@@ -4,15 +4,20 @@ import org.evomaster.core.EMConfig
44import org.evomaster.core.search.FitnessValue
55import org.evomaster.core.search.Individual
66import org.evomaster.core.search.algorithms.wts.WtsEvalIndividual
7+ import org.evomaster.client.java.instrumentation.shared.ObjectiveNaming
8+ import org.evomaster.core.search.service.IdMapper
79
810/* *
9- * LIPS (Linearly Independent Path-based Search).
10- * Single-objective GA that optimizes one target (branch) at a time.
11+ * Linearly Independent Path-based Search (LIPS).
1112 *
12- * - Picks a current target from the uncovered set.
13- * - Runs one GA generation to evolve the population towards the current target.
14- * - when current target is covered or its budget is spent, select a new current target.
13+ * A single-objective GA that optimizes one branch target at a time.
14+ *
15+ * - Initializes a random individual i and build the initial population P = random ∪ {i}.
16+ * - Maintains a current branch target.
17+ * - Per-target budget is a fair share of the global TIME/ACTIONS budget; switches target when the target is covered or its budget is exhausted.
1518 */
19+
20+
1621class LIPSAlgorithm <T > : AbstractGeneticAlgorithm <T >() where T : Individual {
1722
1823 private var currentTarget: Int? = null
@@ -21,51 +26,33 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
2126 override fun getType (): EMConfig .Algorithm = EMConfig .Algorithm .LIPS
2227
2328 override fun initPopulation () {
24- println (" [LIPS DEBUG] initPopulation: enter" )
2529 population.clear()
26- println (" [LIPS DEBUG] initPopulation: population cleared" )
27-
2830 // 1) Generate Random Individual
29- println (" [LIPS DEBUG] initPopulation: sampling initial individual" )
3031 val i = sampleSuite()
31- println (" [LIPS DEBUG] initPopulation: sampled initial individual" )
32-
3332 // 2) P <- RandomPopulation(ps-1) ∪ {i}
3433 population.add(i)
35- println (" [LIPS DEBUG] initPopulation: added initial individual, pop=${population.size} " )
3634 while (population.size < config.populationSize) {
3735 population.add(sampleSuite())
38- if (population.size % 5 == 0 || population.size == config.populationSize) {
39- println (" [LIPS DEBUG] initPopulation: growing pop=${population.size} /${config.populationSize} " )
40- }
4136 }
42- println (" [LIPS DEBUG] initPopulation: exit with pop=${population.size} " )
4337 }
4438
4539 override fun searchOnce () {
4640 beginGeneration()
47- println (" [LIPS DEBUG] searchOnce: popSize=${population.size} " )
41+ // record budget usage for this generation
42+ val startActions = time.evaluatedActions
43+ val startSeconds = time.getElapsedSeconds()
4844
4945 // Compute uncovered goals
5046 val uncovered = archive.notCoveredTargets()
51- println (" [LIPS DEBUG] searchOnce: uncoveredSize=${uncovered.size} " )
52- if (uncovered.isEmpty()) {
53- println (" [LIPS DEBUG] searchOnce: uncovered is EMPTY; ending generation" )
54- endGeneration()
55- return
56- } else {
57- println (" [LIPS DEBUG] searchOnce: uncovered is NOT EMPTY" )
58- }
5947
6048 // current target is null if covered by previous generation or out of budget
61-
62- // Pick target if null, or if previously covered
63- if (currentTarget == null || ! uncovered.contains(currentTarget) ) {
64- val target = uncovered.last ()
49+ // Pick target if null, or if previously covered (check coverage directly)
50+ val needNewTarget = currentTarget == null || archive.isCovered(currentTarget !! )
51+ if (needNewTarget ) {
52+ val target = firstUncoveredBranch ()
6553 currentTarget = target
6654 // Initialize budget for this NEW target
6755 budgetLeftForCurrentTarget = calculatePerTargetBudget(uncovered.size)
68- println (" [LIPS DEBUG] selectTarget: target=$target uncovered=${uncovered.size} budgetLeftForCurrentTarget=$budgetLeftForCurrentTarget " )
6956 }
7057
7158 // Focus scoring on the single selected target
@@ -74,10 +61,6 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
7461 val n = config.populationSize
7562 val nextPop: MutableList <WtsEvalIndividual <T >> = formTheNextPopulation(population)
7663
77- // record budget usage for this generation
78- val startActions = time.evaluatedActions
79- val startSeconds = time.getElapsedSeconds()
80-
8164 while (nextPop.size < n) {
8265 beginStep()
8366
@@ -114,17 +97,10 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
11497 population.addAll(nextPop)
11598
11699 // Update budget usage for this target
117- val usedForTarget = usedForCurrentTarget(startActions, startSeconds)
118- budgetLeftForCurrentTarget - = usedForTarget
119- println (" [LIPS DEBUG] afterGen: target=${currentTarget} used=$usedForTarget budgetLeftForCurrentTarget=$budgetLeftForCurrentTarget " )
100+ updatePerTargetBudget(startActions, startSeconds)
120101
121- // Check if target is covered or out of budget
122- val coveredNow = population.any { score(it) >= 1.0 }
123- val outOfBudget = budgetLeftForCurrentTarget <= 0
124-
125- if (coveredNow || outOfBudget) {
126- currentTarget = null
127- }
102+ // Switch target if covered or out of budget
103+ if (shouldSwitchTarget()) currentTarget = null
128104
129105 endGeneration()
130106 }
@@ -158,6 +134,34 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
158134 else -> 0
159135 }
160136 }
137+
138+ private fun updatePerTargetBudget (actionsAtGenStart : Int , secondsAtGenStart : Int ) {
139+ val usedForTarget = usedForCurrentTarget(actionsAtGenStart, secondsAtGenStart)
140+ budgetLeftForCurrentTarget - = usedForTarget
141+ }
142+
143+ private fun shouldSwitchTarget (): Boolean {
144+ val coveredNow = population.any { score(it) >= 1.0 }
145+ val outOfBudget = budgetLeftForCurrentTarget <= 0
146+ return coveredNow || outOfBudget
147+ }
148+
149+ fun firstUncoveredBranch (): Int? {
150+ if (populations.isEmpty()) return null
151+
152+ // Iterate targets by numeric id in descending order
153+ val orderedIds = populations.keys.sortedDescending()
154+
155+ for (targetId in orderedIds) {
156+ val description = archive.getIdMapper().getDescriptiveId(targetId)
157+ if (description.startsWith(ObjectiveNaming .BRANCH )) {
158+ if (! isCovered(targetId)) {
159+ return targetId
160+ }
161+ }
162+ }
163+ return null
164+ }
161165}
162166
163167
0 commit comments