Skip to content

Commit 9933fd7

Browse files
authored
Merge pull request #22 from TimeDelta/codex/create-unit-tests-for-guidedreproduction-class
Add tests for GuidedReproduction
2 parents 8e2d56b + 2ecf01d commit 9933fd7

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

tests/test_guided_reproduction.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import os
2+
import sys
3+
4+
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
5+
import types
6+
7+
import pytest
8+
9+
from reproduction import GuidedReproduction
10+
11+
12+
class DummyGenome:
13+
def __init__(self, key, fitness=0.0):
14+
self.key = key
15+
self.fitness = fitness
16+
self.crossover_parents = None
17+
self.mutated = False
18+
19+
def configure_crossover(self, p1, p2, config):
20+
self.crossover_parents = (p1.key, p2.key)
21+
22+
def mutate(self, config):
23+
self.mutated = True
24+
25+
26+
class DummySpecies:
27+
def __init__(self, key, members):
28+
self.key = key
29+
self.members = {m.key: m for m in members}
30+
self.adjusted_fitness = None
31+
32+
33+
class DummySpeciesSet:
34+
def __init__(self, species):
35+
self.species = {species.key: species}
36+
37+
38+
class DummyStagnation:
39+
def update(self, species_set, generation):
40+
return [(sid, s, False) for sid, s in species_set.species.items()]
41+
42+
43+
class DummyReporters:
44+
def species_stagnant(self, *args, **kwargs):
45+
pass
46+
47+
def info(self, *args, **kwargs):
48+
pass
49+
50+
51+
class DummyConfig:
52+
def __init__(self, genome_type):
53+
self.genome_type = genome_type
54+
self.genome_config = object()
55+
56+
57+
def make_reproduction(elitism=1, survival_threshold=0.5):
58+
class RC:
59+
def __init__(self):
60+
self.elitism = elitism
61+
self.survival_threshold = survival_threshold
62+
self.min_species_size = 1
63+
64+
return GuidedReproduction(RC(), DummyReporters(), DummyStagnation())
65+
66+
67+
def test_guided_and_standard_offspring():
68+
g1 = DummyGenome(101, fitness=1.0)
69+
g2 = DummyGenome(102, fitness=0.5)
70+
g3 = DummyGenome(103, fitness=0.2)
71+
species = DummySpecies(1, [g1, g2, g3])
72+
species_set = DummySpeciesSet(species)
73+
74+
repro = make_reproduction(elitism=1)
75+
# force deterministic spawn amounts
76+
repro.compute_spawn = lambda *a, **k: [3]
77+
78+
guided_called = {}
79+
80+
def guide_fn(name, features, starting, config, n_offspring):
81+
guided_called["n"] = n_offspring
82+
return [DummyGenome(50)]
83+
84+
repro.guide_fn = guide_fn
85+
86+
config = DummyConfig(DummyGenome)
87+
88+
class DummyTask:
89+
def name(self):
90+
return "dummy"
91+
92+
features = []
93+
94+
pop = repro.reproduce(config, species_set, 3, 0, DummyTask())
95+
96+
assert guided_called["n"] == 1
97+
# expect 3 individuals: 1 elite, 1 guided, 1 crossover
98+
assert len(pop) == 3
99+
assert 101 in pop # elite preserved
100+
assert 50 in pop # guided child
101+
# crossover child gets key 1 from genome_indexer
102+
assert any(isinstance(k, int) and k not in (101, 102, 103, 50) for k in pop)
103+
104+
105+
def test_only_elites_when_spawn_too_small():
106+
g1 = DummyGenome(201, fitness=1.0)
107+
g2 = DummyGenome(202, fitness=0.5)
108+
species = DummySpecies(2, [g1, g2])
109+
species_set = DummySpeciesSet(species)
110+
111+
repro = make_reproduction(elitism=1)
112+
repro.compute_spawn = lambda *a, **k: [1]
113+
114+
repro.guide_fn = lambda *a, **k: pytest.fail("guide_fn should not be called")
115+
116+
config = DummyConfig(DummyGenome)
117+
118+
class DummyTask:
119+
def name(self):
120+
return "dummy"
121+
122+
features = []
123+
124+
pop = repro.reproduce(config, species_set, 2, 0, DummyTask())
125+
126+
# only elite should remain
127+
assert len(pop) == 1
128+
assert 201 in pop

0 commit comments

Comments
 (0)