org.sosy_lab.cpachecker.util.precondition.segkro.RefineSolverBasedItp.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.util.precondition.segkro.RefineSolverBasedItp.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.util.precondition.segkro;

import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.sosy_lab.common.Pair;
import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cfa.CFA;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFAEdgeType;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.core.AnalysisDirection;
import org.sosy_lab.cpachecker.core.algorithm.precondition.PreconditionHelper;
import org.sosy_lab.cpachecker.cpa.arg.ARGPath;
import org.sosy_lab.cpachecker.cpa.arg.ARGPath.PathIterator;
import org.sosy_lab.cpachecker.cpa.arg.ARGPath.PathPosition;
import org.sosy_lab.cpachecker.cpa.predicate.PredicatePrecision;
import org.sosy_lab.cpachecker.exceptions.CPATransferException;
import org.sosy_lab.solver.SolverException;
import org.sosy_lab.cpachecker.util.precondition.segkro.interfaces.InterpolationWithCandidates;
import org.sosy_lab.cpachecker.util.precondition.segkro.interfaces.PreconditionRefiner;
import org.sosy_lab.cpachecker.util.predicates.AbstractionManager;
import org.sosy_lab.cpachecker.util.predicates.AbstractionPredicate;
import org.sosy_lab.cpachecker.util.predicates.Solver;
import org.sosy_lab.solver.api.BooleanFormula;
import org.sosy_lab.cpachecker.util.predicates.interfaces.PathFormulaManager;
import org.sosy_lab.cpachecker.util.predicates.interfaces.view.BooleanFormulaManagerView;
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.predicates.pathformula.PathFormulaManagerImpl;
import org.sosy_lab.cpachecker.util.predicates.pathformula.SSAMap;
import org.sosy_lab.cpachecker.util.predicates.pathformula.pointeraliasing.PointerTargetSet;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;

public class RefineSolverBasedItp implements PreconditionRefiner {

    private static enum FormulaMode {
        INSTANTIATED, UNINSTANTIATED
    }

    private final InterpolationWithCandidates ipc;
    private final BooleanFormulaManagerView bmgr;
    private final PathFormulaManager pmgrFwd;
    private final PreconditionHelper helper;
    private final FormulaManagerView mgrv;
    private final AbstractionManager amgr;
    private final ExtractNewPreds enp;

    public RefineSolverBasedItp(Configuration pConfig, LogManager pLogger, ShutdownNotifier pShutdownNotifier,
            CFA pCfa, Solver pSolver, AbstractionManager pAmgr, ExtractNewPreds pExtractNewPreds,
            InterpolationWithCandidates pMinCorePrio) throws InvalidConfigurationException {

        amgr = pAmgr;
        enp = pExtractNewPreds;
        ipc = pMinCorePrio;
        mgrv = pSolver.getFormulaManager();
        bmgr = mgrv.getBooleanFormulaManager();
        pmgrFwd = new PathFormulaManagerImpl(mgrv, pConfig, pLogger, pShutdownNotifier, pCfa,
                AnalysisDirection.FORWARD);
        helper = new PreconditionHelper(mgrv, pConfig, pLogger, pShutdownNotifier, pCfa);
    }

    private Set<BooleanFormula> uninstantiatedLiterals(BooleanFormula pF) {
        return mgrv.uninstantiate(mgrv.extractLiterals(pF));
    }

    @VisibleForTesting
    BooleanFormula interpolate(final BooleanFormula pPreconditionA, final BooleanFormula pPreconditionB,
            final PathPosition pItpPosition) throws SolverException, InterruptedException {

        List<BooleanFormula> p = enp.extractNewPreds(pPreconditionA);
        BooleanFormula f = (p.size() == 0) ? pPreconditionA : bmgr.and(pPreconditionA, bmgr.and(p));

        return ipc.getInterpolant(f, pPreconditionB, p, null);
    }

