Algoritmos genéticos

Guido García · @palmerabollo

#tefcon2014

"I have called this principle, by which each slight variation, if useful, is preserved, by the term of Natural Selection"

extatosoma tiaratum

3.5 MHz - 48 KB

28 años después

x 1

x 100000

10 FOR i = 1 TO 10
20 PRINT "Hola Mundo!"
30 NEXT
40 END

28 años después

Mismo código

Problema

Solución

conocimiento e inteligencia humanos

imperativo
determinístico

"Programming should be more about the what and less about the how

ALGORITMOS GENÉTICOS

Optimización

optimización
 inspirada en la naturaleza

Mejor solución

Posibles soluciones
(población)

selección natural

Problema

parametrizable


 var population = [..., ..., ...]; // i.e. random

 while (true) {
    population = population.filter(function (individual) {
       return fitness(individual) > THRESHOLD;
    });

    population.crossover();
    population.mutate();
 }

 var fitness = function (individual) {
    return ...; // numeric fitness value
 }

Fitness Function

Ejemplo · Diseñar un coche

GAlib (C++) lancet.mit.edu/ga
VoxCAD www.voxcad.com

EJEMPLO · Evolved CREATURES

EVALUABLE

DIVISIBLE

subóptimO

Antena, NASA 2006

Niigata (Japan), ambulancias

"MONA LISA"

40 minutos

Evolución de redes neuronales

TRADING · Wimbledon 2008 · Mathieu - Čilić

Ejemplo · n reinas

4

6

0

2

7

5

3

1

Codificación
del problema

(genoma ~ array de enteros)

Población inicial

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

Individuo 1

Individuo 2

Individuo 3

Individuo 4

Individuo 5

Individuo 6

Individuo N

...

Supervivencia

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

4

6

0

2

7

5

3

1

Individuo 1

Individuo 2

Individuo 3

Individuo 4

Individuo 5

Individuo 6

= 9

= 8

= 6

= 10

= 14

= 6

Fitness Function: número de reinas atacándose

Operadores genéticos

Cruce

4

3

1

4

0

2

7

7

0

3

4

0

2

5

3

1

Individuo 3

Individuo 6

4

3

1

4

0

2

7

7

0

3

4

0

2

5

3

1

= 6

= 6

= 8

= 5

Mutación

Individuo 3'

Individuo 6'

4

3

1

4

0

2

7

7

0

3

4

0

2

5

1

= 6

= 5

Individuo 3'

Individuo 6'

2

Javascript

Show me da code

var BOARD_SIZE = 8;

var Individual = function (genome) {
    this.genome = genome || [0,0,0,0,0,0,0,0];
};

Individual.prototype.mutate = function (probability) {







};

Individual.prototype.crossover = function (mate) {









};
    if (Math.random() > probability) {
        return;
    }

    var column = _.random(BOARD_SIZE - 1);
    this.genome[column] = _.random(BOARD_SIZE - 1);
    var pivot = BOARD_SIZE / 2;

    var child1 = this.genome.slice(0, pivot)
                            .concat(mate.genome.slice(pivot, BOARD_SIZE));
    var child2 = mate.genome.slice(0, pivot)
                            .concat(this.genome.slice(pivot, BOARD_SIZE));

    return [new Individual(child1), new Individual(child2)];
Individual.prototype.fitness = function () {
    var errors = 0;
    for (var i = 0; i < BOARD_SIZE; i++) {
        for (var j = i+1; j < BOARD_SIZE; j++) {
            if (this.genome[i] === this.genome[j]) {
                errors++;
            }
            if (Math.abs(this.genome[i] - this.genome[j]) === j - i) {
                errors++;
            }
        }
    }
    
    this.fitnessValue = errors;
};
var POPULATION_SIZE = 100;

var population = [];
for (var i=0; i<POPULATION_SIZE; i++) {
    population.push(new Individual());
}

var evolve = function () {












    setTimeout(evolve, 0);
};

evolve();
    population.forEach(function (individual) {
        individual.mutate(0.1);
        individual.fitness();
    });

    population.sort(function (a, b) {
        return a.fitnessValue - b.fitnessValue;
    });

    var children = population[0].crossover(population[1]);
    population.splice(population.length - 2, 2, children[0], children[1]);

(Java, watchmaker)

