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

hu.bme.mit.theta.xsts.analysis.config.XstsConfigBuilder Maven / Gradle / Ivy

There is a newer version: 6.5.2
Show 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.xsts.analysis.config;

import hu.bme.mit.theta.analysis.*;
import hu.bme.mit.theta.analysis.algorithm.arg.ARG;
import hu.bme.mit.theta.analysis.algorithm.arg.ArgBuilder;
import hu.bme.mit.theta.analysis.algorithm.arg.ArgNodeComparators;
import hu.bme.mit.theta.analysis.algorithm.SafetyChecker;
import hu.bme.mit.theta.analysis.algorithm.cegar.Abstractor;
import hu.bme.mit.theta.analysis.algorithm.cegar.BasicAbstractor;
import hu.bme.mit.theta.analysis.algorithm.cegar.CegarChecker;
import hu.bme.mit.theta.analysis.algorithm.cegar.Refiner;
import hu.bme.mit.theta.analysis.algorithm.cegar.abstractor.StopCriterion;
import hu.bme.mit.theta.analysis.algorithm.cegar.abstractor.StopCriterions;
import hu.bme.mit.theta.analysis.expl.*;
import hu.bme.mit.theta.analysis.expr.ExprState;
import hu.bme.mit.theta.analysis.expr.ExprStatePredicate;
import hu.bme.mit.theta.analysis.expr.StmtAction;
import hu.bme.mit.theta.analysis.expr.refinement.*;
import hu.bme.mit.theta.analysis.multi.MultiAnalysisSide;
import hu.bme.mit.theta.analysis.pred.*;
import hu.bme.mit.theta.analysis.pred.PredAbstractors.PredAbstractor;
import hu.bme.mit.theta.analysis.prod2.Prod2Analysis;
import hu.bme.mit.theta.analysis.prod2.Prod2Prec;
import hu.bme.mit.theta.analysis.prod2.Prod2State;
import hu.bme.mit.theta.analysis.prod2.prod2explpred.*;
import hu.bme.mit.theta.analysis.stmtoptimizer.DefaultStmtOptimizer;
import hu.bme.mit.theta.analysis.stmtoptimizer.StmtOptimizer;
import hu.bme.mit.theta.analysis.unit.UnitPrec;
import hu.bme.mit.theta.analysis.unit.UnitState;
import hu.bme.mit.theta.analysis.waitlist.PriorityWaitlist;
import hu.bme.mit.theta.common.logging.Logger;
import hu.bme.mit.theta.common.logging.NullLogger;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.booltype.BoolType;
import hu.bme.mit.theta.solver.ItpSolver;
import hu.bme.mit.theta.solver.Solver;
import hu.bme.mit.theta.solver.SolverFactory;
import hu.bme.mit.theta.xsts.XSTS;
import hu.bme.mit.theta.xsts.analysis.*;
import hu.bme.mit.theta.xsts.analysis.autoexpl.XstsAutoExpl;
import hu.bme.mit.theta.xsts.analysis.autoexpl.XstsNewAtomsAutoExpl;
import hu.bme.mit.theta.xsts.analysis.autoexpl.XstsNewOperandsAutoExpl;
import hu.bme.mit.theta.xsts.analysis.autoexpl.XstsStaticAutoExpl;
import hu.bme.mit.theta.xsts.analysis.initprec.*;
import hu.bme.mit.theta.xsts.analysis.util.XstsCombineExtractUtilsKt;
import hu.bme.mit.theta.xsts.analysis.util.XstsControlInitFuncKt;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;

import static com.google.common.base.Preconditions.checkState;
import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not;

public class XstsConfigBuilder {


    //////////// algorithm selection ////////////

    public enum Algorithm {
        CEGAR,
        CHC,
        BMC,
        KINDUCTION,
        IMC,
        MDD
    }

    //////////// symbolic MDD analysis configuration ////////////

    public enum IterationStrategy {
        BFS, SAT, GSAT
    }

    //////////// CEGAR configuration ////////////

    public enum Domain {
        EXPL(null),
        PRED_BOOL(PredAbstractors::booleanAbstractor),
        PRED_CART(PredAbstractors::cartesianAbstractor),
        PRED_SPLIT(PredAbstractors::booleanSplitAbstractor),
        EXPL_PRED_BOOL(PredAbstractors::booleanAbstractor),
        EXPL_PRED_CART(PredAbstractors::cartesianAbstractor),
        EXPL_PRED_SPLIT(PredAbstractors::booleanSplitAbstractor),
        EXPL_PRED_COMBINED(null);