    private PathFormula pre(final PathPosition pPreForPosition, final FormulaMode pMode)
            throws CPATransferException, SolverException, InterruptedException {

        final ARGPath pathToPosition = pPreForPosition.getPath();
        final PathFormula pf = helper.computePathformulaForArbitraryTrace(pathToPosition, pPreForPosition);
        final BooleanFormula f = mgrv.eliminateDeadVariables(pf.getFormula(), pf.getSsa());

        if (pMode == FormulaMode.UNINSTANTIATED) {
            return alterPf(pmgrFwd.makeEmptyPathFormula(), mgrv.uninstantiate(f));
        } else {
            return alterPf(pf, f);
        }
    }

    @VisibleForTesting
    static class ReversedEdge {

        private CFAEdge original;

        public ReversedEdge(CFAEdge pOriginal) {
            Preconditions.checkNotNull(pOriginal);
            this.original = pOriginal;
        }

        public CFAEdge getOriginal() {
            return original;
        }

        public CFAEdgeType getEdgeType() {
            return original.getEdgeType();
        }

        public CFANode getPredecessor() {
            return original.getSuccessor();
        }

        public CFANode getSuccessor() {
            return original.getPredecessor();
        }

        @Override
        public String toString() {
            return getPredecessor() + " -{" + original.getDescription().replaceAll("\n", " ") + "}-> "
                    + getSuccessor();
        }
    }

    @VisibleForTesting
    List<ReversedEdge> getReversedTrace(ARGPath pTrace) {
        List<ReversedEdge> result = Lists.newArrayListWithCapacity(pTrace.asEdgesList().size());
        for (CFAEdge g : Lists.reverse(pTrace.asEdgesList())) {
            if (g != null) {
                result.add(new ReversedEdge(g));
            }
        }
        return result;
    }

    private Multimap<CFANode, BooleanFormula> predsFromTrace(final PathPosition pFinalWpPosition,
            final PathFormula pInstanciatedTracePrecond)
            throws SolverException, InterruptedException, CPATransferException {

        Preconditions.checkNotNull(pInstanciatedTracePrecond);
        Preconditions.checkNotNull(pFinalWpPosition);

        ImmutableMultimap.Builder<CFANode, BooleanFormula> result = ImmutableMultimap.builder();

        // TODO: It might be possible to use this code to also derive the predicate for the first sate.

        // Get additional predicates from the states along the trace
        //    (or the WPs along the trace)...

        PathFormula preAtK = pInstanciatedTracePrecond; // FIXME: The paper might be wrong here... or hard to understand... (we should start with the negation)

        PathIterator reverseIt = pFinalWpPosition.reverseIterator();

        while (reverseIt.hasNext()) {

            final CFAEdge t = reverseIt.getIncomingEdge();
            reverseIt.advance();
            final PathPosition nextPos = reverseIt.getPosition();

            if (t == null) {
                continue;
            }

            if (t.getEdgeType() != CFAEdgeType.BlankEdge) {

                //
                //           X                         X'
                //        varphi_k                 varphi_k+1
                //    ...--->o------------------------->o---...
                //         psi_E         t_k
                //

                // 1. Compute the two formulas (A/B) that are needed to compute a Craig interpolant
                //      afterTransCond === varphi_{k+1}

                // Formula A
                PathFormula preAtKp1 = pre(nextPos, FormulaMode.INSTANTIATED);

                if (bmgr.isTrue(preAtKp1.getFormula())) {
                    continue;
                }

                final List<BooleanFormula> predsNew = enp.extractNewPreds(preAtKp1.getFormula());
                if (predsNew.size() > 0) {
                    preAtKp1 = alterPf(preAtKp1, bmgr.and(preAtKp1.getFormula(), bmgr.and(predsNew)));
                }

                // Formula B
                final PathFormula transFromPreAtK = computeCounterCondition(t,
                        alterPf(preAtK, bmgr.not(preAtK.getFormula())));

                // Compute an interpolant; use a set of candidate predicates.
                //    The candidates for the interpolant are taken from Formula A (since that formula should get over-approximated)

                final SSAMap instantiateWith = transFromPreAtK.getSsa();
                preAtK = alterPf(transFromPreAtK,
                        ipc.getInterpolant(mgrv.instantiate(preAtKp1.getFormula(), instantiateWith),
                                transFromPreAtK.getFormula(), mgrv.instantiate(predsNew, instantiateWith),
                                t.getSuccessor()));

                result.putAll(t.getSuccessor(), uninstantiatedLiterals(preAtK.getFormula()));
            }
        }

        return result.build();
    }

