140 lines
3.6 KiB
Go
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")
|
|
}
|
|
}
|