gago/ga_test.go

241 lines
5.6 KiB
Go
Raw Permalink Normal View History

2021-09-11 12:47:32 +02:00
package gago
import (
"errors"
"math"
"testing"
"time"
)
func TestValidationSuccess(t *testing.T) {
var err = ga.Validate()
if err != nil {
t.Error("GA parameters are invalid")
}
}
func TestValidationGenomeFactory(t *testing.T) {
var genomeFactory = ga.GenomeFactory
ga.GenomeFactory = nil
if ga.Validate() == nil {
t.Error("Nil GenomeFactory should return an error")
}
ga.GenomeFactory = genomeFactory
}
func TestValidationNPopulations(t *testing.T) {
var nPops = ga.NPops
ga.NPops = -1
if ga.Validate() == nil {
t.Error("Invalid number of Populations should return an error")
}
ga.NPops = nPops
}
func TestValidationNIndividuals(t *testing.T) {
var popSize = ga.PopSize
ga.PopSize = -1
if ga.Validate() == nil {
t.Error("Invalid number of Individuals should return an error")
}
ga.PopSize = popSize
}
func TestValidationModel(t *testing.T) {
var model = ga.Model
// Check nil model raises error
ga.Model = nil
if ga.Validate() == nil {
t.Error("Nil Model should return an error")
}
// Check invalid model raises error
ga.Model = ModGenerational{
Selector: SelTournament{
NContestants: 3,
},
MutRate: -1,
}
if ga.Validate() == nil {
t.Error("Invalid Model should return an error")
}
ga.Model = model
}
func TestValidationMigFrequency(t *testing.T) {
var (
migrator = ga.Migrator
migFrequency = ga.MigFrequency
)
ga.Migrator = MigRing{}
ga.MigFrequency = 0
if ga.Validate() == nil {
t.Error("Invalid MigFrequency should return an error")
}
ga.Migrator = migrator
ga.MigFrequency = migFrequency
}
func TestValidationSpeciator(t *testing.T) {
var speciator = ga.Speciator
ga.Speciator = SpecFitnessInterval{0}
if ga.Validate() == nil {
t.Error("Invalid Speciator should return an error")
}
ga.Speciator = speciator
}
func TestApplyWithSpeciator(t *testing.T) {
var speciator = ga.Speciator
ga.Speciator = SpecFitnessInterval{4}
if ga.Enhance() != nil {
t.Error("Calling Apply with a valid Speciator should not return an error")
}
ga.Speciator = speciator
}
func TestRandomNumberGenerators(t *testing.T) {
for i, pop1 := range ga.Populations {
for j, pop2 := range ga.Populations {
if i != j && &pop1.rng == &pop2.rng {
t.Error("Population should not share random number generators")
}
}
}
}
func TestBest(t *testing.T) {
for _, pop := range ga.Populations {
for _, indi := range pop.Individuals {
if ga.Best.Fitness > indi.Fitness {
t.Error("The current best individual is not the overall best")
}
}
}
}
func TestFindBest(t *testing.T) {
// Check sure the findBest method works as expected
var fitness = ga.Populations[0].Individuals[0].Fitness
ga.Populations[0].Individuals[0].Fitness = math.Inf(-1)
ga.findBest()
if ga.Best.Fitness != math.Inf(-1) {
t.Error("findBest didn't work")
}
ga.Populations[0].Individuals[0].Fitness = fitness
// Check the best individual doesn't a share a pointer with anyone
fitness = ga.Best.Fitness
ga.Best.Fitness = 42
if ga.Populations[0].Individuals[0].Fitness == 42 {
t.Error("Best individual shares a pointer with an individual in the populations")
}
ga.Best.Fitness = fitness
}
// TestDuration verifies the sum of the duration of each population is higher
// the actual duration. This is due to the fact that each population runs on a
// separate core.
func TestDuration(t *testing.T) {
var totalDuration time.Duration
for _, pop := range ga.Populations {
totalDuration += pop.Age
}
if totalDuration < ga.Age {
t.Error("Inefficient parallelism")
}
}
func TestSpeciateEvolveMerge(t *testing.T) {
var (
rng = newRandomNumberGenerator()
testCases = []struct {
pop Population
speciator Speciator
model Model
err error
}{
{
pop: Population{
ID: "42",
rng: rng,
Individuals: Individuals{
Individual{Fitness: 0},
Individual{Fitness: 1},
Individual{Fitness: 2},
Individual{Fitness: 3},
Individual{Fitness: 4},
},
},
speciator: SpecFitnessInterval{3},
model: ModIdentity{},
err: nil,
},
{
pop: Population{
ID: "42",
rng: rng,
Individuals: Individuals{
Individual{Fitness: 0},
Individual{Fitness: 1},
Individual{Fitness: 2},
},
},
speciator: SpecFitnessInterval{4},
model: ModIdentity{},
err: errors.New("Invalid speciator"),
},
{
pop: Population{
ID: "42",
rng: rng,
Individuals: Individuals{
Individual{Fitness: 0},
Individual{Fitness: 1},
Individual{Fitness: 2},
Individual{Fitness: 3},
Individual{Fitness: 4},
},
},
speciator: SpecFitnessInterval{3},
model: ModGenerational{
Selector: SelTournament{6},
MutRate: 0.5,
},
err: errors.New("Invalid model"),
},
}
)
for i, tc := range testCases {
var err = tc.pop.speciateEvolveMerge(tc.speciator, tc.model)
if (err == nil) != (tc.err == nil) {
t.Errorf("Wrong error in test case number %d", i)
}
// If there is no error check the individuals are ordered as they were
// at they were initially
if err == nil {
for j, indi := range tc.pop.Individuals {
if indi.Fitness != float64(j) {
t.Errorf("Wrong result in test case number %d", i)
}
}
}
}
}
func TestCallback(t *testing.T) {
var (
counter int
incrementCounter = func(ga *GA) {
counter++
}
)
ga.Callback = incrementCounter
ga.Initialize()
if counter != 1 {
t.Error("Counter was not incremented by the callback at initialization")
}
ga.Enhance()
if counter != 2 {
t.Error("Counter was not incremented by the callback at enhancement")
}
}