OneMax

Description:

  • Optimization (max)

  • Single-objective

  • Constraints (no)

The general problem statement is given by:

We have a state vector \(\mathbf{x} \in [0, 1]^M\) of bits, such as: \(\mathbf{x} = (0, 0, 1, 1, 0, ..., 1)\).

  • The optimal solution is the one where each variable has the value of ‘1’.

    \[f(\mathbf{x}) = \sum_{i=1}^{M} x_i, \text{ with } x_i \in \{0, 1\}\]
  • Global maximum is found at:

    \[f(1, 1, ..., 1) = M\]

Step 1: Import python libraries and PyGenAlgo classes

import numpy as np
from math import fsum

# Import main classes.
from pygenalgo.genome.gene import Gene
from pygenalgo.genome.chromosome import Chromosome
from pygenalgo.engines.standard_ga import StandardGA
from pygenalgo.utils.utilities import cost_function

# Import Selection Operator(s).
from pygenalgo.operators.selection.linear_rank_selector import LinearRankSelector

# Import Crossover Operator(s).
from pygenalgo.operators.crossover.meta_crossover import MetaCrossover

# Import Mutation Operator(s).
from pygenalgo.operators.mutation.flip_mutator import FlipMutator

Step 2: Define the objective function

# OneMax function.
@cost_function
def fun_OneMax(individual: Chromosome):

    # Compute the function value.
    f_value = fsum(individual.values())

    # Condition for termination.
    solution_found = f_value == len(individual)

    # Return the solution tuple.
    return f_value, solution_found

Step 3: Set the GA parameters

# Set a seed for reproducible initial population.
SEED = 1821

# Random number generator.
rng = np.random.default_rng(SEED)

# Random function: It is used only for compatibility.
boundary_x = lambda: rng.integers(2)

# Define the number of genes.
M = 50

# Define the number of chromosomes.
N = 100

# Draw random samples for the initial points.
x_init = rng.integers(low=0, high=2, size=(N, M))

# Initial population.
population = [Chromosome([Gene(x_init[i, j], boundary_x)
                          for j in range(M)], np.nan, True)
              for i in range(N)]

# Create the StandardGA object that will carry on the optimization.
test_GA = StandardGA(initial_pop=population,
                     fit_func=fun_OneMax,
                     select_op=LinearRankSelector(),
                     mutate_op=FlipMutator(),
                     crossx_op=MetaCrossover())

Step 4: Run the optimization

test_GA(epochs=200, elitism=True, f_tol=1.0e-6, verbose=False)

Step 5: Final output

# Extract the optimal solution from the GA.
optimal_solution = test_GA.best_chromosome()

# Extract the fitness value from the optimal solution.
optimal_fit = optimal_solution.fitness

# Display the (final) optimal value.
print(f"Optimum Found: {optimal_fit:.6f}\n")

# Display each gene value separately.
for i, xi in enumerate(optimal_solution.values(), start=1):
    print(f"x{i} = {xi:>10.6f}")