        public final Function predAbstractorFunction;

        Domain(final Function predAbstractorFunction) {
            this.predAbstractorFunction = predAbstractorFunction;
        }
    }

    public enum Refinement {
        FW_BIN_ITP {
            @Override
            public ExprTraceChecker getItpExprTraceChecker(Expr init, Expr target, ItpSolver solver) {
                return ExprTraceFwBinItpChecker.create(init, target, solver);
            }
        }, BW_BIN_ITP {
            @Override
            public ExprTraceChecker getItpExprTraceChecker(Expr init, Expr target, ItpSolver solver) {
                return ExprTraceBwBinItpChecker.create(init, target, solver);
            }
        }, SEQ_ITP {
            @Override
            public ExprTraceChecker getItpExprTraceChecker(Expr init, Expr target, ItpSolver solver) {
                return ExprTraceSeqItpChecker.create(init, target, solver);
            }
        }, UNSAT_CORE,
        MULTI_SEQ {
            @Override
            public  StopCriterion getStopCriterion() {
                return StopCriterions.fullExploration();
            }

            @Override
            public ExprTraceChecker getItpExprTraceChecker(Expr init, Expr target, ItpSolver solver) {
                return ExprTraceSeqItpChecker.create(init, target, solver);
            }

            @Override
            public  Refiner, XstsAction, P>
            createRefiner(
                    ExprTraceChecker traceChecker,
                    RefutationToPrec refToPrec,
                    PruneStrategy pruneStrategy,
                    Logger logger
            ) {
                return MultiExprTraceRefiner.create(traceChecker, JoiningPrecRefiner.create(refToPrec), pruneStrategy, logger);
            }
        };

        public  StopCriterion getStopCriterion() {
            return StopCriterions.firstCex();
        }

        public ExprTraceChecker getItpExprTraceChecker(
                final Expr init,
                final Expr target,
                final ItpSolver solver
        ) {
            throw new UnsupportedOperationException(String.format("%s domain can't provide trace checker of ItpRefutation", this.getClass().getSimpleName()));
        }

        public  Refiner, XstsAction, P>
        createRefiner(
                ExprTraceChecker traceChecker,
                RefutationToPrec refToPrec,
                PruneStrategy pruneStrategy,
                Logger logger
        ) {
            return SingleExprTraceRefiner.create(traceChecker, JoiningPrecRefiner.create(refToPrec), pruneStrategy, logger);
        }

    }

    public enum Search {
        BFS(ArgNodeComparators.combine(ArgNodeComparators.targetFirst(), ArgNodeComparators.bfs())),

        DFS(ArgNodeComparators.combine(ArgNodeComparators.targetFirst(), ArgNodeComparators.dfs()));

        public final ArgNodeComparators.ArgNodeComparator comparator;

        Search(final ArgNodeComparators.ArgNodeComparator comparator) {
            this.comparator = comparator;
        }

    }

    public enum PredSplit {
        WHOLE(ExprSplitters.whole()),

        CONJUNCTS(ExprSplitters.conjuncts()),

        ATOMS(ExprSplitters.atoms());

        public final ExprSplitters.ExprSplitter splitter;

        PredSplit(final ExprSplitters.ExprSplitter splitter) {
            this.splitter = splitter;
        }
    }

    public enum InitPrec {
        EMPTY(new XstsEmptyInitPrec()),

        PROP(new XstsPropInitPrec()),

        CTRL(new XstsCtrlInitPrec()),

        ALLVARS(new XstsAllVarsInitPrec());

        public final XstsInitPrec builder;

        InitPrec(final XstsInitPrec builder) {
            this.builder = builder;
        }

    }

    public enum AutoExpl {
        STATIC(new XstsStaticAutoExpl()),

        NEWATOMS(new XstsNewAtomsAutoExpl()),

        NEWOPERANDS(new XstsNewOperandsAutoExpl());

        public final XstsAutoExpl builder;

        AutoExpl(final XstsAutoExpl builder) {
            this.builder = builder;
        }
    }

