diff --git a/src/EasyGA.py b/src/EasyGA.py index cdc2c00..c7bfb9f 100644 --- a/src/EasyGA.py +++ b/src/EasyGA.py @@ -4,71 +4,75 @@ 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 +from fitness_function import Fitness_Examples +from initialization import Initialization_Methods +from termination_point import Termination_Methods # Population Methods -from survivor_selection import Survivor_methods +from selection import Selection_Methods # Manipulation Methods -from parent_selection import Parent_methods -from mutation import Mutation_methods -from crossover import Crossover_methods +from mutation import Mutation_Methods +from crossover import Crossover_Methods class GA: def __init__(self): """Initialize the GA.""" # Initilization variables - self.chromosome_length = 3 - self.population_size = 5 + self.chromosome_length = 10 + self.population_size = 150 self.chromosome_impl = None self.gene_impl = None self.population = None - # Termination varibles + self.target_fitness_type = 'maximum' + self.update_fitness = True + + # Selection variables + self.parent_ratio = 0.1 + self.selection_probablity = 0.95 + + # Termination variables self.current_generation = 0 - self.generation_goal = 3 + self.generation_goal = 50 self.current_fitness = 0 - self.fitness_goal = 3 + self.generation_goal = 250 + self.fitness_goal = 9 + # Mutation variables - self.mutation_rate = 0.03 + self.mutation_rate = 0.10 - # Rerun already computed fitness - self.update_fitness = False - - # Defualt EastGA implimentation structure - self.initialization_impl = Initialization_methods.random_initialization - self.fitness_funciton_impl = Fitness_methods.is_it_5 + # Default EasyGA implimentation structure + self.initialization_impl = Initialization_Methods().random_initialization + self.fitness_function_impl = Fitness_Examples().index_dependent_values # Selects which chromosomes should be automaticly moved to the next population - #self.survivor_selection_impl = Survivor_methods. + self.survivor_selection_impl = Selection_Methods().Survivor_Selection().remove_two_worst # Methods for accomplishing parent-selection -> Crossover -> Mutation - # self.parent_selection_impl = Parent_methods.roulette_selection - #self.crossover_impl = Crossover_methods. - #self.mutation_impl = Mutation_methods. + self.parent_selection_impl = Selection_Methods().Parent_Selection().Roulette().roulette_selection + self.crossover_impl = Crossover_Methods().single_point_crossover + self.mutation_impl = Mutation_Methods().per_gene_mutation # The type of termination to impliment - self.termination_impl = Termination_methods.generation_based + self.termination_impl = Termination_Methods().generation_based + - def evolve_generation(self, number_of_generations = 1): + def evolve_generation(self, number_of_generations = 1, consider_termination = True): """Evolves the ga the specified number of generations.""" - while(number_of_generations > 0): + while(number_of_generations > 0 and (consider_termination == False or self.termination_impl(self))): # If its the first generation then initialize the population - if(self.current_generation == 0): - # Initialize the population + if self.current_generation == 0: 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) - # self.parent_selection_impl(self) - # Counter for the local number of generations in evolve_generation + self.set_all_fitness(self.population.chromosome_list) + self.population.set_all_chromosomes(self.sort_by_best_fitness()) + else: + self.parent_selection_impl(self) + next_population = self.crossover_impl(self) + next_population = self.survivor_selection_impl(self, next_population) + next_population.set_all_chromosomes(self.mutation_impl(self, next_population.get_all_chromosomes())) + + self.population = next_population + self.set_all_fitness(self.population.chromosome_list) + self.population.set_all_chromosomes(self.sort_by_best_fitness()) + number_of_generations -= 1 - # Add one to the current overall generation + self.current_generation += 1 def evolve(self): @@ -87,18 +91,38 @@ class GA: implimentation that is currently set""" self.population = self.initialization_impl(self) - def get_population_fitness(self,population): + def set_all_fitness(self,chromosome_set): """Will get and set the fitness of each chromosome in the population. If update_fitness is set then all fitness values are updated. Otherwise only fitness values set to None (i.e. uninitialized fitness values) are updated.""" # Get each chromosome in the population - for chromosome in population: - # If the fitness is not set then get its fitness or if allways getting - # fitness is turn on then always get the fitness of the chromosome. + + for chromosome in chromosome_set: if(chromosome.fitness == None or self.update_fitness == True): # Set the chromosomes fitness using the fitness function - chromosome.fitness = self.fitness_funciton_impl(chromosome) + chromosome.set_fitness(self.fitness_function_impl(chromosome)) + + def sort_by_best_fitness(self, chromosome_set = None): + + if chromosome_set == None: + chromosome_set = self.population.get_all_chromosomes() + + chromosome_set_temp = chromosome_set + not_sorted_check = 0 + while (not_sorted_check != len(chromosome_set_temp)): + not_sorted_check = 0 + for i in range(len(chromosome_set_temp)): + if ((i + 1 < len(chromosome_set_temp)) and (chromosome_set_temp[i + 1].fitness > chromosome_set_temp[i].fitness)): + temp = chromosome_set[i] + chromosome_set_temp[i] = chromosome_set[i + 1] + chromosome_set_temp[i + 1] = temp + else: + not_sorted_check += 1 + + chromosome_set = chromosome_set_temp + + return chromosome_set def make_gene(self,value): """Let's the user create a gene.""" diff --git a/src/crossover/__init__.py b/src/crossover/__init__.py index c722c52..417b9f4 100644 --- a/src/crossover/__init__.py +++ b/src/crossover/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT function_name -from .methods import Crossover_methods +from .crossover_methods import Crossover_Methods diff --git a/src/crossover/crossover_methods.py b/src/crossover/crossover_methods.py new file mode 100644 index 0000000..48e55bf --- /dev/null +++ b/src/crossover/crossover_methods.py @@ -0,0 +1,37 @@ +import random +from initialization.chromosome_structure.chromosome import Chromosome +from initialization.population_structure.population import Population + +class Crossover_Methods: + """ Crossover explination goes here. + + Points - Defined as sections between the chromosomes genetic makeup + """ + def __init__(self): + pass + + def single_point_crossover(self, 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""" + + crossover_pool = ga.population.mating_pool + + new_population = Population() + for i in range(len(crossover_pool)): + if i + 1 < len(crossover_pool): + new_gene_set = [] + parent_one = crossover_pool[i].get_genes() + parent_two = crossover_pool[i+1].get_genes() + #halfway_point = int(ga.chromosome_length/2) + split_point = random.randint(0,ga.chromosome_length) + new_gene_set.extend(parent_one[0:split_point]) + new_gene_set.extend(parent_two[split_point:]) + new_chromosome = Chromosome(new_gene_set) + new_population.add_chromosome(new_chromosome) + + return new_population + + def multi_point_crossover(self, 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/crossover/test_examples.py b/src/crossover/test_examples.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fitness_function/__init__.py b/src/fitness_function/__init__.py index 9b676a7..c1736e7 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 .methods import Fitness_methods +from .fitness_examples import Fitness_Examples diff --git a/src/fitness_function/fitness_examples.py b/src/fitness_function/fitness_examples.py new file mode 100644 index 0000000..1354e9e --- /dev/null +++ b/src/fitness_function/fitness_examples.py @@ -0,0 +1,28 @@ +class Fitness_Examples: + """Fitness function examples used""" + def is_it_5(self, 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.gene_list: + # Check if its value = 5 + if(gene.value == 5): + # If its value is 5 then add one to + # the overal fitness of the chromosome. + fitness += 1 + + return fitness + + def index_dependent_values(self, 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 i in range(len(chromosome.gene_list)): + if (chromosome.gene_list[i].value == i+1): + fitness += 1 + + return fitness diff --git a/src/fitness_function/test_examples.py b/src/fitness_function/test_examples.py new file mode 100644 index 0000000..1cfd756 --- /dev/null +++ b/src/fitness_function/test_examples.py @@ -0,0 +1,12 @@ +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/initialization/__init__.py b/src/initialization/__init__.py index 2712c97..0156465 100644 --- a/src/initialization/__init__.py +++ b/src/initialization/__init__.py @@ -1,5 +1,3 @@ # FROM (. means local) file_name IMPORT function_name -from .methods import Initialization_methods -from .population_structure.population import Population -from .chromosome_structure.chromosome import Chromosome -from .gene_structure.gene import Gene +from .initialization_methods import Initialization_Methods + diff --git a/src/initialization/chromosome_structure/chromosome.py b/src/initialization/chromosome_structure/chromosome.py index c02c940..47afaee 100644 --- a/src/initialization/chromosome_structure/chromosome.py +++ b/src/initialization/chromosome_structure/chromosome.py @@ -1,12 +1,10 @@ class Chromosome: - def __init__(self, gene_list = None): - """Initialize the chromosome based on input gene list, defaulted to an empty list""" if gene_list is None: self.gene_list = [] else: - self.gene_list = gene_list - # The fitness of the overal chromosome + self.gene_list = genes + self.fitness = None # If the chromosome has been selected then the flag would switch to true self.selected = False @@ -18,11 +16,9 @@ class Chromosome: self.gene_list.insert(index, gene) def remove_gene(self, index): - """Remove a gene from the chromosome at the specified index""" del self.gene_list[index] def get_genes(self): - """Return all genes in the chromosome""" return self.gene_list def get_fitness(self): @@ -30,12 +26,10 @@ class Chromosome: return self.fitness def set_gene(self, gene, index): - """Set a gene at a specific index""" self.gene_list[index] = gene - def set_genes(self, gene_list): - """Set the entire gene set of the chromosome""" - self.gene_list = gene_list + def set_genes(self, genes): + self.gene_list = genes def set_fitness(self, fitness): """Set the fitness value of the chromosome""" diff --git a/src/initialization/gene_creation/gene_random.py b/src/initialization/gene_creation/gene_random.py new file mode 100644 index 0000000..dbcc874 --- /dev/null +++ b/src/initialization/gene_creation/gene_random.py @@ -0,0 +1,13 @@ +# Imported library +import random + +def check_values(low,high): + #Check to make sure its not less then zero + assert low > 0 , "The random gene low can not be less then zero" + # Check to make sure the high value is not + # lower than or equal to low and not 0. + assert high > low , "High value can not be smaller then low value" + assert high != 0, "High value can not be zero" + +def random_gene(): + return random.randint(1,100) diff --git a/src/initialization/gene_structure/gene.py b/src/initialization/gene_structure/gene.py index 773b5c1..04ecb53 100644 --- a/src/initialization/gene_structure/gene.py +++ b/src/initialization/gene_structure/gene.py @@ -22,7 +22,7 @@ class Gene: """Set fitness of the gene""" self.fitness = fitness - def set_value(self): + def set_value(self, value): """Set value of the gene""" self.value = value diff --git a/src/initialization/initialization_methods.py b/src/initialization/initialization_methods.py new file mode 100644 index 0000000..5ede298 --- /dev/null +++ b/src/initialization/initialization_methods.py @@ -0,0 +1,32 @@ +# 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 + +class Initialization_Methods: + """Initialization examples that are used as defaults and examples""" + + def random_initialization(self, 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(ga.population_size): + chromosome = create_chromosome() + #Fill the Chromosome with genes + for j in range(ga.chromosome_length): + # Using the chromosome_impl to set every index inside of the chromosome + if ga.chromosome_impl != None: + # Each chromosome location is specified with its own function + chromosome.add_gene(create_gene(ga.chromosome_impl(j))) + # Will break if chromosome_length != len(lists) in domain + elif ga.gene_impl != None: + function = ga.gene_impl[0] + chromosome.add_gene(create_gene(function(*ga.gene_impl[1:]))) + else: + #Exit because either were not specified + print("You did not specify any initialization constraints.") + population.add_chromosome(chromosome) + return population diff --git a/src/initialization/population_structure/population.py b/src/initialization/population_structure/population.py index ec638bf..98f5518 100644 --- a/src/initialization/population_structure/population.py +++ b/src/initialization/population_structure/population.py @@ -1,5 +1,4 @@ class Population: - 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 chromosome_list is None: @@ -7,6 +6,7 @@ class Population: else: self.chromosome_list = chromosome_list self.fitness = None + self.mating_pool = [] def get_closet_fitness(self,value): """Get the chomosome that has the closets fitness to the value defined""" @@ -24,18 +24,18 @@ class Population: def get_all_chromosomes(self): """returns all chromosomes in the population""" - return chromosome_list + return self.chromosome_list def get_fitness(self): """returns the population's fitness""" return self.fitness - def set_all_chromosomes(self, chromosome_list): - """sets the chromosome set of the population""" - self.chromosome_list = chromosome_list + def set_all_chromosomes(self, chromosomes): + self.chromosome_list = chromosomes - def set_chromosome(self, chromosome, index): - """sets a specific chromosome at a specific index""" + def set_chromosome(self, chromosome, index = -1): + if index == -1: + index = len(self.chromosomes)-1 self.chromosome_list[index] = chromosome def set_fitness(self, fitness): @@ -43,8 +43,8 @@ class Population: self.fitness = fitness def __repr__(self): - """Sets the repr() output format""" - return ''.join([chromosome.__repr__() for chromosome in self.chromosome_list]) + for index in range(len(self.chromosomes)): + return f'{self.chromosome_list[index]}' def print_all(self): """Prints information about the population in the following format:""" diff --git a/src/initialization/test_examples.py b/src/initialization/test_examples.py new file mode 100644 index 0000000..e69de29 diff --git a/src/mutation/__init__.py b/src/mutation/__init__.py index f74cc90..c0fabea 100644 --- a/src/mutation/__init__.py +++ b/src/mutation/__init__.py @@ -1,2 +1,2 @@ # FROM (. means local) file_name IMPORT function_name -from .methods import Mutation_methods +from .mutation_methods import Mutation_Methods diff --git a/src/mutation/mutation_methods.py b/src/mutation/mutation_methods.py new file mode 100644 index 0000000..99181ed --- /dev/null +++ b/src/mutation/mutation_methods.py @@ -0,0 +1,42 @@ +import random + +class Mutation_Methods: + + def __init__(self): + pass + + def random_mutation(self, ga, chromosome_set = None): + + if chromosome_set == None: + chromosome_set = ga.population.get_all_chromosomes() + + chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate) + temp_population = ga.initialization_impl(ga) + + while chromosome_mutate_num > 0: + chromosome_set[random.randint(0,ga.population_size-1)] = temp_population.get_all_chromosomes()[chromosome_mutate_num] + chromosome_mutate_num -= 1 + + return chromosome_set + + def per_gene_mutation(self, ga, chromosome_set = None, gene_mutate_count = 1): + + gene_mutate_count_static = int(gene_mutate_count) + + if chromosome_set == None: + chromosome_set = ga.population.get_all_chromosomes() + + for i in range(len(chromosome_set)): + random_num = random.uniform(0,1) + + if (random_num <= ga.mutation_rate): + while gene_mutate_count > 0: + dummy_population = ga.initialization_impl(ga) #Really inefficient, but works for now + random_index = random.randint(0, ga.chromosome_length-1) + chromosome_set[i].get_genes()[random_index] = dummy_population.get_all_chromosomes()[random.randint(0,ga.population_size-1)].get_genes()[random_index] + gene_mutate_count -= 1 + gene_mutate_count = int(gene_mutate_count_static) + + return chromosome_set + + diff --git a/src/mutation/test_examples.py b/src/mutation/test_examples.py new file mode 100644 index 0000000..e69de29 diff --git a/src/new_initialization_method_testing.py b/src/new_initialization_method_testing.py new file mode 100644 index 0000000..f4d84db --- /dev/null +++ b/src/new_initialization_method_testing.py @@ -0,0 +1,36 @@ +import EasyGA +import random + +#1. GA should take in range for gene input +#2. GA should take in index-dependent range for gene input +#3. GA should take in domain input +#4. GA should take in index-dependent domain for gene input +#5. GA should accept mix of range and domain for gene input + + +# Create the Genetic algorithm +ga = EasyGA.GA() + +test_gene_input = [["left", "right"],[1,100],[5.0,10],[22,"up"]] +ga.gene_input_type[1] = "float-range" +ga.gene_input_type[2] = "domain" + +ga.initialize(test_gene_input) +ga.population.print_all() + + +#Example tests +#Note, the following examples assume a chromosome length of 4. +#if the test_gene_input is longer than the chromosomes, it will get truncated at the length of the chromosome +#for example, for chromosomes with length 2, [["left", "right"],[1,100],[5.0,10],[22,"up"]] becomes [["left", "right"],[1,100]] +#if the test_gene_input is shorter than the chromosomes, the remaining elements will be populated with None + +#test_gene_input = [1,100] +#test_gene_input = [["left", "right"],[1,100],[5.0,10],[22,"up"]] +#test_gene_input = ["left", "right", "up", "down"] +#test_gene_input = [[1,100],[0,1],[33,35],[5,6]] +#test_gene_input = [["left", "right"], ["up", "down"], ["left", "down"], ["down", "right"]] + +#ga.gene_input_type = "float-range" +#ga.gene_input_type[1] = "domain" +#ga.gene_input_type[1] = "float-range" \ No newline at end of file diff --git a/src/run_testing.py b/src/run_testing.py index acc5f86..390986b 100644 --- a/src/run_testing.py +++ b/src/run_testing.py @@ -1,16 +1,15 @@ import EasyGA import random + + # Create the Genetic algorithm ga = EasyGA.GA() -ga.chromosome_length = 3 -ga.max_generations = 5 -# If the user wants to use a domain -ga.gene_impl = [random.randrange,1,10] -ga.generation = 36 -# Run Everyhting +ga.gene_impl = [random.randrange,1,100] + +# Run Everything ga.evolve() # Print the current population diff --git a/src/selection/__init__.py b/src/selection/__init__.py new file mode 100644 index 0000000..9c90847 --- /dev/null +++ b/src/selection/__init__.py @@ -0,0 +1,2 @@ +# FROM (. means local) file_name IMPORT function_name +from .selection_methods import Selection_Methods diff --git a/src/selection/selection_methods.py b/src/selection/selection_methods.py new file mode 100644 index 0000000..c8476a6 --- /dev/null +++ b/src/selection/selection_methods.py @@ -0,0 +1,95 @@ +import random +from initialization.chromosome_structure.chromosome import Chromosome as create_chromosome +from initialization.gene_structure.gene import Gene as create_gene +from initialization.population_structure.population import Population +from initialization.chromosome_structure.chromosome import Chromosome + +class Selection_Methods: + """Selection is the process by which chromosomes are selected for crossover and eventually, influence the next generation of chromosomes.""" + def __init__(self): + pass + + class Parent_Selection: + class Tournament: + def with_replacement(self, ga): + tournament_size = int(len(ga.population.get_all_chromosomes())*ga.parent_ratio/10) + if tournament_size < 3: + tournament_size = int(len(ga.population.get_all_chromosomes())*ga.parent_ratio/3) + + # Probability used for determining if a chromosome should enter the mating pool. + selection_probability = ga.selection_probability + + # Repeat tournaments until the mating pool is large enough. + while (len(ga.population.mating_pool) < len(ga.population.get_all_chromosomes())*ga.parent_ratio): + + # Generate a random tournament group and sort by fitness. + tournament_group = ga.sort_by_best_fitness([random.choice(ga.population.get_all_chromosomes()) for n in range(tournament_size)]) + + # For each chromosome, add it to the mating pool based on its rank in the tournament. + for index in range(tournament_size): + # Probability required is selection_probability * (1-selection_probability) ^ (tournament_size-index+1) + # e.g. top ranked fitness has probability: selection_probability + # second ranked fitness has probability: selection_probability * (1-selection_probability) + # third ranked fitness has probability: selection_probability * (1-selection_probability)^2 + # etc. + if random.uniform(0, 1) < selection_probability * pow(1-selection_probability, index+1): + ga.population.mating_pool.append(tournament_group[index]) + + class Roulette: + def roulette_selection(self, 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""" + total_fitness = sum(ga.population.chromosome_list[i].get_fitness() for i in range(len(ga.population.chromosome_list))) + rel_fitnesses = [] + + for chromosome in ga.population.chromosome_list: + if (total_fitness != 0): + rel_fitnesses.append(float(chromosome.fitness)/total_fitness) + + probability = [sum(rel_fitnesses[:i+1]) for i in range(len(rel_fitnesses))] + + while (len(ga.population.mating_pool) < len(ga.population.get_all_chromosomes())*ga.parent_ratio): + rand_number = random.random() + + # Loop through the list of probabilities + for i in range(len(probability)): + # If the probability is greater than the random_number, then select that chromosome + if (probability[i] >= rand_number): + ga.population.mating_pool.append(ga.population.chromosome_list[i]) + # print (f'Selected chromosome : {i}') + break + + class Survivor_Selection: + def repeated_crossover(self, ga, next_population): #Might be cheating? I don't know honestly - RG + while len(next_population.get_all_chromosomes()) < ga.population_size: + crossover_pool = ga.population.mating_pool + + split_point = random.randint(0,ga.chromosome_length) + chromosome_list = [] + for i in range(len(crossover_pool)): + if i + 1 < len(crossover_pool): + new_gene_set = [] + parent_one = crossover_pool[i].get_genes() + parent_two = crossover_pool[i+1].get_genes() + new_gene_set.extend(parent_one[0:split_point]) + new_gene_set.extend(parent_two[split_point:]) + new_chromosome = create_chromosome(new_gene_set) + chromosome_list.append(new_chromosome) + + + for i in range(len(chromosome_list)): + next_population.add_chromosome(chromosome_list[i]) + if len(next_population.get_all_chromosomes()) >= ga.population_size: + break + return next_population + + def remove_two_worst(self, ga, next_population): + iterator = 0 + while len(next_population.get_all_chromosomes()) < ga.population_size: + next_population.add_chromosome(ga.population.get_all_chromosomes()[iterator]) + iterator += 1 + return next_population diff --git a/src/selection/test_examples.py b/src/selection/test_examples.py new file mode 100644 index 0000000..e69de29 diff --git a/src/termination_point/__init__.py b/src/termination_point/__init__.py index 92b7b26..9eb2097 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 .methods import Termination_methods +from .termination_methods import Termination_Methods diff --git a/src/termination_point/termination_methods.py b/src/termination_point/termination_methods.py new file mode 100644 index 0000000..493f02d --- /dev/null +++ b/src/termination_point/termination_methods.py @@ -0,0 +1,21 @@ +class Termination_Methods: + """Example functions that can be used to terminate the the algorithms loop""" + + def fitness_based(self, ga): + """Fitness based approach to terminate when the goal fitness has been reached""" + + status = True + if ga.population == None: + return status + for i in range(len(ga.population.get_all_chromosomes())): + if(ga.population.get_all_chromosomes()[i].fitness >= ga.fitness_goal): + status = False + break + return status + + def generation_based(self, ga): + """Generation based approach to terminate when the goal generation has been reached""" + status = True + if(ga.current_generation > ga.generation_goal): + status = False + return status diff --git a/src/termination_point/test_examples.py b/src/termination_point/test_examples.py new file mode 100644 index 0000000..e69de29