Show me da code

CandidateFactory<int[]> factory = new AbstractCandidateFactory<int[]>() {
    public int[] generateRandomCandidate(Random rng) {
        int[] genome = new int[BOARD_SIZE];
        for (int i = 0; i < BOARD_SIZE; i++) {
            genome[i] = rng.nextInt(BOARD_SIZE);
        }
        return genome;
    }
};
CandidateFactory
List<EvolutionaryOperator<int[]>> operators =
        new LinkedList<EvolutionaryOperator<int[]>>();

operators.add(new IntArrayCrossover());
operators.add(new IntArrayMutation(new Probability(0.05d)));

EvolutionaryOperator<int[]> evolutionScheme =
        new EvolutionPipeline<int[]>(operators);
EvolutionaryOperator, EvolutionPipeline
class BoardEvaluator implements FitnessEvaluator<int[]> {
    public double getFitness(int[] genome, ...) {
        int errors = 0;
        for (int i = 0; i < genome.length; i++) {
            for (int j=i+1; j < genome.length; j++) {
                if (genome[i] == genome[j]) {
                    errors++;
                }
                if (Math.abs(genome[i] - genome[j]) == j - i) {
                    errors++;
                }
            }
        }
        return errors;
    }

    public boolean isNatural() {
        return false;
    }
}
FitnessEvaluator
EvolutionEngine<int[]> engine = new GenerationalEvolutionEngine<int[]>(
                candidateFactory,
                evolutionScheme,
                fitnessEvaluator,
                new RouletteWheelSelection(), // selection strategy
                new MersenneTwisterRNG());    // random generator

engine.evolve(1000, // population size
              1,    // elitism
              new TargetFitness(0, false));
EvolutionEngine

PROGRAMACIÓN GENÉTICA

"programming the unprogrammable"

Evolucionar código

def algorithm(x, y)
  if x > 3:
    return y + 5
  else:
    return y - 2

Imágenes: "Programming Collective Intelligence" O'Reilly, 2007
Chapter 11. Evolving Intelligence

syntax
tree

def algorithm(x, y)
  if x > 3:
    return y + 5
  else:
    return x * y
def algorithm(x, y)
  if x > 3:
    return y * 5 - 2
  else:
    return y - 2

Lisp

(defn algorithm [x, y]
  (if (> x 3) 
    (+ y 5)
    (- y 2)))

código ~ tree

fácil de manipular

Ejemplo · Hipotenusa

x=\sqrt{a^2+b^2}
x=a2+b2
def gp_add(a, b): return a+b
def gp_sub(a, b): return a-b
def gp_mul(a, b): return a*b
def gp_pow(a):    return a**2
def gp_sqrt(a):   return math.sqrt(abs(a))
def main_run():
    tree = GTree.GTreeGP()
    tree.setParams(max_depth=4)
    tree.evaluator += fitness_function

    ga = GSimpleGA.GSimpleGA(tree)
    ga.setParams(gp_terminals=['a', 'b'],
                 gp_function_prefix="gp")

    ga.setElitism(True)
    ga.setGenerations(200)
    ga.setCrossoverRate(1.0)
    ga.setMutationRate(0.05)
    ga.setPopulationSize(100)
    ga.setMinimax(Consts.minimaxType["minimize"])

    ga()
    print ga.bestIndividual()
def fitness_function(individual):
    error = Util.ErrorAccumulator()
    code = individual.getCompiledCode()

    points = [(3,4,5), (0,0,0), (15, 20, 25)]

    for (a,b,target) in points:
        evaluated = eval(code)
        error    += (target, evaluated)

    # penalize big trees
    return error.getRMSE() * chromosome.getNodesCount()

 gp_sqrt(gp_add(gp_mul(a, a), gp_pow(b)))

gp_add(a, gp_sqrt(b))

 gp_sqrt(gp_add(gp_pow(a), gp_pow(b)))

 gp_sqrt(gp_add(gp_sub(b, b), gp_add(gp_pow(a), gp_pow(b))))

\sqrt{(b-b)+(a^2+b^2)}
(bb)+(a2+b2)
\sqrt{a*a+b^2}
aa+b2
\sqrt{a^2+b^2}
a2+b2
a+\sqrt{b}
a+b

Ejemplo · Santa Fe Trail

Preguntas