org.sosy_lab.cpachecker.util.predicates.interpolation.strategy.NestedInterpolation.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.util.predicates.interpolation.strategy.NestedInterpolation.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.predicates.interpolation.strategy;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.common.Triple;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.cfa.model.FunctionEntryNode;
import org.sosy_lab.cpachecker.cfa.model.FunctionExitNode;
import org.sosy_lab.cpachecker.core.interfaces.AbstractState;
import org.sosy_lab.solver.SolverException;
import org.sosy_lab.cpachecker.util.AbstractStates;
import org.sosy_lab.solver.api.BooleanFormula;
import org.sosy_lab.solver.api.BooleanFormulaManager;
import org.sosy_lab.solver.api.InterpolatingProverEnvironment;
import org.sosy_lab.cpachecker.util.predicates.interfaces.view.FormulaManagerView;
import org.sosy_lab.cpachecker.util.predicates.interpolation.InterpolationManager;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

public class NestedInterpolation<T> extends AbstractTreeInterpolation<T> {

    /**
     * This strategy returns a sequence of interpolants.
     * It uses the callstack and previous interpolants to compute the interpolants
     * (see 'Nested Interpolants' from Heizmann, Hoenicke, and Podelski).
     * The resulting interpolants are based on a tree-like scheme.
     */
    public NestedInterpolation(LogManager pLogger, ShutdownNotifier pShutdownNotifier, FormulaManagerView pFmgr,
            BooleanFormulaManager pBfmgr) {
        super(pLogger, pShutdownNotifier, pFmgr, pBfmgr);
    }

    @Override
    public List<BooleanFormula> getInterpolants(final InterpolationManager.Interpolator<T> interpolator,
            final List<Triple<BooleanFormula, AbstractState, T>> formulasWithStatesAndGroupdIds)
            throws InterruptedException, SolverException {
        List<BooleanFormula> interpolants = Lists
                .newArrayListWithExpectedSize(formulasWithStatesAndGroupdIds.size() - 1);
        BooleanFormula lastItp = bfmgr.makeBoolean(true); // PSI_0 = True
        final Deque<Triple<BooleanFormula, BooleanFormula, CFANode>> callstack = new ArrayDeque<>();
        for (int positionOfA = 0; positionOfA < formulasWithStatesAndGroupdIds.size() - 1; positionOfA++) {
            // use a new prover, because we use several distinct queries
            lastItp = getNestedInterpolant(formulasWithStatesAndGroupdIds, interpolants, callstack, interpolator,
                    positionOfA, lastItp);
        }
        return interpolants;
    }

    /** This function implements the paper "Nested Interpolants" with a small modification:
     * instead of a return-edge, we use dummy-edges with simple pathformula "true".
     * Actually the implementation does not use "true", but omits it completely and
     * returns the conjunction of the two interpolants (before and after the (non-existing) dummy edge).
     * TODO simplify this algorithm, it is soo ugly! Maybe it is 'equal' with the normal tree-interpolation. */
    private BooleanFormula getNestedInterpolant(
            final List<Triple<BooleanFormula, AbstractState, T>> formulasWithStatesAndGroupdIds,
            final List<BooleanFormula> interpolants,
            final Deque<Triple<BooleanFormula, BooleanFormula, CFANode>> callstack,
            final InterpolationManager.Interpolator<T> interpolator, int positionOfA, BooleanFormula lastItp)
            throws InterruptedException, SolverException {

        // use a new prover, because we use several distinct queries
        try (final InterpolatingProverEnvironment<T> itpProver = interpolator.newEnvironment()) {

            final List<T> A = new ArrayList<>();
            final List<T> B = new ArrayList<>();

            // If we have entered or exited a function, update the stack of entry points
            final AbstractState abstractionState = checkNotNull(
                    formulasWithStatesAndGroupdIds.get(positionOfA).getSecond());
            final CFANode node = AbstractStates.extractLocation(abstractionState);

            if (node instanceof FunctionEntryNode && callHasReturn(formulasWithStatesAndGroupdIds, positionOfA)) {
                // && (positionOfA > 0)) {
                // case 2 from paper
                final BooleanFormula call = formulasWithStatesAndGroupdIds.get(positionOfA).getFirst();
                callstack.addLast(Triple.of(lastItp, call, node));
                final BooleanFormula itp = bfmgr.makeBoolean(true);
                interpolants.add(itp);
                return itp; // PSIminus = True --> PSI = True, for the 3rd rule ITP is True
            }

            A.add(itpProver.push(lastItp));
            A.add(itpProver.push(formulasWithStatesAndGroupdIds.get(positionOfA).getFirst()));

            // add all remaining PHI_j
            for (Triple<BooleanFormula, AbstractState, T> t : Iterables.skip(formulasWithStatesAndGroupdIds,
                    positionOfA + 1)) {
                B.add(itpProver.push(t.getFirst()));
            }

            // add all previous function calls
            for (Triple<BooleanFormula, BooleanFormula, CFANode> t : callstack) {
                B.add(itpProver.push(t.getFirst())); // add PSI_k
                B.add(itpProver.push(t.getSecond())); // ... and PHI_k
            }

            // update prover with new formulas.
            // this is the expensive step, that is distinct from other strategies.
            // TODO improve! example: reverse ordering of formulas for re-usage of the solver-stack
            boolean unsat = itpProver.isUnsat();
            assert unsat : "formulas were unsat before, they have to be unsat now.";

            // get interpolant of A and B, for B we use the complementary set of A
            final BooleanFormula itp = itpProver.getInterpolant(A);

            if (!callstack.isEmpty() && node instanceof FunctionExitNode) {
                // case 4, we are returning from a function, rule 4
                Triple<BooleanFormula, BooleanFormula, CFANode> scopingItp = callstack.removeLast();

                final InterpolatingProverEnvironment<T> itpProver2 = interpolator.newEnvironment();
                final List<T> A2 = new ArrayList<>();
                final List<T> B2 = new ArrayList<>();

                A2.add(itpProver2.push(itp));
                //A2.add(itpProver2.push(orderedFormulas.get(positionOfA).getFirst()));

                A2.add(itpProver2.push(scopingItp.getFirst()));
                A2.add(itpProver2.push(scopingItp.getSecond()));

                // add all remaining PHI_j
                for (Triple<BooleanFormula, AbstractState, T> t : Iterables.skip(formulasWithStatesAndGroupdIds,
                        positionOfA + 1)) {
                    B2.add(itpProver2.push(t.getFirst()));
                }

                // add all previous function calls
                for (Triple<BooleanFormula, BooleanFormula, CFANode> t : callstack) {
                    B2.add(itpProver2.push(t.getFirst())); // add PSI_k
                    B2.add(itpProver2.push(t.getSecond())); // ... and PHI_k
                }

                boolean unsat2 = itpProver2.isUnsat();
                assert unsat2 : "formulas2 were unsat before, they have to be unsat now.";

                // get interpolant of A and B, for B we use the complementary set of A
                BooleanFormula itp2 = itpProver2.getInterpolant(A2);
                itpProver2.close();

                BooleanFormula rebuildItp = rebuildInterpolant(itp, itp2);
                if (!bfmgr.isTrue(scopingItp.getFirst())) {
                    rebuildItp = bfmgr.and(rebuildItp, scopingItp.getFirst());
                }

                interpolants.add(rebuildItp);
                return itp2;

            } else {
                interpolants.add(itp);
                return itp;
            }
        }
    }
}