    public enum OptimizeStmts {
        ON, OFF
    }

    private Logger logger = NullLogger.getInstance();
    private final SolverFactory abstractionSolverFactory;
    private final SolverFactory refinementSolverFactory;
    private final Domain domain;
    private final Refinement refinement;
    private Search search = Search.BFS;
    private PredSplit predSplit = PredSplit.WHOLE;
    private int maxEnum = 0;
    private InitPrec initPrec = InitPrec.EMPTY;
    private PruneStrategy pruneStrategy = PruneStrategy.LAZY;
    private OptimizeStmts optimizeStmts = OptimizeStmts.ON;
    private AutoExpl autoExpl = AutoExpl.NEWOPERANDS;

    public XstsConfigBuilder(final Domain domain, final Refinement refinement,
                             final SolverFactory abstractionSolverFactory, final SolverFactory refinementSolverFactory) {
        this.domain = domain;
        this.refinement = refinement;
        this.abstractionSolverFactory = abstractionSolverFactory;
        this.refinementSolverFactory = refinementSolverFactory;
    }

    public XstsConfigBuilder logger(final Logger logger) {
        this.logger = logger;
        return this;
    }

    public XstsConfigBuilder search(final Search search) {
        this.search = search;
        return this;
    }

    public XstsConfigBuilder predSplit(final PredSplit predSplit) {
        this.predSplit = predSplit;
        return this;
    }

    public XstsConfigBuilder maxEnum(final int maxEnum) {
        this.maxEnum = maxEnum;
        return this;
    }

    public XstsConfigBuilder initPrec(final InitPrec initPrec) {
        this.initPrec = initPrec;
        return this;
    }

    public XstsConfigBuilder pruneStrategy(final PruneStrategy pruneStrategy) {
        this.pruneStrategy = pruneStrategy;
        return this;
    }

    public XstsConfigBuilder optimizeStmts(final OptimizeStmts optimizeStmts) {
        this.optimizeStmts = optimizeStmts;
        return this;
    }

    public XstsConfigBuilder autoExpl(final AutoExpl autoExpl) {
        this.autoExpl = autoExpl;
        return this;
    }

    public XstsConfig build(final XSTS xsts) {
        if (domain == Domain.EXPL) {
            return (new ExplStrategy(xsts)).buildConfig();
        }
        if (domain == Domain.PRED_BOOL || domain == Domain.PRED_CART
                || domain == Domain.PRED_SPLIT) {
            return (new PredStrategy(xsts)).buildConfig();
        }
        if (domain == Domain.EXPL_PRED_BOOL || domain == Domain.EXPL_PRED_CART
                || domain == Domain.EXPL_PRED_SPLIT || domain == Domain.EXPL_PRED_COMBINED) {
            return (new ProdStrategy(xsts)).buildConfig();
        }
        throw new UnsupportedOperationException(domain + " domain is not supported.");
    }

    public abstract class BuilderStrategy {

        protected static final String UNSUPPORTED_CONFIG_VALUE = "Builder strategy %s does not support configuration value %s as %s";
        protected final XSTS xsts;
        protected final Solver abstractionSolver;
        protected final Expr negProp;

        @SuppressWarnings("java:S1699")
        protected BuilderStrategy(XSTS xsts) {
            checkState(getSupportedDomains().contains(domain), UNSUPPORTED_CONFIG_VALUE, getClass().getSimpleName(), domain, "domain");
            checkState(getSupportedRefinements().contains(refinement), UNSUPPORTED_CONFIG_VALUE, getClass().getSimpleName(), refinement, "refinement");
            this.xsts = xsts;
            abstractionSolver = abstractionSolverFactory.createSolver();
            negProp = Not(xsts.getProp());
        }

        abstract Set getSupportedDomains();

        abstract Set getSupportedRefinements();

        abstract StmtOptimizer getLtsOptimizer();

        StmtOptimizer optimizer() {
            if (optimizeStmts == OptimizeStmts.OFF) {
                return DefaultStmtOptimizer.create();
            }
            return getLtsOptimizer();
        }

        public LTS, XstsAction> getLts() {
            return XstsLts.create(xsts, XstsStmtOptimizer.create(optimizer()));
        }

        public abstract Predicate> getPredicate();

        public abstract Analysis getDataAnalysis();

