All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hu.bme.mit.theta.xta.analysis.expl.XtaExplUtils Maven / Gradle / Ivy

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.expl;

import com.google.common.collect.Lists;
import com.google.common.collect.Streams;
import hu.bme.mit.theta.analysis.expl.ExplState;
import hu.bme.mit.theta.core.decl.VarDecl;
import hu.bme.mit.theta.core.model.MutableValuation;
import hu.bme.mit.theta.core.model.Valuation;
import hu.bme.mit.theta.core.stmt.AssignStmt;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.LitExpr;
import hu.bme.mit.theta.core.type.booltype.BoolType;
import hu.bme.mit.theta.core.type.booltype.FalseExpr;
import hu.bme.mit.theta.core.type.booltype.SmartBoolExprs;
import hu.bme.mit.theta.core.type.booltype.TrueExpr;
import hu.bme.mit.theta.core.utils.ExprUtils;
import hu.bme.mit.theta.core.utils.WpState;
import hu.bme.mit.theta.xta.Guard;
import hu.bme.mit.theta.xta.Guard.DataGuard;
import hu.bme.mit.theta.xta.Update;
import hu.bme.mit.theta.xta.XtaProcess.Edge;
import hu.bme.mit.theta.xta.XtaProcess.Loc;
import hu.bme.mit.theta.xta.analysis.XtaAction;
import hu.bme.mit.theta.xta.analysis.XtaAction.BasicXtaAction;
import hu.bme.mit.theta.xta.analysis.XtaAction.BinaryXtaAction;
import hu.bme.mit.theta.xta.analysis.XtaAction.BroadcastXtaAction;

import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Streams.zip;
import static hu.bme.mit.theta.core.stmt.Stmts.Assume;
import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq;
import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False;
import static hu.bme.mit.theta.core.type.booltype.SmartBoolExprs.*;
import static java.util.stream.Collectors.toList;


public final class XtaExplUtils {

    private XtaExplUtils() {
    }

    public static Valuation interpolate(final Valuation valA, final Expr exprB) {
        final Collection> vars = ExprUtils.getVars(exprB).stream()
                .filter(valA.getDecls()::contains)
                .collect(toList());
        final MutableValuation valI = new MutableValuation();
        for (final VarDecl var : vars) {
            final LitExpr val = valA.eval(var).get();
            valI.put(var, val);
        }

        assert ExprUtils.simplify(exprB, valI).equals(False());

        for (final VarDecl var : vars) {
            valI.remove(var);
            final Expr simplifiedExprB = ExprUtils.simplify(exprB, valI);
            if (simplifiedExprB.equals(False())) {
                continue;
            } else {
                final LitExpr val = valA.eval(var).get();
                valI.put(var, val);
            }
        }

        return valI;
    }

    ////

    public static ExplState post(final Valuation val, final XtaAction action) {
        checkNotNull(val);
        checkNotNull(action);

        if (action.isBasic()) {
            return postForBasicAction(val, action.asBasic());
        } else if (action.isBinary()) {
            return postForBinaryAction(val, action.asBinary());
        } else if (action.isBroadcast()) {
            return postForBroadcastAction(val, action.asBroadcast());
        } else {
            throw new AssertionError();
        }
    }

    private static ExplState postForBasicAction(final Valuation val, final BasicXtaAction action) {
        final Edge edge = action.getEdge();
        final List targetLocs = action.getTargetLocs();

        if (!checkGuards(edge, val)) {
            return ExplState.bottom();
        }

        final MutableValuation succVal = MutableValuation.copyOf(val);
        applyDataUpdates(action.getEdge(), succVal);

        if (!checkDataInvariants(targetLocs, succVal)) {
            return ExplState.bottom();
        }

        return ExplState.of(succVal);
    }

    private static ExplState postForBinaryAction(final Valuation val,
                                                 final BinaryXtaAction action) {
        final Edge emitEdge = action.getEmitEdge();
        final Edge recvEdge = action.getRecvEdge();
        final List targetLocs = action.getTargetLocs();

        if (!checkSync(emitEdge, recvEdge, val)) {
            return ExplState.bottom();
        }

        if (!checkGuards(emitEdge, val)) {
            return ExplState.bottom();
        }

        if (!checkGuards(recvEdge, val)) {
            return ExplState.bottom();
        }

        final MutableValuation succVal = MutableValuation.copyOf(val);
        applyDataUpdates(emitEdge, succVal);
        applyDataUpdates(recvEdge, succVal);

        if (!checkDataInvariants(targetLocs, succVal)) {
            return ExplState.bottom();
        }

        return ExplState.of(succVal);
    }

    private static ExplState postForBroadcastAction(final Valuation val,
                                                    final BroadcastXtaAction action) {
        final Edge emitEdge = action.getEmitEdge();
        final List recvEdges = action.getRecvEdges();
        final List> nonRecvEdges = action.getNonRecvEdges();
        final List targetLocs = action.getTargetLocs();

        if (recvEdges.stream().anyMatch(recvEdge ->
                !checkSync(emitEdge, recvEdge, val))) {
            return ExplState.bottom();
        }

        if (!checkGuards(emitEdge, val)) {
            return ExplState.bottom();
        }

        if (recvEdges.stream().anyMatch(recvEdge ->
                !checkGuards(recvEdge, val))) {
            return ExplState.bottom();
        }

        if (nonRecvEdges.stream().anyMatch(c -> c.stream().anyMatch(nonRecvEdge ->
                nonRecvEdgeDefinitelyEnabled(emitEdge, nonRecvEdge, val)))) {
            return ExplState.bottom();
        }

        final MutableValuation succVal = MutableValuation.copyOf(val);

        applyDataUpdates(emitEdge, succVal);
        recvEdges.stream().forEachOrdered(recvEdge -> applyDataUpdates(recvEdge, succVal));

        if (!checkDataInvariants(targetLocs, succVal)) {
            return ExplState.bottom();
        }

        return ExplState.of(succVal);
    }

    private static boolean nonRecvEdgeDefinitelyEnabled(final Edge emitEdge, final Edge nonRecvEdge,
                                                        final Valuation val) {
        for (final Guard guard : nonRecvEdge.getGuards()) {
            if (guard.isDataGuard()) {
                final DataGuard dataGuard = guard.asDataGuard();
                final Expr expr = ExprUtils.simplify(dataGuard.toExpr(), val);
                if (!(expr instanceof TrueExpr)) {
                    return false;
                }
            }
        }

        final List> emitArgs = emitEdge.getSync().get().getArgs();
        final List> recvArgs = nonRecvEdge.getSync().get().getArgs();
        if (zip(emitArgs.stream(), recvArgs.stream(),
                (e, r) -> !e.eval(val).equals(r.eval(val))).anyMatch(x -> x)) {
            return false;
        }

        return true;
    }

    private static boolean checkSync(final Edge emitEdge, final Edge recvEdge,
                                     final Valuation val) {
        final List> emitArgs = emitEdge.getSync().get().getArgs();
        final List> recvArgs = recvEdge.getSync().get().getArgs();
        return zip(emitArgs.stream(), recvArgs.stream(),
                (e, r) -> e.eval(val).equals(r.eval(val))).allMatch(x -> x);
    }

    private static boolean checkGuards(final Edge edge, final Valuation val) {
        for (final Guard guard : edge.getGuards()) {
            if (guard.isDataGuard()) {
                final DataGuard dataGuard = guard.asDataGuard();
                if (!checkDataGuard(dataGuard, val)) {
                    return false;
                }
            }
        }
        return true;
    }

    private static boolean checkDataGuard(final DataGuard guard, final Valuation val) {
        final Expr expr = ExprUtils.simplify(guard.asDataGuard().toExpr(), val);
        return !(expr instanceof FalseExpr);
    }

