diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1 @@ + diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index cc2fdc5..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,19 +0,0 @@ -graft docs -graft src -graft ci -graft tests - -include .bumpversion.cfg -include .coveragerc -include .cookiecutterrc -include .editorconfig - -include AUTHORS.rst -include CHANGELOG.rst -include CONTRIBUTING.rst -include LICENSE -include README.rst - -include tox.ini .travis.yml .appveyor.yml .readthedocs.yml .pre-commit-config.yaml - -global-exclude *.py[cod] __pycache__/* *.so *.dylib diff --git a/README.md b/README.md index a6b9de2..4624399 100644 --- a/README.md +++ b/README.md @@ -25,37 +25,7 @@ ga.evolve() Put the out here ``` -## Customized: -```python -import random -import EasyGA -# Create the Genetic algorithm -ga = EasyGA.GA() - -# Makes a new gene -new_gene = ga.make_gene("HelloWorld") -# Makes a chromosome to store genes in -new_chromosome = ga.make_chromosome() -# Makes a Population to store chromosomes in -new_population = ga.make_population() - -ga.initialize() - -print(ga.population) - -for chromosome in ga.population.chromosomes: - print(chromosome.genes[0].__dict__) -``` - -### Output: -```python - -{'fitness': None, 'value': 47} -{'fitness': None, 'value': 4} -{'fitness': None, 'value': 68} -{'fitness': None, 'value': 57} -``` # How Testing works diff --git a/setup.py b/setup.py index 157dce4..2983dfa 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,21 @@ -from setuptools import setup +from setuptools import setup, find_packages with open("README.md", "r") as fh: long_description = fh.read() + setup( name='EasyGA', - version='0.0.8', + version='0.0.25', description='A ubiquitous or general purpuse GA', py_modules=["EasyGA"], - package_dir={'':'src'}, + packages=find_packages(where='EasyGA'), + package_dir={ + '': 'EasyGA', + }, python_requires='>=3.6', url="https://github.com/danielwilczak101/EasyGA", - author="Daniel Wilczak", + author="Daniel Wilczak, Jack RyanNguyen, Ryley Griffith, Jared Curtis, Matthew Chase Oxamendi", author_email="danielwilczak101@gmail.com", long_description = long_description, long_description_content_type = "text/markdown", diff --git a/src/EasyGA.py b/src/EasyGA.py index 575d5b3..c7bfb9f 100644 --- a/src/EasyGA.py +++ b/src/EasyGA.py @@ -72,6 +72,7 @@ class GA: self.population.set_all_chromosomes(self.sort_by_best_fitness()) number_of_generations -= 1 + self.current_generation += 1 def evolve(self): @@ -124,10 +125,13 @@ class GA: return chromosome_set def make_gene(self,value): + """Let's the user create a gene.""" return create_gene(value) def make_chromosome(self): + """Let's the user create a chromosome.""" return create_chromosome() def make_population(self): + """Let's the user create a population.""" return create_population() diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..6e90f58 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,3 @@ +import EasyGA +import run_testing +import test_EasyGA diff --git a/src/crossover/README.md b/src/crossover/README.md index 92ad7d2..c38d93c 100644 --- a/src/crossover/README.md +++ b/src/crossover/README.md @@ -1 +1 @@ -# Crossover function +# Mutation functions diff --git a/src/crossover/methods.py b/src/crossover/methods.py new file mode 100644 index 0000000..eb81ec7 --- /dev/null +++ b/src/crossover/methods.py @@ -0,0 +1,3 @@ +class Crossover_methods: + """Mutation examples will go here """ + pass diff --git a/src/crossover/test_crossover.py b/src/crossover/test_methods.py similarity index 100% rename from src/crossover/test_crossover.py rename to src/crossover/test_methods.py diff --git a/src/fitness_function/methods.py b/src/fitness_function/methods.py new file mode 100644 index 0000000..0e8615e --- /dev/null +++ b/src/fitness_function/methods.py @@ -0,0 +1,16 @@ +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.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 diff --git a/src/fitness_function/test_fitness_function.py b/src/fitness_function/test_fitness_function.py deleted file mode 100644 index 1cfd756..0000000 --- a/src/fitness_function/test_fitness_function.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 c293145..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 .initialization_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/mutation/test_mutation.py b/src/initialization/chromosome_structure/__init__.py similarity index 100% rename from src/mutation/test_mutation.py rename to src/initialization/chromosome_structure/__init__.py diff --git a/src/initialization/chromosome_structure/chromosome.py b/src/initialization/chromosome_structure/chromosome.py index f9e16e6..47afaee 100644 --- a/src/initialization/chromosome_structure/chromosome.py +++ b/src/initialization/chromosome_structure/chromosome.py @@ -1,13 +1,16 @@ class Chromosome: - - def __init__(self, genes = None): - if genes is None: + def __init__(self, gene_list = None): + if gene_list is None: self.gene_list = [] else: self.gene_list = genes + self.fitness = None + # If the chromosome has been selected then the flag would switch to true + self.selected = False 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.gene_list) self.gene_list.insert(index, gene) @@ -19,6 +22,7 @@ class Chromosome: return self.gene_list def get_fitness(self): + """Return the fitness of the chromosome""" return self.fitness def set_gene(self, gene, index): @@ -28,9 +32,11 @@ class Chromosome: self.gene_list = genes def set_fitness(self, fitness): + """Set the fitness value of the chromosome""" self.fitness = fitness def __repr__(self): + """Format the repr() output for the chromosome""" output_str = '' for gene in self.gene_list: output_str += gene.__repr__() diff --git a/src/test_EasyGA.py b/src/initialization/gene_structure/__init__.py similarity index 100% rename from src/test_EasyGA.py rename to src/initialization/gene_structure/__init__.py diff --git a/src/initialization/gene_structure/gene.py b/src/initialization/gene_structure/gene.py index bd13b54..04ecb53 100644 --- a/src/initialization/gene_structure/gene.py +++ b/src/initialization/gene_structure/gene.py @@ -6,16 +6,20 @@ def check_gene(value): class Gene: def __init__(self, value): + """Initialize a gene with fitness of value None and the input value""" self.fitness = None self.value = check_gene(value) def get_fitness(self): + """Return fitness of the gene""" return self.fitness def get_value(self): + """Return value of the gene""" return self.value def set_fitness(self, fitness): + """Set fitness of the gene""" self.fitness = fitness def set_value(self, value): @@ -23,4 +27,5 @@ class Gene: self.value = value def __repr__(self): + """Format the repr() output value""" return f'[{self.value}]' diff --git a/src/initialization/methods.py b/src/initialization/methods.py new file mode 100644 index 0000000..312580c --- /dev/null +++ b/src/initialization/methods.py @@ -0,0 +1,33 @@ +# 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(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: + # gene_impl = [range function,lowerbound,upperbound] + 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") + population.add_chromosome(chromosome) + return population diff --git a/src/initialization/population_structure/__init__.py b/src/initialization/population_structure/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/initialization/population_structure/population.py b/src/initialization/population_structure/population.py index 94bdcb7..98f5518 100644 --- a/src/initialization/population_structure/population.py +++ b/src/initialization/population_structure/population.py @@ -1,24 +1,25 @@ class Population: - - # fitness = Empty; population = [chromosome, chromosome, etc.] - def __init__(self, chromosomes = None): - if chromosomes is 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 chromosome_list is None: self.chromosome_list = [] else: - self.chromosome_list = chromosomes + 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 + """Get the chomosome that has the closets fitness to the value defined""" pass 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.chromosome_list) self.chromosome_list.insert(index, chromosome) def remove_chromosome(self, index): + """removes a chromosome from the indicated index""" del self.chromosome_list[index] def get_all_chromosomes(self): @@ -26,6 +27,7 @@ class Population: return self.chromosome_list def get_fitness(self): + """returns the population's fitness""" return self.fitness def set_all_chromosomes(self, chromosomes): @@ -37,6 +39,7 @@ class Population: self.chromosome_list[index] = chromosome def set_fitness(self, fitness): + """Sets the fitness value of the population""" self.fitness = fitness def __repr__(self): @@ -44,9 +47,10 @@ class Population: return f'{self.chromosome_list[index]}' def print_all(self): - # Ex .Current population - # Chromosome 1 - [gene][gene][gene][.etc] / Chromosome fitness - # + """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.chromosome_list)): print(f'Chromosome - {index} {self.chromosome_list[index]}', end = "") - print(f' / Fitness = {self.chromosome_list[index].fitness}') \ No newline at end of file + print(f' / Fitness = {self.chromosome_list[index].fitness}') diff --git a/src/initialization/test_methods.py b/src/initialization/test_methods.py new file mode 100644 index 0000000..e69de29 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/mutation/test_methods.py b/src/mutation/test_methods.py new file mode 100644 index 0000000..e69de29 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/parent_selection/__init__.py b/src/parent_selection/__init__.py new file mode 100644 index 0000000..8ecd200 --- /dev/null +++ b/src/parent_selection/__init__.py @@ -0,0 +1,2 @@ +# FROM (. means local) file_name IMPORT function_name +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/parent_selection/test_methods.py b/src/parent_selection/test_methods.py new file mode 100644 index 0000000..e69de29 diff --git a/src/run_testing.py b/src/run_testing.py index 2381627..390986b 100644 --- a/src/run_testing.py +++ b/src/run_testing.py @@ -13,4 +13,4 @@ ga.gene_impl = [random.randrange,1,100] ga.evolve() # Print the current population -ga.population.print_all() \ No newline at end of file +ga.population.print_all() 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/survivor_selection/__init__.py b/src/survivor_selection/__init__.py new file mode 100644 index 0000000..ea2e686 --- /dev/null +++ b/src/survivor_selection/__init__.py @@ -0,0 +1,2 @@ +# FROM (. means local) file_name IMPORT function_name +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/survivor_selection/test_methods.py b/src/survivor_selection/test_methods.py new file mode 100644 index 0000000..e69de29 diff --git a/src/termination_point/methods.py b/src/termination_point/methods.py new file mode 100644 index 0000000..8f1aaa5 --- /dev/null +++ b/src/termination_point/methods.py @@ -0,0 +1,16 @@ +class Termination_methods: + """Example functions that can be used to terminate the the algorithms loop""" + + def fitness_based(ga): + """Fitness based approach to terminate when the goal fitness has been reached""" + status = True + if(ga.current_fitness > ga.fitness_goal): + status = False + return status + + def generation_based(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_methods.py b/src/termination_point/test_methods.py new file mode 100644 index 0000000..e69de29