org.sosy_lab.cpachecker.util.precondition.segkro.rules.PatternBasedRule.java Source code

Java tutorial

Introduction

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.sosy_lab.solver.SolverException;
import org.sosy_lab.cpachecker.util.precondition.segkro.Cartesian;
import org.sosy_lab.cpachecker.util.precondition.segkro.interfaces.Premise;
import org.sosy_lab.cpachecker.util.predicates.Solver;
import org.sosy_lab.solver.api.BooleanFormula;
import org.sosy_lab.solver.api.Formula;
import org.sosy_lab.solver.api.NumeralFormula.IntegerFormula;
import org.sosy_lab.cpachecker.util.predicates.interfaces.view.ArrayFormulaManagerView;
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.interfaces.view.NumeralFormulaManagerView;
import org.sosy_lab.cpachecker.util.predicates.interfaces.view.QuantifiedFormulaManagerView;
import org.sosy_lab.cpachecker.util.predicates.matching.SmtAstMatchResult;
import org.sosy_lab.cpachecker.util.predicates.matching.SmtAstMatcher;
import org.sosy_lab.cpachecker.util.statistics.StatKind;
import org.sosy_lab.cpachecker.util.statistics.StatTimer;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;

public abstract class PatternBasedRule extends AbstractRule {

    protected final NumeralFormulaManagerView<IntegerFormula, IntegerFormula> ifm;
    protected final QuantifiedFormulaManagerView qfm;
    protected final ArrayFormulaManagerView afm;
    protected final BooleanFormulaManagerView bfm;
    protected final FormulaManagerView fmv;

    final StatTimer constraintCheckTimer = new StatTimer(StatKind.SUM, "Constraint checking");
    final StatTimer conclusionTimer = new StatTimer(StatKind.SUM, "Concluding");
    final StatTimer matchingTimer = new StatTimer(StatKind.SUM, "Matching");
    final StatTimer overallTimer = new StatTimer(StatKind.SUM, "Overall");
    final StatTimer conclusionValidationTimer = new StatTimer(StatKind.SUM, "Validation");

    public PatternBasedRule(Solver pSolver, SmtAstMatcher pMatcher) {
        super(pSolver, pMatcher);

        fmv = pSolver.getFormulaManager();
        bfm = fmv.getBooleanFormulaManager();
        ifm = fmv.getIntegerFormulaManager();
        qfm = fmv.getQuantifiedFormulaManager();
        afm = fmv.getArrayFormulaManager();

        setupPatterns();
    }

    protected abstract void setupPatterns();

    protected boolean satisfiesConstraints(Map<String, Formula> pAssignment)
            throws SolverException, InterruptedException {
        return true;
    }

    protected Collection<BooleanFormula> deriveConclusion(Map<String, Formula> pAssignment) {
        return Collections.emptyList();
    }

    @Override
    public Set<BooleanFormula> apply(BooleanFormula pInput) throws SolverException, InterruptedException {
        return apply(fmv.extractLiterals(pInput), HashMultimap.<String, Formula>create());
    }

    protected Formula substituteInParent(final Formula pParent, final Formula pToSubstitute,
            final Formula pSubstituteBy, final Formula pReplaceParentIn) {

        Map<Formula, Formula> transformation = Maps.newHashMap();
        transformation.put(pToSubstitute, pSubstituteBy);

        final Formula parentPrime = matcher.substitute(pParent, transformation);

        Map<Formula, Formula> transformation2 = Maps.newHashMap();
        transformation2.put(pParent, parentPrime);

        return matcher.substitute(pReplaceParentIn, transformation2);
    }

    @Override
    public Set<BooleanFormula> apply(final Collection<BooleanFormula> pConjunctiveInputPredicates,
            final Multimap<String, Formula> pMatchingBindings) throws SolverException, InterruptedException {

        HashSet<BooleanFormula> result = Sets.newHashSet();

        final int premiseCount = getPremises().size();
        Verify.verify(premiseCount != 0);

        final List<Collection<BooleanFormula>> dimensions = new ArrayList<>(premiseCount);
        for (int i = 0; i < premiseCount; i++) {
            dimensions.add(pConjunctiveInputPredicates);
        }

        for (List<BooleanFormula> tuple : Cartesian.product(dimensions)) {
            final Set<BooleanFormula> inferred = applyWithInputRelatingPremises(tuple, pMatchingBindings);
            result.addAll(inferred);
        }

        return result;
    }

