Last active
February 23, 2022 17:57
-
-
Save dfbarrero/ea3f81cd9a7847147e48490dd0b44b50 to your computer and use it in GitHub Desktop.
Genetic Algorithm implemented with Inspyred to solve the one-max problem, with command-line argument parsing. Some evolution statistics are printed in stdout with CSV format, general info is printed in stderr.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ Genetic Algorithm that solves the one-max problem. | |
| Genetic Algorithm that solves the one-max problem, many parameters in the GA | |
| can be changed by command line. This script has been designed for teaching | |
| GA. Its code is based on the inspyred library examples. | |
| This program is free software: you can redistribute it and/or modify it under | |
| the terms of the GNU General Public License as published by the Free Software | |
| Foundation, either version 3 of the License, or (at your option) any later | |
| version. | |
| This program is distributed in the hope that it will be useful, but WITHOUT | |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
| FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License along with | |
| this program. If not, see <http://www.gnu.org/licenses/>. | |
| """ | |
| from random import Random | |
| from time import time | |
| import inspyred | |
| import argparse | |
| import statistics | |
| import sys | |
| def onemax_fitness(candidates, args): | |
| fitness = [] | |
| for cs in candidates: | |
| fit = sum(cs) | |
| fitness.append(fit) | |
| generations = args['_ec'].num_generations | |
| if args['_ec'].num_evaluations > 0: | |
| generations += 1 | |
| parsed = args['pararg'] | |
| print(",".join(map(str, (args['job'] + 1, generations, | |
| max(fitness), min(fitness), | |
| statistics.mean(fitness), statistics.median(fitness), statistics.stdev(fitness), | |
| parsed.population, parsed.tournament, | |
| parsed.length, parsed.mutation, parsed.crossover)))) | |
| return fitness | |
| def generator(random, args): | |
| return [random.choice([0, 1]) for _ in range(args["length"])] | |
| parser = argparse.ArgumentParser(description='One-max problem with a Genetic Algorithms optimizer.') | |
| parser.add_argument('--population', '-p', type=int, metavar='POP', default=30, | |
| help='population size used in the GA [default=30]') | |
| parser.add_argument('--tournament', '-t', type=int, metavar='TOUR', default=2, | |
| help='tournament size [default=2]') | |
| parser.add_argument('--length', '-l', type=int, metavar='SIZE', default=30, | |
| help='chromosome length [default=30]') | |
| parser.add_argument('--generations', '-g', type=int, metavar='GEN', default=20, | |
| help='maximum number of generations to run [default=20]') | |
| parser.add_argument('--crossover', '-c', type=float, metavar='PROB', default=1, | |
| help='crossover probability [default=1]') | |
| parser.add_argument('--mutation', '-m', type=float, metavar='PROB', default=0.01, | |
| help='mutation rate [default=0.01]') | |
| parser.add_argument('--elite', '-e', type=int, metavar='NUM', default=0, | |
| help='elitism size [default=0]') | |
| parser.add_argument('--jobs', '-j', type=int, metavar='JOBS', default=1, | |
| help='number of jobs [default=1]') | |
| args = parser.parse_args() | |
| if (args.mutation > 1): | |
| sys.exit("ERROR: Mutation must be a probability (0 <= pm <= 1)") | |
| if (args.crossover > 1): | |
| sys.exit("ERROR: Crossover must be a probability (0 <= pc <= 1)") | |
| prng = Random() | |
| prng.seed(time()) | |
| ea = inspyred.ec.GA(prng) | |
| ea.terminator = inspyred.ec.terminators.generation_termination | |
| ea.selector = inspyred.ec.selectors.tournament_selection | |
| #ea.observer = [inspyred.ec.observers.stats_observer, | |
| # inspyred.ec.observers.plot_observer] | |
| sys.stderr.write(repr(args) + "\n\n") | |
| sys.stderr.flush() | |
| job = 0 | |
| print("job,generation,max,min,mean,median,stdev,population,tournament,length,mutation,crossover") | |
| for job in range(args.jobs): | |
| final_pop = ea.evolve(generator=generator, | |
| evaluator=onemax_fitness, | |
| pop_size=args.population, | |
| tournament_size=args.tournament, | |
| max_generations=args.generations, | |
| length=args.length, | |
| mutation_rate=args.mutation, | |
| crossover_rate=args.crossover, | |
| num_elites=args.elite, | |
| pararg=args, | |
| job=job) | |
| best = max(final_pop) | |
| sys.stderr.write('Best solution: \n\t{0}\n'.format(str(best))) | |
| if (best.fitness == args.length): | |
| sys.stderr.write("Solution found!\n") | |
| else: | |
| sys.stderr.write("Solution NOT found\n") | |
| sys.stderr.flush() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment