Skip to content

Commit 3dbddc1

Browse files
committed
Use execution source priority as a secondary sort key
1 parent 1eb5e13 commit 3dbddc1

File tree

3 files changed

+67
-28
lines changed

3 files changed

+67
-28
lines changed

utbot-framework-test/src/test/kotlin/org/utbot/framework/minimization/MinimizationGreedyEssentialTest.kt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import org.junit.jupiter.api.Test
99
class MinimizationGreedyEssentialTest {
1010
@Test
1111
fun testEmpty() {
12-
val executions = emptyMap<Int, List<Int>>()
12+
val executions = emptyMap<Int, Pair<Int, List<Int>>>()
1313
val minimizedExecutions = GreedyEssential.minimize(executions)
1414
assertTrue(minimizedExecutions.isEmpty())
1515
}
1616

1717
@Test
1818
fun testCustom1() {
1919
val executions = mapOf(
20-
1 to listOf(1, 2, 3, 4, 5),
21-
2 to listOf(2, 3, 4, 5, 6, 7),
22-
3 to listOf(1, 7),
23-
4 to listOf(8),
24-
5 to listOf(1, 8)
20+
1 to (0 to listOf(1, 2, 3, 4, 5)),
21+
2 to (0 to listOf(2, 3, 4, 5, 6, 7)),
22+
3 to (0 to listOf(1, 7)),
23+
4 to (0 to listOf(8)),
24+
5 to (0 to listOf(1, 8))
2525
)
2626
val minimizedExecutions = GreedyEssential.minimize(executions)
2727
assertEquals(listOf(2, 5), minimizedExecutions)
@@ -30,11 +30,11 @@ class MinimizationGreedyEssentialTest {
3030
@Test
3131
fun testCustom2() {
3232
val executions = mapOf(
33-
10 to listOf(1, 2, 3, 4, 5),
34-
20 to listOf(2, 3, 4, 5, 6, 7),
35-
21 to listOf(1, 7, 2, 3, 5),
36-
24 to listOf(8, 5, 6, 7),
37-
50 to listOf(1, 8)
33+
10 to (0 to listOf(1, 2, 3, 4, 5)),
34+
20 to (0 to listOf(2, 3, 4, 5, 6, 7)),
35+
21 to (0 to listOf(1, 7, 2, 3, 5)),
36+
24 to (0 to listOf(8, 5, 6, 7)),
37+
50 to (0 to listOf(1, 8))
3838
)
3939
val minimizedExecutions = GreedyEssential.minimize(executions)
4040
assertEquals(listOf(20, 50), minimizedExecutions)
@@ -44,9 +44,9 @@ class MinimizationGreedyEssentialTest {
4444
fun testBigExecutionAndSmallExecutions() {
4545
val size = 10000
4646
val executions = (1..size)
47-
.associateWith { listOf(it, it + size, it + 2 * size) }
47+
.associateWith { 0 to listOf(it, it + size, it + 2 * size) }
4848
.toMutableMap().apply {
49-
put(0, (1..3 * size).toList())
49+
put(0, 0 to (1..3 * size).toList())
5050
}
5151
val minimizedExecutions = GreedyEssential.minimize(executions)
5252
assertEquals(listOf(0), minimizedExecutions.sorted())
@@ -56,15 +56,15 @@ class MinimizationGreedyEssentialTest {
5656
fun testSameSizeExecutions() {
5757
val size = 2000
5858
val executionSize = 100
59-
val executions = (0 until size).associateWith { (it until min(size, it + executionSize)).toList() }
59+
val executions = (0 until size).associateWith { 0 to (it until min(size, it + executionSize)).toList() }
6060
val minimizedExecutions = GreedyEssential.minimize(executions)
6161
assertEquals(fromClosedRange(0, size - 1, executionSize).toList(), minimizedExecutions.sorted())
6262
}
6363

6464
@Test
6565
fun testManyExcluding() {
6666
val size = 10000
67-
val executions = (1..size).associateWith { listOf(it, it + size, it + 2 * size) }
67+
val executions = (1..size).associateWith { 0 to listOf(it, it + size, it + 2 * size) }
6868
val minimizedExecutions = GreedyEssential.minimize(executions)
6969
assertEquals((1..size).toList(), minimizedExecutions.sorted())
7070
}

utbot-framework/src/main/kotlin/org/utbot/framework/minimization/GreedyEssential.kt

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,58 @@
11
package org.utbot.framework.minimization
22

3+
import org.utbot.framework.UtSettings
34
import java.util.PriorityQueue
45

5-
private inline class ExecutionNumber(val number: Int)
6+
@JvmInline
7+
private value class ExecutionNumber(val number: Int)
68

7-
private inline class LineNumber(val number: Int)
9+
@JvmInline
10+
private value class LineNumber(val number: Int)
11+
12+
@JvmInline
13+
private value class SourcePriority(val number: Int)
14+
15+
private data class CoveredLinesWithSourcePriority(
16+
val sourcePriority: SourcePriority,
17+
val coveredLines: List<LineNumber>
18+
)
819

920
/**
1021
* [Greedy essential algorithm](CONFLUENCE:Test+Minimization)
1122
*/
1223
class GreedyEssential private constructor(
13-
executionToCoveredLines: Map<ExecutionNumber, List<LineNumber>>
24+
executionToCoveredLines: Map<ExecutionNumber, CoveredLinesWithSourcePriority>
1425
) {
26+
private val executionToSourcePriority: Map<ExecutionNumber, SourcePriority> =
27+
executionToCoveredLines
28+
.mapValues { it.value.sourcePriority }
29+
1530
private val executionToUsefulLines: Map<ExecutionNumber, MutableSet<LineNumber>> =
1631
executionToCoveredLines
17-
.mapValues { it.value.toMutableSet() }
32+
.mapValues { it.value.coveredLines.toMutableSet() }
1833

1934
private val lineToUnusedCoveringExecutions: Map<LineNumber, MutableSet<ExecutionNumber>> =
2035
executionToCoveredLines
21-
.flatMap { (execution, lines) -> lines.map { it to execution } }
36+
.flatMap { (execution, lines) -> lines.coveredLines.map { it to execution } }
2237
.groupBy({ it.first }) { it.second }
2338
.mapValues { it.value.toMutableSet() }
2439

40+
private val executionComparator = if (UtSettings.preferSymbolicExecutionsDuringMinimization) {
41+
compareByDescending<Triple<ExecutionNumber, Int, SourcePriority>> { it.second }
42+
.thenBy { it.third.number }
43+
.thenBy { it.first.number }
44+
} else {
45+
compareByDescending<Triple<ExecutionNumber, Int, SourcePriority>> { it.second }
46+
.thenBy { it.first.number }
47+
}
48+
2549
private val executionByPriority =
26-
PriorityQueue(compareByDescending<Pair<ExecutionNumber, Int>> { it.second }.thenBy { it.first.number })
50+
PriorityQueue(executionComparator)
2751
.apply {
2852
addAll(
2953
executionToCoveredLines
3054
.keys
31-
.map { it to executionToUsefulLines[it]!!.size }
55+
.map { Triple(it, executionToUsefulLines[it]!!.size, executionToSourcePriority[it]!!) }
3256
)
3357
}
3458

@@ -69,7 +93,7 @@ class GreedyEssential private constructor(
6993
}
7094

7195
private fun executionToPriority(execution: ExecutionNumber) =
72-
execution to executionToUsefulLines[execution]!!.size
96+
Triple(execution, executionToUsefulLines[execution]!!.size, executionToSourcePriority[execution]!!)
7397

7498
private fun removeLineFromExecution(execution: ExecutionNumber, line: LineNumber) {
7599
executionByPriority.remove(executionToPriority(execution))
@@ -89,10 +113,15 @@ class GreedyEssential private constructor(
89113
*
90114
* @return retained execution ids.
91115
*/
92-
fun minimize(executions: Map<Int, List<Int>>): List<Int> {
116+
fun minimize(executions: Map<Int, Pair<Int, List<Int>>>): List<Int> {
93117
val convertedExecutions = executions
94118
.entries
95-
.associate { (execution, lines) -> ExecutionNumber(execution) to lines.map { LineNumber(it) } }
119+
.associate { (execution, coveredLinesWithSourcePriority) ->
120+
ExecutionNumber(execution) to CoveredLinesWithSourcePriority(
121+
SourcePriority(coveredLinesWithSourcePriority.first),
122+
coveredLinesWithSourcePriority.second.map { LineNumber(it) }
123+
)
124+
}
96125

97126
val prioritizer = GreedyEssential(convertedExecutions)
98127
val list = mutableListOf<ExecutionNumber>()

utbot-framework/src/main/kotlin/org/utbot/framework/minimization/Minimization.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ import org.utbot.framework.plugin.api.UtExecutableCallModel
1313
import org.utbot.framework.plugin.api.UtExecution
1414
import org.utbot.framework.plugin.api.UtExecutionFailure
1515
import org.utbot.framework.plugin.api.UtExecutionResult
16+
import org.utbot.framework.plugin.api.UtFailedExecution
1617
import org.utbot.framework.plugin.api.UtModel
1718
import org.utbot.framework.plugin.api.UtNullModel
1819
import org.utbot.framework.plugin.api.UtPrimitiveModel
1920
import org.utbot.framework.plugin.api.UtStatementModel
21+
import org.utbot.framework.plugin.api.UtSymbolicExecution
2022
import org.utbot.framework.plugin.api.UtVoidModel
23+
import org.utbot.fuzzer.UtFuzzedExecution
2124

2225

2326
/**
@@ -64,6 +67,13 @@ fun minimizeExecutions(executions: List<UtExecution>): List<UtExecution> {
6467
}
6568
}
6669

70+
private fun UtExecution.getSourcePriority(): Int = when (this) {
71+
is UtSymbolicExecution -> 0
72+
is UtFuzzedExecution -> 1
73+
is UtFailedExecution -> 2
74+
else -> 3
75+
}
76+
6777
/**
6878
* Groups the [executions] by their `paths` on `first` [branchInstructionsNumber] `branch` instructions.
6979
*
@@ -144,11 +154,11 @@ private fun <T : Any> groupExecutionsByTestSuite(
144154
/**
145155
* Builds a mapping from execution id to edges id.
146156
*/
147-
private fun buildMapping(executions: List<UtExecution>): Map<Int, List<Int>> {
157+
private fun buildMapping(executions: List<UtExecution>): Map<Int, Pair<Int, List<Int>>> {
148158
// (inst1, instr2) -> edge id --- edge represents as a pair of instructions, which are connected by this edge
149159
val allCoveredEdges = mutableMapOf<Pair<Long, Long>, Int>()
150160
val thrownExceptions = mutableMapOf<String, Long>()
151-
val mapping = mutableMapOf<Int, List<Int>>()
161+
val mapping = mutableMapOf<Int, Pair<Int, List<Int>>>()
152162

153163

154164
executions.forEachIndexed { idx, execution ->
@@ -167,7 +177,7 @@ private fun buildMapping(executions: List<UtExecution>): Map<Int, List<Int>> {
167177
for (i in 0 until instructions.size - 1) {
168178
edges += allCoveredEdges[instructions[i] to instructions[i + 1]]!!
169179
}
170-
mapping[idx] = edges
180+
mapping[idx] = execution.getSourcePriority() to edges
171181
}
172182
}
173183
}

0 commit comments

Comments
 (0)