/*
* 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.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import de.uni_freiburg.informatik.ultimate.core.lib.exceptions.ToolchainCanceledException;
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.core.model.translation.IProgramExecution;
import de.uni_freiburg.informatik.ultimate.icfgtransformer.LoopAccelerators;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.AcceleratedInterpolationCore.IStrategySupplier;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.benchmark.AcceleratedInterpolationBenchmark;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.benchmark.AcceleratedInterpolationBenchmark.AcceleratedInterpolationStatisticsDefinitions;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopaccelerator.AcceleratorFastUPR;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopaccelerator.AcceleratorJordan;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopaccelerator.AcceleratorQvasr;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopaccelerator.AcceleratorQvasrs;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopaccelerator.AcceleratorWernerOverapprox;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopaccelerator.IAccelerator;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopdetector.ILoopdetector;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.loopdetector.Loopdetector;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.looppreprocessor.ILoopPreprocessor;
import de.uni_freiburg.informatik.ultimate.lib.acceleratedinterpolation.looppreprocessor.LoopPreprocessor;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg;
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.smt.interpolant.IInterpolatingTraceCheck;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.interpolant.InterpolantComputationStatus;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.interpolant.InterpolantComputationStatus.ItpErrorStatus;
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.TermDomainOperationProvider;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.tracecheck.ITraceCheckPreferences;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.tracecheck.TraceCheckReasonUnknown;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.tracecheck.TraceCheckReasonUnknown.ExceptionHandlingCategory;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.tracecheck.TraceCheckReasonUnknown.Reason;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript;
import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.Counterexample;
import de.uni_freiburg.informatik.ultimate.logic.SMTLIBException;
import de.uni_freiburg.informatik.ultimate.logic.Script.LBool;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.util.statistics.IStatisticsDataProvider;
/**
* Class for the accelerated interpolation interpolant generation scheme. Accelerated interpolation makes use of loop
* accelerations/summaries to speed up interpolant computation.
*
* @author Jonas Werner (wernerj@informatik.uni-freiburg.de)
*
*
* @param
* A letter of a word.
*/
public class AcceleratedInterpolation> implements IInterpolatingTraceCheck {
private final ILogger mLogger;
private final ManagedScript mScript;
private final IUltimateServiceProvider mServices;
private final Counterexample mCounterexampleTrace;
private final List mCounterexample;
private final IPredicateUnifier mPredUnifier;
private final PredicateTransformer mPredTransformer;
private final PredicateHelper mPredHelper;
private final ITraceCheckPreferences mPrefs;
private final IIcfg> mIcfg;
private LBool mIsTraceCorrect;
private IPredicate[] mInterpolants;
private IProgramExecution mFeasibleProgramExecution;
private TraceCheckReasonUnknown mReasonUnknown;
private boolean mTraceCheckFinishedNormally;
private final AcceleratedInterpolationBenchmark mAccelInterpolBench;
private final Class mTransitionClazz;
/**
* Interpolation using loop acceleration. By detecting loops in program traces, we compute the reflexive transitive
* closure to capture all possible loop iterations and interpolate of this meta-trace.
*
* @param logger
* A {@link ILogger}
* @param prefs
* Ultimate's preferences.
* @param script
* A {@link ManagedScript}
* @param predicateUnifier
* A {@link PredicateTransformer}
* @param counterexample
* A possible counterexample.
* @param transitionClazz
* The letter clazz.
* @param strategySupplier
*/
public AcceleratedInterpolation(final IUltimateServiceProvider services, final ILogger logger,
final ITraceCheckPreferences prefs, final ManagedScript script, final IPredicateUnifier predicateUnifier,
final Counterexample counterexample, final Class transitionClazz,
final LoopAccelerators accelerationMethod, final IStrategySupplier strategySupplier) {
mLogger = logger;
mScript = script;
mTransitionClazz = transitionClazz;
mServices = services;
mCounterexampleTrace = counterexample;
mCounterexample = mCounterexampleTrace.getWord().asList();
mPrefs = prefs;
mAccelInterpolBench = new AcceleratedInterpolationBenchmark();
mAccelInterpolBench.start(AcceleratedInterpolationStatisticsDefinitions.ACCELINTERPOL_OVERALL);
mIcfg = mPrefs.getIcfgContainer();
mPredUnifier = predicateUnifier;
mLogger.debug("Accelerated Interpolation engaged!");
mPredTransformer = new PredicateTransformer<>(mScript, new TermDomainOperationProvider(mServices, mScript));
mPredHelper = new PredicateHelper<>(mPredUnifier, mPredTransformer, mLogger, mScript, mServices);
mInterpolants = new IPredicate[mCounterexample.size()];
final ILoopdetector loopdetector;
final ILoopPreprocessor loopPreprocessor;
final IAccelerator loopAccelerator;
switch (accelerationMethod) {
case FAST_UPR:
loopdetector = new Loopdetector<>(mCounterexample, mLogger);
final List fastUPRPreprocessOptions = new ArrayList<>(Arrays.asList("ite", "mod", "!=", "not"));
loopPreprocessor = new LoopPreprocessor<>(mLogger, mScript, mServices, mPredUnifier, mPredHelper,
mIcfg.getCfgSmtToolkit(), fastUPRPreprocessOptions);
loopAccelerator =
new AcceleratorFastUPR(mLogger, mScript, mServices, mIcfg.getCfgSmtToolkit().getSymbolTable());
break;
case JORDAN:
loopdetector = new Loopdetector<>(mCounterexample, mLogger);
loopPreprocessor = new LoopPreprocessor<>(mLogger, mScript, mServices, mPredUnifier, mPredHelper,
mIcfg.getCfgSmtToolkit(), new ArrayList<>(Arrays.asList("ite")));
loopAccelerator = new AcceleratorJordan(mLogger, mScript, mServices);
break;
case QVASR:
loopdetector = new Loopdetector<>(mCounterexample, mLogger);
loopPreprocessor = new LoopPreprocessor<>(mLogger, mScript, mServices, mPredUnifier, mPredHelper,
mIcfg.getCfgSmtToolkit(), Arrays.asList("No DNF"));
loopAccelerator = new AcceleratorQvasr(mLogger, mScript, mServices, mPredUnifier);
break;
case QVASRS:
loopdetector = new Loopdetector<>(mCounterexample, mLogger);
loopPreprocessor = new LoopPreprocessor<>(mLogger, mScript, mServices, mPredUnifier, mPredHelper,
mIcfg.getCfgSmtToolkit(), Arrays.asList("No DNF"));
loopAccelerator = new AcceleratorQvasrs(mLogger, mScript, mServices);
break;
case WERNER_OVERAPPROX:
loopdetector = new Loopdetector<>(mCounterexample, mLogger);
loopPreprocessor = new LoopPreprocessor<>(mLogger, mScript, mServices, mPredUnifier, mPredHelper,
mIcfg.getCfgSmtToolkit(), new ArrayList<>(Arrays.asList("")));
loopAccelerator = new AcceleratorWernerOverapprox(mLogger, mScript, mServices,
mIcfg.getCfgSmtToolkit().getSymbolTable());
break;
default:
throw new UnsupportedOperationException("Unkown " + accelerationMethod);
}
final AcceleratedInterpolationCore accelInterpolCore =
new AcceleratedInterpolationCore<>(mServices, mLogger, mScript, mPredUnifier, mPrefs,
mCounterexampleTrace, mIcfg, loopdetector, loopPreprocessor, loopAccelerator, strategySupplier);
try {
mAccelInterpolBench.start(AcceleratedInterpolationStatisticsDefinitions.ACCELINTERPOL_CORE);
mIsTraceCorrect = accelInterpolCore.acceleratedInterpolationCoreIsCorrect();
if (mIsTraceCorrect == LBool.UNSAT) {
mInterpolants = accelInterpolCore.getInterpolants();
}
mTraceCheckFinishedNormally = true;
if (mIsTraceCorrect == LBool.UNKNOWN) {
mReasonUnknown = new TraceCheckReasonUnknown(Reason.SOLVER_RESPONSE_OTHER, null,
ExceptionHandlingCategory.KNOWN_DEPENDING);
} else {
mReasonUnknown = null;
}
} catch (final ToolchainCanceledException tce) {
mTraceCheckFinishedNormally = false;
mIsTraceCorrect = LBool.UNKNOWN;
mReasonUnknown = new TraceCheckReasonUnknown(Reason.ULTIMATE_TIMEOUT, tce,
ExceptionHandlingCategory.KNOWN_DEPENDING);
} catch (final SMTLIBException e) {
mTraceCheckFinishedNormally = false;
mIsTraceCorrect = LBool.UNKNOWN;
mReasonUnknown = TraceCheckReasonUnknown.constructReasonUnknown(e);
} finally {
mAccelInterpolBench.stopAllStopwatches();
mLogger.debug("Finished");
}
}
private IProgramExecution computeProgramExecution() {
// TODO: construct a real IProgramExecution using
// IcfgProgramExecutionBuilder
if (mIsTraceCorrect == LBool.SAT) {
return IProgramExecution.emptyExecution(Term.class, mTransitionClazz);
}
return null;
}
@Override
public InterpolantComputationStatus getInterpolantComputationStatus() {
if (isCorrect() == LBool.UNSAT) {
return new InterpolantComputationStatus();
}
if (isCorrect() == LBool.SAT) {
return new InterpolantComputationStatus(ItpErrorStatus.TRACE_FEASIBLE, null);
}
throw new UnsupportedOperationException();
}
@Override
public IPredicate[] getInterpolants() {
return mInterpolants;
}
@Override
public Map getPendingContexts() {
return Collections.emptyMap();
}
@Override
public IPredicate getPostcondition() {
return mPredUnifier.getFalsePredicate();
}
@Override
public IPredicate getPrecondition() {
return mPredUnifier.getTruePredicate();
}
@Override
public IPredicateUnifier getPredicateUnifier() {
return mPredUnifier;
}
@Override
public IProgramExecution getRcfgProgramExecution() {
if (mFeasibleProgramExecution == null) {
mFeasibleProgramExecution = computeProgramExecution();
}
return mFeasibleProgramExecution;
}
@Override
public IStatisticsDataProvider getStatistics() {
// TODO Auto-generated method stub
return null;
}
@Override
public List getTrace() {
return mCounterexample;
}
@Override
public TraceCheckReasonUnknown getTraceCheckReasonUnknown() {
return mReasonUnknown;
}
@Override
public LBool isCorrect() {
return mIsTraceCorrect;
}
@Override
public boolean isPerfectSequence() {
return isCorrect() == LBool.UNSAT;
}
@Override
public boolean providesRcfgProgramExecution() {
return mIsTraceCorrect != LBool.SAT;
}
@Override
public boolean wasTracecheckFinishedNormally() {
return mTraceCheckFinishedNormally;
}
}