Added most list functionality
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
from structure import Gene as make_gene
|
from structure import Gene as make_gene
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
def to_gene(gene):
|
def to_gene(gene):
|
||||||
"""Converts the input to a gene if it isn't already one."""
|
"""Converts the input to a gene if it isn't already one."""
|
||||||
@ -9,7 +10,7 @@ def to_gene(gene):
|
|||||||
return make_gene(gene)
|
return make_gene(gene)
|
||||||
|
|
||||||
|
|
||||||
class Chromosome:
|
class Chromosome():
|
||||||
|
|
||||||
def __init__(self, gene_list):
|
def __init__(self, gene_list):
|
||||||
"""Initialize the chromosome with fitness value of None, and a
|
"""Initialize the chromosome with fitness value of None, and a
|
||||||
@ -19,18 +20,6 @@ class Chromosome:
|
|||||||
self.fitness = None
|
self.fitness = None
|
||||||
|
|
||||||
|
|
||||||
def add_gene(self, gene, index = None):
|
|
||||||
"""Add a gene to the chromosome at the specified index, defaulted to end of the chromosome"""
|
|
||||||
if index is None:
|
|
||||||
index = len(self)
|
|
||||||
self.gene_list.insert(index, to_gene(gene))
|
|
||||||
|
|
||||||
|
|
||||||
def remove_gene(self, index):
|
|
||||||
"""Removes the gene at the given index"""
|
|
||||||
return self.gene_list.pop(index)
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def gene_value_list(self):
|
def gene_value_list(self):
|
||||||
"""Returns a list of gene values"""
|
"""Returns a list of gene values"""
|
||||||
@ -43,6 +32,11 @@ class Chromosome:
|
|||||||
return (gene.value for gene in self)
|
return (gene.value for gene in self)
|
||||||
|
|
||||||
|
|
||||||
|
#==================================================#
|
||||||
|
# Magic-Dunder Methods replicating list structure. #
|
||||||
|
#==================================================#
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
@ -109,16 +103,50 @@ class Chromosome:
|
|||||||
return (to_gene(gene) in self.gene_list)
|
return (to_gene(gene) in self.gene_list)
|
||||||
|
|
||||||
|
|
||||||
def index_of(self, gene, guess = None):
|
def __eq__(self, chromosome):
|
||||||
|
"""Returns self == chromosome, True if all genes match."""
|
||||||
|
return self.gene_list == chromosome.gene_list
|
||||||
|
|
||||||
|
|
||||||
|
def __add__(self, chromosome):
|
||||||
|
"""Return self + chromosome, a chromosome made by concatenating the genes."""
|
||||||
|
return Chromosome(chain(self, chromosome))
|
||||||
|
|
||||||
|
|
||||||
|
def __iadd__(self, chromosome):
|
||||||
|
"""Implement self += chromosome by concatenating the new genes."""
|
||||||
|
self.gene_list += (to_gene(gene) for gene in chromosome)
|
||||||
|
|
||||||
|
|
||||||
|
def append(self, gene):
|
||||||
|
"""Append gene to the end of the chromosome."""
|
||||||
|
self.gene_list.append(to_gene(gene))
|
||||||
|
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Remove all genes from chromosome."""
|
||||||
|
self.gene_list = []
|
||||||
|
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
"""Return a copy of the chromosome."""
|
||||||
|
return Chromosome(self)
|
||||||
|
|
||||||
|
|
||||||
|
def count(self, gene):
|
||||||
|
"""Return number of occurrences of the gene in the chromosome."""
|
||||||
|
return self.gene_list.count(to_gene(gene))
|
||||||
|
|
||||||
|
|
||||||
|
def index(self, gene, guess = None):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
index = chromosome.index_of(gene)
|
index = chromosome.index(gene)
|
||||||
index = chromosome.index_of(gene, guess)
|
index = chromosome.index(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
|
|
||||||
first, or to catch an IndexError exception if the gene
|
If no guess is given, it finds the index of the first match.
|
||||||
is not in the chromosome. A guess may be used to find
|
If a guess is given, it finds index of the nearest match.
|
||||||
the index quicker.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Cast to gene object
|
# Cast to gene object
|
||||||
@ -145,18 +173,28 @@ class Chromosome:
|
|||||||
return (guess+i) % len(self)
|
return (guess+i) % len(self)
|
||||||
|
|
||||||
# Gene not found
|
# Gene not found
|
||||||
else:
|
raise ValueError("No such gene in the chromosome found")
|
||||||
raise IndexError("No such gene in the chromosome found")
|
|
||||||
|
|
||||||
|
|
||||||
def __eq__(self, chromosome):
|
def insert(self, index, gene):
|
||||||
|
"""Insert gene so that self[index] == gene."""
|
||||||
|
self.gene_list.insert(index, to_gene(gene))
|
||||||
|
|
||||||
|
|
||||||
|
def pop(self, index = -1):
|
||||||
|
"""Remove and return gene at index (default last).
|
||||||
|
|
||||||
|
Raises IndexError if chromosome is empty or index is out of range.
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
return self.gene_list.pop(index)
|
||||||
chromosome_1 == chromosome_2
|
|
||||||
chromosome_1 != chromosome_2
|
|
||||||
to compare two chromosomes based on their genes.
|
def remove(self, gene):
|
||||||
|
"""Remove first occurrence of gene.
|
||||||
|
|
||||||
|
Raises ValueError if the gene in not present.
|
||||||
"""
|
"""
|
||||||
return self.gene_list == chromosome.gene_list
|
self.gene_list.remove(to_gene(gene))
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
from structure import Chromosome as make_chromosome
|
from structure import Chromosome as make_chromosome
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
def to_chromosome(chromosome):
|
def to_chromosome(chromosome):
|
||||||
"""Converts the input to a chromosome if it isn't already one."""
|
"""Converts the input to a chromosome if it isn't already one."""
|
||||||
@ -66,11 +67,6 @@ class Population:
|
|||||||
] + self.next_population
|
] + self.next_population
|
||||||
|
|
||||||
|
|
||||||
def sort_by_best_fitness(self, ga):
|
|
||||||
"""Sorts the population by fitness"""
|
|
||||||
ga.sort_by_best_fitness(self.chromosome_list, in_place = True)
|
|
||||||
|
|
||||||
|
|
||||||
def add_chromosome(self, chromosome, index = None):
|
def add_chromosome(self, chromosome, index = None):
|
||||||
"""Adds a chromosome to the population at the input index,
|
"""Adds a chromosome to the population at the input index,
|
||||||
defaulted to the end of the chromosome set"""
|
defaulted to the end of the chromosome set"""
|
||||||
@ -95,6 +91,11 @@ class Population:
|
|||||||
self.add_parent(self[index])
|
self.add_parent(self[index])
|
||||||
|
|
||||||
|
|
||||||
|
#==================================================#
|
||||||
|
# Magic-Dunder Methods replicating list structure. #
|
||||||
|
#==================================================#
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
@ -127,6 +128,15 @@ class Population:
|
|||||||
self.chromosome_list[index] = to_chromosome(chromosome)
|
self.chromosome_list[index] = to_chromosome(chromosome)
|
||||||
|
|
||||||
|
|
||||||
|
def __delitem__(self, index):
|
||||||
|
"""
|
||||||
|
Allows the user to use
|
||||||
|
del population[index]
|
||||||
|
to delete a chromosome at the specified index.
|
||||||
|
"""
|
||||||
|
del self.chromosome_list[index]
|
||||||
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
@ -145,30 +155,64 @@ class Population:
|
|||||||
return (to_chromosome(chromosome) in self.chromosome_list)
|
return (to_chromosome(chromosome) in self.chromosome_list)
|
||||||
|
|
||||||
|
|
||||||
def index_of(self, chromosome, guess = None):
|
def __eq__(self, population):
|
||||||
|
"""Returns self == population, True if all chromosomes match."""
|
||||||
|
return self.chromosome_list == population.chromosome_list
|
||||||
|
|
||||||
|
|
||||||
|
def __add__(self, population):
|
||||||
|
"""Returns self + population, a population made by concatenating the chromosomes."""
|
||||||
|
return Population(chain(self, population))
|
||||||
|
|
||||||
|
|
||||||
|
def __iadd__(self, population):
|
||||||
|
"""Implement self += population by concatenating the new chromosomes."""
|
||||||
|
self.chromosome_list += (to_chromosome(chromosome) for chromosome in population)
|
||||||
|
|
||||||
|
|
||||||
|
def append(self, chromosome):
|
||||||
|
"""Append chromosome to the end of the population."""
|
||||||
|
self.chromosome_list.append(to_chromosome(chromosome))
|
||||||
|
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Remove all chromosomes from the population."""
|
||||||
|
self.chromosome_list = []
|
||||||
|
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
"""Return a copy of the population."""
|
||||||
|
return Population(self)
|
||||||
|
|
||||||
|
|
||||||
|
def count(self, chromosome):
|
||||||
|
"""Return number of occurrences of the chromosome in the population."""
|
||||||
|
return self.chromosome_list.count(to_chromosome(chromosome))
|
||||||
|
|
||||||
|
|
||||||
|
def index(self, chromosome, guess = None):
|
||||||
"""
|
"""
|
||||||
Allows the user to use
|
Allows the user to use
|
||||||
index = population.index_of(chromosome)
|
index = population.index(chromosome)
|
||||||
index = population.index_of(chromosome, guess)
|
index = population.index(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
|
|
||||||
first, or to catch an IndexError exception if the chromosome
|
If no guess is given, it finds the index of the first match.
|
||||||
is not in the population. A guess may be used to find the
|
If a guess is given, it finds index of the nearest match.
|
||||||
index quicker.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
chromosome = to_chromosome(chromosome)
|
chromosome = to_chromosome(chromosome)
|
||||||
|
|
||||||
# Use built-in method
|
# Use built-in method
|
||||||
if guess is None:
|
if guess is None:
|
||||||
return self.chromosome_list.index(gene)
|
return self.chromosome_list.index(chromosome)
|
||||||
|
|
||||||
# Use symmetric mod
|
# Use symmetric mod
|
||||||
guess %= len(self)
|
guess %= len(self)
|
||||||
if guess >= len(self)//2:
|
if guess >= len(self)//2:
|
||||||
guess -= len(self)
|
guess -= len(self)
|
||||||
|
|
||||||
# Search outwards for the gene
|
# Search outwards for the chromosome
|
||||||
for i in range(len(self)//2):
|
for i in range(len(self)//2):
|
||||||
|
|
||||||
# Search to the left
|
# Search to the left
|
||||||
@ -179,9 +223,37 @@ class Population:
|
|||||||
elif chromosome == self[guess+i]:
|
elif chromosome == self[guess+i]:
|
||||||
return (guess+i) % len(self)
|
return (guess+i) % len(self)
|
||||||
|
|
||||||
# Gene not found
|
# Chromosome not found
|
||||||
else:
|
raise IndexError("No such chromosome in the population found")
|
||||||
raise IndexError("No such chromosome in the population found")
|
|
||||||
|
|
||||||
|
def insert(self, index, chromosome):
|
||||||
|
"""Insert chromosome so that self[index] == chromsome."""
|
||||||
|
self.chromosome_list.insert(index, to_chromosome(chromosome))
|
||||||
|
|
||||||
|
|
||||||
|
def pop(self, index = -1):
|
||||||
|
"""Remove and return chromosome at index (default last).
|
||||||
|
|
||||||
|
Raises IndexError if population is empty or index is out of range.
|
||||||
|
"""
|
||||||
|
return self.chromosome_list.pop(index)
|
||||||
|
|
||||||
|
|
||||||
|
def remove(self, chromosome):
|
||||||
|
"""Remove first occurrence of chromosome.
|
||||||
|
|
||||||
|
Raises ValueError if the chromosome is not present.
|
||||||
|
"""
|
||||||
|
self.chromosome_list.remove(to_chromosome(chromosome))
|
||||||
|
|
||||||
|
|
||||||
|
def sort(self, *, key = lambda chromosome: chromosome.fitness, reverse):
|
||||||
|
"""Sorts the population."""
|
||||||
|
self.chromosome_list.sort(
|
||||||
|
key = key,
|
||||||
|
reverse = reverse
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user