    private static boolean checkDataInvariants(final List locs, final Valuation val) {
        for (final Loc loc : locs) {
            final Collection invars = loc.getInvars();
            for (final Guard invar : invars) {
                if (invar.isDataGuard()) {
                    final Expr expr = ExprUtils.simplify(invar.asDataGuard().toExpr(),
                            val);
                    if (expr instanceof FalseExpr) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private static void applyDataUpdates(final Edge edge, final MutableValuation val) {
        final List updates = edge.getUpdates();
        for (final Update update : updates) {
            if (update.isDataUpdate()) {
                final AssignStmt stmt = (AssignStmt) update.toStmt();
                final VarDecl varDecl = stmt.getVarDecl();
                final Expr expr = ExprUtils.simplify(stmt.getExpr(), val);
                if (expr instanceof LitExpr) {
                    final LitExpr value = (LitExpr) expr;
                    val.put(varDecl, value);
                } else {
                    val.remove(varDecl);
                }
            }
        }
    }

    ////

    public static Expr pre(final Expr expr, final XtaAction action) {
        checkNotNull(expr);
        checkNotNull(action);

        if (action.isBasic()) {
            return preForBasicAction(expr, action.asBasic());
        } else if (action.isBinary()) {
            return preForBinaryAction(expr, action.asBinary());
        } else if (action.isBroadcast()) {
            return preForBroadcastAction(expr, action.asBroadcast());
        } else {
            throw new AssertionError();
        }
    }

    private static Expr preForBasicAction(final Expr expr,
                                                    final BasicXtaAction action) {
        final Edge edge = action.getEdge();
        final WpState wp0 = WpState.of(expr);
        final WpState wp1 = applyInverseUpdates(wp0, edge);
        final WpState wp2 = applyGuards(wp1, edge);
        return wp2.getExpr();
    }

    private static Expr preForBinaryAction(final Expr expr,
                                                     final BinaryXtaAction action) {
        final Edge emitEdge = action.getEmitEdge();
        final Edge recvEdge = action.getRecvEdge();
        final WpState wp0 = WpState.of(expr);
        final WpState wp1 = applyInverseUpdates(wp0, recvEdge);
        final WpState wp2 = applyInverseUpdates(wp1, emitEdge);
        final WpState wp3 = applyGuards(wp2, recvEdge);
        final WpState wp4 = applyGuards(wp3, emitEdge);
        final WpState wp5 = applySync(wp4, emitEdge, recvEdge);
        return wp5.getExpr();
    }

    private static Expr preForBroadcastAction(final Expr expr,
                                                        final BroadcastXtaAction action) {
        final Edge emitEdge = action.getEmitEdge();
        final List recvEdges = action.getRecvEdges();
        final List reverseRecvEdges = Lists.reverse(recvEdges);
        final List> nonRecvEdgeCols = action.getNonRecvEdges();

        final WpState wp0 = WpState.of(expr);

        WpState wp1 = wp0;
        for (final Edge recvEdge : reverseRecvEdges) {
            wp1 = applyInverseUpdates(wp1, recvEdge);
        }
        final WpState wp2 = applyInverseUpdates(wp1, emitEdge);

        WpState wp3 = wp2;
        for (final Edge recvEdge : reverseRecvEdges) {
            wp3 = applyGuards(wp3, recvEdge);
        }
        final WpState wp4 = applyGuards(wp3, emitEdge);

        WpState wp5 = wp4;
        for (final Edge recvEdge : reverseRecvEdges) {
            wp5 = applySync(wp5, emitEdge, recvEdge);
        }

        WpState wp6 = wp5;
        for (final Collection nonRecvEdges : nonRecvEdgeCols) {
            for (final Edge nonRecvEdge : nonRecvEdges) {
                wp6 = applyNonRecvEdge(wp6, emitEdge, nonRecvEdge);
            }
        }

        return wp6.getExpr();
    }

    private static WpState applyInverseUpdates(final WpState state, final Edge edge) {
        WpState res = state;
        for (final Update update : Lists.reverse(edge.getUpdates())) {
            if (update.isDataUpdate()) {
                res = res.wep(update.asDataUpdate().toStmt());
            }
        }
        return res;
    }

    private static WpState applyGuards(final WpState state, final Edge edge) {
        WpState res = state;
        for (final Guard guard : edge.getGuards()) {
            if (guard.isDataGuard()) {
                res = res.wep(Assume(guard.asDataGuard().toExpr()));
            }
        }
        return res;
    }

    private static WpState applySync(final WpState state, final Edge emitEdge,
                                     final Edge recvEdge) {
        final Stream> emitArgs = emitEdge.getSync().get().getArgs().stream();
        final Stream> recvArgs = recvEdge.getSync().get().getArgs().stream();
        final List> exprs = zip(emitArgs, recvArgs,
                (e, r) -> (Expr) Eq(e, r))
                .collect(toImmutableList());
        final Expr andExpr = And(exprs);
        return state.wep(Assume(andExpr));
    }

    private static WpState applyNonRecvEdge(final WpState state, 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());
        return state.wep(Assume(Or(exprs)));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy