Skip to content

Commit 63c3a1a

Browse files
authored
Merge pull request #380 from ftsrg/coordination
XSTS MDD improvements
2 parents de20ec2 + b9e582d commit 63c3a1a

File tree

26 files changed

+962
-166
lines changed

26 files changed

+962
-166
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ buildscript {
2929

3030
allprojects {
3131
group = "hu.bme.mit.theta"
32-
version = "6.17.2"
32+
version = "6.17.3"
3333

3434

3535
apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts"))

subprojects/cfa/cfa-analysis/src/test/java/hu/bme/mit/theta/cfa/analysis/CfaMddCheckerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ public void test() throws Exception {
103103
MddChecker.IterationStrategy.GSAT,
104104
valuation -> monolithicExpr.getValToState().invoke(valuation),
105105
(Valuation v1, Valuation v2) ->
106-
monolithicExpr.getBiValToAction().invoke(v1, v2));
106+
monolithicExpr.getBiValToAction().invoke(v1, v2),
107+
true);
107108
status = checker.check(null);
108109
}
109110

subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/AbstractMonolithicExpr.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ import hu.bme.mit.theta.core.type.booltype.BoolExprs
2727
import hu.bme.mit.theta.core.type.booltype.BoolLitExpr
2828
import hu.bme.mit.theta.core.type.booltype.BoolType
2929
import hu.bme.mit.theta.core.type.booltype.IffExpr
30-
import hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.And
31-
import hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.Not
30+
import hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.*
3231
import hu.bme.mit.theta.core.utils.ExprUtils
3332
import hu.bme.mit.theta.core.utils.indexings.VarIndexingFactory
3433
import java.util.HashMap
@@ -81,9 +80,11 @@ fun MonolithicExpr.createAbstract(prec: PredPrec): MonolithicExpr {
8180
}
8281
}
8382

