Skip to content

Commit

Permalink
Add GAMutatorRandom which replaces one gene with a random one.
Browse files Browse the repository at this point in the history
  • Loading branch information
subruber committed Dec 28, 2015
1 parent 04aeb0d commit ed4d023
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
30 changes: 30 additions & 0 deletions mutator_random.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright 2015 Ludovico Gardenghi <[email protected]>.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
This mutator replaces one gene with a random one. It works by creating a new random genome and
splicing one gene at a random position on the given one, so it is not very efficient (in many cases
it would suffice to generate one single gene rather than a full genome).
*/

package ga

import (
"math/rand"
)

type GAMutatorRandom struct{}

// Mutate returns a gene which is identical to the given one except for one
// gene, which is replaced with a random one.
func (m GAMutatorRandom) Mutate(a GAGenome) GAGenome {
r := a.Copy()
r.Randomize()
p := rand.Intn(a.Len())

ac := a.Copy()
ac.Splice(r, p, p, 1)
return ac
}
func (m GAMutatorRandom) String() string { return "GAMutatorRandom" }
52 changes: 52 additions & 0 deletions mutator_random_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package ga

import (
"math"
"reflect"
"testing"
)

func TestRandomMutatorReplaces(t *testing.T) {
// A float genome with min/max set to 10. After one mutation, exactly one gene must have
// been replaced with 10.
g := NewFloatGenome([]float64{0, 0}, nil, 10, 10)
m := &GAMutatorRandom{}
gn := m.Mutate(g).(*GAFloatGenome)

if !reflect.DeepEqual(gn.Gene, []float64{0, 10}) &&
!reflect.DeepEqual(gn.Gene, []float64{10, 0}) {
t.Errorf("GAMutatorRandom.Mutate(%v) = %v; want {0, 10} or {10, 0}", g.Gene, gn.Gene)
}
}

func TestRandomMutatorUniform(t *testing.T) {
// A float genome with min/max set to 1. We keep mutating it and checking which gene has
// been mutated, to keep track of the distribution of replacements.
g := NewFloatGenome([]float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, nil, 1, 1)
m := &GAMutatorRandom{}

count := make([]int, len(g.Gene))
for i := 0; i < 100000; i++ {
gn := m.Mutate(g).(*GAFloatGenome)
for i, v := range gn.Gene {
if v > 0 {
count[i]++
}
}
}

min, max := math.MaxInt64, 0
for _, c := range count {
if c < min {
min = c
}
if c > max {
max = c
}
}

if s := float64(min+1) / float64(max+1); s < 0.90 {
t.Errorf("GARandomMutator replacement counters similarity = %v; want >= 0.9", s)
t.Errorf("Gene replacement counters: %v", count)
}
}

0 comments on commit ed4d023

Please sign in to comment.