Skip to content

Commit

Permalink
Merge pull request #40 from jbytecode/main
Browse files Browse the repository at this point in the history
introduce GeneType enum to replace Real, Permutation, and Binary stri…
  • Loading branch information
jbytecode authored Aug 9, 2024
2 parents 32bd5fa + f9a0561 commit 512e6e1
Show file tree
Hide file tree
Showing 26 changed files with 83 additions and 95 deletions.
28 changes: 18 additions & 10 deletions src/individual.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
from enum import Enum
from numpy import random
import numpy as np
import random as rd
from problems.abstract_problem import AbstractProblem



class GeneType(Enum):
BINARY = 1
PERMUTATION = 2
REAL = 3



class Individual:
"""
A class to represent an individual in an evolutionary algorithm.
Expand All @@ -21,14 +29,14 @@ class Individual:
The positions of the individual's neighbors.
neighbors : list or None
The list of neighbors for the individual.
gen_type : str
The type of genome representation ("Binary", "Permutation", "Real").
gen_type : GeneType
The enum type of genome representation (GeneType.BINARY, GeneType.PERMUTATION, GeneType.REAL).
ch_size : int
The size of the chromosome.
"""

def __init__(self,
gen_type: str = "",
gen_type: GeneType = GeneType.BINARY,
ch_size: int = 0,
problem: AbstractProblem = None,
mins : list[float] = [],
Expand All @@ -39,7 +47,7 @@ def __init__(self,
Parameters
----------
gen_type : str, optional
The type of genome representation. Must be one of "Binary", "Permutation", or "Real". (default is "Binary")
The type of genome representation. Must be one of GeneType.BINARY, "Permutation", or "Real". (default is GeneType.BINARY)
ch_size : int
The size of the chromosome.
mins: list[float]
Expand Down Expand Up @@ -73,18 +81,17 @@ def randomize(self):
NotImplementedError
If the genome type is not implemented.
"""
problem_name = self.problem.__class__.__name__

if self.gen_type == "Binary":
if self.gen_type == GeneType.BINARY:
self.chromosome = [random.randint(2) for i in range(self.ch_size)]

elif self.gen_type == "Permutation":
elif self.gen_type == GeneType.PERMUTATION:
# Generate a random permutation of the numbers 1 to ch_size.
# by default random.permutation emits numbers from 0 to ch_size-1
# so we add 1 to each number to get the desired range.
self.chromosome = list(np.random.permutation(self.ch_size) + 1)

elif self.gen_type == "Real":
elif self.gen_type == GeneType.REAL:
if len(self.mins) > 0:
assert len(self.mins) == len(self.maxs) == self.ch_size
self.chromosome = [rd.uniform(self.mins[i], self.maxs[i]) for i in range(self.ch_size)]
Expand All @@ -95,7 +102,8 @@ def randomize(self):
raise NotImplementedError(self.gen_type + " not implemented yet.")
return self.chromosome

def generate_candidate(self, vector: list) -> list:

def generate_candidate(self, probvector: list) -> list:
"""
Generate a candidate chromosome based on the given probability vector.
Expand All @@ -109,7 +117,7 @@ def generate_candidate(self, vector: list) -> list:
list
The generated candidate chromosome as a list of 0s and 1s.
"""
ind = [1 if random.rand() < p else 0 for p in vector]
ind = [1 if random.rand() < p else 0 for p in probvector]
return ind

def getneighbors_positions(self) -> list:
Expand Down
2 changes: 1 addition & 1 deletion src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
# n_rows = 5,
# n_gen = 100,
# ch_size = 10,
# gen_type = "Binary",
# gen_type = GeneType.BINARY,
# problem = optimizer.OneMax(),
# selection = optimizer.TournamentSelection)

Expand Down
25 changes: 2 additions & 23 deletions src/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ def alpha_cga(
ch_size : int
Size of the chromosome.
gen_type : str
Type of genome representation ("Binary", "Permutation", "Real").
Type of genome representation (GeneType.BINARY, "Permutation", "Real").
p_crossover : float
Probability of crossover, should be between 0 and 1.
p_mutation : float
Expand Down Expand Up @@ -522,7 +522,7 @@ def ccga(
ch_size : int
Size of the chromosome.
gen_type : str
Type of genome representation ("Binary", "Permutation", "Real").
Type of genome representation (GeneType.BINARY, "Permutation", "Real").
problem : AbstractProblem
The problem instance used to evaluate fitness.
selection : Callable
Expand Down Expand Up @@ -840,26 +840,5 @@ def generate_probability_vector(mins: List[float], maxs: List[float], ntries: in
return probvector


def sample(probvector: List[float]) -> List[int]:
"""
Sample a vector based on the provided probability vector.
Parameters
----------
probvector : List[float]
Probability vector for sampling.
Returns
-------
List[int]
Sampled binary vector.
"""
n = len(probvector)
newvector = [0] * n

for i in range(n):
if random.random() < probvector[i]:
newvector[i] = 1

return newvector

2 changes: 1 addition & 1 deletion src/population.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Population:
n_cols : int
The number of columns in the grid.
gen_type : str
The type of genome representation ("Binary", "Permutation", "Real").
The type of genome representation (GeneType.BINARY, Genetype.PERMUTATION, GeneType.REAL).
problem : AbstractProblem
The problem instance used to evaluate fitness.
vector : list
Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_arithmetic_crossover.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
import random
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from recombination.arithmetic_crossover import ArithmeticCrossover # Replace with the actual path if different

Expand Down Expand Up @@ -34,8 +34,8 @@ def setup_parents():
list
A list containing two parent individuals with predefined chromosomes and size.
"""
ind1 = Individual("Real", 5)
ind2 = Individual("Real", 5)
ind1 = Individual(GeneType.REAL, 5)
ind2 = Individual(GeneType.REAL, 5)
ind1.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind2.chromosome = [5.0, 4.0, 3.0, 2.0, 1.0]
ind1.ch_size = 5
Expand Down
4 changes: 2 additions & 2 deletions src/tests/test_bit_flip_mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pytest
from mutation.bit_flip_mutation import BitFlipMutation
from problems.single_objective.discrete.binary.one_max import OneMax
from individual import Individual
from individual import Individual, GeneType

def test_bit_flip_mutation():
"""
Expand Down Expand Up @@ -37,7 +37,7 @@ def test_bit_flip_mutation():
CHSIZE = 20

# Create an individual with all zeros
ind = Individual("Binary", CHSIZE)
ind = Individual(GeneType.BINARY, CHSIZE)
ind.chromosome = [0] * CHSIZE
ind.ch_size = CHSIZE

Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_blxalpha_crossover.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
import random
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from recombination.blxalpha_crossover import BlxalphaCrossover # Replace with the actual path if different

Expand Down Expand Up @@ -34,8 +34,8 @@ def setup_parents():
list
A list containing two parent individuals with predefined chromosomes and size.
"""
ind1 = Individual("Real", 5)
ind2 = Individual("Real", 5)
ind1 = Individual(GeneType.REAL, 5)
ind2 = Individual(GeneType.REAL, 5)
ind1.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind2.chromosome = [5.0, 4.0, 3.0, 2.0, 1.0]
ind1.ch_size = 5
Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_byte_mutation.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest
import numpy as np
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from mutation.byte_mutation import ByteMutation # Replace with the actual path if different
import struct


class MockProblem(AbstractProblem):
"""
Expand Down Expand Up @@ -35,7 +35,7 @@ def setup_individual():
Individual
An individual instance with a predefined chromosome and size.
"""
ind = Individual("Real", 5)
ind = Individual(GeneType.REAL, 5)
ind.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind.ch_size = 5
return ind
Expand Down
5 changes: 2 additions & 3 deletions src/tests/test_byte_mutation_random.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import pytest
import numpy as np
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from mutation.byte_mutation_random import ByteMutationRandom # Replace with the actual path if different
import struct

class MockProblem(AbstractProblem):
"""
Expand Down Expand Up @@ -35,7 +34,7 @@ def setup_individual():
Individual
An individual instance with a predefined chromosome and size.
"""
ind = Individual("Real", 5)
ind = Individual(GeneType.REAL, 5)
ind.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind.ch_size = 5
return ind
Expand Down
8 changes: 4 additions & 4 deletions src/tests/test_byte_one_point_crossover.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest
import numpy as np
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from recombination.byte_one_point_crossover import ByteOnePointCrossover # Replace with the actual path if different
import struct


class MockProblem(AbstractProblem):
"""
Expand Down Expand Up @@ -35,8 +35,8 @@ def setup_parents():
list
A list containing two parent individuals with predefined chromosomes and size.
"""
ind1 = Individual("Real", 5)
ind2 = Individual("Real", 5)
ind1 = Individual(GeneType.REAL, 5)
ind2 = Individual(GeneType.REAL, 5)
ind1.chromosome = [1.15, 2.45, 3.03, 4.76, 5.34]
ind2.chromosome = [5.36, 4.98, 3.23, 2.45, 1.67]
ind1.ch_size = 5
Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_byte_uniform_crossover.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
import numpy.random as randomgenerator
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from recombination.byte_uniform_crossover import ByteUniformCrossover # Replace with the actual path if different
import struct
Expand Down Expand Up @@ -35,8 +35,8 @@ def setup_parents():
list
A list containing two parent individuals with predefined chromosomes and size.
"""
ind1 = Individual("Real", 5)
ind2 = Individual("Real", 5)
ind1 = Individual(GeneType.REAL, 5)
ind2 = Individual(GeneType.REAL, 5)
ind1.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind2.chromosome = [5.0, 4.0, 3.0, 2.0, 1.0]
ind1.ch_size = 5
Expand Down
6 changes: 3 additions & 3 deletions src/tests/test_flat_crossover.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
import random
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from recombination.flat_crossover import FlatCrossover # Replace with the actual path if different

Expand Down Expand Up @@ -34,8 +34,8 @@ def setup_parents():
list
A list containing two parent individuals with predefined chromosomes and size.
"""
ind1 = Individual("Real", 5)
ind2 = Individual("Real", 5)
ind1 = Individual(GeneType.REAL, 5)
ind2 = Individual(GeneType.REAL, 5)
ind1.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind2.chromosome = [5.0, 4.0, 3.0, 2.0, 1.0]
ind1.ch_size = 5
Expand Down
4 changes: 2 additions & 2 deletions src/tests/test_float_uniform_mutation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest
import random
from individual import Individual
from individual import Individual, GeneType
from problems.abstract_problem import AbstractProblem
from mutation.float_uniform_mutation import FloatUniformMutation # Replace with the actual path if different

Expand Down Expand Up @@ -34,7 +34,7 @@ def setup_individual():
Individual
An individual instance with a predefined chromosome and size.
"""
ind = Individual("Real", 5)
ind = Individual(GeneType.REAL, 5)
ind.chromosome = [1.0, 2.0, 3.0, 4.0, 5.0]
ind.ch_size = 5
return ind
Expand Down
14 changes: 7 additions & 7 deletions src/tests/test_individual.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
from numpy import random
import random as rd
from individual import Individual
from individual import Individual, GeneType
from problems.single_objective.discrete.binary.one_max import OneMax
from problems.single_objective.continuous.ackley import Ackley
from problems.single_objective.discrete.permutation.tsp import Tsp
Expand All @@ -12,14 +12,14 @@ def setup_individual():
"""
Fixture to provide an instance of the Individual class with different configurations.
"""
return Individual(gen_type="Binary", ch_size=10, problem=OneMax())
return Individual(gen_type=GeneType.BINARY, ch_size=10, problem=OneMax())

def test_individual_init():
"""
Test the initialization of the Individual class.
"""
ind = Individual(gen_type="Binary", ch_size=10, problem=OneMax())
assert ind.gen_type == "Binary"
ind = Individual(gen_type=GeneType.BINARY, ch_size=10, problem=OneMax())
assert ind.gen_type == GeneType.BINARY
assert ind.ch_size == 10
assert ind.chromosome == []
assert ind.fitness_value == 0
Expand All @@ -31,7 +31,7 @@ def test_randomize_binary():
"""
Test the randomization of the chromosome for a binary genome type.
"""
ind = Individual(gen_type="Binary", ch_size=10, problem=OneMax())
ind = Individual(gen_type=GeneType.BINARY, ch_size=10, problem=OneMax())
ind.randomize()
assert len(ind.chromosome) == 10
assert all(gene in [0, 1] for gene in ind.chromosome)
Expand All @@ -41,7 +41,7 @@ def test_randomize_permutation():
Test the randomization of the chromosome for a permutation genome type.
"""
chsize = 14
ind = Individual(gen_type="Permutation", ch_size=chsize, problem=Tsp())
ind = Individual(gen_type=GeneType.PERMUTATION, ch_size=chsize, problem=Tsp())
ind.randomize()
assert len(ind.chromosome) == chsize
for i in range(1, chsize+1):
Expand All @@ -54,7 +54,7 @@ def test_randomize_real_valued():
Test the randomization of the chromosome for a real-valued genome type.
"""
chsize = 10
ind = Individual(gen_type="Real", ch_size=chsize, problem=Ackley())
ind = Individual(gen_type=GeneType.REAL, ch_size=chsize, problem=Ackley())
ind.randomize()
assert len(ind.chromosome) == chsize
assert all(isinstance(gene, float) for gene in ind.chromosome)
Expand Down
4 changes: 2 additions & 2 deletions src/tests/test_insertion_mutation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from mutation.insertion_mutation import InsertionMutation
from problems.single_objective.discrete.permutation.tsp import Tsp
from individual import Individual
from individual import Individual, GeneType
import random

def test_insertion_mutation():
Expand Down Expand Up @@ -32,7 +32,7 @@ def test_insertion_mutation():
CHSIZE = 14

# Create an individual with a random permutation of integers from 1 to CHSIZE
ind = Individual("Permutation", CHSIZE)
ind = Individual(GeneType.PERMUTATION, CHSIZE)
ind.chromosome = list(random.sample(range(1, CHSIZE + 1), CHSIZE))

# Initialize the TSP problem
Expand Down
Loading

0 comments on commit 512e6e1

Please sign in to comment.