diff --git a/src/EasyGA.py b/src/EasyGA.py index 1ae5d60..b3e97f9 100644 --- a/src/EasyGA.py +++ b/src/EasyGA.py @@ -1,15 +1,17 @@ import random # Import all the data structure prebuilt modules -from initialization import population as create_population -from initialization import chromosome as create_chromosome -from initialization import gene as create_gene -# Import example classes -from fitness_function import fitness_examples -from initialization import initialization_examples -from termination_point import termination_examples -from selection import selection_examples -from crossover import crossover_examples -from mutation import mutation_examples +from initialization import Population as create_population +from initialization import Chromosome as create_chromosome +from initialization import Gene as create_gene +# Structure Methods +from fitness_function import Fitness_methods +from initialization import Initialization_methods +from termination_point import Termination_methods +# Population Methods +from survivor_selection import Survivor_methods +# Manipulation Methods +from parent_selection import Parent_methods +from mutation import Mutation_methods class GA: def __init__(self): @@ -22,8 +24,9 @@ class GA: self.population = None # Termination varibles self.current_generation = 0 - self.current_fitness = 0 self.generation_goal = 3 + + self.current_fitness = 0 self.fitness_goal = 3 # Mutation variables self.mutation_rate = 0.03 @@ -32,21 +35,56 @@ class GA: self.update_fitness = False # Defualt EastGA implimentation structure - self.initialization_impl = initialization_examples.random_initialization - self.fitness_funciton_impl = fitness_examples.is_it_5 - #self.mutation_impl = PerGeneMutation(Mutation_rate) - #self.selection_impl = TournamentSelection() - #self.crossover_impl = FastSinglePointCrossover() - self.termination_impl = termination_examples.generation_based + self.initialization_impl = Initialization_methods.random_initialization + self.fitness_funciton_impl = Fitness_methods.is_it_5 + # Selects which chromosomes should be automaticly moved to the next population + #self.survivor_selection_impl = Survivor_methods. + # Methods for accomplishing parent-selection -> Crossover -> Mutation + #self.parent_selection_impl = Parent_methods. + #self.crossover_impl = Crossover_methods. + #self.mutation_impl = Mutation_methods. + # The type of termination to impliment + self.termination_impl = Termination_methods.generation_based + + def evolve_generation(self, number_of_generations = 1): + """Evolves the ga the specified number of generations.""" + while(number_of_generations > 0): + # If its the first generation then initialize the population + if(self.current_generation == 0): + # Initialize the population + self.initialize_population() + # First get the fitness of the population + self.get_population_fitness(self.population.chromosome_list) + # Selection - Triggers flags in the chromosome if its been selected + # self.selection_impl(self) + # Crossover - Takes the flagged chromosome_list and crosses there genetic + # makup to make new offsprings. + # self.crossover_impl(self) + # Repopulate - Manipulates the population to some desired way + # self.repopulate_impl(self) + # Mutation - Manipulates the population very slightly + # self.mutation_impl(self) + + # Counter for the local number of generations in evolve_generation + number_of_generations -= 1 + # Add one to the current overall generation + self.current_generation += 1 + + def evolve(self): + """Runs the ga until the termination point has been satisfied.""" + # While the termination point hasnt been reached keep running + while(self.active()): + self.evolve_generation() + + def active(self): + """Returns if the ga should terminate base on the termination implimented""" + # Send termination_impl the whole ga class + return self.termination_impl(self) def initialize_population(self): """Initialize the population using the initialization implimentation that is currently set""" - self.population = self.initialization_impl( - self.population_size, - self.chromosome_length, - self.chromosome_impl, - self.gene_impl) + self.population = self.initialization_impl(self) def get_population_fitness(self,population): """Will get and set the fitness of each chromosome in the population. @@ -61,43 +99,6 @@ class GA: # Set the chromosomes fitness using the fitness function chromosome.fitness = self.fitness_funciton_impl(chromosome) - - def evolve(self): - """Runs the ga until the termination point has been satisfied.""" - # While the termination point hasnt been reached keep running - while(self.active()): - self.evolve_generation() - - def active(self): - """Returns if the ga should terminate base on the termination implimented""" - # Send termination_impl the whole ga class - return self.termination_impl(self) - - - def evolve_generation(self, number_of_generations = 1): - """Evolves the ga the specified number of generations.""" - while(number_of_generations > 0): - # If its the first generation then initialize the population - if(self.current_generation == 0): - # Initialize the population - self.initialize_population() - # First get the fitness of the population - self.get_population_fitness(self.population.chromosomes) - # Selection - Triggers flags in the chromosome if its been selected - # self.selection_impl(self) - # Crossover - Takes the flagged chromosomes and crosses there genetic - # makup to make new offsprings. - # self.crossover_impl(self) - # Repopulate - Manipulates the population to some desired way - # self.repopulate_impl(self) - # Mutation - Manipulates the population very slightly - # self.mutation_impl(self) - - # Counter for the local number of generations in evolve_generation - number_of_generations -= 1 - # Add one to the current overall generation - self.current_generation += 1 - def make_gene(self,value): """Let's the user create a gene.""" return create_gene(value) diff --git a/src/crossover/README.md b/src/crossover/README.md deleted file mode 100644 index 92ad7d2..0000000 --- a/src/crossover/README.md +++ /dev/null @@ -1 +0,0 @@ -# Crossover function diff --git a/src/crossover/examples.py b/src/crossover/examples.py deleted file mode 100644 index 5b64d81..0000000 --- a/src/crossover/examples.py +++ /dev/null @@ -1,15 +0,0 @@ -class crossover_examples: - """ Crossover explination goes here. - - Points - Defined as sections between the chromosomes genetic makeup - """ - - def single_point_crossover(ga): - """Single point crossover is when a "point" is selected and the genetic - make up of the two parent chromosomes are "Crossed" or better known as swapped""" - pass - - def multi_point_crossover(ga,number_of_points = 2): - """Multi point crossover is when a specific number (More then one) of - "points" are created to merge the genetic makup of the chromosomes.""" - pass diff --git a/src/fitness_function/__init__.py b/src/fitness_function/__init__.py index f6294c2..9b676a7 100644 --- a/src/fitness_function/__init__.py +++ b/src/fitness_function/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT class name -from .examples import fitness_examples +from .methods import Fitness_methods diff --git a/src/fitness_function/examples.py b/src/fitness_function/methods.py similarity index 88% rename from src/fitness_function/examples.py rename to src/fitness_function/methods.py index ab964e8..0e8615e 100644 --- a/src/fitness_function/examples.py +++ b/src/fitness_function/methods.py @@ -1,13 +1,13 @@ -class fitness_examples: +class Fitness_methods: """Fitness function examples used""" - + def is_it_5(chromosome): """A very simple case test function - If the chromosomes gene value is a 5 add one to the chromosomes overall fitness value.""" # Overall fitness value fitness = 0 # For each gene in the chromosome - for gene in chromosome.genes: + for gene in chromosome.gene_list: # Check if its value = 5 if(gene.value == 5): # If its value is 5 then add one to diff --git a/src/fitness_function/test_examples.py b/src/fitness_function/test_examples.py deleted file mode 100644 index 1cfd756..0000000 --- a/src/fitness_function/test_examples.py +++ /dev/null @@ -1,12 +0,0 @@ -class test_fitness_funciton: - def get_fitness(self, chromosome): - # For every gene in chromosome - for i in range(len(chromosome.genes)): - # If the gene has a five then add one to the fitness - # Example -> Chromosome = [5],[2],[2],[5],[5] then fitness = 3 - if (chromosome.genes[i].get_value == 5): - # Add to the genes fitness - chromosome.genes[i].fitness += 1 - # Add to the chromosomes fitness - chromosome.fitness += 1 - return chromosome.fitness diff --git a/src/fitness_function/test_methods.py b/src/fitness_function/test_methods.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/fitness_function/test_methods.py @@ -0,0 +1 @@ + diff --git a/src/initialization/__init__.py b/src/initialization/__init__.py index c4790d1..2712c97 100644 --- a/src/initialization/__init__.py +++ b/src/initialization/__init__.py @@ -1,5 +1,5 @@ # FROM (. means local) file_name IMPORT function_name -from .examples import initialization_examples -from .population_structure.population import population -from .chromosome_structure.chromosome import chromosome -from .gene_structure.gene import gene +from .methods import Initialization_methods +from .population_structure.population import Population +from .chromosome_structure.chromosome import Chromosome +from .gene_structure.gene import Gene diff --git a/src/initialization/chromosome_structure/chromosome.py b/src/initialization/chromosome_structure/chromosome.py index aaec88f..c02c940 100644 --- a/src/initialization/chromosome_structure/chromosome.py +++ b/src/initialization/chromosome_structure/chromosome.py @@ -1,11 +1,11 @@ -class chromosome: +class Chromosome: - def __init__(self, genes = None): + def __init__(self, gene_list = None): """Initialize the chromosome based on input gene list, defaulted to an empty list""" - if genes is None: - self.genes = [] + if gene_list is None: + self.gene_list = [] else: - self.genes = genes + self.gene_list = gene_list # The fitness of the overal chromosome self.fitness = None # If the chromosome has been selected then the flag would switch to true @@ -14,16 +14,16 @@ class chromosome: def add_gene(self, gene, index = -1): """Add a gene to the chromosome at the specified index, defaulted to end of the chromosome""" if index == -1: - index = len(self.genes) - self.genes.insert(index, gene) + index = len(self.gene_list) + self.gene_list.insert(index, gene) def remove_gene(self, index): """Remove a gene from the chromosome at the specified index""" - del self.genes[index] + del self.gene_list[index] def get_genes(self): """Return all genes in the chromosome""" - return self.genes + return self.gene_list def get_fitness(self): """Return the fitness of the chromosome""" @@ -31,11 +31,11 @@ class chromosome: def set_gene(self, gene, index): """Set a gene at a specific index""" - self.genes[index] = gene + self.gene_list[index] = gene - def set_genes(self, genes): + def set_genes(self, gene_list): """Set the entire gene set of the chromosome""" - self.genes = genes + self.gene_list = gene_list def set_fitness(self, fitness): """Set the fitness value of the chromosome""" @@ -44,6 +44,6 @@ class chromosome: def __repr__(self): """Format the repr() output for the chromosome""" output_str = '' - for gene in self.genes: + for gene in self.gene_list: output_str += gene.__repr__() return output_str diff --git a/src/initialization/gene_structure/gene.py b/src/initialization/gene_structure/gene.py index 598b6dc..773b5c1 100644 --- a/src/initialization/gene_structure/gene.py +++ b/src/initialization/gene_structure/gene.py @@ -3,7 +3,7 @@ def check_gene(value): assert value != "" , "Gene can not be empty" return value -class gene: +class Gene: def __init__(self, value): """Initialize a gene with fitness of value None and the input value""" diff --git a/src/initialization/examples.py b/src/initialization/methods.py similarity index 60% rename from src/initialization/examples.py rename to src/initialization/methods.py index 9257b44..312580c 100644 --- a/src/initialization/examples.py +++ b/src/initialization/methods.py @@ -1,31 +1,31 @@ # Import the data structure -from .population_structure.population import population as create_population -from .chromosome_structure.chromosome import chromosome as create_chromosome -from .gene_structure.gene import gene as create_gene +from .population_structure.population import Population as create_population +from .chromosome_structure.chromosome import Chromosome as create_chromosome +from .gene_structure.gene import Gene as create_gene -class initialization_examples: +class Initialization_methods: """Initialization examples that are used as defaults and examples""" - def random_initialization(population_size, chromosome_length, chromosome_impl, gene_impl): + def random_initialization(ga): """Takes the initialization inputs and choregraphs them to output the type of population with the given parameters.""" # Create the population object population = create_population() # Fill the population with chromosomes - for i in range(population_size): + for i in range(ga.population_size): chromosome = create_chromosome() #Fill the Chromosome with genes - for j in range(chromosome_length): + for j in range(ga.chromosome_length): # Using the chromosome_impl to set every index inside of the chromosome - if chromosome_impl != None: + if ga.chromosome_impl != None: # Each chromosome location is specified with its own function - chromosome.add_gene(create_gene(chromosome_impl(j))) + chromosome.add_gene(create_gene(ga.chromosome_impl(j))) # Will break if chromosome_length != len(lists) in domain - elif gene_impl != None: + elif ga.gene_impl != None: # gene_impl = [range function,lowerbound,upperbound] - function = gene_impl[0] - chromosome.add_gene(create_gene(function(*gene_impl[1:]))) + function = ga.gene_impl[0] + chromosome.add_gene(create_gene(function(*ga.gene_impl[1:]))) else: #Exit because either were not specified print("Your domain or range were not specified") diff --git a/src/initialization/population_structure/population.py b/src/initialization/population_structure/population.py index 18c7e38..ec638bf 100644 --- a/src/initialization/population_structure/population.py +++ b/src/initialization/population_structure/population.py @@ -1,11 +1,11 @@ -class population: +class Population: - def __init__(self, chromosomes = None): + def __init__(self, chromosome_list = None): """Intiialize the population with fitness of value None, and a set of chromosomes dependant on user-passed parameter""" - if chromosomes is None: - self.chromosomes = [] + if chromosome_list is None: + self.chromosome_list = [] else: - self.chromosomes = chromosomes + self.chromosome_list = chromosome_list self.fitness = None def get_closet_fitness(self,value): @@ -15,42 +15,42 @@ class population: def add_chromosome(self, chromosome, index = -1): """Adds a chromosome to the population at the input index, defaulted to the end of the chromosome set""" if index == -1: - index = len(self.chromosomes) - self.chromosomes.insert(index, chromosome) + index = len(self.chromosome_list) + self.chromosome_list.insert(index, chromosome) def remove_chromosome(self, index): """removes a chromosome from the indicated index""" - del self.chromosomes[index] + del self.chromosome_list[index] def get_all_chromosomes(self): """returns all chromosomes in the population""" - return chromosomes + return chromosome_list def get_fitness(self): """returns the population's fitness""" return self.fitness - def set_all_chromosomes(self, chromosomes): + def set_all_chromosomes(self, chromosome_list): """sets the chromosome set of the population""" - self.chromosomes = chromosomes + self.chromosome_list = chromosome_list def set_chromosome(self, chromosome, index): """sets a specific chromosome at a specific index""" - self.chromosomes[index] = chromosome + self.chromosome_list[index] = chromosome def set_fitness(self, fitness): - """Sets the fitness value of the population""" + """Sets the fitness value of the population""" self.fitness = fitness def __repr__(self): """Sets the repr() output format""" - return ''.join([chromosome.__repr__() for chromosome in self.chromosomes]) + return ''.join([chromosome.__repr__() for chromosome in self.chromosome_list]) def print_all(self): """Prints information about the population in the following format:""" """Ex .Current population""" """Chromosome 1 - [gene][gene][gene][.etc] / Chromosome fitness - """ print("Current population:") - for index in range(len(self.chromosomes)): - print(f'Chromosome - {index} {self.chromosomes[index]}', end = "") - print(f' / Fitness = {self.chromosomes[index].fitness}') + for index in range(len(self.chromosome_list)): + print(f'Chromosome - {index} {self.chromosome_list[index]}', end = "") + print(f' / Fitness = {self.chromosome_list[index].fitness}') diff --git a/src/crossover/test_examples.py b/src/initialization/test_methods.py similarity index 100% rename from src/crossover/test_examples.py rename to src/initialization/test_methods.py diff --git a/src/mutation/__init__.py b/src/mutation/__init__.py index c7e2fa1..f74cc90 100644 --- a/src/mutation/__init__.py +++ b/src/mutation/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT function_name -from .examples import mutation_examples +from .methods import Mutation_methods diff --git a/src/mutation/examples.py b/src/mutation/examples.py deleted file mode 100644 index e97b9ff..0000000 --- a/src/mutation/examples.py +++ /dev/null @@ -1,3 +0,0 @@ -class mutation_examples: - """Selection examples will go here """ - pass diff --git a/src/mutation/methods.py b/src/mutation/methods.py new file mode 100644 index 0000000..f09b180 --- /dev/null +++ b/src/mutation/methods.py @@ -0,0 +1,3 @@ +class Mutation_methods: + """Mutation examples will go here """ + pass diff --git a/src/initialization/test_examples.py b/src/mutation/test_methods.py similarity index 100% rename from src/initialization/test_examples.py rename to src/mutation/test_methods.py diff --git a/src/selection/README.md b/src/parent_selection/README.md similarity index 100% rename from src/selection/README.md rename to src/parent_selection/README.md diff --git a/src/selection/__init__.py b/src/parent_selection/__init__.py similarity index 56% rename from src/selection/__init__.py rename to src/parent_selection/__init__.py index b5f82e4..8ecd200 100644 --- a/src/selection/__init__.py +++ b/src/parent_selection/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT function_name -from .examples import selection_examples +from .methods import Parent_methods diff --git a/src/parent_selection/methods.py b/src/parent_selection/methods.py new file mode 100644 index 0000000..b97811c --- /dev/null +++ b/src/parent_selection/methods.py @@ -0,0 +1,37 @@ +class Parent_methods: + """Selection defintion here""" + + def tournament_selection(ga,matchs): + """Tournament selection involves running several "tournaments" among a + few individuals (or "chromosomes")chosen at random from the population. + The winner of each tournament (the one with the best fitness) is selected + for crossover. + Ex + Chromsome 1----1 wins ------ + Chromsome 2---- - --1 wins---- + - - + Chromsome 3----3 wins ------ -- 5 Wins --->Chromosome 5 becomes Parent + Chromsome 4---- - + - + Chromsome 5----5 wins ---------5 wins---- + Chromsome 6---- + ^--Matchs--^ + """ + + def small_tournament(ga): + """ Small tournament is only one round of tournament. Beat the other + randomly selected chromosome and your are selected as a parent. + Chromosome 1---- + -- 1 wins -> Becomes selected for crossover. + Chromosome 2---- + """ + pass + + def roulette_selection(ga): + """Roulette selection works based off of how strong the fitness is of the + chromosomes in the population. The stronger the fitness the higher the probability + that it will be selected. Using the example of a casino roulette wheel. + Where the chromosomes are the numbers to be selected and the board size for + those numbers are directly proportional to the chromosome's current fitness. Where + the ball falls is a randomly generated number between 0 and 1""" + pass diff --git a/src/mutation/test_examples.py b/src/parent_selection/test_methods.py similarity index 100% rename from src/mutation/test_examples.py rename to src/parent_selection/test_methods.py diff --git a/src/selection/examples.py b/src/selection/examples.py deleted file mode 100644 index 2c149a7..0000000 --- a/src/selection/examples.py +++ /dev/null @@ -1,15 +0,0 @@ -class selection_examples: - """Selection defintion here""" - - def tournament_selection(): - """ """ - pass - - def roulette_selection(): - """Roulette selection works based off of how strong the fitness is of the - chromosomes in the population. The stronger the fitness the higher the probability - that it will be selected. Using the example of a casino roulette wheel. - Where the chromosomes are the numbers to be selected and the board size for - those numbers are directly proportional to the chromosome's current fitness. Where - the ball falls is a randomly generated number between 0 and 1""" - pass diff --git a/src/survivor_selection/README.md b/src/survivor_selection/README.md new file mode 100644 index 0000000..98253e9 --- /dev/null +++ b/src/survivor_selection/README.md @@ -0,0 +1 @@ +# Selection functions diff --git a/src/crossover/__init__.py b/src/survivor_selection/__init__.py similarity index 56% rename from src/crossover/__init__.py rename to src/survivor_selection/__init__.py index f9697e1..ea2e686 100644 --- a/src/crossover/__init__.py +++ b/src/survivor_selection/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT function_name -from .examples import crossover_examples +from .methods import Survivor_methods diff --git a/src/survivor_selection/methods.py b/src/survivor_selection/methods.py new file mode 100644 index 0000000..ad287b8 --- /dev/null +++ b/src/survivor_selection/methods.py @@ -0,0 +1,8 @@ +class Survivor_methods: + """Survivor methods defintion here""" + + def elitism(): + pass + + def remove_two_worst(): + pass diff --git a/src/selection/test_examples.py b/src/survivor_selection/test_methods.py similarity index 100% rename from src/selection/test_examples.py rename to src/survivor_selection/test_methods.py diff --git a/src/termination_point/__init__.py b/src/termination_point/__init__.py index 55fe7e1..92b7b26 100644 --- a/src/termination_point/__init__.py +++ b/src/termination_point/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT class name -from .examples import termination_examples +from .methods import Termination_methods diff --git a/src/termination_point/examples.py b/src/termination_point/methods.py similarity index 95% rename from src/termination_point/examples.py rename to src/termination_point/methods.py index 823757a..8f1aaa5 100644 --- a/src/termination_point/examples.py +++ b/src/termination_point/methods.py @@ -1,4 +1,4 @@ -class termination_examples: +class Termination_methods: """Example functions that can be used to terminate the the algorithms loop""" def fitness_based(ga): diff --git a/src/termination_point/test_examples.py b/src/termination_point/test_methods.py similarity index 100% rename from src/termination_point/test_examples.py rename to src/termination_point/test_methods.py