@@ -17,9 +17,38 @@ import org.evomaster.core.search.algorithms.wts.WtsEvalIndividual
1717class LIPSAlgorithm <T > : AbstractGeneticAlgorithm <T >() where T : Individual {
1818
1919 private var currentTarget: Int? = null
20+ private val budgetLeftPerTarget: MutableMap <Int , Int > = mutableMapOf ()
2021
2122 override fun getType (): EMConfig .Algorithm = EMConfig .Algorithm .LIPS
2223
24+ override fun initPopulation () {
25+ population.clear()
26+
27+ // 1) Generate i
28+ val i = sampleSuite()
29+
30+ // 2) Compute uncovered
31+ val uncovered = archive.notCoveredTargets()
32+ if (uncovered.isEmpty()) {
33+ return
34+ }
35+
36+ // 3) Select current target b
37+ val target = uncovered.last()
38+ currentTarget = target
39+ frozenTargets = setOf (target)
40+
41+ // 4) initialize per-target budget
42+ val perTarget = calculatePerTargetBudget(uncovered.size)
43+ budgetLeftPerTarget.putIfAbsent(target, perTarget)
44+
45+ // 5) P <- RandomPopulation(ps-1) ∪ {i}
46+ population.add(i)
47+ while (population.size < config.populationSize) {
48+ population.add(sampleSuite())
49+ }
50+ }
51+
2352 override fun searchOnce () {
2453 beginGeneration()
2554
@@ -36,16 +65,20 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
3665 }
3766
3867 // Focus scoring on the single selected target
39- frozenTargets = setOf (currentTarget!! )
40-
41- // Ensure population exists
42- if (population.isEmpty()) {
43- initPopulation()
44- }
68+ frozenTargets = setOf (currentTarget)
4569
4670 val n = config.populationSize
4771 val nextPop: MutableList <WtsEvalIndividual <T >> = formTheNextPopulation(population)
4872
73+ // record budget usage for this generation
74+ val startActions = time.evaluatedActions
75+ val startSeconds = time.getElapsedSeconds()
76+
77+ val t = currentTarget!!
78+ val targetBudgetLeft = budgetLeftPerTarget.getOrPut(t) {
79+ calculatePerTargetBudget(uncovered.size)
80+ }
81+
4982 while (nextPop.size < n) {
5083 beginStep()
5184
@@ -69,8 +102,14 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
69102 val a = if (score(o1) >= score(o2)) o1 else o2
70103 nextPop.add(a)
71104
72- // Stop if time is up
73- if (! time.shouldContinueSearch()) {
105+ // Stop if global budget or target budget is up
106+ val usedForTarget = when (config.stoppingCriterion) {
107+ EMConfig .StoppingCriterion .ACTION_EVALUATIONS -> time.evaluatedActions - startActions
108+ EMConfig .StoppingCriterion .TIME -> time.getElapsedSeconds() - startSeconds
109+ else -> 0
110+ }
111+
112+ if (! time.shouldContinueSearch() || usedForTarget >= targetBudgetLeft) {
74113 endStep()
75114 break
76115 }
@@ -80,14 +119,40 @@ class LIPSAlgorithm<T> : AbstractGeneticAlgorithm<T>() where T : Individual {
80119 population.clear()
81120 population.addAll(nextPop)
82121
83- // If target got covered (score 1 for any in pop), refresh target next time
122+ // Update budget usage for this target
123+ currentTarget?.let { target ->
124+ val usedForTarget = when (config.stoppingCriterion) {
125+ EMConfig .StoppingCriterion .ACTION_EVALUATIONS -> time.evaluatedActions - startActions
126+ EMConfig .StoppingCriterion .TIME -> time.getElapsedSeconds() - startSeconds
127+ else -> 0
128+ }
129+ budgetLeftPerTarget[target] = (budgetLeftPerTarget[target] ? : 0 ) - usedForTarget
130+ }
131+
132+ // Check if target is covered or out of budget
84133 val coveredNow = population.any { score(it) >= 1.0 }
85- if (coveredNow) {
134+ val outOfBudget = currentTarget?.let { (budgetLeftPerTarget[it] ? : 1 ) <= 0 } ? : false
135+
136+ if (coveredNow || outOfBudget) {
86137 currentTarget = null
87138 }
88139
89140 endGeneration()
90141 }
142+
143+ /* *
144+ * Calculate per-target budget based on the current stopping criterion.
145+ * Returns the fair share: total budget divided by number of uncovered targets.
146+ */
147+ private fun calculatePerTargetBudget (uncoveredSize : Int ): Int {
148+ return when (config.stoppingCriterion) {
149+ EMConfig .StoppingCriterion .ACTION_EVALUATIONS ->
150+ config.maxEvaluations / uncoveredSize
151+ EMConfig .StoppingCriterion .TIME ->
152+ config.timeLimitInSeconds() / uncoveredSize
153+ else -> Int .MAX_VALUE
154+ }
155+ }
91156}
92157
93158
0 commit comments