@@ -120,6 +120,54 @@ class MuPlusLambdaEvolutionaryAlgorithmTest {
120120 assertEquals(0 , rec.mutated.size)
121121 }
122122 }
123+
124+ // One iteration properties: population size, best-µ selection, mutation count
125+ @Test
126+ fun testNextGenerationIsTheBestMuOfParentsUnionOffspring () {
127+ TestUtils .handleFlaky {
128+ val ea = injector.getInstance(
129+ Key .get(object : TypeLiteral <MuPlusLambdaEvolutionaryAlgorithm <OneMaxIndividual >>() {})
130+ )
131+
132+ val rec = GARecorder <OneMaxIndividual >()
133+ ea.addObserver(rec)
134+
135+ val config = injector.getInstance(EMConfig ::class .java)
136+ config.populationSize = 5
137+ config.muPlusLambdaOffspringSize = 10 // divisible by mu -> perParent = 2
138+ config.xoverProbability = 0.0 // not used in (µ+λ)
139+ config.fixedRateMutation = 1.0 // force mutation on all offspring
140+
141+ // initialize population and snapshot parents
142+ ea.setupBeforeSearch()
143+ val parents = ea.getViewOfPopulation().toList()
144+
145+ // run a single generation
146+ ea.searchOnce()
147+
148+ val finalPop = ea.getViewOfPopulation()
149+ val mu = config.populationSize
150+
151+ // 1) population size remains µ
152+ assertEquals(mu, finalPop.size)
153+
154+ // 2) final population equals best-µ of parents ∪ offspring (compare scores)
155+ val offspring = rec.mutated.toList()
156+ val expectedScores = (parents + offspring)
157+ .map { ea.score(it) }
158+ .sortedDescending()
159+ .take(mu)
160+ val finalScores = finalPop
161+ .map { ea.score(it) }
162+ .sortedDescending()
163+ assertEquals(expectedScores, finalScores)
164+
165+ // 3) with fixedRateMutation=1, mutations equal number of created offspring
166+ val perParent = config.muPlusLambdaOffspringSize / config.populationSize
167+ val expectedMutations = perParent * config.populationSize
168+ assertEquals(expectedMutations, rec.mutated.size)
169+ }
170+ }
123171}
124172
125173
0 commit comments