Skip to content

Commit 57153ca

Browse files
committed
Server UnitTests
1 parent 3339c84 commit 57153ca

File tree

2 files changed

+171
-2
lines changed

2 files changed

+171
-2
lines changed

‎mlp-ea-decentralized/common/ga/server.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (s *Server) MigrateIndividuals(ctx context.Context, batch *IndividualsBatch
129129

130130
// Check if the worst from the population are
131131
// actually better than the bests from the candidates
132-
i, j, k := len(population)-len(candidates)-1, 0, 0
132+
i, j, k := len(population)-len(candidates), 0, 0
133133
for k < s.Pool.NMigrate {
134134
if population[i].Fitness < candidates[j].Fitness {
135135
toAppend[k] = population[i]
@@ -154,7 +154,7 @@ func (s *Server) MigrateIndividuals(ctx context.Context, batch *IndividualsBatch
154154

155155
// Remove the worst ones from the population that were
156156
// not better than the candidates
157-
for a := i; i < len(candidates); i++ {
157+
for a := i; a < len(population); a++ {
158158
s.Pool.population.Remove(population[a])
159159
}
160160

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,170 @@
11
package ga
2+
3+
import (
4+
"context"
5+
"math/rand"
6+
"testing"
7+
8+
"github.com/golang/protobuf/ptypes/empty"
9+
10+
"github.com/salvacorts/TFG-Parasitic-Metaheuristics/mlp-ea-decentralized/common/mlp"
11+
"github.com/salvacorts/eaopt"
12+
"github.com/sirupsen/logrus"
13+
)
14+
15+
func TestBorrowIndividual(t *testing.T) {
16+
mlp.Config.FactoryCfg.MinHiddenNeurons = 2
17+
mlp.Config.FactoryCfg.MaxHiddenNeurons = 4
18+
pool := &PoolModel{Delegate: mlp.DelegateImpl{}}
19+
20+
// We need a buffered chan to not get stuck
21+
input := make(chan eaopt.Individual, 100)
22+
output := make(chan eaopt.Individual, 100)
23+
24+
server := Server{
25+
Log: logrus.New(),
26+
Input: input,
27+
Output: output,
28+
Pool: pool,
29+
}
30+
31+
server.Input <- eaopt.Individual{
32+
ID: "Test",
33+
Fitness: 0,
34+
Evaluated: false,
35+
Genome: mlp.NewRandMLP(rand.New(rand.NewSource(7))),
36+
}
37+
38+
indiv, err := server.BorrowIndividual(context.Background(), &empty.Empty{})
39+
if err != nil {
40+
t.Errorf("Error on server.BorrowIndividual(). %s", err.Error())
41+
} else if indiv.IndividualID != "Test" {
42+
t.Errorf("ID of individual do not match")
43+
}
44+
}
45+
46+
func TestReturnIndividual(t *testing.T) {
47+
mlp.Config.FactoryCfg.MinHiddenNeurons = 2
48+
mlp.Config.FactoryCfg.MaxHiddenNeurons = 4
49+
pool := &PoolModel{Delegate: mlp.DelegateImpl{}}
50+
51+
input := make(chan eaopt.Individual, 100)
52+
output := make(chan eaopt.Individual, 100)
53+
54+
server := Server{
55+
Log: logrus.New(),
56+
Input: input,
57+
Output: output,
58+
Pool: pool,
59+
}
60+
61+
indiv := &Individual{
62+
IndividualID: "Test",
63+
Evaluated: true,
64+
Fitness: 0,
65+
Genome: pool.Delegate.SerializeGenome(
66+
mlp.NewRandMLP(rand.New(rand.NewSource(7)))),
67+
}
68+
69+
_, err := server.ReturnIndividual(context.Background(), indiv)
70+
if err != nil {
71+
t.Errorf("Error on server.ReturnIndividual(). %s", err.Error())
72+
} else {
73+
indiv2 := <-server.Output
74+
75+
if indiv2.ID != indiv.IndividualID {
76+
t.Errorf("Returned individual ID do not match the original")
77+
}
78+
}
79+
}
80+
81+
func TestMigrateIndividuals(t *testing.T) {
82+
size := 10
83+
rnd := rand.New(rand.NewSource(7))
84+
mlp.Config.FactoryCfg.MinHiddenNeurons = 2
85+
mlp.Config.FactoryCfg.MaxHiddenNeurons = 4
86+
pool := MakePool(size, 9999, 9998, []string{}, rnd, mlp.NewRandMLP)
87+
pool.Delegate = mlp.DelegateImpl{}
88+
pool.SortFunc = mlp.SortByFitnessAndNeurons
89+
pool.NMigrate = 4
90+
91+
input := make(chan eaopt.Individual, 100)
92+
output := make(chan eaopt.Individual, 100)
93+
94+
server := Server{
95+
Log: logrus.New(),
96+
Input: input,
97+
Output: output,
98+
Pool: pool,
99+
}
100+
101+
// All individuals in population to fitness [0, 10, 20, ..., 100]
102+
for i, in := range pool.GetPopulationSnapshot() {
103+
in.Fitness = float64(i * 100)
104+
in.Evaluated = true
105+
pool.population.Add(in)
106+
}
107+
108+
batch := &IndividualsBatch{
109+
Individuals: []Individual{
110+
Individual{
111+
IndividualID: "Test1",
112+
Fitness: 5,
113+
Genome: pool.Delegate.SerializeGenome(mlp.NewRandMLP(rnd)),
114+
},
115+
Individual{
116+
IndividualID: "Test2",
117+
Fitness: 15,
118+
Genome: pool.Delegate.SerializeGenome(mlp.NewRandMLP(rnd)),
119+
},
120+
Individual{
121+
IndividualID: "Test3",
122+
Fitness: 1005,
123+
Genome: pool.Delegate.SerializeGenome(mlp.NewRandMLP(rnd)),
124+
},
125+
Individual{
126+
IndividualID: "Test4",
127+
Fitness: 2005,
128+
Genome: pool.Delegate.SerializeGenome(mlp.NewRandMLP(rnd)),
129+
},
130+
},
131+
}
132+
133+
_, err := server.MigrateIndividuals(context.Background(), batch)
134+
if err != nil {
135+
t.Errorf("Error on server.TestMigrateIndividuals(). %s", err.Error())
136+
} else {
137+
138+
if pool.population.Length() != size {
139+
t.Errorf("Migrate increased population size")
140+
}
141+
142+
snap := pool.GetPopulationSnapshot()
143+
scores := make([]float64, 0, len(snap))
144+
found := make(map[string]bool)
145+
for _, is := range snap {
146+
scores = append(scores, is.Fitness)
147+
for _, ib := range batch.Individuals {
148+
if is.ID == ib.IndividualID {
149+
found[ib.IndividualID] = true
150+
}
151+
}
152+
}
153+
154+
t.Logf("Snap: %v", scores)
155+
156+
// We expect Test1 and Test2 to be on the population
157+
// and Test3 and T4 to not being in there
158+
if found["Test3"] || found["Test4"] {
159+
t.Errorf("Migration replaced better individuals by worse ones")
160+
}
161+
162+
if !found["Test1"] || !found["Test2"] {
163+
t.Errorf("Migration did not replace better individuals by worst ones")
164+
}
165+
166+
if pool.BestSolution.ID != "Test1" || pool.BestSolution.Fitness != 5 {
167+
t.Errorf("Migration did not replace the best individual")
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)