        public XstsAnalysis getAnalysis() {
            return XstsAnalysis.create(getDataAnalysis());
        }

        public abstract RefutationToPrec getItpRefToPrec();

        public Refiner, XstsAction, P> getRefiner() {
            return refinement.createRefiner(
                    refinement.getItpExprTraceChecker(
                            xsts.getInitFormula(),
                            negProp,
                            refinementSolverFactory.createItpSolver()),
                    getItpRefToPrec(),
                    pruneStrategy,
                    logger);
        }

        public abstract P getInitPrec();

        XstsConfig, XstsAction, P> buildConfig() {
            final LTS, XstsAction> lts = getLts();
            final Predicate> target = getPredicate();
            final Analysis, XstsAction, P> analysis = getAnalysis();
            final ArgBuilder, XstsAction, P> argBuilder = ArgBuilder.create(
                    lts, analysis, target,
                    true);
            final Abstractor, XstsAction, P> abstractor = BasicAbstractor.builder(
                            argBuilder)
                    .waitlist(PriorityWaitlist.create(search.comparator))
                    .stopCriterion(refinement.getStopCriterion())
                    .logger(logger).build();
            final Refiner, XstsAction, P> refiner = getRefiner();
            final SafetyChecker, XstsAction>, Trace, XstsAction>, P> checker = CegarChecker.create(
                    abstractor, refiner,
                    logger);
            return XstsConfig.create(checker, getInitPrec());
        }

        public MultiAnalysisSide, S, XstsState, XstsAction, P, UnitPrec> getMultiSide() {
            return new MultiAnalysisSide<>(
                    getAnalysis(),
                    XstsControlInitFuncKt.xstsControlInitFunc(),
                    XstsCombineExtractUtilsKt::xstsCombineStates,
                    XstsCombineExtractUtilsKt::xstsExtractControlState,
                    XstsCombineExtractUtilsKt::xstsExtractDataState,
                    XstsCombineExtractUtilsKt::xstsExtractControlPrec);
        }

    }

    public class ExplStrategy extends BuilderStrategy {

        @Override
        Set getSupportedDomains() {
            return new HashSet<>(List.of(Domain.EXPL));
        }

        @Override
        Set getSupportedRefinements() {
            return new HashSet<>(List.of(Refinement.values()));
        }

        public ExplStrategy(XSTS xsts) {
            super(xsts);
            checkState(domain == Domain.EXPL,
                    UNSUPPORTED_CONFIG_VALUE, this.getClass().getSimpleName(), domain, "domain");
        }

        @Override
        public StmtOptimizer getLtsOptimizer() {
            return ExplStmtOptimizer.getInstance();
        }

        @Override
        public Predicate> getPredicate() {
            return new XstsStatePredicate<>(new ExplStatePredicate(negProp, abstractionSolver));
        }

        @Override
        public Analysis getDataAnalysis() {
            return ExplStmtAnalysis.create(abstractionSolver, xsts.getInitFormula(), maxEnum);
        }

        @Override
        public RefutationToPrec getItpRefToPrec() {
            return new ItpRefToExplPrec();
        }

        @Override
        public Refiner, XstsAction, ExplPrec> getRefiner() {
            if (refinement == Refinement.UNSAT_CORE) {
                return SingleExprTraceRefiner.create(
                        ExprTraceUnsatCoreChecker.create(xsts.getInitFormula(), negProp,
                                refinementSolverFactory.createUCSolver()),
                        JoiningPrecRefiner.create(new VarsRefToExplPrec()), pruneStrategy, logger);
            }
            return super.getRefiner();
        }

        @Override
        public ExplPrec getInitPrec() {
            return initPrec.builder.createExpl(xsts);
        }

    }

    public class PredStrategy extends BuilderStrategy {
        @Override
        Set getSupportedDomains() {
            return new HashSet<>(List.of(Domain.PRED_CART, Domain.PRED_BOOL, Domain.PRED_SPLIT));
        }

        @Override
        Set getSupportedRefinements() {
            return new HashSet<>(List.of(Refinement.FW_BIN_ITP, Refinement.BW_BIN_ITP, Refinement.SEQ_ITP, Refinement.MULTI_SEQ));
        }

