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
10 FOR i = 1 TO 10
20 PRINT "Hola Mundo!"
30 NEXT
40 END
Problema
Solución
conocimiento e inteligencia humanos
"Programming should be more about the what and less about the how"
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
GAlib (C++) lancet.mit.edu/ga
VoxCAD www.voxcad.com
40 minutos
TRADING · Wimbledon 2008 · Mathieu - Čilić
4
6
0
2
7
5
3
1
Codificación
del problema
(genoma ~ array de enteros)
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
...
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
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
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]);
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
"programming the unprogrammable"
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
(defn algorithm [x, y]
(if (> x 3)
(+ y 5)
(- y 2)))
código ~ tree
fácil de manipular
clojure: github.com/vollmerm/fungp
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))))
python (DEAP): deap.googlecode.com/hg-history/default/examples/gp/ant.py