83+
val transExpr = Or(this.split().map { And(lambdaList + lambdaPrimeList + it) })
84+
8485
return MonolithicExpr(
8586
initExpr = And(And(lambdaList), initExpr),
86-
transExpr = And(And(lambdaList), And(lambdaPrimeList), transExpr),
87+
transExpr = transExpr,
8788
propExpr = Not(And(And(lambdaList), Not(propExpr))),
8889
transOffsetIndex = indexingBuilder.build(),
8990
initOffsetIndex = VarIndexingFactory.indexing(0),

subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/BoundedChecker.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,21 @@ constructor(
152152
val bmcSolver = this.bmcSolver!!
153153
logger.write(Logger.Level.MAINSTEP, "\tStarting BMC\n")
154154

155+
if (iteration == 1) {
156+
WithPushPop(bmcSolver).use {
157+
bmcSolver.add(Not(unfoldedPropExpr(indices.first())))
158+
159+
if (bmcSolver.check().isSat) {
160+
val trace = getTrace(bmcSolver.model)
161+
logger.write(
162+
Logger.Level.MAINSTEP,
163+
"CeX found in the initial state (length ${trace.length()})\n",
164+
)
165+
return SafetyResult.unsafe(trace, PredState.of(), BoundedStatistics(iteration))
166+
}
167+
}
168+
}
169+
155170
bmcSolver.add(exprs.last())
156171

157172
if (lfPathOnly()) { // indices contains currIndex as last()
@@ -249,6 +264,22 @@ constructor(
249264
val b = itpSolver.createMarker()
250265
val pattern = itpSolver.createBinPattern(a, b)
251266

267+
if (iteration == 1) {
268+
WithPushPop(itpSolver).use {
269+
itpSolver.add(a, unfoldedInitExpr)
270+
itpSolver.add(a, Not(unfoldedPropExpr(indices.first())))
271+
272+
if (itpSolver.check().isSat) {
273+
val trace = getTrace(itpSolver.model)
274+
logger.write(
275+
Logger.Level.MAINSTEP,
276+
"CeX found in the initial state (length ${trace.length()})\n",
277+
)
278+
return SafetyResult.unsafe(trace, PredState.of(), BoundedStatistics(iteration))
279+
}
280+
}
281+
}
282+
252283
itpSolver.push()
253284

254285
itpSolver.add(a, unfoldedInitExpr)

subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/bounded/MonolithicExprCegarChecker.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import hu.bme.mit.theta.analysis.expr.refinement.ExprTraceFwBinItpChecker;
2929
import hu.bme.mit.theta.analysis.expr.refinement.ExprTraceStatus;
3030
import hu.bme.mit.theta.analysis.expr.refinement.ItpRefutation;
31+
import hu.bme.mit.theta.analysis.pred.ExprSplitters;
3132
import hu.bme.mit.theta.analysis.pred.PredPrec;
3233
import hu.bme.mit.theta.analysis.unit.UnitPrec;
3334
import hu.bme.mit.theta.common.logging.Logger;
@@ -122,9 +123,12 @@ public MonolithicExprCegarChecker(
122123
} else {
123124
final var ref = concretizationResult.asInfeasible().getRefutation();
124125
final var newPred = ref.get(ref.getPruneIndex());
125-
final var newPrec = PredPrec.of(newPred);
126-
predPrec = predPrec.join(newPrec);
127-
logger.write(Logger.Level.INFO, "Added new predicate " + newPrec + "\n");
126+
for (var splitPred : ExprSplitters.conjuncts().apply(newPred)) {
127+
final var newPrec = PredPrec.of(splitPred);
128+
predPrec = predPrec.join(newPrec);
129+
}
130+
131+
logger.write(Logger.Level.INFO, "Added new predicate " + newPred + "\n");
128132
}
129133
}
130134
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2025 Budapest University of Technology and Economics
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package hu.bme.mit.theta.analysis.algorithm.bounded
17+
18+
import hu.bme.mit.theta.analysis.algorithm.mdd.varordering.Event
19+
import hu.bme.mit.theta.analysis.algorithm.mdd.varordering.orderVarsFromRandomStartingPoints
20+
import hu.bme.mit.theta.core.decl.VarDecl
21+
import hu.bme.mit.theta.core.model.BasicSubstitution
22+
import hu.bme.mit.theta.core.type.Expr
23+
import hu.bme.mit.theta.core.type.booltype.BoolType
24+
import hu.bme.mit.theta.core.utils.ExprUtils
25+
import hu.bme.mit.theta.core.utils.PathUtils
26+
import hu.bme.mit.theta.core.utils.indexings.VarIndexing
27+
28+
fun MonolithicExpr.orderVars(): List<VarDecl<*>> {
29+
val events = this.split().map { MonolithicExprEvent(it, this.transOffsetIndex) }.toSet()
30+
val orderedVars = orderVarsFromRandomStartingPoints(this.vars, events)
31+
return orderedVars
32+
}
33+
34+
// Filters affected variables
35+
class MonolithicExprEvent : Event {
36+
37+
constructor(expr: Expr<BoolType>, transOffsetIndex: VarIndexing) {
38+
val vars = ExprUtils.getVars(expr)
39+
var sub = BasicSubstitution.builder()
40+
for (v in vars) {
41+
sub = sub.put(v.getConstDecl(transOffsetIndex.get(v)), v.getConstDecl(0).ref)
42+
}
43+
val identityRemovedExpr = ExprUtils.simplify(sub.build().apply(PathUtils.unfold(expr, 0)))
44+
val remainingConstants = ExprUtils.getConstants(identityRemovedExpr)
45+
this.affectedVars = vars.filter { it.getConstDecl(0) in remainingConstants }.toSet()
46+
}
47+
48+
private val affectedVars: Set<VarDecl<*>>
49+
50+
override fun getAffectedVars(): Set<VarDecl<*>> = affectedVars
51+
}

subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddChecker.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import hu.bme.mit.theta.analysis.algorithm.SafetyResult;
3333
import hu.bme.mit.theta.analysis.algorithm.bounded.MonolithicExpr;
3434
import hu.bme.mit.theta.analysis.algorithm.bounded.MonolithicExprKt;
35+
import hu.bme.mit.theta.analysis.algorithm.bounded.MonolithicExprVarOrderingKt;
3536
import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor;
3637
import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.impl.*;
3738
import hu.bme.mit.theta.analysis.algorithm.mdd.expressionnode.ExprLatticeDefinition;
@@ -67,6 +68,7 @@ public class MddChecker<S extends ExprState, A extends ExprAction>
6768
private final IterationStrategy iterationStrategy;
6869
private final Function<Valuation, S> valToState;
6970
private final BiFunction<Valuation, Valuation, A> biValToAction;
71+
private final boolean forwardTrace;
7072

7173
public enum IterationStrategy {
7274
BFS,
@@ -81,14 +83,16 @@ private MddChecker(
8183
Logger logger,
8284
IterationStrategy iterationStrategy,
8385
Function<Valuation, S> valToState,
84-
BiFunction<Valuation, Valuation, A> biValToAction) {
86+
BiFunction<Valuation, Valuation, A> biValToAction,
87+
boolean forwardTrace) {
8588
this.monolithicExpr = monolithicExpr;
8689
this.variableOrdering = variableOrdering;
8790
this.solverPool = solverPool;
8891
this.logger = logger;
8992
this.iterationStrategy = iterationStrategy;
9093
this.valToState = valToState;
9194
this.biValToAction = biValToAction;
95+
this.forwardTrace = forwardTrace;
9296
}
9397

9498
public static <S extends ExprState, A extends ExprAction> MddChecker<S, A> create(
@@ -97,15 +101,17 @@ public static <S extends ExprState, A extends ExprAction> MddChecker<S, A> creat
97101
SolverPool solverPool,
98102
Logger logger,
99103
Function<Valuation, S> valToState,
100-
BiFunction<Valuation, Valuation, A> biValToAction) {
104+
BiFunction<Valuation, Valuation, A> biValToAction,
105+
boolean forwardTrace) {
101106
return new MddChecker<S, A>(
102107
monolithicExpr,
103108
variableOrdering,
104109
solverPool,
105110
logger,
106111
IterationStrategy.GSAT,
107112
valToState,
108-
biValToAction);
113+
biValToAction,
114+
forwardTrace);
109115
}
110116

111117
public static <S extends ExprState, A extends ExprAction> MddChecker<S, A> create(
@@ -115,15 +121,17 @@ public static <S extends ExprState, A extends ExprAction> MddChecker<S, A> creat
115121
Logger logger,
116122
IterationStrategy iterationStrategy,
117123
Function<Valuation, S> valToState,
118-
BiFunction<Valuation, Valuation, A> biValToAction) {
124+
BiFunction<Valuation, Valuation, A> biValToAction,
125+
boolean forwardTrace) {
119126
return new MddChecker<S, A>(
120127
monolithicExpr,
121128
variableOrdering,
122129
solverPool,
123130
logger,
124131
iterationStrategy,
125132
valToState,
126-
biValToAction);
133+
biValToAction,
134+
forwardTrace);
127135
}
128136

129137
@Override
@@ -147,7 +155,8 @@ public SafetyResult<MddProof, Trace<S, A>> check(UnitPrec prec) {
147155
variableOrdering.size() == Containers.createSet(variableOrdering).size(),
148156
"Variable ordering contains duplicates");
149157
final var identityExprs = new ArrayList<Expr<BoolType>>();
150-
for (var v : Lists.reverse(variableOrdering)) {
158+
final var orderedVars = MonolithicExprVarOrderingKt.orderVars(monolithicExpr);
159+
for (var v : Lists.reverse(orderedVars)) {
151160
var domainSize = Math.max(v.getType().getDomainSize().getFiniteSize().intValue(), 0);
152161

153162
// if (domainSize > 100) {
@@ -285,9 +294,17 @@ public SafetyResult<MddProof, Trace<S, A>> check(UnitPrec prec) {
285294
}
286295
}
287296

288-
result =
289-
SafetyResult.unsafe(
290-
Trace.of(states, actions), MddProof.of(stateSpace), statistics);
297+
if (forwardTrace) {
298+
result =
299+
SafetyResult.unsafe(
300+
Trace.of(states, actions), MddProof.of(stateSpace), statistics);
301+
} else {
302+
result =
303+
SafetyResult.unsafe(
304+
Trace.of(Lists.reverse(states), Lists.reverse(actions)),
305+
MddProof.of(stateSpace),
306+
statistics);
307+
}
291308
} else {
292309
result = SafetyResult.safe(MddProof.of(stateSpace), statistics);
293310
}

subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/fixedpoint/TraceProvider.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
import hu.bme.mit.delta.mdd.MddInterpreter;
2121
import hu.bme.mit.theta.analysis.algorithm.mdd.MddSinglePathExtractor;
2222
import hu.bme.mit.theta.analysis.algorithm.mdd.ansd.AbstractNextStateDescriptor;
23-
import java.util.ArrayList;
2423
import java.util.List;
24+
import java.util.Stack;
2525

2626
public final class TraceProvider implements MddGraph.CleanupListener {
2727
public static boolean verbose = false;
@@ -48,10 +48,10 @@ public List<MddHandle> compute(
4848
MddHandle initialStates,
4949
MddVariableHandle highestAffectedVariable) {
5050

51-
MddHandle alreadyExplored = targetStates;
5251
MddHandle currentState = targetStates;
53-
final List<MddHandle> states = new ArrayList<>();
54-
states.add(targetStates);
52+
MddHandle alreadyExplored = currentState;
53+
final Stack<MddHandle> states = new Stack<>();
54+
states.push(currentState);
5555

5656
while (MddInterpreter.calculateNonzeroCount(currentState.intersection(initialStates))
5757
<= 0) {
@@ -62,9 +62,14 @@ public List<MddHandle> compute(
6262
reversedNextStateRelation,
6363
highestAffectedVariable)
6464
.minus(alreadyExplored);
65-
currentState = MddSinglePathExtractor.INSTANCE.transform((MddHandle) newLayer);
66-
states.add(currentState);
67-
alreadyExplored = (MddHandle) alreadyExplored.union(currentState);
65+
if (MddInterpreter.calculateNonzeroCount(newLayer) > 0) {
66+
currentState = MddSinglePathExtractor.INSTANCE.transform((MddHandle) newLayer);
67+
states.push(currentState);
68+
alreadyExplored = (MddHandle) alreadyExplored.union(currentState);
69+
} else {
70+
states.pop();
71+
currentState = states.peek();
72+
}
6873
}
6974

7075
return Lists.reverse(states);

subprojects/common/analysis/src/main/java/hu/bme/mit/theta/analysis/algorithm/mdd/varordering/ForceVarOrdering.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@
1616
package hu.bme.mit.theta.analysis.algorithm.mdd.varordering
1717

1818
import hu.bme.mit.theta.core.decl.VarDecl
19-
import hu.bme.mit.theta.core.stmt.Stmt
20-
import hu.bme.mit.theta.core.utils.StmtUtils
2119
import kotlin.random.Random
2220

21+
interface Event {
22+
fun getAffectedVars(): Set<VarDecl<*>>
23+
}
24+
2325
/**
2426
* Variable ordering based on the 'FORCE' variable ordering heuristic.
2527
* https://doi.org/10.1145/764808.764839
2628
*/
2729
fun orderVarsFromRandomStartingPoints(
2830
vars: List<VarDecl<*>>,
29-
events: Set<Stmt>,
31+
events: Set<Event>,
3032
numStartingPoints: Int = 5,
3133
): List<VarDecl<*>> {
3234
val random = Random(0)
@@ -35,9 +37,9 @@ fun orderVarsFromRandomStartingPoints(
3537
return orderings.minBy { eventSpans(it, events) }
3638
}
3739

38-
fun orderVars(vars: List<VarDecl<*>>, events: Set<Stmt>): List<VarDecl<*>> {
40+
fun orderVars(vars: List<VarDecl<*>>, events: Set<Event>): List<VarDecl<*>> {
3941

40-
val affectedVars = events.associateWith { event -> StmtUtils.getVars(event) }
42+
val affectedVars = events.associateWith { it.getAffectedVars() }
4143

4244
val affectingEvents =
4345
vars.associateWith { varDecl -> events.filter { varDecl in affectedVars[it]!! }.toSet() }
@@ -73,10 +75,10 @@ fun orderVars(vars: List<VarDecl<*>>, events: Set<Stmt>): List<VarDecl<*>> {
7375
return currentVarOrdering
7476
}
7577

76-
private fun eventSpans(vars: List<VarDecl<*>>, events: Set<Stmt>) =
78+
private fun eventSpans(vars: List<VarDecl<*>>, events: Set<Event>) =
7779
events
7880
.map { event ->
79-
StmtUtils.getVars(event).let {
81+
event.getAffectedVars().let {
8082
when (it.isEmpty()) {
8183
true -> 0
8284
else -> {

subprojects/common/analysis/src/test/java/hu/bme/mit/theta/analysis/algorithm/mdd/MddCheckerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ public void testWithIterationStrategy(MddChecker.IterationStrategy iterationStra
185185
iterationStrategy,
186186
valuation -> monolithicExpr.getValToState().invoke(valuation),
187187
(Valuation v1, Valuation v2) ->
188-
monolithicExpr.getBiValToAction().invoke(v1, v2));
188+
monolithicExpr.getBiValToAction().invoke(v1, v2),
189+
true);
189190
status = checker.check(null);
190191
}
191192

0 commit comments

Comments
 (0)