@@ -16,12 +16,10 @@ import org.evomaster.core.search.service.IdMapper
1616 * - Maintains a current branch target.
1717 * - 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.
1818 */
19-
20-
2119class LIPSAlgorithm <T > : AbstractGeneticAlgorithm <T >() where T : Individual {
2220
2321 private var currentTarget: Int? = null
24- private var budgetLeftForCurrentTarget : Int = 0
22+ private lateinit var budget : LipsBudget
2523
2624 override fun getType (): EMConfig .Algorithm = EMConfig .Algorithm .LIPS
2725
@@ -34,32 +32,51 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
3432 while (population.size < config.populationSize) {
3533 population.add(sampleSuite())
3634 }
35+ // Initialize budget manager and first per-target budget using current uncovered targets
36+ budget = LipsBudget (config, time)
37+ val initUncoveredSize = archive.notCoveredTargets().size
38+ budget.budgetLeftForCurrentTarget = budget.computePerTargetBudget(initUncoveredSize)
39+ println (" [LIPS DEBUG] initPopulation: initial per-target budget set using uncoveredSize=$initUncoveredSize -> budget=${budget.budgetLeftForCurrentTarget} " )
3740 }
3841
3942 override fun searchOnce () {
4043 beginGeneration()
44+ println (" [LIPS DEBUG] searchOnce: ENTER" )
4145 // record budget usage for this generation
4246 val startActions = time.evaluatedActions
4347 val startSeconds = time.getElapsedSeconds()
4448
4549 // Compute uncovered goals
4650 val uncovered = archive.notCoveredTargets()
51+ println (" [LIPS DEBUG] uncovered targets size = ${uncovered.size} " )
4752
4853 // current target is null if covered by previous generation or out of budget
4954 // Pick target if null, or if previously covered (check coverage directly)
5055 val needNewTarget = currentTarget == null || archive.isCovered(currentTarget!! )
56+ println (" [LIPS DEBUG] needNewTarget=$needNewTarget currentTarget=${currentTarget} " )
5157 if (needNewTarget) {
52- val target = firstUncoveredBranch()
58+ println (" [LIPS DEBUG] selecting new target from archive snapshot" )
59+ val target = lastUncoveredBranchTargetId()
5360 currentTarget = target
61+ println (" [LIPS DEBUG] currentTarget set to $currentTarget " )
5462 // Initialize budget for this NEW target
55- budgetLeftForCurrentTarget = calculatePerTargetBudget(uncovered.size)
63+ println (" [LIPS DEBUG] calculating per-target budget with uncoveredSize=${uncovered.size} " )
64+ budget.budgetLeftForCurrentTarget = budget.computePerTargetBudget(uncovered.size)
65+ println (" [LIPS DEBUG] selectTarget: target=$target uncovered=${uncovered.size} budgetLeftForCurrentTarget=${budget.budgetLeftForCurrentTarget} " )
5666 }
5767
58- // Focus scoring on the single selected target
59- frozenTargets = setOf (currentTarget!! )
68+ // Focus scoring on the single selected target if present; otherwise use global fitness
69+ if (currentTarget == null ) {
70+ frozenTargets = emptySet()
71+ println (" [LIPS DEBUG] no currentTarget; using global fitness (frozenTargets empty)" )
72+ } else {
73+ frozenTargets = setOf (currentTarget!! )
74+ println (" [LIPS DEBUG] frozenTargets=${frozenTargets} " )
75+ }
6076
6177 val n = config.populationSize
6278 val nextPop: MutableList <WtsEvalIndividual <T >> = formTheNextPopulation(population)
79+ println (" [LIPS DEBUG] formed base nextPop with elites size=${nextPop.size} target=$currentTarget " )
6380
6481 while (nextPop.size < n) {
6582 beginStep()
@@ -84,9 +101,11 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
84101 nextPop.add(o2)
85102
86103 // Stop if global budget or target budget is up
87- val usedForTarget = usedForCurrentTarget(startActions, startSeconds)
88-
89- if (! time.shouldContinueSearch() || usedForTarget >= budgetLeftForCurrentTarget) {
104+ val usedForTarget = budget.usedForCurrentTarget(startActions, startSeconds)
105+ if ((nextPop.size % 10 ) == 0 || usedForTarget >= budget.budgetLeftForCurrentTarget) {
106+ println (" [LIPS DEBUG] innerLoop: nextSize=${nextPop.size} usedForTarget=$usedForTarget budgetLeft=${budget.budgetLeftForCurrentTarget} " )
107+ }
108+ if (! time.shouldContinueSearch() || usedForTarget >= budget.budgetLeftForCurrentTarget) {
90109 endStep()
91110 break
92111 }
@@ -97,69 +116,40 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
97116 population.addAll(nextPop)
98117
99118 // Update budget usage for this target
100- updatePerTargetBudget(startActions, startSeconds)
119+ budget.updatePerTargetBudget(startActions, startSeconds)
120+ println (" [LIPS DEBUG] afterGen: budgetLeftForCurrentTarget=${budget.budgetLeftForCurrentTarget} " )
101121
102122 // Switch target if covered or out of budget
103- if (shouldSwitchTarget()) currentTarget = null
123+ val coveredNow = population.any { score(it) >= 1.0 }
124+ val switching = budget.shouldSwitchTarget(coveredNow)
125+ println (" [LIPS DEBUG] shouldSwitchTarget=$switching currentTarget=$currentTarget " )
126+ if (switching) currentTarget = null
104127
105128 endGeneration()
129+ println (" [LIPS DEBUG] searchOnce: EXIT" )
106130 }
107131
108- /* *
109- * Calculate per-target budget based on the current stopping criterion.
110- * Returns the fair share: total budget divided by number of uncovered targets.
111- */
112- private fun calculatePerTargetBudget (uncoveredSize : Int ): Int {
113- return when (config.stoppingCriterion) {
114- EMConfig .StoppingCriterion .ACTION_EVALUATIONS -> {
115- val remaining = (config.maxEvaluations - time.evaluatedActions).coerceAtLeast(0 )
116- remaining / uncoveredSize
117- }
118- EMConfig .StoppingCriterion .TIME -> {
119- val remaining = (config.timeLimitInSeconds() - time.getElapsedSeconds()).coerceAtLeast(0 )
120- remaining / uncoveredSize
121- }
122- else -> Int .MAX_VALUE
123- }
124- }
125-
126- /* *
127- * Compute the budget spent since the start of the current generation,
128- * based on the active stopping criterion.
129- */
130- private fun usedForCurrentTarget (startActions : Int , startSeconds : Int ): Int {
131- return when (config.stoppingCriterion) {
132- EMConfig .StoppingCriterion .ACTION_EVALUATIONS -> time.evaluatedActions - startActions
133- EMConfig .StoppingCriterion .TIME -> time.getElapsedSeconds() - startSeconds
134- else -> 0
135- }
136- }
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
132+ fun lastUncoveredBranchTargetId (): Int? {
133+ val snapshot = archive.getSnapshotOfBestIndividuals()
134+ if (snapshot.isEmpty()) return null
151135
152136 // Iterate targets by numeric id in descending order
153- val orderedIds = populations.keys.sortedDescending()
137+ val orderedIds = snapshot.keys.sortedDescending()
138+ println (" [LIPS DEBUG] lastUncoveredBranch: snapshotSize=${snapshot.size} orderedIdsCount=${orderedIds.size} " )
154139
155140 for (targetId in orderedIds) {
156141 val description = archive.getIdMapper().getDescriptiveId(targetId)
157- if (description.startsWith(ObjectiveNaming .BRANCH )) {
158- if (! isCovered(targetId)) {
142+ val isBranch = description.startsWith(ObjectiveNaming .BRANCH )
143+ val covered = archive.isCovered(targetId)
144+ println (" [LIPS DEBUG] candidate targetId=$targetId desc=$description isBranch=$isBranch covered=$covered " )
145+ if (isBranch) {
146+ if (! covered) {
147+ println (" [LIPS DEBUG] lastUncoveredBranch: selected targetId=$targetId " )
159148 return targetId
160149 }
161150 }
162151 }
152+ println (" [LIPS DEBUG] lastUncoveredBranch: no candidate found" )
163153 return null
164154 }
165155}
0 commit comments