From 17fff124da527d4d5b036decbf78ee98acb3f39a Mon Sep 17 00:00:00 2001 From: Guillaume Simonneau <2980507+khezen@users.noreply.github.com> Date: Sat, 6 Mar 2021 01:18:46 +0100 Subject: [PATCH] crossover: produces two children (#30) --- crosser.go | 2 +- examplegnetic_test.go | 16 ++++++++++------ genetic.go | 25 ++++++++++++++----------- mock_test.go | 9 +++++++-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/crosser.go b/crosser.go index dd94377..e6c6be1 100644 --- a/crosser.go +++ b/crosser.go @@ -2,5 +2,5 @@ package evoli // Crosser produces a new individual from two individuals. This operators provides convergence to a population. type Crosser interface { - Cross(individual1, individual2 Individual) (Individual, error) + Cross(parent1, parent2 Individual) (child1, child2 Individual, err error) } diff --git a/examplegnetic_test.go b/examplegnetic_test.go index 66abc18..1e61e37 100644 --- a/examplegnetic_test.go +++ b/examplegnetic_test.go @@ -49,13 +49,17 @@ func (m HMutater) Mutate(indiv evoli.Individual) (evoli.Individual, error) { type HCrosser struct { } -func (h HCrosser) Cross(indiv1, indiv2 evoli.Individual) (evoli.Individual, error) { - fIndiv1, _ := indiv1.(*HIndividual) - fIndiv2, _ := indiv2.(*HIndividual) +func (h HCrosser) Cross(parent1, parent2 evoli.Individual) (child1, child2 evoli.Individual, err error) { + fIndiv1, _ := parent1.(*HIndividual) + fIndiv2, _ := parent2.(*HIndividual) + w := 0.1 + 0.8*rand.Float64() return &HIndividual{ - x: []float64{(fIndiv1.x[0] + fIndiv2.x[0]) / 2, (fIndiv1.x[1] + fIndiv2.x[1]) / 2}, - v: []float64{(fIndiv1.v[0] + fIndiv2.v[0]) / 2, (fIndiv1.v[1] + fIndiv2.v[1]) / 2}, - }, nil + x: []float64{w*fIndiv1.x[0] + (1-w)*fIndiv2.x[0], w*fIndiv1.x[1] + (1-w)*fIndiv2.x[1]}, + v: []float64{w*fIndiv1.v[0] + (1-w)*fIndiv2.v[0], w*fIndiv1.v[1] + (1-w)*fIndiv2.v[1]}, + }, &HIndividual{ + x: []float64{(1-w)*fIndiv1.x[0] + w*fIndiv2.x[0], (1-w)*fIndiv1.x[1] + w*fIndiv2.x[1]}, + v: []float64{(1-w)*fIndiv1.v[0] + w*fIndiv2.v[0], (1-w)*fIndiv1.v[1] + w*fIndiv2.v[1]}, + }, nil } type HEvaluater struct { diff --git a/genetic.go b/genetic.go index e25d1ef..74b3591 100644 --- a/genetic.go +++ b/genetic.go @@ -47,15 +47,15 @@ func (g *genetic) Next() error { if deads != nil { deads.Close() } - newBorns, err := g.crossovers(survivors) + offsprings, err := g.crossovers(survivors) if err != nil { return err } - newBorns, err = g.mutations(newBorns) + offsprings, err = g.mutations(offsprings) if err != nil { return err } - survivors.Add(newBorns.Slice()...) + survivors.Add(offsprings.Slice()...) g.pop = survivors return nil } @@ -88,15 +88,15 @@ func (g *genetic) evaluation(pop Population) error { func (g *genetic) crossovers(pop Population) (Population, error) { var ( - newBorns = NewPopulation(pop.Cap() - pop.Len()) + capacity = pop.Cap() - pop.Len() + offsprings = NewPopulation(capacity) mut sync.Mutex - capacity = newBorns.Cap() wg = sync.WaitGroup{} bubbledErr error ) - for index := 0; index < capacity; index++ { + for index := 0; index < capacity; index += 2 { wg.Add(1) - go func() { + go func(index int) { defer wg.Done() var i, j = rand.Intn(pop.Len()), rand.Intn(pop.Len()) if i == j { @@ -108,21 +108,24 @@ func (g *genetic) crossovers(pop Population) (Population, error) { } } indiv1, indiv2 := pop.Get(i), pop.Get(j) - newBorn, err := g.crosser.Cross(indiv1, indiv2) + child1, child2, err := g.crosser.Cross(indiv1, indiv2) if err != nil { bubbledErr = err return } mut.Lock() - newBorns.Add(newBorn) + offsprings.Add(child1) + if index+1 < capacity { + offsprings.Add(child2) + } mut.Unlock() - }() + }(index) } wg.Wait() if bubbledErr != nil { return nil, bubbledErr } - return newBorns, nil + return offsprings, nil } func (g *genetic) mutations(pop Population) (Population, error) { diff --git a/mock_test.go b/mock_test.go index 3eb6542..e38b12e 100644 --- a/mock_test.go +++ b/mock_test.go @@ -1,10 +1,15 @@ package evoli +import "math/rand" + type crosserMock struct { } -func (c crosserMock) Cross(individual1, individual2 Individual) (Individual, error) { - return NewIndividual((individual1.Fitness() + individual2.Fitness()) / 2), nil +func (c crosserMock) Cross(parent1, parent2 Individual) (child1, child2 Individual, err error) { + w := 0.1 + 0.8*rand.Float64() + return NewIndividual(w*parent1.Fitness() + (1-w)*parent2.Fitness()), + NewIndividual((1-w)*parent1.Fitness() + w*parent2.Fitness()), + nil } type evaluaterMock struct {