gago/speciation_test.go
2021-09-11 12:47:32 +02:00

140 lines
3.6 KiB
Go

package gago
import (
"errors"
"math"
"testing"
)
func TestSpecKMedoidsApply(t *testing.T) {
var (
rng = newRandomNumberGenerator()
testCases = []struct {
indis Individuals
kmeds SpecKMedoids
speciesSizes []int
err error
}{
// Example dataset from https://www.wikiwand.com/en/K-medoids
{
indis: Individuals{
NewIndividual(Vector{2, 6}, rng),
NewIndividual(Vector{3, 4}, rng),
NewIndividual(Vector{3, 8}, rng),
NewIndividual(Vector{4, 7}, rng),
NewIndividual(Vector{6, 2}, rng),
NewIndividual(Vector{6, 4}, rng),
NewIndividual(Vector{7, 3}, rng),
NewIndividual(Vector{7, 4}, rng),
NewIndividual(Vector{8, 5}, rng),
NewIndividual(Vector{7, 6}, rng),
},
kmeds: SpecKMedoids{2, 1, l1Distance, 10},
speciesSizes: []int{4, 6},
err: nil,
},
{
indis: Individuals{
NewIndividual(Vector{1, 1}, rng),
NewIndividual(Vector{1, 1}, rng),
},
kmeds: SpecKMedoids{2, 1, l1Distance, 10},
speciesSizes: []int{1, 1},
err: nil,
},
{
indis: Individuals{
NewIndividual(Vector{1, 1}, rng),
NewIndividual(Vector{1, 2}, rng),
},
kmeds: SpecKMedoids{3, 1, l1Distance, 10},
speciesSizes: []int{1, 1},
err: errors.New("K > len(indis)"),
},
}
)
for i, tc := range testCases {
var species, err = tc.kmeds.Apply(tc.indis, rng)
// Check the number of species is correct
if err == nil && len(species) != tc.kmeds.K {
t.Errorf("Wrong number of species in test case number %d", i)
}
// Check size of each specie
if err == nil {
for j, specie := range species {
if len(specie) != tc.speciesSizes[j] {
t.Errorf("Wrong specie size test case number %d", i)
}
}
}
// Check error is nil or not
if (err == nil) != (tc.err == nil) {
t.Errorf("Wrong error in test case number %d", i)
}
}
}
func TestSpecKMedoidsValidate(t *testing.T) {
var spec = SpecKMedoids{2, 1, l1Distance, 1}
if err := spec.Validate(); err != nil {
t.Error("Validation should not have raised error")
}
// Set K lower than 2
spec.K = 1
if err := spec.Validate(); err == nil {
t.Error("Validation should have raised error")
}
spec.K = 2
// Nullify Metric
spec.Metric = nil
if err := spec.Validate(); err == nil {
t.Error("Validation should have raised error")
}
spec.Metric = l1Distance
// Set MaxIterations lower than 1
spec.MaxIterations = 0
if err := spec.Validate(); err == nil {
t.Error("Validation should have raised error")
}
}
func TestSpecFitnessIntervalApply(t *testing.T) {
var (
nIndividuals = []int{1, 2, 3}
nSpecies = []int{1, 2, 3}
rng = newRandomNumberGenerator()
)
for _, nbi := range nIndividuals {
for _, nbs := range nSpecies {
var (
m = min(int(math.Ceil(float64(nbi/nbs))), nbi)
indis = newIndividuals(nbi, NewVector, rng)
spec = SpecFitnessInterval{K: nbs}
species, _ = spec.Apply(indis, rng)
)
// Check the cluster sizes are equal to min(n-i, m) where i is a
// multiple of m
for i, specie := range species {
var (
expected = min(nbi-i*m, m)
obtained = len(specie)
)
if obtained != expected {
t.Errorf("Wrong number of individuals, expected %d got %d", expected, obtained)
}
}
}
}
}
func TestSpecFitnessIntervalValidate(t *testing.T) {
var spec = SpecFitnessInterval{2}
if err := spec.Validate(); err != nil {
t.Error("Validation should not have raised error")
}
// Set K lower than 2
spec.K = 1
if err := spec.Validate(); err == nil {
t.Error("Validation should have raised error")
}
}