Real-Valued and Integer Genetic Algorithms#

This page covers two more genotype representations built on top of the same GeneticAlgorithm framework used by the Binary Genetic Algorithm, see Genetic Algorithms. As there, the running example is minimizing the Rosenbrock function.

from typing import Iterable
from numbers import Number
import numpy as np


def Rosenbrock(x: Iterable[Number], a: Number = 1, b: Number = 100) -> float:
    return (a - x[0]) ** 2 + b * (x[1] - x[0] ** 2) ** 2


ranges = [[-2, 2], [-1, 3]]

Real-Valued Genetic Algorithm (RGA)#

If you prefer to avoid the precision/chromosome-length trade-off of binary encoding, use the real-valued genetic algorithm (RealValuedGeneticAlgorithm), which operates directly on real-valued chromosomes (genotype and phenotype coincide) using arithmetic crossover and Gaussian mutation. It exposes the same interface as BinaryGeneticAlgorithm. 📖 RGA API Reference.

from sigmaepsilon.math.optimize.rga import RealValuedGeneticAlgorithm as RGA

rga = RGA(Rosenbrock, ranges, nPop=100, minimize=True, maxage=20, seed=0)
result = rga.solve()
type(result), result.phenotype, result.fitness

Integer Genetic Algorithm (IGA)#

If your decision variables are natively boolean or small bounded integers (e.g. a 0/1 knapsack indicator, or a handful of discrete levels per variable) rather than continuous reals, use the integer genetic algorithm (IntegerGeneticAlgorithm). It reuses BGA’s bit-chromosome representation and operators, but rounds the decoded value to the nearest integer instead of keeping it as a continuous float. 📖 IGA API Reference.

from sigmaepsilon.math.optimize import IntegerGeneticAlgorithm as IGA

# a small 0/1 knapsack problem: pick a subset of items to maximize value
# without exceeding a weight budget
values = np.array([60, 100, 120, 80, 30])
weights = np.array([10, 20, 30, 15, 5])
capacity = 50


def knapsack(x):
    total_weight = np.dot(weights, x)
    total_value = np.dot(values, x)
    penalty = 1000 * max(0, total_weight - capacity)
    return total_value - penalty


iga = IGA(knapsack, [[0, 1]] * len(values), length=1, nPop=50, seed=0)
champion = iga.solve()
selection = champion.phenotype
selection, champion.fitness

ranges isn’t limited to [0, 1]; any small bounded-integer domain works, e.g. [0, 6] for a 7-valued discrete variable. Choose length so that 2 ** length - 1 comfortably covers the width of the widest range:

def f(x):
    return -((x[0] - 4) ** 2)


iga_int = IGA(f, [[0, 6]], length=3, nPop=20, seed=2)
champion = iga_int.solve()
champion.phenotype