Skip to content
/ Evo Public

Lightweight Tool for Genetic Algorithms in Python

License

Notifications You must be signed in to change notification settings

Inspiaaa/Evo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Evo

A lightweight library for creating genetic algorithms with ease in Python.

  • 100% pure python

  • Lightweight: No external dependencies / packages

  • Quick start template for multi-parameter optimisation problems

Getting started

  1. Copy the evo2.py file into your own project

  2. Import the file and create a class which will represent an individual of the population

from evo2 import Individual, Evolution, Selection
import random


class Optimisation (Individual):
   # __slots__ makes the individual class use less memory
   __slots__ = ("x")

   def __init__(self):
       super().__init__()
       self.x = 0

   # You can pass in your own data for initialisation
   # Although a dictionary is handy for that, any data type can be used
   def create(self, init_params):
       # Here you randomly initialise the individual
       self.x = random.uniform(init_params["lower"], init_params["upper"])

   # Mutate is used for introducing some randomness after pairing
   def mutate(self, mutate_params):
       self.x += random.random() * mutate_params["intensity"]
       # Clamp the x value into the desired range, if it goes over
       self.x = min(mutate_params["upper"], min(mutate_params["lower"], self.x))

   # Create a new offspring (Also known as the crossover operator)
   def pair(self, other, pair_params):
       offspring = Optimisation()
       offspring.x = (self.x + other.x) / 2
  1. Create a fitness function
def curve(x):
    return -x*(x-1)*(x-2)*(x-3)*(x-4)
  1. Initialise a population
evo = Evolution(
    Optimisation,
    size=20,
    n_offsprings=10,
    selection_method=Selection.tournament
    init_params={"lower": 0, "upper": 4},
    mutate_params={"lower": 0, "upper": 4},
    fitness_func=lambda obj: curve(obj.x))
  1. Run the algorithm
# Run 100 generations
evo.evolve(100)
  1. Get the best individual
best = evo.get_best_n(1)[0]
best_fitness = best.fitness

Other features

  • Computing the diversity: Evo uses the standard deviation of the fitness values to describe the diversity of the population
diversity = evo.population.compute_diversity()
  • Stopping after a certain number of generations without improvement
while True:
    evo.evolve()

    # Stop after 50 generations of no improvement
    if evo.stall_gens > 50:
        break
  • Preserving diversity by using "social disasters"
from evo2 import SocialDisasters

for i in range(100):
    diversity = evo.population.compute_diversity()

    if diversity < 50:
        # Randomly re-initialise individuals that are too similar
        SocialDisasters.packing(evo.population, 10)

        # OR only keep the best individual and randomly re-initialise all others
        SocialDisasters.judgement_day(evo.population)
  • Getting the generation number

    print(f"Generation #{ evo.gen_number }")

Using the optimisation template

The Evo library has a builtin template for multi parameter optimisation problems

  1. Copy the evo_templates.py file in to your workspace (as well as the main Evo file itself)

  2. Define the problem

    # 3 parameter function, taking 3 floats
    def cost(a, b, c):
        return (a+1)*(b+2)*(c+3)*(a-b-c)*(c-b-a)
  3. Let the library optimise for you

    from evo_templates import maximise_multi_param
    
    a, b, c = maximise_multi_param(cost, lower_bounds=[-2, -2, -2], upper_bounds=[2, 2, 2]))
    print(a, b, c)

Different selection methods

The selection method tells Evo, which individuals to pair

  • Selection.random Randomly chooses individuals

  • Selection.fittest Chooses the best individuals

  • Selection.roullette_wheel Gives the best individuals a better chance of being chosen

  • Selection.tournament Takes two random individuals and chooses the better one