From 5821e709a34bc4ca9ac4ebced55d4690904d0259 Mon Sep 17 00:00:00 2001 From: RyleyGG Date: Fri, 25 Sep 2020 01:15:53 -0400 Subject: [PATCH] New Initialization Method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a test implementation of a potential new initialization method. A testing file - new_initialization_method_testing.py - is included to allow for quick testing. In summary here is are the major points: 1) Two new attributes of GA were created - gene_input and gene_input_type. gene_input holds the user's custom range(s)/domain(s) after it gets passed to the initialize() function. gene_input_type holds an array with the same length as the chromosomes that holds the input type of the user's gene_input on a gene-by-gene basis. It does this in the same exact way that index-dependent gene ranges/domains are handled. By making the gene_input_type array the same size as the chromosome, the elements can be paired very easily. The acceptable values for this are either "range" or "domain". With a range, any value between the two can be generated; with domain, only the two elements included can be selected from randomly. 2) As mentioned in change 1, the user now has to pass their range(s)/domain(s) to the initialize() function. 3) The package is capable of implicitly determining if a certain input from the user is a range or domain. Strings can only ever be a domain – if given an element that only includes integers, the program assumes range. 4) If the user wishes to use numbers only as a domain, they can specify this by directly interacting with the ga.gene_input_type (or through a setter function). 5) the initialize() function in the GA object determines the implicit range/domain assignments if the user doesn’t do so themselves. 6) The random_initialization() function is effectively the same, except there is now an if/else to determine if the user is using the built-in gene creation function or not. If they are, then pass the gene_input, gene_input_type, and current gene index as arguments to the gene function. If they are using their own function, random_initialization() functions exactly the same way as it does in the current master branch. 7) Based on all the settings mentioned above, the random_gene() function will create a value before passing it back to random_initialization(). --- src/EasyGA.py | 33 ++++++++++++++++- .../gene_creation/gene_random.py | 13 +++++++ .../gene_function/gene_random.py | 20 ++++++++-- src/initialization/random_initialization.py | 37 +++++++++++++------ src/new_initialization_method_testing.py | 18 +++++++++ 5 files changed, 105 insertions(+), 16 deletions(-) create mode 100644 src/initialization/gene_creation/gene_random.py create mode 100644 src/new_initialization_method_testing.py diff --git a/src/EasyGA.py b/src/EasyGA.py index ef9dff8..75b7986 100644 --- a/src/EasyGA.py +++ b/src/EasyGA.py @@ -19,6 +19,8 @@ class GA: self.mutation_rate = 0.03 # Defualt EastGA implimentation structure self.gene_function_impl = random_gene + self.gene_input = [] + self.gene_input_type = [] #What if user gives two numbers (i.e. [1,100]) but wants to pick between the two (domain)? # Set the GA Configuration self.initialization_impl = random_initialization #self.mutation_impl = PerGeneMutation(Mutation_rate) @@ -28,12 +30,39 @@ class GA: #self.evaluation_impl = TestEvaluation() - def initialize(self): + def initialize(self, gene_input): + self.gene_input = gene_input + + #assuming domain if string (strings can never be range) + if self.gene_input_type == []: + for x in range(len(self.gene_input)): + if (isinstance(self.gene_input[x], list)): + for y in range(len(self.gene_input[x])): + if isinstance(gene_input[x][y], str): + self.gene_input_type.append("domain") + break + elif y == (len(self.gene_input[x]) -1): + self.gene_input_type.append("range") + else: + if isinstance(gene_input[x], str): + self.gene_input_type.append("domain") + else: + if isinstance(gene_input[x], int): + self.gene_input[x] = [self.gene_input[x], self.gene_input[x]] + self.gene_input_type.append("range") + + #If length doesn't correspond to chromosome, update here + while len(self.gene_input_type) != self.chromosome_length: + self.gene_input_type.append(self.gene_input_type[len(self.gene_input_type)-1]) + # Create the first population self.population = self.initialization_impl( self.population_size, self.chromosome_length, - self.gene_function_impl) + self.gene_function_impl, + self.gene_input, + self.gene_input_type) + def evolve(): # If you just want to evolve through all generations 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_function/gene_random.py b/src/initialization/gene_function/gene_random.py index dbcc874..d3e16dd 100644 --- a/src/initialization/gene_function/gene_random.py +++ b/src/initialization/gene_function/gene_random.py @@ -6,8 +6,22 @@ def check_values(low,high): 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 > 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) +def random_gene(gene_input, gene_input_type, gene_index): + + created_gene = None + #Determining if single range/domain or index-dependent + if isinstance(gene_input[0], list): + if gene_input_type[gene_index] == "range": + created_gene = random.randint(gene_input[gene_index][0], gene_input[gene_index][1]) + elif gene_input_type[gene_index] == "domain": + created_gene = random.choice(gene_input[gene_index]) + else: + if gene_input_type[gene_index] == "range": + created_gene = random.randint(gene_input[0], gene_input[1]) + elif gene_input_type[gene_index] == "domain": + created_gene = random.choice(gene_input) + + return created_gene diff --git a/src/initialization/random_initialization.py b/src/initialization/random_initialization.py index cdef3ef..72cfbfa 100644 --- a/src/initialization/random_initialization.py +++ b/src/initialization/random_initialization.py @@ -2,15 +2,30 @@ 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 .gene_function.gene_random import random_gene as random_gene -def random_initialization(chromosome_length,population_size,gene_function): - # Create the population object - population = create_population() - # Fill the population with chromosomes - for i in range(population_size): - chromosome = create_chromosome() - #Fill the Chromosome with genes - for j in range(chromosome_length): - chromosome.add_gene(create_gene(gene_function())) - population.add_chromosome(chromosome) - return population +def random_initialization(chromosome_length,population_size,gene_function,gene_input,gene_input_type): + + if gene_function == random_gene: + # Create the population object + population = create_population() + # Fill the population with chromosomes + for i in range(population_size): + chromosome = create_chromosome() + #Fill the Chromosome with genes + for j in range(chromosome_length-1): + chromosome.add_gene(create_gene(gene_function(gene_input, gene_input_type, j))) + population.add_chromosome(chromosome) + return population + + else: #For user input gene-function, don't do anything with gene_input parameter + # Create the population object + population = create_population() + # Fill the population with chromosomes + for i in range(population_size): + chromosome = create_chromosome() + #Fill the Chromosome with genes + for j in range(chromosome_length): + chromosome.add_gene(create_gene(gene_function())) + population.add_chromosome(chromosome) + return population \ No newline at end of file diff --git a/src/new_initialization_method_testing.py b/src/new_initialization_method_testing.py new file mode 100644 index 0000000..8687dd0 --- /dev/null +++ b/src/new_initialization_method_testing.py @@ -0,0 +1,18 @@ +import EasyGA +import random + +# Create the Genetic algorithm +ga = EasyGA.GA() +test_range_two = [["left", "right"],[22,88],5,[22,"up"]] +ga.initialize(test_range_two) +ga.population.print_all() + + + + +#test_range_one = [1,100] +#test_domain_one = ["left", "right", "up", "down"] +#test_range_two = [[1,100],[0,1],[33,35],[5,6]] +#test_domain_two = [["left", "right"], ["up", "down"], ["left", "down"], ["down", "right"]] + +#for index-specific bounds, do list of lists i.e. test_range = [[1, 100], [1, 25], [5, 25]] \ No newline at end of file