hu.bme.mit.theta.xta.analysis.XtaAction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of theta-xta-analysis Show documentation
Show all versions of theta-xta-analysis Show documentation
Xta Analysis subproject in the Theta model checking framework
The newest version!
/*
* 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.xta.analysis;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Streams;
import hu.bme.mit.theta.analysis.expr.StmtAction;
import hu.bme.mit.theta.common.LispStringBuilder;
import hu.bme.mit.theta.common.Utils;
import hu.bme.mit.theta.core.decl.VarDecl;
import hu.bme.mit.theta.core.stmt.Stmt;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.booltype.BoolType;
import hu.bme.mit.theta.core.type.booltype.SmartBoolExprs;
import hu.bme.mit.theta.core.type.rattype.RatType;
import hu.bme.mit.theta.xta.Guard;
import hu.bme.mit.theta.xta.Label;
import hu.bme.mit.theta.xta.Sync;
import hu.bme.mit.theta.xta.XtaProcess.Edge;
import hu.bme.mit.theta.xta.XtaProcess.Loc;
import hu.bme.mit.theta.xta.XtaProcess.LocKind;
import hu.bme.mit.theta.xta.XtaSystem;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Streams.zip;
import static hu.bme.mit.theta.core.decl.Decls.Var;
import static hu.bme.mit.theta.core.stmt.Stmts.*;
import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq;
import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.Not;
import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.Or;
import static hu.bme.mit.theta.core.type.rattype.RatExprs.*;
import static hu.bme.mit.theta.xta.Sync.Kind.EMIT;
public abstract class XtaAction extends StmtAction {
private static final VarDecl DELAY = Var("_delay", Rat());
private final Collection> clockVars;
private final List sourceLocs;
private XtaAction(final XtaSystem system, final List source) {
checkNotNull(system);
this.clockVars = system.getClockVars();
this.sourceLocs = ImmutableList.copyOf(checkNotNull(source));
}
public static BasicXtaAction basic(final XtaSystem system, final List sourceLocs,
final Edge edge) {
return new BasicXtaAction(system, sourceLocs, edge);
}
public static BinaryXtaAction binary(final XtaSystem system, final List sourceLocs,
final Edge emitEdge,
final Edge recvEdge) {
return new BinaryXtaAction(system, sourceLocs, emitEdge, recvEdge);
}
public static BroadcastXtaAction broadcast(final XtaSystem system, final List sourceLocs,
final Edge emitEdge,
final List recvEdges) {
return new BroadcastXtaAction(system, sourceLocs, emitEdge, recvEdges);
}
public Collection> getClockVars() {
return clockVars;
}
public List getSourceLocs() {
return sourceLocs;
}
public abstract List getTargetLocs();
public boolean isBasic() {
return false;
}
public boolean isBinary() {
return false;
}
public boolean isBroadcast() {
return false;
}
public BasicXtaAction asBasic() {
throw new ClassCastException();
}
public BinaryXtaAction asBinary() {
throw new ClassCastException();
}
public BroadcastXtaAction asBroadcast() {
throw new ClassCastException();
}
public static final class BasicXtaAction extends XtaAction {
private final Edge edge;
private final List targetLocs;
private volatile List stmts = null;
private BasicXtaAction(final XtaSystem system, final List sourceLocs,
final Edge edge) {
super(system, sourceLocs);
this.edge = checkNotNull(edge);
final ImmutableList.Builder builder = ImmutableList.builder();
final Loc source = edge.getSource();
final Loc target = edge.getTarget();
boolean matched = false;
for (final Loc loc : sourceLocs) {
if (loc.equals(source)) {
checkArgument(!matched);
builder.add(target);
matched = true;
} else {
builder.add(loc);
}
}
checkArgument(matched);
targetLocs = builder.build();
}
public Edge getEdge() {
return edge;
}
@Override
public List getTargetLocs() {
return targetLocs;
}
@Override
public boolean isBasic() {
return true;
}
@Override
public BasicXtaAction asBasic() {
return this;
}
@Override
public List getStmts() {
List result = stmts;
if (stmts == null) {
final ImmutableList.Builder builder = ImmutableList.builder();
addClocksNonNegative(builder, getClockVars());
addInvariants(builder, getSourceLocs());
addGuards(builder, edge);
addUpdates(builder, edge);
addInvariants(builder, targetLocs);
if (shouldApplyDelay(getTargetLocs())) {
addDelay(builder, getClockVars());
}
result = builder.build();
stmts = result;
}
return result;
}
@Override
public String toString() {
return Utils.lispStringBuilder(getClass().getSimpleName()).body()
.addAll(edge.getGuards())
.addAll(edge.getUpdates()).toString();
}
}
public static final class BinaryXtaAction extends XtaAction {
private final Edge emitEdge;
private final Edge recvEdge;
private final List targetLocs;
private volatile List stmts = null;
private BinaryXtaAction(final XtaSystem system, final List sourceLocs,
final Edge emitEdge,
final Edge recvEdge) {
super(system, sourceLocs);
this.emitEdge = checkNotNull(emitEdge);
this.recvEdge = checkNotNull(recvEdge);
checkArgument(emitEdge.getSync().isPresent());
checkArgument(recvEdge.getSync().isPresent());
final Label emitLabel = emitEdge.getSync().get().getLabel();
final Label recvLabel = recvEdge.getSync().get().getLabel();
checkArgument(emitLabel.equals(recvLabel));
final ImmutableList.Builder builder = ImmutableList.builder();
final Loc emitSource = emitEdge.getSource();
final Loc emitTarget = emitEdge.getTarget();
final Loc recvSource = recvEdge.getSource();
final Loc recvTarget = recvEdge.getTarget();
boolean emitMatched = false;
boolean recvMatched = false;
for (final Loc loc : sourceLocs) {
if (loc.equals(emitSource)) {
checkArgument(!emitMatched);
builder.add(emitTarget);
emitMatched = true;
} else if (loc.equals(recvSource)) {
checkArgument(!recvMatched);
builder.add(recvTarget);
recvMatched = true;
} else {
builder.add(loc);
}
}
checkArgument(emitMatched);
checkArgument(recvMatched);
targetLocs = builder.build();
}
public Edge getEmitEdge() {
return emitEdge;
}
public Edge getRecvEdge() {
return recvEdge;
}
@Override
public List getTargetLocs() {
return targetLocs;
}
@Override
public boolean isBinary() {
return true;
}
@Override
public BinaryXtaAction asBinary() {
return this;
}
@Override
public List getStmts() {
List result = stmts;
if (stmts == null) {
final ImmutableList.Builder builder = ImmutableList.builder();
addClocksNonNegative(builder, getClockVars());
addInvariants(builder, getSourceLocs());
addSync(builder, emitEdge, recvEdge);
addGuards(builder, emitEdge);
addGuards(builder, recvEdge);
addUpdates(builder, emitEdge);
addUpdates(builder, recvEdge);
addInvariants(builder, targetLocs);
if (shouldApplyDelay(getTargetLocs())) {
addDelay(builder, getClockVars());
}
result = builder.build();
stmts = result;
}
return result;
}
@Override
public String toString() {
return Utils.lispStringBuilder(getClass().getSimpleName()).add(emitEdge.getSync().get())
.add(recvEdge.getSync().get()).body().addAll(emitEdge.getGuards())
.addAll(recvEdge.getGuards())
.addAll(emitEdge.getUpdates()).addAll(recvEdge.getUpdates()).toString();
}
}
public static final class BroadcastXtaAction extends XtaAction {
private final Edge emitEdge;
private final List recvEdges;
private final List> nonRecvEdges;
private final List targetLocs;
private volatile List stmts = null;
private BroadcastXtaAction(final XtaSystem system, final List sourceLocs,
final Edge emitEdge, List recvEdges) {
super(system, sourceLocs);
this.emitEdge = checkNotNull(emitEdge);
this.recvEdges = ImmutableList.copyOf(checkNotNull(recvEdges));
checkArgument(emitEdge.getSync().isPresent());
final Sync emitSync = emitEdge.getSync().get();
checkArgument(emitSync.getKind().equals(EMIT));
final ImmutableList.Builder> nonRecvEdgesBuilder = ImmutableList.builder();
final ImmutableList.Builder targetLocsBuilder = ImmutableList.builder();
final Loc emitSource = emitEdge.getSource();
final Loc emitTarget = emitEdge.getTarget();
boolean emitMatched = false;
final Iterator recvEdgesIterator = recvEdges.listIterator();
Optional optRecvEdge = safeNext(recvEdgesIterator);
for (final Loc loc : sourceLocs) {
if (loc.equals(emitSource)) {
targetLocsBuilder.add(emitTarget);
emitMatched = true;
} else if (!optRecvEdge.isPresent() || !optRecvEdge.get().getSource().equals(loc)) {
final Collection nonRecvEdgesForLoc = outEdgesOfLocThatMayReceiveSync(loc,
emitSync);
if (!nonRecvEdgesForLoc.isEmpty()) {
nonRecvEdgesBuilder.add(nonRecvEdgesForLoc);
}
targetLocsBuilder.add(loc);
} else {
final Edge recvEdge = optRecvEdge.get();
checkArgument(recvEdge.getSync().isPresent());
final Sync recvSync = recvEdge.getSync().get();
checkArgument(recvSync.mayReceive(emitSync));
final Loc recvTarget = recvEdge.getTarget();
targetLocsBuilder.add(recvTarget);
optRecvEdge = safeNext(recvEdgesIterator);
}
}
final boolean recvsMatched = optRecvEdge.isEmpty();
assert emitMatched;
assert recvsMatched;
nonRecvEdges = nonRecvEdgesBuilder.build();
targetLocs = targetLocsBuilder.build();
final long nrLocsExceptEmitSourceWithAnyEdgeThatMayRecvSync =
nrLocsExceptEmitSourceWithAnyEdgeThatMayRecvSync(emitSource, sourceLocs, emitSync);
assert nrLocsExceptEmitSourceWithAnyEdgeThatMayRecvSync
== recvEdges.size() + nonRecvEdges.size();
assert targetLocs.size() == sourceLocs.size();
}
private Collection outEdgesOfLocThatMayReceiveSync(final Loc loc,
final Sync emitSync) {
return loc.getOutEdges().stream()
.filter(e ->
e.getSync().isPresent() &&
e.getSync().get().mayReceive(emitSync))
.collect(toImmutableSet());
}
private long nrLocsExceptEmitSourceWithAnyEdgeThatMayRecvSync(final Loc emitSource,
final List sourceLocs, final Sync emitSync) {
return sourceLocs.stream()
.filter(l -> !l.equals(emitSource))
.filter(l -> l.getOutEdges().stream().anyMatch(e ->
e.getSync().isPresent() && e.getSync().get().mayReceive(emitSync))
).count();
}
private final Optional safeNext(Iterator extends T> iterator) {
if (iterator.hasNext()) {
return Optional.of(iterator.next());
} else {
return Optional.empty();
}
}
public Edge getEmitEdge() {
return emitEdge;
}
public List getRecvEdges() {
return recvEdges;
}
public List> getNonRecvEdges() {
return nonRecvEdges;
}
@Override
public List getTargetLocs() {
return targetLocs;
}
@Override
public boolean isBroadcast() {
return true;
}
@Override
public BroadcastXtaAction asBroadcast() {
return this;
}
@Override
public List getStmts() {
List result = stmts;
if (stmts == null) {
final ImmutableList.Builder builder = ImmutableList.builder();
addClocksNonNegative(builder, getClockVars());
addInvariants(builder, getSourceLocs());
recvEdges.stream().forEachOrdered(recvEdge -> addSync(builder, emitEdge, recvEdge));
addGuards(builder, emitEdge);
recvEdges.stream().forEachOrdered(recvEdge -> addGuards(builder, recvEdge));
addUpdates(builder, emitEdge);
recvEdges.stream().forEachOrdered(recvEdge -> addUpdates(builder, recvEdge));
nonRecvEdges.stream().forEachOrdered(c -> c.stream().forEachOrdered(nonRecvEdge ->
addNonRecvSyncAndGuards(builder, emitEdge, nonRecvEdge)));
addInvariants(builder, targetLocs);
if (shouldApplyDelay(getTargetLocs())) {
addDelay(builder, getClockVars());
}
result = builder.build();
stmts = result;
}
return result;
}
@Override
public String toString() {
final LispStringBuilder builder = Utils.lispStringBuilder(getClass().getSimpleName());
builder.add(emitEdge.getSync().get()).body();
builder.addAll(emitEdge.getGuards());
builder.addAll(recvEdges.stream().map(edge ->
Utils.lispStringBuilder("enabled")
.add(edge.getSync().get())
.body()
.addAll(edge.getGuards())));
builder.addAll(nonRecvEdges.stream().flatMap(edges ->
edges.stream().map(edge ->
Utils.lispStringBuilder("disabled")
.add(edge.getSync().get())
.body()
.addAll(edge.getGuards()
))));
builder.addAll(emitEdge.getUpdates())
.addAll(recvEdges.stream().flatMap(e -> e.getUpdates().stream()));
return builder.toString();
}
}
private static void addClocksNonNegative(final ImmutableList.Builder builder,
final Collection> clocks) {
clocks.forEach(c -> builder.add(Assume(Geq(c.getRef(), Rat(0, 1)))));
}
private static void addInvariants(final ImmutableList.Builder builder,
final List locs) {
locs.forEach(l -> l.getInvars().forEach(i -> builder.add(Assume(i.toExpr()))));
}
private static void addSync(final Builder builder, final Edge emitEdge,
final Edge recvEdge) {
final Stream> emitArgs = emitEdge.getSync().get().getArgs().stream();
final Stream> recvArgs = recvEdge.getSync().get().getArgs().stream();
zip(emitArgs, recvArgs, (e, r) -> Assume(Eq(e, r))).forEach(builder::add);
}
private static void addGuards(final ImmutableList.Builder builder, final Edge edge) {
edge.getGuards().forEach(g -> builder.add(Assume(g.toExpr())));
}
private static void addNonRecvSyncAndGuards(final ImmutableList.Builder builder,
final Edge emitEdge, final Edge nonRecvEdge) {
final Stream> emitArgs = emitEdge.getSync().get().getArgs().stream();
final Stream> nonRecvArgs = nonRecvEdge.getSync().get().getArgs().stream();
final Stream> notEqExprs = zip(emitArgs, nonRecvArgs,
(e, r) -> Not(Eq(e, r)));
final Stream> notGuards = nonRecvEdge.getGuards().stream()
.filter(Guard::isDataGuard)
.map(Guard::toExpr)
.map(SmartBoolExprs::Not);
final List> exprs = Streams.concat(notEqExprs, notGuards)
.collect(toImmutableList());
builder.add(Assume(Or(exprs)));
}
private static void addUpdates(final ImmutableList.Builder builder, final Edge edge) {
edge.getUpdates().forEach(u -> builder.add(u.toStmt()));
}
private static void addDelay(final ImmutableList.Builder builder,
final Collection> clocks) {
builder.add(Havoc(DELAY));
builder.add(Assume(Geq(DELAY.getRef(), Rat(0, 1))));
clocks.forEach(c -> builder.add(Assign(c, Add(c.getRef(), DELAY.getRef()))));
}
private static boolean shouldApplyDelay(final List locs) {
return locs.stream().allMatch(l -> l.getKind() == LocKind.NORMAL);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy