Skip to content

Commit d61b7a9

Browse files
committed
Added simplification/rewriting for assumptions
1 parent 715c59b commit d61b7a9

File tree

8 files changed

+90
-48
lines changed

8 files changed

+90
-48
lines changed

utbot-framework-test/src/test/kotlin/org/utbot/engine/pc/QueryOptimizationsTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import kotlinx.collections.immutable.persistentListOf
3434
import org.junit.jupiter.api.AfterAll
3535
import org.junit.jupiter.api.BeforeAll
3636
import org.junit.jupiter.api.Test
37+
import org.utbot.engine.symbolic.EmptyAssumption
3738

3839
private var expressionSimplificationValue: Boolean = UtSettings.useExpressionSimplification
3940

@@ -51,7 +52,7 @@ fun afterAll() {
5152
class QueryOptimizationsTest {
5253

5354
private fun BaseQuery.check(vararg exprs: UtBoolExpression, checker: (BaseQuery) -> Unit = {}): BaseQuery =
54-
this.with(hard = exprs.toList(), soft = emptyList()).also {
55+
this.with(hard = exprs.toList(), soft = emptyList(), assumptions = EmptyAssumption).also {
5556
checker(it)
5657
}
5758

utbot-framework-test/src/test/kotlin/org/utbot/examples/stream/BaseStreamExampleTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ class BaseStreamExampleTest : UtValueTestCaseChecker(
8787
}
8888

8989
@Test
90-
@Disabled("Java 11 transition -- Yura looks at this. We have similar issue with Strings")
9190
fun testDistinctExample() {
9291
check(
9392
BaseStreamExample::distinctExample,

utbot-framework/src/main/kotlin/org/utbot/engine/DataClasses.kt

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ import org.utbot.engine.pc.UtIsExpression
88
import org.utbot.engine.pc.UtTrue
99
import org.utbot.engine.pc.mkAnd
1010
import org.utbot.engine.pc.mkOr
11-
import org.utbot.engine.symbolic.Assumption
12-
import org.utbot.engine.symbolic.HardConstraint
13-
import org.utbot.engine.symbolic.SoftConstraint
14-
import org.utbot.engine.symbolic.SymbolicStateUpdate
11+
import org.utbot.engine.symbolic.*
1512
import org.utbot.framework.plugin.api.FieldId
1613
import org.utbot.framework.plugin.api.UtInstrumentation
1714
import java.util.Objects
@@ -133,17 +130,17 @@ data class MethodResult(
133130

134131
constructor(
135132
symbolicResult: SymbolicResult,
136-
hardConstraints: HardConstraint = HardConstraint(),
137-
softConstraints: SoftConstraint = SoftConstraint(),
138-
assumption: Assumption = Assumption(),
133+
hardConstraints: HardConstraint = EmptyHardConstraint,
134+
softConstraints: SoftConstraint = EmptySoftConstraint,
135+
assumption: Assumption = EmptyAssumption,
139136
memoryUpdates: MemoryUpdate = MemoryUpdate()
140137
) : this(symbolicResult, SymbolicStateUpdate(hardConstraints, softConstraints, assumption, memoryUpdates))
141138

142139
constructor(
143140
value: SymbolicValue,
144-
hardConstraints: HardConstraint = HardConstraint(),
145-
softConstraints: SoftConstraint = SoftConstraint(),
146-
assumption: Assumption = Assumption(),
141+
hardConstraints: HardConstraint = EmptyHardConstraint,
142+
softConstraints: SoftConstraint = EmptySoftConstraint,
143+
assumption: Assumption = EmptyAssumption,
147144
memoryUpdates: MemoryUpdate = MemoryUpdate(),
148145
) : this(SymbolicSuccess(value), hardConstraints, softConstraints, assumption, memoryUpdates)
149146
}

utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,7 @@ import org.utbot.engine.pc.mkNot
6666
import org.utbot.engine.pc.mkOr
6767
import org.utbot.engine.pc.select
6868
import org.utbot.engine.pc.store
69-
import org.utbot.engine.symbolic.HardConstraint
70-
import org.utbot.engine.symbolic.SoftConstraint
71-
import org.utbot.engine.symbolic.Assumption
72-
import org.utbot.engine.symbolic.SymbolicStateUpdate
73-
import org.utbot.engine.symbolic.asHardConstraint
74-
import org.utbot.engine.symbolic.asSoftConstraint
75-
import org.utbot.engine.symbolic.asAssumption
76-
import org.utbot.engine.symbolic.asUpdate
69+
import org.utbot.engine.symbolic.*
7770
import org.utbot.engine.util.trusted.isFromTrustedLibrary
7871
import org.utbot.engine.util.statics.concrete.associateEnumSootFieldsWithConcreteValues
7972
import org.utbot.engine.util.statics.concrete.isEnumAffectingExternalStatics
@@ -1076,8 +1069,8 @@ class Traverser(
10761069
}
10771070

10781071
// Depending on existance of assumeExpr we have to add corresponding hardConstraints and assumptions
1079-
val hardConstraints = if (!isAssumeExpr) negativeCasePathConstraint.asHardConstraint() else HardConstraint()
1080-
val assumption = if (isAssumeExpr) negativeCasePathConstraint.asAssumption() else Assumption()
1072+
val hardConstraints = if (!isAssumeExpr) negativeCasePathConstraint.asHardConstraint() else EmptyHardConstraint
1073+
val assumption = if (isAssumeExpr) negativeCasePathConstraint.asAssumption() else EmptyAssumption
10811074

10821075
val negativeCaseState = environment.state.updateQueued(
10831076
negativeCaseEdge,
@@ -2957,10 +2950,7 @@ class Traverser(
29572950
private fun collectSymbolicStateUpdates(expr: UtBoolExpression): SymbolicStateUpdateForResolvedCondition {
29582951
return when (expr) {
29592952
is UtInstanceOfExpression -> { // for now only this type of expression produces deferred updates
2960-
val onlyMemoryUpdates = expr.symbolicStateUpdate.copy(
2961-
hardConstraints = HardConstraint(),
2962-
softConstraints = SoftConstraint()
2963-
)
2953+
val onlyMemoryUpdates = expr.symbolicStateUpdate.copy()
29642954
SymbolicStateUpdateForResolvedCondition(onlyMemoryUpdates)
29652955
}
29662956
is UtAndBoolExpression -> {

utbot-framework/src/main/kotlin/org/utbot/engine/pc/Query.kt

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import kotlinx.collections.immutable.mutate
1919
import kotlinx.collections.immutable.persistentHashMapOf
2020
import kotlinx.collections.immutable.persistentHashSetOf
2121
import kotlinx.collections.immutable.toPersistentSet
22+
import org.utbot.engine.symbolic.Assumption
23+
import org.utbot.engine.symbolic.EmptyAssumption
24+
import org.utbot.engine.symbolic.asAssumption
2225

2326
/**
2427
* Base class that represents immutable query of constraints to solver.
@@ -31,6 +34,7 @@ import kotlinx.collections.immutable.toPersistentSet
3134
sealed class BaseQuery(
3235
open val hard: PersistentSet<UtBoolExpression>,
3336
open val soft: PersistentSet<UtBoolExpression>,
37+
open val assumptions: Assumption,
3438
open val status: UtSolverStatus,
3539
open val lastAdded: Collection<UtBoolExpression>
3640
) {
@@ -40,7 +44,11 @@ sealed class BaseQuery(
4044
* @param hard - new constraints that must be satisfied.
4145
* @param soft - new constraints that are suggested to be satisfied if possible.
4246
*/
43-
abstract fun with(hard: Collection<UtBoolExpression>, soft: Collection<UtBoolExpression>): BaseQuery
47+
abstract fun with(
48+
hard: Collection<UtBoolExpression>,
49+
soft: Collection<UtBoolExpression>,
50+
assumptions: Assumption
51+
): BaseQuery
4452

4553
/**
4654
* Set [status] of the query.
@@ -55,11 +63,19 @@ sealed class BaseQuery(
5563
* UnsatQuery.[status] is [UtSolverStatusUNSAT].
5664
* UnsatQuery.[lastAdded] = [emptyList]
5765
*/
58-
class UnsatQuery(hard: PersistentSet<UtBoolExpression>) :
59-
BaseQuery(hard, persistentHashSetOf(), UtSolverStatusUNSAT(UtSolverStatusKind.UNSAT), emptyList()) {
66+
class UnsatQuery(hard: PersistentSet<UtBoolExpression>) : BaseQuery(
67+
hard,
68+
soft = persistentHashSetOf(),
69+
EmptyAssumption,
70+
UtSolverStatusUNSAT(UtSolverStatusKind.UNSAT),
71+
lastAdded = emptyList()
72+
) {
6073

61-
override fun with(hard: Collection<UtBoolExpression>, soft: Collection<UtBoolExpression>): BaseQuery =
62-
error("State with UnsatQuery isn't eliminated. Adding constraints to $this isn't allowed.")
74+
override fun with(
75+
hard: Collection<UtBoolExpression>,
76+
soft: Collection<UtBoolExpression>,
77+
assumptions: Assumption
78+
): BaseQuery = error("State with UnsatQuery isn't eliminated. Adding constraints to $this isn't allowed.")
6379

6480
override fun withStatus(newStatus: UtSolverStatus) = this
6581

@@ -78,12 +94,13 @@ class UnsatQuery(hard: PersistentSet<UtBoolExpression>) :
7894
data class Query(
7995
override val hard: PersistentSet<UtBoolExpression> = persistentHashSetOf(),
8096
override val soft: PersistentSet<UtBoolExpression> = persistentHashSetOf(),
97+
override val assumptions: Assumption = EmptyAssumption,
8198
override val status: UtSolverStatus = UtSolverStatusUNDEFINED,
8299
override val lastAdded: Collection<UtBoolExpression> = emptyList(),
83100
private val eqs: PersistentMap<UtExpression, UtExpression> = persistentHashMapOf(),
84101
private val lts: PersistentMap<UtExpression, Long> = persistentHashMapOf(),
85102
private val gts: PersistentMap<UtExpression, Long> = persistentHashMapOf()
86-
) : BaseQuery(hard, soft, status, lastAdded) {
103+
) : BaseQuery(hard, soft, assumptions, status, lastAdded) {
87104

88105
val rewriter: RewritingVisitor
89106
get() = RewritingVisitor(eqs, lts, gts)
@@ -179,6 +196,7 @@ data class Query(
179196
private fun addSimplified(
180197
hard: Collection<UtBoolExpression>,
181198
soft: Collection<UtBoolExpression>,
199+
assumptions: Assumption
182200
): BaseQuery {
183201
val addedHard = hard.simplify().filterNot { it is UtTrue }
184202
if (addedHard.isEmpty() && soft.isEmpty()) {
@@ -266,20 +284,50 @@ data class Query(
266284
.filterNot { it is UtBoolLiteral }
267285
.toPersistentSet()
268286

287+
// Apply simplifications to assumptions in query.
288+
// We do not filter out UtFalse here because we need them to get UNSAT in corresponding cases and run concrete instead.
289+
val newAssumptions = this.assumptions
290+
.plus(assumptions)
291+
.constraints
292+
.simplify(newEqs, newLts, newGts)
293+
.toPersistentSet()
294+
.asAssumption()
295+
269296
val diffHard = newHard - this.hard
270-
return Query(newHard, newSoft, status.checkFastSatAndReturnStatus(diffHard), diffHard, newEqs, newLts, newGts)
297+
298+
return Query(
299+
newHard,
300+
newSoft,
301+
newAssumptions,
302+
status.checkFastSatAndReturnStatus(diffHard),
303+
lastAdded = diffHard,
304+
newEqs,
305+
newLts,
306+
newGts
307+
)
271308
}
272309

273310
/**
274311
* Add constraints to query and apply simplifications if [useExpressionSimplification] is true.
275312
* @param hard - set of constraints that must be satisfied.
276313
* @param soft - set of constraints that should be satisfied if possible.
277314
*/
278-
override fun with(hard: Collection<UtBoolExpression>, soft: Collection<UtBoolExpression>): BaseQuery {
315+
override fun with(
316+
hard: Collection<UtBoolExpression>,
317+
soft: Collection<UtBoolExpression>,
318+
assumptions: Assumption
319+
): BaseQuery {
279320
return if (useExpressionSimplification) {
280-
addSimplified(hard, soft)
321+
addSimplified(hard, soft, assumptions)
281322
} else {
282-
Query(this.hard.addAll(hard), this.soft.addAll(soft), status.checkFastSatAndReturnStatus(hard), hard, this.eqs)
323+
Query(
324+
this.hard.addAll(hard),
325+
this.soft.addAll(soft),
326+
this.assumptions.plus(assumptions),
327+
status.checkFastSatAndReturnStatus(hard),
328+
lastAdded = hard,
329+
this.eqs
330+
)
283331
}
284332
}
285333

utbot-framework/src/main/kotlin/org/utbot/engine/pc/UtSolver.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.microsoft.z3.Status.UNSATISFIABLE
3131
import kotlinx.collections.immutable.PersistentSet
3232
import kotlinx.collections.immutable.persistentHashSetOf
3333
import mu.KotlinLogging
34+
import org.utbot.engine.symbolic.EmptyAssumption
3435
import soot.ByteType
3536
import soot.CharType
3637
import soot.IntType
@@ -131,7 +132,7 @@ data class UtSolver constructor(
131132
// Constraints that should not be added in the solver as hypothesis.
132133
// Instead, we use `check` to find out if they are satisfiable.
133134
// It is required to have unsat cores with them.
134-
var assumption: Assumption = Assumption(),
135+
var assumption: Assumption = EmptyAssumption,
135136

136137
//new constraints for solver (kind of incremental behavior)
137138
private var hardConstraintsNotYetAddedToZ3Solver: PersistentSet<UtBoolExpression> = persistentHashSetOf(),
@@ -175,9 +176,9 @@ data class UtSolver constructor(
175176

176177
var expectUndefined: Boolean = false
177178

178-
fun add(hard: HardConstraint, soft: SoftConstraint, assumption: Assumption = Assumption()): UtSolver {
179+
fun add(hard: HardConstraint, soft: SoftConstraint, assumption: Assumption): UtSolver {
179180
// status can implicitly change here to UNDEFINED or UNSAT
180-
val newConstraints = constraints.with(hard.constraints, soft.constraints)
181+
val newConstraints = constraints.with(hard.constraints, soft.constraints, assumption)
181182
val wantClone = (expectUndefined && newConstraints.status is UtSolverStatusUNDEFINED)
182183
|| (!expectUndefined && newConstraints.status !is UtSolverStatusUNSAT)
183184

@@ -204,7 +205,7 @@ data class UtSolver constructor(
204205
copy(
205206
constraints = constraintsWithStatus,
206207
hardConstraintsNotYetAddedToZ3Solver = newConstraints.hard,
207-
assumption = this.assumption + assumption,
208+
assumption = newConstraints.assumptions,
208209
z3Solver = context.mkSolver().also { it.setParameters(params) },
209210
)
210211
}

utbot-framework/src/main/kotlin/org/utbot/engine/symbolic/SymbolicStateUpdate.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,47 +22,53 @@ sealed class Constraint<T : Constraint<T>>(constraints: Set<UtBoolExpression> =
2222
/**
2323
* Represents hard constraints.
2424
*/
25-
class HardConstraint(
25+
open class HardConstraint(
2626
constraints: Set<UtBoolExpression> = emptySet()
2727
) : Constraint<HardConstraint>(constraints) {
2828
override fun plus(other: HardConstraint): HardConstraint =
2929
HardConstraint(addConstraints(other.constraints))
3030
}
3131

32+
object EmptyHardConstraint : HardConstraint()
33+
3234
/**
3335
* Represents soft constraints.
3436
*/
35-
class SoftConstraint(
37+
open class SoftConstraint(
3638
constraints: Set<UtBoolExpression> = emptySet()
3739
) : Constraint<SoftConstraint>(constraints) {
3840
override fun plus(other: SoftConstraint): SoftConstraint =
3941
SoftConstraint(addConstraints(other.constraints))
4042
}
4143

44+
object EmptySoftConstraint : SoftConstraint()
45+
4246
/**
4347
* Represent constraints that must be satisfied for symbolic execution.
4448
* At the same time, if they don't, the state they belong to still
4549
* might be executed concretely without these assume.
4650
*
4751
* @see
4852
*/
49-
class Assumption(
53+
open class Assumption(
5054
constraints: Set<UtBoolExpression> = emptySet()
5155
): Constraint<Assumption>(constraints) {
5256
override fun plus(other: Assumption): Assumption = Assumption(addConstraints(other.constraints))
5357

5458
override fun toString() = constraints.joinToString(System.lineSeparator())
5559
}
5660

61+
object EmptyAssumption : Assumption()
62+
5763
/**
5864
* Represents one or more updates that can be applied to [SymbolicState].
5965
*
6066
* TODO: move [localMemoryUpdates] to another place
6167
*/
6268
data class SymbolicStateUpdate(
63-
val hardConstraints: HardConstraint = HardConstraint(),
64-
val softConstraints: SoftConstraint = SoftConstraint(),
65-
val assumptions: Assumption = Assumption(),
69+
val hardConstraints: HardConstraint = EmptyHardConstraint,
70+
val softConstraints: SoftConstraint = EmptySoftConstraint,
71+
val assumptions: Assumption = EmptyAssumption,
6672
val memoryUpdates: MemoryUpdate = MemoryUpdate(),
6773
val localMemoryUpdates: LocalMemoryUpdate = LocalMemoryUpdate()
6874
) {
@@ -107,7 +113,7 @@ fun Collection<UtBoolExpression>.asSoftConstraint() = SoftConstraint(transformTo
107113

108114
fun UtBoolExpression.asSoftConstraint() = SoftConstraint(setOf(this))
109115

110-
fun Collection<UtBoolExpression>.asAssumption() = Assumption(toSet())
116+
fun Collection<UtBoolExpression>.asAssumption() = Assumption(transformToSet())
111117

112118
fun UtBoolExpression.asAssumption() = Assumption(setOf(this))
113119

utbot-sample/src/main/java/org/utbot/examples/stream/BaseStreamExample.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ boolean distinctExample(List<Integer> list) {
6868

6969
int prevSize = list.size();
7070

71-
int newSize = list.stream().distinct().toArray().length;
71+
int newSize = (int) list.stream().distinct().count();
7272

7373
return prevSize != newSize;
7474
}

0 commit comments

Comments
 (0)