1
1
package org.usvm
2
2
3
- import org.usvm.StateForker.Companion.splitModelsByCondition
3
+ import io.ksmt.utils.cast
4
4
import org.usvm.collections.immutable.internal.MutabilityOwnership
5
5
import org.usvm.model.UModelBase
6
6
import org.usvm.solver.USatResult
@@ -12,39 +12,7 @@ private typealias StateToCheck = Boolean
12
12
private const val ForkedState = true
13
13
private const val OriginalState = false
14
14
15
- interface StateForker {
16
-
17
- companion object {
18
- /* *
19
- * Splits the passed [models] with this [condition] to the three categories:
20
- * - models that satisfy this [condition];
21
- * - models that are in contradiction with this [condition];
22
- * - models that can not evaluate this [condition].
23
- */
24
- fun <Type > splitModelsByCondition (
25
- models : List <UModelBase <Type >>,
26
- condition : UBoolExpr ,
27
- ): SplittedModels <Type > {
28
- val trueModels = mutableListOf<UModelBase <Type >>()
29
- val falseModels = mutableListOf<UModelBase <Type >>()
30
- val unknownModels = mutableListOf<UModelBase <Type >>()
31
-
32
- models.forEach { model ->
33
- val holdsInModel = model.eval(condition)
34
-
35
- when {
36
- holdsInModel.isTrue -> trueModels + = model
37
- holdsInModel.isFalse -> falseModels + = model
38
- // Sometimes we cannot evaluate the condition – for example, a result for a division by symbolic expression
39
- // that is evaluated to 0 is unknown
40
- else -> unknownModels + = model
41
- }
42
- }
43
-
44
- return SplittedModels (trueModels, falseModels, unknownModels)
45
- }
46
- }
47
-
15
+ sealed interface StateForker {
48
16
/* *
49
17
* Implements symbolic branching.
50
18
* Checks if [condition] and ![condition] are satisfiable within [state].
@@ -78,9 +46,10 @@ object WithSolverStateForker : StateForker {
78
46
state : T ,
79
47
condition : UBoolExpr ,
80
48
): ForkResult <T > {
81
- val (trueModels, falseModels, _) = splitModelsByCondition(state.models, condition)
49
+ val unwrappedCondition: UBoolExpr = condition.unwrapJoinedExpr(state.ctx).cast()
50
+ val (trueModels, falseModels, _) = splitModelsByCondition(state.models, unwrappedCondition)
82
51
83
- val notCondition = state.ctx.mkNot(condition )
52
+ val notCondition = if (condition is UJoinedBoolExpr ) condition. not () else state.ctx.mkNot(unwrappedCondition )
84
53
val (posState, negState) = when {
85
54
86
55
trueModels.isNotEmpty() && falseModels.isNotEmpty() -> {
@@ -89,23 +58,23 @@ object WithSolverStateForker : StateForker {
89
58
90
59
posState.models = trueModels
91
60
negState.models = falseModels
92
- posState.pathConstraints + = condition
61
+ posState.pathConstraints + = unwrappedCondition
93
62
negState.pathConstraints + = notCondition
94
63
95
64
posState to negState
96
65
}
97
66
98
67
trueModels.isNotEmpty() -> state to forkIfSat(
99
68
state,
100
- newConstraintToOriginalState = condition ,
69
+ newConstraintToOriginalState = unwrappedCondition ,
101
70
newConstraintToForkedState = notCondition,
102
71
stateToCheck = ForkedState
103
72
)
104
73
105
74
falseModels.isNotEmpty() -> {
106
75
val forkedState = forkIfSat(
107
76
state,
108
- newConstraintToOriginalState = condition ,
77
+ newConstraintToOriginalState = unwrappedCondition ,
109
78
newConstraintToForkedState = notCondition,
110
79
stateToCheck = OriginalState
111
80
)
@@ -287,12 +256,41 @@ object NoSolverStateForker : StateForker {
287
256
}
288
257
}
289
258
259
+ /* *
260
+ * Splits the passed [models] with this [condition] to the three categories:
261
+ * - models that satisfy this [condition];
262
+ * - models that are in contradiction with this [condition];
263
+ * - models that can not evaluate this [condition].
264
+ */
265
+ private fun <Type > splitModelsByCondition (
266
+ models : List <UModelBase <Type >>,
267
+ condition : UBoolExpr ,
268
+ ): SplittedModels <Type > {
269
+ val trueModels = mutableListOf<UModelBase <Type >>()
270
+ val falseModels = mutableListOf<UModelBase <Type >>()
271
+ val unknownModels = mutableListOf<UModelBase <Type >>()
272
+
273
+ models.forEach { model ->
274
+ val holdsInModel = model.eval(condition)
275
+
276
+ when {
277
+ holdsInModel.isTrue -> trueModels + = model
278
+ holdsInModel.isFalse -> falseModels + = model
279
+ // Sometimes we cannot evaluate the condition – for example, a result for a division by symbolic expression
280
+ // that is evaluated to 0 is unknown
281
+ else -> unknownModels + = model
282
+ }
283
+ }
284
+
285
+ return SplittedModels (trueModels, falseModels, unknownModels)
286
+ }
287
+
290
288
data class ForkResult <T >(
291
289
val positiveState : T ? ,
292
290
val negativeState : T ? ,
293
291
)
294
292
295
- data class SplittedModels <Type >(
293
+ private data class SplittedModels <Type >(
296
294
val trueModels : List <UModelBase <Type >>,
297
295
val falseModels : List <UModelBase <Type >>,
298
296
val unknownModels : List <UModelBase <Type >>,
0 commit comments