/* * Copyright (C) 2017 Matthias Heizmann (heizmann@informatik.uni-freiburg.de) * Copyright (C) 2017 Dennis Wölfing * Copyright (C) 2017 University of Freiburg * * This file is part of the ULTIMATE ModelCheckerUtils Library. * * The ULTIMATE ModelCheckerUtils Library 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 ModelCheckerUtils Library 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 ModelCheckerUtils Library. If not, see . * * Additional permission under GNU GPL version 3 section 7: * If you modify the ULTIMATE ModelCheckerUtils 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 ModelCheckerUtils Library grant you additional permission * to convey the resulting work. */ package de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.dangerinvariants; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Deque; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; 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.IcfgUtils; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IAction; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; 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.smt.MonolithicImplicationChecker; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.BasicPredicateFactory; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate; 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.smtlibutils.IncrementalPlicationChecker; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.IncrementalPlicationChecker.Validity; 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.smtlibutils.quantifier.PartialQuantifierElimination; import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation; /** * Class contains static auxiliary methods * * @author Matthias Heizmann (heizmann@informatik.uni-freiburg.de) * */ public class DangerInvariantUtils { private DangerInvariantUtils() { // do not instanciate } /** * Given a predicate predec and all its successors (as a HashRelation from IActions to IPredicates) succs. Check if * every state that satisfies predec has some successor state. * * @param mgdScript * @param services * @param csToolkit * @param predicateFactory * @param logger * @return */ public static Validity eachStateHasSuccessor(final IPredicate predec, final HashRelation succs, final ManagedScript mgdScript, final IUltimateServiceProvider services, final CfgSmtToolkit csToolkit, final BasicPredicateFactory predicateFactory, final ILogger logger) { final PredicateTransformer pt = new PredicateTransformer<>(mgdScript, new TermDomainOperationProvider(services, mgdScript)); final Collection predecessors = new ArrayList<>(); for (final Entry entry : succs.getSetOfPairs()) { final Term pre = constructPreInternal(logger, predicateFactory, csToolkit, pt, entry.getKey().getTransformula(), entry.getValue(), services); predecessors.add(predicateFactory.newPredicate(pre)); } final IPredicate disjunction = predicateFactory.or(SimplificationTechnique.SIMPLIFY_DDA, predecessors); final MonolithicImplicationChecker mic = new MonolithicImplicationChecker(services, mgdScript); final Validity result = mic.checkImplication(predec, false, disjunction, false); return result; } /** * Check if a given predicate is satisfied for at least one program state. */ public static Validity predicateIsNotEmpty(final IPredicate pred, final ManagedScript mgdScript) { final LBool lbool = SmtUtils.checkSatTerm(mgdScript.getScript(), pred.getClosedFormula()); return IncrementalPlicationChecker.convertLBool2Validity(lbool); } private static Term constructPreInternal(final ILogger logger, final BasicPredicateFactory predicateFactory, final CfgSmtToolkit csToolkit, final PredicateTransformer pt, final TransFormula tf, final IPredicate succPred, final IUltimateServiceProvider services) { final Term wp = pt.weakestPrecondition(predicateFactory.not(succPred), tf); final Term wpLessQuantifiers = PartialQuantifierElimination.eliminateCompat(services, csToolkit.getManagedScript(), SimplificationTechnique.SIMPLIFY_DDA, wp); final Term pre = SmtUtils.not(csToolkit.getManagedScript().getScript(), wpLessQuantifiers); return pre; } /** * Checks whether a given danger invariant is correct. * * @param invariants * the danger invariant for each location * @param icfg * @param mgdScript * @param services * @param predicateFactory * @param logger * @return VALID if the danger invariant is correct */ public static Validity checkDangerInvariant(final Map invariants, final IIcfg icfg, final ManagedScript mgdScript, final IUltimateServiceProvider services, final BasicPredicateFactory predicateFactory, final ILogger logger) { for (final IcfgLocation location : icfg.getInitialNodes()) { // TODO: This returns INVALID when it is correct ??? final Validity validity = predicateIsNotEmpty(invariants.get(location), mgdScript); if (validity == Validity.VALID) { return Validity.INVALID; } else if (validity != Validity.INVALID) { return validity; } } final Deque open = new ArrayDeque<>(icfg.getInitialNodes()); final Set closed = new HashSet<>(); while (!open.isEmpty()) { final IcfgLocation location = open.pop(); closed.add(location); if (IcfgUtils.isErrorLocation(icfg, location)) { continue; } final HashRelation relation = new HashRelation<>(); for (final IcfgEdge transition : location.getOutgoingEdges()) { final IcfgLocation target = transition.getTarget(); relation.addPair(transition, invariants.get(target)); if (!closed.contains(target)) { open.add(target); } } final Validity validity = eachStateHasSuccessor(invariants.get(location), relation, mgdScript, services, icfg.getCfgSmtToolkit(), predicateFactory, logger); if (validity != Validity.VALID) { return validity; } } return Validity.VALID; } }