Proper repr implementations, improved index_of method, and improved initialization
- Repr now supports reversal using eval i.e. obj == eval(repr(obj)) for any data object. This assumes a GA object called ga. - Index of now supports local searching if an estimate of the index is given. - Initialization of data objects is now easier and works for any iterable input e.g. ga.make_chromosome
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
from copy import deepcopy
|
from structure import Gene as make_gene
|
||||||
|
|
||||||
class Chromosome:
|
class Chromosome:
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ class Chromosome:
|
|||||||
"""Initialize the chromosome with fitness value of None, and a
|
"""Initialize the chromosome with fitness value of None, and a
|
||||||
set of genes dependent on user-passed parameter."""
|
set of genes dependent on user-passed parameter."""
|
||||||
|
|
||||||
self.gene_list = [deepcopy(gene) for gene in gene_list]
|
self.gene_list = [make_gene(gene) for gene in gene_list]
|
||||||
self.fitness = None
|
self.fitness = None
|
||||||
|
|
||||||
|
|
||||||
@ -70,6 +70,15 @@ class Chromosome:
|
|||||||
self.gene_list[index] = gene
|
self.gene_list[index] = gene
|
||||||
|
|
||||||
|
|
||||||
|
def __delitem__(self, index):
|
||||||
|
"""
|
||||||
|
Allows the user to use
|
||||||
|
del chromosome[index]
|
||||||
|
to delete a gene at the specified index.
|
||||||
|
"""
|
||||||
|
del self.gene_list[index]
|
||||||
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
@ -88,16 +97,41 @@ class Chromosome:
|
|||||||
return (searched_gene in self.gene_list)
|
return (searched_gene in self.gene_list)
|
||||||
|
|
||||||
|
|
||||||
def index_of(self, searched_gene):
|
def index_of(self, gene, guess = None):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
index = chromosome.index_of(gene)
|
index = chromosome.index_of(gene)
|
||||||
|
index = chromosome.index_of(gene, guess)
|
||||||
to find the index of a gene in the chromosome.
|
to find the index of a gene in the chromosome.
|
||||||
Be sure to check if the chromosome contains the gene
|
Be sure to check if the chromosome contains the gene
|
||||||
first, or to catch an exception if the gene is not
|
first, or to catch an IndexError exception if the gene
|
||||||
in the chromosome.
|
is not in the chromosome. A guess may be used to find
|
||||||
|
the index quicker.
|
||||||
"""
|
"""
|
||||||
return self.gene_list.index(searched_gene)
|
|
||||||
|
# Use built-in method
|
||||||
|
if guess is None:
|
||||||
|
return self.gene_list.index(gene)
|
||||||
|
|
||||||
|
# Use symmetric mod
|
||||||
|
guess %= len(self)
|
||||||
|
if guess >= len(self)//2:
|
||||||
|
guess -= len(self)
|
||||||
|
|
||||||
|
# Search outwards for the gene
|
||||||
|
for i in range(1+len(self)//2):
|
||||||
|
|
||||||
|
# Search to the left
|
||||||
|
if gene == self[guess-i]:
|
||||||
|
return (guess-i) % len(self)
|
||||||
|
|
||||||
|
# Search to the right
|
||||||
|
elif gene == self[guess+i]:
|
||||||
|
return (guess+i) % len(self)
|
||||||
|
|
||||||
|
# Gene not found
|
||||||
|
else:
|
||||||
|
raise IndexError("No such gene in the chromosome found")
|
||||||
|
|
||||||
|
|
||||||
def __eq__(self, chromosome):
|
def __eq__(self, chromosome):
|
||||||
@ -107,17 +141,19 @@ class Chromosome:
|
|||||||
chromosome_1 != chromosome_2
|
chromosome_1 != chromosome_2
|
||||||
to compare two chromosomes based on their genes.
|
to compare two chromosomes based on their genes.
|
||||||
"""
|
"""
|
||||||
|
return self.gene_list == chromosome.gene_list
|
||||||
return all(gene_1 == gene_2 for gene_1, gene_2 in zip(self, chromosome))
|
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
repr(chromosome)
|
chromosome_string = repr(chromosome)
|
||||||
to get a backend representation of the chromosome.
|
chromosome = eval(chromosome_string)
|
||||||
|
to get a backend representation of the chromosome
|
||||||
|
which can be evaluated directly as code to create
|
||||||
|
the chromosome.
|
||||||
"""
|
"""
|
||||||
return ', '.join(repr(gene) for gene in self)
|
return f"EasyGA.make_chromosome({repr(self.gene_list)})"
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@ -3,7 +3,14 @@ from copy import deepcopy
|
|||||||
class Gene:
|
class Gene:
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
"""Initialize a gene with fitness of value None and the input value."""
|
"""Initialize a gene with the input value."""
|
||||||
|
|
||||||
|
# Copy another gene
|
||||||
|
try:
|
||||||
|
self.value = deepcopy(value.value)
|
||||||
|
|
||||||
|
# Otherwise copy the given value
|
||||||
|
except:
|
||||||
self.value = deepcopy(value)
|
self.value = deepcopy(value)
|
||||||
|
|
||||||
|
|
||||||
@ -20,10 +27,11 @@ class Gene:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
repr(gene)
|
gene_string = repr(gene)
|
||||||
|
gene = eval(gene_string)
|
||||||
to get a backend representation of the gene.
|
to get a backend representation of the gene.
|
||||||
"""
|
"""
|
||||||
return str(self.value)
|
return f"EasyGA.make_gene({repr(self.value)})"
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
from copy import deepcopy
|
from structure import Chromosome as make_chromosome
|
||||||
|
|
||||||
class Population:
|
class Population:
|
||||||
|
|
||||||
def __init__(self, chromosome_list):
|
def __init__(self, chromosome_list):
|
||||||
"""Initialize the population with fitness of value None, and a
|
"""Initialize the population with a collection
|
||||||
set of chromosomes dependant on user-passed parameter."""
|
of chromosomes dependant on user-passed parameter."""
|
||||||
|
|
||||||
self.chromosome_list = [deepcopy(chromosome) for chromosome in chromosome_list]
|
self.chromosome_list = [make_chromosome(chromosome) for chromosome in chromosome_list]
|
||||||
self.fitness = None
|
|
||||||
self.mating_pool = []
|
self.mating_pool = []
|
||||||
self.next_population = []
|
self.next_population = []
|
||||||
|
|
||||||
@ -135,25 +134,61 @@ class Population:
|
|||||||
return (searched_chromosome in self.chromosome_list)
|
return (searched_chromosome in self.chromosome_list)
|
||||||
|
|
||||||
|
|
||||||
def index_of(self, searched_chromosome):
|
def index_of(self, chromosome, guess = None):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
index = population.index_of(chromosome)
|
index = population.index_of(chromosome)
|
||||||
|
index = population.index_of(chromosome, guess)
|
||||||
to find the index of a chromosome in the population.
|
to find the index of a chromosome in the population.
|
||||||
Be sure to check if the population contains the chromosome
|
Be sure to check if the population contains the chromosome
|
||||||
first, or to catch an exception if the chromosome is not
|
first, or to catch an IndexError exception if the chromosome
|
||||||
in the population.
|
is not in the population. A guess may be used to find the
|
||||||
|
index quicker.
|
||||||
"""
|
"""
|
||||||
return self.chromosome_list.index(searched_chromosome)
|
|
||||||
|
# Use built-in method
|
||||||
|
if guess is None:
|
||||||
|
return self.chromosome_list.index(gene)
|
||||||
|
|
||||||
|
# Use symmetric mod
|
||||||
|
guess %= len(self)
|
||||||
|
if guess >= len(self)//2:
|
||||||
|
guess -= len(self)
|
||||||
|
|
||||||
|
# Search outwards for the gene
|
||||||
|
for i in range(len(self)//2):
|
||||||
|
|
||||||
|
# Search to the left
|
||||||
|
if chromosome == self[guess-i]:
|
||||||
|
return (guess-i) % len(self)
|
||||||
|
|
||||||
|
# Search to the right
|
||||||
|
elif chromosome == self[guess+i]:
|
||||||
|
return (guess+i) % len(self)
|
||||||
|
|
||||||
|
# Gene not found
|
||||||
|
else:
|
||||||
|
raise IndexError("No such chromosome in the population found")
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
repr(population)
|
population_string = repr(population)
|
||||||
|
population = eval(population_string)
|
||||||
|
to get a backend representation of the population
|
||||||
|
which can be evaluated directly as code to create
|
||||||
|
the population.
|
||||||
|
"""
|
||||||
|
return "EasyGA.make_population({repr(self.chromosome_list)})"
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
Allows the user to use
|
||||||
str(population)
|
str(population)
|
||||||
print(population)
|
print(population)
|
||||||
to get a backend representation of the population.
|
to get a frontend representation of the population.
|
||||||
"""
|
"""
|
||||||
return ''.join(
|
return ''.join(
|
||||||
f'Chromosome - {index} {chromosome} / Fitness = {chromosome.fitness}\n'
|
f'Chromosome - {index} {chromosome} / Fitness = {chromosome.fitness}\n'
|
||||||
|
|||||||
Reference in New Issue
Block a user