hu.bme.mit.theta.cfa.CFA Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of theta-cfa Show documentation
Show all versions of theta-cfa Show documentation
Cfa subproject in the Theta model checking framework
/*
* Copyright 2024 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.cfa;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.lang.String.format;
import java.util.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import hu.bme.mit.theta.common.Utils;
import hu.bme.mit.theta.common.container.Containers;
import hu.bme.mit.theta.core.decl.VarDecl;
import hu.bme.mit.theta.core.stmt.Stmt;
import hu.bme.mit.theta.core.utils.StmtUtils;
/**
* Represents an immutable Control Flow Automata (CFA). Use the builder class to create a new
* instance.
*/
public final class CFA {
private final Loc initLoc;
private final Optional finalLoc;
private final Optional errorLoc;
private final Collection> vars;
private final Collection locs;
private final Collection edges;
private CFA(final Builder builder) {
initLoc = builder.initLoc;
finalLoc = Optional.ofNullable(builder.finalLoc);
errorLoc = Optional.ofNullable(builder.errorLoc);
locs = ImmutableSet.copyOf(builder.locs);
edges = ImmutableList.copyOf(builder.edges);
vars = edges.stream().flatMap(e -> StmtUtils.getVars(e.getStmt()).stream())
.collect(toImmutableSet());
Set varNames = Containers.createSet();
for (var v : vars) {
checkArgument(!varNames.contains(v.getName()),
"Variable with name '" + v.getName() + "' already exists in the CFA.");
varNames.add(v.getName());
}
}
public Loc getInitLoc() {
return initLoc;
}
public Optional getFinalLoc() {
return finalLoc;
}
public Optional getErrorLoc() {
return errorLoc;
}
/**
* Get the variables appearing on the edges of the CFA.
*/
public Collection> getVars() {
return vars;
}
public Collection getLocs() {
return locs;
}
public Collection getEdges() {
return edges;
}
public static Builder builder() {
return new Builder();
}
@Override
public String toString() {
return Utils.lispStringBuilder("process").aligned().addAll(vars).body()
.addAll(locs.stream().map(this::locToString))
.addAll(edges.stream().map(this::edgeToString)).toString();
}
private String locToString(final Loc loc) {
if (initLoc.equals(loc)) {
return format("(init %s)", loc.getName());
} else if (finalLoc.isPresent() && finalLoc.get().equals(loc)) {
return format("(final %s)", loc.getName());
} else if (errorLoc.isPresent() && errorLoc.get().equals(loc)) {
return format("(error %s)", loc.getName());
} else {
return format("(loc %s)", loc.getName());
}
}
private String edgeToString(final Edge edge) {
return Utils.lispStringBuilder("edge").add(edge.getSource().getName())
.add(edge.getTarget().getName())
.add(edge.getStmt()).toString();
}
public static final class Loc {
private final String name;
private final Collection inEdges;
private final Collection outEdges;
private Loc(final String name) {
this.name = checkNotNull(name);
inEdges = new LinkedList<>();
outEdges = new LinkedList<>();
}
////
public String getName() {
return name;
}
public Collection getInEdges() {
return Collections.unmodifiableCollection(inEdges);
}
public Collection getOutEdges() {
return Collections.unmodifiableCollection(outEdges);
}
////
@Override
public String toString() {
return name;
}
}
public static final class Edge {
private final Loc source;
private final Loc target;
private final Stmt stmt;
private Edge(final Loc source, final Loc target, final Stmt stmt) {
this.source = checkNotNull(source);
this.target = checkNotNull(target);
this.stmt = checkNotNull(stmt);
}
public Loc getSource() {
return source;
}
public Loc getTarget() {
return target;
}
public Stmt getStmt() {
return stmt;
}
}
public static final class Builder {
private Loc initLoc;
private Loc finalLoc;
private Loc errorLoc;
private final Collection locs;
private final Collection edges;
private final Set locNames;
private boolean built;
private static int UNNAMED_LOC_LABEL = 0;
private Builder() {
locs = Containers.createSet();
locNames = Containers.createSet();
edges = new LinkedList<>();
built = false;
}
public Loc getInitLoc() {
return initLoc;
}
public Loc getFinalLoc() {
return finalLoc;
}
public Loc getErrorLoc() {
return errorLoc;
}
public void setInitLoc(final Loc initLoc) {
checkNotBuilt();
checkNotNull(initLoc);
checkArgument(locs.contains(initLoc), "Initial location not present in CFA.");
checkArgument(!initLoc.equals(finalLoc), "Initial location cannot be same as final.");
checkArgument(!initLoc.equals(errorLoc), "Initial location cannot be same as error.");
this.initLoc = initLoc;
}
public void setFinalLoc(final Loc finalLoc) {
checkNotBuilt();
checkNotNull(finalLoc);
checkArgument(locs.contains(finalLoc), "Final location not present in CFA.");
checkArgument(!finalLoc.equals(initLoc), "Final location cannot be same as init.");
checkArgument(!finalLoc.equals(errorLoc), "Final location cannot be same as error.");
this.finalLoc = finalLoc;
}
public void setErrorLoc(final Loc errorLoc) {
checkNotBuilt();
checkNotNull(errorLoc);
checkArgument(locs.contains(errorLoc), "Error location not present in CFA.");
checkArgument(!errorLoc.equals(initLoc), "Error location cannot be same as init.");
checkArgument(!errorLoc.equals(finalLoc), "Error location cannot be same as final.");
this.errorLoc = errorLoc;
}
public Loc createLoc(final String name) {
checkNotBuilt();
checkArgument(!locNames.contains(name),
"Location with name '" + name + "' already exists in the CFA.");
final Loc loc = new Loc(name);
locs.add(loc);
locNames.add(name);
return loc;
}
public Loc createLoc() {
return createLoc("__" + UNNAMED_LOC_LABEL++);
}
public Edge createEdge(final Loc source, final Loc target, final Stmt stmt) {
checkNotBuilt();
checkArgument(locs.contains(source), "Invalid source.");
checkArgument(locs.contains(target), "Invalid target.");
final Edge edge = new Edge(source, target, stmt);
source.outEdges.add(edge);
target.inEdges.add(edge);
edges.add(edge);
return edge;
}
public CFA build() {
checkState(initLoc != null, "Initial location must be set.");
if (finalLoc != null) {
checkState(finalLoc.getOutEdges().isEmpty(),
"Final location cannot have outgoing edges.");
}
if (errorLoc != null) {
checkState(errorLoc.getOutEdges().isEmpty(),
"Error location cannot have outgoing edges.");
}
built = true;
return new CFA(this);
}
private void checkNotBuilt() {
checkState(!built, "A CFA was already built.");
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy