org.sosy_lab.cpachecker.cpa.predicate.PredicateBasedPrefixProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.cpa.predicate.PredicateBasedPrefixProvider.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  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.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package org.sosy_lab.cpachecker.cpa.predicate;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;

import org.sosy_lab.common.Pair;
import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.configuration.Option;
import org.sosy_lab.common.configuration.Options;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cfa.model.BlankEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdgeType;
import org.sosy_lab.cpachecker.cpa.arg.ARGPath;
import org.sosy_lab.cpachecker.cpa.arg.ARGPath.PathIterator;
import org.sosy_lab.cpachecker.cpa.arg.ARGState;
import org.sosy_lab.cpachecker.cpa.arg.MutableARGPath;
import org.sosy_lab.cpachecker.exceptions.CPAException;
import org.sosy_lab.cpachecker.exceptions.CPATransferException;
import org.sosy_lab.solver.SolverException;
import org.sosy_lab.cpachecker.util.predicates.Solver;
import org.sosy_lab.solver.api.BooleanFormula;
import org.sosy_lab.solver.api.InterpolatingProverEnvironmentWithAssumptions;
import org.sosy_lab.cpachecker.util.predicates.interfaces.PathFormulaManager;
import org.sosy_lab.cpachecker.util.predicates.interfaces.view.FormulaManagerView;
import org.sosy_lab.cpachecker.util.predicates.pathformula.PathFormula;
import org.sosy_lab.cpachecker.util.refinement.InfeasiblePrefix;
import org.sosy_lab.cpachecker.util.refinement.PrefixProvider;

import com.google.common.collect.Iterables;

@Options(prefix = "cpa.predicate.refinement")
public class PredicateBasedPrefixProvider implements PrefixProvider {
    @Option(secure = true, description = "Max. number of prefixes to extract")
    private int maxPrefixCount = 64;

    @Option(secure = true, description = "Max. length of feasible prefixes to extract from if at least one prefix was already extracted")
    private int maxPrefixLength = 1024;

    private final LogManager logger;

    private final Solver solver;

    private final PathFormulaManager pathFormulaManager;

    /**
     * This method acts as the constructor of the class.
     *
     * @param pSolver the solver to use
     */
    public PredicateBasedPrefixProvider(Configuration config, LogManager pLogger, Solver pSolver,
            PathFormulaManager pPathFormulaManager) {
        try {
            config.inject(this);
        } catch (InvalidConfigurationException e) {
            pLogger.log(Level.INFO,
                    "Invalid configuration given to " + getClass().getSimpleName() + ". Using defaults instead.");
        }

        logger = pLogger;
        solver = pSolver;
        pathFormulaManager = pPathFormulaManager;
    }

    /* (non-Javadoc)
     * @see org.sosy_lab.cpachecker.cpa.predicate.PrefixProvider#getInfeasiblePrefixes(org.sosy_lab.cpachecker.cpa.arg.ARGPath)
     */
    @Override
    public List<InfeasiblePrefix> extractInfeasiblePrefixes(final ARGPath path)
            throws CPAException, InterruptedException {
        List<InfeasiblePrefix> prefixes = new ArrayList<>();
        MutableARGPath feasiblePrefixPath = new MutableARGPath();
        List<Object> feasiblePrefixTerms = new ArrayList<>(path.size());

        try (@SuppressWarnings("unchecked")
        InterpolatingProverEnvironmentWithAssumptions<Object> prover = (InterpolatingProverEnvironmentWithAssumptions<Object>) solver
                .newProverEnvironmentWithInterpolation()) {

            PathFormula formula = pathFormulaManager.makeEmptyPathFormula();

            PathIterator iterator = path.pathIterator();
            while (iterator.hasNext()) {
                feasiblePrefixPath.addLast(Pair.of(iterator.getAbstractState(), iterator.getOutgoingEdge()));
                try {
                    formula = pathFormulaManager.makeAnd(pathFormulaManager.makeEmptyPathFormula(formula),
                            iterator.getOutgoingEdge());
                    Object term = prover.push(formula.getFormula());
                    feasiblePrefixTerms.add(term);

                    if (iterator.getOutgoingEdge().getEdgeType() == CFAEdgeType.AssumeEdge && prover.isUnsat()) {
                        logger.log(Level.FINE, "found infeasible prefix: ", iterator.getOutgoingEdge(),
                                " resulted in an unsat-formula");

                        List<BooleanFormula> interpolantSequence = extractInterpolantSequence(feasiblePrefixTerms,
                                prover);

                        // add infeasible prefix
                        InfeasiblePrefix infeasiblePrefix = buildInfeasiblePrefix(path, feasiblePrefixPath,
                                interpolantSequence, solver.getFormulaManager());
                        prefixes.add(infeasiblePrefix);

                        // remove failing operation
                        Pair<ARGState, CFAEdge> failingOperation = removeFailingOperation(feasiblePrefixPath,
                                feasiblePrefixTerms, prover);

                        // add noop-operation
                        formula = addNoopOperation(feasiblePrefixPath, feasiblePrefixTerms, prover, formula,
                                failingOperation);

                        if (prefixes.size() >= maxPrefixCount) {
                            break;
                        }
                    }
                }

                catch (SolverException | CPATransferException e) {
                    throw new CPAException("Error during computation of prefixes: " + e.getMessage(), e);
                }

                if (!prefixes.isEmpty() && feasiblePrefixPath.size() >= maxPrefixLength) {
                    break;
                }

                iterator.advance();
            }
        }

        return prefixes;
    }

