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") } }