    private Collection<Map<String, Formula>> getAllAssignments(Multimap<String, Formula> pFromBindings) {
        final Set<String> boundVariables = pFromBindings.keySet();
        final List<Collection<Formula>> dimensions = new ArrayList<>(boundVariables.size());
        for (String var : boundVariables) {
            dimensions.add(pFromBindings.get(var));
        }

        Collection<Map<String, Formula>> result = Lists.newArrayList();
        for (List<Formula> x : Cartesian.product(dimensions)) {
            final Map<String, Formula> tuple = Maps.newHashMap();
            final Iterator<Formula> xIt = x.iterator();
            for (String var : boundVariables) {
                Formula f = xIt.next();
                tuple.put(var, f);
            }
            result.add(tuple);
        }

        return result;
    }

    @Override
    public Set<BooleanFormula> applyWithInputRelatingPremises(List<BooleanFormula> pConjunctiveInputPredicates)
            throws SolverException, InterruptedException {

        return applyWithInputRelatingPremises(pConjunctiveInputPredicates, HashMultimap.<String, Formula>create());
    }

    public Set<BooleanFormula> applyWithInputRelatingPremises(
            final Collection<BooleanFormula> pConjunctiveInputPredicates,
            final Multimap<String, Formula> pMatchingBindings) throws SolverException, InterruptedException {

        overallTimer.start();
        try {

            Preconditions.checkArgument(pConjunctiveInputPredicates.size() == getPremises().size());

            final Set<BooleanFormula> result = Sets.newHashSet();

            // Check premises -------------------
            boolean allPremisesMatch = true;
            final Multimap<String, Formula> matchingBindings = HashMultimap.create(pMatchingBindings);
            Iterator<BooleanFormula> it = pConjunctiveInputPredicates.iterator();

            for (Premise p : getPremises()) {
                assert p instanceof PatternBasedPremise;
                final PatternBasedPremise pp = (PatternBasedPremise) p;
                final BooleanFormula predicate = it.next();

                matchingTimer.start();
                final SmtAstMatchResult matchingResult = matcher.perform(pp.getPatternSelection(), null, predicate,
                        Optional.of(matchingBindings));
                matchingTimer.stop();

                if (!matchingResult.matches()) {
                    allPremisesMatch = false;
                    break;
                }

                matchingResult.appendBindingsTo(matchingBindings);
            }

            // Derive conclusion ------------------
            if (!allPremisesMatch) {
                return Collections.emptySet();
            }

            for (Map<String, Formula> tuple : getAllAssignments(matchingBindings)) {
                // Check whether the tuple satisfies the constraints...
                constraintCheckTimer.start();
                final boolean constraintsSatisfied = satisfiesConstraints(tuple);
                constraintCheckTimer.stop();
                if (!constraintsSatisfied) {
                    continue;
                }

                // Now we can instantiate the conclusion...
                conclusionTimer.start();
                result.addAll(deriveConclusion(tuple));
                conclusionTimer.stop();
            }

            // The conclusion must be a valid over-approximation
            conclusionValidationTimer.start();
            boolean isValidOverapproximation = isValidConclusion(pConjunctiveInputPredicates, result);
            conclusionValidationTimer.stop();

            if (!isValidOverapproximation) {
                return Collections.emptySet();
            }

            return result;

        } finally {
            overallTimer.stop();
        }
    }

    protected boolean isValidConclusion(final Collection<BooleanFormula> pConjunctiveInputPredicates,
            final Set<BooleanFormula> pResult) throws SolverException, InterruptedException {

        return solver.isUnsat(bfm.not(bfm.implication(bfm.and(ImmutableList.copyOf(pConjunctiveInputPredicates)),
                bfm.and(ImmutableList.copyOf(pResult)))));
    }

}