Skip to content

Commit

Permalink
Fixed bounded, ic3, added xcfa-cli support, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
leventeBajczi committed Feb 25, 2025
1 parent fc9153a commit 4addc51
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ constructor(
while (!shouldGiveUp(iteration)) {
iteration++
logger.write(Logger.Level.MAINSTEP, "Starting iteration $iteration\n")
if (!kindEnabled(iteration) && imcEnabled(iteration) && bmcEnabled()) {
logger.writeln(
Logger.Level.INFO,
"BMC and IMC together are inefficient; IMC includes BMC as a substep.",
)
}
check((!kindEnabled(iteration)) || bmcEnabled()) {
"K-Induction needs BMC as an external substep."
}

exprs.add(PathUtils.unfold(monolithicExpr.transExpr, indices.last()))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package hu.bme.mit.theta.analysis.algorithm.bounded;

import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True;
import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not;

import com.google.common.base.Preconditions;
import hu.bme.mit.theta.analysis.*;
Expand Down Expand Up @@ -92,7 +92,9 @@ public MonolithicExprCegarChecker(

final ExprTraceChecker<ItpRefutation> exprTraceFwBinItpChecker =
ExprTraceFwBinItpChecker.create(
True(), True(), solverFactory.createItpSolver());
abstractMonolithicExpr.getInitExpr(),
Not(abstractMonolithicExpr.getPropExpr()),
solverFactory.createItpSolver());

if (trace != null) {
logger.write(Logger.Level.VERBOSE, "\tFound trace: %s\n", trace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public SafetyResult<EmptyProof, Trace<S, A>> check(UnitPrec prec) {
new ProofObligation(
new HashSet<>(counterExample), currentFrameNumber));
if (proofObligationsList != null) {
var trace = traceMaker(proofObligationsList);
var trace = makeTrace(proofObligationsList);
final var result = SafetyResult.unsafe(trace, EmptyProof.getInstance());
logger.writeln(Logger.Level.RESULT, result.toString());
return result;
Expand Down Expand Up @@ -277,7 +277,9 @@ public Trace<S, A> checkFirst() {
List.of(
valToState.apply(
PathUtils.extractValuation(
solver.getModel(), 0, monolithicExpr.getVars()))),
solver.getModel(),
monolithicExpr.getInitOffsetIndex(),
monolithicExpr.getVars()))),
List.of());
}
}
Expand All @@ -295,9 +297,23 @@ public Trace<S, A> checkFirst() {
valToState.apply(
PathUtils.extractValuation(
solver.getModel(),
0,
monolithicExpr.getInitOffsetIndex(),
monolithicExpr.getVars())),
valToState.apply(
PathUtils.extractValuation(
solver.getModel(),
monolithicExpr.getTransOffsetIndex(),
monolithicExpr.getVars()))),
List.of());
List.of(
biValToAction.apply(
PathUtils.extractValuation(
solver.getModel(),
monolithicExpr.getInitOffsetIndex(),
monolithicExpr.getVars()),
PathUtils.extractValuation(
solver.getModel(),
monolithicExpr.getTransOffsetIndex(),
monolithicExpr.getVars()))));
} else {
return null;
}
Expand Down Expand Up @@ -368,7 +384,7 @@ public boolean propagate() {
return false;
}

