[email protected] @BWKnopper github.com/bknopper By Developers. For Developers. De missie van JCore is om ambitieuze Java Developers een traject te bieden waarmee ze sneller en beter Senior Java Developers kunnen worden. Wat (Java Consultancy) -> We helpen klanten met het realiseren van complexe IT projecten. Hoe Met ambitieuze en enthousiaste Java Consultants die een bijdrage leveren bij de klant. Waarom Vanuit een passie voor IT en het oplossen van complexe problemen.
[email protected] @BWKnopper github.com/bknopper What I would like to accomplish… • Interest • Understanding • How & when • Add to toolbox • Attention @DevFestNL #EvolutionaryAlgorithms #golang @BWKnopper
[email protected] @BWKnopper github.com/bknopper NASA • Space Technology 5 mission • launched March 22, 2006, and completed June 20, 2006 • Three full service 25-kilogram-class spacecraft
[email protected] @BWKnopper github.com/bknopper NASA Continued • Needs even smaller antenna • That still functions according to spec • Need forsolution that’s not easy to engineer • So they used an EA that made these:
[email protected] @BWKnopper github.com/bknopper Evolution - “Survival of the fittest” Finite Resources Lifeforms with a basic instinct towards Reproduction Natural Selection
[email protected] @BWKnopper github.com/bknopper Travelling Salesman Problem • Given n cities • n = number of cities to visit • Find (optimal) route for visiting all cities • Visit every city only once • Return to origin city • Search space is huge • For 30 cities there are 30! ≈ 10^32 possible routes That’s 100.000.000.000.000.000.000.000.000.000.000 possible routes! Brute force might not be the best solution…
[email protected] @BWKnopper github.com/bknopper Puzzle solving time! • More down to earth example • TravellingSalesman Problem • Use case to show you • EvolutionaryAlgorithm Design • Plain Go Code • Demo
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate;
[email protected] @BWKnopper github.com/bknopper /** * Calculates the total distance of the whole route * and stores it as this candidate solution's fitness */ func (candidateSolution *CandidateSolution) calculateFitness() { }
[email protected] @BWKnopper github.com/bknopper /** * Calculates the total distance of the whole route * and stores it as this candidate solution's fitness */ func (candidateSolution *CandidateSolution) calculateFitness() { totalDistance := float64(0) for i := 0; i < (len(candidateSolution.Route) - 1); i++ { } candidateSolution.Fitness = totalDistance }
[email protected] @BWKnopper github.com/bknopper /** * Calculates the total distance of the whole route * and stores it as this candidate solution's fitness */ func (candidateSolution *CandidateSolution) calculateFitness() { totalDistance := float64(0) for i := 0; i < (len(candidateSolution.Route) - 1); i++ { city := candidateSolution.Route[i] nextCity := candidateSolution.Route[i + 1] totalDistance += city.calculateDistance(nextCity) } candidateSolution.Fitness = totalDistance }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate;
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { }
[email protected] @BWKnopper github.com/bknopper Termination Condition • Combination • Sure to terminate • Time • Max number of runs (generations) • Goal • Fitness threshold • Fitness improvementstagnation Figure from “Introduction to Evolutionary Computing” by A.E. Eiben & J.E. Smith (Springer)
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; }
[email protected] @BWKnopper github.com/bknopper Parent Selection • Where x is the number of parents: • Pick x best • Random x • Best xout of random y • In our example: • Best x out of random y
[email protected] @BWKnopper github.com/bknopper func (algorithm *Algorithm) parentSelection() CandidateSolutions { tempPopulation := make(CandidateSolutions, algorithm.populationSize) copy(tempPopulation, algorithm.population) randomCandidates := make(CandidateSolutions, algorithm.parentPoolSize) for i := 0; i < algorithm.parentPoolSize; i++ { randomIndex := rand.Intn(len(tempPopulation)) randomCandidateSolution := tempPopulation[randomIndex] randomCandidates[i] = randomCandidateSolution /* delete the candidate from the temp population, so we can't pick it again */ tempPopulation[randomIndex] = tempPopulation[len(tempPopulation)-1] tempPopulation = tempPopulation[:len(tempPopulation)-1] } /* Sort the population so that the best candidates are up front */ sort.Sort(randomCandidates)
[email protected] @BWKnopper github.com/bknopper func (algorithm *Algorithm) parentSelection() CandidateSolutions { tempPopulation := make(CandidateSolutions, algorithm.populationSize) copy(tempPopulation, algorithm.population) randomCandidates := make(CandidateSolutions, algorithm.parentPoolSize) for i := 0; i < algorithm.parentPoolSize; i++ { randomIndex := rand.Intn(len(tempPopulation)) randomCandidateSolution := tempPopulation[randomIndex] randomCandidates[i] = randomCandidateSolution /* delete the candidate from the temp population, so we can't pick it again */ tempPopulation[randomIndex] = tempPopulation[len(tempPopulation)-1] tempPopulation = tempPopulation[:len(tempPopulation)-1] } /* Sort the population so that the best candidates are up front */ sort.Sort(randomCandidates) /* return a list with size parentSelectionSize with the best CandidateSolutions */ return randomCandidates[0:algorithm.parentSelectionSize] }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; }
[email protected] @BWKnopper github.com/bknopper func (candidateSolution *CandidateSolution) recombine(otherParent CandidateSolution) CandidateSolutions { /* get routes of both parents */ parentRoute1 := candidateSolution.VisitingCities parentRoute2 := otherParent.VisitingCities /* randomize cutIndex for "cross-and-fill point" */ cutIndex := int32(rand.Intn(len(parentRoute1))) /* initialize the routes for the children */ childRoute1 := make(Cities, len(parentRoute1)) childRoute2 := make(Cities, len(parentRoute1)) /* get the first part of both parent routes using the cut index */ partRoute1 := parentRoute1[0:cutIndex] partRoute2 := parentRoute2[0:cutIndex]
[email protected] @BWKnopper github.com/bknopper func (candidateSolution *CandidateSolution) recombine(otherParent CandidateSolution) CandidateSolutions { /* get routes of both parents */ parentRoute1 := candidateSolution.VisitingCities parentRoute2 := otherParent.VisitingCities /* randomize cutIndex for "cross-and-fill point" */ cutIndex := int32(rand.Intn(len(parentRoute1))) /* initialize the routes for the children */ childRoute1 := make(Cities, len(parentRoute1)) childRoute2 := make(Cities, len(parentRoute1)) /* get the first part of both parent routes using the cut index */ partRoute1 := parentRoute1[0:cutIndex] partRoute2 := parentRoute2[0:cutIndex] /* copy the first part of the parents cut into the children */ copy(childRoute1, partRoute1) copy(childRoute2, partRoute2)
[email protected] @BWKnopper github.com/bknopper func (candidateSolution *CandidateSolution) recombine(otherParent CandidateSolution) CandidateSolutions { /* get routes of both parents */ parentRoute1 := candidateSolution.VisitingCities parentRoute2 := otherParent.VisitingCities /* randomize cutIndex for "cross-and-fill point" */ cutIndex := int32(rand.Intn(len(parentRoute1))) /* initialize the routes for the children */ childRoute1 := make(Cities, len(parentRoute1)) childRoute2 := make(Cities, len(parentRoute1)) /* get the first part of both parent routes using the cut index */ partRoute1 := parentRoute1[0:cutIndex] partRoute2 := parentRoute2[0:cutIndex] /* copy the first part of the parents cut into the children */ copy(childRoute1, partRoute1) copy(childRoute2, partRoute2) candidateSolution.crossFill(childRoute1, parentRoute2, cutIndex) candidateSolution.crossFill(childRoute2, parentRoute1, cutIndex)
[email protected] @BWKnopper github.com/bknopper func (candidateSolution *CandidateSolution) recombine(otherParent CandidateSolution) CandidateSolutions { /* get routes of both parents */ parentRoute1 := candidateSolution.VisitingCities parentRoute2 := otherParent.VisitingCities /* randomize cutIndex for "cross-and-fill point" */ cutIndex := int32(rand.Intn(len(parentRoute1))) /* initialize the routes for the children */ childRoute1 := make(Cities, len(parentRoute1)) childRoute2 := make(Cities, len(parentRoute1)) /* get the first part of both parent routes using the cut index */ partRoute1 := parentRoute1[0:cutIndex] partRoute2 := parentRoute2[0:cutIndex] /* copy the first part of the parents cut into the children */ copy(childRoute1, partRoute1) copy(childRoute2, partRoute2) candidateSolution.crossFill(childRoute1, parentRoute2, cutIndex) candidateSolution.crossFill(childRoute2, parentRoute1, cutIndex) /* create new children using the new children routes */ child1 := NewCandidateSolution(getBaseCity(), childRoute1); child2 := NewCandidateSolution(getBaseCity(), childRoute2); /* put the children in a list and return it */ return CandidateSolutions{child1, child2} }
[email protected] @BWKnopper github.com/bknopper /** * Check the rest of the route in the crossing parent and add the cities that are not yet in the child * (in the order of the route of the crossing parent) */ func (candidateSolution *CandidateSolution) crossFill(childRoute Cities, parentRoute []City, cutIndex int32) {
[email protected] @BWKnopper github.com/bknopper /** * Check the rest of the route in the crossing parent and add the cities that are not yet in the child * (in the order of the route of the crossing parent) */ func (candidateSolution *CandidateSolution) crossFill(childRoute Cities, parentRoute []City, cutIndex int32) { /* * traverse the parent route from the cut index on and add every city * not yet in the child to the child */ childRouteIndex := cutIndex for i := cutIndex; i < int32(len(parentRoute)); i++ { nextCityOnRoute := parentRoute[i] if (!childRoute.contains(nextCityOnRoute)) { childRoute[childRouteIndex] = nextCityOnRoute childRouteIndex++ } } 1 4 2 5 6 3 1
[email protected] @BWKnopper github.com/bknopper /** * Check the rest of the route in the crossing parent and add the cities that are not yet in the child * (in the order of the route of the crossing parent) */ func (candidateSolution *CandidateSolution) crossFill(childRoute Cities, parentRoute []City, cutIndex int32) { /* * traverse the parent route from the cut index on and add every city * not yet in the child to the child */ childRouteIndex := cutIndex for i := cutIndex; i < int32(len(parentRoute)); i++ { nextCityOnRoute := parentRoute[i] if (!childRoute.contains(nextCityOnRoute)) { childRoute[childRouteIndex] = nextCityOnRoute childRouteIndex++ } } /* * traverse the parent route from the start of the route and add every * city not yet in the child to the child */ for i := 0; i < int(cutIndex); i++ { nextCityOnRoute := parentRoute[i] if (!childRoute.contains(nextCityOnRoute)) { childRoute[childRouteIndex] = nextCityOnRoute childRouteIndex++ } } } 1 4 2 5 6 3 1 1 4 2 5 6 3 1
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; 3 MUTATE the resulting offspring; }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; 3 MUTATE the resulting offspring; }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; 3 MUTATE the resulting offspring; 4 EVALUATE new candidates; }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; 3 MUTATE the resulting offspring; 4 EVALUATE new candidates; 5 SELECT individuals for the next generation; }
[email protected] @BWKnopper github.com/bknopper /** * Selects the survivors by removing the worst candidate * solutions from the list, so we have the original * population size again */ func (algorithm *Algorithm) selectSurvivors() { }
[email protected] @BWKnopper github.com/bknopper /** * Selects the survivors by removing the worst candidate * solutions from the list, so we have the original * population size again */ func (algorithm *Algorithm) selectSurvivors() { sort.Sort(algorithm.population) }
[email protected] @BWKnopper github.com/bknopper /** * Selects the survivors by removing the worst candidate * solutions from the list, so we have the original * population size again */ func (algorithm *Algorithm) selectSurvivors() { sort.Sort(algorithm.population) algorithm.population = algorithm.population[:algorithm.populationSize] }
[email protected] @BWKnopper github.com/bknopper EA Algorithm (Pseudocode) INITIALISE population with random candidate solutions; EVALUATE each candidate; WHILE ( TERMINATION CONDITION is not satisfied ) { 1 SELECT parents; 2 RECOMBINE pairs of parents; 3 MUTATE the resulting offspring; 4 EVALUATE new candidates; 5 SELECT individuals for the next generation; }
[email protected] @BWKnopper github.com/bknopper EA Behavior Figures from “Introduction to Evolutionary Computing” by A.E. Eiben & J.E. Smith (Springer)
[email protected] @BWKnopper github.com/bknopper With great power comes great responsibility • I’m sure I cannot find a solution using a brute-force approach? • (within a reasonable amountof time) • Am I facing an optimization or search problem? • Can I encode a candidate solution to the problem? • Representationpossible? • Can I determine the fitness of a candidate solution?