        public PredStrategy(XSTS xsts) {
            super(xsts);
            checkState(domain == Domain.PRED_BOOL || domain == Domain.PRED_SPLIT || domain == Domain.PRED_CART,
                    UNSUPPORTED_CONFIG_VALUE, this.getClass().getSimpleName(), domain, "domain");
        }

        @Override
        StmtOptimizer getLtsOptimizer() {
            return PredStmtOptimizer.getInstance();
        }

        @Override
        public Predicate> getPredicate() {
            return new XstsStatePredicate<>(new ExprStatePredicate(negProp, abstractionSolver));
        }

        @Override
        public Analysis getDataAnalysis() {
            return PredAnalysis.create(
                    abstractionSolver,
                    domain.predAbstractorFunction.apply(abstractionSolver),
                    xsts.getInitFormula());
        }

        @Override
        public RefutationToPrec getItpRefToPrec() {
            return new ItpRefToPredPrec(predSplit.splitter);
        }

        @Override
        public PredPrec getInitPrec() {
            return initPrec.builder.createPred(xsts);
        }
    }

    public class ProdStrategy extends BuilderStrategy, Prod2Prec> {

        @Override
        Set getSupportedDomains() {
            return new HashSet<>(List.of(Domain.EXPL_PRED_BOOL, Domain.EXPL_PRED_CART, Domain.EXPL_PRED_SPLIT, Domain.EXPL_PRED_COMBINED));
        }

        @Override
        Set getSupportedRefinements() {
            return new HashSet<>(List.of(Refinement.FW_BIN_ITP, Refinement.BW_BIN_ITP, Refinement.SEQ_ITP, Refinement.MULTI_SEQ));
        }

        public ProdStrategy(XSTS xsts) {
            super(xsts);
            checkState(domain == Domain.EXPL_PRED_BOOL || domain == Domain.EXPL_PRED_SPLIT
                            || domain == Domain.EXPL_PRED_CART || domain == Domain.EXPL_PRED_COMBINED,
                    UNSUPPORTED_CONFIG_VALUE, this.getClass().getSimpleName(), domain, "domain");
            checkState(refinement != Refinement.UNSAT_CORE, UNSUPPORTED_CONFIG_VALUE, getClass().getSimpleName(), refinement, "refinement");
        }

        @Override
        StmtOptimizer> getLtsOptimizer() {
            return Prod2ExplPredStmtOptimizer.create(
                    ExplStmtOptimizer.getInstance()
            );
        }

        @Override
        public Predicate>> getPredicate() {
            return new XstsStatePredicate<>(
                    new ExprStatePredicate(negProp, abstractionSolver));
        }

        @Override
        public Analysis, StmtAction, Prod2Prec> getDataAnalysis() {
            if (domain == Domain.EXPL_PRED_BOOL || domain == Domain.EXPL_PRED_CART
                    || domain == Domain.EXPL_PRED_SPLIT) {
                final PredAbstractors.PredAbstractor predAbstractor = domain.predAbstractorFunction.apply(abstractionSolver);
                return Prod2Analysis.create(
                        ExplStmtAnalysis.create(abstractionSolver, xsts.getInitFormula(), maxEnum),
                        PredAnalysis.create(abstractionSolver, predAbstractor, xsts.getInitFormula()),
                        Prod2ExplPredPreStrengtheningOperator.create(),
                        Prod2ExplPredStrengtheningOperator.create(abstractionSolver));
            } else {
                final Prod2ExplPredAbstractors.Prod2ExplPredAbstractor prodAbstractor = Prod2ExplPredAbstractors.booleanAbstractor(
                        abstractionSolver);
                return Prod2ExplPredAnalysis.create(
                        ExplAnalysis.create(abstractionSolver, xsts.getInitFormula()),
                        PredAnalysis.create(abstractionSolver,
                                PredAbstractors.booleanAbstractor(abstractionSolver),
                                xsts.getInitFormula()),
                        Prod2ExplPredStrengtheningOperator.create(abstractionSolver),
                        prodAbstractor);
            }
        }

        @Override
        public RefutationToPrec, ItpRefutation> getItpRefToPrec() {
            return AutomaticItpRefToProd2ExplPredPrec.create(
                    autoExpl.builder.create(xsts), predSplit.splitter);
        }

        @Override
        public Prod2Prec getInitPrec() {
            return initPrec.builder.createProd2ExplPred(xsts);
        }

    }

}