    private <T> List<BooleanFormula> extractInterpolantSequence(List<T> feasiblePrefixFormulas,
            InterpolatingProverEnvironmentWithAssumptions<T> prover) throws SolverException {

        List<BooleanFormula> interpolantSequence = new ArrayList<>();

        for (int i = 1; i < feasiblePrefixFormulas.size(); i++) {
            interpolantSequence.add(prover.getInterpolant(feasiblePrefixFormulas.subList(0, i)));
        }

        return interpolantSequence;
    }

    private InfeasiblePrefix buildInfeasiblePrefix(final ARGPath path, MutableARGPath currentPrefix,
            List<BooleanFormula> interpolantSequence, FormulaManagerView fmgr) {
        MutableARGPath infeasiblePrefix = new MutableARGPath();
        infeasiblePrefix.addAll(currentPrefix);

        // for interpolation/refinement to work properly with existing code,
        // add another transition after the infeasible one, also add FALSE itp
        infeasiblePrefix.add(obtainSuccessorTransition(path, currentPrefix.size()));
        interpolantSequence.add(fmgr.getBooleanFormulaManager().makeBoolean(false));

        // additionally, add final (target) state, also to satisfy requirements of existing code
        infeasiblePrefix
                .add(Pair.of(Iterables.getLast(path.asStatesList()), Iterables.getLast(path.asEdgesList())));

        return InfeasiblePrefix.buildForPredicateDomain(infeasiblePrefix.immutableCopy(), interpolantSequence,
                fmgr);
    }

    /**
     * This method returns the pair of state and edge at the given offset.
     */
    private Pair<ARGState, CFAEdge> obtainSuccessorTransition(final ARGPath path, final int offset) {
        Pair<ARGState, CFAEdge> transition = path.obtainTransitionAt(offset);
        return Pair.<ARGState, CFAEdge>of(transition.getFirst(), BlankEdge
                .buildNoopEdge(transition.getSecond().getPredecessor(), transition.getSecond().getSuccessor()));
    }

    private <T> Pair<ARGState, CFAEdge> removeFailingOperation(MutableARGPath feasiblePrefixPath,
            List<T> feasiblePrefixTerms, InterpolatingProverEnvironmentWithAssumptions<T> prover) {
        Pair<ARGState, CFAEdge> failingOperation = feasiblePrefixPath.removeLast();

        // also remove formula, term for failing assume edge from stack, formula
        prover.pop();
        feasiblePrefixTerms.remove(feasiblePrefixTerms.size() - 1);
        return failingOperation;
    }

    private <T> PathFormula addNoopOperation(MutableARGPath feasiblePrefixPath, List<T> feasiblePrefixTerms,
            InterpolatingProverEnvironmentWithAssumptions<T> prover, PathFormula formula,
            Pair<ARGState, CFAEdge> failingOperation) throws CPATransferException, InterruptedException {
        CFAEdge noopEdge = BlankEdge.buildNoopEdge(failingOperation.getSecond().getPredecessor(),
                failingOperation.getSecond().getSuccessor());

        feasiblePrefixPath.add(Pair.<ARGState, CFAEdge>of(failingOperation.getFirst(), noopEdge));

        formula = pathFormulaManager.makeAnd(pathFormulaManager.makeEmptyPathFormula(formula), noopEdge);
        feasiblePrefixTerms.add(prover.push(formula.getFormula()));
        return formula;
    }
}