Skip to content

Commit

Permalink
Merge pull request #85 from ftsrg/cfaprop
Browse files Browse the repository at this point in the history
Make error loc of CFA optional, add errorloc argument to CLI tool
  • Loading branch information
hajduakos authored Oct 1, 2020
2 parents b8140b8 + 1fc3c37 commit c48087a
Show file tree
Hide file tree
Showing 16 changed files with 211 additions and 67 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {

allprojects {
group = "hu.bme.mit.inf.theta"
version = "2.6.1"
version = "2.7.0"

apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ public class DistToErrComparator implements ArgNodeComparator {
private final int errorWeight;
private final int depthWeight;
private final CFA cfa;
private final Loc errLoc;

public DistToErrComparator(final CFA cfa) {
this(cfa, 1, 0);
public DistToErrComparator(final CFA cfa, final Loc errLoc) {
this(cfa, errLoc, 1, 0);
}

public DistToErrComparator(final CFA cfa, final int errorWeight, final int depthWeight) {
public DistToErrComparator(final CFA cfa, final Loc errLoc, final int errorWeight, final int depthWeight) {
this.cfa = cfa;
this.errLoc = errLoc;
this.errorWeight = errorWeight;
this.depthWeight = depthWeight;
distancesToError = null;
Expand All @@ -74,16 +76,16 @@ private int getWeightedDistance(final ArgNode<? extends State, ? extends Action>

private int getDistanceToError(final Loc loc) {
if (distancesToError == null) {
distancesToError = calculateDistancesToError(cfa);
distancesToError = calculateDistancesToError(cfa, errLoc);
}
return distancesToError.getOrDefault(loc, Integer.MAX_VALUE);
}

static Map<Loc, Integer> calculateDistancesToError(final CFA cfa) {
static Map<Loc, Integer> calculateDistancesToError(final CFA cfa, final Loc errLoc) {
List<Loc> queue = new LinkedList<>();
final Map<Loc, Integer> distancesToError = new HashMap<>();
queue.add(cfa.getErrorLoc());
distancesToError.put(cfa.getErrorLoc(), 0);
queue.add(errLoc);
distancesToError.put(errLoc, 0);
int distance = 1;

while (!queue.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,26 @@ public enum Refinement {
public enum Search {
BFS {
@Override
public ArgNodeComparator getComp(final CFA cfa) {
public ArgNodeComparator getComp(final CFA cfa, final CFA.Loc errLoc) {
return ArgNodeComparators.combine(ArgNodeComparators.targetFirst(), ArgNodeComparators.bfs());
}
},

DFS {
@Override
public ArgNodeComparator getComp(final CFA cfa) {
public ArgNodeComparator getComp(final CFA cfa, final CFA.Loc errLoc) {
return ArgNodeComparators.combine(ArgNodeComparators.targetFirst(), ArgNodeComparators.dfs());
}
},

ERR {
@Override
public ArgNodeComparator getComp(final CFA cfa) {
return new DistToErrComparator(cfa);
public ArgNodeComparator getComp(final CFA cfa, final CFA.Loc errLoc) {
return new DistToErrComparator(cfa, errLoc);
}
};

public abstract ArgNodeComparator getComp(CFA cfa);
public abstract ArgNodeComparator getComp(CFA cfa, CFA.Loc errLoc);

}

Expand Down Expand Up @@ -147,19 +147,19 @@ public abstract <S extends ExprState, A extends Action, P extends Prec, R extend
public enum Encoding {
SBE {
@Override
public CfaLts getLts() {
public CfaLts getLts(CFA.Loc errorLoc) {
return new CfaCachedLts(CfaSbeLts.getInstance());
}
},

LBE {
@Override
public CfaLts getLts() {
return new CfaCachedLts(CfaLbeLts.getInstance());
public CfaLts getLts(CFA.Loc errorLoc) {
return new CfaCachedLts(CfaLbeLts.of(errorLoc));
}
};

public abstract CfaLts getLts();
public abstract CfaLts getLts(CFA.Loc errorLoc);
}

public enum InitPrec {
Expand Down Expand Up @@ -224,18 +224,18 @@ public CfaConfigBuilder pruneStrategy(final PruneStrategy pruneStrategy) {
return this;
}

public CfaConfig<? extends State, ? extends Action, ? extends Prec> build(final CFA cfa) {
public CfaConfig<? extends State, ? extends Action, ? extends Prec> build(final CFA cfa, final CFA.Loc errLoc) {
final ItpSolver solver = solverFactory.createItpSolver();
final CfaLts lts = encoding.getLts();
final CfaLts lts = encoding.getLts(errLoc);

if (domain == Domain.EXPL) {
final Analysis<CfaState<ExplState>, CfaAction, CfaPrec<ExplPrec>> analysis = CfaAnalysis
.create(cfa.getInitLoc(), ExplStmtAnalysis.create(solver, True(), maxEnum));
final ArgBuilder<CfaState<ExplState>, CfaAction, CfaPrec<ExplPrec>> argBuilder = ArgBuilder.create(lts,
analysis, s -> s.getLoc().equals(cfa.getErrorLoc()), true);
analysis, s -> s.getLoc().equals(errLoc), true);
final Abstractor<CfaState<ExplState>, CfaAction, CfaPrec<ExplPrec>> abstractor = BasicAbstractor
.builder(argBuilder).projection(CfaState::getLoc)
.waitlist(PriorityWaitlist.create(search.getComp(cfa)))
.waitlist(PriorityWaitlist.create(search.getComp(cfa, errLoc)))
.stopCriterion(refinement == Refinement.MULTI_SEQ ? StopCriterions.fullExploration()
: StopCriterions.firstCex()).logger(logger).build();

Expand Down Expand Up @@ -372,10 +372,10 @@ public CfaConfigBuilder pruneStrategy(final PruneStrategy pruneStrategy) {
final Analysis<CfaState<PredState>, CfaAction, CfaPrec<PredPrec>> analysis = CfaAnalysis
.create(cfa.getInitLoc(), PredAnalysis.create(solver, predAbstractor, True()));
final ArgBuilder<CfaState<PredState>, CfaAction, CfaPrec<PredPrec>> argBuilder = ArgBuilder.create(lts,
analysis, s -> s.getLoc().equals(cfa.getErrorLoc()), true);
analysis, s -> s.getLoc().equals(errLoc), true);
final Abstractor<CfaState<PredState>, CfaAction, CfaPrec<PredPrec>> abstractor = BasicAbstractor
.builder(argBuilder).projection(CfaState::getLoc)
.waitlist(PriorityWaitlist.create(search.getComp(cfa)))
.waitlist(PriorityWaitlist.create(search.getComp(cfa, errLoc)))
.stopCriterion(refinement == Refinement.MULTI_SEQ ? StopCriterions.fullExploration()
: StopCriterions.firstCex()).logger(logger).build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,22 @@
import hu.bme.mit.theta.cfa.analysis.CfaState;
import hu.bme.mit.theta.common.Utils;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* Large block encoding (LBE) implementation for CFA LTS. It maps each path
* (with no branching) into a single action.
*/
public final class CfaLbeLts implements CfaLts {

private static final class LazyHolder {
private static final CfaLbeLts INSTANCE = new CfaLbeLts();
}
private final Loc targetLoc;

private CfaLbeLts() {
private CfaLbeLts(Loc targetLoc) {
this.targetLoc = checkNotNull(targetLoc, "Target location must be given for LBE encoder.");
}

public static CfaLbeLts getInstance() {
return LazyHolder.INSTANCE;
public static CfaLbeLts of(Loc targetLoc) {
return new CfaLbeLts(targetLoc);
}

@Override
Expand All @@ -52,7 +53,7 @@ public Collection<CfaAction> getEnabledActionsFor(final CfaState<?> state) {
final List<Edge> edges = new LinkedList<>();
edges.add(edge);
Loc running = edge.getTarget();
while (running.getInEdges().size() == 1 && running.getOutEdges().size() == 1) {
while (running.getInEdges().size() == 1 && running.getOutEdges().size() == 1 && !running.equals(targetLoc)) {
final Edge next = Utils.singleElementOf(running.getOutEdges());
edges.add(next);
running = next.getTarget();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,15 @@ private static void addLocation(final Graph graph, final CFA cfa, final Loc loc,
final String id = LOC_ID_PREFIX + ids.size();
ids.put(loc, id);
String label = loc.getName();
boolean isError = cfa.getErrorLoc().isPresent() && loc == cfa.getErrorLoc().get();
if (loc == cfa.getInitLoc()) {
label += " (init)";
} else if (loc == cfa.getFinalLoc()) {
} else if (cfa.getFinalLoc().isPresent() && loc == cfa.getFinalLoc().get()) {
label += " (end)";
} else if (loc == cfa.getErrorLoc()) {
} else if (isError) {
label += " (error)";
}
final int peripheries = loc == cfa.getErrorLoc() ? 2 : 1;
final int peripheries = isError ? 2 : 1;
final NodeAttributes nAttrs = NodeAttributes.builder().label(label).fillColor(FILL_COLOR).lineColor(LINE_COLOR)
.lineStyle(LOC_LINE_STYLE).peripheries(peripheries).build();
graph.addNode(id, nAttrs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static Collection<Object[]> data() {
public void test() throws IOException {
CFA cfa = CfaDslManager.createCfa(new FileInputStream(filePath));
CfaConfig<? extends State, ? extends Action, ? extends Prec> config
= new CfaConfigBuilder(domain, refinement, Z3SolverFactory.getInstance()).build(cfa);
= new CfaConfigBuilder(domain, refinement, Z3SolverFactory.getInstance()).build(cfa, cfa.getErrorLoc().get());
SafetyResult<? extends State, ? extends Action> result = config.check();
Assert.assertEquals(isSafe, result.isSafe());
if (result.isUnsafe()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void test() {
builder.createEdge(loc2, locFinal, stmt);

final CFA cfa = builder.build();
final Map<Loc, Integer> distancesToError = DistToErrComparator.calculateDistancesToError(cfa);
final Map<Loc, Integer> distancesToError = DistToErrComparator.calculateDistancesToError(cfa, cfa.getErrorLoc().get());

Assert.assertEquals(0, (int) distancesToError.get(locErr));
Assert.assertEquals(2, (int) distancesToError.get(loc0));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package hu.bme.mit.theta.cfa.analysis;

import com.google.common.collect.ImmutableSet;
import hu.bme.mit.theta.analysis.expr.ExprState;
import hu.bme.mit.theta.cfa.CFA;
import hu.bme.mit.theta.cfa.analysis.lts.CfaLbeLts;
import hu.bme.mit.theta.cfa.analysis.lts.CfaLts;
import hu.bme.mit.theta.cfa.analysis.lts.CfaSbeLts;
import hu.bme.mit.theta.cfa.dsl.CfaDslManager;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.booltype.BoolType;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class EncodingTest {

private CFA cfa;

private CFA.Loc getLocByName(String name) {
for (CFA.Loc loc : cfa.getLocs()) {
if (loc.getName().equals(name)) return loc;
}
throw new IllegalArgumentException("Location not found");
}

private Set<String> getNextLocs(CfaLts lts, String loc) {
Set<String> locs = new HashSet<>();
SS ss = new SS();
for (var act : lts.getEnabledActionsFor(CfaState.of(getLocByName(loc), ss))) {
locs.add(act.getTarget().getName());
}
return locs;
}

private class SS implements ExprState {
@Override
public boolean isBottom() {
return false;
}

@Override
public Expr<BoolType> toExpr() {
return null;
}
}

@Before
public void load() throws IOException {
try (var fis = new FileInputStream("src/test/resources/block-encoding.cfa")) {
cfa = CfaDslManager.createCfa(fis);
}
}

@Test
public void testSbe() {
CfaSbeLts lts = CfaSbeLts.getInstance();
Assert.assertEquals(ImmutableSet.of("L1"), getNextLocs(lts, "L0"));
Assert.assertEquals(ImmutableSet.of("L2", "L4"), getNextLocs(lts, "L1"));
Assert.assertEquals(ImmutableSet.of("L3"), getNextLocs(lts, "L2"));
Assert.assertEquals(ImmutableSet.of("L4"), getNextLocs(lts, "L3"));
Assert.assertEquals(ImmutableSet.of("L5"), getNextLocs(lts, "L4"));
Assert.assertEquals(ImmutableSet.of("L1", "L6"), getNextLocs(lts, "L5"));
Assert.assertEquals(ImmutableSet.of("L7"), getNextLocs(lts, "L6"));
Assert.assertEquals(ImmutableSet.of(), getNextLocs(lts, "L7"));
}

@Test
public void testLbe1() {
CfaLbeLts lts = CfaLbeLts.of(getLocByName("L7"));
Assert.assertEquals(ImmutableSet.of("L1"), getNextLocs(lts, "L0"));
Assert.assertEquals(ImmutableSet.of("L4"), getNextLocs(lts, "L1"));
Assert.assertEquals(ImmutableSet.of("L4"), getNextLocs(lts, "L2"));
Assert.assertEquals(ImmutableSet.of("L4"), getNextLocs(lts, "L3"));
Assert.assertEquals(ImmutableSet.of("L5"), getNextLocs(lts, "L4"));
Assert.assertEquals(ImmutableSet.of("L1", "L7"), getNextLocs(lts, "L5"));
Assert.assertEquals(ImmutableSet.of("L7"), getNextLocs(lts, "L6"));
Assert.assertEquals(ImmutableSet.of(), getNextLocs(lts, "L7"));
}

@Test
public void testLbe2() {
CfaLbeLts lts = CfaLbeLts.of(getLocByName("L3"));
Assert.assertEquals(ImmutableSet.of("L1"), getNextLocs(lts, "L0"));
Assert.assertEquals(ImmutableSet.of("L3", "L4"), getNextLocs(lts, "L1"));
Assert.assertEquals(ImmutableSet.of("L3"), getNextLocs(lts, "L2"));
Assert.assertEquals(ImmutableSet.of("L4"), getNextLocs(lts, "L3"));
Assert.assertEquals(ImmutableSet.of("L5"), getNextLocs(lts, "L4"));
Assert.assertEquals(ImmutableSet.of("L1", "L7"), getNextLocs(lts, "L5"));
Assert.assertEquals(ImmutableSet.of("L7"), getNextLocs(lts, "L6"));
Assert.assertEquals(ImmutableSet.of(), getNextLocs(lts, "L7"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public void test() throws FileNotFoundException, IOException {

final ItpSolver solver = Z3SolverFactory.getInstance().createItpSolver();

final PredImpactChecker checker = PredImpactChecker.create(CfaLbeLts.getInstance(), cfa.getInitLoc(),
l -> l.equals(cfa.getErrorLoc()), solver);
final PredImpactChecker checker = PredImpactChecker.create(CfaLbeLts.of(cfa.getErrorLoc().get()), cfa.getInitLoc(),
l -> l.equals(cfa.getErrorLoc().get()), solver);

// Act
final SafetyResult<? extends ExprState, ? extends ExprAction> status = checker.check(UnitPrec.getInstance());
Expand Down
20 changes: 20 additions & 0 deletions subprojects/cfa-analysis/src/test/resources/block-encoding.cfa
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
main process cfa {
init loc L0
loc L1
loc L2
loc L3
loc L4
loc L5
loc L6
loc L7

L0 -> L1 { }
L1 -> L2 { }
L2 -> L3 { }
L3 -> L4 { }
L1 -> L4 { }
L4 -> L5 { }
L5 -> L6 { }
L6 -> L7 { }
L5 -> L1 { }
}
3 changes: 2 additions & 1 deletion subprojects/cfa-cli/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Overview

The `cfa-cli` project is an executable (command line) tool for running CEGAR-based analyses on CFAs.
The `cfa-cli` project is an executable (command line) tool for running CEGAR-based location-reachability analyses on CFAs.
Furthermore, it also includes some utilities, such as calculating metrics or visualizing the CFA.
For more information about the CFA formalism and its supported language elements, take a look at the [`cfa`](../cfa/README.md) project.

Expand Down Expand Up @@ -46,6 +46,7 @@ Note that the model must be given as the first positional argument (without `--m
All arguments are optional, except `--model`.

* `--model`: Path of the input CFA model (mandatory).
* `--errorloc`: Name of the error (target) location in the CFA, which is checked for reachability. The CFA is safe if the error location is not reachable, and unsafe otherwise. This argument can be omitted if a location in the CFA is marked with the error keyword. If there is an error location marked in the CFA and this argument is also given, the argument has priority.
* `--cex`: Output file where the counterexample is written (if the result is unsafe). If the argument is not given (default) the counterexample is not printed. Use `CON` (Windows) or `/dev/stdout` (Linux) as argument to print to the standard output.
* `--loglevel`: Detailedness of logging.
* Possible values (from the least to the most detailed): `RESULT`, `MAINSTEP`, `SUBSTEP` (default), `INFO`, `DETAIL`, `VERBOSE`.
Expand Down
Loading

0 comments on commit c48087a

Please sign in to comment.