/* * Copyright (C) 2020 Jonas Werner (wernerj@informatik.uni-freiburg.de) * Copyright (C) 2020 University of Freiburg * * This file is part of the ULTIMATE accelerated interpolation library . * * The ULTIMATE framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ULTIMATE framework is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ULTIMATE accelerated interpolation library . If not, see . * * Additional permission under GNU GPL version 3 section 7: * If you modify the ULTIMATE PDR library , or any covered work, by linking * or combining it with Eclipse RCP (or a modified version of Eclipse RCP), * containing parts covered by the terms of the Eclipse Public License, the * licensors of the ULTIMATE accelerated interpolation library grant you additional permission * to convey the resulting work. */ package de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import de.uni_freiburg.informatik.ultimate.automata.nestedword.NestedWord; import de.uni_freiburg.informatik.ultimate.core.model.services.ILogger; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgCallTransition; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgReturnTransition; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgTransition; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormula; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.UnmodifiableTransFormula; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramNonOldVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicateUnifier; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.PredicateTransformer; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.PredicateUnifier; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils.SimplificationTechnique; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.predicates.IterativePredicateTransformer; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.singletracecheck.DefaultTransFormulas; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.singletracecheck.TraceCheckUtils; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; /** * Transforms a given counterexample to a meta trace by replacing loops with their transitive closure. * * @author Jonas Werner (wernerj@informatik.uni-freiburg.de) * * @param * Type of transition. */ public class MetaTraceTransformer> { private final ILogger mLogger; private final ManagedScript mScript; private final List mCounterexample; private final IPredicateUnifier mPredUnifier; private final IUltimateServiceProvider mServices; private final PredicateTransformer mPredTransformer; private final CfgSmtToolkit mToolkit; private final Map, IPredicate> mCallPred; /** * Determine how to construct the meta-trace. * * @author Jonas Werner (wernerj@informatik.uni-freiburg.de) * */ public enum MetaTraceApplicationMethod { ONLY_AT_FIRST_LOOP_ENTRY, ON_EACH_LOOP_ENTRY, INVARIANT } /** * Transforms given meta trace interpolants to inductive trace interpolants * * @param logger * A {@link ILogger} * @param script * A {@link ManagedScript} * @param counterexample * A possible counterexample trace. * @param predUnifier * A {@link PredicateUnifier} * @param services * {@link IUltimateServiceProvider} * @param predTransformer * A {@link PredicateTransformer} * @param toolkit * A {@link CfgSmtToolkit} */ public MetaTraceTransformer(final ILogger logger, final ManagedScript script, final List counterexample, final IPredicateUnifier predUnifier, final IUltimateServiceProvider services, final PredicateTransformer predTransformer, final CfgSmtToolkit toolkit) { mLogger = logger; mScript = script; mServices = services; mCounterexample = counterexample; mPredUnifier = predUnifier; mPredTransformer = predTransformer; mToolkit = toolkit; mCallPred = new HashMap<>(); } /** * Given meta trace interpolants yield inductive interpolants for an error trace * * @param preds * A set of {@link IPredicate} * @param accelerations * Accelerations for loops in the trace. * @param loopSizes * The sizes of each loop, eg, where in the trace do they begin and where end. * @param metaTraceApplicationMethod * Which {@link MetaTraceApplicationMethod} is used. * @return Inductive interpolants as {@link IPredicate} */ public IPredicate[] getInductiveLoopInterpolants(final IPredicate[] preds, final Map> accelerations, final Map> loopSizes, final MetaTraceApplicationMethod metaTraceApplicationMethod) { final MetaTraceApplicationMethod mtam = metaTraceApplicationMethod; IPredicate[] actualInterpolants = new IPredicate[mCounterexample.size() - 1]; int cnt = 0; for (int i = 0; i < actualInterpolants.length; i++) { final IcfgLocation target = mCounterexample.get(i).getTarget(); /* * When the next location is a loophead, use loopaccelerations */ if (accelerations.containsKey(target)) { final Pair loopSize = loopSizes.get(target); final List loopAccelerations = new ArrayList<>(accelerations.get(target)); final List loopAccelerationsForEntryLocation = new ArrayList<>(); final int maxLoopPredicates = 2 * loopAccelerations.size(); /* * In case there are multiple loop accelerations, construct post of meta trace's interpolant and * corresponding loop acceleration */ Term loopAccelerationsForEntryLocationDisjunction; final int loopSkip = 3; if (loopAccelerations.size() > 1) { int currentPredCounter = cnt; int currentIterationCounter = 0; while (currentPredCounter < maxLoopPredicates + cnt) { final IPredicate loopEntryInterpolantMetaTrace = preds[currentPredCounter]; final UnmodifiableTransFormula loopAccelerationForCorrespondingLoop = loopAccelerations.get(currentIterationCounter); final Term postInterpolantLoopacceleration = mPredTransformer.strongestPostcondition( loopEntryInterpolantMetaTrace, loopAccelerationForCorrespondingLoop); loopAccelerationsForEntryLocation.add(postInterpolantLoopacceleration); currentIterationCounter++; currentPredCounter = currentPredCounter + loopSkip; } loopAccelerationsForEntryLocationDisjunction = SmtUtils.and(mScript.getScript(), loopAccelerationsForEntryLocation); } else { final IPredicate loopEntryInterpolantMetaTrace = preds[cnt]; final UnmodifiableTransFormula loopAccelerationForCorrespondingLoop = loopAccelerations.get(0); final Term postInterpolantLoopacceleration = mPredTransformer.strongestPostcondition( loopEntryInterpolantMetaTrace, loopAccelerationForCorrespondingLoop); loopAccelerationsForEntryLocationDisjunction = postInterpolantLoopacceleration; } cnt = cnt + maxLoopPredicates - 1; loopAccelerationsForEntryLocationDisjunction = SmtUtils.simplify(mScript, loopAccelerationsForEntryLocationDisjunction, mServices, SimplificationTechnique.SIMPLIFY_DDA); final IPredicate interpolantPred = mPredUnifier.getOrConstructPredicate(loopAccelerationsForEntryLocationDisjunction); actualInterpolants[i] = interpolantPred; i++; final Integer loopEndPoint = i + loopSize.getSecond() - loopSize.getFirst(); /* * Because the meta trace interpolants are too few, we need to post through the whole loop to get an * inductive interpolant sequence */ switch (mtam) { case ONLY_AT_FIRST_LOOP_ENTRY: actualInterpolants = getInductiveFirstEntryOnlyPost(actualInterpolants, i, loopEndPoint); break; case INVARIANT: actualInterpolants = getInductiveInvariant(actualInterpolants, i, loopEndPoint); break; default: throw new UnsupportedOperationException(); } i = loopEndPoint - 1; } else { final IPredicate prevInterpol; /* * post does not work well with false, there are instances where the interpolant on the loopexit in the * meta trace is false, this, however, may not always be inductive. */ if (SmtUtils.isFalseLiteral(preds[cnt].getFormula()) && i != 0) { final IPredicate tmpPrevInterpol = actualInterpolants[i - 1]; final Term post = mPredTransformer.strongestPostcondition(tmpPrevInterpol, mCounterexample.get(i).getTransformula()); prevInterpol = mPredUnifier.getOrConstructPredicate(post); } else { prevInterpol = preds[cnt]; } actualInterpolants[i] = prevInterpol; } cnt++; } return actualInterpolants; } private IPredicate[] getInductiveFirstEntryOnlyIterativePredTransformer(final IPredicate[] currentPreds, final Integer start, final Integer end, final IPredicate precondition, final IPredicate postcondition) { final List loopTrace = mCounterexample.subList(start, end); final NestedWord nestedWordLoopTrace = TraceCheckUtils.toNestedWord(loopTrace); final DefaultTransFormulas rtf = new DefaultTransFormulas<>(nestedWordLoopTrace, precondition, postcondition, Collections.emptySortedMap(), mToolkit.getOldVarsAssignmentCache(), false); final IterativePredicateTransformer itp = new IterativePredicateTransformer<>( mPredUnifier.getPredicateFactory(), mScript, mToolkit.getModifiableGlobalsTable(), mServices, nestedWordLoopTrace, precondition, postcondition, Collections.emptySortedMap(), mPredUnifier.getTruePredicate(), SimplificationTechnique.SIMPLIFY_DDA, mToolkit.getSymbolTable()); final List loopInterpols = itp.computeStrongestPostconditionSequence(rtf, Collections.emptyList()).getPredicates(); int j = start + 1; currentPreds[start] = precondition; for (int i = 0; i < loopInterpols.size(); i++) { currentPreds[j] = loopInterpols.get(i); j++; } currentPreds[end] = postcondition; return currentPreds; } /** * Apply the disjunction of looppath predicates only to the first loophead, then post until loopexit. * * @param currentPreds * @param start * @param end * @return */ private IPredicate[] getInductiveFirstEntryOnlyPost(final IPredicate[] currentPreds, final Integer start, final Integer end) { for (int j = start; j < end; j++) { final L l = mCounterexample.get(j); final IPredicate loopPostTerm = currentPreds[j - 1]; Term postTfPred; final UnmodifiableTransFormula transRel = l.getTransformula(); if (l instanceof IIcfgCallTransition) { final IIcfgCallTransition callTrans = (IIcfgCallTransition) l; final UnmodifiableTransFormula localAss = callTrans.getLocalVarsAssignment(); final UnmodifiableTransFormula globalAss = mToolkit.getOldVarsAssignmentCache() .getGlobalVarsAssignment(callTrans.getSucceedingProcedure()); final UnmodifiableTransFormula oldAss = mToolkit.getOldVarsAssignmentCache().getOldVarsAssignment(callTrans.getSucceedingProcedure()); final Set modGlob = mToolkit.getModifiableGlobalsTable().getModifiedBoogieVars(callTrans.getSucceedingProcedure()); postTfPred = mPredTransformer.strongestPostconditionCall(loopPostTerm, localAss, globalAss, oldAss, modGlob); mCallPred.put(callTrans, mPredUnifier.getOrConstructPredicate(postTfPred)); mLogger.debug("Dealt with Call"); } if (l instanceof IIcfgReturnTransition) { final IIcfgReturnTransition returnTrans = (IIcfgReturnTransition) l; final UnmodifiableTransFormula oldAss = mToolkit.getOldVarsAssignmentCache().getOldVarsAssignment(returnTrans.getPrecedingProcedure()); final Set modGlob = mToolkit.getModifiableGlobalsTable().getModifiedBoogieVars(returnTrans.getPrecedingProcedure()); postTfPred = mPredTransformer.strongestPostconditionReturn(loopPostTerm, mPredUnifier.getTruePredicate(), returnTrans.getTransformula(), returnTrans.getCorrespondingCall().getTransformula(), oldAss, modGlob); mLogger.debug("Dealt with Return"); } else { postTfPred = mPredTransformer.strongestPostcondition(loopPostTerm, transRel); } currentPreds[j] = mPredUnifier.getOrConstructPredicate(postTfPred); mLogger.debug("Generated Interpolant"); } return currentPreds; } private IPredicate[] getInductiveInvariant(final IPredicate[] currentPreds, final Integer start, final Integer end) { final IPredicate invariant = currentPreds[start - 1]; for (int j = start; j < end; j++) { currentPreds[j] = mPredUnifier.getOrConstructPredicate(invariant); } return currentPreds; } }