@@ -8,14 +8,21 @@ import kotlin.math.abs
88/* *
99 * Chemical Reaction Optimization (CRO)
1010 *
11- * Each molecule corresponds to a [WtsEvalIndividual] (a test suite). Potential energy (PE)
12- * is defined as the negative of the combined fitness of the suite, so that minimization
13- * semantics of the CRO equations align with EvoMaster's higher-is-better fitness.
11+ * Each molecule corresponds to a [WtsEvalIndividual] (a test suite).
1412 */
1513class CroAlgorithm <T > : AbstractGeneticAlgorithm <T >() where T : Individual {
1614
1715 private val molecules: MutableList <Molecule <T >> = mutableListOf ()
1816 private lateinit var reactor: CroReactor <T >
17+ private var reactorFactory:
18+ (EMConfig ,
19+ org.evomaster.core.search.service.Randomness ,
20+ (WtsEvalIndividual <T >) -> Unit ,
21+ (WtsEvalIndividual <T >) -> Double ,
22+ (WtsEvalIndividual <T >, WtsEvalIndividual <T >) -> Unit ) -> CroReactor <T > =
23+ { emConfig, randomnessService, mutateFn, potentialFn, crossoverFn ->
24+ CroReactor (emConfig, randomnessService, mutateFn, potentialFn, crossoverFn)
25+ }
1926
2027 // container is the global energy reservoir.
2128 // It collects kinetic energy lost in reactions and can be borrowed to enable otherwise infeasible decompositions, keeping total energy conserved.
@@ -36,13 +43,13 @@ class CroAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
3643 // Initialize the underlying GA population to reuse sampling utilities
3744 super .setupBeforeSearch()
3845
39- // Initialize reactor with dependencies once
40- reactor = CroReactor (
41- config = config ,
42- randomness = randomness ,
43- mutate = this ::mutate,
44- potential = this ::potential,
45- xover = this ::xover
46+ // Initialize reactor with dependencies once (allow overriding via factory for tests)
47+ reactor = reactorFactory (
48+ config,
49+ randomness,
50+ this ::mutate,
51+ this ::potential,
52+ this ::xover
4653 )
4754
4855 // Convert GA population to CRO molecules with initial KE
@@ -54,6 +61,27 @@ class CroAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
5461 initialEnergy = getCurrentEnergy()
5562 }
5663
64+ /* *
65+ * Allows tests to inject a deterministic reactor without reflection.
66+ * Must be called before [setupBeforeSearch].
67+ */
68+ fun setReactorFactoryForTesting (factory :
69+ (EMConfig ,
70+ org.evomaster.core.search.service.Randomness ,
71+ (WtsEvalIndividual <T >) -> Unit ,
72+ (WtsEvalIndividual <T >) -> Double ,
73+ (WtsEvalIndividual <T >, WtsEvalIndividual <T >) -> Unit ) -> CroReactor <T >
74+ ) {
75+ this .reactorFactory = factory
76+ }
77+
78+ /* *
79+ * Read-only snapshot of molecules for assertions in tests.
80+ */
81+ fun getMoleculesSnapshot (): List <Molecule <T >> = molecules.map { m ->
82+ Molecule (m.suite, m.kineticEnergy, m.numCollisions)
83+ }
84+
5785 override fun searchOnce () {
5886
5987 if (randomness.nextDouble() > config.croMolecularCollisionRate || molecules.size == 1 ) {
0 commit comments