public Trace<S, A> traceMaker(LinkedList<ProofObligation> forwardProofObligations) {
public Trace<S, A> makeTrace(LinkedList<ProofObligation> forwardProofObligations) {
var abstractStates = new ArrayList<ExprState>();
var abstractActions = new ArrayList<ExprAction>();
while (!forwardProofObligations.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,34 +56,36 @@ fun getBoundedChecker(
else it
}

val baseChecker = { monolithicExpr: MonolithicExpr ->
BoundedChecker(
monolithicExpr = monolithicExpr,
bmcSolver =
tryGetSolver(boundedConfig.bmcConfig.bmcSolver, boundedConfig.bmcConfig.validateBMCSolver)
?.createSolver(),
bmcEnabled = { !boundedConfig.bmcConfig.disable },
lfPathOnly = { !boundedConfig.bmcConfig.nonLfPath },
itpSolver =
tryGetSolver(boundedConfig.itpConfig.itpSolver, boundedConfig.itpConfig.validateItpSolver)
?.createItpSolver(),
imcEnabled = { !boundedConfig.itpConfig.disable },
indSolver =
tryGetSolver(boundedConfig.indConfig.indSolver, boundedConfig.indConfig.validateIndSolver)
?.createSolver(),
kindEnabled = { !boundedConfig.indConfig.disable },
valToState = monolithicExpr.valToState,
biValToAction = monolithicExpr.biValToAction,
logger = logger,
)
val baseChecker = { nonlfPath: Boolean ->
{ monolithicExpr: MonolithicExpr ->
BoundedChecker(
monolithicExpr = monolithicExpr,
bmcSolver =
tryGetSolver(boundedConfig.bmcConfig.bmcSolver, boundedConfig.bmcConfig.validateBMCSolver)
?.createSolver(),
bmcEnabled = { !boundedConfig.bmcConfig.disable },
lfPathOnly = { !nonlfPath },
itpSolver =
tryGetSolver(boundedConfig.itpConfig.itpSolver, boundedConfig.itpConfig.validateItpSolver)
?.createItpSolver(),
imcEnabled = { !boundedConfig.itpConfig.disable },
indSolver =
tryGetSolver(boundedConfig.indConfig.indSolver, boundedConfig.indConfig.validateIndSolver)
?.createSolver(),
kindEnabled = { !boundedConfig.indConfig.disable },
valToState = monolithicExpr.valToState,
biValToAction = monolithicExpr.biValToAction,
logger = logger,
)
}
}

val checker =
if (boundedConfig.cegar) {
val cegarChecker =
MonolithicExprCegarChecker(
monolithicExpr,
baseChecker,
baseChecker(true),
logger,
getSolver(boundedConfig.bmcConfig.bmcSolver, false),
)
Expand Down Expand Up @@ -116,7 +118,7 @@ fun getBoundedChecker(
}
}
} else {
baseChecker(monolithicExpr)
baseChecker(boundedConfig.bmcConfig.nonLfPath)(monolithicExpr)
}

return checker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@ fun getChecker(
SafetyResult.unknown()
}
Backend.CHC -> getHornChecker(xcfa, mcm, config, logger)
Backend.IC3 -> getIc3Checker(xcfa, mcm, parseContext, config, logger)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2025 Budapest University of Technology and Economics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hu.bme.mit.theta.xcfa.cli.checkers

import hu.bme.mit.theta.analysis.Trace
import hu.bme.mit.theta.analysis.algorithm.EmptyProof
import hu.bme.mit.theta.analysis.algorithm.SafetyChecker
import hu.bme.mit.theta.analysis.algorithm.SafetyResult
import hu.bme.mit.theta.analysis.algorithm.bounded.*
import hu.bme.mit.theta.analysis.algorithm.bounded.createMonolithicL2S
import hu.bme.mit.theta.analysis.algorithm.ic3.Ic3Checker
import hu.bme.mit.theta.analysis.pred.PredPrec
import hu.bme.mit.theta.analysis.pred.PredState
import hu.bme.mit.theta.analysis.ptr.PtrPrec
import hu.bme.mit.theta.analysis.ptr.PtrState
import hu.bme.mit.theta.common.logging.Logger
import hu.bme.mit.theta.core.model.Valuation
import hu.bme.mit.theta.core.type.booltype.BoolExprs.True
import hu.bme.mit.theta.frontend.ParseContext
import hu.bme.mit.theta.graphsolver.patterns.constraints.MCM
import hu.bme.mit.theta.solver.SolverFactory
import hu.bme.mit.theta.xcfa.analysis.*
import hu.bme.mit.theta.xcfa.cli.params.Ic3Config
import hu.bme.mit.theta.xcfa.cli.params.XcfaConfig
import hu.bme.mit.theta.xcfa.cli.utils.getSolver
import hu.bme.mit.theta.xcfa.model.XCFA

fun getIc3Checker(
xcfa: XCFA,
mcm: MCM,
parseContext: ParseContext,
config: XcfaConfig<*, *>,
logger: Logger,
): SafetyChecker<EmptyProof, Trace<XcfaState<PtrState<*>>, XcfaAction>, XcfaPrec<*>> {

val ic3Config = config.backendConfig.specConfig as Ic3Config
val solverFactory: SolverFactory = getSolver(ic3Config.solver, ic3Config.validateSolver)

val monolithicExpr =
xcfa
.toMonolithicExpr(parseContext)
.let {
if (config.inputConfig.property == ErrorDetection.TERMINATION)
it.copy(propExpr = True()).createMonolithicL2S()
else it
}
.let { if (ic3Config.reversed) it.createReversed() else it }

val baseChecker = { monolithicExpr: MonolithicExpr ->
Ic3Checker(
/* monolithicExpr = */ monolithicExpr,
/* forwardTrace = */ true,
/* solverFactory = */ solverFactory,
/* valToState = */ { valuation -> monolithicExpr.valToState.invoke(valuation) },
/* biValToAction = */ { v1: Valuation, v2: Valuation ->
monolithicExpr.biValToAction.invoke(v1, v2)
},
/* formerFramesOpt = */ true,
/* unSatOpt = */ true,
/* notBOpt = */ true,
/* propagateOpt = */ true,
/* filterOpt = */ true,
/* propertyOpt = */ true,
/* logger = */ logger,
)
}

val checker =
if (ic3Config.cegar) {
val cegarChecker =
MonolithicExprCegarChecker(
monolithicExpr,
baseChecker,
logger,
getSolver(ic3Config.solver, false),
)
object :
SafetyChecker<
EmptyProof,
Trace<XcfaState<PtrState<PredState>>, XcfaAction>,
XcfaPrec<PtrPrec<PredPrec>>,
> {
override fun check(
initPrec: XcfaPrec<PtrPrec<PredPrec>>
): SafetyResult<EmptyProof, Trace<XcfaState<PtrState<PredState>>, XcfaAction>> {
val result = cegarChecker.check() // states are PredState, actions are XcfaAction
if (result.isUnsafe) {
val cex = result.asUnsafe().cex as Trace<PredState, XcfaAction>
val locs =
(0 until cex.length()).map { i -> cex.actions[i].source } +
cex.actions[cex.length() - 1].target
val states = locs.mapIndexed { i, it -> XcfaState(xcfa, it, PtrState(cex.states[i])) }
return SafetyResult.unsafe(Trace.of(states, cex.actions), result.proof)
} else
return result
as SafetyResult<EmptyProof, Trace<XcfaState<PtrState<PredState>>, XcfaAction>>
}

override fun check():
SafetyResult<EmptyProof, Trace<XcfaState<PtrState<PredState>>, XcfaAction>> {
return check(ic3Config.initPrec.predPrec(xcfa))
}
}
} else {
baseChecker(monolithicExpr)
}

return checker
as SafetyChecker<EmptyProof, Trace<XcfaState<PtrState<*>>, XcfaAction>, XcfaPrec<*>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enum class Backend {
LAZY,
PORTFOLIO,
MDD,
IC3,
NONE,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ data class BackendConfig<T : SpecBackendConfig>(
Backend.PORTFOLIO -> PortfolioConfig() as T
Backend.MDD -> MddConfig() as T
Backend.NONE -> null
Backend.IC3 -> Ic3Config() as T
}
}
}
Expand Down Expand Up @@ -413,6 +414,23 @@ data class MddConfig(
var initPrec: InitPrec = InitPrec.EMPTY,
) : SpecBackendConfig

data class Ic3Config(
@Parameter(names = ["--solver", "--mdd-solver"], description = "MDD solver name")
var solver: String = "Z3",
@Parameter(
names = ["--validate-solver", "--validate-mdd-solver"],
description =
"Activates a wrapper, which validates the assertions in the solver in each (SAT) check. Filters some solver issues.",
)
var validateSolver: Boolean = false,
@Parameter(names = ["--reversed"], description = "Create a reversed monolithic expression")
var reversed: Boolean = false,
@Parameter(names = ["--cegar"], description = "Wrap the check in a predicate-based CEGAR loop")
var cegar: Boolean = false,
@Parameter(names = ["--initprec"], description = "Wrap the check in a predicate-based CEGAR loop")
var initPrec: InitPrec = InitPrec.EMPTY,
) : SpecBackendConfig

data class OutputConfig(
@Parameter(names = ["--version"], description = "Display version", help = true)
var versionInfo: Boolean = false,
Expand Down

0 comments on commit 4addc51

Please sign in to comment.