    /**
     *
     * @param pTransition           The transition to encode
     * @param pCounterStatePrecond  An uninstanciated formula that describes a precondition
     * @return
     * @throws SolverException
     */
    private PathFormula computeCounterCondition(final CFAEdge pTransition, final PathFormula pCounterStatePrecond)
            throws CPATransferException, InterruptedException {

        return pmgrFwd.makeAnd(pCounterStatePrecond, pTransition);
    }

    private PathFormula alterPf(PathFormula pPf, BooleanFormula pF) {
        return new PathFormula(pF, pPf.getSsa(), PointerTargetSet.emptyPointerTargetSet(), 1);
    }

    @Override
    public PredicatePrecision refine(final PathPosition pTraceFromViolation,
            final PathPosition pTraceFromValidTermination)
            throws SolverException, InterruptedException, CPATransferException {

        // Compute the precondition for both traces
        PathFormula pcViolation = pre(pTraceFromViolation, FormulaMode.INSTANTIATED);
        PathFormula pcValid = pre(pTraceFromValidTermination, FormulaMode.INSTANTIATED);

        // "Enrich" the preconditions with more general predicates
        // TODO: Is this part completely useless when using QE?
        pcViolation = alterPf(pcViolation,
                interpolate(pcViolation.getFormula(), pcValid.getFormula(), pTraceFromViolation));
        pcValid = alterPf(pcValid,
                interpolate(pcValid.getFormula(), pcViolation.getFormula(), pTraceFromValidTermination));

        // Now we have an initial set of useful predicates; add them to the corresponding list.
        Builder<BooleanFormula> globalPreds = ImmutableList.builder();
        ImmutableMultimap.Builder<CFANode, BooleanFormula> localPreds = ImmutableMultimap.builder();

        globalPreds.addAll(uninstantiatedLiterals(pcViolation.getFormula()));
        globalPreds.addAll(uninstantiatedLiterals(pcValid.getFormula()));

        // Get additional predicates from the states along the trace
        //    (or the WPs along the trace)...
        //
        // -- along the trace to the violating state...
        Multimap<CFANode, BooleanFormula> predsViolation = predsFromTrace(pTraceFromViolation, pcViolation);
        localPreds.putAll(predsViolation);
        // -- along the trace to the termination state...
        Multimap<CFANode, BooleanFormula> predsFromValid = predsFromTrace(pTraceFromValidTermination, pcValid);
        localPreds.putAll(predsFromValid);

        return predicatesAsGlobalPrecision(globalPreds.build(), localPreds.build());
    }

    private PredicatePrecision predicatesAsGlobalPrecision(final ImmutableList<BooleanFormula> pGlobalPreds,
            final ImmutableMultimap<CFANode, BooleanFormula> pLocalPreds) {

        Multimap<Pair<CFANode, Integer>, AbstractionPredicate> locationInstancePredicates = HashMultimap.create();
        Multimap<CFANode, AbstractionPredicate> localPredicates = HashMultimap.create();
        Multimap<String, AbstractionPredicate> functionPredicates = HashMultimap.create();
        Collection<AbstractionPredicate> globalPredicates = Lists.newArrayList();

        // TODO: Make the local predicates really local!!
        for (BooleanFormula f : pLocalPreds.values()) {
            AbstractionPredicate ap = amgr.makePredicate(f);
            globalPredicates.add(ap);
        }

        for (BooleanFormula f : pGlobalPreds) {
            AbstractionPredicate ap = amgr.makePredicate(f);
            globalPredicates.add(ap);
        }

        return new PredicatePrecision(locationInstancePredicates, localPredicates, functionPredicates,
                globalPredicates);
    }

}