From 8a7e12511b7b3e36158f87fc3804c36c0c95a86d Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Sat, 1 Apr 2023 12:59:23 +0200 Subject: [PATCH 001/114] IcfgToChcConcurrent: some documentation and minor refactoring --- .../concurrent/IcfgToChcConcurrent.java | 169 ++++++++++++++---- 1 file changed, 131 insertions(+), 38 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java index 597b84a67fc..28c2f312a54 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java @@ -51,14 +51,38 @@ public class IcfgToChcConcurrent { private final ManagedScript mManagedScript; + // maps a procedure name and a location (in the procedure) to an integer, such that the location variable has this + // integer as value iff control is in the given location private final NestedMap2 mLocationIndices; + + // maps each thread template (identified by procedure name) to the number of instances private final Map mNumberOfThreads; + + // used as location for threads that are not currently running private final Term mBottomLocation; + private final HcPredicateSymbol mPredicate; private final HcSymbolTable mHcSymbolTable; + + // list of "head vars" (?), in the order as given to the CHC predicate + // these variables are always used in the head of any clause generated by this class private final List mDefaultHeadVars; + + /** + * maps a number i to the variable used for the i-th argument of the CHC predicate + */ private final BidirectionalMap mPositions2Vars; + /** + * + * @param numberOfThreads + * Maps thread names to the number of instances to include in the Horn clause system + * @param managedScript + * @param cfgSmtToolkit + * @param hcSymbolTable + * @param variableFilter + * + */ public IcfgToChcConcurrent(final Map numberOfThreads, final ManagedScript managedScript, final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable hcSymbolTable, final Predicate variableFilter) { @@ -70,16 +94,20 @@ public IcfgToChcConcurrent(final Map numberOfThreads, final Man mNumberOfThreads = new LinkedHashMap<>(numberOfThreads); mLocationIndices = new NestedMap2<>(); mBottomLocation = numeral(-1); + final Map> localVariables = new HashMap<>(); - mPositions2Vars = new BidirectionalMap<>(); for (final String proc : mNumberOfThreads.keySet()) { localVariables.put(proc, symbolTable.getLocals(proc).stream().filter(variableFilter).collect(Collectors.toList())); } + + mPositions2Vars = new BidirectionalMap<>(); initializeDefaultVars(globalVariables, localVariables); + final List sorts = IntStream.range(0, mPositions2Vars.size()) .mapToObj(x -> mPositions2Vars.get(x).getSort()).collect(Collectors.toList()); mPredicate = hcSymbolTable.getOrConstructHornClausePredicateSymbol(FUNCTION_NAME, sorts); + mDefaultHeadVars = IntStream.range(0, mPositions2Vars.size()) .mapToObj(x -> constructHeadVar(mPositions2Vars.get(x), x)).collect(Collectors.toList()); } @@ -92,16 +120,20 @@ private void initializeDefaultVars(final Collection globalVariables final Map> localVariables) { int i = 0; for (final IProgramVar v : globalVariables) { - mPositions2Vars.put(i++, new HcGlobalVar(v)); + mPositions2Vars.put(i, new HcGlobalVar(v)); + i++; } for (final Entry entry : mNumberOfThreads.entrySet()) { final String proc = entry.getKey(); final List localVars = localVariables.get(proc); for (int j = 0; j < entry.getValue(); j++) { // Location - mPositions2Vars.put(i++, new HcLocationVar(proc, j, getIntSort())); + mPositions2Vars.put(i, new HcLocationVar(proc, j, getIntSort())); + i++; + for (final IProgramVar v : localVars) { - mPositions2Vars.put(i++, new HcLocalVar(v, j)); + mPositions2Vars.put(i, new HcLocalVar(v, j)); + i++; } } } @@ -133,6 +165,7 @@ private Term getLocIndexTerm(final IcfgLocation loc, final String proc) { return numeral(index); } + // pc_0 = l_0 -> Inv(pc_0, ...) public HornClause getInitialClause(final Collection initialLocations) { final NestedMap2 locationMap = new NestedMap2<>(); for (final Entry entry : mNumberOfThreads.entrySet()) { @@ -147,23 +180,57 @@ public HornClause getInitialClause(final Collection initialLocatio return constructHornClause(getConstraintFromLocationMap(locationMap), List.of(), Set.of()); } + /** + * Constructs a Horn clause with a given body and the default head. + * + * @param constraint + * The SMT constraint in the clause body + * @param bodyArguments + * Each list of terms is used as arguments for an invocation of {@link #mPredicate} in the body + * @param bodyVars + * Variables used in the bodyArguments. These will be universally quanmBodyVariablestified in the clause. + * @return A Horn clause with a body built from the given arguments, and a head consisting of an {@link #mPredicate} + * invocation with the default variables ({@link #mDefaultHeadVars}). + */ private HornClause constructHornClause(final Term constraint, final List> bodyArguments, final Set bodyVars) { return new HornClause(mManagedScript, mHcSymbolTable, constraint, mPredicate, mDefaultHeadVars, Collections.nCopies(bodyArguments.size(), mPredicate), bodyArguments, bodyVars); } + /** + * Constructs a constraint that specifies control locations. + * + * @param locationMap + * A map from thread template (i.e. procedure name) and instance number to a term representing the + * respective location. + * @return A conjunction of equalities between the default variables for control locations + * ({@link #mDefaultHeadVars}) and the locations specified by the map + */ private Term getConstraintFromLocationMap(final NestedMap2 locationMap) { final List constraints = new ArrayList<>(); for (final var triple : locationMap.entrySet()) { - final HcLocationVar locVar = new HcLocationVar(triple.getFirst(), triple.getSecond(), getIntSort()); - final int index = mPositions2Vars.inverse().get(locVar); - final Term term = mDefaultHeadVars.get(index).getTerm(); - constraints.add(SmtUtils.binaryEquality(getScript(), term, triple.getThird())); + final var constraint = getLocationConstraint(triple.getFirst(), triple.getSecond(), triple.getThird()); + constraints.add(constraint); } return SmtUtils.and(getScript(), constraints); } + /** + * Constructs a constraint that specifies a single control location. + * + * @return Equality between the default variable for the given thread's control location ({@link #mDefaultHeadVars}) + * and the given location term + */ + private Term getLocationConstraint(final String proc, final int threadInstance, final Term location) { + final HcLocationVar locVar = new HcLocationVar(proc, threadInstance, getIntSort()); + final int index = mPositions2Vars.inverse().get(locVar); + final Term term = mDefaultHeadVars.get(index).getTerm(); + return SmtUtils.binaryEquality(getScript(), term, location); + } + + // list of clauses of the form + // Inv(..., pc_i, ...) /\ pc_i = l_err -> false public Collection getSafetyClauses(final Collection errorLocations) { final List result = new ArrayList<>(); final Set vars = new HashSet<>(mDefaultHeadVars); @@ -171,9 +238,7 @@ public Collection getSafetyClauses(final Collection er for (final IcfgLocation loc : errorLocations) { final String proc = loc.getProcedure(); for (int i = 0; i < mNumberOfThreads.get(proc); i++) { - final NestedMap2 locationMap = new NestedMap2<>(); - locationMap.put(proc, i, getLocIndexTerm(loc, proc)); - final Term constraint = getConstraintFromLocationMap(locationMap); + final Term constraint = getLocationConstraint(proc, i, getLocIndexTerm(loc, proc)); result.add(new HornClause(mManagedScript, mHcSymbolTable, constraint, List.of(mPredicate), List.of(bodyArgs), vars)); } @@ -181,6 +246,11 @@ public Collection getSafetyClauses(final Collection er return result; } + /** + * + * @param procs + * @return + */ private List> getCartesianProductOfIndices(final Collection procs) { List> result = List.of(Map.of()); for (final String p : procs) { @@ -197,47 +267,63 @@ private List> getCartesianProductOfIndices(final Collection return result; } + /** + * + * @param locations + * @param indexMap + * @return + */ + private NestedMap2 getLocationMap(final Collection locations, + final Map indexMap) { + final NestedMap2 locMap = new NestedMap2<>(); + for (final IcfgLocation loc : locations) { + final String proc = loc.getProcedure(); + locMap.put(proc, indexMap.get(proc), getLocIndexTerm(loc, proc)); + } + return locMap; + } + + /** + * + * @param pre + * @param edge + * @param post + * @return + */ public Collection getInductivityClauses(final List pre, final IIcfgTransition edge, final List post) { final List result = new ArrayList<>(); final Set containedProcs = Stream.concat(pre.stream(), post.stream()).map(IcfgLocation::getProcedure).collect(Collectors.toSet()); for (final Map indexMap : getCartesianProductOfIndices(containedProcs)) { - final NestedMap2 locMapIn = new NestedMap2<>(); - final NestedMap2 locMapOut = new NestedMap2<>(); - for (final IcfgLocation loc : pre) { - final String proc = loc.getProcedure(); - locMapIn.put(proc, indexMap.get(proc), getLocIndexTerm(loc, proc)); - } - for (final IcfgLocation loc : post) { - final String proc = loc.getProcedure(); - locMapOut.put(proc, indexMap.get(proc), getLocIndexTerm(loc, proc)); - } + final NestedMap2 locMapIn = getLocationMap(pre, indexMap); + final NestedMap2 locMapOut = getLocationMap(post, indexMap); + final TransFormula transformula = edge.getTransformula(); - final Map substitution = new HashMap<>(); + final Map substitution = new HashMap<>(); final List constraints = new ArrayList<>(); final List bodyArgs = getDefaultArgs(); final Set bodyVars = new HashSet<>(); + for (final var entry : mPositions2Vars.entrySet()) { final int index = entry.getKey(); final IHcReplacementVar rv = entry.getValue(); IProgramVar pv = null; if (rv instanceof HcLocalVar) { final HcLocalVar lv = (HcLocalVar) rv; - if (Objects.equals(indexMap.get(lv.getProcedure()), lv.getIndex())) { - pv = lv.getVariable(); + if (!Objects.equals(indexMap.get(lv.getProcedure()), lv.getIndex())) { + continue; } - } - if (rv instanceof HcGlobalVar) { + pv = lv.getVariable(); + } else if (rv instanceof HcGlobalVar) { final HcGlobalVar gv = (HcGlobalVar) rv; pv = gv.getVariable(); - } - if (rv instanceof HcLocationVar) { + } else if (rv instanceof HcLocationVar) { final HcLocationVar lv = (HcLocationVar) rv; final String procedure = lv.getProcedure(); - final int index2 = lv.getIndex(); - Term locIn = locMapIn.get(procedure, index2); - Term locOut = locMapOut.get(procedure, index2); + final int instanceIndex = lv.getIndex(); + Term locIn = locMapIn.get(procedure, instanceIndex); + Term locOut = locMapOut.get(procedure, instanceIndex); if (locIn == null && locOut == null) { continue; } @@ -252,10 +338,16 @@ public Collection getInductivityClauses(final List pre if (!locIn.equals(locOut)) { bodyArgs.set(index, locIn); } - } - if (pv == null) { + + // rv does not appear in transition formula, so skip the rest of the loop continue; + } else { + throw new UnsupportedOperationException("Unknown kind of variable: " + rv); } + + // TODO add HcSleepVar class, create at start, then add elseif-case above to handle it + + assert pv != null; final TermVariable inVar = transformula.getInVars().get(pv); final TermVariable outVar = transformula.getOutVars().get(pv); substitution.put(outVar, mDefaultHeadVars.get(index).getTerm()); @@ -267,6 +359,7 @@ public Collection getInductivityClauses(final List pre bodyVars.add(bv); } } + // Replace all other variables with aux-vars final Term formula = transformula.getFormula(); for (final TermVariable v : formula.getFreeVars()) { @@ -297,7 +390,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { bodyArguments.add(getDefaultArgs()); } final TransFormula transformula = edge.getTransformula(); - final Map substitution = new HashMap<>(); + final Map substitution = new HashMap<>(); final Set bodyVars = new HashSet<>(); for (final var entry : mPositions2Vars.entrySet()) { final int index = entry.getKey(); @@ -325,8 +418,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { bodyVars.add(auxVar); } } - } - if (rv instanceof HcGlobalVar) { + } else if (rv instanceof HcGlobalVar) { final IProgramVar pv = ((HcGlobalVar) rv).getVariable(); final TermVariable inVar = transformula.getInVars().get(pv); final TermVariable outVar = transformula.getOutVars().get(pv); @@ -340,8 +432,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { substitution.put(inVar, term); bodyVars.add(bv); } - } - if (rv instanceof HcLocationVar) { + } else if (rv instanceof HcLocationVar) { final HcLocationVar lv = (HcLocationVar) rv; if (lv.getProcedure().equals(procedure)) { final Term loc = getLocIndexTerm(edge.getSource(), procedure); @@ -351,6 +442,8 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { bodyArguments.get(i + 1).set(newIndex, loc); } } + } else { + throw new UnsupportedOperationException("Unknown kind of variable: " + rv); } } // Replace all other variables with aux-vars From ce90413d833ef7290188262f3ad9fa4e1185396a Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 4 Apr 2023 10:38:18 +0200 Subject: [PATCH 002/114] begin (very hacky) support for sleep sets in Horn clauses --- .../plugins/icfgtochc/IcfgToChcObserver.java | 10 +- .../concurrent/ChcProviderConcurrent.java | 19 +- .../ChcProviderConcurrentWithLbe.java | 4 +- .../icfgtochc/concurrent/HcSleepVar.java | 85 +++++ .../icfgtochc/concurrent/HcThreadIdVar.java | 85 +++++ .../concurrent/IcfgToChcConcurrent.java | 315 +++++++++++++++++- 6 files changed, 498 insertions(+), 20 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 872893c71fc..b61a6c94134 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -64,7 +64,7 @@ public class IcfgToChcObserver extends BaseObserver { private IElement mResult; // TODO: Make this a setting - private static final boolean USE_LBE_FOR_CONCURRENT_PROGRAMS = true; + private static final boolean USE_LBE_FOR_CONCURRENT_PROGRAMS = false; public IcfgToChcObserver(final ILogger logger, final IUltimateServiceProvider services) { mLogger = logger; @@ -95,7 +95,9 @@ private void processIcfg(final IIcfg icfg) { final ChcCategoryInfo chcCategoryInfo = new ChcCategoryInfo(getLogics(resultChcs, mgdScript), hasNonLinearClauses); - assert resultChcs.stream().allMatch(chc -> chc.constructFormula(mgdScript, false).getFreeVars().length == 0); + final var bad = resultChcs.stream() + .filter(chc -> chc.constructFormula(mgdScript, false).getFreeVars().length != 0).findAny(); + assert bad.isEmpty() : bad; final HornAnnot annot = new HornAnnot(icfg.getIdentifier(), mgdScript, hcSymbolTable, new ArrayList<>(resultChcs), true, chcCategoryInfo); @@ -152,12 +154,12 @@ private static boolean isReturnReachable(final IIcfg icfg) { private IChcProvider getChcProvider(final IIcfg icfg, final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable) { - if (IcfgUtils.isConcurrent(icfg)) { + if (true || IcfgUtils.isConcurrent(icfg)) { assert !isReturnReachable(icfg); if (USE_LBE_FOR_CONCURRENT_PROGRAMS) { return new ChcProviderConcurrentWithLbe(mgdScript, hcSymbolTable, mServices); } else { - return new ChcProviderConcurrent(mgdScript, hcSymbolTable); + return new ChcProviderConcurrent(mServices, mgdScript, hcSymbolTable); } } return new ChcProviderForCalls(mgdScript, hcSymbolTable); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java index 9d2dfaafe68..cecf8103dbc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java @@ -8,6 +8,7 @@ import java.util.Set; import java.util.stream.Collectors; +import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; @@ -17,6 +18,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; /** @@ -26,12 +28,15 @@ * */ public class ChcProviderConcurrent implements IChcProvider { + private final IUltimateServiceProvider mServices; private final ManagedScript mMgdScript; private final HcSymbolTable mHcSymbolTable; private static final int MAXIMUM_NUMBER_OF_THREADS = 2; - public ChcProviderConcurrent(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable) { + public ChcProviderConcurrent(final IUltimateServiceProvider services, final ManagedScript mgdScript, + final HcSymbolTable hcSymbolTable) { + mServices = services; mMgdScript = mgdScript; mHcSymbolTable = hcSymbolTable; } @@ -59,10 +64,20 @@ public Collection getHornClauses(final IIcfg icfg) { } } } + + numberOfThreads.clear(); + numberOfThreads.put("thread", 2); + unboundedThreads.clear(); + unboundedThreads.add("thread"); + + final var independence = new SemanticIndependenceRelation<>(mServices, mMgdScript, false, true); + final var locations = icfg.getProgramPoints().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); final IcfgToChcConcurrent factory = new IcfgToChcConcurrent(numberOfThreads, mMgdScript, - icfg.getCfgSmtToolkit(), mHcSymbolTable, x -> true); + icfg.getCfgSmtToolkit(), mHcSymbolTable, x -> true, locations, independence); final List result = new ArrayList<>(); result.add(factory.getInitialClause(icfg.getInitialNodes())); + // result.add(factory.getIdUniquenessClause()); final Set errorNodes = icfg.getProcedureErrorNodes().values().stream().flatMap(Set::stream).collect(Collectors.toSet()); final Map entryNodes = icfg.getProcedureEntryNodes(); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java index a6cbb9d0a77..693fd88ff1a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java @@ -73,8 +73,10 @@ public Collection getHornClauses(final IIcfg icfg) { final List result = new ArrayList<>(); final List errorLocs = getLocations(petriNet.getAcceptingPlaces()).stream() .filter(x -> numberOfThreads.containsKey(x.getProcedure())).collect(Collectors.toList()); + final var locations = icfg.getProgramPoints().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); final IcfgToChcConcurrent factory = new IcfgToChcConcurrent(numberOfThreads, mMgdScript, - petrified.getCfgSmtToolkit(), mHcSymbolTable, x -> true); + petrified.getCfgSmtToolkit(), mHcSymbolTable, x -> true, locations, null); result.add(factory.getInitialClause(getLocations(petriNet.getInitialPlaces()))); result.addAll(factory.getSafetyClauses(errorLocs)); for (final Transition transition : petriNet.getTransitions()) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java new file mode 100644 index 00000000000..bed131eeceb --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Objects; + +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; + +public class HcSleepVar implements IHcReplacementVar { + private static final String SORT = "Int"; + + private final Sort mSort; + private final String mThreadTemplateName; + private final int mInstanceIndex; + + public HcSleepVar(final Script script, final String threadTemplateName, final int instanceIndex) { + mSort = script.sort(SORT); + mThreadTemplateName = threadTemplateName; + mInstanceIndex = instanceIndex; + } + + @Override + public Sort getSort() { + return mSort; + } + + public String getThreadTemplateName() { + return mThreadTemplateName; + } + + public int getInstanceIndex() { + return mInstanceIndex; + } + + @Override + public String toString() { + return "sleep_" + IcfgToChcConcurrentUtils.getReadableString(mThreadTemplateName) + "_" + (mInstanceIndex + 1); + } + + @Override + public int hashCode() { + return Objects.hash(mInstanceIndex, mThreadTemplateName); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final HcSleepVar other = (HcSleepVar) obj; + return mInstanceIndex == other.mInstanceIndex && Objects.equals(mThreadTemplateName, other.mThreadTemplateName); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java new file mode 100644 index 00000000000..2c452d52bde --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Objects; + +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; + +public class HcThreadIdVar implements IHcReplacementVar { + private static final String SORT = "Int"; + + private final Sort mSort; + private final String mThreadTemplateName; + private final int mInstanceIndex; + + public HcThreadIdVar(final Script script, final String threadTemplateName, final int instanceIndex) { + mSort = script.sort(SORT); + mThreadTemplateName = threadTemplateName; + mInstanceIndex = instanceIndex; + } + + @Override + public Sort getSort() { + return mSort; + } + + public String getThreadTemplateName() { + return mThreadTemplateName; + } + + public int getInstanceIndex() { + return mInstanceIndex; + } + + @Override + public String toString() { + return "id_" + IcfgToChcConcurrentUtils.getReadableString(mThreadTemplateName) + "_" + (mInstanceIndex + 1); + } + + @Override + public int hashCode() { + return Objects.hash(mInstanceIndex, mThreadTemplateName); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final HcThreadIdVar other = (HcThreadIdVar) obj; + return mInstanceIndex == other.mInstanceIndex && Objects.equals(mThreadTemplateName, other.mThreadTemplateName); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java index 28c2f312a54..3f3960fa6cc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java @@ -17,6 +17,8 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; import de.uni_freiburg.informatik.ultimate.lib.chc.HcBodyVar; import de.uni_freiburg.informatik.ultimate.lib.chc.HcHeadVar; import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; @@ -39,6 +41,7 @@ import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; /** * Class to create horn-clauses for given edges to create thread-modular proofs. @@ -53,7 +56,7 @@ public class IcfgToChcConcurrent { // maps a procedure name and a location (in the procedure) to an integer, such that the location variable has this // integer as value iff control is in the given location - private final NestedMap2 mLocationIndices; + private final NestedMap2 mLocationIndices = new NestedMap2<>(); // maps each thread template (identified by procedure name) to the number of instances private final Map mNumberOfThreads; @@ -68,10 +71,18 @@ public class IcfgToChcConcurrent { // these variables are always used in the head of any clause generated by this class private final List mDefaultHeadVars; + private final NestedMap2 mSleepVars = new NestedMap2<>(); + private final NestedMap2 mLocationsVars = new NestedMap2<>(); + private final NestedMap2 mIdVars = new NestedMap2<>(); + + private final Map> mThreadLocations; + /** * maps a number i to the variable used for the i-th argument of the CHC predicate */ - private final BidirectionalMap mPositions2Vars; + private final BidirectionalMap mPositions2Vars = new BidirectionalMap<>(); + + private final IIndependenceRelation> mIndependence; /** * @@ -85,23 +96,23 @@ public class IcfgToChcConcurrent { */ public IcfgToChcConcurrent(final Map numberOfThreads, final ManagedScript managedScript, final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable hcSymbolTable, - final Predicate variableFilter) { + final Predicate variableFilter, final Map> threadLocations, + final IIndependenceRelation> independence) { final IIcfgSymbolTable symbolTable = cfgSmtToolkit.getSymbolTable(); mHcSymbolTable = hcSymbolTable; mManagedScript = managedScript; final List globalVariables = symbolTable.getGlobals().stream().filter(variableFilter).collect(Collectors.toList()); mNumberOfThreads = new LinkedHashMap<>(numberOfThreads); - mLocationIndices = new NestedMap2<>(); mBottomLocation = numeral(-1); + mThreadLocations = threadLocations; + mIndependence = independence; final Map> localVariables = new HashMap<>(); for (final String proc : mNumberOfThreads.keySet()) { localVariables.put(proc, symbolTable.getLocals(proc).stream().filter(variableFilter).collect(Collectors.toList())); } - - mPositions2Vars = new BidirectionalMap<>(); initializeDefaultVars(globalVariables, localVariables); final List sorts = IntStream.range(0, mPositions2Vars.size()) @@ -127,8 +138,22 @@ private void initializeDefaultVars(final Collection globalVariables final String proc = entry.getKey(); final List localVars = localVariables.get(proc); for (int j = 0; j < entry.getValue(); j++) { + // thread ID + final var id = new HcThreadIdVar(getScript(), proc, j); + mIdVars.put(proc, j, id); + mPositions2Vars.put(i, id); + i++; + // Location - mPositions2Vars.put(i, new HcLocationVar(proc, j, getIntSort())); + final var loc = new HcLocationVar(proc, j, getIntSort()); + mLocationsVars.put(proc, j, loc); + mPositions2Vars.put(i, loc); + i++; + + // sleep set + final var sleep = new HcSleepVar(getScript(), proc, j); + mSleepVars.put(proc, j, sleep); + mPositions2Vars.put(i, sleep); i++; for (final IProgramVar v : localVars) { @@ -175,9 +200,40 @@ public HornClause getInitialClause(final Collection initialLocatio } for (final IcfgLocation loc : initialLocations) { final String proc = loc.getProcedure(); - locationMap.put(proc, 0, getLocIndexTerm(loc, proc)); + for (int i = 0; i < mNumberOfThreads.get(proc); i++) { + locationMap.put(proc, i, getLocIndexTerm(loc, proc)); + } } - return constructHornClause(getConstraintFromLocationMap(locationMap), List.of(), Set.of()); + final var locConstraint = getConstraintFromLocationMap(locationMap); + + final var idConstraints = new ArrayList(); + // final var instances = mNumberOfThreads.entrySet().stream() + // .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) + // .collect(Collectors.toList()); + // for (int i = 0; i < instances.size(); ++i) { + // final var first = instances.get(i); + // final var firstIndex = + // mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + // final var firstId = mDefaultHeadVars.get(firstIndex); + // + // for (int j = i + 1; j < instances.size(); ++j) { + // final var second = instances.get(j); + // final var secondIndex = mPositions2Vars.inverse() + // .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + // final var secondId = mDefaultHeadVars.get(secondIndex); + // + // idConstraints.add(SmtUtils.distinct(getScript(), firstId.getTerm(), secondId.getTerm())); + // } + // } + + // sleep set initially empty + final var sleepConstraints = mSleepVars.values() + .map(sv -> SmtUtils.binaryEquality(getScript(), + mDefaultHeadVars.get(mPositions2Vars.inverse().get(sv)).getTerm(), numeral(0))) + .collect(Collectors.toList()); + + return constructHornClause(SmtUtils.and(getScript(), locConstraint, SmtUtils.and(getScript(), sleepConstraints), + SmtUtils.and(getScript(), idConstraints)), List.of(), Set.of()); } /** @@ -292,6 +348,8 @@ private NestedMap2 getLocationMap(final Collection getInductivityClauses(final List pre, final IIcfgTransition edge, final List post) { + final String activeProcedure = edge.getPrecedingProcedure(); + final List result = new ArrayList<>(); final Set containedProcs = Stream.concat(pre.stream(), post.stream()).map(IcfgLocation::getProcedure).collect(Collectors.toSet()); @@ -341,12 +399,91 @@ public Collection getInductivityClauses(final List pre // rv does not appear in transition formula, so skip the rest of the loop continue; + } else if (rv instanceof HcSleepVar) { + final var sv = (HcSleepVar) rv; + final var activeInstanceIndex = indexMap.get(sv.getThreadTemplateName()); + if (Objects.equals(sv.getInstanceIndex(), activeInstanceIndex)) { + // this is the sleep variable for the active thread + final var bv = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); + bodyVars.add(bv); + bodyArgs.set(index, bv.getTerm()); + + // ensure that the active thread is not sleeping + constraints.add(SmtUtils.binaryEquality(getScript(), bv.getTerm(), numeral(0))); + } else { + final var oldSleep = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); + bodyVars.add(oldSleep); + bodyArgs.set(index, oldSleep.getTerm()); + final var newSleep = mDefaultHeadVars.get(index).getTerm(); + + final var hcLoc = + new HcLocationVar(sv.getThreadTemplateName(), sv.getInstanceIndex(), getIntSort()); + final int locIndex = mPositions2Vars.inverse().get(hcLoc); + final var locVar = mDefaultHeadVars.get(locIndex); + + final var currentId = mDefaultHeadVars.get(mPositions2Vars.inverse() + .get(new HcThreadIdVar(getScript(), activeProcedure, activeInstanceIndex))); + final var otherId = mDefaultHeadVars.get(mPositions2Vars.inverse().get( + new HcThreadIdVar(getScript(), sv.getThreadTemplateName(), sv.getInstanceIndex()))); + + // update sleep variable depending on commutativity and thread ID ordering + final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar.getTerm(), edge); + constraints + .add(SmtUtils.binaryBooleanEquality(getScript(), + SmtUtils.binaryEquality(getScript(), newSleep, numeral(0)), + SmtUtils.or(getScript(), SmtUtils.and(getScript(), + SmtUtils.greater(getScript(), otherId.getTerm(), currentId.getTerm()), + SmtUtils.binaryEquality(getScript(), oldSleep.getTerm(), numeral(0))), + nonCommConstr))); + } + // else if ((activeInstanceIndex != null && sv.getInstanceIndex() < activeInstanceIndex) + // || (activeInstanceIndex == null + // && sv.getThreadTemplateName().compareTo(activeProcedure) < 0)) { + // final var newSleep = mDefaultHeadVars.get(index).getTerm(); + // + // final var locVar = mLocationsVars.get(sv.getThreadTemplateName(), sv.getInstanceIndex()); + // final var locVarIndex = mPositions2Vars.inverse().get(locVar); + // final var locVar2 = + // mHcSymbolTable.getOrConstructBodyVar(mPredicate, locVarIndex, locVar.getSort(), locVar); + // bodyVars.add(locVar2); + // bodyArgs.set(locVarIndex, locVar2.getTerm()); + // + // // set newSleep to true/false depending on commutativity + // final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar2.getTerm(), edge); + // constraints.add(SmtUtils.binaryBooleanEquality(getScript(), + // SmtUtils.binaryEquality(getScript(), newSleep, numeral(0)), nonCommConstr)); + // } else { + // assert (activeInstanceIndex != null && sv.getInstanceIndex() > activeInstanceIndex) + // || (activeInstanceIndex == null + // && sv.getThreadTemplateName().compareTo(activeProcedure) > 0); + // + // final var oldSleep = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); + // bodyVars.add(oldSleep); + // bodyArgs.set(index, oldSleep.getTerm()); + // final var newSleep = mDefaultHeadVars.get(index).getTerm(); + // + // final var locVar = mLocationsVars.get(sv.getThreadTemplateName(), sv.getInstanceIndex()); + // final var locVarIndex = mPositions2Vars.inverse().get(locVar); + // final var locVar2 = + // mHcSymbolTable.getOrConstructBodyVar(mPredicate, locVarIndex, locVar.getSort(), locVar); + // bodyVars.add(locVar2); + // bodyArgs.set(locVarIndex, locVar2.getTerm()); + // + // // set newSleep to old/false depending on commutativity + // final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar2.getTerm(), edge); + // constraints.add(SmtUtils.ite(getScript(), nonCommConstr, + // SmtUtils.binaryEquality(getScript(), newSleep, numeral(0)), + // SmtUtils.binaryEquality(getScript(), newSleep, oldSleep.getTerm()))); + // } + continue; + } else if (rv instanceof HcThreadIdVar) { + // nothing to do here: the default argument in the body is already the headVar + // this is correct, because the thread ID never changes + continue; } else { throw new UnsupportedOperationException("Unknown kind of variable: " + rv); } - // TODO add HcSleepVar class, create at start, then add elseif-case above to handle it - assert pv != null; final TermVariable inVar = transformula.getInVars().get(pv); final TermVariable outVar = transformula.getOutVars().get(pv); @@ -360,6 +497,26 @@ public Collection getInductivityClauses(final List pre } } + // add ID constraints + final var instances = mNumberOfThreads.entrySet().stream() + .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) + .collect(Collectors.toList()); + for (int i = 0; i < instances.size(); ++i) { + final var first = instances.get(i); + final var firstIndex = + mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + final var firstId = mDefaultHeadVars.get(firstIndex); + + for (int j = i + 1; j < instances.size(); ++j) { + final var second = instances.get(j); + final var secondIndex = mPositions2Vars.inverse() + .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + final var secondId = mDefaultHeadVars.get(secondIndex); + + constraints.add(SmtUtils.less(getScript(), firstId.getTerm(), secondId.getTerm())); + } + } + // Replace all other variables with aux-vars final Term formula = transformula.getFormula(); for (final TermVariable v : formula.getFreeVars()) { @@ -378,10 +535,55 @@ public Collection getInductivityClauses(final List pre return result; } + private Term getNonCommutativityConstraint(final HcSleepVar sv, final Term locVar, + final IIcfgTransition currentEdge) { + + final var nonCommLocations = new HashSet(); + for (final var loc : mThreadLocations.get(sv.getThreadTemplateName())) { + if (loc.getOutgoingEdges().stream() + .anyMatch(edge -> mIndependence.isIndependent(null, edge, currentEdge) != Dependence.INDEPENDENT)) { + nonCommLocations.add(getLocIndexTerm(loc, sv.getThreadTemplateName())); + } + } + + nonCommLocations.stream().map(loc -> SmtUtils.binaryEquality(getScript(), locVar, loc)) + .collect(Collectors.toList()); + return SmtUtils.and(getScript(), nonCommLocations.stream() + .map(loc -> SmtUtils.binaryEquality(getScript(), locVar, loc)).collect(Collectors.toList())); + } + public Collection getInductivityClauses(final IIcfgTransition edge) { return getInductivityClauses(List.of(edge.getSource()), edge, List.of(edge.getTarget())); } + public HornClause getIdUniquenessClause() { + final var bodyArgs = getDefaultArgs(); + final var constraints = new ArrayList(); + + final var instances = mNumberOfThreads.entrySet().stream() + .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) + .collect(Collectors.toList()); + + for (int i = 0; i < instances.size(); ++i) { + final var first = instances.get(i); + final var firstIndex = + mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + final var firstId = bodyArgs.get(firstIndex); + + for (int j = i + 1; j < instances.size(); ++j) { + final var second = instances.get(j); + final var secondIndex = mPositions2Vars.inverse() + .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + final var secondId = bodyArgs.get(secondIndex); + + constraints.add(SmtUtils.binaryEquality(getScript(), firstId, secondId)); + } + } + + return new HornClause(mManagedScript, mHcSymbolTable, SmtUtils.or(getScript(), constraints), + List.of(mPredicate), List.of(bodyArgs), Set.copyOf(mDefaultHeadVars)); + } + public HornClause getNonInterferenceClause(final IIcfgTransition edge) { final String procedure = edge.getPrecedingProcedure(); final int n = mNumberOfThreads.get(procedure); @@ -392,6 +594,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { final TransFormula transformula = edge.getTransformula(); final Map substitution = new HashMap<>(); final Set bodyVars = new HashSet<>(); + final var constraints = new ArrayList(); for (final var entry : mPositions2Vars.entrySet()) { final int index = entry.getKey(); final IHcReplacementVar rv = entry.getValue(); @@ -442,10 +645,96 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { bodyArguments.get(i + 1).set(newIndex, loc); } } + } else if (rv instanceof HcSleepVar) { + final var sv = (HcSleepVar) rv; + final var oldSleep = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); + bodyVars.add(oldSleep); + + // insert the variable in each body clause (in one, it may be replaced below by the interfering thread) + for (int i = 0; i <= n; ++i) { + bodyArguments.get(i).set(index, oldSleep.getTerm()); + } + + final var newSleep = mDefaultHeadVars.get(index); + + final var hcLoc = new HcLocationVar(sv.getThreadTemplateName(), sv.getInstanceIndex(), getIntSort()); + final int locIndex = mPositions2Vars.inverse().get(hcLoc); + final var locVar = mDefaultHeadVars.get(locIndex); + + final var currentId = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), + new HcThreadIdVar(getScript(), procedure, -1)); + bodyVars.add(currentId); + final var otherId = mDefaultHeadVars.get(mPositions2Vars.inverse() + .get(new HcThreadIdVar(getScript(), sv.getThreadTemplateName(), sv.getInstanceIndex()))); + + // update sleep variable depending on commutativity and thread ID ordering + final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar.getTerm(), edge); + constraints.add(SmtUtils.binaryBooleanEquality(getScript(), + SmtUtils.binaryEquality(getScript(), newSleep.getTerm(), numeral(0)), + SmtUtils.or(getScript(), + SmtUtils.and(getScript(), + SmtUtils.greater(getScript(), otherId.getTerm(), currentId.getTerm()), + SmtUtils.binaryEquality(getScript(), oldSleep.getTerm(), numeral(0))), + nonCommConstr))); + + // special case: add the constraint that the interfering thread does not sleep + if (sv.getThreadTemplateName().equals(procedure)) { + final var bodyVar = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, sv.getSort(), sv); + bodyVars.add(bodyVar); + + // for each non-interference premise, insert the variable in the index for the interfering thread + for (int i = 0; i < n; ++i) { + final int newIndex = mPositions2Vars.inverse() + .get(new HcSleepVar(getScript(), sv.getThreadTemplateName(), i)); + bodyArguments.get(i + 1).set(newIndex, bodyVar.getTerm()); + } + + // add constraint ensuring that the interfering thread is not sleeping + constraints.add(SmtUtils.binaryEquality(getScript(), bodyVar.getTerm(), numeral(0))); + } + continue; + } else if (rv instanceof HcThreadIdVar) { + final var iv = (HcThreadIdVar) rv; + if (iv.getThreadTemplateName().equals(procedure)) { + final var id = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), + new HcThreadIdVar(getScript(), procedure, -1)); + bodyVars.add(id); + for (int i = 0; i < n; ++i) { + final var newIndex = mPositions2Vars.inverse() + .get(new HcSleepVar(getScript(), iv.getThreadTemplateName(), i)); + bodyArguments.get(i + 1).set(newIndex, id.getTerm()); + } + } } else { throw new UnsupportedOperationException("Unknown kind of variable: " + rv); } } + + // add ID constraints + final var instances = mNumberOfThreads.entrySet().stream() + .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) + .collect(Collectors.toList()); + final var interferingId = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), + new HcThreadIdVar(getScript(), procedure, -1)); + assert bodyVars.contains(interferingId); + for (int i = 0; i < instances.size(); ++i) { + final var first = instances.get(i); + final var firstIndex = + mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + final var firstId = mDefaultHeadVars.get(firstIndex); + + for (int j = i + 1; j < instances.size(); ++j) { + final var second = instances.get(j); + final var secondIndex = mPositions2Vars.inverse() + .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + final var secondId = mDefaultHeadVars.get(secondIndex); + + constraints.add(SmtUtils.less(getScript(), firstId.getTerm(), secondId.getTerm())); + } + + constraints.add(SmtUtils.distinct(getScript(), interferingId.getTerm(), firstId.getTerm())); + } + // Replace all other variables with aux-vars final Term formula = transformula.getFormula(); for (final TermVariable v : formula.getFreeVars()) { @@ -457,8 +746,8 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { substitution.put(v, auxVar.getTerm()); bodyVars.add(auxVar); } - return constructHornClause(Substitution.apply(mManagedScript, substitution, transformula.getFormula()), - bodyArguments, bodyVars); + constraints.add(Substitution.apply(mManagedScript, substitution, transformula.getFormula())); + return constructHornClause(SmtUtils.and(getScript(), constraints), bodyArguments, bodyVars); } public interface IHcReplacementVar { From f9675a1d73d2ff352d15787b8c3ac2d768db4a0b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 4 Apr 2023 11:15:46 +0200 Subject: [PATCH 003/114] add common interface for variables specific to a thread instance --- .../icfgtochc/concurrent/HcLocalVar.java | 30 ++--- .../icfgtochc/concurrent/HcLocationVar.java | 33 +++-- .../icfgtochc/concurrent/HcSleepVar.java | 28 ++-- .../icfgtochc/concurrent/HcThreadIdVar.java | 28 ++-- .../concurrent/IHcThreadSpecificVar.java | 43 ++++++ .../concurrent/IcfgToChcConcurrent.java | 124 +++++++++--------- .../icfgtochc/concurrent/ThreadInstance.java | 67 ++++++++++ 7 files changed, 230 insertions(+), 123 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java index 99518a0d3da..67b67e4e849 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java @@ -4,32 +4,28 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; /** * * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) * */ -public class HcLocalVar implements IHcReplacementVar { +public class HcLocalVar implements IHcThreadSpecificVar { private final IProgramVar mVariable; - private final int mIndex; + private final ThreadInstance mInstance; - public HcLocalVar(final IProgramVar variable, final int index) { + public HcLocalVar(final IProgramVar variable, final int instanceNumber) { mVariable = variable; - mIndex = index; + mInstance = new ThreadInstance(mVariable.getProcedure(), instanceNumber); } public IProgramVar getVariable() { return mVariable; } - public int getIndex() { - return mIndex; - } - - public String getProcedure() { - return mVariable.getProcedure(); + @Override + public ThreadInstance getThreadInstance() { + return mInstance; } @Override @@ -39,12 +35,13 @@ public Sort getSort() { @Override public String toString() { - return IcfgToChcConcurrentUtils.getReadableString(mVariable) + (mIndex + 1); + return IcfgToChcConcurrentUtils.getReadableString(mVariable) + (mInstance.getInstanceNumber() + 1); } @Override public int hashCode() { - return Objects.hash(mIndex, mVariable); + final int prime = 97; + return prime * Objects.hash(mInstance, mVariable); } @Override @@ -52,10 +49,13 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof HcLocalVar)) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { return false; } final HcLocalVar other = (HcLocalVar) obj; - return mIndex == other.mIndex && mVariable.equals(other.mVariable); + return Objects.equals(mInstance, other.mInstance) && Objects.equals(mVariable, other.mVariable); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java index f5e59644502..f1fe01879c0 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java @@ -3,30 +3,24 @@ import java.util.Objects; import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; /** * * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) * */ -public class HcLocationVar implements IHcReplacementVar { - private final String mProcedure; - private final int mIndex; +public class HcLocationVar implements IHcThreadSpecificVar { + private final ThreadInstance mInstance; private final Sort mSort; - public HcLocationVar(final String procedure, final int index, final Sort sort) { - mProcedure = procedure; - mIndex = index; + public HcLocationVar(final ThreadInstance instance, final Sort sort) { + mInstance = instance; mSort = sort; } - public String getProcedure() { - return mProcedure; - } - - public int getIndex() { - return mIndex; + @Override + public ThreadInstance getThreadInstance() { + return mInstance; } @Override @@ -36,12 +30,14 @@ public Sort getSort() { @Override public String toString() { - return "loc_" + IcfgToChcConcurrentUtils.getReadableString(mProcedure) + "_" + (mIndex + 1); + return "loc_" + IcfgToChcConcurrentUtils.getReadableString(mInstance.getTemplateName()) + "_" + + (mInstance.getInstanceNumber() + 1); } @Override public int hashCode() { - return Objects.hash(mIndex, mProcedure); + final int prime = 79; + return prime * Objects.hash(mInstance); } @Override @@ -49,10 +45,13 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof HcLocationVar)) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { return false; } final HcLocationVar other = (HcLocationVar) obj; - return mIndex == other.mIndex && mProcedure.equals(other.mProcedure); + return Objects.equals(mInstance, other.mInstance); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index bed131eeceb..e222bef9ebd 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -30,19 +30,16 @@ import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; -public class HcSleepVar implements IHcReplacementVar { +public class HcSleepVar implements IHcThreadSpecificVar { private static final String SORT = "Int"; private final Sort mSort; - private final String mThreadTemplateName; - private final int mInstanceIndex; + private final ThreadInstance mInstance; - public HcSleepVar(final Script script, final String threadTemplateName, final int instanceIndex) { + public HcSleepVar(final ThreadInstance instance, final Script script) { + mInstance = instance; mSort = script.sort(SORT); - mThreadTemplateName = threadTemplateName; - mInstanceIndex = instanceIndex; } @Override @@ -50,22 +47,21 @@ public Sort getSort() { return mSort; } - public String getThreadTemplateName() { - return mThreadTemplateName; - } - - public int getInstanceIndex() { - return mInstanceIndex; + @Override + public ThreadInstance getThreadInstance() { + return mInstance; } @Override public String toString() { - return "sleep_" + IcfgToChcConcurrentUtils.getReadableString(mThreadTemplateName) + "_" + (mInstanceIndex + 1); + return "sleep_" + IcfgToChcConcurrentUtils.getReadableString(mInstance.getTemplateName()) + "_" + + (mInstance.getInstanceNumber() + 1); } @Override public int hashCode() { - return Objects.hash(mInstanceIndex, mThreadTemplateName); + final int prime = 31; + return prime * Objects.hash(mInstance); } @Override @@ -80,6 +76,6 @@ public boolean equals(final Object obj) { return false; } final HcSleepVar other = (HcSleepVar) obj; - return mInstanceIndex == other.mInstanceIndex && Objects.equals(mThreadTemplateName, other.mThreadTemplateName); + return Objects.equals(mInstance, other.mInstance); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java index 2c452d52bde..fa8c35b2296 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java @@ -30,19 +30,16 @@ import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; -public class HcThreadIdVar implements IHcReplacementVar { +public class HcThreadIdVar implements IHcThreadSpecificVar { private static final String SORT = "Int"; private final Sort mSort; - private final String mThreadTemplateName; - private final int mInstanceIndex; + private final ThreadInstance mInstance; - public HcThreadIdVar(final Script script, final String threadTemplateName, final int instanceIndex) { + public HcThreadIdVar(final ThreadInstance instance, final Script script) { + mInstance = instance; mSort = script.sort(SORT); - mThreadTemplateName = threadTemplateName; - mInstanceIndex = instanceIndex; } @Override @@ -50,22 +47,21 @@ public Sort getSort() { return mSort; } - public String getThreadTemplateName() { - return mThreadTemplateName; - } - - public int getInstanceIndex() { - return mInstanceIndex; + @Override + public ThreadInstance getThreadInstance() { + return mInstance; } @Override public String toString() { - return "id_" + IcfgToChcConcurrentUtils.getReadableString(mThreadTemplateName) + "_" + (mInstanceIndex + 1); + return "id_" + IcfgToChcConcurrentUtils.getReadableString(mInstance.getTemplateName()) + "_" + + (mInstance.getInstanceNumber() + 1); } @Override public int hashCode() { - return Objects.hash(mInstanceIndex, mThreadTemplateName); + final int prime = 59; + return prime * Objects.hash(mInstance); } @Override @@ -80,6 +76,6 @@ public boolean equals(final Object obj) { return false; } final HcThreadIdVar other = (HcThreadIdVar) obj; - return mInstanceIndex == other.mInstanceIndex && Objects.equals(mThreadTemplateName, other.mThreadTemplateName); + return Objects.equals(mInstance, other.mInstance); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java new file mode 100644 index 00000000000..8f537d5efcb --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; + +public interface IHcThreadSpecificVar extends IHcReplacementVar { + ThreadInstance getThreadInstance(); + + @Deprecated + default String getThreadTemplateName() { + return getThreadInstance().getTemplateName(); + } + + @Deprecated + default int getInstanceIndex() { + return getThreadInstance().getInstanceNumber(); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java index 3f3960fa6cc..d5ff0155fdc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java @@ -41,7 +41,6 @@ import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; -import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; /** * Class to create horn-clauses for given edges to create thread-modular proofs. @@ -51,6 +50,7 @@ */ public class IcfgToChcConcurrent { private static final String FUNCTION_NAME = "Inv"; + private static final int INTERFERING_INSTANCE_ID = -1; private final ManagedScript mManagedScript; @@ -138,20 +138,22 @@ private void initializeDefaultVars(final Collection globalVariables final String proc = entry.getKey(); final List localVars = localVariables.get(proc); for (int j = 0; j < entry.getValue(); j++) { + final var instance = new ThreadInstance(proc, j); + // thread ID - final var id = new HcThreadIdVar(getScript(), proc, j); + final var id = new HcThreadIdVar(instance, getScript()); mIdVars.put(proc, j, id); mPositions2Vars.put(i, id); i++; // Location - final var loc = new HcLocationVar(proc, j, getIntSort()); + final var loc = new HcLocationVar(instance, getIntSort()); mLocationsVars.put(proc, j, loc); mPositions2Vars.put(i, loc); i++; // sleep set - final var sleep = new HcSleepVar(getScript(), proc, j); + final var sleep = new HcSleepVar(instance, getScript()); mSleepVars.put(proc, j, sleep); mPositions2Vars.put(i, sleep); i++; @@ -190,18 +192,34 @@ private Term getLocIndexTerm(final IcfgLocation loc, final String proc) { return numeral(index); } - // pc_0 = l_0 -> Inv(pc_0, ...) - public HornClause getInitialClause(final Collection initialLocations) { - final NestedMap2 locationMap = new NestedMap2<>(); + private Collection getInstances(final String template) { + final var result = new ArrayList(); + for (int i = 0; i < mNumberOfThreads.get(template); i++) { + result.add(new ThreadInstance(template, i)); + } + return result; + } + + private List getInstances() { + final var result = new ArrayList(); for (final Entry entry : mNumberOfThreads.entrySet()) { for (int i = 0; i < entry.getValue(); i++) { - locationMap.put(entry.getKey(), i, mBottomLocation); + result.add(new ThreadInstance(entry.getKey(), i)); } } + return result; + } + + // pc_0 = l_0 -> Inv(pc_0, ...) + public HornClause getInitialClause(final Collection initialLocations) { + final Map locationMap = new HashMap<>(); + for (final var instance : getInstances()) { + locationMap.put(instance, mBottomLocation); + } for (final IcfgLocation loc : initialLocations) { final String proc = loc.getProcedure(); for (int i = 0; i < mNumberOfThreads.get(proc); i++) { - locationMap.put(proc, i, getLocIndexTerm(loc, proc)); + locationMap.put(new ThreadInstance(proc, i), getLocIndexTerm(loc, proc)); } } final var locConstraint = getConstraintFromLocationMap(locationMap); @@ -263,10 +281,10 @@ private HornClause constructHornClause(final Term constraint, final List locationMap) { + private Term getConstraintFromLocationMap(final Map locationMap) { final List constraints = new ArrayList<>(); - for (final var triple : locationMap.entrySet()) { - final var constraint = getLocationConstraint(triple.getFirst(), triple.getSecond(), triple.getThird()); + for (final var pair : locationMap.entrySet()) { + final var constraint = getLocationConstraint(pair.getKey(), pair.getValue()); constraints.add(constraint); } return SmtUtils.and(getScript(), constraints); @@ -278,8 +296,8 @@ private Term getConstraintFromLocationMap(final NestedMap2 getSafetyClauses(final Collection er final List bodyArgs = getDefaultArgs(); for (final IcfgLocation loc : errorLocations) { final String proc = loc.getProcedure(); - for (int i = 0; i < mNumberOfThreads.get(proc); i++) { - final Term constraint = getLocationConstraint(proc, i, getLocIndexTerm(loc, proc)); + for (final var instance : getInstances(proc)) { + final Term constraint = getLocationConstraint(instance, getLocIndexTerm(loc, proc)); result.add(new HornClause(mManagedScript, mHcSymbolTable, constraint, List.of(mPredicate), List.of(bodyArgs), vars)); } @@ -369,7 +387,7 @@ public Collection getInductivityClauses(final List pre IProgramVar pv = null; if (rv instanceof HcLocalVar) { final HcLocalVar lv = (HcLocalVar) rv; - if (!Objects.equals(indexMap.get(lv.getProcedure()), lv.getIndex())) { + if (!Objects.equals(indexMap.get(lv.getThreadTemplateName()), lv.getInstanceIndex())) { continue; } pv = lv.getVariable(); @@ -378,8 +396,8 @@ public Collection getInductivityClauses(final List pre pv = gv.getVariable(); } else if (rv instanceof HcLocationVar) { final HcLocationVar lv = (HcLocationVar) rv; - final String procedure = lv.getProcedure(); - final int instanceIndex = lv.getIndex(); + final String procedure = lv.getThreadTemplateName(); + final int instanceIndex = lv.getInstanceIndex(); Term locIn = locMapIn.get(procedure, instanceIndex); Term locOut = locMapOut.get(procedure, instanceIndex); if (locIn == null && locOut == null) { @@ -416,15 +434,14 @@ public Collection getInductivityClauses(final List pre bodyArgs.set(index, oldSleep.getTerm()); final var newSleep = mDefaultHeadVars.get(index).getTerm(); - final var hcLoc = - new HcLocationVar(sv.getThreadTemplateName(), sv.getInstanceIndex(), getIntSort()); + final var hcLoc = new HcLocationVar(sv.getThreadInstance(), getIntSort()); final int locIndex = mPositions2Vars.inverse().get(hcLoc); final var locVar = mDefaultHeadVars.get(locIndex); - final var currentId = mDefaultHeadVars.get(mPositions2Vars.inverse() - .get(new HcThreadIdVar(getScript(), activeProcedure, activeInstanceIndex))); - final var otherId = mDefaultHeadVars.get(mPositions2Vars.inverse().get( - new HcThreadIdVar(getScript(), sv.getThreadTemplateName(), sv.getInstanceIndex()))); + final var currentId = mDefaultHeadVars.get(mPositions2Vars.inverse().get(new HcThreadIdVar( + new ThreadInstance(activeProcedure, activeInstanceIndex), getScript()))); + final var otherId = mDefaultHeadVars.get( + mPositions2Vars.inverse().get(new HcThreadIdVar(sv.getThreadInstance(), getScript()))); // update sleep variable depending on commutativity and thread ID ordering final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar.getTerm(), edge); @@ -498,19 +515,15 @@ public Collection getInductivityClauses(final List pre } // add ID constraints - final var instances = mNumberOfThreads.entrySet().stream() - .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) - .collect(Collectors.toList()); + final var instances = getInstances(); for (int i = 0; i < instances.size(); ++i) { final var first = instances.get(i); - final var firstIndex = - mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + final var firstIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(first, getScript())); final var firstId = mDefaultHeadVars.get(firstIndex); for (int j = i + 1; j < instances.size(); ++j) { final var second = instances.get(j); - final var secondIndex = mPositions2Vars.inverse() - .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + final var secondIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(second, getScript())); final var secondId = mDefaultHeadVars.get(secondIndex); constraints.add(SmtUtils.less(getScript(), firstId.getTerm(), secondId.getTerm())); @@ -560,20 +573,15 @@ public HornClause getIdUniquenessClause() { final var bodyArgs = getDefaultArgs(); final var constraints = new ArrayList(); - final var instances = mNumberOfThreads.entrySet().stream() - .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) - .collect(Collectors.toList()); - + final var instances = getInstances(); for (int i = 0; i < instances.size(); ++i) { final var first = instances.get(i); - final var firstIndex = - mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + final var firstIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(first, getScript())); final var firstId = bodyArgs.get(firstIndex); for (int j = i + 1; j < instances.size(); ++j) { final var second = instances.get(j); - final var secondIndex = mPositions2Vars.inverse() - .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + final var secondIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(second, getScript())); final var secondId = bodyArgs.get(secondIndex); constraints.add(SmtUtils.binaryEquality(getScript(), firstId, secondId)); @@ -586,6 +594,8 @@ public HornClause getIdUniquenessClause() { public HornClause getNonInterferenceClause(final IIcfgTransition edge) { final String procedure = edge.getPrecedingProcedure(); + final var interferingThread = new ThreadInstance(procedure, INTERFERING_INSTANCE_ID); + final int n = mNumberOfThreads.get(procedure); final List> bodyArguments = new ArrayList<>(); for (int i = 0; i <= n; i++) { @@ -600,7 +610,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { final IHcReplacementVar rv = entry.getValue(); if (rv instanceof HcLocalVar) { final HcLocalVar lv = (HcLocalVar) rv; - if (lv.getProcedure().equals(procedure)) { + if (lv.getThreadTemplateName().equals(procedure)) { final IProgramVar pv = lv.getVariable(); final TermVariable inVar = transformula.getInVars().get(pv); final TermVariable outVar = transformula.getOutVars().get(pv); @@ -637,11 +647,11 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { } } else if (rv instanceof HcLocationVar) { final HcLocationVar lv = (HcLocationVar) rv; - if (lv.getProcedure().equals(procedure)) { + if (lv.getThreadTemplateName().equals(procedure)) { final Term loc = getLocIndexTerm(edge.getSource(), procedure); for (int i = 0; i < n; i++) { - final int newIndex = - mPositions2Vars.inverse().get(new HcLocationVar(procedure, i, getIntSort())); + final int newIndex = mPositions2Vars.inverse() + .get(new HcLocationVar(new ThreadInstance(procedure, i), getIntSort())); bodyArguments.get(i + 1).set(newIndex, loc); } } @@ -657,15 +667,15 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { final var newSleep = mDefaultHeadVars.get(index); - final var hcLoc = new HcLocationVar(sv.getThreadTemplateName(), sv.getInstanceIndex(), getIntSort()); + final var hcLoc = new HcLocationVar(sv.getThreadInstance(), getIntSort()); final int locIndex = mPositions2Vars.inverse().get(hcLoc); final var locVar = mDefaultHeadVars.get(locIndex); final var currentId = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), - new HcThreadIdVar(getScript(), procedure, -1)); + new HcThreadIdVar(interferingThread, getScript())); bodyVars.add(currentId); - final var otherId = mDefaultHeadVars.get(mPositions2Vars.inverse() - .get(new HcThreadIdVar(getScript(), sv.getThreadTemplateName(), sv.getInstanceIndex()))); + final var otherId = mDefaultHeadVars + .get(mPositions2Vars.inverse().get(new HcThreadIdVar(sv.getThreadInstance(), getScript()))); // update sleep variable depending on commutativity and thread ID ordering final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar.getTerm(), edge); @@ -685,7 +695,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { // for each non-interference premise, insert the variable in the index for the interfering thread for (int i = 0; i < n; ++i) { final int newIndex = mPositions2Vars.inverse() - .get(new HcSleepVar(getScript(), sv.getThreadTemplateName(), i)); + .get(new HcSleepVar(new ThreadInstance(sv.getThreadTemplateName(), i), getScript())); bodyArguments.get(i + 1).set(newIndex, bodyVar.getTerm()); } @@ -697,11 +707,11 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { final var iv = (HcThreadIdVar) rv; if (iv.getThreadTemplateName().equals(procedure)) { final var id = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), - new HcThreadIdVar(getScript(), procedure, -1)); + new HcThreadIdVar(interferingThread, getScript())); bodyVars.add(id); for (int i = 0; i < n; ++i) { final var newIndex = mPositions2Vars.inverse() - .get(new HcSleepVar(getScript(), iv.getThreadTemplateName(), i)); + .get(new HcSleepVar(new ThreadInstance(iv.getThreadTemplateName(), i), getScript())); bodyArguments.get(i + 1).set(newIndex, id.getTerm()); } } @@ -711,22 +721,18 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { } // add ID constraints - final var instances = mNumberOfThreads.entrySet().stream() - .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) - .collect(Collectors.toList()); + final var instances = getInstances(); final var interferingId = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), - new HcThreadIdVar(getScript(), procedure, -1)); + new HcThreadIdVar(interferingThread, getScript())); assert bodyVars.contains(interferingId); for (int i = 0; i < instances.size(); ++i) { final var first = instances.get(i); - final var firstIndex = - mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); + final var firstIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(first, getScript())); final var firstId = mDefaultHeadVars.get(firstIndex); for (int j = i + 1; j < instances.size(); ++j) { final var second = instances.get(j); - final var secondIndex = mPositions2Vars.inverse() - .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); + final var secondIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(second, getScript())); final var secondId = mDefaultHeadVars.get(secondIndex); constraints.add(SmtUtils.less(getScript(), firstId.getTerm(), secondId.getTerm())); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java new file mode 100644 index 00000000000..346ba360d35 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Objects; + +public final class ThreadInstance { + private final String mTemplateName; + private final int mInstanceNumber; + + public ThreadInstance(final String templateName, final int instanceNumber) { + mTemplateName = templateName; + mInstanceNumber = instanceNumber; + } + + public String getTemplateName() { + return mTemplateName; + } + + public int getInstanceNumber() { + return mInstanceNumber; + } + + @Override + public int hashCode() { + return Objects.hash(mInstanceNumber, mTemplateName); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ThreadInstance other = (ThreadInstance) obj; + return mInstanceNumber == other.mInstanceNumber && Objects.equals(mTemplateName, other.mTemplateName); + } +} From ddc58b651c8475592ac82eac1347b611c313e551 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 4 Apr 2023 11:22:56 +0200 Subject: [PATCH 004/114] more simplification with ThreadInstance --- .../concurrent/IcfgToChcConcurrent.java | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java index d5ff0155fdc..fe77f051321 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java @@ -71,9 +71,9 @@ public class IcfgToChcConcurrent { // these variables are always used in the head of any clause generated by this class private final List mDefaultHeadVars; - private final NestedMap2 mSleepVars = new NestedMap2<>(); - private final NestedMap2 mLocationsVars = new NestedMap2<>(); - private final NestedMap2 mIdVars = new NestedMap2<>(); + private final Map mSleepVars = new HashMap<>(); + private final Map mLocationsVars = new HashMap<>(); + private final Map mIdVars = new HashMap<>(); private final Map> mThreadLocations; @@ -127,41 +127,34 @@ private HcHeadVar constructHeadVar(final IHcReplacementVar rv, final int index) return mHcSymbolTable.getOrConstructHeadVar(mPredicate, index, rv.getSort(), rv); } + private void addVariable(final IHcReplacementVar variable) { + mPositions2Vars.put(mPositions2Vars.size(), variable); + } + private void initializeDefaultVars(final Collection globalVariables, final Map> localVariables) { - int i = 0; for (final IProgramVar v : globalVariables) { - mPositions2Vars.put(i, new HcGlobalVar(v)); - i++; + addVariable(new HcGlobalVar(v)); } - for (final Entry entry : mNumberOfThreads.entrySet()) { - final String proc = entry.getKey(); - final List localVars = localVariables.get(proc); - for (int j = 0; j < entry.getValue(); j++) { - final var instance = new ThreadInstance(proc, j); - - // thread ID - final var id = new HcThreadIdVar(instance, getScript()); - mIdVars.put(proc, j, id); - mPositions2Vars.put(i, id); - i++; - - // Location - final var loc = new HcLocationVar(instance, getIntSort()); - mLocationsVars.put(proc, j, loc); - mPositions2Vars.put(i, loc); - i++; - - // sleep set - final var sleep = new HcSleepVar(instance, getScript()); - mSleepVars.put(proc, j, sleep); - mPositions2Vars.put(i, sleep); - i++; - - for (final IProgramVar v : localVars) { - mPositions2Vars.put(i, new HcLocalVar(v, j)); - i++; - } + for (final var instance : getInstances()) { + // thread ID + final var id = new HcThreadIdVar(instance, getScript()); + mIdVars.put(instance, id); + addVariable(id); + + // Location + final var loc = new HcLocationVar(instance, getIntSort()); + mLocationsVars.put(instance, loc); + addVariable(loc); + + // sleep set + final var sleep = new HcSleepVar(instance, getScript()); + mSleepVars.put(instance, sleep); + addVariable(sleep); + + final List localVars = localVariables.get(instance.getTemplateName()); + for (final IProgramVar v : localVars) { + addVariable(new HcLocalVar(v, instance.getInstanceNumber())); } } } @@ -245,7 +238,7 @@ public HornClause getInitialClause(final Collection initialLocatio // } // sleep set initially empty - final var sleepConstraints = mSleepVars.values() + final var sleepConstraints = mSleepVars.values().stream() .map(sv -> SmtUtils.binaryEquality(getScript(), mDefaultHeadVars.get(mPositions2Vars.inverse().get(sv)).getTerm(), numeral(0))) .collect(Collectors.toList()); From 7d637c5e1b15701950e9ce2f3a74caec509f9b9a Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 5 Apr 2023 11:34:50 +0200 Subject: [PATCH 005/114] new implementation of Horn clause generation for thread-modular proofs This new implementation is meant to be easier to understand, extensible and modular. As an example, see the included implementation of sleep set reduction in the Horn clauses. The implementation is not yet completely finished, a few TODOs remain. --- .../ExtensibleHornClauseProvider.java | 74 +++ .../concurrent/HornClauseBuilder.java | 138 ++++++ .../icfgtochc/concurrent/PredicateInfo.java | 87 ++++ ...eepSetThreadModularHornClauseProvider.java | 230 +++++++++ .../ThreadModularHornClauseProvider.java | 437 ++++++++++++++++++ 5 files changed, 966 insertions(+) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java new file mode 100644 index 00000000000..2f39c1d3b0e --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.math.BigInteger; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +public abstract class ExtensibleHornClauseProvider { + protected final ManagedScript mManagedScript; + protected final Script mScript; + protected final HcSymbolTable mSymbolTable; + + public ExtensibleHornClauseProvider(final ManagedScript mgdScript, final HcSymbolTable symbolTable) { + mManagedScript = mgdScript; + mScript = mgdScript.getScript(); + mSymbolTable = symbolTable; + } + + protected final HornClauseBuilder createBuilder(final PredicateInfo predicate) { + return new HornClauseBuilder(mManagedScript, mSymbolTable, Objects.requireNonNull(predicate)); + } + + protected final HornClauseBuilder createBuilder() { + return new HornClauseBuilder(mManagedScript, mSymbolTable); + } + + protected abstract List buildAllClauses(); + + public final List getClauses() { + return buildAllClauses().stream().map(HornClauseBuilder::build).collect(Collectors.toList()); + } + + protected final Term numeral(final long n) { + return mScript.numeral(BigInteger.valueOf(n)); + } + + protected Sort getIntSort() { + return SmtSortUtils.getIntSort(mScript); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java new file mode 100644 index 00000000000..b749a817fba --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import de.uni_freiburg.informatik.ultimate.lib.chc.HcBodyVar; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcHeadVar; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcVar; +import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; +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.Substitution; +import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.logic.TermVariable; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; + +public class HornClauseBuilder { + private final ManagedScript mManagedScript; + private final HcSymbolTable mSymbolTable; + private final PredicateInfo mHeadPredicate; + + private final Map mSubstitution = new HashMap<>(); + private final List mBodyPreds = new ArrayList<>(); + private final List> mBodyArgs = new ArrayList<>(); + private final List mConstraints = new ArrayList<>(); + private final Set mBodyVars = new HashSet<>(); + + public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symbolTable, + final PredicateInfo headPredicate) { + mManagedScript = mgdScript; + mSymbolTable = symbolTable; + mHeadPredicate = headPredicate; + } + + public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symbolTable) { + this(mgdScript, symbolTable, null); + } + + public HcBodyVar getFreshBodyVar(final Object identifier, final Sort sort) { + // TODO Using the number of bodyVars as index is a hack! + // TODO suitable parameters for getOrConstructBodyVar + final HcBodyVar auxVar = mSymbolTable.getOrConstructBodyVar(null, mBodyVars.size(), sort, identifier); + mBodyVars.add(auxVar); + return auxVar; + } + + public HcBodyVar getBodyVar(final IHcReplacementVar variable) { + // TODO suitable parameters for getOrConstructBodyVar + final var result = mSymbolTable.getOrConstructBodyVar(null, -1, variable.getSort(), variable); + mBodyVars.add(result); + return result; + } + + public HcHeadVar getHeadVar(final IHcReplacementVar variable) { + // TODO + assert mHeadPredicate.hasParameter(variable); + return null; + } + + public void sameBodyHeadVar(final IHcReplacementVar variable) { + mSubstitution.put(getBodyVar(variable).getTermVariable(), getHeadVar(variable).getTerm()); + } + + public List getDefaultBodyArgs(final PredicateInfo predicate) { + return IntStream.range(0, predicate.getParamCount()) + .mapToObj(i -> getBodyVar(predicate.getParameter(i)).getTerm()) + .collect(Collectors.toCollection(ArrayList::new)); + } + + public void addBodyPredicate(final PredicateInfo predicate, final List arguments) { + mBodyPreds.add(predicate.getPredicate()); + mBodyArgs.add(arguments); + } + + public void addConstraint(final Term term) { + mConstraints.add(term); + } + + public HornClause build() { + final var constraint = getSubstitutedConstraint(); + + final var substitutedBodyArgs = new ArrayList>(mBodyArgs.size()); + for (final var args : mBodyArgs) { + substitutedBodyArgs.add(args.stream().map(this::substitute).collect(Collectors.toList())); + } + + return new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, mBodyVars); + } + + private Term substitute(final Term term) { + if (mSubstitution.isEmpty()) { + return term; + } + return Substitution.apply(mManagedScript, mSubstitution, term); + } + + private Term getSubstitutedConstraint() { + if (mConstraints.isEmpty()) { + return null; + } + return substitute(SmtUtils.and(mManagedScript.getScript(), mConstraints)); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java new file mode 100644 index 00000000000..ff5d091ebaf --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Objects; + +import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; +import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; + +public class PredicateInfo { + private final HcPredicateSymbol mPredicate; + private final BidirectionalMap mVariable2Index; + + public PredicateInfo(final HcPredicateSymbol predicate, + final BidirectionalMap variable2Index) { + mPredicate = predicate; + mVariable2Index = variable2Index; + } + + public HcPredicateSymbol getPredicate() { + return mPredicate; + } + + public boolean hasParameter(final IHcReplacementVar variable) { + return mVariable2Index.containsKey(variable); + } + + public int getIndex(final IHcReplacementVar variable) { + assert mVariable2Index.containsKey(variable); + return mVariable2Index.get(variable); + } + + public IHcReplacementVar getParameter(final int index) { + final var result = mVariable2Index.inverse().get(index); + assert result != null; + return result; + } + + public int getParamCount() { + return mVariable2Index.size(); + } + + @Override + public int hashCode() { + return Objects.hash(mPredicate, mVariable2Index); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PredicateInfo other = (PredicateInfo) obj; + return Objects.equals(mPredicate, other.mPredicate) && Objects.equals(mVariable2Index, other.mVariable2Index); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java new file mode 100644 index 00000000000..9e9853e6beb --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; +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.variables.IProgramVar; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornClauseProvider { + private final IIndependenceRelation> mIndependence; + private final Map> mThreadLocations; + + private final Map mIdVars = new HashMap<>(); + private final Map mSleepVars = new HashMap<>(); + + public SleepSetThreadModularHornClauseProvider(final Map numberOfThreads, + final ManagedScript mgdScript, final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable symbolTable, + final Predicate variableFilter, final Collection initialLocations, + final Collection errorLocations, + final IIndependenceRelation> independence, + final Map> threadLocations) { + super(numberOfThreads, mgdScript, cfgSmtToolkit, symbolTable, variableFilter, initialLocations, errorLocations); + mIndependence = independence; + mThreadLocations = threadLocations; + } + + @Override + protected List createThreadSpecificVars(final ThreadInstance instance) { + final var result = super.createThreadSpecificVars(instance); + + // thread ID + final var id = new HcThreadIdVar(instance, mScript); + mIdVars.put(instance, id); + result.add(0, id); + + // sleep set + final var sleep = new HcSleepVar(instance, mScript); + mSleepVars.put(instance, sleep); + result.add(1, sleep); + + return result; + } + + @Override + protected HornClauseBuilder buildInitialClause() { + final var clause = super.buildInitialClause(); + + // all sleep variables are initialized to 0 + for (final var instance : mInstances) { + final var sleep = mSleepVars.get(instance); + clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getHeadVar(sleep).getTerm(), numeral(0))); + } + + return clause; + } + + @Override + protected HornClauseBuilder buildInductivityClause(final IIcfgTransition transition, + final Map preds, final Map succs, + final ThreadInstance updatedThread) { + final var clause = super.buildInductivityClause(transition, preds, succs, updatedThread); + + // active threads are not sleeping + for (final var active : preds.keySet()) { + final var sleep = mSleepVars.get(active); + clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getBodyVar(sleep).getTerm(), numeral(0))); + } + + // thread IDs are ordered + ensureThreadOrdering(clause); + + // update sleep variables + for (final var instance : mInstances) { + updateSleepInductive(clause, transition, preds.keySet(), updatedThread, instance); + } + + return clause; + } + + @Override + protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { + final var clause = super.buildNonInterferenceClause(transition); + + final var interferingThread = getInterferingThread(transition); + final var interferingId = new HcThreadIdVar(interferingThread, mScript); + + // thread IDs are ordered + ensureThreadOrdering(clause); + + // ensure interfering thread has distinct thread ID + for (final var instance : mInstances) { + clause.addConstraint(SmtUtils.distinct(mScript, clause.getBodyVar(mIdVars.get(instance)).getTerm(), + clause.getBodyVar(interferingId).getTerm())); + } + + // interfering thread is not sleeping + final var sleep = new HcSleepVar(interferingThread, mScript); + clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getBodyVar(sleep).getTerm(), numeral(0))); + + // update sleep variables + for (final var instance : mInstances) { + updateSleepNonInterference(clause, transition, interferingId, instance); + } + + return clause; + } + + private void ensureThreadOrdering(final HornClauseBuilder clause) { + for (int i = 0; i < mInstances.size(); ++i) { + final var instance = mInstances.get(i); + final var id = mIdVars.get(instance); + + // thread ID must not change + clause.sameBodyHeadVar(id); + + // fix ordering between thread IDs + if (i + 1 < mInstances.size()) { + final var next = mInstances.get(i + 1); + final var nextId = mIdVars.get(next); + clause.addConstraint( + SmtUtils.less(mScript, clause.getBodyVar(id).getTerm(), clause.getBodyVar(nextId).getTerm())); + } + } + } + + // update sleep variable depending on commutativity and thread ID ordering + // Here the ordering can be resolved statically + private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTransition transition, + final Set activeThreads, final ThreadInstance primaryActiveThread, + final ThreadInstance current) { + final var loc = clause.getBodyVar(mLocationVars.get(current)); + final Term nonCommConstr = getNonCommutativityConstraint(current, loc.getTerm(), transition); + + // for now, the preference order is non-positional, and given by the ordering in mInstances + final int ordering = Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(current)); + + if (activeThreads.contains(current)) { + // no update of sleep variable + } else if (ordering < 0) { + // set sleep variable to false / leave unchanged + final var sleep = mSleepVars.get(current); + final var oldSleep = clause.getBodyVar(sleep); + final var newSleep = clause.getHeadVar(sleep); + clause.addConstraint(SmtUtils.ite(mScript, nonCommConstr, + SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), + SmtUtils.binaryEquality(mScript, newSleep.getTerm(), oldSleep.getTerm()))); + } else { + // set sleep variable to false / true + final var sleep = mSleepVars.get(current); + final var newSleep = clause.getHeadVar(sleep); + clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, + SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), nonCommConstr)); + } + } + + // update sleep variable depending on commutativity and thread ID ordering + // Here the ordering can only be resolved at runtime, so we treat it statically + private void updateSleepNonInterference(final HornClauseBuilder clause, final IIcfgTransition transition, + final HcThreadIdVar interferingId, final ThreadInstance current) { + final var oldSleep = clause.getBodyVar(mSleepVars.get(current)); + final var newSleep = clause.getHeadVar(mSleepVars.get(current)); + + final var currentLoc = clause.getBodyVar(mLocationVars.get(current)); + final var currentId = clause.getBodyVar(mIdVars.get(current)); + + final Term nonCommConstr = getNonCommutativityConstraint(current, currentLoc.getTerm(), transition); + clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, + SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), + SmtUtils.or(mScript, + SmtUtils.and(mScript, + SmtUtils.greater(mScript, currentId.getTerm(), + clause.getBodyVar(interferingId).getTerm()), + SmtUtils.binaryEquality(mScript, oldSleep.getTerm(), numeral(0))), + nonCommConstr))); + } + + protected Term getNonCommutativityConstraint(final ThreadInstance instance, final Term locVar, + final IIcfgTransition currentEdge) { + + final var nonCommLocations = new HashSet(); + for (final var loc : mThreadLocations.get(instance.getTemplateName())) { + if (loc.getOutgoingEdges().stream() + .anyMatch(edge -> mIndependence.isIndependent(null, edge, currentEdge) != Dependence.INDEPENDENT)) { + nonCommLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); + } + } + return SmtUtils.and(mScript, nonCommLocations.stream().map(loc -> SmtUtils.binaryEquality(mScript, locVar, loc)) + .collect(Collectors.toList())); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java new file mode 100644 index 00000000000..1b2ae36ffaf --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2022 Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2022-2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; +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.variables.IProgramVar; +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.Substitution; +import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.logic.TermVariable; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; +import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; + +/** + * Generates Horn clauses for a thread-modular proof. + * + * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + */ +public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvider { + private static final String FUNCTION_NAME = "Inv"; + private static final int INTERFERING_INSTANCE_ID = -1; + + private final IIcfgSymbolTable mCfgSymbolTable; + private final Predicate mVariableFilter; + + private final Map mInitialLocations; + private final HashRelation mErrorLocations = new HashRelation<>(); + + // maps a procedure name and a location (in the procedure) to an integer, such that the location variable has this + // integer as value iff control is in the given location + private final NestedMap2 mLocationIndices = new NestedMap2<>(); + + // used as location for threads that are not currently running + private final Term mBottomLocation; + + protected final List mInstances; + + protected final PredicateInfo mInvariantPredicate; + + protected final Set mGlobalVars = new HashSet<>(); + protected final Map> mThreadSpecificVars = new HashMap<>(); + protected final Map mLocationVars = new HashMap<>(); + protected final NestedMap2 mLocalVars = new NestedMap2<>(); + + public ThreadModularHornClauseProvider(final Map numberOfThreads, final ManagedScript mgdScript, + final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable symbolTable, + final Predicate variableFilter, final Collection initialLocations, + final Collection errorLocations) { + super(mgdScript, symbolTable); + mCfgSymbolTable = cfgSmtToolkit.getSymbolTable(); + mVariableFilter = variableFilter; + mBottomLocation = numeral(-1); + mInstances = getInstances(numberOfThreads); + mInvariantPredicate = createInvariantPredicate(); + + // TODO also support the non-parametric setting, i.e., only set initial location for ID 0 + mInitialLocations = createInstanceLocationMap(initialLocations); + + for (final IcfgLocation loc : errorLocations) { + for (final var instance : getInstances(loc.getProcedure())) { + mErrorLocations.addPair(instance, loc); + } + } + } + + // Initialization code and variable creation + // ----------------------------------------------------------------------------------------------------------------- + + private static List getInstances(final Map numberOfThreads) { + final var result = new ArrayList(); + for (final var entry : numberOfThreads.entrySet()) { + for (int i = 0; i < entry.getValue(); i++) { + result.add(new ThreadInstance(entry.getKey(), i)); + } + } + return result; + } + + private List getInstances(final String template) { + return mInstances.stream().filter(inst -> inst.getTemplateName().equals(template)).collect(Collectors.toList()); + } + + private Map createInstanceLocationMap(final Collection locations) { + final var result = new HashMap(); + for (final IcfgLocation loc : locations) { + for (final var instance : getInstances(loc.getProcedure())) { + result.put(instance, loc); + } + } + return result; + } + + private PredicateInfo createInvariantPredicate() { + final var parameters = getInvariantParameters(); + + final List sorts = parameters.stream().map(IHcReplacementVar::getSort).collect(Collectors.toList()); + final var predicate = mSymbolTable.getOrConstructHornClausePredicateSymbol(FUNCTION_NAME, sorts); + + final var paramMap = IntStream.range(0, parameters.size()).mapToObj(i -> new Pair<>(parameters.get(i), i)) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue, (i, j) -> i, BidirectionalMap::new)); + + return new PredicateInfo(predicate, paramMap); + } + + /** + * Constructs the sequence of parameters for the invariant predicate. + * + * Subclasses can override this method, or more specific methods below ({@link #createGlobalVars()} or + * {@link #createThreadSpecificVars(ThreadInstance)}), to add additional parameters. + * + * @return A (modifiable) list of parameters. The list must not contain duplicates. + */ + protected List getInvariantParameters() { + final var result = new ArrayList(); + result.addAll(createGlobalVars()); + for (final var instance : mInstances) { + final var threadSpecific = createThreadSpecificVars(instance); + mThreadSpecificVars.put(instance, threadSpecific); + result.addAll(threadSpecific); + } + return result; + } + + /** + * Constructs those parameters of the invariant predicate that correspond to global variables (used by + * {@link #getInvariantParameters()}). + * + * @return A (modifiable) list of parameters. The list must not contain duplicates. + */ + protected List createGlobalVars() { + final var result = new ArrayList(); + for (final var pv : mCfgSymbolTable.getGlobals()) { + if (mVariableFilter.test(pv)) { + final var global = new HcGlobalVar(pv); + mGlobalVars.add(global); + result.add(global); + } + } + return result; + } + + /** + * Constructs parameters of the invariant predicate that are specific to the given thread instance (used by + * {@link #getInvariantParameters()}). By default, this includes local variables of the thread template, and a + * location variable (for the program counter). + * + * @return A (modifiable) list of parameters. The list must not contain duplicates. + */ + protected List createThreadSpecificVars(final ThreadInstance instance) { + final var result = new ArrayList(); + + final var location = new HcLocationVar(instance, getIntSort()); + mLocationVars.put(instance, location); + result.add(location); + + final List localVars = mCfgSymbolTable.getLocals(instance.getTemplateName()).stream() + .filter(mVariableFilter).collect(Collectors.toList()); + for (final IProgramVar pv : localVars) { + final var local = new HcLocalVar(pv, instance.getInstanceNumber()); + mLocalVars.put(instance, pv, local); + result.add(local); + } + + return result; + } + + // Horn clause generation + // ----------------------------------------------------------------------------------------------------------------- + + @Override + protected List buildAllClauses() { + final var result = new ArrayList(); + + result.add(buildInitialClause()); + for (final var entry : mErrorLocations.getSetOfPairs()) { + result.add(buildSafetyClause(entry.getKey(), entry.getValue())); + } + // TODO inductive clauses + // TODO noninterference clauses + + return result; + } + + /** + * Builds the initial clause that encodes the precondition. By default, this method only fixes the initial location + * of the threads. + */ + protected HornClauseBuilder buildInitialClause() { + final var clause = createBuilder(mInvariantPredicate); + + // add location constraints + for (final var instance : mInstances) { + // If instance does not have an initial location, a constraint for mBottomLocation is added. + addOutLocationConstraint(clause, instance, mInitialLocations.get(instance)); + } + + return clause; + } + + /** + * Builds a safety clause specifying unreachability of a given error location. + * + * @param thread + * The thread instance which must not reach the error location + * @param errorLoc + * The error location that shall be proven unreachable + */ + protected HornClauseBuilder buildSafetyClause(final ThreadInstance thread, final IcfgLocation errorLoc) { + // create a clause with head "false" + final var clause = createBuilder(); + + // add body clause + clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); + + // location constraint + addOutLocationConstraint(clause, thread, errorLoc); + + return clause; + } + + /** + * Builds an inductivity clause that encodes the effect of a transition on the thread that executes it. + * + * @param transition + * The transition whose effect is encoded + * @param preds + * A map specifying predecessor locations of the transition. Each thread instance involved in the + * transition must have an entry; other thread instances must not. + * + * Specifying multiple predecessors can be useful for joins. However, joins are not yet fully supported + * by this class. + * @param succs + * A map specifying successor locations of the transition. Each thread instance involved in the + * transition must have an entry; other thread instances must not. + * + * Specifying multiple predecessors can be useful for forks. + * @param updatedThread + * The primary active thread, whose local variables are updated by the transition. + */ + protected HornClauseBuilder buildInductivityClause(final IIcfgTransition transition, + final Map preds, final Map succs, + final ThreadInstance updatedThread) { + final var clause = createBuilder(mInvariantPredicate); + + // add body clause + clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); + + // add location constraints + for (final var entry : preds.entrySet()) { + addInLocationConstraint(clause, entry.getKey(), entry.getValue()); + } + for (final var entry : succs.entrySet()) { + addOutLocationConstraint(clause, entry.getKey(), entry.getValue()); + } + + // add transition constraint + final var locals = mLocalVars.values().collect(Collectors.toList()); + addTransitionConstraint(clause, transition, updatedThread, locals); + + return clause; + } + + /** + * Builds a noninterference clause for the given transition. + */ + protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { + final var clause = createBuilder(mInvariantPredicate); + + // TODO support transitions with multiple predecessors (joins) + final var interferingThread = getInterferingThread(transition); + + // add interference-free clause to body + clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); + + // add precondition clauses + for (final var instance : getInstances(interferingThread.getTemplateName())) { + final var bodyArgs = clause.getDefaultBodyArgs(mInvariantPredicate); + + // replace thread-specific variables with those for the interfering thread + final var instanceVars = mThreadSpecificVars.get(instance); + final var interferingVars = createThreadSpecificVars(interferingThread); + for (int i = 0; i < instanceVars.size(); ++i) { + final var original = instanceVars.get(i); + final var replaced = interferingVars.get(i); + if (mInvariantPredicate.hasParameter(original)) { + final int index = mInvariantPredicate.getIndex(original); + bodyArgs.set(index, clause.getBodyVar(replaced).getTerm()); + } + } + + clause.addBodyPredicate(mInvariantPredicate, bodyArgs); + } + + // add location constraint + addInLocationConstraint(clause, interferingThread, transition.getSource()); + + // add transition constraint + final var locals = Stream.concat(mLocalVars.values(), getInterferingLocals(interferingThread)) + .collect(Collectors.toList()); + addTransitionConstraint(clause, transition, interferingThread, locals); + + return clause; + } + + // Auxiliary methods + // ----------------------------------------------------------------------------------------------------------------- + + protected void addInLocationConstraint(final HornClauseBuilder clause, final ThreadInstance threadInstance, + final IcfgLocation location) { + final var locTerm = + location == null ? mBottomLocation : getLocIndexTerm(location, threadInstance.getTemplateName()); + final HcLocationVar locVar = mLocationVars.get(threadInstance); + final Term term = clause.getBodyVar(locVar).getTerm(); + clause.addConstraint(SmtUtils.binaryEquality(mScript, term, locTerm)); + } + + protected void addOutLocationConstraint(final HornClauseBuilder clause, final ThreadInstance threadInstance, + final IcfgLocation location) { + final var locTerm = + location == null ? mBottomLocation : getLocIndexTerm(location, threadInstance.getTemplateName()); + final HcLocationVar locVar = mLocationVars.get(threadInstance); + final Term term = clause.getHeadVar(locVar).getTerm(); + clause.addConstraint(SmtUtils.binaryEquality(mScript, term, locTerm)); + } + + protected Term getLocIndexTerm(final IcfgLocation loc, final String proc) { + Integer index = mLocationIndices.get(proc, loc); + if (index == null) { + final Map otherIndices = mLocationIndices.get(proc); + index = otherIndices == null ? 0 : otherIndices.size(); + mLocationIndices.put(proc, loc, index); + } + return numeral(index); + } + + protected void addTransitionConstraint(final HornClauseBuilder clause, final IIcfgTransition transition, + final ThreadInstance updatedThread, final Collection localVariables) { + final var tf = transition.getTransformula(); + final var assigned = tf.getAssignedVars(); + final var substitution = new HashMap(); + + // deal with global variables + for (final var global : mGlobalVars) { + if (assigned.contains(global.getVariable())) { + prepareSubstitution(clause, transition, substitution, global, global.getVariable()); + } else { + clause.sameBodyHeadVar(global); + } + } + + // deal with local variables + for (final HcLocalVar local : localVariables) { + if (local.getThreadInstance().equals(updatedThread) && assigned.contains(local.getVariable())) { + prepareSubstitution(clause, transition, substitution, local, local.getVariable()); + } else { + clause.sameBodyHeadVar(local); + } + } + + // replace all other variables with auxiliary variables + final Term formula = tf.getFormula(); + for (final TermVariable v : formula.getFreeVars()) { + substitution.computeIfAbsent(v, variable -> clause.getFreshBodyVar(variable, variable.getSort()).getTerm()); + } + + // add transition constraint + clause.addConstraint(Substitution.apply(mManagedScript, substitution, formula)); + } + + private static void prepareSubstitution(final HornClauseBuilder clause, final IIcfgTransition transition, + final Map substitution, final IHcReplacementVar rv, final IProgramVar pv) { + final TermVariable inVar = transition.getTransformula().getInVars().get(pv); + final TermVariable outVar = transition.getTransformula().getOutVars().get(pv); + substitution.put(outVar, clause.getHeadVar(rv).getTerm()); + + assert !Objects.equals(inVar, outVar); + substitution.put(inVar, clause.getBodyVar(rv).getTerm()); + } + + protected ThreadInstance getInterferingThread(final IIcfgTransition transition) { + return new ThreadInstance(transition.getPrecedingProcedure(), INTERFERING_INSTANCE_ID); + } + + private Stream getInterferingLocals(final ThreadInstance interferingThread) { + return mCfgSymbolTable.getLocals(interferingThread.getTemplateName()).stream().filter(mVariableFilter) + .map(pv -> new HcLocalVar(pv, INTERFERING_INSTANCE_ID)); + } +} From db0f9e5deebe3fbbc84fe255a8dc3ca2d74e3b3f Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 5 Apr 2023 15:27:39 +0200 Subject: [PATCH 006/114] fix Horn clauses with non-false head --- .../plugins/icfgtochc/concurrent/HornClauseBuilder.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index b749a817fba..504190805fd 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -119,7 +119,14 @@ public HornClause build() { substitutedBodyArgs.add(args.stream().map(this::substitute).collect(Collectors.toList())); } - return new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, mBodyVars); + if (mHeadPredicate == null) { + return new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, mBodyVars); + } + + final var headArgs = IntStream.range(0, mHeadPredicate.getParamCount()) + .mapToObj(i -> getHeadVar(mHeadPredicate.getParameter(i))).collect(Collectors.toList()); + return new HornClause(mManagedScript, mSymbolTable, constraint, mHeadPredicate.getPredicate(), headArgs, + mBodyPreds, substitutedBodyArgs, mBodyVars); } private Term substitute(final Term term) { From 053b75539bc5a7b689b444da793756f89d3d64b2 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 5 Apr 2023 15:28:41 +0200 Subject: [PATCH 007/114] add support for variables not tied to a specific predicate and index --- .../concurrent/HornClauseBuilder.java | 10 ++--- .../ultimate/lib/chc/HcBodyVar.java | 7 +--- .../ultimate/lib/chc/HcHeadVar.java | 5 +-- .../ultimate/lib/chc/HcPredVar.java | 40 ++++--------------- .../ultimate/lib/chc/HcSymbolTable.java | 35 +++++++++++++++- .../ultimate/lib/chc/HornUtilConstants.java | 6 ++- 6 files changed, 52 insertions(+), 51 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 504190805fd..07af91a4d53 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -72,24 +72,20 @@ public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symb } public HcBodyVar getFreshBodyVar(final Object identifier, final Sort sort) { - // TODO Using the number of bodyVars as index is a hack! - // TODO suitable parameters for getOrConstructBodyVar - final HcBodyVar auxVar = mSymbolTable.getOrConstructBodyVar(null, mBodyVars.size(), sort, identifier); + final HcBodyVar auxVar = mSymbolTable.getOrConstructBodyVar(identifier, sort); mBodyVars.add(auxVar); return auxVar; } public HcBodyVar getBodyVar(final IHcReplacementVar variable) { - // TODO suitable parameters for getOrConstructBodyVar - final var result = mSymbolTable.getOrConstructBodyVar(null, -1, variable.getSort(), variable); + final var result = mSymbolTable.getOrConstructBodyVar(variable, variable.getSort()); mBodyVars.add(result); return result; } public HcHeadVar getHeadVar(final IHcReplacementVar variable) { - // TODO assert mHeadPredicate.hasParameter(variable); - return null; + return mSymbolTable.getOrConstructHeadVar(variable, variable.getSort()); } public void sameBodyHeadVar(final IHcReplacementVar variable) { diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcBodyVar.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcBodyVar.java index f5b4e29b409..62ab0a95f6f 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcBodyVar.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcBodyVar.java @@ -31,7 +31,6 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.logic.Sort; - /** * * @@ -42,7 +41,6 @@ public class HcBodyVar extends HcPredVar implements ILocalProgramVar { private static final long serialVersionUID = 4653727851496150630L; - /** * Identified by the first three parameters (headPredSymProcName, index, sort) * @@ -53,12 +51,11 @@ public class HcBodyVar extends HcPredVar implements ILocalProgramVar { * @param defaultConstant * @param primedConstant */ - public HcBodyVar(final String globallyUniqueId, final HcPredicateSymbol headPredSym, final int index, final Sort sort, + public HcBodyVar(final String globallyUniqueId, final String procName, final int index, final Sort sort, final ManagedScript script, final Object lockOwner) { - super(globallyUniqueId, false, headPredSym, index, sort, script, lockOwner); + super(globallyUniqueId, false, procName, index, sort, script, lockOwner); } - @Override public String getIdentifier() { return getGloballyUniqueId(); diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcHeadVar.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcHeadVar.java index 944751d676c..94165acad71 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcHeadVar.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcHeadVar.java @@ -30,7 +30,6 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.logic.Sort; - /** * * @@ -51,8 +50,8 @@ public class HcHeadVar extends HcPredVar { * @param defaultConstant * @param primedConstant */ - HcHeadVar(final String globallyUniqueId, final HcPredicateSymbol headPredSym, final int index, final Sort sort, + HcHeadVar(final String globallyUniqueId, final String predName, final int index, final Sort sort, final ManagedScript mgdScript, final Object lockOwner) { - super(globallyUniqueId, true, headPredSym, index, sort, mgdScript, lockOwner); + super(globallyUniqueId, true, predName, index, sort, mgdScript, lockOwner); } } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java index c87e730e4a5..450c99a65f0 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java @@ -6,52 +6,26 @@ public abstract class HcPredVar extends HcVar { - - /** - * The sort of the TermVariable and constants - * --> this is a field just because it is part of this HCOutVar's identity. - */ - private final Sort mSort; - - private final HcPredicateSymbol mPredSymbol; - private final int mIndex; /** * * @param globallyUniqueId - * @param headNotBody TODO this determines isGlobal -- why??? + * @param headNotBody + * TODO this determines isGlobal -- why??? * @param predSym * @param index * @param sort * @param mgdScript * @param lockOwner */ - HcPredVar(final String globallyUniqueId, final boolean headNotBody, final HcPredicateSymbol predSym, final int index, final Sort sort, - final ManagedScript mgdScript, final Object lockOwner) { - super(globallyUniqueId, - mgdScript.variable(globallyUniqueId, sort), + HcPredVar(final String globallyUniqueId, final boolean headNotBody, final String procName, final int index, + final Sort sort, final ManagedScript mgdScript, final Object lockOwner) { + super(globallyUniqueId, mgdScript.variable(globallyUniqueId, sort), ProgramVarUtils.constructDefaultConstant(mgdScript, lockOwner, sort, globallyUniqueId), - ProgramVarUtils.constructPrimedConstant(mgdScript, lockOwner, sort, globallyUniqueId), - headNotBody, - HornUtilConstants.sanitzePredName(predSym.getName()) - ); - - mPredSymbol = predSym; -// mProcName = HornUtilConstants.sanitzePredName(predSym.getName()); + ProgramVarUtils.constructPrimedConstant(mgdScript, lockOwner, sort, globallyUniqueId), headNotBody, + HornUtilConstants.sanitzePredName(procName)); mIndex = index; - mSort = sort; - -// mIsGlobal = headNotBody; - -// mGloballyUniqueId = globallyUniqueId; -// HornUtilConstants.computeNameForHcVar(headNotBody ? -// HornUtilConstants.HEADVARPREFIX : -// HornUtilConstants.BODYVARPREFIX, -// predSym, index, sort.toString()); -// mTermVariable = mgdScript.variable(mGloballyUniqueId, sort); -// mDefaultConstant = ProgramVarUtils.constructDefaultConstant(mgdScript, lockOwner, sort, mGloballyUniqueId); -// mPrimedConstant = ProgramVarUtils.constructPrimedConstant(mgdScript, lockOwner, sort, mGloballyUniqueId); } public int getIndex() { diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java index 24c68b77a6e..9c90f9505ef 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java @@ -45,6 +45,9 @@ */ public class HcSymbolTable extends DefaultIcfgSymbolTable implements ITerm2ExpressionSymbolTable { + private static final String DUMMY_PRED_NAME = "DUMMY"; + private static final int DUMMY_PRED_INDEX = 0; + private final ManagedScript mManagedScript; private final NestedMap2, HcPredicateSymbol> mNameToSortsToHornClausePredicateSymbol; @@ -55,6 +58,8 @@ public class HcSymbolTable extends DefaultIcfgSymbolTable implements ITerm2Expre final Map mVersionsMap; + private final Map mBodyVars = new HashMap<>(); + private final Map mHeadVars = new HashMap<>(); private final NestedMap3 mPredSymNameToIndexToSortToHcHeadVar; private final NestedMap3 mPredSymNameToIndexToSortToHcBodyVar; private final Map mTermVariableToHcBodyAuxVar; @@ -272,7 +277,7 @@ public HcHeadVar getOrConstructHeadVar(final HcPredicateSymbol predSym, final in predSym, index, identfier.toString()); mManagedScript.lock(this); - result = new HcHeadVar(globallyUniqueId, predSym, index, transferredSort, mManagedScript, this); + result = new HcHeadVar(globallyUniqueId, predSym.getName(), index, transferredSort, mManagedScript, this); mManagedScript.unlock(this); mPredSymNameToIndexToSortToHcHeadVar.put(predSym, index, transferredSort, result); mTermVarToProgramVar.put(result.getTermVariable(), result); @@ -285,6 +290,19 @@ public HcHeadVar getOrConstructHeadVar(final HcPredicateSymbol predSym, final in return getOrConstructHeadVar(predSym, index, pv.getSort(), pv); } + public HcHeadVar getOrConstructHeadVar(final Object identifier, final Sort sort) { + return mHeadVars.computeIfAbsent(identifier, id -> { + final Sort transferredSort = transferSort(sort); + final String globallyUniqueId = + HornUtilConstants.computeNameForHcVar(HornUtilConstants.BODYVARPREFIX, id.toString()); + mManagedScript.lock(this); + final var result = new HcHeadVar(globallyUniqueId, DUMMY_PRED_NAME, DUMMY_PRED_INDEX, transferredSort, + mManagedScript, this); + mManagedScript.unlock(this); + return result; + }); + } + public HcBodyVar getOrConstructBodyVar(final HcPredicateSymbol predSym, final int index, final Sort sort, final Object identfier) { final Sort transferredSort = transferSort(sort); @@ -296,7 +314,7 @@ public HcBodyVar getOrConstructBodyVar(final HcPredicateSymbol predSym, final in predSym, index, identfier.toString()); mManagedScript.lock(this); - result = new HcBodyVar(globallyUniqueId, predSym, index, transferredSort, mManagedScript, this); + result = new HcBodyVar(globallyUniqueId, predSym.getName(), index, transferredSort, mManagedScript, this); mManagedScript.unlock(this); mPredSymNameToIndexToSortToHcBodyVar.put(predSym, index, transferredSort, result); mTermVarToProgramVar.put(result.getTermVariable(), result); @@ -309,6 +327,19 @@ public HcBodyVar getOrConstructBodyVar(final HcPredicateSymbol predSym, final in return getOrConstructBodyVar(predSym, index, pv.getSort(), pv); } + public HcBodyVar getOrConstructBodyVar(final Object identifier, final Sort sort) { + return mBodyVars.computeIfAbsent(identifier, id -> { + final Sort transferredSort = transferSort(sort); + final String globallyUniqueId = + HornUtilConstants.computeNameForHcVar(HornUtilConstants.BODYVARPREFIX, id.toString()); + mManagedScript.lock(this); + final var result = new HcBodyVar(globallyUniqueId, DUMMY_PRED_NAME, DUMMY_PRED_INDEX, transferredSort, + mManagedScript, this); + mManagedScript.unlock(this); + return result; + }); + } + public HcBodyAuxVar getOrConstructBodyAuxVar(final TermVariable tv, final Object lockOwner) { HcBodyAuxVar result = mTermVariableToHcBodyAuxVar.get(tv); if (result == null) { diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java index 1cb017b205e..a05281d3395 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java @@ -60,12 +60,16 @@ private HornUtilConstants() { public static String computeNameForHcVar(final String prefix, final HcPredicateSymbol predSym, final int index, final String identifier) { - final String name = HornUtilConstants.sanitzePredName(predSym.getName()); final String identifierString = identifier.replaceAll(" ", "_").replaceAll("[()]", ""); return String.format("%s_%s_%s_%d", prefix, name, identifierString, index); } + public static String computeNameForHcVar(final String prefix, final String identifier) { + final String identifierString = identifier.replaceAll(" ", "_").replaceAll("[()]", ""); + return String.format("%s_%s", prefix, identifierString); + } + /** * The allowed characters for smt identifiers are not all allowed for Boogie idenifiers. * From 10f4bfcdf8f517060988c528c9b25824523c52e1 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 5 Apr 2023 15:28:56 +0200 Subject: [PATCH 008/114] fix location constraint --- .../icfgtochc/concurrent/ThreadModularHornClauseProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 1b2ae36ffaf..064f89b61aa 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -262,7 +262,7 @@ protected HornClauseBuilder buildSafetyClause(final ThreadInstance thread, final clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); // location constraint - addOutLocationConstraint(clause, thread, errorLoc); + addInLocationConstraint(clause, thread, errorLoc); return clause; } From 83e5dcabe1baf77380e465890751091bc4730117 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 5 Apr 2023 16:44:27 +0200 Subject: [PATCH 009/114] refactor ChcProviderConcurrentWithLbe: create new ICFG, use existing ChcProvider --- .../ChcProviderConcurrentWithLbe.java | 100 +--------- .../concurrent/IcfgLiptonReducer.java | 186 ++++++++++++++++++ 2 files changed, 190 insertions(+), 96 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgLiptonReducer.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java index 693fd88ff1a..2c0b5eb996a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java @@ -1,34 +1,13 @@ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; -import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import de.uni_freiburg.informatik.ultimate.automata.AutomataLibraryException; -import de.uni_freiburg.informatik.ultimate.automata.petrinet.netdatastructures.BoundedPetriNet; -import de.uni_freiburg.informatik.ultimate.automata.petrinet.netdatastructures.Transition; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgPetrifier; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; 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.smt.predicates.IPredicate; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.ISLPredicate; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.PredicateFactory; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.initialabstraction.PetriInitialAbstractionProvider; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.initialabstraction.PetriLbeInitialAbstractionProvider; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.IndependenceSettings; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.petrinetlbe.IcfgCompositionFactory; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; /** @@ -38,12 +17,12 @@ * */ public class ChcProviderConcurrentWithLbe implements IChcProvider { + private static final int MAXIMUM_NUMBER_OF_THREADS = 2; + private final ManagedScript mMgdScript; private final HcSymbolTable mHcSymbolTable; private final IUltimateServiceProvider mServices; - private static final int MAXIMUM_NUMBER_OF_THREADS = 2; - public ChcProviderConcurrentWithLbe(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, final IUltimateServiceProvider services) { mMgdScript = mgdScript; @@ -53,78 +32,7 @@ public ChcProviderConcurrentWithLbe(final ManagedScript mgdScript, final HcSymbo @Override public Collection getHornClauses(final IIcfg icfg) { - final IIcfg petrified = new IcfgPetrifier(mServices, icfg, 2, false).getPetrifiedIcfg(); - final Map numberOfThreads = - petrified.getInitialNodes().stream().collect(Collectors.toMap(IcfgLocation::getProcedure, x -> 1)); - final Set unboundedThreads = new HashSet<>(); - final var forksInLoops = IcfgUtils.getForksInLoop(petrified); - final var instanceMap = petrified.getCfgSmtToolkit().getConcurrencyInformation().getThreadInstanceMap(); - for (final var entry : instanceMap.entrySet()) { - final String instance = entry.getValue().get(0).getThreadInstanceName(); - // TODO: Only add if fork is reachable - if (forksInLoops.contains(entry.getKey())) { - numberOfThreads.put(instance, MAXIMUM_NUMBER_OF_THREADS); - unboundedThreads.add(instance); - } else { - numberOfThreads.put(instance, 1); - } - } - final BoundedPetriNet petriNet = getPetriNetWithLbe(petrified, mServices); - final List result = new ArrayList<>(); - final List errorLocs = getLocations(petriNet.getAcceptingPlaces()).stream() - .filter(x -> numberOfThreads.containsKey(x.getProcedure())).collect(Collectors.toList()); - final var locations = icfg.getProgramPoints().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); - final IcfgToChcConcurrent factory = new IcfgToChcConcurrent(numberOfThreads, mMgdScript, - petrified.getCfgSmtToolkit(), mHcSymbolTable, x -> true, locations, null); - result.add(factory.getInitialClause(getLocations(petriNet.getInitialPlaces()))); - result.addAll(factory.getSafetyClauses(errorLocs)); - for (final Transition transition : petriNet.getTransitions()) { - final IcfgEdge edge = transition.getSymbol(); - final String proc = edge.getPrecedingProcedure(); - if (!numberOfThreads.containsKey(proc) || !numberOfThreads.containsKey(edge.getSucceedingProcedure())) { - continue; - } - final List pre = getLocations(transition.getPredecessors()); - final List post = getLocations(transition.getSuccessors()); - result.addAll(factory.getInductivityClauses(pre, edge, post)); - if (unboundedThreads.contains(proc)) { - result.add(factory.getNonInterferenceClause(edge)); - } - // TODO: Special case for a fork to do "nothing"? - // TODO: What about joins? - } - return result; - } - - private static List getLocations(final Collection places) { - final List result = new ArrayList<>(); - for (final IPredicate p : places) { - if (p instanceof ISLPredicate) { - result.add(((ISLPredicate) p).getProgramPoint()); - } - } - return result; - } - - private static BoundedPetriNet getPetriNetWithLbe(final IIcfg icfg, - final IUltimateServiceProvider services) { - final CfgSmtToolkit csToolkit = icfg.getCfgSmtToolkit(); - final PredicateFactory predicateFactory = - new PredicateFactory(services, csToolkit.getManagedScript(), csToolkit.getSymbolTable()); - final PetriInitialAbstractionProvider petriNetProvider = - new PetriInitialAbstractionProvider<>(services, predicateFactory, true); - final PetriLbeInitialAbstractionProvider lbeProvider = new PetriLbeInitialAbstractionProvider<>( - petriNetProvider, services, IcfgEdge.class, new IndependenceSettings(), - new IcfgCompositionFactory(services, csToolkit), Activator.PLUGIN_ID); - final Set inUseLocs = - new HashSet<>(icfg.getCfgSmtToolkit().getConcurrencyInformation().getInUseErrorNodeMap().values()); - final Set errors = icfg.getProcedureErrorNodes().values().stream().flatMap(Collection::stream) - .filter(x -> !inUseLocs.contains(x)).collect(Collectors.toSet()); - try { - return lbeProvider.getInitialAbstraction(icfg, errors); - } catch (final AutomataLibraryException e) { - throw new AssertionError(e); - } + final var reduced = new IcfgLiptonReducer(mServices, icfg, MAXIMUM_NUMBER_OF_THREADS).getResult(); + return new ChcProviderConcurrent(mServices, mMgdScript, mHcSymbolTable).getHornClauses(reduced); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgLiptonReducer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgLiptonReducer.java new file mode 100644 index 00000000000..a45147fee7d --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgLiptonReducer.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2022 Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2022-2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.automata.AutomataLibraryException; +import de.uni_freiburg.informatik.ultimate.automata.petrinet.netdatastructures.BoundedPetriNet; +import de.uni_freiburg.informatik.ultimate.automata.petrinet.netdatastructures.Transition; +import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.BasicIcfg; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgPetrifier; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgForkTransitionThreadOther; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgJoinTransitionThreadOther; +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.smt.predicates.IPredicate; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.ISLPredicate; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.PredicateFactory; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.initialabstraction.PetriInitialAbstractionProvider; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.initialabstraction.PetriLbeInitialAbstractionProvider; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.IndependenceSettings; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.petrinetlbe.IcfgCompositionFactory; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; + +/** + * Performs Lipton reduction on a concurrent program, and returns a new ICFG for the reduced program. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * + */ +public class IcfgLiptonReducer { + private final IIcfg mPetrifiedIcfg; + private final BasicIcfg mNewIcfg; + + private final List mInitialLocs; + private final List mErrorLocs; + + public IcfgLiptonReducer(final IUltimateServiceProvider services, final IIcfg icfg, + final int numberOfInstances) { + mPetrifiedIcfg = new IcfgPetrifier(services, icfg, numberOfInstances, false).getPetrifiedIcfg(); + final BoundedPetriNet petriNet = getPetriNetWithLbe(mPetrifiedIcfg, services); + mInitialLocs = getLocations(petriNet.getInitialPlaces()); + mErrorLocs = getLocations(petriNet.getAcceptingPlaces()); + + mNewIcfg = new BasicIcfg<>(mPetrifiedIcfg.getIdentifier() + "_afterLipton", mPetrifiedIcfg.getCfgSmtToolkit(), + mPetrifiedIcfg.getLocationClass()); + addLocations(mInitialLocs); + addLocations(mErrorLocs); + + for (final Transition transition : petriNet.getTransitions()) { + final IcfgEdge edge = transition.getSymbol(); + + final List post = getLocations(transition.getSuccessors()); + final List pre = getLocations(transition.getPredecessors()); + addLocations(pre); + addLocations(post); + + if (edge instanceof IIcfgForkTransitionThreadOther) { + final var forkOther = (IIcfgForkTransitionThreadOther) edge; + final var forkCurrent = forkOther.getCorrespondingIIcfgForkTransitionCurrentThread(); + + assert Objects.equals(forkOther.getSource(), forkCurrent.getSource()); + assert Objects.equals(pre, List.of(forkOther.getSource())); + assert Objects.equals(post, List.of(forkOther.getTarget(), forkCurrent.getTarget())); + + forkOther.getSource().addOutgoing(edge); + forkOther.getSource().addOutgoing((IcfgEdge) forkCurrent); + forkOther.getTarget().addIncoming(edge); + forkCurrent.getTarget().addIncoming((IcfgEdge) forkCurrent); + } else if (edge instanceof IIcfgJoinTransitionThreadOther) { + final var joinOther = (IIcfgJoinTransitionThreadOther) edge; + final var joinCurrent = joinOther.getCorrespondingIIcfgJoinTransitionCurrentThread(); + + assert Objects.equals(joinOther.getTarget(), joinCurrent.getTarget()); + assert Objects.equals(pre, List.of(joinOther.getSource(), joinCurrent.getSource())); + assert Objects.equals(post, List.of(joinOther.getTarget())); + + joinOther.getSource().addOutgoing(edge); + joinCurrent.getSource().addOutgoing((IcfgEdge) joinCurrent); + joinOther.getTarget().addIncoming(edge); + joinOther.getTarget().addIncoming((IcfgEdge) joinCurrent); + } else { + assert Objects.equals(pre, List.of(edge.getSource())); + assert Objects.equals(post, List.of(edge.getTarget())); + + edge.getSource().addOutgoing(edge); + edge.getTarget().addIncoming(edge); + } + } + } + + private void addLocations(final Collection locs) { + for (final var loc : locs) { + addLocation(loc); + } + } + + private void addLocation(final IcfgLocation loc) { + final var procLocs = mNewIcfg.getProgramPoints().get(loc.getProcedure()); + if (procLocs == null) { + mNewIcfg.addProcedure(loc.getProcedure()); + } else if (procLocs.containsKey(loc.getDebugIdentifier())) { + // already added + return; + } + + // clean slate: remove all edges of location + loc.removeAllIncoming(loc.getIncomingEdges()); + loc.removeAllOutgoing(loc.getOutgoingEdges()); + + final var isProcEntry = Objects.equals(mPetrifiedIcfg.getProcedureEntryNodes().get(loc.getProcedure()), loc); + final var isProcExit = Objects.equals(mPetrifiedIcfg.getProcedureExitNodes().get(loc.getProcedure()), loc); + mNewIcfg.addLocation(loc, mInitialLocs.contains(loc), mErrorLocs.contains(loc), isProcEntry, isProcExit, + mPetrifiedIcfg.getLoopLocations().contains(loc)); + } + + private static List getLocations(final Collection places) { + final List result = new ArrayList<>(); + for (final IPredicate p : places) { + if (p instanceof ISLPredicate) { + result.add(((ISLPredicate) p).getProgramPoint()); + } + } + return result; + } + + private static BoundedPetriNet getPetriNetWithLbe(final IIcfg icfg, + final IUltimateServiceProvider services) { + final CfgSmtToolkit csToolkit = icfg.getCfgSmtToolkit(); + final PredicateFactory predicateFactory = + new PredicateFactory(services, csToolkit.getManagedScript(), csToolkit.getSymbolTable()); + final PetriInitialAbstractionProvider petriNetProvider = + new PetriInitialAbstractionProvider<>(services, predicateFactory, true); + final PetriLbeInitialAbstractionProvider lbeProvider = new PetriLbeInitialAbstractionProvider<>( + petriNetProvider, services, IcfgEdge.class, new IndependenceSettings(), + new IcfgCompositionFactory(services, csToolkit), Activator.PLUGIN_ID); + final Set inUseLocs = + new HashSet<>(icfg.getCfgSmtToolkit().getConcurrencyInformation().getInUseErrorNodeMap().values()); + final Set errors = icfg.getProcedureErrorNodes().values().stream().flatMap(Collection::stream) + .filter(x -> !inUseLocs.contains(x)).collect(Collectors.toSet()); + try { + return lbeProvider.getInitialAbstraction(icfg, errors); + } catch (final AutomataLibraryException e) { + throw new AssertionError(e); + } + } + + public IIcfg getResult() { + return mNewIcfg; + } +} From 5b7e3f0f3635f52c9ebb6a3c4abbde0a889544a9 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 5 Apr 2023 16:50:55 +0200 Subject: [PATCH 010/114] add mode and level parameters to ChcProviderConcurrent --- .../plugins/icfgtochc/IcfgToChcObserver.java | 9 ++++++--- .../icfgtochc/concurrent/ChcProviderConcurrent.java | 12 +++++++++++- .../concurrent/ChcProviderConcurrentWithLbe.java | 4 +++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index b61a6c94134..b5ab537c2ff 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -49,6 +49,7 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.Mode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithLbe; /** @@ -154,13 +155,15 @@ private static boolean isReturnReachable(final IIcfg icfg) { private IChcProvider getChcProvider(final IIcfg icfg, final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable) { - if (true || IcfgUtils.isConcurrent(icfg)) { + final boolean isParametric = true; + if (isParametric || IcfgUtils.isConcurrent(icfg)) { assert !isReturnReachable(icfg); if (USE_LBE_FOR_CONCURRENT_PROGRAMS) { + assert !isParametric; return new ChcProviderConcurrentWithLbe(mgdScript, hcSymbolTable, mServices); - } else { - return new ChcProviderConcurrent(mServices, mgdScript, hcSymbolTable); } + return new ChcProviderConcurrent(mServices, mgdScript, hcSymbolTable, + isParametric ? Mode.PARAMETRIC : Mode.SINGLE_MAIN, 2); } return new ChcProviderForCalls(mgdScript, hcSymbolTable); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java index cecf8103dbc..89d877b12a2 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java @@ -28,17 +28,27 @@ * */ public class ChcProviderConcurrent implements IChcProvider { + public enum Mode { + SINGLE_MAIN, PARAMETRIC + } + private final IUltimateServiceProvider mServices; private final ManagedScript mMgdScript; private final HcSymbolTable mHcSymbolTable; + private final Mode mMode; + private final int mLevel; private static final int MAXIMUM_NUMBER_OF_THREADS = 2; public ChcProviderConcurrent(final IUltimateServiceProvider services, final ManagedScript mgdScript, - final HcSymbolTable hcSymbolTable) { + final HcSymbolTable hcSymbolTable, final Mode mode, final int level) { mServices = services; mMgdScript = mgdScript; mHcSymbolTable = hcSymbolTable; + mMode = mode; + mLevel = level; + + assert level >= 1; } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java index 2c0b5eb996a..6d9582bfb98 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java @@ -9,6 +9,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.Mode; /** * ChcProvider for concurrent programs based on the petri-net using LBE. @@ -33,6 +34,7 @@ public ChcProviderConcurrentWithLbe(final ManagedScript mgdScript, final HcSymbo @Override public Collection getHornClauses(final IIcfg icfg) { final var reduced = new IcfgLiptonReducer(mServices, icfg, MAXIMUM_NUMBER_OF_THREADS).getResult(); - return new ChcProviderConcurrent(mServices, mMgdScript, mHcSymbolTable).getHornClauses(reduced); + return new ChcProviderConcurrent(mServices, mMgdScript, mHcSymbolTable, Mode.SINGLE_MAIN, + MAXIMUM_NUMBER_OF_THREADS).getHornClauses(reduced); } } From a50b4e5cf5263708cef75a44b3e2901301c400ef Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 11 Apr 2023 14:46:58 +0200 Subject: [PATCH 011/114] add BidirectionalMap::merge (allows to be used in stream collectors) --- .../util/datastructures/BidirectionalMap.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/trunk/source/Library-UltimateUtil/src/de/uni_freiburg/informatik/ultimate/util/datastructures/BidirectionalMap.java b/trunk/source/Library-UltimateUtil/src/de/uni_freiburg/informatik/ultimate/util/datastructures/BidirectionalMap.java index c7d42b82783..b529c678024 100644 --- a/trunk/source/Library-UltimateUtil/src/de/uni_freiburg/informatik/ultimate/util/datastructures/BidirectionalMap.java +++ b/trunk/source/Library-UltimateUtil/src/de/uni_freiburg/informatik/ultimate/util/datastructures/BidirectionalMap.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; /** * A bidirectional map is a 1:1 mapping, having unique keys and unique values. @@ -183,5 +184,23 @@ public void putAll(Map m) { } } + @Override + public V merge(final K key, final V value, final BiFunction remappingFunction) { + final var old = get(key); + final var result = mergeAsymmetric(key, value, remappingFunction); + if (old != null) { + mInverse.removeAsymmetric(old); + } + if (result != null) { + mInverse.putAsymmetric(result, key); + } + return result; + } + + private V mergeAsymmetric(final K key, final V value, + final BiFunction remappingFunction) { + return super.merge(key, value, remappingFunction); + } + // equals() and hashCode() from super class work for this implementation } From e450ef4b18397232d118ffbc75724331c154f73c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 11 Apr 2023 14:47:55 +0200 Subject: [PATCH 012/114] HcSymbolTable fix copy-paste error --- .../uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java index 9c90f9505ef..015fb827bfe 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java @@ -294,7 +294,7 @@ public HcHeadVar getOrConstructHeadVar(final Object identifier, final Sort sort) return mHeadVars.computeIfAbsent(identifier, id -> { final Sort transferredSort = transferSort(sort); final String globallyUniqueId = - HornUtilConstants.computeNameForHcVar(HornUtilConstants.BODYVARPREFIX, id.toString()); + HornUtilConstants.computeNameForHcVar(HornUtilConstants.HEADVARPREFIX, id.toString()); mManagedScript.lock(this); final var result = new HcHeadVar(globallyUniqueId, DUMMY_PRED_NAME, DUMMY_PRED_INDEX, transferredSort, mManagedScript, this); From 366c8588d8925eb8b05c7ea457d6b2a163c95729 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 11 Apr 2023 14:58:57 +0200 Subject: [PATCH 013/114] continue refactoring - ThreadModularHornClauseProvider: give params to individual methods, not constructor - ThreadModularHornClauseProvider: fix several bugs with generated clauses, e.g. transition constraints - HornClauseBuilder: default to not modifying variable unless explicitly stated (rather than the reverse) - HornClauseBuilder: support comments on clauses - ChcProviderConcurrent: use new Horn clause generation --- .../plugins/icfgtochc/IcfgToChcObserver.java | 25 ++- .../concurrent/ChcProviderConcurrent.java | 170 +++++++++++++----- .../ChcProviderConcurrentWithLbe.java | 4 +- .../ChcProviderConcurrentWithSleep.java | 57 ++++++ .../ExtensibleHornClauseProvider.java | 8 +- .../concurrent/HornClauseBuilder.java | 46 +++-- .../icfgtochc/concurrent/PredicateInfo.java | 2 +- ...eepSetThreadModularHornClauseProvider.java | 54 +++--- .../icfgtochc/concurrent/ThreadInstance.java | 5 + .../ThreadModularHornClauseProvider.java | 105 +++++------ 10 files changed, 321 insertions(+), 155 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index b5ab537c2ff..a0dbfc86c60 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -51,6 +51,7 @@ import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.Mode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithLbe; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithSleep; /** * @@ -64,8 +65,11 @@ public class IcfgToChcObserver extends BaseObserver { private IElement mResult; - // TODO: Make this a setting + // TODO: Make these into settings + private static final boolean TREAT_AS_PARAMETRIC_PROGRAM = true; private static final boolean USE_LBE_FOR_CONCURRENT_PROGRAMS = false; + private static final boolean USE_SLEEP_SETS = true; + private static final int THREAD_MODULAR_PROOF_LEVEL = 2; public IcfgToChcObserver(final ILogger logger, final IUltimateServiceProvider services) { mLogger = logger; @@ -155,15 +159,24 @@ private static boolean isReturnReachable(final IIcfg icfg) { private IChcProvider getChcProvider(final IIcfg icfg, final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable) { - final boolean isParametric = true; - if (isParametric || IcfgUtils.isConcurrent(icfg)) { + if (TREAT_AS_PARAMETRIC_PROGRAM || IcfgUtils.isConcurrent(icfg)) { assert !isReturnReachable(icfg); if (USE_LBE_FOR_CONCURRENT_PROGRAMS) { - assert !isParametric; + // TODO support LBE for parametric programs + assert !TREAT_AS_PARAMETRIC_PROGRAM; + + // TODO support combination of LBE and sleep sets + assert !USE_SLEEP_SETS; + return new ChcProviderConcurrentWithLbe(mgdScript, hcSymbolTable, mServices); } - return new ChcProviderConcurrent(mServices, mgdScript, hcSymbolTable, - isParametric ? Mode.PARAMETRIC : Mode.SINGLE_MAIN, 2); + + final var mode = TREAT_AS_PARAMETRIC_PROGRAM ? Mode.PARAMETRIC : Mode.SINGLE_MAIN_THREAD; + if (USE_SLEEP_SETS) { + return new ChcProviderConcurrentWithSleep(mServices, mgdScript, hcSymbolTable, mode, + THREAD_MODULAR_PROOF_LEVEL); + } + return new ChcProviderConcurrent(mgdScript, hcSymbolTable, mode, THREAD_MODULAR_PROOF_LEVEL); } return new ChcProviderForCalls(mgdScript, hcSymbolTable); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java index 89d877b12a2..973e7d66dd2 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java @@ -5,44 +5,41 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Objects; import java.util.stream.Collectors; -import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgForkTransitionThreadCurrent; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgJoinTransitionThreadCurrent; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Triple; /** * ChcProvider for concurrent programs based on the icfg. * * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) - * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) */ public class ChcProviderConcurrent implements IChcProvider { public enum Mode { - SINGLE_MAIN, PARAMETRIC + SINGLE_MAIN_THREAD, PARAMETRIC } - private final IUltimateServiceProvider mServices; - private final ManagedScript mMgdScript; - private final HcSymbolTable mHcSymbolTable; - private final Mode mMode; - private final int mLevel; - - private static final int MAXIMUM_NUMBER_OF_THREADS = 2; + protected final ManagedScript mMgdScript; + protected final HcSymbolTable mHcSymbolTable; + protected final Mode mMode; + protected final int mLevel; - public ChcProviderConcurrent(final IUltimateServiceProvider services, final ManagedScript mgdScript, - final HcSymbolTable hcSymbolTable, final Mode mode, final int level) { - mServices = services; + public ChcProviderConcurrent(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, final Mode mode, + final int level) { mMgdScript = mgdScript; mHcSymbolTable = hcSymbolTable; mMode = mode; @@ -53,6 +50,83 @@ public ChcProviderConcurrent(final IUltimateServiceProvider services, final Mana @Override public Collection getHornClauses(final IIcfg icfg) { + final var threadBounds = getThreadNumbersAndUnboundedThreads(icfg); + final var numberOfThreads = threadBounds.getFirst(); + final var unboundedThreads = threadBounds.getSecond(); + + final var factory = createFactory(numberOfThreads, icfg); + final List result = new ArrayList<>(); + + final var initialClause = factory.buildInitialClause(getInitialLocations(icfg, factory.getInstances())).build(); + result.add(initialClause); + + final Map entryNodes = icfg.getProcedureEntryNodes(); + for (final String proc : numberOfThreads.keySet()) { + final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); + while (edges.hasNext()) { + final IcfgEdge edge = edges.next(); + for (final var prePost : getCartesianPrePostProduct(factory, icfg, edge)) { + final var clause = factory + .buildInductivityClause(edge, prePost.getFirst(), prePost.getSecond(), prePost.getThird()) + .build(); + result.add(clause); + } + + if (unboundedThreads.contains(proc)) { + result.add(factory.buildNonInterferenceClause(edge).build()); + } + } + } + + final var errorLocs = getErrorLocations(icfg, factory.getInstances()); + for (final var pair : errorLocs) { + final var safetyClause = factory.buildSafetyClause(pair.getFirst(), pair.getSecond()).build(); + result.add(safetyClause); + } + + return result; + } + + private static List, Map, ThreadInstance>> + getCartesianPrePostProduct(final ThreadModularHornClauseProvider factory, final IIcfg icfg, + final IcfgEdge edge) { + if (edge instanceof IIcfgForkTransitionThreadCurrent) { + final var forkCurrent = (IIcfgForkTransitionThreadCurrent) edge; + final var forkEntry = icfg.getProcedureEntryNodes().get(forkCurrent.getNameOfForkedProcedure()); + final var result = + new ArrayList, Map, ThreadInstance>>(); + for (final var instance : factory.getInstances(edge.getPrecedingProcedure())) { + final var preds = Map.of(instance, edge.getSource()); + for (final var forked : factory.getInstances(forkCurrent.getNameOfForkedProcedure())) { + if (Objects.equals(instance, forked)) { + continue; + } + final var succs = Map.of(instance, edge.getTarget(), forked, forkEntry); + result.add(new Triple<>(preds, succs, instance)); + } + } + return result; + } + if (edge instanceof IIcfgJoinTransitionThreadCurrent) { + assert false : "Joins not supported"; + } + + return factory.getInstances(edge.getPrecedingProcedure()).stream() + .map(t -> new Triple<>(Map.of(t, edge.getSource()), Map.of(t, edge.getTarget()), t)) + .collect(Collectors.toList()); + } + + protected Pair, List> + getThreadNumbersAndUnboundedThreads(final IIcfg icfg) { + if (mMode == Mode.PARAMETRIC) { + final var numberOfThreads = + icfg.getInitialNodes().stream().collect(Collectors.toMap(loc -> loc.getProcedure(), loc -> mLevel)); + final var unbounded = List.copyOf(numberOfThreads.keySet()); + return new Pair<>(numberOfThreads, unbounded); + } + + assert mMode == Mode.SINGLE_MAIN_THREAD : "Unknown mode: " + mMode; + final var forksInLoops = IcfgUtils.getForksInLoop(icfg); final var instanceMap = icfg.getCfgSmtToolkit().getConcurrencyInformation().getThreadInstanceMap(); final Map numberOfThreads = new HashMap<>(); @@ -63,11 +137,11 @@ public Collection getHornClauses(final IIcfg icfg) { final String procedure = fork.getNameOfForkedProcedure(); // TODO: Only add if fork is reachable if (forksInLoops.contains(fork)) { - numberOfThreads.put(procedure, MAXIMUM_NUMBER_OF_THREADS); + numberOfThreads.put(procedure, mLevel); unboundedThreads.add(procedure); } else { final Integer oldCount = numberOfThreads.getOrDefault(procedure, 0); - if (oldCount == MAXIMUM_NUMBER_OF_THREADS) { + if (oldCount == mLevel) { unboundedThreads.add(procedure); } else { numberOfThreads.put(procedure, oldCount + 1); @@ -75,39 +149,37 @@ public Collection getHornClauses(final IIcfg icfg) { } } - numberOfThreads.clear(); - numberOfThreads.put("thread", 2); - unboundedThreads.clear(); - unboundedThreads.add("thread"); + return new Pair<>(numberOfThreads, unboundedThreads); + } - final var independence = new SemanticIndependenceRelation<>(mServices, mMgdScript, false, true); - final var locations = icfg.getProgramPoints().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); - final IcfgToChcConcurrent factory = new IcfgToChcConcurrent(numberOfThreads, mMgdScript, - icfg.getCfgSmtToolkit(), mHcSymbolTable, x -> true, locations, independence); - final List result = new ArrayList<>(); - result.add(factory.getInitialClause(icfg.getInitialNodes())); - // result.add(factory.getIdUniquenessClause()); - final Set errorNodes = - icfg.getProcedureErrorNodes().values().stream().flatMap(Set::stream).collect(Collectors.toSet()); - final Map entryNodes = icfg.getProcedureEntryNodes(); - result.addAll(factory.getSafetyClauses(errorNodes)); - for (final String proc : numberOfThreads.keySet()) { - final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); - while (edges.hasNext()) { - // TODO: Add the handling of joins (needs thread id?) - final IcfgEdge edge = edges.next(); - if (edge instanceof IIcfgForkTransitionThreadCurrent) { - final String forked = ((IIcfgForkTransitionThreadCurrent) edge).getNameOfForkedProcedure(); - result.addAll(factory.getInductivityClauses(List.of(edge.getSource()), edge, - List.of(edge.getTarget(), entryNodes.get(forked)))); - } - result.addAll(factory.getInductivityClauses(edge)); - if (unboundedThreads.contains(proc)) { - result.add(factory.getNonInterferenceClause(edge)); - } - } + protected Map getInitialLocations(final IIcfg icfg, + final List instances) { + switch (mMode) { + case PARAMETRIC: + // combine each initial location (usually there is only one) with ALL instances of its template + return icfg + .getInitialNodes().stream().flatMap(l -> instances.stream() + .filter(i -> i.getTemplateName().equals(l.getProcedure())).map(i -> new Pair<>(i, l))) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + case SINGLE_MAIN_THREAD: + // combine each initial location (usually there is only one) with instance 0 of its template + return icfg.getInitialNodes().stream() + .collect(Collectors.toMap(l -> new ThreadInstance(l.getProcedure(), 0), l -> l)); } - return result; + throw new UnsupportedOperationException("Unknown mode: " + mMode); + } + + protected List> getErrorLocations(final IIcfg icfg, + final List instances) { + return icfg.getProcedureErrorNodes().entrySet().stream() + .flatMap(e -> e.getValue().stream().map(l -> new Pair<>(e.getKey(), l))).flatMap(e -> instances.stream() + .filter(i -> i.getTemplateName().equals(e.getKey())).map(i -> new Pair<>(i, e.getValue()))) + .collect(Collectors.toList()); + } + + protected ThreadModularHornClauseProvider createFactory(final Map numberOfThreads, + final IIcfg icfg) { + return new ThreadModularHornClauseProvider(numberOfThreads, mMgdScript, icfg.getCfgSmtToolkit(), mHcSymbolTable, + x -> true); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java index 6d9582bfb98..3f1b28fe995 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java @@ -34,7 +34,7 @@ public ChcProviderConcurrentWithLbe(final ManagedScript mgdScript, final HcSymbo @Override public Collection getHornClauses(final IIcfg icfg) { final var reduced = new IcfgLiptonReducer(mServices, icfg, MAXIMUM_NUMBER_OF_THREADS).getResult(); - return new ChcProviderConcurrent(mServices, mMgdScript, mHcSymbolTable, Mode.SINGLE_MAIN, - MAXIMUM_NUMBER_OF_THREADS).getHornClauses(reduced); + return new ChcProviderConcurrent(mMgdScript, mHcSymbolTable, Mode.SINGLE_MAIN_THREAD, MAXIMUM_NUMBER_OF_THREADS) + .getHornClauses(reduced); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java new file mode 100644 index 00000000000..ed86d289cca --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Map; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; + +public class ChcProviderConcurrentWithSleep extends ChcProviderConcurrent { + private final IUltimateServiceProvider mServices; + + public ChcProviderConcurrentWithSleep(final IUltimateServiceProvider services, final ManagedScript mgdScript, + final HcSymbolTable hcSymbolTable, final Mode mode, final int level) { + super(mgdScript, hcSymbolTable, mode, level); + mServices = services; + } + + @Override + protected ThreadModularHornClauseProvider createFactory(final Map numberOfThreads, + final IIcfg icfg) { + final var independence = new SemanticIndependenceRelation<>(mServices, mMgdScript, false, true); + final var locations = icfg.getProgramPoints().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); + return new SleepSetThreadModularHornClauseProvider(numberOfThreads, mMgdScript, icfg.getCfgSmtToolkit(), + mHcSymbolTable, x -> true, independence, locations); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java index 2f39c1d3b0e..ee81b4423c6 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java @@ -50,12 +50,12 @@ public ExtensibleHornClauseProvider(final ManagedScript mgdScript, final HcSymbo mSymbolTable = symbolTable; } - protected final HornClauseBuilder createBuilder(final PredicateInfo predicate) { - return new HornClauseBuilder(mManagedScript, mSymbolTable, Objects.requireNonNull(predicate)); + protected final HornClauseBuilder createBuilder(final PredicateInfo predicate, final String comment) { + return new HornClauseBuilder(mManagedScript, mSymbolTable, Objects.requireNonNull(predicate), comment); } - protected final HornClauseBuilder createBuilder() { - return new HornClauseBuilder(mManagedScript, mSymbolTable); + protected final HornClauseBuilder createBuilder(final String comment) { + return new HornClauseBuilder(mManagedScript, mSymbolTable, comment); } protected abstract List buildAllClauses(); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 07af91a4d53..0fe8da638f0 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -53,22 +53,25 @@ public class HornClauseBuilder { private final ManagedScript mManagedScript; private final HcSymbolTable mSymbolTable; private final PredicateInfo mHeadPredicate; + private final String mComment; private final Map mSubstitution = new HashMap<>(); + private final Set mModifiedVars = new HashSet<>(); private final List mBodyPreds = new ArrayList<>(); private final List> mBodyArgs = new ArrayList<>(); private final List mConstraints = new ArrayList<>(); private final Set mBodyVars = new HashSet<>(); public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symbolTable, - final PredicateInfo headPredicate) { + final PredicateInfo headPredicate, final String comment) { mManagedScript = mgdScript; mSymbolTable = symbolTable; mHeadPredicate = headPredicate; + mComment = comment; } - public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symbolTable) { - this(mgdScript, symbolTable, null); + public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symbolTable, final String comment) { + this(mgdScript, symbolTable, null, comment); } public HcBodyVar getFreshBodyVar(final Object identifier, final Sort sort) { @@ -84,12 +87,14 @@ public HcBodyVar getBodyVar(final IHcReplacementVar variable) { } public HcHeadVar getHeadVar(final IHcReplacementVar variable) { + assert mHeadPredicate != null : "Clause does not have head predicate"; assert mHeadPredicate.hasParameter(variable); return mSymbolTable.getOrConstructHeadVar(variable, variable.getSort()); } - public void sameBodyHeadVar(final IHcReplacementVar variable) { - mSubstitution.put(getBodyVar(variable).getTermVariable(), getHeadVar(variable).getTerm()); + public void differentBodyHeadVar(final IHcReplacementVar variable) { + assert mHeadPredicate != null : "Clause does not have head predicate"; + mModifiedVars.add(variable); } public List getDefaultBodyArgs(final PredicateInfo predicate) { @@ -108,6 +113,7 @@ public void addConstraint(final Term term) { } public HornClause build() { + prepareSubstitution(); final var constraint = getSubstitutedConstraint(); final var substitutedBodyArgs = new ArrayList>(mBodyArgs.size()); @@ -115,14 +121,34 @@ public HornClause build() { substitutedBodyArgs.add(args.stream().map(this::substitute).collect(Collectors.toList())); } + HornClause clause; if (mHeadPredicate == null) { - return new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, mBodyVars); + clause = new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, + mBodyVars); + } else { + final var headArgs = IntStream.range(0, mHeadPredicate.getParamCount()) + .mapToObj(i -> getHeadVar(mHeadPredicate.getParameter(i))).collect(Collectors.toList()); + clause = new HornClause(mManagedScript, mSymbolTable, constraint, mHeadPredicate.getPredicate(), headArgs, + mBodyPreds, substitutedBodyArgs, mBodyVars); + } + if (mComment != null) { + clause.setComment(mComment); + } + return clause; + } + + private void prepareSubstitution() { + if (mHeadPredicate == null) { + return; } - final var headArgs = IntStream.range(0, mHeadPredicate.getParamCount()) - .mapToObj(i -> getHeadVar(mHeadPredicate.getParameter(i))).collect(Collectors.toList()); - return new HornClause(mManagedScript, mSymbolTable, constraint, mHeadPredicate.getPredicate(), headArgs, - mBodyPreds, substitutedBodyArgs, mBodyVars); + mSubstitution.clear(); + for (int i = 0; i < mHeadPredicate.getParamCount(); ++i) { + final var variable = mHeadPredicate.getParameter(i); + if (!mModifiedVars.contains(variable)) { + mSubstitution.put(getBodyVar(variable).getTermVariable(), getHeadVar(variable).getTerm()); + } + } } private Term substitute(final Term term) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java index ff5d091ebaf..f399c748159 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java @@ -57,7 +57,7 @@ public int getIndex(final IHcReplacementVar variable) { public IHcReplacementVar getParameter(final int index) { final var result = mVariable2Index.inverse().get(index); - assert result != null; + assert result != null : "No parameter at index " + index + " (out of " + mPredicate.getArity() + ")"; return result; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 9e9853e6beb..956b2ca8527 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -27,10 +27,10 @@ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -45,45 +45,49 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornClauseProvider { private final IIndependenceRelation> mIndependence; private final Map> mThreadLocations; - private final Map mIdVars = new HashMap<>(); - private final Map mSleepVars = new HashMap<>(); + private final Map mIdVars; + private final Map mSleepVars; public SleepSetThreadModularHornClauseProvider(final Map numberOfThreads, final ManagedScript mgdScript, final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable symbolTable, - final Predicate variableFilter, final Collection initialLocations, - final Collection errorLocations, + final Predicate variableFilter, final IIndependenceRelation> independence, final Map> threadLocations) { - super(numberOfThreads, mgdScript, cfgSmtToolkit, symbolTable, variableFilter, initialLocations, errorLocations); + super(numberOfThreads, mgdScript, cfgSmtToolkit, symbolTable, variableFilter); mIndependence = independence; mThreadLocations = threadLocations; + + mIdVars = extractThreadVars(HcThreadIdVar.class); + mSleepVars = extractThreadVars(HcSleepVar.class); + } + + private Map extractThreadVars(final Class varClass) { + return mThreadSpecificVars.entrySet().stream() + .map(entry -> new Pair<>(entry.getKey(), + entry.getValue().stream().filter(varClass::isInstance).map(varClass::cast).findFirst().get())) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } @Override protected List createThreadSpecificVars(final ThreadInstance instance) { final var result = super.createThreadSpecificVars(instance); - // thread ID - final var id = new HcThreadIdVar(instance, mScript); - mIdVars.put(instance, id); - result.add(0, id); - - // sleep set - final var sleep = new HcSleepVar(instance, mScript); - mSleepVars.put(instance, sleep); - result.add(1, sleep); + // add thread ID and sleep set + result.add(0, new HcThreadIdVar(instance, mScript)); + result.add(1, new HcSleepVar(instance, mScript)); return result; } @Override - protected HornClauseBuilder buildInitialClause() { - final var clause = super.buildInitialClause(); + protected HornClauseBuilder buildInitialClause(final Map initialLocations) { + final var clause = super.buildInitialClause(initialLocations); // all sleep variables are initialized to 0 for (final var instance : mInstances) { @@ -150,9 +154,6 @@ private void ensureThreadOrdering(final HornClauseBuilder clause) { final var instance = mInstances.get(i); final var id = mIdVars.get(instance); - // thread ID must not change - clause.sameBodyHeadVar(id); - // fix ordering between thread IDs if (i + 1 < mInstances.size()) { final var next = mInstances.get(i + 1); @@ -174,11 +175,12 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra // for now, the preference order is non-positional, and given by the ordering in mInstances final int ordering = Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(current)); + final var sleep = mSleepVars.get(current); if (activeThreads.contains(current)) { // no update of sleep variable } else if (ordering < 0) { // set sleep variable to false / leave unchanged - final var sleep = mSleepVars.get(current); + clause.differentBodyHeadVar(sleep); final var oldSleep = clause.getBodyVar(sleep); final var newSleep = clause.getHeadVar(sleep); clause.addConstraint(SmtUtils.ite(mScript, nonCommConstr, @@ -186,7 +188,7 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra SmtUtils.binaryEquality(mScript, newSleep.getTerm(), oldSleep.getTerm()))); } else { // set sleep variable to false / true - final var sleep = mSleepVars.get(current); + clause.differentBodyHeadVar(sleep); final var newSleep = clause.getHeadVar(sleep); clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), nonCommConstr)); @@ -197,8 +199,10 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra // Here the ordering can only be resolved at runtime, so we treat it statically private void updateSleepNonInterference(final HornClauseBuilder clause, final IIcfgTransition transition, final HcThreadIdVar interferingId, final ThreadInstance current) { - final var oldSleep = clause.getBodyVar(mSleepVars.get(current)); - final var newSleep = clause.getHeadVar(mSleepVars.get(current)); + final var sleep = mSleepVars.get(current); + clause.differentBodyHeadVar(sleep); + final var oldSleep = clause.getBodyVar(sleep); + final var newSleep = clause.getHeadVar(sleep); final var currentLoc = clause.getBodyVar(mLocationVars.get(current)); final var currentId = clause.getBodyVar(mIdVars.get(current)); @@ -224,7 +228,7 @@ protected Term getNonCommutativityConstraint(final ThreadInstance instance, fina nonCommLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); } } - return SmtUtils.and(mScript, nonCommLocations.stream().map(loc -> SmtUtils.binaryEquality(mScript, locVar, loc)) + return SmtUtils.or(mScript, nonCommLocations.stream().map(loc -> SmtUtils.binaryEquality(mScript, locVar, loc)) .collect(Collectors.toList())); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java index 346ba360d35..57f69b21bc3 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java @@ -45,6 +45,11 @@ public int getInstanceNumber() { return mInstanceNumber; } + @Override + public String toString() { + return mTemplateName + "_" + mInstanceNumber; + } + @Override public int hashCode() { return Objects.hash(mInstanceNumber, mTemplateName); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 064f89b61aa..80a1cea69b8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -54,7 +54,6 @@ import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; -import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; @@ -72,9 +71,6 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide private final IIcfgSymbolTable mCfgSymbolTable; private final Predicate mVariableFilter; - private final Map mInitialLocations; - private final HashRelation mErrorLocations = new HashRelation<>(); - // maps a procedure name and a location (in the procedure) to an integer, such that the location variable has this // integer as value iff control is in the given location private final NestedMap2 mLocationIndices = new NestedMap2<>(); @@ -93,23 +89,13 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide public ThreadModularHornClauseProvider(final Map numberOfThreads, final ManagedScript mgdScript, final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable symbolTable, - final Predicate variableFilter, final Collection initialLocations, - final Collection errorLocations) { + final Predicate variableFilter) { super(mgdScript, symbolTable); mCfgSymbolTable = cfgSmtToolkit.getSymbolTable(); mVariableFilter = variableFilter; mBottomLocation = numeral(-1); mInstances = getInstances(numberOfThreads); mInvariantPredicate = createInvariantPredicate(); - - // TODO also support the non-parametric setting, i.e., only set initial location for ID 0 - mInitialLocations = createInstanceLocationMap(initialLocations); - - for (final IcfgLocation loc : errorLocations) { - for (final var instance : getInstances(loc.getProcedure())) { - mErrorLocations.addPair(instance, loc); - } - } } // Initialization code and variable creation @@ -125,18 +111,12 @@ private static List getInstances(final Map numb return result; } - private List getInstances(final String template) { - return mInstances.stream().filter(inst -> inst.getTemplateName().equals(template)).collect(Collectors.toList()); + public List getInstances() { + return mInstances; } - private Map createInstanceLocationMap(final Collection locations) { - final var result = new HashMap(); - for (final IcfgLocation loc : locations) { - for (final var instance : getInstances(loc.getProcedure())) { - result.put(instance, loc); - } - } - return result; + public List getInstances(final String template) { + return mInstances.stream().filter(inst -> inst.getTemplateName().equals(template)).collect(Collectors.toList()); } private PredicateInfo createInvariantPredicate() { @@ -220,10 +200,10 @@ protected List createThreadSpecificVars(final ThreadInstan protected List buildAllClauses() { final var result = new ArrayList(); - result.add(buildInitialClause()); - for (final var entry : mErrorLocations.getSetOfPairs()) { - result.add(buildSafetyClause(entry.getKey(), entry.getValue())); - } + // result.add(buildInitialClause()); + // for (final var entry : mErrorLocations.getSetOfPairs()) { + // result.add(buildSafetyClause(entry.getKey(), entry.getValue())); + // } // TODO inductive clauses // TODO noninterference clauses @@ -234,13 +214,13 @@ protected List buildAllClauses() { * Builds the initial clause that encodes the precondition. By default, this method only fixes the initial location * of the threads. */ - protected HornClauseBuilder buildInitialClause() { - final var clause = createBuilder(mInvariantPredicate); + protected HornClauseBuilder buildInitialClause(final Map initialLocations) { + final var clause = createBuilder(mInvariantPredicate, "initial clause"); // add location constraints for (final var instance : mInstances) { // If instance does not have an initial location, a constraint for mBottomLocation is added. - addOutLocationConstraint(clause, instance, mInitialLocations.get(instance)); + addOutLocationConstraint(clause, instance, initialLocations.get(instance)); } return clause; @@ -256,12 +236,12 @@ protected HornClauseBuilder buildInitialClause() { */ protected HornClauseBuilder buildSafetyClause(final ThreadInstance thread, final IcfgLocation errorLoc) { // create a clause with head "false" - final var clause = createBuilder(); + final var clause = createBuilder("safety clause for location " + errorLoc + " in thread instance " + thread); // add body clause clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); - // location constraint + // location constraints addInLocationConstraint(clause, thread, errorLoc); return clause; @@ -289,17 +269,22 @@ protected HornClauseBuilder buildSafetyClause(final ThreadInstance thread, final protected HornClauseBuilder buildInductivityClause(final IIcfgTransition transition, final Map preds, final Map succs, final ThreadInstance updatedThread) { - final var clause = createBuilder(mInvariantPredicate); + final var clause = createBuilder(mInvariantPredicate, + "inductivity clause for transition " + transition.hashCode() + " with transformula " + + transition.getTransformula() + " and thread instance " + updatedThread); // add body clause clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); // add location constraints - for (final var entry : preds.entrySet()) { - addInLocationConstraint(clause, entry.getKey(), entry.getValue()); - } - for (final var entry : succs.entrySet()) { - addOutLocationConstraint(clause, entry.getKey(), entry.getValue()); + for (final var instance : mInstances) { + final var isActive = preds.containsKey(instance) || succs.containsKey(instance); + if (isActive) { + // if instance only in preds or only in succs, the respective other location is mBottomLocation + clause.differentBodyHeadVar(mLocationVars.get(instance)); + addInLocationConstraint(clause, instance, preds.get(instance)); + addOutLocationConstraint(clause, instance, succs.get(instance)); + } } // add transition constraint @@ -313,7 +298,8 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran * Builds a noninterference clause for the given transition. */ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { - final var clause = createBuilder(mInvariantPredicate); + final var clause = createBuilder(mInvariantPredicate, "non-interference clause for transition " + + transition.hashCode() + " with transformula " + transition.getTransformula()); // TODO support transitions with multiple predecessors (joins) final var interferingThread = getInterferingThread(transition); @@ -385,30 +371,23 @@ protected Term getLocIndexTerm(final IcfgLocation loc, final String proc) { protected void addTransitionConstraint(final HornClauseBuilder clause, final IIcfgTransition transition, final ThreadInstance updatedThread, final Collection localVariables) { final var tf = transition.getTransformula(); - final var assigned = tf.getAssignedVars(); final var substitution = new HashMap(); // deal with global variables for (final var global : mGlobalVars) { - if (assigned.contains(global.getVariable())) { - prepareSubstitution(clause, transition, substitution, global, global.getVariable()); - } else { - clause.sameBodyHeadVar(global); - } + prepareSubstitution(clause, transition, substitution, global, global.getVariable(), true); } // deal with local variables for (final HcLocalVar local : localVariables) { - if (local.getThreadInstance().equals(updatedThread) && assigned.contains(local.getVariable())) { - prepareSubstitution(clause, transition, substitution, local, local.getVariable()); - } else { - clause.sameBodyHeadVar(local); - } + final var updatable = local.getThreadInstance().equals(updatedThread); + prepareSubstitution(clause, transition, substitution, local, local.getVariable(), updatable); } // replace all other variables with auxiliary variables final Term formula = tf.getFormula(); for (final TermVariable v : formula.getFreeVars()) { + assert substitution.containsKey(v) || tf.getAuxVars().contains(v) : "not an auxiliary variable: " + v; substitution.computeIfAbsent(v, variable -> clause.getFreshBodyVar(variable, variable.getSort()).getTerm()); } @@ -417,13 +396,23 @@ protected void addTransitionConstraint(final HornClauseBuilder clause, final IIc } private static void prepareSubstitution(final HornClauseBuilder clause, final IIcfgTransition transition, - final Map substitution, final IHcReplacementVar rv, final IProgramVar pv) { - final TermVariable inVar = transition.getTransformula().getInVars().get(pv); - final TermVariable outVar = transition.getTransformula().getOutVars().get(pv); - substitution.put(outVar, clause.getHeadVar(rv).getTerm()); + final Map substitution, final IHcReplacementVar rv, final IProgramVar pv, + final boolean canBeUpdated) { + final var tf = transition.getTransformula(); - assert !Objects.equals(inVar, outVar); - substitution.put(inVar, clause.getBodyVar(rv).getTerm()); + final TermVariable inVar = tf.getInVars().get(pv); + if (inVar != null) { + substitution.put(inVar, clause.getBodyVar(rv).getTerm()); + } + + final TermVariable outVar = tf.getOutVars().get(pv); + if (outVar != null && !Objects.equals(inVar, outVar)) { + substitution.put(outVar, clause.getHeadVar(rv).getTerm()); + } + + if (canBeUpdated && tf.getAssignedVars().contains(pv)) { + clause.differentBodyHeadVar(rv); + } } protected ThreadInstance getInterferingThread(final IIcfgTransition transition) { From 3a232af1ef8cf7f7e31c6e343a7d719da921764e Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 11 Apr 2023 15:30:38 +0200 Subject: [PATCH 014/114] make sleep set vars boolean --- .../ExtensibleHornClauseProvider.java | 4 ++ .../icfgtochc/concurrent/HcSleepVar.java | 7 +-- .../concurrent/IcfgToChcConcurrent.java | 10 ++-- ...eepSetThreadModularHornClauseProvider.java | 50 +++++++++---------- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java index ee81b4423c6..6b49d270381 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java @@ -71,4 +71,8 @@ protected final Term numeral(final long n) { protected Sort getIntSort() { return SmtSortUtils.getIntSort(mScript); } + + protected Sort getBoolSort() { + return SmtSortUtils.getBoolSort(mScript); + } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index e222bef9ebd..65ec8a70148 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -28,18 +28,15 @@ import java.util.Objects; -import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; public class HcSleepVar implements IHcThreadSpecificVar { - private static final String SORT = "Int"; - private final Sort mSort; private final ThreadInstance mInstance; - public HcSleepVar(final ThreadInstance instance, final Script script) { + public HcSleepVar(final ThreadInstance instance, final Sort sort) { mInstance = instance; - mSort = script.sort(SORT); + mSort = sort; } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java index fe77f051321..f98ead848fb 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java @@ -148,7 +148,7 @@ private void initializeDefaultVars(final Collection globalVariables addVariable(loc); // sleep set - final var sleep = new HcSleepVar(instance, getScript()); + final var sleep = new HcSleepVar(instance, getBoolSort()); mSleepVars.put(instance, sleep); addVariable(sleep); @@ -163,6 +163,10 @@ private Sort getIntSort() { return SmtSortUtils.getIntSort(getScript()); } + private Sort getBoolSort() { + return SmtSortUtils.getBoolSort(getScript()); + } + private List getDefaultArgs() { return mDefaultHeadVars.stream().map(HcVar::getTerm).collect(Collectors.toList()); } @@ -688,7 +692,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { // for each non-interference premise, insert the variable in the index for the interfering thread for (int i = 0; i < n; ++i) { final int newIndex = mPositions2Vars.inverse() - .get(new HcSleepVar(new ThreadInstance(sv.getThreadTemplateName(), i), getScript())); + .get(new HcSleepVar(new ThreadInstance(sv.getThreadTemplateName(), i), getBoolSort())); bodyArguments.get(i + 1).set(newIndex, bodyVar.getTerm()); } @@ -704,7 +708,7 @@ public HornClause getNonInterferenceClause(final IIcfgTransition edge) { bodyVars.add(id); for (int i = 0; i < n; ++i) { final var newIndex = mPositions2Vars.inverse() - .get(new HcSleepVar(new ThreadInstance(iv.getThreadTemplateName(), i), getScript())); + .get(new HcSleepVar(new ThreadInstance(iv.getThreadTemplateName(), i), getBoolSort())); bodyArguments.get(i + 1).set(newIndex, id.getTerm()); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 956b2ca8527..4ff4ed0c455 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -80,7 +80,7 @@ protected List createThreadSpecificVars(final ThreadInstan // add thread ID and sleep set result.add(0, new HcThreadIdVar(instance, mScript)); - result.add(1, new HcSleepVar(instance, mScript)); + result.add(1, new HcSleepVar(instance, getBoolSort())); return result; } @@ -89,10 +89,10 @@ protected List createThreadSpecificVars(final ThreadInstan protected HornClauseBuilder buildInitialClause(final Map initialLocations) { final var clause = super.buildInitialClause(initialLocations); - // all sleep variables are initialized to 0 + // all sleep variables are initialized to false for (final var instance : mInstances) { final var sleep = mSleepVars.get(instance); - clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getHeadVar(sleep).getTerm(), numeral(0))); + clause.addConstraint(SmtUtils.not(mScript, clause.getHeadVar(sleep).getTerm())); } return clause; @@ -107,7 +107,7 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran // active threads are not sleeping for (final var active : preds.keySet()) { final var sleep = mSleepVars.get(active); - clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getBodyVar(sleep).getTerm(), numeral(0))); + clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); } // thread IDs are ordered @@ -138,8 +138,8 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition } // interfering thread is not sleeping - final var sleep = new HcSleepVar(interferingThread, mScript); - clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getBodyVar(sleep).getTerm(), numeral(0))); + final var sleep = new HcSleepVar(interferingThread, getBoolSort()); + clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); // update sleep variables for (final var instance : mInstances) { @@ -170,7 +170,7 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra final Set activeThreads, final ThreadInstance primaryActiveThread, final ThreadInstance current) { final var loc = clause.getBodyVar(mLocationVars.get(current)); - final Term nonCommConstr = getNonCommutativityConstraint(current, loc.getTerm(), transition); + final Term commConstr = getCommutativityConstraint(current, loc.getTerm(), transition); // for now, the preference order is non-positional, and given by the ordering in mInstances final int ordering = Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(current)); @@ -179,19 +179,18 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra if (activeThreads.contains(current)) { // no update of sleep variable } else if (ordering < 0) { + // current thread is AFTER primary thread // set sleep variable to false / leave unchanged clause.differentBodyHeadVar(sleep); final var oldSleep = clause.getBodyVar(sleep); final var newSleep = clause.getHeadVar(sleep); - clause.addConstraint(SmtUtils.ite(mScript, nonCommConstr, - SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), - SmtUtils.binaryEquality(mScript, newSleep.getTerm(), oldSleep.getTerm()))); + clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), + SmtUtils.and(mScript, oldSleep.getTerm(), commConstr))); } else { // set sleep variable to false / true clause.differentBodyHeadVar(sleep); final var newSleep = clause.getHeadVar(sleep); - clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, - SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), nonCommConstr)); + clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), commConstr)); } } @@ -207,28 +206,29 @@ private void updateSleepNonInterference(final HornClauseBuilder clause, final II final var currentLoc = clause.getBodyVar(mLocationVars.get(current)); final var currentId = clause.getBodyVar(mIdVars.get(current)); - final Term nonCommConstr = getNonCommutativityConstraint(current, currentLoc.getTerm(), transition); - clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, - SmtUtils.binaryEquality(mScript, newSleep.getTerm(), numeral(0)), - SmtUtils.or(mScript, + final Term commConstr = getCommutativityConstraint(current, currentLoc.getTerm(), transition); + // sleep' = (current < interfering \/ sleep) /\ commConstr + clause.addConstraint( + SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), SmtUtils.and(mScript, - SmtUtils.greater(mScript, currentId.getTerm(), - clause.getBodyVar(interferingId).getTerm()), - SmtUtils.binaryEquality(mScript, oldSleep.getTerm(), numeral(0))), - nonCommConstr))); + SmtUtils.or(mScript, + SmtUtils.less(mScript, currentId.getTerm(), + clause.getBodyVar(interferingId).getTerm()), + oldSleep.getTerm()), + commConstr))); } - protected Term getNonCommutativityConstraint(final ThreadInstance instance, final Term locVar, + protected Term getCommutativityConstraint(final ThreadInstance instance, final Term locVar, final IIcfgTransition currentEdge) { - final var nonCommLocations = new HashSet(); + final var commLocations = new HashSet(); for (final var loc : mThreadLocations.get(instance.getTemplateName())) { if (loc.getOutgoingEdges().stream() - .anyMatch(edge -> mIndependence.isIndependent(null, edge, currentEdge) != Dependence.INDEPENDENT)) { - nonCommLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); + .allMatch(e -> mIndependence.isIndependent(null, e, currentEdge) == Dependence.INDEPENDENT)) { + commLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); } } - return SmtUtils.or(mScript, nonCommLocations.stream().map(loc -> SmtUtils.binaryEquality(mScript, locVar, loc)) + return SmtUtils.or(mScript, commLocations.stream().map(loc -> SmtUtils.binaryEquality(mScript, locVar, loc)) .collect(Collectors.toList())); } } From eb16dfe90bda7e770c3f9e15656f1691214a3bb0 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 18 Apr 2023 19:29:08 +0200 Subject: [PATCH 015/114] IcfgToChc: add preferences --- .../ultimate/plugins/icfgtochc/IcfgToChc.java | 6 +- .../plugins/icfgtochc/IcfgToChcObserver.java | 34 +++---- .../concurrent/ChcProviderConcurrent.java | 16 +-- .../ChcProviderConcurrentWithLbe.java | 4 +- .../ChcProviderConcurrentWithSleep.java | 2 +- .../IcfgToChcPreferenceInitializer.java | 98 +++++++++++++++++++ .../preferences/IcfgToChcPreferences.java | 49 ++++------ 7 files changed, 152 insertions(+), 57 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChc.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChc.java index 3a2f34c50c3..57dfeffb5f9 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChc.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChc.java @@ -37,6 +37,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceInitializer; 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.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; /** @@ -72,7 +73,8 @@ public void setInputDefinition(final ModelType graphType) { @Override public List getObservers() { final List observers = new ArrayList<>(); - mObserver = new IcfgToChcObserver(mLogger, mServices); + final var prefs = new IcfgToChcPreferences(IcfgToChcPreferenceInitializer.getPreferenceProvider(mServices)); + mObserver = new IcfgToChcObserver(mLogger, mServices, prefs); observers.add(mObserver); return observers; } @@ -104,7 +106,7 @@ public List getDesiredToolIds() { @Override public IPreferenceInitializer getPreferences() { - return new IcfgToChcPreferences(); + return new IcfgToChcPreferenceInitializer(); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index a0dbfc86c60..72ac00cc785 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -49,9 +49,10 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.Mode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithLbe; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithSleep; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; /** * @@ -62,18 +63,15 @@ public class IcfgToChcObserver extends BaseObserver { private final ILogger mLogger; private final IUltimateServiceProvider mServices; + private final IcfgToChcPreferences mPrefs; private IElement mResult; - // TODO: Make these into settings - private static final boolean TREAT_AS_PARAMETRIC_PROGRAM = true; - private static final boolean USE_LBE_FOR_CONCURRENT_PROGRAMS = false; - private static final boolean USE_SLEEP_SETS = true; - private static final int THREAD_MODULAR_PROOF_LEVEL = 2; - - public IcfgToChcObserver(final ILogger logger, final IUltimateServiceProvider services) { + public IcfgToChcObserver(final ILogger logger, final IUltimateServiceProvider services, + final IcfgToChcPreferences prefs) { mLogger = logger; mServices = services; + mPrefs = prefs; } public IElement getModel() { @@ -111,7 +109,7 @@ private void processIcfg(final IIcfg icfg) { ModelUtils.copyAnnotations(icfg, mResult); } - private Logics getLogics(final Collection resultChcs, final ManagedScript mgdScript) { + private static Logics getLogics(final Collection resultChcs, final ManagedScript mgdScript) { final TermClassifier termClassifierChcs = new TermClassifier(); resultChcs.forEach(chc -> termClassifierChcs.checkTerm(chc.constructFormula(mgdScript, false))); final TermClassifier termClassifierConstraints = new TermClassifier(); @@ -159,24 +157,24 @@ private static boolean isReturnReachable(final IIcfg icfg) { private IChcProvider getChcProvider(final IIcfg icfg, final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable) { - if (TREAT_AS_PARAMETRIC_PROGRAM || IcfgUtils.isConcurrent(icfg)) { + if (mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC || IcfgUtils.isConcurrent(icfg)) { assert !isReturnReachable(icfg); - if (USE_LBE_FOR_CONCURRENT_PROGRAMS) { + if (mPrefs.useLiptonReduction()) { // TODO support LBE for parametric programs - assert !TREAT_AS_PARAMETRIC_PROGRAM; + assert mPrefs.concurrencyMode() == ConcurrencyMode.SINGLE_MAIN_THREAD; // TODO support combination of LBE and sleep sets - assert !USE_SLEEP_SETS; + assert !mPrefs.useSleepSets(); return new ChcProviderConcurrentWithLbe(mgdScript, hcSymbolTable, mServices); } - final var mode = TREAT_AS_PARAMETRIC_PROGRAM ? Mode.PARAMETRIC : Mode.SINGLE_MAIN_THREAD; - if (USE_SLEEP_SETS) { - return new ChcProviderConcurrentWithSleep(mServices, mgdScript, hcSymbolTable, mode, - THREAD_MODULAR_PROOF_LEVEL); + if (mPrefs.useSleepSets()) { + return new ChcProviderConcurrentWithSleep(mServices, mgdScript, hcSymbolTable, mPrefs.concurrencyMode(), + mPrefs.getThreadModularProofLevel()); } - return new ChcProviderConcurrent(mgdScript, hcSymbolTable, mode, THREAD_MODULAR_PROOF_LEVEL); + return new ChcProviderConcurrent(mgdScript, hcSymbolTable, mPrefs.concurrencyMode(), + mPrefs.getThreadModularProofLevel()); } return new ChcProviderForCalls(mgdScript, hcSymbolTable); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java index 973e7d66dd2..76583d5f091 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java @@ -29,17 +29,21 @@ * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) */ public class ChcProviderConcurrent implements IChcProvider { - public enum Mode { + public enum ConcurrencyMode { SINGLE_MAIN_THREAD, PARAMETRIC } + public enum SpecMode { + ASSERT_VIOLATIONS, PRE_POST + } + protected final ManagedScript mMgdScript; protected final HcSymbolTable mHcSymbolTable; - protected final Mode mMode; + protected final ConcurrencyMode mMode; protected final int mLevel; - public ChcProviderConcurrent(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, final Mode mode, - final int level) { + public ChcProviderConcurrent(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, + final ConcurrencyMode mode, final int level) { mMgdScript = mgdScript; mHcSymbolTable = hcSymbolTable; mMode = mode; @@ -118,14 +122,14 @@ public Collection getHornClauses(final IIcfg icfg) { protected Pair, List> getThreadNumbersAndUnboundedThreads(final IIcfg icfg) { - if (mMode == Mode.PARAMETRIC) { + if (mMode == ConcurrencyMode.PARAMETRIC) { final var numberOfThreads = icfg.getInitialNodes().stream().collect(Collectors.toMap(loc -> loc.getProcedure(), loc -> mLevel)); final var unbounded = List.copyOf(numberOfThreads.keySet()); return new Pair<>(numberOfThreads, unbounded); } - assert mMode == Mode.SINGLE_MAIN_THREAD : "Unknown mode: " + mMode; + assert mMode == ConcurrencyMode.SINGLE_MAIN_THREAD : "Unknown mode: " + mMode; final var forksInLoops = IcfgUtils.getForksInLoop(icfg); final var instanceMap = icfg.getCfgSmtToolkit().getConcurrencyInformation().getThreadInstanceMap(); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java index 3f1b28fe995..0613f59c78e 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java @@ -9,7 +9,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.Mode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; /** * ChcProvider for concurrent programs based on the petri-net using LBE. @@ -34,7 +34,7 @@ public ChcProviderConcurrentWithLbe(final ManagedScript mgdScript, final HcSymbo @Override public Collection getHornClauses(final IIcfg icfg) { final var reduced = new IcfgLiptonReducer(mServices, icfg, MAXIMUM_NUMBER_OF_THREADS).getResult(); - return new ChcProviderConcurrent(mMgdScript, mHcSymbolTable, Mode.SINGLE_MAIN_THREAD, MAXIMUM_NUMBER_OF_THREADS) + return new ChcProviderConcurrent(mMgdScript, mHcSymbolTable, ConcurrencyMode.SINGLE_MAIN_THREAD, MAXIMUM_NUMBER_OF_THREADS) .getHornClauses(reduced); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java index ed86d289cca..6f77286af02 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java @@ -40,7 +40,7 @@ public class ChcProviderConcurrentWithSleep extends ChcProviderConcurrent { private final IUltimateServiceProvider mServices; public ChcProviderConcurrentWithSleep(final IUltimateServiceProvider services, final ManagedScript mgdScript, - final HcSymbolTable hcSymbolTable, final Mode mode, final int level) { + final HcSymbolTable hcSymbolTable, final ConcurrencyMode mode, final int level) { super(mgdScript, hcSymbolTable, mode, level); mServices = services; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java new file mode 100644 index 00000000000..b837943c01d --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 Alexander Nutz (nutz@informatik.uni-freiburg.de) + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2019-2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences; + +import de.uni_freiburg.informatik.ultimate.core.lib.preferences.UltimatePreferenceInitializer; +import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; +import de.uni_freiburg.informatik.ultimate.core.model.preferences.PreferenceType; +import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItem; +import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.SpecMode; + +/** + * + * @author Alexander Nutz (nutz@informatik.uni-freiburg.de) + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + */ +public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitializer { + + public static final String LABEL_CONCURRENCY_MODE = "Concurrency mode"; + public static final String DESC_CONCURRENCY_MODE = + "Whether the program starts as a single thread, which may dynamically fork and join new threads, " + + "or as a parametric program, i.e., with an unbounded number of threads, " + + "all starting at once."; + public static final ConcurrencyMode DEF_CONCURRENCY_MODE = ConcurrencyMode.PARAMETRIC; + + public static final String LABEL_SPEC_MODE = "Specification mode"; + public static final String DESC_SPEC_MODE = "Describes how the specification for the program is given."; + public static final SpecMode DEF_SPEC_MODE = SpecMode.PRE_POST; + + public static final String LABEL_THREADMODULAR_LEVEL = "Thread-Modular Proof Level"; + public static final String DESC_THREADMODULAR_LEVEL = "The level at which thread-modular proofs should be computed"; + public static final int DEF_THREADMODULAR_LEVEL = 2; + + public static final String LABEL_LIPTON_REDUCTION = "Apply Lipton reduction"; + public static final String DESC_LIPTON_REDUCTION = "If enabled, Lipton reduction is applied to simplify thread " + + "templates, before a thread-modular proof is computed."; + public static final boolean DEF_LIPTON_REDUCTION = false; + + public static final String LABEL_SLEEP_SET_REDUCTION = "Enable sleep set reduction"; + public static final String DESC_SLEEP_SET_REDUCTION = "If enabled, symbolic sleep set reduction is applied to the " + + "program. This allows for more programs to be proven correct."; + public static final boolean DEF_SLEEP_SET_REDUCTION = true; + + /** + * Default constructor. + */ + public IcfgToChcPreferenceInitializer() { + super(Activator.PLUGIN_ID, Activator.PLUGIN_NAME); + } + + @Override + protected UltimatePreferenceItem[] initDefaultPreferences() { + return new UltimatePreferenceItem[] { + // Settings for thread-modular proofs + new UltimatePreferenceItem<>(LABEL_CONCURRENCY_MODE, DEF_CONCURRENCY_MODE, DESC_CONCURRENCY_MODE, + PreferenceType.Combo, ConcurrencyMode.values()), + new UltimatePreferenceItem<>(LABEL_SPEC_MODE, DEF_SPEC_MODE, DESC_SPEC_MODE, PreferenceType.Combo, + SpecMode.values()), + new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, + DESC_THREADMODULAR_LEVEL, PreferenceType.Integer), + new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, + PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, + DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean) }; + } + + public static IPreferenceProvider getPreferenceProvider(final IUltimateServiceProvider services) { + return services.getPreferenceProvider(Activator.PLUGIN_ID); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 4a82a2f5536..627c2a1e89f 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -1,6 +1,6 @@ /* - * Copyright (C) 2019 Alexander Nutz (nutz@informatik.uni-freiburg.de) - * Copyright (C) 2019 University of Freiburg + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg * * This file is part of the ULTIMATE IcfgToChc plug-in. * @@ -26,41 +26,34 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences; -import de.uni_freiburg.informatik.ultimate.core.lib.preferences.UltimatePreferenceInitializer; import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; -import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItem; -import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.SpecMode; -/** - * - * @author Alexander Nutz (nutz@informatik.uni-freiburg.de) - * - */ -public class IcfgToChcPreferences extends UltimatePreferenceInitializer { +public class IcfgToChcPreferences { + private final IPreferenceProvider mPrefs; -// public static final String LABEL_TRANSFORMATION_TYPE = "TransformationType"; -// private static final String DESC_TRANSFORMATION_TYPE = ""; + public IcfgToChcPreferences(final IPreferenceProvider prefs) { + mPrefs = prefs; + } - /** - * Default constructor. - */ - public IcfgToChcPreferences() { - super(Activator.PLUGIN_ID, Activator.PLUGIN_NAME); + public ConcurrencyMode concurrencyMode() { + return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_CONCURRENCY_MODE, ConcurrencyMode.class); } - @Override - protected UltimatePreferenceItem[] initDefaultPreferences() { - return new UltimatePreferenceItem[] { + public SpecMode specMode() { + return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_SPEC_MODE, SpecMode.class); + } -// new UltimatePreferenceItem<>(LABEL_TRANSFORMATION_TYPE, -// TransformationTestType.LOOP_ACCELERATION_EXAMPLE, DESC_TRANSFORMATION_TYPE, -// PreferenceType.Combo, TransformationTestType.values()), + public int getThreadModularProofLevel() { + return mPrefs.getInt(IcfgToChcPreferenceInitializer.LABEL_THREADMODULAR_LEVEL); + } - }; + public boolean useLiptonReduction() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_LIPTON_REDUCTION); } - public static IPreferenceProvider getPreferenceProvider(final IUltimateServiceProvider services) { - return services.getPreferenceProvider(Activator.PLUGIN_ID); + public boolean useSleepSets() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SLEEP_SET_REDUCTION); } } From 77aeaca517a4a5c53d85842e7f7ae61947c09040 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 18 Apr 2023 22:16:26 +0200 Subject: [PATCH 016/114] extract ConcurrencyMode functionality --- .../plugins/icfgtochc/IcfgToChcObserver.java | 2 +- .../concurrent/ChcProviderConcurrent.java | 69 +--------- .../ChcProviderConcurrentWithLbe.java | 1 - .../icfgtochc/concurrent/ConcurrencyMode.java | 125 ++++++++++++++++++ .../IcfgToChcPreferenceInitializer.java | 4 +- .../preferences/IcfgToChcPreferences.java | 7 +- 6 files changed, 137 insertions(+), 71 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 72ac00cc785..f1763038928 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -49,9 +49,9 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithLbe; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithSleep; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; /** diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java index 76583d5f091..fecb4deb923 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -10,7 +9,6 @@ import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgForkTransitionThreadCurrent; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgJoinTransitionThreadCurrent; @@ -29,13 +27,6 @@ * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) */ public class ChcProviderConcurrent implements IChcProvider { - public enum ConcurrencyMode { - SINGLE_MAIN_THREAD, PARAMETRIC - } - - public enum SpecMode { - ASSERT_VIOLATIONS, PRE_POST - } protected final ManagedScript mMgdScript; protected final HcSymbolTable mHcSymbolTable; @@ -54,14 +45,15 @@ public ChcProviderConcurrent(final ManagedScript mgdScript, final HcSymbolTable @Override public Collection getHornClauses(final IIcfg icfg) { - final var threadBounds = getThreadNumbersAndUnboundedThreads(icfg); + final var threadBounds = mMode.getThreadNumbersAndUnboundedThreads(icfg, mLevel); final var numberOfThreads = threadBounds.getFirst(); final var unboundedThreads = threadBounds.getSecond(); final var factory = createFactory(numberOfThreads, icfg); final List result = new ArrayList<>(); - final var initialClause = factory.buildInitialClause(getInitialLocations(icfg, factory.getInstances())).build(); + final var initialClause = + factory.buildInitialClause(mMode.getInitialLocations(icfg, factory.getInstances())).build(); result.add(initialClause); final Map entryNodes = icfg.getProcedureEntryNodes(); @@ -120,60 +112,7 @@ public Collection getHornClauses(final IIcfg icfg) { .collect(Collectors.toList()); } - protected Pair, List> - getThreadNumbersAndUnboundedThreads(final IIcfg icfg) { - if (mMode == ConcurrencyMode.PARAMETRIC) { - final var numberOfThreads = - icfg.getInitialNodes().stream().collect(Collectors.toMap(loc -> loc.getProcedure(), loc -> mLevel)); - final var unbounded = List.copyOf(numberOfThreads.keySet()); - return new Pair<>(numberOfThreads, unbounded); - } - - assert mMode == ConcurrencyMode.SINGLE_MAIN_THREAD : "Unknown mode: " + mMode; - - final var forksInLoops = IcfgUtils.getForksInLoop(icfg); - final var instanceMap = icfg.getCfgSmtToolkit().getConcurrencyInformation().getThreadInstanceMap(); - final Map numberOfThreads = new HashMap<>(); - icfg.getInitialNodes().forEach(x -> numberOfThreads.put(x.getProcedure(), 1)); - final List unboundedThreads = new ArrayList<>(); - // TODO: This needs to be more accurate in general - for (final var fork : instanceMap.keySet()) { - final String procedure = fork.getNameOfForkedProcedure(); - // TODO: Only add if fork is reachable - if (forksInLoops.contains(fork)) { - numberOfThreads.put(procedure, mLevel); - unboundedThreads.add(procedure); - } else { - final Integer oldCount = numberOfThreads.getOrDefault(procedure, 0); - if (oldCount == mLevel) { - unboundedThreads.add(procedure); - } else { - numberOfThreads.put(procedure, oldCount + 1); - } - } - } - - return new Pair<>(numberOfThreads, unboundedThreads); - } - - protected Map getInitialLocations(final IIcfg icfg, - final List instances) { - switch (mMode) { - case PARAMETRIC: - // combine each initial location (usually there is only one) with ALL instances of its template - return icfg - .getInitialNodes().stream().flatMap(l -> instances.stream() - .filter(i -> i.getTemplateName().equals(l.getProcedure())).map(i -> new Pair<>(i, l))) - .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); - case SINGLE_MAIN_THREAD: - // combine each initial location (usually there is only one) with instance 0 of its template - return icfg.getInitialNodes().stream() - .collect(Collectors.toMap(l -> new ThreadInstance(l.getProcedure(), 0), l -> l)); - } - throw new UnsupportedOperationException("Unknown mode: " + mMode); - } - - protected List> getErrorLocations(final IIcfg icfg, + private static List> getErrorLocations(final IIcfg icfg, final List instances) { return icfg.getProcedureErrorNodes().entrySet().stream() .flatMap(e -> e.getValue().stream().map(l -> new Pair<>(e.getKey(), l))).flatMap(e -> instances.stream() diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java index 0613f59c78e..44eef72a887 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java @@ -9,7 +9,6 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; /** * ChcProvider for concurrent programs based on the petri-net using LBE. diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java new file mode 100644 index 00000000000..6c515e5c599 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; + +public enum ConcurrencyMode { + /** + * A single instance of the main thread is started initially. More threads are created dynamically through fork and + * join statements. + */ + SINGLE_MAIN_THREAD, + + /** + * An unbounded number of threads (all with the same template) are all started at the same time. + */ + PARAMETRIC; + + /** + * Given an {@link IIcfg}, determines how many thread instances of each template should be considered, and for which + * thread templates we assume an unbounded number of instances. + * + * @param icfg + * The (unpetrified) control flow graph of the concurrent program + * @param level + * The thread modularity level of the analysis + * @return a pair, where the first component maps each thread template to the number of instances to consider, and + * the second component contains all threads that may have more than {@code level} instances. + */ + public Pair, List> getThreadNumbersAndUnboundedThreads(final IIcfg icfg, + final int level) { + if (this == ConcurrencyMode.PARAMETRIC) { + final var numberOfThreads = + icfg.getInitialNodes().stream().collect(Collectors.toMap(loc -> loc.getProcedure(), loc -> level)); + final var unbounded = List.copyOf(numberOfThreads.keySet()); + return new Pair<>(numberOfThreads, unbounded); + } + + assert this == ConcurrencyMode.SINGLE_MAIN_THREAD : "Unknown mode: " + this; + + final var forksInLoops = IcfgUtils.getForksInLoop(icfg); + final var instanceMap = icfg.getCfgSmtToolkit().getConcurrencyInformation().getThreadInstanceMap(); + final Map numberOfThreads = new HashMap<>(); + icfg.getInitialNodes().forEach(x -> numberOfThreads.put(x.getProcedure(), 1)); + final List unboundedThreads = new ArrayList<>(); + // TODO: This needs to be more accurate in general + for (final var fork : instanceMap.keySet()) { + final String procedure = fork.getNameOfForkedProcedure(); + // TODO: Only add if fork is reachable + if (forksInLoops.contains(fork)) { + numberOfThreads.put(procedure, level); + unboundedThreads.add(procedure); + } else { + final Integer oldCount = numberOfThreads.getOrDefault(procedure, 0); + if (oldCount == level) { + unboundedThreads.add(procedure); + } else { + numberOfThreads.put(procedure, oldCount + 1); + } + } + } + + return new Pair<>(numberOfThreads, unboundedThreads); + } + + /** + * Determines the initial locations of a given program. + * + * @param icfg + * The control flow graph of the program + * @param instances + * The set of thread instances considered by the analyis + * @return A mapping from initially running thread instances to their initial locations + */ + public Map getInitialLocations(final IIcfg icfg, + final List instances) { + switch (this) { + case PARAMETRIC: + // combine each initial location (usually there is only one) with ALL instances of its template + return icfg + .getInitialNodes().stream().flatMap(l -> instances.stream() + .filter(i -> i.getTemplateName().equals(l.getProcedure())).map(i -> new Pair<>(i, l))) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + case SINGLE_MAIN_THREAD: + // combine each initial location (usually there is only one) with instance 0 of its template + return icfg.getInitialNodes().stream() + .collect(Collectors.toMap(l -> new ThreadInstance(l.getProcedure(), 0), l -> l)); + } + throw new UnsupportedOperationException("Unknown mode: " + this); + } +} \ No newline at end of file diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index b837943c01d..f5896b2f84b 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -33,8 +33,8 @@ import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItem; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.SpecMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences.SpecMode; /** * diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 627c2a1e89f..5f95db4960e 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -27,12 +27,15 @@ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences; import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.ConcurrencyMode; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent.SpecMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; public class IcfgToChcPreferences { private final IPreferenceProvider mPrefs; + public enum SpecMode { + ASSERT_VIOLATIONS, PRE_POST + } + public IcfgToChcPreferences(final IPreferenceProvider prefs) { mPrefs = prefs; } From b6359addecc64e84981e490714695e8ce6b8f9ce Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 18 Apr 2023 23:19:16 +0200 Subject: [PATCH 017/114] refactor Horn clause generation Definition of the different kinds of clauses, and iteration over the Icfg are tightly coupled. Hence they are now managed by the same class. --- .../icfgtochc/ChcProviderForCalls.java | 4 +- .../plugins/icfgtochc/IcfgToChcObserver.java | 34 ++--- .../concurrent/ChcProviderConcurrent.java | 128 ------------------ .../ChcProviderConcurrentWithLbe.java | 39 ------ .../ChcProviderConcurrentWithSleep.java | 57 -------- .../icfgtochc/concurrent/ConcurrencyMode.java | 11 +- ...eepSetThreadModularHornClauseProvider.java | 23 ++-- .../ThreadModularHornClauseProvider.java | 116 ++++++++++++++-- 8 files changed, 136 insertions(+), 276 deletions(-) delete mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java delete mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java delete mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java index 68e57b8daf5..742c83d39a8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java @@ -41,7 +41,6 @@ import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder.cfg.Call; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; /** * @@ -49,7 +48,7 @@ * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) * */ -public class ChcProviderForCalls implements IChcProvider { +public class ChcProviderForCalls { private final ManagedScript mMgdScript; private final HcSymbolTable mHcSymbolTable; private IIcfg mIcfg; @@ -71,7 +70,6 @@ public ChcProviderForCalls(final ManagedScript mgdScript, final HcSymbolTable hc mMgdScript.constructFreshTermVariable(ASSERTIONVIOLATEDVARNAME, SmtSortUtils.getBoolSort(mMgdScript)); } - @Override @SuppressWarnings("unchecked") public Collection getHornClauses(final IIcfg icfg) { /* add chcs for the icfg's edges */ diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index f1763038928..7b1e785da27 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -47,11 +47,12 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; import de.uni_freiburg.informatik.ultimate.logic.Logics; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrent; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithLbe; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ChcProviderConcurrentWithSleep; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.SleepSetThreadModularHornClauseProvider; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; /** @@ -91,10 +92,11 @@ public boolean process(final IElement root) throws Exception { private void processIcfg(final IIcfg icfg) { final ManagedScript mgdScript = icfg.getCfgSmtToolkit().getManagedScript(); final HcSymbolTable hcSymbolTable = new HcSymbolTable(mgdScript); - final Collection resultChcs = getChcProvider(icfg, mgdScript, hcSymbolTable).getHornClauses(icfg); + final Collection resultChcs = getHornClauses(icfg, mgdScript, hcSymbolTable); final boolean isReturnReachable = isReturnReachable(icfg); - final boolean hasNonLinearClauses = isReturnReachable || !IcfgUtils.getForksInLoop(icfg).isEmpty(); + final boolean hasNonLinearClauses = isReturnReachable || !IcfgUtils.getForksInLoop(icfg).isEmpty() + || mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC; final ChcCategoryInfo chcCategoryInfo = new ChcCategoryInfo(getLogics(resultChcs, mgdScript), hasNonLinearClauses); @@ -155,7 +157,7 @@ private static boolean isReturnReachable(final IIcfg icfg) { return new IcfgEdgeIterator(icfg).asStream().anyMatch(IIcfgSummaryTransition.class::isInstance); } - private IChcProvider getChcProvider(final IIcfg icfg, final ManagedScript mgdScript, + private Collection getHornClauses(IIcfg icfg, final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable) { if (mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC || IcfgUtils.isConcurrent(icfg)) { assert !isReturnReachable(icfg); @@ -166,20 +168,20 @@ private IChcProvider getChcProvider(final IIcfg icfg, final Manage // TODO support combination of LBE and sleep sets assert !mPrefs.useSleepSets(); - return new ChcProviderConcurrentWithLbe(mgdScript, hcSymbolTable, mServices); + // Create 2 instances of every thread, to ensure the reduction checks mover properties of each thread + // template against another copy of the same template. + final int instanceCount = 2; + + icfg = new IcfgLiptonReducer(mServices, icfg, instanceCount).getResult(); } if (mPrefs.useSleepSets()) { - return new ChcProviderConcurrentWithSleep(mServices, mgdScript, hcSymbolTable, mPrefs.concurrencyMode(), - mPrefs.getThreadModularProofLevel()); + final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, true); + return new SleepSetThreadModularHornClauseProvider(mgdScript, icfg, hcSymbolTable, independence, mPrefs) + .getClauses(); } - return new ChcProviderConcurrent(mgdScript, hcSymbolTable, mPrefs.concurrencyMode(), - mPrefs.getThreadModularProofLevel()); + return new ThreadModularHornClauseProvider(mgdScript, icfg, hcSymbolTable, mPrefs).getClauses(); } - return new ChcProviderForCalls(mgdScript, hcSymbolTable); - } - - public interface IChcProvider { - Collection getHornClauses(final IIcfg icfg); + return new ChcProviderForCalls(mgdScript, hcSymbolTable).getHornClauses(icfg); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java deleted file mode 100644 index fecb4deb923..00000000000 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrent.java +++ /dev/null @@ -1,128 +0,0 @@ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgForkTransitionThreadCurrent; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgJoinTransitionThreadCurrent; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; -import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; -import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Triple; - -/** - * ChcProvider for concurrent programs based on the icfg. - * - * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) - * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - */ -public class ChcProviderConcurrent implements IChcProvider { - - protected final ManagedScript mMgdScript; - protected final HcSymbolTable mHcSymbolTable; - protected final ConcurrencyMode mMode; - protected final int mLevel; - - public ChcProviderConcurrent(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, - final ConcurrencyMode mode, final int level) { - mMgdScript = mgdScript; - mHcSymbolTable = hcSymbolTable; - mMode = mode; - mLevel = level; - - assert level >= 1; - } - - @Override - public Collection getHornClauses(final IIcfg icfg) { - final var threadBounds = mMode.getThreadNumbersAndUnboundedThreads(icfg, mLevel); - final var numberOfThreads = threadBounds.getFirst(); - final var unboundedThreads = threadBounds.getSecond(); - - final var factory = createFactory(numberOfThreads, icfg); - final List result = new ArrayList<>(); - - final var initialClause = - factory.buildInitialClause(mMode.getInitialLocations(icfg, factory.getInstances())).build(); - result.add(initialClause); - - final Map entryNodes = icfg.getProcedureEntryNodes(); - for (final String proc : numberOfThreads.keySet()) { - final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); - while (edges.hasNext()) { - final IcfgEdge edge = edges.next(); - for (final var prePost : getCartesianPrePostProduct(factory, icfg, edge)) { - final var clause = factory - .buildInductivityClause(edge, prePost.getFirst(), prePost.getSecond(), prePost.getThird()) - .build(); - result.add(clause); - } - - if (unboundedThreads.contains(proc)) { - result.add(factory.buildNonInterferenceClause(edge).build()); - } - } - } - - final var errorLocs = getErrorLocations(icfg, factory.getInstances()); - for (final var pair : errorLocs) { - final var safetyClause = factory.buildSafetyClause(pair.getFirst(), pair.getSecond()).build(); - result.add(safetyClause); - } - - return result; - } - - private static List, Map, ThreadInstance>> - getCartesianPrePostProduct(final ThreadModularHornClauseProvider factory, final IIcfg icfg, - final IcfgEdge edge) { - if (edge instanceof IIcfgForkTransitionThreadCurrent) { - final var forkCurrent = (IIcfgForkTransitionThreadCurrent) edge; - final var forkEntry = icfg.getProcedureEntryNodes().get(forkCurrent.getNameOfForkedProcedure()); - final var result = - new ArrayList, Map, ThreadInstance>>(); - for (final var instance : factory.getInstances(edge.getPrecedingProcedure())) { - final var preds = Map.of(instance, edge.getSource()); - for (final var forked : factory.getInstances(forkCurrent.getNameOfForkedProcedure())) { - if (Objects.equals(instance, forked)) { - continue; - } - final var succs = Map.of(instance, edge.getTarget(), forked, forkEntry); - result.add(new Triple<>(preds, succs, instance)); - } - } - return result; - } - if (edge instanceof IIcfgJoinTransitionThreadCurrent) { - assert false : "Joins not supported"; - } - - return factory.getInstances(edge.getPrecedingProcedure()).stream() - .map(t -> new Triple<>(Map.of(t, edge.getSource()), Map.of(t, edge.getTarget()), t)) - .collect(Collectors.toList()); - } - - private static List> getErrorLocations(final IIcfg icfg, - final List instances) { - return icfg.getProcedureErrorNodes().entrySet().stream() - .flatMap(e -> e.getValue().stream().map(l -> new Pair<>(e.getKey(), l))).flatMap(e -> instances.stream() - .filter(i -> i.getTemplateName().equals(e.getKey())).map(i -> new Pair<>(i, e.getValue()))) - .collect(Collectors.toList()); - } - - protected ThreadModularHornClauseProvider createFactory(final Map numberOfThreads, - final IIcfg icfg) { - return new ThreadModularHornClauseProvider(numberOfThreads, mMgdScript, icfg.getCfgSmtToolkit(), mHcSymbolTable, - x -> true); - } -} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java deleted file mode 100644 index 44eef72a887..00000000000 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithLbe.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; - -import java.util.Collection; - -import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.IcfgToChcObserver.IChcProvider; - -/** - * ChcProvider for concurrent programs based on the petri-net using LBE. - * - * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) - * - */ -public class ChcProviderConcurrentWithLbe implements IChcProvider { - private static final int MAXIMUM_NUMBER_OF_THREADS = 2; - - private final ManagedScript mMgdScript; - private final HcSymbolTable mHcSymbolTable; - private final IUltimateServiceProvider mServices; - - public ChcProviderConcurrentWithLbe(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, - final IUltimateServiceProvider services) { - mMgdScript = mgdScript; - mHcSymbolTable = hcSymbolTable; - mServices = services; - } - - @Override - public Collection getHornClauses(final IIcfg icfg) { - final var reduced = new IcfgLiptonReducer(mServices, icfg, MAXIMUM_NUMBER_OF_THREADS).getResult(); - return new ChcProviderConcurrent(mMgdScript, mHcSymbolTable, ConcurrencyMode.SINGLE_MAIN_THREAD, MAXIMUM_NUMBER_OF_THREADS) - .getHornClauses(reduced); - } -} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java deleted file mode 100644 index 6f77286af02..00000000000 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ChcProviderConcurrentWithSleep.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * Copyright (C) 2023 University of Freiburg - * - * This file is part of the ULTIMATE IcfgToChc plug-in. - * - * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . - * - * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission - * to convey the resulting work. - */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; - -import java.util.Map; -import java.util.stream.Collectors; - -import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; - -public class ChcProviderConcurrentWithSleep extends ChcProviderConcurrent { - private final IUltimateServiceProvider mServices; - - public ChcProviderConcurrentWithSleep(final IUltimateServiceProvider services, final ManagedScript mgdScript, - final HcSymbolTable hcSymbolTable, final ConcurrencyMode mode, final int level) { - super(mgdScript, hcSymbolTable, mode, level); - mServices = services; - } - - @Override - protected ThreadModularHornClauseProvider createFactory(final Map numberOfThreads, - final IIcfg icfg) { - final var independence = new SemanticIndependenceRelation<>(mServices, mMgdScript, false, true); - final var locations = icfg.getProgramPoints().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); - return new SleepSetThreadModularHornClauseProvider(numberOfThreads, mMgdScript, icfg.getCfgSmtToolkit(), - mHcSymbolTable, x -> true, independence, locations); - } -} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java index 6c515e5c599..8ba4d826ebb 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java @@ -27,10 +27,11 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; -import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; @@ -61,12 +62,12 @@ public enum ConcurrencyMode { * @return a pair, where the first component maps each thread template to the number of instances to consider, and * the second component contains all threads that may have more than {@code level} instances. */ - public Pair, List> getThreadNumbersAndUnboundedThreads(final IIcfg icfg, + public Pair, Set> getThreadNumbersAndUnboundedThreads(final IIcfg icfg, final int level) { if (this == ConcurrencyMode.PARAMETRIC) { final var numberOfThreads = icfg.getInitialNodes().stream().collect(Collectors.toMap(loc -> loc.getProcedure(), loc -> level)); - final var unbounded = List.copyOf(numberOfThreads.keySet()); + final var unbounded = Set.copyOf(numberOfThreads.keySet()); return new Pair<>(numberOfThreads, unbounded); } @@ -76,7 +77,7 @@ public Pair, List> getThreadNumbersAndUnboundedThre final var instanceMap = icfg.getCfgSmtToolkit().getConcurrencyInformation().getThreadInstanceMap(); final Map numberOfThreads = new HashMap<>(); icfg.getInitialNodes().forEach(x -> numberOfThreads.put(x.getProcedure(), 1)); - final List unboundedThreads = new ArrayList<>(); + final Set unboundedThreads = new HashSet<>(); // TODO: This needs to be more accurate in general for (final var fork : instanceMap.keySet()) { final String procedure = fork.getNameOfForkedProcedure(); @@ -106,7 +107,7 @@ public Pair, List> getThreadNumbersAndUnboundedThre * The set of thread instances considered by the analyis * @return A mapping from initially running thread instances to their initial locations */ - public Map getInitialLocations(final IIcfg icfg, + public Map getInitialLocations(final IIcfg icfg, final List instances) { switch (this) { case PARAMETRIC: diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 4ff4ed0c455..262a26b98ab 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -30,21 +30,19 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; -import java.util.function.Predicate; import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; +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.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornClauseProvider { @@ -54,14 +52,13 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornCl private final Map mIdVars; private final Map mSleepVars; - public SleepSetThreadModularHornClauseProvider(final Map numberOfThreads, - final ManagedScript mgdScript, final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable symbolTable, - final Predicate variableFilter, - final IIndependenceRelation> independence, - final Map> threadLocations) { - super(numberOfThreads, mgdScript, cfgSmtToolkit, symbolTable, variableFilter); + public SleepSetThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcfg icfg, + final HcSymbolTable symbolTable, final IIndependenceRelation> independence, + final IcfgToChcPreferences prefs) { + super(mgdScript, icfg, symbolTable, prefs); mIndependence = independence; - mThreadLocations = threadLocations; + mThreadLocations = icfg.getProgramPoints().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); mIdVars = extractThreadVars(HcThreadIdVar.class); mSleepVars = extractThreadVars(HcSleepVar.class); @@ -86,8 +83,8 @@ protected List createThreadSpecificVars(final ThreadInstan } @Override - protected HornClauseBuilder buildInitialClause(final Map initialLocations) { - final var clause = super.buildInitialClause(initialLocations); + protected HornClauseBuilder buildInitialClause() { + final var clause = super.buildInitialClause(); // all sleep variables are initialized to false for (final var instance : mInstances) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 80a1cea69b8..f58d4952fff 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -41,9 +41,13 @@ import java.util.stream.Stream; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgForkTransitionThreadCurrent; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgJoinTransitionThreadCurrent; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgTransition; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; @@ -53,9 +57,11 @@ import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Triple; /** * Generates Horn clauses for a thread-modular proof. @@ -68,6 +74,8 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide private static final String FUNCTION_NAME = "Inv"; private static final int INTERFERING_INSTANCE_ID = -1; + protected final IIcfg mIcfg; + protected final IcfgToChcPreferences mPrefs; private final IIcfgSymbolTable mCfgSymbolTable; private final Predicate mVariableFilter; @@ -78,7 +86,9 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide // used as location for threads that are not currently running private final Term mBottomLocation; + protected final Set mTemplates; protected final List mInstances; + protected final Set mUnboundedTemplates; protected final PredicateInfo mInvariantPredicate; @@ -87,14 +97,27 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide protected final Map mLocationVars = new HashMap<>(); protected final NestedMap2 mLocalVars = new NestedMap2<>(); - public ThreadModularHornClauseProvider(final Map numberOfThreads, final ManagedScript mgdScript, - final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable symbolTable, - final Predicate variableFilter) { + public ThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcfg icfg, + final HcSymbolTable symbolTable, final IcfgToChcPreferences prefs) { + this(mgdScript, icfg, symbolTable, x -> true, prefs); + } + + public ThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcfg icfg, + final HcSymbolTable symbolTable, final Predicate variableFilter, + final IcfgToChcPreferences prefs) { super(mgdScript, symbolTable); - mCfgSymbolTable = cfgSmtToolkit.getSymbolTable(); + mIcfg = icfg; + mPrefs = prefs; + mCfgSymbolTable = mIcfg.getCfgSmtToolkit().getSymbolTable(); mVariableFilter = variableFilter; + + final var threadInfo = + mPrefs.concurrencyMode().getThreadNumbersAndUnboundedThreads(icfg, mPrefs.getThreadModularProofLevel()); + mTemplates = Set.copyOf(threadInfo.getFirst().keySet()); + mInstances = getInstances(threadInfo.getFirst()); + mUnboundedTemplates = threadInfo.getSecond(); + mBottomLocation = numeral(-1); - mInstances = getInstances(numberOfThreads); mInvariantPredicate = createInvariantPredicate(); } @@ -193,34 +216,93 @@ protected List createThreadSpecificVars(final ThreadInstan return result; } - // Horn clause generation + // IIcfg iteration // ----------------------------------------------------------------------------------------------------------------- @Override protected List buildAllClauses() { final var result = new ArrayList(); - // result.add(buildInitialClause()); - // for (final var entry : mErrorLocations.getSetOfPairs()) { - // result.add(buildSafetyClause(entry.getKey(), entry.getValue())); - // } - // TODO inductive clauses - // TODO noninterference clauses + final var initialClause = buildInitialClause(); + result.add(initialClause); + + final var entryNodes = mIcfg.getProcedureEntryNodes(); + for (final String proc : mTemplates) { + final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); + while (edges.hasNext()) { + final IcfgEdge edge = edges.next(); + for (final var prePost : getCartesianPrePostProduct(edge)) { + final var clause = + buildInductivityClause(edge, prePost.getFirst(), prePost.getSecond(), prePost.getThird()); + result.add(clause); + } + + if (mUnboundedTemplates.contains(proc)) { + result.add(buildNonInterferenceClause(edge)); + } + } + } + + final var errorLocs = getErrorLocations(); + for (final var pair : errorLocs) { + final var safetyClause = buildSafetyClause(pair.getFirst(), pair.getSecond()); + result.add(safetyClause); + } return result; } + private List, Map, ThreadInstance>> + getCartesianPrePostProduct(final IcfgEdge edge) { + if (edge instanceof IIcfgForkTransitionThreadCurrent) { + final var forkCurrent = (IIcfgForkTransitionThreadCurrent) edge; + final var forkEntry = mIcfg.getProcedureEntryNodes().get(forkCurrent.getNameOfForkedProcedure()); + final var result = + new ArrayList, Map, ThreadInstance>>(); + for (final var instance : getInstances(edge.getPrecedingProcedure())) { + final var preds = Map.of(instance, edge.getSource()); + for (final var forked : getInstances(forkCurrent.getNameOfForkedProcedure())) { + if (Objects.equals(instance, forked)) { + continue; + } + final var succs = Map.of(instance, edge.getTarget(), forked, forkEntry); + result.add(new Triple<>(preds, succs, instance)); + } + } + return result; + } + if (edge instanceof IIcfgJoinTransitionThreadCurrent) { + assert false : "Joins not supported"; + } + + return getInstances(edge.getPrecedingProcedure()).stream() + .map(t -> new Triple<>(Map.of(t, edge.getSource()), Map.of(t, edge.getTarget()), t)) + .collect(Collectors.toList()); + } + + private List> getErrorLocations() { + return mIcfg.getProcedureErrorNodes().entrySet().stream() + .flatMap(e -> e.getValue().stream().map(l -> new Pair<>(e.getKey(), l))) + .flatMap(e -> mInstances.stream().filter(i -> i.getTemplateName().equals(e.getKey())) + .> map(i -> new Pair<>(i, e.getValue()))) + .collect(Collectors.toList()); + } + + // Horn clause generation + // ----------------------------------------------------------------------------------------------------------------- + /** * Builds the initial clause that encodes the precondition. By default, this method only fixes the initial location * of the threads. */ - protected HornClauseBuilder buildInitialClause(final Map initialLocations) { + protected HornClauseBuilder buildInitialClause() { final var clause = createBuilder(mInvariantPredicate, "initial clause"); // add location constraints + final var initialLocs = getInitialLocations(); for (final var instance : mInstances) { // If instance does not have an initial location, a constraint for mBottomLocation is added. - addOutLocationConstraint(clause, instance, initialLocations.get(instance)); + addOutLocationConstraint(clause, instance, initialLocs.get(instance)); } return clause; @@ -340,6 +422,10 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition // Auxiliary methods // ----------------------------------------------------------------------------------------------------------------- + protected Map getInitialLocations() { + return mPrefs.concurrencyMode().getInitialLocations(mIcfg, mInstances); + } + protected void addInLocationConstraint(final HornClauseBuilder clause, final ThreadInstance threadInstance, final IcfgLocation location) { final var locTerm = From dc6408f8238dc0132f60886eb7df48b3657ff91d Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 18 Apr 2023 23:27:58 +0200 Subject: [PATCH 018/114] remove obsolete code --- .../icfgtochc/concurrent/HcGlobalVar.java | 1 - .../icfgtochc/concurrent/HcLocalVar.java | 5 +- .../icfgtochc/concurrent/HcLocationVar.java | 3 +- .../icfgtochc/concurrent/HcSleepVar.java | 3 +- .../icfgtochc/concurrent/HcThreadIdVar.java | 3 +- .../concurrent/HornClauseBuilder.java | 1 - .../concurrent/IHcReplacementVar.java | 33 + .../concurrent/IHcThreadSpecificVar.java | 12 - .../concurrent/IcfgToChcConcurrent.java | 759 ------------------ .../icfgtochc/concurrent/PredicateInfo.java | 1 - .../icfgtochc/concurrent/ThreadInstance.java | 2 +- .../ThreadModularHornClauseProvider.java | 5 +- 12 files changed, 42 insertions(+), 786 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java delete mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java index f2646521cb2..ae84542e662 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java @@ -4,7 +4,6 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; /** * diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java index 67b67e4e849..092195d5358 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java @@ -14,9 +14,10 @@ public class HcLocalVar implements IHcThreadSpecificVar { private final IProgramVar mVariable; private final ThreadInstance mInstance; - public HcLocalVar(final IProgramVar variable, final int instanceNumber) { + public HcLocalVar(final IProgramVar variable, final ThreadInstance instance) { + assert variable.getProcedure().equals(instance.getTemplateName()); mVariable = variable; - mInstance = new ThreadInstance(mVariable.getProcedure(), instanceNumber); + mInstance = instance; } public IProgramVar getVariable() { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java index f1fe01879c0..c6bbdb71d99 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java @@ -30,8 +30,7 @@ public Sort getSort() { @Override public String toString() { - return "loc_" + IcfgToChcConcurrentUtils.getReadableString(mInstance.getTemplateName()) + "_" - + (mInstance.getInstanceNumber() + 1); + return "loc_" + mInstance; } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index 65ec8a70148..0247f66f732 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -51,8 +51,7 @@ public ThreadInstance getThreadInstance() { @Override public String toString() { - return "sleep_" + IcfgToChcConcurrentUtils.getReadableString(mInstance.getTemplateName()) + "_" - + (mInstance.getInstanceNumber() + 1); + return "sleep_" + mInstance; } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java index fa8c35b2296..f05240c07aa 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java @@ -54,8 +54,7 @@ public ThreadInstance getThreadInstance() { @Override public String toString() { - return "id_" + IcfgToChcConcurrentUtils.getReadableString(mInstance.getTemplateName()) + "_" - + (mInstance.getInstanceNumber() + 1); + return "id_" + mInstance; } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 0fe8da638f0..b6d8786d824 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -47,7 +47,6 @@ import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; public class HornClauseBuilder { private final ManagedScript mManagedScript; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java new file mode 100644 index 00000000000..33a3033da31 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import de.uni_freiburg.informatik.ultimate.logic.Sort; + +public interface IHcReplacementVar { + Sort getSort(); +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java index 8f537d5efcb..389f62066ef 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java @@ -26,18 +26,6 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; - public interface IHcThreadSpecificVar extends IHcReplacementVar { ThreadInstance getThreadInstance(); - - @Deprecated - default String getThreadTemplateName() { - return getThreadInstance().getTemplateName(); - } - - @Deprecated - default int getInstanceIndex() { - return getThreadInstance().getInstanceNumber(); - } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java deleted file mode 100644 index f98ead848fb..00000000000 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrent.java +++ /dev/null @@ -1,759 +0,0 @@ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcBodyVar; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcHeadVar; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcVar; -import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; -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.variables.IProgramVar; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.Substitution; -import de.uni_freiburg.informatik.ultimate.logic.Script; -import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.logic.Term; -import de.uni_freiburg.informatik.ultimate.logic.TermVariable; -import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; -import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; - -/** - * Class to create horn-clauses for given edges to create thread-modular proofs. - * - * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) - * - */ -public class IcfgToChcConcurrent { - private static final String FUNCTION_NAME = "Inv"; - private static final int INTERFERING_INSTANCE_ID = -1; - - private final ManagedScript mManagedScript; - - // maps a procedure name and a location (in the procedure) to an integer, such that the location variable has this - // integer as value iff control is in the given location - private final NestedMap2 mLocationIndices = new NestedMap2<>(); - - // maps each thread template (identified by procedure name) to the number of instances - private final Map mNumberOfThreads; - - // used as location for threads that are not currently running - private final Term mBottomLocation; - - private final HcPredicateSymbol mPredicate; - private final HcSymbolTable mHcSymbolTable; - - // list of "head vars" (?), in the order as given to the CHC predicate - // these variables are always used in the head of any clause generated by this class - private final List mDefaultHeadVars; - - private final Map mSleepVars = new HashMap<>(); - private final Map mLocationsVars = new HashMap<>(); - private final Map mIdVars = new HashMap<>(); - - private final Map> mThreadLocations; - - /** - * maps a number i to the variable used for the i-th argument of the CHC predicate - */ - private final BidirectionalMap mPositions2Vars = new BidirectionalMap<>(); - - private final IIndependenceRelation> mIndependence; - - /** - * - * @param numberOfThreads - * Maps thread names to the number of instances to include in the Horn clause system - * @param managedScript - * @param cfgSmtToolkit - * @param hcSymbolTable - * @param variableFilter - * - */ - public IcfgToChcConcurrent(final Map numberOfThreads, final ManagedScript managedScript, - final CfgSmtToolkit cfgSmtToolkit, final HcSymbolTable hcSymbolTable, - final Predicate variableFilter, final Map> threadLocations, - final IIndependenceRelation> independence) { - final IIcfgSymbolTable symbolTable = cfgSmtToolkit.getSymbolTable(); - mHcSymbolTable = hcSymbolTable; - mManagedScript = managedScript; - final List globalVariables = - symbolTable.getGlobals().stream().filter(variableFilter).collect(Collectors.toList()); - mNumberOfThreads = new LinkedHashMap<>(numberOfThreads); - mBottomLocation = numeral(-1); - mThreadLocations = threadLocations; - mIndependence = independence; - - final Map> localVariables = new HashMap<>(); - for (final String proc : mNumberOfThreads.keySet()) { - localVariables.put(proc, - symbolTable.getLocals(proc).stream().filter(variableFilter).collect(Collectors.toList())); - } - initializeDefaultVars(globalVariables, localVariables); - - final List sorts = IntStream.range(0, mPositions2Vars.size()) - .mapToObj(x -> mPositions2Vars.get(x).getSort()).collect(Collectors.toList()); - mPredicate = hcSymbolTable.getOrConstructHornClausePredicateSymbol(FUNCTION_NAME, sorts); - - mDefaultHeadVars = IntStream.range(0, mPositions2Vars.size()) - .mapToObj(x -> constructHeadVar(mPositions2Vars.get(x), x)).collect(Collectors.toList()); - } - - private HcHeadVar constructHeadVar(final IHcReplacementVar rv, final int index) { - return mHcSymbolTable.getOrConstructHeadVar(mPredicate, index, rv.getSort(), rv); - } - - private void addVariable(final IHcReplacementVar variable) { - mPositions2Vars.put(mPositions2Vars.size(), variable); - } - - private void initializeDefaultVars(final Collection globalVariables, - final Map> localVariables) { - for (final IProgramVar v : globalVariables) { - addVariable(new HcGlobalVar(v)); - } - for (final var instance : getInstances()) { - // thread ID - final var id = new HcThreadIdVar(instance, getScript()); - mIdVars.put(instance, id); - addVariable(id); - - // Location - final var loc = new HcLocationVar(instance, getIntSort()); - mLocationsVars.put(instance, loc); - addVariable(loc); - - // sleep set - final var sleep = new HcSleepVar(instance, getBoolSort()); - mSleepVars.put(instance, sleep); - addVariable(sleep); - - final List localVars = localVariables.get(instance.getTemplateName()); - for (final IProgramVar v : localVars) { - addVariable(new HcLocalVar(v, instance.getInstanceNumber())); - } - } - } - - private Sort getIntSort() { - return SmtSortUtils.getIntSort(getScript()); - } - - private Sort getBoolSort() { - return SmtSortUtils.getBoolSort(getScript()); - } - - private List getDefaultArgs() { - return mDefaultHeadVars.stream().map(HcVar::getTerm).collect(Collectors.toList()); - } - - private Term numeral(final long n) { - return getScript().numeral(BigInteger.valueOf(n)); - } - - private Script getScript() { - return mManagedScript.getScript(); - } - - private Term getLocIndexTerm(final IcfgLocation loc, final String proc) { - Integer index = mLocationIndices.get(proc, loc); - if (index == null) { - final Map otherIndices = mLocationIndices.get(proc); - index = otherIndices == null ? 0 : otherIndices.size(); - mLocationIndices.put(proc, loc, index); - } - return numeral(index); - } - - private Collection getInstances(final String template) { - final var result = new ArrayList(); - for (int i = 0; i < mNumberOfThreads.get(template); i++) { - result.add(new ThreadInstance(template, i)); - } - return result; - } - - private List getInstances() { - final var result = new ArrayList(); - for (final Entry entry : mNumberOfThreads.entrySet()) { - for (int i = 0; i < entry.getValue(); i++) { - result.add(new ThreadInstance(entry.getKey(), i)); - } - } - return result; - } - - // pc_0 = l_0 -> Inv(pc_0, ...) - public HornClause getInitialClause(final Collection initialLocations) { - final Map locationMap = new HashMap<>(); - for (final var instance : getInstances()) { - locationMap.put(instance, mBottomLocation); - } - for (final IcfgLocation loc : initialLocations) { - final String proc = loc.getProcedure(); - for (int i = 0; i < mNumberOfThreads.get(proc); i++) { - locationMap.put(new ThreadInstance(proc, i), getLocIndexTerm(loc, proc)); - } - } - final var locConstraint = getConstraintFromLocationMap(locationMap); - - final var idConstraints = new ArrayList(); - // final var instances = mNumberOfThreads.entrySet().stream() - // .flatMap(e -> IntStream.range(0, e.getValue()).mapToObj(i -> new Pair<>(e.getKey(), i))) - // .collect(Collectors.toList()); - // for (int i = 0; i < instances.size(); ++i) { - // final var first = instances.get(i); - // final var firstIndex = - // mPositions2Vars.inverse().get(new HcThreadIdVar(getScript(), first.getKey(), first.getValue())); - // final var firstId = mDefaultHeadVars.get(firstIndex); - // - // for (int j = i + 1; j < instances.size(); ++j) { - // final var second = instances.get(j); - // final var secondIndex = mPositions2Vars.inverse() - // .get(new HcThreadIdVar(getScript(), second.getKey(), second.getValue())); - // final var secondId = mDefaultHeadVars.get(secondIndex); - // - // idConstraints.add(SmtUtils.distinct(getScript(), firstId.getTerm(), secondId.getTerm())); - // } - // } - - // sleep set initially empty - final var sleepConstraints = mSleepVars.values().stream() - .map(sv -> SmtUtils.binaryEquality(getScript(), - mDefaultHeadVars.get(mPositions2Vars.inverse().get(sv)).getTerm(), numeral(0))) - .collect(Collectors.toList()); - - return constructHornClause(SmtUtils.and(getScript(), locConstraint, SmtUtils.and(getScript(), sleepConstraints), - SmtUtils.and(getScript(), idConstraints)), List.of(), Set.of()); - } - - /** - * Constructs a Horn clause with a given body and the default head. - * - * @param constraint - * The SMT constraint in the clause body - * @param bodyArguments - * Each list of terms is used as arguments for an invocation of {@link #mPredicate} in the body - * @param bodyVars - * Variables used in the bodyArguments. These will be universally quanmBodyVariablestified in the clause. - * @return A Horn clause with a body built from the given arguments, and a head consisting of an {@link #mPredicate} - * invocation with the default variables ({@link #mDefaultHeadVars}). - */ - private HornClause constructHornClause(final Term constraint, final List> bodyArguments, - final Set bodyVars) { - return new HornClause(mManagedScript, mHcSymbolTable, constraint, mPredicate, mDefaultHeadVars, - Collections.nCopies(bodyArguments.size(), mPredicate), bodyArguments, bodyVars); - } - - /** - * Constructs a constraint that specifies control locations. - * - * @param locationMap - * A map from thread template (i.e. procedure name) and instance number to a term representing the - * respective location. - * @return A conjunction of equalities between the default variables for control locations - * ({@link #mDefaultHeadVars}) and the locations specified by the map - */ - private Term getConstraintFromLocationMap(final Map locationMap) { - final List constraints = new ArrayList<>(); - for (final var pair : locationMap.entrySet()) { - final var constraint = getLocationConstraint(pair.getKey(), pair.getValue()); - constraints.add(constraint); - } - return SmtUtils.and(getScript(), constraints); - } - - /** - * Constructs a constraint that specifies a single control location. - * - * @return Equality between the default variable for the given thread's control location ({@link #mDefaultHeadVars}) - * and the given location term - */ - private Term getLocationConstraint(final ThreadInstance threadInstance, final Term location) { - final HcLocationVar locVar = new HcLocationVar(threadInstance, getIntSort()); - final int index = mPositions2Vars.inverse().get(locVar); - final Term term = mDefaultHeadVars.get(index).getTerm(); - return SmtUtils.binaryEquality(getScript(), term, location); - } - - // list of clauses of the form - // Inv(..., pc_i, ...) /\ pc_i = l_err -> false - public Collection getSafetyClauses(final Collection errorLocations) { - final List result = new ArrayList<>(); - final Set vars = new HashSet<>(mDefaultHeadVars); - final List bodyArgs = getDefaultArgs(); - for (final IcfgLocation loc : errorLocations) { - final String proc = loc.getProcedure(); - for (final var instance : getInstances(proc)) { - final Term constraint = getLocationConstraint(instance, getLocIndexTerm(loc, proc)); - result.add(new HornClause(mManagedScript, mHcSymbolTable, constraint, List.of(mPredicate), - List.of(bodyArgs), vars)); - } - } - return result; - } - - /** - * - * @param procs - * @return - */ - private List> getCartesianProductOfIndices(final Collection procs) { - List> result = List.of(Map.of()); - for (final String p : procs) { - final List> newResult = new ArrayList<>(); - for (int i = 0; i < mNumberOfThreads.get(p); i++) { - for (final Map map : result) { - final Map newMap = new HashMap<>(map); - newMap.put(p, i); - newResult.add(newMap); - } - } - result = newResult; - } - return result; - } - - /** - * - * @param locations - * @param indexMap - * @return - */ - private NestedMap2 getLocationMap(final Collection locations, - final Map indexMap) { - final NestedMap2 locMap = new NestedMap2<>(); - for (final IcfgLocation loc : locations) { - final String proc = loc.getProcedure(); - locMap.put(proc, indexMap.get(proc), getLocIndexTerm(loc, proc)); - } - return locMap; - } - - /** - * - * @param pre - * @param edge - * @param post - * @return - */ - public Collection getInductivityClauses(final List pre, final IIcfgTransition edge, - final List post) { - final String activeProcedure = edge.getPrecedingProcedure(); - - final List result = new ArrayList<>(); - final Set containedProcs = - Stream.concat(pre.stream(), post.stream()).map(IcfgLocation::getProcedure).collect(Collectors.toSet()); - for (final Map indexMap : getCartesianProductOfIndices(containedProcs)) { - final NestedMap2 locMapIn = getLocationMap(pre, indexMap); - final NestedMap2 locMapOut = getLocationMap(post, indexMap); - - final TransFormula transformula = edge.getTransformula(); - final Map substitution = new HashMap<>(); - final List constraints = new ArrayList<>(); - final List bodyArgs = getDefaultArgs(); - final Set bodyVars = new HashSet<>(); - - for (final var entry : mPositions2Vars.entrySet()) { - final int index = entry.getKey(); - final IHcReplacementVar rv = entry.getValue(); - IProgramVar pv = null; - if (rv instanceof HcLocalVar) { - final HcLocalVar lv = (HcLocalVar) rv; - if (!Objects.equals(indexMap.get(lv.getThreadTemplateName()), lv.getInstanceIndex())) { - continue; - } - pv = lv.getVariable(); - } else if (rv instanceof HcGlobalVar) { - final HcGlobalVar gv = (HcGlobalVar) rv; - pv = gv.getVariable(); - } else if (rv instanceof HcLocationVar) { - final HcLocationVar lv = (HcLocationVar) rv; - final String procedure = lv.getThreadTemplateName(); - final int instanceIndex = lv.getInstanceIndex(); - Term locIn = locMapIn.get(procedure, instanceIndex); - Term locOut = locMapOut.get(procedure, instanceIndex); - if (locIn == null && locOut == null) { - continue; - } - if (locIn == null) { - locIn = mBottomLocation; - } - if (locOut == null) { - locOut = mBottomLocation; - } - constraints - .add(SmtUtils.binaryEquality(getScript(), mDefaultHeadVars.get(index).getTerm(), locOut)); - if (!locIn.equals(locOut)) { - bodyArgs.set(index, locIn); - } - - // rv does not appear in transition formula, so skip the rest of the loop - continue; - } else if (rv instanceof HcSleepVar) { - final var sv = (HcSleepVar) rv; - final var activeInstanceIndex = indexMap.get(sv.getThreadTemplateName()); - if (Objects.equals(sv.getInstanceIndex(), activeInstanceIndex)) { - // this is the sleep variable for the active thread - final var bv = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); - bodyVars.add(bv); - bodyArgs.set(index, bv.getTerm()); - - // ensure that the active thread is not sleeping - constraints.add(SmtUtils.binaryEquality(getScript(), bv.getTerm(), numeral(0))); - } else { - final var oldSleep = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); - bodyVars.add(oldSleep); - bodyArgs.set(index, oldSleep.getTerm()); - final var newSleep = mDefaultHeadVars.get(index).getTerm(); - - final var hcLoc = new HcLocationVar(sv.getThreadInstance(), getIntSort()); - final int locIndex = mPositions2Vars.inverse().get(hcLoc); - final var locVar = mDefaultHeadVars.get(locIndex); - - final var currentId = mDefaultHeadVars.get(mPositions2Vars.inverse().get(new HcThreadIdVar( - new ThreadInstance(activeProcedure, activeInstanceIndex), getScript()))); - final var otherId = mDefaultHeadVars.get( - mPositions2Vars.inverse().get(new HcThreadIdVar(sv.getThreadInstance(), getScript()))); - - // update sleep variable depending on commutativity and thread ID ordering - final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar.getTerm(), edge); - constraints - .add(SmtUtils.binaryBooleanEquality(getScript(), - SmtUtils.binaryEquality(getScript(), newSleep, numeral(0)), - SmtUtils.or(getScript(), SmtUtils.and(getScript(), - SmtUtils.greater(getScript(), otherId.getTerm(), currentId.getTerm()), - SmtUtils.binaryEquality(getScript(), oldSleep.getTerm(), numeral(0))), - nonCommConstr))); - } - // else if ((activeInstanceIndex != null && sv.getInstanceIndex() < activeInstanceIndex) - // || (activeInstanceIndex == null - // && sv.getThreadTemplateName().compareTo(activeProcedure) < 0)) { - // final var newSleep = mDefaultHeadVars.get(index).getTerm(); - // - // final var locVar = mLocationsVars.get(sv.getThreadTemplateName(), sv.getInstanceIndex()); - // final var locVarIndex = mPositions2Vars.inverse().get(locVar); - // final var locVar2 = - // mHcSymbolTable.getOrConstructBodyVar(mPredicate, locVarIndex, locVar.getSort(), locVar); - // bodyVars.add(locVar2); - // bodyArgs.set(locVarIndex, locVar2.getTerm()); - // - // // set newSleep to true/false depending on commutativity - // final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar2.getTerm(), edge); - // constraints.add(SmtUtils.binaryBooleanEquality(getScript(), - // SmtUtils.binaryEquality(getScript(), newSleep, numeral(0)), nonCommConstr)); - // } else { - // assert (activeInstanceIndex != null && sv.getInstanceIndex() > activeInstanceIndex) - // || (activeInstanceIndex == null - // && sv.getThreadTemplateName().compareTo(activeProcedure) > 0); - // - // final var oldSleep = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); - // bodyVars.add(oldSleep); - // bodyArgs.set(index, oldSleep.getTerm()); - // final var newSleep = mDefaultHeadVars.get(index).getTerm(); - // - // final var locVar = mLocationsVars.get(sv.getThreadTemplateName(), sv.getInstanceIndex()); - // final var locVarIndex = mPositions2Vars.inverse().get(locVar); - // final var locVar2 = - // mHcSymbolTable.getOrConstructBodyVar(mPredicate, locVarIndex, locVar.getSort(), locVar); - // bodyVars.add(locVar2); - // bodyArgs.set(locVarIndex, locVar2.getTerm()); - // - // // set newSleep to old/false depending on commutativity - // final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar2.getTerm(), edge); - // constraints.add(SmtUtils.ite(getScript(), nonCommConstr, - // SmtUtils.binaryEquality(getScript(), newSleep, numeral(0)), - // SmtUtils.binaryEquality(getScript(), newSleep, oldSleep.getTerm()))); - // } - continue; - } else if (rv instanceof HcThreadIdVar) { - // nothing to do here: the default argument in the body is already the headVar - // this is correct, because the thread ID never changes - continue; - } else { - throw new UnsupportedOperationException("Unknown kind of variable: " + rv); - } - - assert pv != null; - final TermVariable inVar = transformula.getInVars().get(pv); - final TermVariable outVar = transformula.getOutVars().get(pv); - substitution.put(outVar, mDefaultHeadVars.get(index).getTerm()); - if (!Objects.equals(inVar, outVar)) { - final HcBodyVar bv = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, pv); - final Term term = bv.getTerm(); - bodyArgs.set(index, term); - substitution.put(inVar, term); - bodyVars.add(bv); - } - } - - // add ID constraints - final var instances = getInstances(); - for (int i = 0; i < instances.size(); ++i) { - final var first = instances.get(i); - final var firstIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(first, getScript())); - final var firstId = mDefaultHeadVars.get(firstIndex); - - for (int j = i + 1; j < instances.size(); ++j) { - final var second = instances.get(j); - final var secondIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(second, getScript())); - final var secondId = mDefaultHeadVars.get(secondIndex); - - constraints.add(SmtUtils.less(getScript(), firstId.getTerm(), secondId.getTerm())); - } - } - - // Replace all other variables with aux-vars - final Term formula = transformula.getFormula(); - for (final TermVariable v : formula.getFreeVars()) { - if (substitution.containsKey(v)) { - continue; - } - // TODO: Using the number of bodyVars as index is a hack! - final HcBodyVar auxVar = - mHcSymbolTable.getOrConstructBodyVar(mPredicate, bodyVars.size(), v.getSort(), v); - substitution.put(v, auxVar.getTerm()); - bodyVars.add(auxVar); - } - constraints.add(Substitution.apply(mManagedScript, substitution, formula)); - result.add(constructHornClause(SmtUtils.and(getScript(), constraints), List.of(bodyArgs), bodyVars)); - } - return result; - } - - private Term getNonCommutativityConstraint(final HcSleepVar sv, final Term locVar, - final IIcfgTransition currentEdge) { - - final var nonCommLocations = new HashSet(); - for (final var loc : mThreadLocations.get(sv.getThreadTemplateName())) { - if (loc.getOutgoingEdges().stream() - .anyMatch(edge -> mIndependence.isIndependent(null, edge, currentEdge) != Dependence.INDEPENDENT)) { - nonCommLocations.add(getLocIndexTerm(loc, sv.getThreadTemplateName())); - } - } - - nonCommLocations.stream().map(loc -> SmtUtils.binaryEquality(getScript(), locVar, loc)) - .collect(Collectors.toList()); - return SmtUtils.and(getScript(), nonCommLocations.stream() - .map(loc -> SmtUtils.binaryEquality(getScript(), locVar, loc)).collect(Collectors.toList())); - } - - public Collection getInductivityClauses(final IIcfgTransition edge) { - return getInductivityClauses(List.of(edge.getSource()), edge, List.of(edge.getTarget())); - } - - public HornClause getIdUniquenessClause() { - final var bodyArgs = getDefaultArgs(); - final var constraints = new ArrayList(); - - final var instances = getInstances(); - for (int i = 0; i < instances.size(); ++i) { - final var first = instances.get(i); - final var firstIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(first, getScript())); - final var firstId = bodyArgs.get(firstIndex); - - for (int j = i + 1; j < instances.size(); ++j) { - final var second = instances.get(j); - final var secondIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(second, getScript())); - final var secondId = bodyArgs.get(secondIndex); - - constraints.add(SmtUtils.binaryEquality(getScript(), firstId, secondId)); - } - } - - return new HornClause(mManagedScript, mHcSymbolTable, SmtUtils.or(getScript(), constraints), - List.of(mPredicate), List.of(bodyArgs), Set.copyOf(mDefaultHeadVars)); - } - - public HornClause getNonInterferenceClause(final IIcfgTransition edge) { - final String procedure = edge.getPrecedingProcedure(); - final var interferingThread = new ThreadInstance(procedure, INTERFERING_INSTANCE_ID); - - final int n = mNumberOfThreads.get(procedure); - final List> bodyArguments = new ArrayList<>(); - for (int i = 0; i <= n; i++) { - bodyArguments.add(getDefaultArgs()); - } - final TransFormula transformula = edge.getTransformula(); - final Map substitution = new HashMap<>(); - final Set bodyVars = new HashSet<>(); - final var constraints = new ArrayList(); - for (final var entry : mPositions2Vars.entrySet()) { - final int index = entry.getKey(); - final IHcReplacementVar rv = entry.getValue(); - if (rv instanceof HcLocalVar) { - final HcLocalVar lv = (HcLocalVar) rv; - if (lv.getThreadTemplateName().equals(procedure)) { - final IProgramVar pv = lv.getVariable(); - final TermVariable inVar = transformula.getInVars().get(pv); - final TermVariable outVar = transformula.getOutVars().get(pv); - if (inVar != null) { - final HcBodyVar bodyVar = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, pv); - bodyVars.add(bodyVar); - final Term bodyVarTerm = bodyVar.getTerm(); - substitution.put(inVar, bodyVarTerm); - for (int i = 0; i < n; i++) { - final int newIndex = mPositions2Vars.inverse().get(new HcLocalVar(pv, i)); - bodyArguments.get(i + 1).set(newIndex, bodyVarTerm); - } - } - if (outVar != null && !outVar.equals(inVar)) { - // TODO: Should this be a HcBodyAuxVar instead? => ChcToBoogie crashes then... - final HcBodyVar auxVar = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, pv); - substitution.put(outVar, auxVar.getTerm()); - bodyVars.add(auxVar); - } - } - } else if (rv instanceof HcGlobalVar) { - final IProgramVar pv = ((HcGlobalVar) rv).getVariable(); - final TermVariable inVar = transformula.getInVars().get(pv); - final TermVariable outVar = transformula.getOutVars().get(pv); - substitution.put(outVar, mDefaultHeadVars.get(index).getTerm()); - if (!Objects.equals(inVar, outVar)) { - final HcBodyVar bv = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, pv); - final Term term = bv.getTerm(); - for (int i = 0; i <= n; i++) { - bodyArguments.get(i).set(index, term); - } - substitution.put(inVar, term); - bodyVars.add(bv); - } - } else if (rv instanceof HcLocationVar) { - final HcLocationVar lv = (HcLocationVar) rv; - if (lv.getThreadTemplateName().equals(procedure)) { - final Term loc = getLocIndexTerm(edge.getSource(), procedure); - for (int i = 0; i < n; i++) { - final int newIndex = mPositions2Vars.inverse() - .get(new HcLocationVar(new ThreadInstance(procedure, i), getIntSort())); - bodyArguments.get(i + 1).set(newIndex, loc); - } - } - } else if (rv instanceof HcSleepVar) { - final var sv = (HcSleepVar) rv; - final var oldSleep = mHcSymbolTable.getOrConstructBodyVar(mPredicate, index, sv.getSort(), sv); - bodyVars.add(oldSleep); - - // insert the variable in each body clause (in one, it may be replaced below by the interfering thread) - for (int i = 0; i <= n; ++i) { - bodyArguments.get(i).set(index, oldSleep.getTerm()); - } - - final var newSleep = mDefaultHeadVars.get(index); - - final var hcLoc = new HcLocationVar(sv.getThreadInstance(), getIntSort()); - final int locIndex = mPositions2Vars.inverse().get(hcLoc); - final var locVar = mDefaultHeadVars.get(locIndex); - - final var currentId = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), - new HcThreadIdVar(interferingThread, getScript())); - bodyVars.add(currentId); - final var otherId = mDefaultHeadVars - .get(mPositions2Vars.inverse().get(new HcThreadIdVar(sv.getThreadInstance(), getScript()))); - - // update sleep variable depending on commutativity and thread ID ordering - final Term nonCommConstr = getNonCommutativityConstraint(sv, locVar.getTerm(), edge); - constraints.add(SmtUtils.binaryBooleanEquality(getScript(), - SmtUtils.binaryEquality(getScript(), newSleep.getTerm(), numeral(0)), - SmtUtils.or(getScript(), - SmtUtils.and(getScript(), - SmtUtils.greater(getScript(), otherId.getTerm(), currentId.getTerm()), - SmtUtils.binaryEquality(getScript(), oldSleep.getTerm(), numeral(0))), - nonCommConstr))); - - // special case: add the constraint that the interfering thread does not sleep - if (sv.getThreadTemplateName().equals(procedure)) { - final var bodyVar = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, sv.getSort(), sv); - bodyVars.add(bodyVar); - - // for each non-interference premise, insert the variable in the index for the interfering thread - for (int i = 0; i < n; ++i) { - final int newIndex = mPositions2Vars.inverse() - .get(new HcSleepVar(new ThreadInstance(sv.getThreadTemplateName(), i), getBoolSort())); - bodyArguments.get(i + 1).set(newIndex, bodyVar.getTerm()); - } - - // add constraint ensuring that the interfering thread is not sleeping - constraints.add(SmtUtils.binaryEquality(getScript(), bodyVar.getTerm(), numeral(0))); - } - continue; - } else if (rv instanceof HcThreadIdVar) { - final var iv = (HcThreadIdVar) rv; - if (iv.getThreadTemplateName().equals(procedure)) { - final var id = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), - new HcThreadIdVar(interferingThread, getScript())); - bodyVars.add(id); - for (int i = 0; i < n; ++i) { - final var newIndex = mPositions2Vars.inverse() - .get(new HcSleepVar(new ThreadInstance(iv.getThreadTemplateName(), i), getBoolSort())); - bodyArguments.get(i + 1).set(newIndex, id.getTerm()); - } - } - } else { - throw new UnsupportedOperationException("Unknown kind of variable: " + rv); - } - } - - // add ID constraints - final var instances = getInstances(); - final var interferingId = mHcSymbolTable.getOrConstructBodyVar(mPredicate, -1, getIntSort(), - new HcThreadIdVar(interferingThread, getScript())); - assert bodyVars.contains(interferingId); - for (int i = 0; i < instances.size(); ++i) { - final var first = instances.get(i); - final var firstIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(first, getScript())); - final var firstId = mDefaultHeadVars.get(firstIndex); - - for (int j = i + 1; j < instances.size(); ++j) { - final var second = instances.get(j); - final var secondIndex = mPositions2Vars.inverse().get(new HcThreadIdVar(second, getScript())); - final var secondId = mDefaultHeadVars.get(secondIndex); - - constraints.add(SmtUtils.less(getScript(), firstId.getTerm(), secondId.getTerm())); - } - - constraints.add(SmtUtils.distinct(getScript(), interferingId.getTerm(), firstId.getTerm())); - } - - // Replace all other variables with aux-vars - final Term formula = transformula.getFormula(); - for (final TermVariable v : formula.getFreeVars()) { - if (substitution.containsKey(v)) { - continue; - } - // TODO: Using the number of bodyVars as index is a hack! - final HcBodyVar auxVar = mHcSymbolTable.getOrConstructBodyVar(mPredicate, bodyVars.size(), v.getSort(), v); - substitution.put(v, auxVar.getTerm()); - bodyVars.add(auxVar); - } - constraints.add(Substitution.apply(mManagedScript, substitution, transformula.getFormula())); - return constructHornClause(SmtUtils.and(getScript(), constraints), bodyArguments, bodyVars); - } - - public interface IHcReplacementVar { - Sort getSort(); - } -} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java index f399c748159..4d13dbdf187 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java @@ -29,7 +29,6 @@ import java.util.Objects; import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; public class PredicateInfo { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java index 57f69b21bc3..70df1092830 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java @@ -47,7 +47,7 @@ public int getInstanceNumber() { @Override public String toString() { - return mTemplateName + "_" + mInstanceNumber; + return IcfgToChcConcurrentUtils.getReadableString(mTemplateName) + "_" + (mInstanceNumber + 1); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index f58d4952fff..df5ecaad805 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -56,7 +56,6 @@ import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgToChcConcurrent.IHcReplacementVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; @@ -208,7 +207,7 @@ protected List createThreadSpecificVars(final ThreadInstan final List localVars = mCfgSymbolTable.getLocals(instance.getTemplateName()).stream() .filter(mVariableFilter).collect(Collectors.toList()); for (final IProgramVar pv : localVars) { - final var local = new HcLocalVar(pv, instance.getInstanceNumber()); + final var local = new HcLocalVar(pv, instance); mLocalVars.put(instance, pv, local); result.add(local); } @@ -507,6 +506,6 @@ protected ThreadInstance getInterferingThread(final IIcfgTransition transitio private Stream getInterferingLocals(final ThreadInstance interferingThread) { return mCfgSymbolTable.getLocals(interferingThread.getTemplateName()).stream().filter(mVariableFilter) - .map(pv -> new HcLocalVar(pv, INTERFERING_INSTANCE_ID)); + .map(pv -> new HcLocalVar(pv, interferingThread)); } } From f510f23faf5ca696ee45b5e7478ed622799a9033 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 18 Apr 2023 23:28:47 +0200 Subject: [PATCH 019/114] add missing license header --- .../concurrent/IcfgToChcConcurrentUtils.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrentUtils.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrentUtils.java index c4e95a4f26f..fef1c0f2a6d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrentUtils.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IcfgToChcConcurrentUtils.java @@ -1,3 +1,29 @@ +/* + * Copyright (C) 2023 Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; /** From 247528eb15534a6bd34ea634fbddb6b05e3c75a6 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 19 Apr 2023 11:31:39 +0200 Subject: [PATCH 020/114] implement support for pre-/postconditions For parametric programs, we can now generate CHC systems that encode correctness wrt a pre- / postcondition pair. The precondition should be annotated as a "free requires" on the thread template, Similarly, the postcondition should be annotated as a "free ensures". --- .../plugins/icfgtochc/IcfgToChcObserver.java | 6 +- .../concurrent/HcThreadCounterVar.java | 96 +++++++++ ...eepSetThreadModularHornClauseProvider.java | 12 +- .../ThreadModularHornClauseProvider.java | 196 ++++++++++++++++-- 4 files changed, 280 insertions(+), 30 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 7b1e785da27..fb54afea2a6 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -177,10 +177,10 @@ private Collection getHornClauses(IIcfg icfg, final Ma if (mPrefs.useSleepSets()) { final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, true); - return new SleepSetThreadModularHornClauseProvider(mgdScript, icfg, hcSymbolTable, independence, mPrefs) - .getClauses(); + return new SleepSetThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, + independence, mPrefs).getClauses(); } - return new ThreadModularHornClauseProvider(mgdScript, icfg, hcSymbolTable, mPrefs).getClauses(); + return new ThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, mPrefs).getClauses(); } return new ChcProviderForCalls(mgdScript, hcSymbolTable).getHornClauses(icfg); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java new file mode 100644 index 00000000000..b668c6e75a0 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Objects; + +import de.uni_freiburg.informatik.ultimate.logic.Sort; + +/** + * A variable that counts the number of started resp. of terminated threads. These variables are used for a + * thread-modular encoding of postconditions. + * + * The thread-modular encoding of postconditions works as follows: + *
    + *
  1. The number of started threads is incremented each time one of the initially running threads takes its first + * step.
  2. + *
  3. The number of terminated threads is incremented each time one of the initially running threads terminates.
  4. + *
  5. If an initially running thread has terminated, and the numbers of started and terminated threads are equal, then + * the postcondition must hold.
  6. + *
+ * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + */ +public class HcThreadCounterVar implements IHcReplacementVar { + + // An instance either represents the number of started threads (if this boolean is true) or of terminated threads + private final boolean mIsStarted; + private final Sort mSort; + + public HcThreadCounterVar(final boolean isStarted, final Sort sort) { + mIsStarted = isStarted; + mSort = sort; + } + + @Override + public Sort getSort() { + return mSort; + } + + public boolean isStarted() { + return mIsStarted; + } + + public boolean isTerminated() { + return !mIsStarted; + } + + @Override + public String toString() { + return mIsStarted ? "~started" : "~terminated"; + } + + @Override + public int hashCode() { + return Objects.hash(mIsStarted); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final HcThreadCounterVar other = (HcThreadCounterVar) obj; + return mIsStarted == other.mIsStarted; + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 262a26b98ab..9bd5f2cdbfb 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -35,6 +35,7 @@ import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; +import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfgTransition; @@ -52,10 +53,10 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornCl private final Map mIdVars; private final Map mSleepVars; - public SleepSetThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcfg icfg, - final HcSymbolTable symbolTable, final IIndependenceRelation> independence, - final IcfgToChcPreferences prefs) { - super(mgdScript, icfg, symbolTable, prefs); + public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider services, + final ManagedScript mgdScript, final IIcfg icfg, final HcSymbolTable symbolTable, + final IIndependenceRelation> independence, final IcfgToChcPreferences prefs) { + super(services, mgdScript, icfg, symbolTable, prefs); mIndependence = independence; mThreadLocations = icfg.getProgramPoints().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); @@ -217,10 +218,11 @@ private void updateSleepNonInterference(final HornClauseBuilder clause, final II protected Term getCommutativityConstraint(final ThreadInstance instance, final Term locVar, final IIcfgTransition currentEdge) { - final var commLocations = new HashSet(); for (final var loc : mThreadLocations.get(instance.getTemplateName())) { if (loc.getOutgoingEdges().stream() + // ignore spec edges: the original edges are replaced, and the replacing transitions commute + .filter(e -> !isPreConditionSpecEdge(e) && !isPostConditionSpecEdge(e)) .allMatch(e -> mIndependence.isIndependent(null, e, currentEdge) == Dependence.INDEPENDENT)) { commLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index df5ecaad805..e83dcfd7bdd 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -40,6 +40,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; @@ -49,6 +50,9 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaBuilder; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaUtils; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.UnmodifiableTransFormula; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; @@ -57,7 +61,9 @@ import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences.SpecMode; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; +import de.uni_freiburg.informatik.ultimate.util.datastructures.DataStructureUtils; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Triple; @@ -65,6 +71,10 @@ /** * Generates Horn clauses for a thread-modular proof. * + * This class supports two modes of specification: Either we prove absence of assertion violations in all threads, or we + * prove a precondition-postcondition pair (the postcondition holds once all initially running threads have terminated). + * The specification mode is set via the preferences (passed to the constructor). + * * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) * @@ -73,6 +83,7 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide private static final String FUNCTION_NAME = "Inv"; private static final int INTERFERING_INSTANCE_ID = -1; + protected final IUltimateServiceProvider mServices; protected final IIcfg mIcfg; protected final IcfgToChcPreferences mPrefs; private final IIcfgSymbolTable mCfgSymbolTable; @@ -92,19 +103,22 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide protected final PredicateInfo mInvariantPredicate; protected final Set mGlobalVars = new HashSet<>(); + protected final HcThreadCounterVar mStartedVar; + protected final HcThreadCounterVar mTerminatedVar; protected final Map> mThreadSpecificVars = new HashMap<>(); protected final Map mLocationVars = new HashMap<>(); protected final NestedMap2 mLocalVars = new NestedMap2<>(); - public ThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcfg icfg, - final HcSymbolTable symbolTable, final IcfgToChcPreferences prefs) { - this(mgdScript, icfg, symbolTable, x -> true, prefs); + public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, final ManagedScript mgdScript, + final IIcfg icfg, final HcSymbolTable symbolTable, final IcfgToChcPreferences prefs) { + this(services, mgdScript, icfg, symbolTable, x -> true, prefs); } - public ThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcfg icfg, - final HcSymbolTable symbolTable, final Predicate variableFilter, + public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, final ManagedScript mgdScript, + final IIcfg icfg, final HcSymbolTable symbolTable, final Predicate variableFilter, final IcfgToChcPreferences prefs) { super(mgdScript, symbolTable); + mServices = services; mIcfg = icfg; mPrefs = prefs; mCfgSymbolTable = mIcfg.getCfgSmtToolkit().getSymbolTable(); @@ -117,6 +131,13 @@ public ThreadModularHornClauseProvider(final ManagedScript mgdScript, final IIcf mUnboundedTemplates = threadInfo.getSecond(); mBottomLocation = numeral(-1); + if (mPrefs.specMode() == SpecMode.PRE_POST) { + mStartedVar = new HcThreadCounterVar(true, getIntSort()); + mTerminatedVar = new HcThreadCounterVar(false, getIntSort()); + } else { + mStartedVar = null; + mTerminatedVar = null; + } mInvariantPredicate = createInvariantPredicate(); } @@ -163,6 +184,13 @@ private PredicateInfo createInvariantPredicate() { */ protected List getInvariantParameters() { final var result = new ArrayList(); + + // add variables for thread-modular encoding of postconditions + if (mPrefs.specMode() == SpecMode.PRE_POST) { + result.add(mStartedVar); + result.add(mTerminatedVar); + } + result.addAll(createGlobalVars()); for (final var instance : mInstances) { final var threadSpecific = createThreadSpecificVars(instance); @@ -229,28 +257,98 @@ protected List buildAllClauses() { for (final String proc : mTemplates) { final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); while (edges.hasNext()) { - final IcfgEdge edge = edges.next(); + final IcfgEdge original = edges.next(); + + // replace spec edges by dummy transitions that do nothing (actual constraints are added later) + IcfgEdge edge; + if (isPreConditionSpecEdge(original) || isPostConditionSpecEdge(original)) { + edge = createDummyEdge(original); + } else { + edge = original; + } + + // add inductivity clauses for (final var prePost : getCartesianPrePostProduct(edge)) { final var clause = buildInductivityClause(edge, prePost.getFirst(), prePost.getSecond(), prePost.getThird()); + transformSpecEdgeClause(original, clause); result.add(clause); } + // add non-interference clause if (mUnboundedTemplates.contains(proc)) { - result.add(buildNonInterferenceClause(edge)); + final var clause = buildNonInterferenceClause(edge); + transformSpecEdgeClause(original, clause); + result.add(clause); } } } - final var errorLocs = getErrorLocations(); - for (final var pair : errorLocs) { - final var safetyClause = buildSafetyClause(pair.getFirst(), pair.getSecond()); - result.add(safetyClause); + // add safety clauses + switch (mPrefs.specMode()) { + case ASSERT_VIOLATIONS: + for (final var pair : getErrorLocations()) { + final var safetyClause = buildErrorSafetyClause(pair.getFirst(), pair.getSecond()); + result.add(safetyClause); + } + break; + case PRE_POST: + for (final var thread : getInitialLocations().keySet()) { + final var safetyClause = buildPostconditionSafetyClause(thread); + result.add(safetyClause); + } + break; } return result; } + protected IcfgEdge createDummyEdge(final IcfgEdge original) { + final var tf = TransFormulaBuilder.getTrivialTransFormula(mManagedScript); + return new IcfgEdge(original.getSource(), original.getTarget(), original.getPayload()) { + @Override + public UnmodifiableTransFormula getTransformula() { + return tf; + } + }; + } + + // add actual constraints for spec edges, do nothing if not a spec edge + protected void transformSpecEdgeClause(final IcfgEdge edge, final HornClauseBuilder clause) { + if (isPreConditionSpecEdge(edge)) { + incrementThreadCounter(clause, mStartedVar); + } else if (isPostConditionSpecEdge(edge)) { + incrementThreadCounter(clause, mTerminatedVar); + } + } + + protected void incrementThreadCounter(final HornClauseBuilder clause, final HcThreadCounterVar counter) { + // add constraint counter' = counter + 1 + clause.differentBodyHeadVar(counter); + clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getHeadVar(counter).getTerm(), + SmtUtils.sum(mScript, getIntSort(), clause.getBodyVar(counter).getTerm(), numeral(1L)))); + } + + protected boolean isPreConditionSpecEdge(final IcfgEdge edge) { + if (mPrefs.specMode() != SpecMode.PRE_POST) { + return false; + } + + final var template = edge.getPrecedingProcedure(); + final var entryLoc = mIcfg.getProcedureEntryNodes().get(template); + return edge.getSource().equals(entryLoc); + } + + protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { + if (mPrefs.specMode() != SpecMode.PRE_POST) { + return false; + } + + final var template = edge.getPrecedingProcedure(); + final var exitLoc = mIcfg.getProcedureExitNodes().get(template); + return edge.getTarget().equals(exitLoc); + } + private List, Map, ThreadInstance>> getCartesianPrePostProduct(final IcfgEdge edge) { if (edge instanceof IIcfgForkTransitionThreadCurrent) { @@ -291,19 +389,37 @@ private List> getErrorLocations() { // ----------------------------------------------------------------------------------------------------------------- /** - * Builds the initial clause that encodes the precondition. By default, this method only fixes the initial location - * of the threads. + * Builds the initial clause that encodes the precondition. */ protected HornClauseBuilder buildInitialClause() { final var clause = createBuilder(mInvariantPredicate, "initial clause"); + final var initialLocs = getInitialLocations(); // add location constraints - final var initialLocs = getInitialLocations(); for (final var instance : mInstances) { - // If instance does not have an initial location, a constraint for mBottomLocation is added. + // If an instance does not have an initial location, a constraint for mBottomLocation is added. addOutLocationConstraint(clause, instance, initialLocs.get(instance)); } + if (mPrefs.specMode() == SpecMode.PRE_POST) { + // add constraints that thread counters (for thread-modular encoding of postconditions) are initially 0 + clause.addConstraint( + SmtUtils.binaryEquality(mScript, clause.getHeadVar(mStartedVar).getTerm(), numeral(0))); + clause.addConstraint( + SmtUtils.binaryEquality(mScript, clause.getHeadVar(mTerminatedVar).getTerm(), numeral(0))); + + // add precondition constraint + final var locals = mLocalVars.values().collect(Collectors.toList()); + for (final var entry : initialLocs.entrySet()) { + // The (only) outgoing edge of the initial location should be an assumption of the precondition + final var precond = DataStructureUtils + .getOneAndOnly(entry.getValue().getOutgoingEdges(), "outgoing edge of initial location") + .getTransformula(); + assert precond.getAssignedVars().isEmpty() : "Precondition must not modify variables"; + addTransitionConstraint(clause, precond, entry.getKey(), locals); + } + } + return clause; } @@ -315,7 +431,7 @@ protected HornClauseBuilder buildInitialClause() { * @param errorLoc * The error location that shall be proven unreachable */ - protected HornClauseBuilder buildSafetyClause(final ThreadInstance thread, final IcfgLocation errorLoc) { + protected HornClauseBuilder buildErrorSafetyClause(final ThreadInstance thread, final IcfgLocation errorLoc) { // create a clause with head "false" final var clause = createBuilder("safety clause for location " + errorLoc + " in thread instance " + thread); @@ -328,6 +444,40 @@ protected HornClauseBuilder buildSafetyClause(final ThreadInstance thread, final return clause; } + /** + * Builds a safety clause specifying that if a given thread exits, and the numbers of started and exited threads are + * equal, the postcondition holds. + * + * @param thread + * The thread for which the clause should be generated. This must be a thread that runs initially. + */ + protected HornClauseBuilder buildPostconditionSafetyClause(final ThreadInstance thread) { + // create a clause with head "false" + final var clause = createBuilder("safety clause for postcondition in thread instance " + thread); + + // add body clause + clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); + + // location constraints + final var exitLoc = mIcfg.getProcedureExitNodes().get(thread.getTemplateName()); + addInLocationConstraint(clause, thread, exitLoc); + + // add thread counter constraint: started == terminated + clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getBodyVar(mStartedVar).getTerm(), + clause.getBodyVar(mTerminatedVar).getTerm())); + + // add negated postcondition + final var postcondition = DataStructureUtils + .getOneAndOnly(exitLoc.getIncomingEdges(), "transition to exit location").getTransformula(); + assert postcondition.getAssignedVars().isEmpty() : "postcondition cannot modify variables"; + final var negated = TransFormulaUtils.negate( + TransFormulaUtils.computeGuard(postcondition, mManagedScript, mServices), mManagedScript, mServices); + final var locals = mLocalVars.values().collect(Collectors.toList()); + addTransitionConstraint(clause, negated, null, locals); + + return clause; + } + /** * Builds an inductivity clause that encodes the effect of a transition on the thread that executes it. * @@ -455,18 +605,22 @@ protected Term getLocIndexTerm(final IcfgLocation loc, final String proc) { protected void addTransitionConstraint(final HornClauseBuilder clause, final IIcfgTransition transition, final ThreadInstance updatedThread, final Collection localVariables) { - final var tf = transition.getTransformula(); + addTransitionConstraint(clause, transition.getTransformula(), updatedThread, localVariables); + } + + protected void addTransitionConstraint(final HornClauseBuilder clause, final UnmodifiableTransFormula tf, + final ThreadInstance updatedThread, final Collection localVariables) { final var substitution = new HashMap(); // deal with global variables for (final var global : mGlobalVars) { - prepareSubstitution(clause, transition, substitution, global, global.getVariable(), true); + prepareSubstitution(clause, tf, substitution, global, global.getVariable(), true); } // deal with local variables for (final HcLocalVar local : localVariables) { final var updatable = local.getThreadInstance().equals(updatedThread); - prepareSubstitution(clause, transition, substitution, local, local.getVariable(), updatable); + prepareSubstitution(clause, tf, substitution, local, local.getVariable(), updatable); } // replace all other variables with auxiliary variables @@ -480,11 +634,9 @@ protected void addTransitionConstraint(final HornClauseBuilder clause, final IIc clause.addConstraint(Substitution.apply(mManagedScript, substitution, formula)); } - private static void prepareSubstitution(final HornClauseBuilder clause, final IIcfgTransition transition, + private static void prepareSubstitution(final HornClauseBuilder clause, final UnmodifiableTransFormula tf, final Map substitution, final IHcReplacementVar rv, final IProgramVar pv, final boolean canBeUpdated) { - final var tf = transition.getTransformula(); - final TermVariable inVar = tf.getInVars().get(pv); if (inVar != null) { substitution.put(inVar, clause.getBodyVar(rv).getTerm()); From f10639ea0c64d6b543caf823fdd4c6ba069c4d6b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 20 Apr 2023 09:46:58 +0200 Subject: [PATCH 021/114] separate ability to specify preconditions from spec mode --- .../icfgtochc/concurrent/HornClauseBuilder.java | 3 ++- .../ThreadModularHornClauseProvider.java | 16 +++++++++------- .../IcfgToChcPreferenceInitializer.java | 9 ++++++++- .../preferences/IcfgToChcPreferences.java | 6 +++++- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index b6d8786d824..26adda8d550 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -87,7 +87,8 @@ public HcBodyVar getBodyVar(final IHcReplacementVar variable) { public HcHeadVar getHeadVar(final IHcReplacementVar variable) { assert mHeadPredicate != null : "Clause does not have head predicate"; - assert mHeadPredicate.hasParameter(variable); + assert mHeadPredicate.hasParameter(variable) : "Predicate " + mHeadPredicate.getPredicate() + + " does not have parameter " + variable; return mSymbolTable.getOrConstructHeadVar(variable, variable.getSort()); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index e83dcfd7bdd..b1b4a05ebb6 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -131,7 +131,7 @@ public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, mUnboundedTemplates = threadInfo.getSecond(); mBottomLocation = numeral(-1); - if (mPrefs.specMode() == SpecMode.PRE_POST) { + if (mPrefs.specMode() == SpecMode.POSTCONDITION) { mStartedVar = new HcThreadCounterVar(true, getIntSort()); mTerminatedVar = new HcThreadCounterVar(false, getIntSort()); } else { @@ -186,7 +186,7 @@ protected List getInvariantParameters() { final var result = new ArrayList(); // add variables for thread-modular encoding of postconditions - if (mPrefs.specMode() == SpecMode.PRE_POST) { + if (mPrefs.specMode() == SpecMode.POSTCONDITION) { result.add(mStartedVar); result.add(mTerminatedVar); } @@ -292,7 +292,7 @@ protected List buildAllClauses() { result.add(safetyClause); } break; - case PRE_POST: + case POSTCONDITION: for (final var thread : getInitialLocations().keySet()) { final var safetyClause = buildPostconditionSafetyClause(thread); result.add(safetyClause); @@ -315,7 +315,7 @@ public UnmodifiableTransFormula getTransformula() { // add actual constraints for spec edges, do nothing if not a spec edge protected void transformSpecEdgeClause(final IcfgEdge edge, final HornClauseBuilder clause) { - if (isPreConditionSpecEdge(edge)) { + if (isPreConditionSpecEdge(edge) && mPrefs.specMode() == SpecMode.POSTCONDITION) { incrementThreadCounter(clause, mStartedVar); } else if (isPostConditionSpecEdge(edge)) { incrementThreadCounter(clause, mTerminatedVar); @@ -330,7 +330,7 @@ protected void incrementThreadCounter(final HornClauseBuilder clause, final HcTh } protected boolean isPreConditionSpecEdge(final IcfgEdge edge) { - if (mPrefs.specMode() != SpecMode.PRE_POST) { + if (!mPrefs.hasPreconditions()) { return false; } @@ -340,7 +340,7 @@ protected boolean isPreConditionSpecEdge(final IcfgEdge edge) { } protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { - if (mPrefs.specMode() != SpecMode.PRE_POST) { + if (mPrefs.specMode() != SpecMode.POSTCONDITION) { return false; } @@ -401,13 +401,15 @@ protected HornClauseBuilder buildInitialClause() { addOutLocationConstraint(clause, instance, initialLocs.get(instance)); } - if (mPrefs.specMode() == SpecMode.PRE_POST) { + if (mPrefs.specMode() == SpecMode.POSTCONDITION) { // add constraints that thread counters (for thread-modular encoding of postconditions) are initially 0 clause.addConstraint( SmtUtils.binaryEquality(mScript, clause.getHeadVar(mStartedVar).getTerm(), numeral(0))); clause.addConstraint( SmtUtils.binaryEquality(mScript, clause.getHeadVar(mTerminatedVar).getTerm(), numeral(0))); + } + if (mPrefs.hasPreconditions()) { // add precondition constraint final var locals = mLocalVars.values().collect(Collectors.toList()); for (final var entry : initialLocs.entrySet()) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index f5896b2f84b..a20f4bbf9af 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -51,9 +51,14 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "all starting at once."; public static final ConcurrencyMode DEF_CONCURRENCY_MODE = ConcurrencyMode.PARAMETRIC; + public static final String LABEL_HAS_PRECONDITION = "Assume program has a precondition"; + public static final String DESC_HAS_PRECONDITION = + "Use if the thread templates have a precondition annotated as a 'free requires'."; + public static final boolean DEF_HAS_PRECONDITION = true; + public static final String LABEL_SPEC_MODE = "Specification mode"; public static final String DESC_SPEC_MODE = "Describes how the specification for the program is given."; - public static final SpecMode DEF_SPEC_MODE = SpecMode.PRE_POST; + public static final SpecMode DEF_SPEC_MODE = SpecMode.POSTCONDITION; public static final String LABEL_THREADMODULAR_LEVEL = "Thread-Modular Proof Level"; public static final String DESC_THREADMODULAR_LEVEL = "The level at which thread-modular proofs should be computed"; @@ -82,6 +87,8 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { // Settings for thread-modular proofs new UltimatePreferenceItem<>(LABEL_CONCURRENCY_MODE, DEF_CONCURRENCY_MODE, DESC_CONCURRENCY_MODE, PreferenceType.Combo, ConcurrencyMode.values()), + new UltimatePreferenceItem<>(LABEL_HAS_PRECONDITION, DEF_HAS_PRECONDITION, DESC_HAS_PRECONDITION, + PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SPEC_MODE, DEF_SPEC_MODE, DESC_SPEC_MODE, PreferenceType.Combo, SpecMode.values()), new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 5f95db4960e..918390fb399 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -33,7 +33,7 @@ public class IcfgToChcPreferences { private final IPreferenceProvider mPrefs; public enum SpecMode { - ASSERT_VIOLATIONS, PRE_POST + ASSERT_VIOLATIONS, POSTCONDITION } public IcfgToChcPreferences(final IPreferenceProvider prefs) { @@ -44,6 +44,10 @@ public ConcurrencyMode concurrencyMode() { return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_CONCURRENCY_MODE, ConcurrencyMode.class); } + public boolean hasPreconditions() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_HAS_PRECONDITION); + } + public SpecMode specMode() { return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_SPEC_MODE, SpecMode.class); } From 3cf5dbcc9762ad002e25d8e7d925121edc09f445 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 8 May 2023 20:17:42 +0200 Subject: [PATCH 022/114] IHcReplacementVar: consistently give Script not Sort --- .../plugins/icfgtochc/concurrent/HcLocationVar.java | 6 ++++-- .../ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java | 6 ++++-- .../plugins/icfgtochc/concurrent/HcThreadCounterVar.java | 6 ++++-- .../plugins/icfgtochc/concurrent/HcThreadIdVar.java | 5 ++--- .../concurrent/SleepSetThreadModularHornClauseProvider.java | 4 ++-- .../concurrent/ThreadModularHornClauseProvider.java | 6 +++--- 6 files changed, 19 insertions(+), 14 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java index c6bbdb71d99..d7227a85efb 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java @@ -2,6 +2,8 @@ import java.util.Objects; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; /** @@ -13,9 +15,9 @@ public class HcLocationVar implements IHcThreadSpecificVar { private final ThreadInstance mInstance; private final Sort mSort; - public HcLocationVar(final ThreadInstance instance, final Sort sort) { + public HcLocationVar(final ThreadInstance instance, final Script script) { mInstance = instance; - mSort = sort; + mSort = SmtSortUtils.getIntSort(script); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index 0247f66f732..847d04c060e 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -28,15 +28,17 @@ import java.util.Objects; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; public class HcSleepVar implements IHcThreadSpecificVar { private final Sort mSort; private final ThreadInstance mInstance; - public HcSleepVar(final ThreadInstance instance, final Sort sort) { + public HcSleepVar(final ThreadInstance instance, final Script script) { mInstance = instance; - mSort = sort; + mSort = SmtSortUtils.getBoolSort(script); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java index b668c6e75a0..99cc78e0733 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java @@ -28,6 +28,8 @@ import java.util.Objects; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; /** @@ -51,9 +53,9 @@ public class HcThreadCounterVar implements IHcReplacementVar { private final boolean mIsStarted; private final Sort mSort; - public HcThreadCounterVar(final boolean isStarted, final Sort sort) { + public HcThreadCounterVar(final boolean isStarted, final Script script) { mIsStarted = isStarted; - mSort = sort; + mSort = SmtSortUtils.getIntSort(script); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java index f05240c07aa..aef70349095 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java @@ -28,18 +28,17 @@ import java.util.Objects; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; public class HcThreadIdVar implements IHcThreadSpecificVar { - private static final String SORT = "Int"; - private final Sort mSort; private final ThreadInstance mInstance; public HcThreadIdVar(final ThreadInstance instance, final Script script) { mInstance = instance; - mSort = script.sort(SORT); + mSort = SmtSortUtils.getIntSort(script); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 9bd5f2cdbfb..2a3e67a9906 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -78,7 +78,7 @@ protected List createThreadSpecificVars(final ThreadInstan // add thread ID and sleep set result.add(0, new HcThreadIdVar(instance, mScript)); - result.add(1, new HcSleepVar(instance, getBoolSort())); + result.add(1, new HcSleepVar(instance, mScript)); return result; } @@ -136,7 +136,7 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition } // interfering thread is not sleeping - final var sleep = new HcSleepVar(interferingThread, getBoolSort()); + final var sleep = new HcSleepVar(interferingThread, mScript); clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); // update sleep variables diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index b1b4a05ebb6..6f06c8aa88a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -132,8 +132,8 @@ public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, mBottomLocation = numeral(-1); if (mPrefs.specMode() == SpecMode.POSTCONDITION) { - mStartedVar = new HcThreadCounterVar(true, getIntSort()); - mTerminatedVar = new HcThreadCounterVar(false, getIntSort()); + mStartedVar = new HcThreadCounterVar(true, mScript); + mTerminatedVar = new HcThreadCounterVar(false, mScript); } else { mStartedVar = null; mTerminatedVar = null; @@ -228,7 +228,7 @@ protected List createGlobalVars() { protected List createThreadSpecificVars(final ThreadInstance instance) { final var result = new ArrayList(); - final var location = new HcLocationVar(instance, getIntSort()); + final var location = new HcLocationVar(instance, mScript); mLocationVars.put(instance, location); result.add(location); From bc239dc93072decbd0f7d32b6a964d3de000b595 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 8 May 2023 20:22:23 +0200 Subject: [PATCH 023/114] add interface for finite-valued variables, and implement for HcSleepVar --- .../icfgtochc/concurrent/HcSleepVar.java | 11 ++++- .../concurrent/IHcFiniteReplacementVar.java | 49 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcFiniteReplacementVar.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index 847d04c060e..54d41c3c480 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -27,18 +27,22 @@ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; import java.util.Objects; +import java.util.Set; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.logic.Term; -public class HcSleepVar implements IHcThreadSpecificVar { +public class HcSleepVar implements IHcThreadSpecificVar, IHcFiniteReplacementVar { private final Sort mSort; private final ThreadInstance mInstance; + private final Set mValues; public HcSleepVar(final ThreadInstance instance, final Script script) { mInstance = instance; mSort = SmtSortUtils.getBoolSort(script); + mValues = Set.of(script.term("true"), script.term("false")); } @Override @@ -51,6 +55,11 @@ public ThreadInstance getThreadInstance() { return mInstance; } + @Override + public Set getAllValues() { + return mValues; + } + @Override public String toString() { return "sleep_" + mInstance; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcFiniteReplacementVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcFiniteReplacementVar.java new file mode 100644 index 00000000000..52f75815c87 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcFiniteReplacementVar.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.Set; + +import de.uni_freiburg.informatik.ultimate.logic.Term; + +/** + * An interface for variables that can only take finitely many distinct values. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + */ +public interface IHcFiniteReplacementVar extends IHcReplacementVar { + /** + * The set of all possible values this variable can take. All terms must have the sort returned by + * {@link #getSort()}. The terms must not have free variables, nor refer to uninterpreted function symbols. + * + * For any two terms t1 and t2 in the returned set, either + * Objects.equals(t1, t2) must return true, or the equation (= t1 t2) must be + * unsatisfiable. + */ + Set getAllValues(); +} From 049375592b2ce6f692f20773fd2a6da70512430d Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 8 May 2023 20:29:19 +0200 Subject: [PATCH 024/114] PredicateInfo: drop bidirectional map, simplify code --- .../concurrent/HornClauseBuilder.java | 11 +++---- .../icfgtochc/concurrent/PredicateInfo.java | 31 +++++++------------ .../ThreadModularHornClauseProvider.java | 15 ++++----- 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 26adda8d550..de1dddc3a84 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -33,7 +33,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.IntStream; import de.uni_freiburg.informatik.ultimate.lib.chc.HcBodyVar; import de.uni_freiburg.informatik.ultimate.lib.chc.HcHeadVar; @@ -98,8 +97,7 @@ public void differentBodyHeadVar(final IHcReplacementVar variable) { } public List getDefaultBodyArgs(final PredicateInfo predicate) { - return IntStream.range(0, predicate.getParamCount()) - .mapToObj(i -> getBodyVar(predicate.getParameter(i)).getTerm()) + return predicate.getParameters().stream().map(param -> getBodyVar(param).getTerm()) .collect(Collectors.toCollection(ArrayList::new)); } @@ -126,8 +124,8 @@ public HornClause build() { clause = new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, mBodyVars); } else { - final var headArgs = IntStream.range(0, mHeadPredicate.getParamCount()) - .mapToObj(i -> getHeadVar(mHeadPredicate.getParameter(i))).collect(Collectors.toList()); + final var headArgs = + mHeadPredicate.getParameters().stream().map(this::getHeadVar).collect(Collectors.toList()); clause = new HornClause(mManagedScript, mSymbolTable, constraint, mHeadPredicate.getPredicate(), headArgs, mBodyPreds, substitutedBodyArgs, mBodyVars); } @@ -143,8 +141,7 @@ private void prepareSubstitution() { } mSubstitution.clear(); - for (int i = 0; i < mHeadPredicate.getParamCount(); ++i) { - final var variable = mHeadPredicate.getParameter(i); + for (final var variable : mHeadPredicate.getParameters()) { if (!mModifiedVars.contains(variable)) { mSubstitution.put(getBodyVar(variable).getTermVariable(), getHeadVar(variable).getTerm()); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java index 4d13dbdf187..08a271885d8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java @@ -26,47 +26,40 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; +import java.util.Collection; +import java.util.List; import java.util.Objects; import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; -import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; public class PredicateInfo { private final HcPredicateSymbol mPredicate; - private final BidirectionalMap mVariable2Index; + protected final List mParameters; - public PredicateInfo(final HcPredicateSymbol predicate, - final BidirectionalMap variable2Index) { + public PredicateInfo(final HcPredicateSymbol predicate, final List parameters) { mPredicate = predicate; - mVariable2Index = variable2Index; + mParameters = parameters; } public HcPredicateSymbol getPredicate() { return mPredicate; } - public boolean hasParameter(final IHcReplacementVar variable) { - return mVariable2Index.containsKey(variable); - } - - public int getIndex(final IHcReplacementVar variable) { - assert mVariable2Index.containsKey(variable); - return mVariable2Index.get(variable); + public Collection getParameters() { + return mParameters; } - public IHcReplacementVar getParameter(final int index) { - final var result = mVariable2Index.inverse().get(index); - assert result != null : "No parameter at index " + index + " (out of " + mPredicate.getArity() + ")"; - return result; + public boolean hasParameter(final IHcReplacementVar variable) { + return mParameters.contains(variable); } public int getParamCount() { - return mVariable2Index.size(); + return mParameters.size(); } @Override public int hashCode() { - return Objects.hash(mPredicate, mVariable2Index); + return Objects.hash(mPredicate, mParameters); } @Override @@ -81,6 +74,6 @@ public boolean equals(final Object obj) { return false; } final PredicateInfo other = (PredicateInfo) obj; - return Objects.equals(mPredicate, other.mPredicate) && Objects.equals(mVariable2Index, other.mVariable2Index); + return Objects.equals(mPredicate, other.mPredicate) && Objects.equals(mParameters, other.mParameters); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 6f06c8aa88a..036e30a68f4 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -37,7 +38,6 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.IntStream; import java.util.stream.Stream; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; @@ -62,7 +62,6 @@ import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences.SpecMode; -import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; import de.uni_freiburg.informatik.ultimate.util.datastructures.DataStructureUtils; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; @@ -168,10 +167,7 @@ private PredicateInfo createInvariantPredicate() { final List sorts = parameters.stream().map(IHcReplacementVar::getSort).collect(Collectors.toList()); final var predicate = mSymbolTable.getOrConstructHornClausePredicateSymbol(FUNCTION_NAME, sorts); - final var paramMap = IntStream.range(0, parameters.size()).mapToObj(i -> new Pair<>(parameters.get(i), i)) - .collect(Collectors.toMap(Pair::getKey, Pair::getValue, (i, j) -> i, BidirectionalMap::new)); - - return new PredicateInfo(predicate, paramMap); + return new PredicateInfo(predicate, parameters); } /** @@ -549,10 +545,11 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition final var interferingVars = createThreadSpecificVars(interferingThread); for (int i = 0; i < instanceVars.size(); ++i) { final var original = instanceVars.get(i); - final var replaced = interferingVars.get(i); if (mInvariantPredicate.hasParameter(original)) { - final int index = mInvariantPredicate.getIndex(original); - bodyArgs.set(index, clause.getBodyVar(replaced).getTerm()); + final var originalTerm = clause.getBodyVar(original).getTerm(); + final var replaced = interferingVars.get(i); + final var replacedTerm = clause.getBodyVar(replaced).getTerm(); + Collections.replaceAll(bodyArgs, originalTerm, replacedTerm); } } From 1a5620faddce8c6d0f8bb0454776473327a20164 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 8 May 2023 20:30:12 +0200 Subject: [PATCH 025/114] add small optimization: drop Horn clauses with constraint false --- .../icfgtochc/concurrent/ExtensibleHornClauseProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java index 6b49d270381..f98e406ad01 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java @@ -35,6 +35,7 @@ import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; @@ -61,7 +62,8 @@ protected final HornClauseBuilder createBuilder(final String comment) { protected abstract List buildAllClauses(); public final List getClauses() { - return buildAllClauses().stream().map(HornClauseBuilder::build).collect(Collectors.toList()); + return buildAllClauses().stream().map(HornClauseBuilder::build) + .filter(c -> !SmtUtils.isFalseLiteral(c.getConstraintFormula())).collect(Collectors.toList()); } protected final Term numeral(final long n) { From 95355cc5b625f871dc2fc2d5e08420636bf3d462 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 9 May 2023 08:29:39 +0200 Subject: [PATCH 026/114] add predicate families, to prepare support for different encodings --- .../icfgtochc/concurrent/PredicateFamily.java | 146 +++++++++++++++++ .../concurrent/PredicateVariant.java | 147 ++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateFamily.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateVariant.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateFamily.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateFamily.java new file mode 100644 index 00000000000..371ccae4181 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateFamily.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.ArrayDeque; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.util.datastructures.DataStructureUtils; +import de.uni_freiburg.informatik.ultimate.util.datastructures.ImmutableList; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; + +/** + * A finite indexed family of predicate symbols. The index is given by a list of {@link IHcFiniteReplacementVar}s. For + * each combination of values of these variables, there is a unique predicate symbol. + * + * For instance, consider a predicate {@code P(x,y,z)}. If the first two parameters are booleans (and can thus only take + * finitely many values), we can describe this predicate through the family consisting of the four predicates + * {@code P_false_false(z)}, {@code P_false_true(z)}, {@code P_true_false(z)} and {@code P_true_true(z)}. + * + * We use this class to abstract over different modes for Horn clause generation, where certain finite parameters (e.g. + * ICFG locations) can either be treated symbolically (using quantified variables, and possibly constraints over them) + * or explicitly (i.e., different predicate symbols depending on the variables' values). + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + */ +public class PredicateFamily { + private final HcSymbolTable mSymbolTable; + private final PredicateInfo mBasePredicate; + private final List mIndices; + + private final List mVariants; + + /** + * Creates a new indexed family of predicates. + * + * @param symbolTable + * A symbol table where predicate symbols shall be declared + * @param basePredicate + * A base predicate for the family, where all parameters are symbolic. The various predicates in the + * family will be derived by removing the {@code indices} from the symbolic parameters, and making them + * explicit instead. + * @param indices + * The parameters of the base predicate that shall be made explicit. + */ + public PredicateFamily(final HcSymbolTable symbolTable, final PredicateInfo basePredicate, + final List indices) { + mSymbolTable = symbolTable; + mBasePredicate = basePredicate; + mIndices = indices; + + mVariants = createVariants(); + } + + public PredicateInfo getBasePredicate() { + return mBasePredicate; + } + + public List getVariants() { + return mVariants; + } + + public List getVariants(final Map indexValues) { + return mVariants.stream().filter(p -> p.matches(indexValues)).collect(Collectors.toList()); + } + + public PredicateVariant getVariant(final Map indexValues) { + assert isCompleteIndexMap(indexValues); + return DataStructureUtils.getOneAndOnly(mVariants.stream().filter(p -> p.matches(indexValues))::iterator, + "instance"); + } + + public boolean isIndexedBy(final IHcFiniteReplacementVar variable) { + return mIndices.contains(variable); + } + + private List createVariants() { + return constructCartesianProductOfValues().stream().map(this::constructVariant).collect(Collectors.toList()); + } + + private PredicateVariant constructVariant(final ImmutableList values) { + final var valueMap = + IntStream.range(0, mIndices.size()).mapToObj(i -> new Pair<>(mIndices.get(i), values.get(i))) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + return new PredicateVariant(mSymbolTable, this, valueMap); + } + + private ArrayDeque> constructCartesianProductOfValues() { + final var product = new ArrayDeque>(); + product.push(ImmutableList.empty()); + + final var iterator = mIndices.listIterator(mIndices.size()); + while (iterator.hasPrevious()) { + final var index = iterator.previous(); + final int size = product.size(); + for (int i = 0; i < size; ++i) { + final var tuple = product.pollFirst(); + for (final var value : index.getAllValues()) { + final var extendedTuple = new ImmutableList<>(value, tuple); + product.offerLast(extendedTuple); + } + } + } + + return product; + } + + private boolean isCompleteIndexMap(final Map indexValues) { + for (final var ind : mIndices) { + final var value = indexValues.get(ind); + if (value == null) { + return false; + } + assert ind.getAllValues().contains(value) : "Wrong value for " + ind + ": " + value; + } + return true; + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateVariant.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateVariant.java new file mode 100644 index 00000000000..97fc3aa9c4c --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateVariant.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +/** + * A member of a {@link PredicateFamily}, where the family's indices have been fixed to concrete values. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + */ +public class PredicateVariant extends PredicateInfo { + private final PredicateFamily mFamily; + private final Map mIndexValues; + + PredicateVariant(final HcSymbolTable symbolTable, final PredicateFamily family, + final Map indexValues) { + this(symbolTable, family, indexValues, + projectParameters(family.getBasePredicate().mParameters, indexValues.keySet())); + } + + private PredicateVariant(final HcSymbolTable symbolTable, final PredicateFamily family, + final Map indexValues, final List parameters) { + super(instantiatePredicate(symbolTable, family.getBasePredicate(), indexValues, parameters), parameters); + mFamily = family; + mIndexValues = indexValues; + } + + /** + * Determines if this instance has the given values for its indices. Values for parameters which are not indices are + * ignored. + * + * @param indexMap + * Maps certain variables to values. May include mappings for variables that are not indices (ignored), + * and may omit mappings for some of the indices (can have any value). + * @return {@code true} if for all indices of this predicate that are present in the map, the instance's value + * equals the value in the map; {@code false} otherwise. + */ + public boolean matches(final Map indexMap) { + for (final var entry : indexMap.entrySet()) { + final var variable = entry.getKey(); + if (mFamily.isIndexedBy(variable) && !Objects.equals(entry.getValue(), mIndexValues.get(variable))) { + return false; + } + } + return true; + } + + /** + * Determines if the given variable is an index of this predicate variant (i.e., the predicate fixes a value of the + * variable). + */ + public boolean hasIndex(final IHcFiniteReplacementVar variable) { + return mFamily.isIndexedBy(variable); + } + + /** + * Retrieves the fixed value of the given variable associated with this predicate variant. The variable must be an + * index of the predicate variant (see {@link #hasIndex(IHcFiniteReplacementVar)}). + */ + public Term getIndexValue(final IHcFiniteReplacementVar variable) { + assert hasIndex(variable) : variable + " is not an index of this predicate variant"; + return mIndexValues.get(variable); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Objects.hash(mFamily, mIndexValues); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PredicateVariant other = (PredicateVariant) obj; + return Objects.equals(mFamily, other.mFamily) && Objects.equals(mIndexValues, other.mIndexValues); + } + + private static HcPredicateSymbol instantiatePredicate(final HcSymbolTable symbolTable, + final PredicateInfo predicate, final Map indexValues, + final List parameters) { + final var name = constructInstanceName(predicate.getPredicate().getName(), indexValues); + final var paramSorts = parameters.stream().map(IHcReplacementVar::getSort).collect(Collectors.toList()); + return symbolTable.getOrConstructHornClausePredicateSymbol(name, paramSorts); + } + + private static String constructInstanceName(final String basename, + final Map indexValues) { + final var name = new StringBuilder(basename); + + for (final var entry : indexValues.entrySet()) { + name.append("_"); + name.append(entry.getKey()); + name.append("="); + name.append(entry.getValue()); + } + + return name.toString(); + } + + private static List projectParameters(final List parameters, + final Set indices) { + return parameters.stream().filter(p -> !indices.contains(p)).collect(Collectors.toList()); + } +} From a7f57b1af524033335598e396fa3840c20e97a22 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 9 May 2023 08:45:32 +0200 Subject: [PATCH 027/114] add settings for future encoding variants --- .../IcfgToChcPreferenceInitializer.java | 16 +++++++++++++++- .../preferences/IcfgToChcPreferences.java | 8 ++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index a20f4bbf9af..317fc0cadf3 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -64,6 +64,11 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize public static final String DESC_THREADMODULAR_LEVEL = "The level at which thread-modular proofs should be computed"; public static final int DEF_THREADMODULAR_LEVEL = 2; + public static final String LABEL_EXPLICIT_LOCATIONS = "Encode control locations explicitly"; + public static final String DESC_EXPLICIT_LOCATIONS = "Control locations can be encoded symbolically " + + "(as CHC variables), or explicitly (by using different predicate symbols)."; + public static final boolean DEF_EXPLICIT_LOCATIONS = false; + public static final String LABEL_LIPTON_REDUCTION = "Apply Lipton reduction"; public static final String DESC_LIPTON_REDUCTION = "If enabled, Lipton reduction is applied to simplify thread " + "templates, before a thread-modular proof is computed."; @@ -74,6 +79,11 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "program. This allows for more programs to be proven correct."; public static final boolean DEF_SLEEP_SET_REDUCTION = true; + public static final String LABEL_EXPLICIT_SLEEP = "Encode sleep sets explicitly"; + public static final String DESC_EXPLICIT_SLEEP = "Sleep sets can be encoded symbolically (as CHC variables), " + + "or explicitly (by using different predicate symbols)."; + public static final boolean DEF_EXPLICIT_SLEEP = false; + /** * Default constructor. */ @@ -93,10 +103,14 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { SpecMode.values()), new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, DESC_THREADMODULAR_LEVEL, PreferenceType.Integer), + new UltimatePreferenceItem<>(LABEL_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, + PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, - DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean) }; + DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, + PreferenceType.Boolean) }; } public static IPreferenceProvider getPreferenceProvider(final IUltimateServiceProvider services) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 918390fb399..0e4bdf01f9b 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -56,6 +56,10 @@ public int getThreadModularProofLevel() { return mPrefs.getInt(IcfgToChcPreferenceInitializer.LABEL_THREADMODULAR_LEVEL); } + public boolean explicitLocations() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_LOCATIONS); + } + public boolean useLiptonReduction() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_LIPTON_REDUCTION); } @@ -63,4 +67,8 @@ public boolean useLiptonReduction() { public boolean useSleepSets() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SLEEP_SET_REDUCTION); } + + public boolean explicitSleep() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_SLEEP); + } } From 85aa4c433bbbd4815c123511fd81fdf9226c20e7 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 9 May 2023 13:13:41 +0200 Subject: [PATCH 028/114] add setting for different preference order encoding --- .../preferences/IcfgToChcPreferenceInitializer.java | 7 +++++++ .../icfgtochc/preferences/IcfgToChcPreferences.java | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 317fc0cadf3..b44c2e9a8d8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -79,6 +79,11 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "program. This allows for more programs to be proven correct."; public static final boolean DEF_SLEEP_SET_REDUCTION = true; + public static final String LABEL_BREAK_PREFORDER_SYMMETRY = "Break symmetry of preference order"; + public static final String DESC_BREAK_PREFORDER_SYMMETRY = "A straightforward encoding forces proofs to consider " + + "all symmetric preference orders. If we break symmetry, more proofs are accepted."; + public static final boolean DEF_BREAK_PREFORDER_SYMMETRY = true; + public static final String LABEL_EXPLICIT_SLEEP = "Encode sleep sets explicitly"; public static final String DESC_EXPLICIT_SLEEP = "Sleep sets can be encoded symbolically (as CHC variables), " + "or explicitly (by using different predicate symbols)."; @@ -109,6 +114,8 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DESC_BREAK_PREFORDER_SYMMETRY, + DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, PreferenceType.Boolean) }; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 0e4bdf01f9b..9ad7681e7c2 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -68,6 +68,10 @@ public boolean useSleepSets() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SLEEP_SET_REDUCTION); } + public boolean breakPreferenceOrderSymmetry() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.DESC_BREAK_PREFORDER_SYMMETRY); + } + public boolean explicitSleep() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_SLEEP); } From 4114dde94a677f95af9a69ac4327e8d9844e3474 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 10 May 2023 10:05:07 +0200 Subject: [PATCH 029/114] IHcThreadSpecificVar: add forInstance method --- .../icfgtochc/concurrent/HcLocalVar.java | 5 +++++ .../icfgtochc/concurrent/HcLocationVar.java | 11 +++++++++- .../icfgtochc/concurrent/HcSleepVar.java | 22 ++++++++++++++----- .../icfgtochc/concurrent/HcThreadIdVar.java | 19 +++++++++++----- .../concurrent/IHcThreadSpecificVar.java | 8 +++++++ 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java index 092195d5358..fe0f8fbaec4 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java @@ -29,6 +29,11 @@ public ThreadInstance getThreadInstance() { return mInstance; } + @Override + public IHcThreadSpecificVar forInstance(final int instanceId) { + return new HcLocalVar(mVariable, new ThreadInstance(mInstance.getTemplateName(), instanceId)); + } + @Override public Sort getSort() { return mVariable.getSort(); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java index d7227a85efb..5e067058f32 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java @@ -16,8 +16,12 @@ public class HcLocationVar implements IHcThreadSpecificVar { private final Sort mSort; public HcLocationVar(final ThreadInstance instance, final Script script) { + this(instance, SmtSortUtils.getIntSort(script)); + } + + private HcLocationVar(final ThreadInstance instance, final Sort sort) { mInstance = instance; - mSort = SmtSortUtils.getIntSort(script); + mSort = sort; } @Override @@ -25,6 +29,11 @@ public ThreadInstance getThreadInstance() { return mInstance; } + @Override + public IHcThreadSpecificVar forInstance(final int instanceId) { + return new HcLocationVar(new ThreadInstance(mInstance.getTemplateName(), instanceId), mSort); + } + @Override public Sort getSort() { return mSort; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index 54d41c3c480..3c66f98c8b5 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -40,14 +40,13 @@ public class HcSleepVar implements IHcThreadSpecificVar, IHcFiniteReplacementVar private final Set mValues; public HcSleepVar(final ThreadInstance instance, final Script script) { - mInstance = instance; - mSort = SmtSortUtils.getBoolSort(script); - mValues = Set.of(script.term("true"), script.term("false")); + this(instance, SmtSortUtils.getBoolSort(script), Set.of(script.term("true"), script.term("false"))); } - @Override - public Sort getSort() { - return mSort; + private HcSleepVar(final ThreadInstance instance, final Sort sort, final Set values) { + mInstance = instance; + mSort = sort; + mValues = values; } @Override @@ -55,11 +54,22 @@ public ThreadInstance getThreadInstance() { return mInstance; } + @Override + public IHcThreadSpecificVar forInstance(final int instanceId) { + // TODO Auto-generated method stub + return null; + } + @Override public Set getAllValues() { return mValues; } + @Override + public Sort getSort() { + return mSort; + } + @Override public String toString() { return "sleep_" + mInstance; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java index aef70349095..b00defe0ae3 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java @@ -37,13 +37,12 @@ public class HcThreadIdVar implements IHcThreadSpecificVar { private final ThreadInstance mInstance; public HcThreadIdVar(final ThreadInstance instance, final Script script) { - mInstance = instance; - mSort = SmtSortUtils.getIntSort(script); + this(instance, SmtSortUtils.getIntSort(script)); } - @Override - public Sort getSort() { - return mSort; + private HcThreadIdVar(final ThreadInstance instance, final Sort sort) { + mInstance = instance; + mSort = sort; } @Override @@ -51,6 +50,16 @@ public ThreadInstance getThreadInstance() { return mInstance; } + @Override + public IHcThreadSpecificVar forInstance(final int instanceId) { + return new HcThreadIdVar(new ThreadInstance(mInstance.getTemplateName(), instanceId), mSort); + } + + @Override + public Sort getSort() { + return mSort; + } + @Override public String toString() { return "id_" + mInstance; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java index 389f62066ef..0add2e14be7 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcThreadSpecificVar.java @@ -28,4 +28,12 @@ public interface IHcThreadSpecificVar extends IHcReplacementVar { ThreadInstance getThreadInstance(); + + /** + * Retrieves the corresponding variable for the given thread instance ID. + * + * @param instanceId + * the instance number + */ + IHcThreadSpecificVar forInstance(int instanceId); } From 65b7c63a6c5d846df7adda264f89d44690d90cda Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 10 May 2023 10:59:38 +0200 Subject: [PATCH 030/114] fix IcfgToChc preferences, output more detailed error in the future --- .../informatik/ultimate/core/coreplugin/PluginFactory.java | 5 +++-- .../preferences/IcfgToChcPreferenceInitializer.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/PluginFactory.java b/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/PluginFactory.java index 2936827df7c..a5d4d4dcbc8 100644 --- a/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/PluginFactory.java +++ b/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/PluginFactory.java @@ -208,8 +208,9 @@ private List loadAdmissiblePlugins() { } rtr.add(tool); } catch (final Exception ex) { - mLogger.fatal("Exception during admissibility check of plugin " + elem.getName() + ": " - + ex.getMessage()); + mLogger.fatal( + "Exception during admissibility check of plugin " + elem.getName() + ": " + ex.getMessage(), + ex); } } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index b44c2e9a8d8..d5f0e03855d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -108,13 +108,13 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { SpecMode.values()), new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, DESC_THREADMODULAR_LEVEL, PreferenceType.Integer), - new UltimatePreferenceItem<>(LABEL_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, + new UltimatePreferenceItem<>(LABEL_EXPLICIT_LOCATIONS, DEF_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean), - new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DESC_BREAK_PREFORDER_SYMMETRY, + new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DEF_BREAK_PREFORDER_SYMMETRY, DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, PreferenceType.Boolean) }; From 721589e2d8f4d83a7a84522130ca2fd1f917b421 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 10 May 2023 13:36:21 +0200 Subject: [PATCH 031/114] another fix for settings code --- .../plugins/icfgtochc/preferences/IcfgToChcPreferences.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 9ad7681e7c2..875371e0022 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -69,7 +69,7 @@ public boolean useSleepSets() { } public boolean breakPreferenceOrderSymmetry() { - return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.DESC_BREAK_PREFORDER_SYMMETRY); + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_BREAK_PREFORDER_SYMMETRY); } public boolean explicitSleep() { From 9aa0c92c54d50d2f20427c49fab48fa9ebad0096 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 10 May 2023 13:37:05 +0200 Subject: [PATCH 032/114] HcSleepVar: properly implement forInstance --- .../ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index 3c66f98c8b5..8b4f780113b 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -56,8 +56,7 @@ public ThreadInstance getThreadInstance() { @Override public IHcThreadSpecificVar forInstance(final int instanceId) { - // TODO Auto-generated method stub - return null; + return new HcSleepVar(new ThreadInstance(mInstance.getTemplateName(), instanceId), mSort, mValues); } @Override From c78c7c0aa6d4d584c58693ae52eea796e480f1cb Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 10 May 2023 13:41:22 +0200 Subject: [PATCH 033/114] SleepSetThreadModularProofs: properly implement symmetry breaking --- .../icfgtochc/concurrent/HcSleepVar.java | 4 +- ...eepSetThreadModularHornClauseProvider.java | 209 +++++++++++++----- .../ThreadModularHornClauseProvider.java | 106 +++++---- 3 files changed, 224 insertions(+), 95 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java index 8b4f780113b..1dbebc8f9ea 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java @@ -30,6 +30,7 @@ import java.util.Set; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; @@ -40,7 +41,8 @@ public class HcSleepVar implements IHcThreadSpecificVar, IHcFiniteReplacementVar private final Set mValues; public HcSleepVar(final ThreadInstance instance, final Script script) { - this(instance, SmtSortUtils.getBoolSort(script), Set.of(script.term("true"), script.term("false"))); + this(instance, SmtSortUtils.getBoolSort(script), + Set.of(script.term(SMTLIBConstants.TRUE), script.term(SMTLIBConstants.FALSE))); } private HcSleepVar(final ThreadInstance instance, final Sort sort, final Set values) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 2a3e67a9906..81521a16c82 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -26,12 +26,15 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.IntStream; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; @@ -42,6 +45,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; @@ -61,7 +65,11 @@ public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider se mThreadLocations = icfg.getProgramPoints().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); - mIdVars = extractThreadVars(HcThreadIdVar.class); + if (!mPrefs.breakPreferenceOrderSymmetry()) { + mIdVars = extractThreadVars(HcThreadIdVar.class); + } else { + mIdVars = null; + } mSleepVars = extractThreadVars(HcSleepVar.class); } @@ -76,9 +84,13 @@ private Map extractThreadVars(final Class varClass) { protected List createThreadSpecificVars(final ThreadInstance instance) { final var result = super.createThreadSpecificVars(instance); - // add thread ID and sleep set - result.add(0, new HcThreadIdVar(instance, mScript)); - result.add(1, new HcSleepVar(instance, mScript)); + // add sleep set variable + result.add(0, new HcSleepVar(instance, mScript)); + + if (!mPrefs.breakPreferenceOrderSymmetry()) { + // add thread ID (used to describe preference order) + result.add(0, new HcThreadIdVar(instance, mScript)); + } return result; } @@ -87,6 +99,11 @@ protected List createThreadSpecificVars(final ThreadInstan protected HornClauseBuilder buildInitialClause() { final var clause = super.buildInitialClause(); + // thread IDs are pairwise different + if (!mPrefs.breakPreferenceOrderSymmetry()) { + ensureUniqueThreadIDs(clause); + } + // all sleep variables are initialized to false for (final var instance : mInstances) { final var sleep = mSleepVars.get(instance); @@ -108,9 +125,6 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); } - // thread IDs are ordered - ensureThreadOrdering(clause); - // update sleep variables for (final var instance : mInstances) { updateSleepInductive(clause, transition, preds.keySet(), updatedThread, instance); @@ -119,16 +133,34 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran return clause; } + @Override + protected List buildNonInterferenceClauses(final IIcfgTransition transition) { + if (!mPrefs.breakPreferenceOrderSymmetry()) { + return super.buildNonInterferenceClauses(transition); + } + + final var result = new ArrayList(); + final var instanceCount = getInstances(transition.getPrecedingProcedure()).size(); + for (int i = 0; i <= instanceCount; ++i) { + result.add(buildNonInterferenceClause(transition, i)); + } + + return result; + } + + // This overload constructs non-interference clauses where the preference order is treated symbolically. @Override protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { + if (mPrefs.breakPreferenceOrderSymmetry()) { + throw new UnsupportedOperationException("This method does not support breaking preference order symmetry. " + + "Call the other overload of this method instead."); + } + final var clause = super.buildNonInterferenceClause(transition); final var interferingThread = getInterferingThread(transition); final var interferingId = new HcThreadIdVar(interferingThread, mScript); - // thread IDs are ordered - ensureThreadOrdering(clause); - // ensure interfering thread has distinct thread ID for (final var instance : mInstances) { clause.addConstraint(SmtUtils.distinct(mScript, clause.getBodyVar(mIdVars.get(instance)).getTerm(), @@ -147,79 +179,148 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition return clause; } - private void ensureThreadOrdering(final HornClauseBuilder clause) { - for (int i = 0; i < mInstances.size(); ++i) { - final var instance = mInstances.get(i); - final var id = mIdVars.get(instance); - - // fix ordering between thread IDs - if (i + 1 < mInstances.size()) { - final var next = mInstances.get(i + 1); - final var nextId = mIdVars.get(next); - clause.addConstraint( - SmtUtils.less(mScript, clause.getBodyVar(id).getTerm(), clause.getBodyVar(nextId).getTerm())); + // This overload constructs non-interference clauses where preference order symmetry is broken, and the preference + // order is resolved statically. + protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition, final int index) { + if (!mPrefs.breakPreferenceOrderSymmetry()) { + throw new UnsupportedOperationException("This method breaks preference order symmetry, which is turned off." + + " Call the other overload of this method instead."); + } + + // TODO support transitions with multiple predecessors (joins) + final var interferingThread = getInterferingThread(transition); + // final var interferingVars = createThreadSpecificVars(interferingThread); + final var instances = getInstances(interferingThread.getTemplateName()); + + final var clause = buildNonInterferenceClause(transition, (c, replacedInstance) -> { + // the sequence of instances to consider + final var relevantInstances = new ArrayList<>(instances); + relevantInstances.add(index, interferingThread); + relevantInstances.remove(replacedInstance); + + final var substitution = IntStream.range(0, instances.size()) + .mapToObj(i -> new Pair<>(instances.get(i), relevantInstances.get(i))) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + + // take the default parameters, and adjust them to the relevant sequence of instances + final var bodyArgs = new ArrayList<>(mInvariantPredicate.getParameters()); + for (int i = 0; i < bodyArgs.size(); ++i) { + final var arg = bodyArgs.get(i); + if (!(arg instanceof IHcThreadSpecificVar)) { + continue; + } + final var specific = (IHcThreadSpecificVar) arg; + final var oldThread = specific.getThreadInstance(); + final var newThread = substitution.get(oldThread); + if (newThread != null) { + assert Objects.equals(oldThread.getTemplateName(), newThread.getTemplateName()); + final var replaced = specific.forInstance(newThread.getInstanceNumber()); + bodyArgs.set(i, replaced); + } + } + + return bodyArgs.stream().map(v -> c.getBodyVar(v).getTerm()).collect(Collectors.toList()); + }); + + // interfering thread is not sleeping + final var sleep = new HcSleepVar(interferingThread, mScript); + clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); + + // update sleep variables + for (final var instance : mInstances) { + final var prefOrder = index < instance.getInstanceNumber() ? mScript.term(SMTLIBConstants.FALSE) + : mScript.term(SMTLIBConstants.TRUE); + updateSleep(clause, transition, instance, prefOrder); + } + + return clause; + } + + private void ensureUniqueThreadIDs(final HornClauseBuilder clause) { + for (final var first : mInstances) { + final var firstId = clause.getHeadVar(mIdVars.get(first)); + for (final var second : mInstances) { + if (!Objects.equals(first, second)) { + final var secondId = clause.getHeadVar(mIdVars.get(second)); + clause.addConstraint(SmtUtils.distinct(mScript, firstId.getTerm(), secondId.getTerm())); + } } } } - // update sleep variable depending on commutativity and thread ID ordering - // Here the ordering can be resolved statically + // update sleep variable depending on commutativity and preference order private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTransition transition, final Set activeThreads, final ThreadInstance primaryActiveThread, final ThreadInstance current) { - final var loc = clause.getBodyVar(mLocationVars.get(current)); - final Term commConstr = getCommutativityConstraint(current, loc.getTerm(), transition); - - // for now, the preference order is non-positional, and given by the ordering in mInstances - final int ordering = Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(current)); - - final var sleep = mSleepVars.get(current); if (activeThreads.contains(current)) { // no update of sleep variable - } else if (ordering < 0) { - // current thread is AFTER primary thread - // set sleep variable to false / leave unchanged - clause.differentBodyHeadVar(sleep); - final var oldSleep = clause.getBodyVar(sleep); - final var newSleep = clause.getHeadVar(sleep); - clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), - SmtUtils.and(mScript, oldSleep.getTerm(), commConstr))); + return; + } + + final Term prefOrder; + if (mPrefs.breakPreferenceOrderSymmetry()) { + // We resolve the preference order statically. + // For now, the preference order is non-positional, and given by the ordering in mInstances. + final int ordering = Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(current)); + // Formula expressing whether current thread is BEFORE primary thread. + prefOrder = ordering < 0 ? mScript.term(SMTLIBConstants.FALSE) : mScript.term(SMTLIBConstants.TRUE); } else { - // set sleep variable to false / true - clause.differentBodyHeadVar(sleep); - final var newSleep = clause.getHeadVar(sleep); - clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), commConstr)); + // We resolve the preference order symbolically, using ID variables. + prefOrder = symbolicPreferenceOrderConstraint(clause, current, primaryActiveThread); } + + updateSleep(clause, transition, current, prefOrder); } - // update sleep variable depending on commutativity and thread ID ordering - // Here the ordering can only be resolved at runtime, so we treat it statically + // update sleep variable depending on commutativity and preference order private void updateSleepNonInterference(final HornClauseBuilder clause, final IIcfgTransition transition, final HcThreadIdVar interferingId, final ThreadInstance current) { + // TODO if breaking symmetry, do this statically! + final var prefOrder = symbolicPreferenceOrderConstraint(clause, current, interferingId.getThreadInstance()); + + updateSleep(clause, transition, current, prefOrder); + } + + // update sleep variable depending on commutativity and preference order + private void updateSleep(final HornClauseBuilder clause, final IIcfgTransition transition, + final ThreadInstance current, final Term prefOrder) { final var sleep = mSleepVars.get(current); clause.differentBodyHeadVar(sleep); + final var oldSleep = clause.getBodyVar(sleep); final var newSleep = clause.getHeadVar(sleep); - final var currentLoc = clause.getBodyVar(mLocationVars.get(current)); - final var currentId = clause.getBodyVar(mIdVars.get(current)); + final var canBePutToSleep = SmtUtils.or(mScript, prefOrder, oldSleep.getTerm()); + if (SmtUtils.isFalseLiteral(canBePutToSleep)) { + // optimization: If commutativity does not play a role, skip computation of commutativity constraint + // sleep' = false + clause.addConstraint( + SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), mScript.term(SMTLIBConstants.FALSE))); + return; + } + + // get constraint describing commutativity + final var currentLoc = clause.getBodyVar(mLocationVars.get(current)); final Term commConstr = getCommutativityConstraint(current, currentLoc.getTerm(), transition); + // sleep' = (current < interfering \/ sleep) /\ commConstr - clause.addConstraint( - SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), - SmtUtils.and(mScript, - SmtUtils.or(mScript, - SmtUtils.less(mScript, currentId.getTerm(), - clause.getBodyVar(interferingId).getTerm()), - oldSleep.getTerm()), - commConstr))); + clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), + SmtUtils.and(mScript, canBePutToSleep, commConstr))); + } + + private Term symbolicPreferenceOrderConstraint(final HornClauseBuilder clause, final ThreadInstance current, + final ThreadInstance active) { + final var currentId = clause.getBodyVar(new HcThreadIdVar(current, mScript)); + final var activeId = clause.getBodyVar(new HcThreadIdVar(active, mScript)); + return SmtUtils.less(mScript, currentId.getTerm(), activeId.getTerm()); } protected Term getCommutativityConstraint(final ThreadInstance instance, final Term locVar, final IIcfgTransition currentEdge) { final var commLocations = new HashSet(); for (final var loc : mThreadLocations.get(instance.getTemplateName())) { + // TODO can be optimized: if (= locVar loc) is false, don't check independence if (loc.getOutgoingEdges().stream() // ignore spec edges: the original edges are replaced, and the replacing transitions commute .filter(e -> !isPreConditionSpecEdge(e) && !isPostConditionSpecEdge(e)) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 036e30a68f4..a4df8ed3d55 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -36,6 +36,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -254,29 +255,7 @@ protected List buildAllClauses() { final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); while (edges.hasNext()) { final IcfgEdge original = edges.next(); - - // replace spec edges by dummy transitions that do nothing (actual constraints are added later) - IcfgEdge edge; - if (isPreConditionSpecEdge(original) || isPostConditionSpecEdge(original)) { - edge = createDummyEdge(original); - } else { - edge = original; - } - - // add inductivity clauses - for (final var prePost : getCartesianPrePostProduct(edge)) { - final var clause = - buildInductivityClause(edge, prePost.getFirst(), prePost.getSecond(), prePost.getThird()); - transformSpecEdgeClause(original, clause); - result.add(clause); - } - - // add non-interference clause - if (mUnboundedTemplates.contains(proc)) { - final var clause = buildNonInterferenceClause(edge); - transformSpecEdgeClause(original, clause); - result.add(clause); - } + result.addAll(buildClausesForTransition(original)); } } @@ -299,6 +278,37 @@ protected List buildAllClauses() { return result; } + protected List buildClausesForTransition(final IcfgEdge original) { + final var result = new ArrayList(); + + // replace spec edges by dummy transitions that do nothing (actual constraints are added later) + IcfgEdge edge; + if (isPreConditionSpecEdge(original) || isPostConditionSpecEdge(original)) { + edge = createDummyEdge(original); + } else { + edge = original; + } + + // add inductivity clauses + for (final var prePost : getCartesianPrePostProduct(edge)) { + final var clause = + buildInductivityClause(edge, prePost.getFirst(), prePost.getSecond(), prePost.getThird()); + transformSpecEdgeClause(original, clause); + result.add(clause); + } + + // add non-interference clause + if (mUnboundedTemplates.contains(edge.getPrecedingProcedure())) { + final var clauses = buildNonInterferenceClauses(edge); + for (final var clause : clauses) { + transformSpecEdgeClause(original, clause); + } + result.addAll(clauses); + } + + return result; + } + protected IcfgEdge createDummyEdge(final IcfgEdge original) { final var tf = TransFormulaBuilder.getTrivialTransFormula(mManagedScript); return new IcfgEdge(original.getSource(), original.getTarget(), original.getPayload()) { @@ -523,10 +533,29 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran return clause; } + protected List buildNonInterferenceClauses(final IIcfgTransition transition) { + final var result = new ArrayList(); + result.add(buildNonInterferenceClause(transition)); + return result; + } + /** * Builds a noninterference clause for the given transition. */ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { + // TODO support transitions with multiple predecessors (joins) + final var interferingThread = getInterferingThread(transition); + final var interferingVars = createThreadSpecificVars(interferingThread); + + return buildNonInterferenceClause(transition, (clause, instance) -> { + final var bodyArgs = new ArrayList<>(mInvariantPredicate.getParameters()); + replaceThreadVariables(bodyArgs, instance, interferingVars); + return bodyArgs.stream().map(v -> clause.getBodyVar(v).getTerm()).collect(Collectors.toList()); + }); + } + + protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition, + final BiFunction> getInterferencePrecondition) { final var clause = createBuilder(mInvariantPredicate, "non-interference clause for transition " + transition.hashCode() + " with transformula " + transition.getTransformula()); @@ -538,21 +567,7 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition // add precondition clauses for (final var instance : getInstances(interferingThread.getTemplateName())) { - final var bodyArgs = clause.getDefaultBodyArgs(mInvariantPredicate); - - // replace thread-specific variables with those for the interfering thread - final var instanceVars = mThreadSpecificVars.get(instance); - final var interferingVars = createThreadSpecificVars(interferingThread); - for (int i = 0; i < instanceVars.size(); ++i) { - final var original = instanceVars.get(i); - if (mInvariantPredicate.hasParameter(original)) { - final var originalTerm = clause.getBodyVar(original).getTerm(); - final var replaced = interferingVars.get(i); - final var replacedTerm = clause.getBodyVar(replaced).getTerm(); - Collections.replaceAll(bodyArgs, originalTerm, replacedTerm); - } - } - + final var bodyArgs = getInterferencePrecondition.apply(clause, instance); clause.addBodyPredicate(mInvariantPredicate, bodyArgs); } @@ -567,6 +582,17 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition return clause; } + protected void replaceThreadVariables(final List parameters, final ThreadInstance oldInstance, + final List newVariables) { + final var oldVariables = mThreadSpecificVars.get(oldInstance); + assert oldVariables.size() == newVariables.size(); + for (int i = 0; i < oldVariables.size(); ++i) { + final var original = oldVariables.get(i); + final var replaced = newVariables.get(i); + Collections.replaceAll(parameters, original, replaced); + } + } + // Auxiliary methods // ----------------------------------------------------------------------------------------------------------------- @@ -578,7 +604,7 @@ protected void addInLocationConstraint(final HornClauseBuilder clause, final Thr final IcfgLocation location) { final var locTerm = location == null ? mBottomLocation : getLocIndexTerm(location, threadInstance.getTemplateName()); - final HcLocationVar locVar = mLocationVars.get(threadInstance); + final HcLocationVar locVar = new HcLocationVar(threadInstance, mScript); final Term term = clause.getBodyVar(locVar).getTerm(); clause.addConstraint(SmtUtils.binaryEquality(mScript, term, locTerm)); } @@ -655,7 +681,7 @@ protected ThreadInstance getInterferingThread(final IIcfgTransition transitio return new ThreadInstance(transition.getPrecedingProcedure(), INTERFERING_INSTANCE_ID); } - private Stream getInterferingLocals(final ThreadInstance interferingThread) { + protected Stream getInterferingLocals(final ThreadInstance interferingThread) { return mCfgSymbolTable.getLocals(interferingThread.getTemplateName()).stream().filter(mVariableFilter) .map(pv -> new HcLocalVar(pv, interferingThread)); } From 6552ec7f69df95e76249b8074b521f74ad810fd7 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 10 May 2023 13:51:01 +0200 Subject: [PATCH 034/114] SleepSetThreadModular w/o symmetry-breaking: simplify code slightly --- .../SleepSetThreadModularHornClauseProvider.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index 81521a16c82..a78ba7da910 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -173,7 +173,8 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition // update sleep variables for (final var instance : mInstances) { - updateSleepNonInterference(clause, transition, interferingId, instance); + final var prefOrder = symbolicPreferenceOrderConstraint(clause, instance, interferingThread); + updateSleep(clause, transition, instance, prefOrder); } return clause; @@ -272,15 +273,6 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra updateSleep(clause, transition, current, prefOrder); } - // update sleep variable depending on commutativity and preference order - private void updateSleepNonInterference(final HornClauseBuilder clause, final IIcfgTransition transition, - final HcThreadIdVar interferingId, final ThreadInstance current) { - // TODO if breaking symmetry, do this statically! - final var prefOrder = symbolicPreferenceOrderConstraint(clause, current, interferingId.getThreadInstance()); - - updateSleep(clause, transition, current, prefOrder); - } - // update sleep variable depending on commutativity and preference order private void updateSleep(final HornClauseBuilder clause, final IIcfgTransition transition, final ThreadInstance current, final Term prefOrder) { From 7e3d4fa0757dc1e12c3c574caa7e46c39cc9d063 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 17 May 2023 17:16:06 +0200 Subject: [PATCH 035/114] fix transition constraints for local variables In non-interference clauses, the interfering thread's local variables may be updated, but do not appear in the head. Hence, use body variables instead of head variables for them. --- .../icfgtochc/concurrent/HornClauseBuilder.java | 4 ++++ .../concurrent/ThreadModularHornClauseProvider.java | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index de1dddc3a84..37b178ddd4b 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -72,6 +72,10 @@ public HornClauseBuilder(final ManagedScript mgdScript, final HcSymbolTable symb this(mgdScript, symbolTable, null, comment); } + public PredicateInfo getHeadPredicate() { + return mHeadPredicate; + } + public HcBodyVar getFreshBodyVar(final Object identifier, final Sort sort) { final HcBodyVar auxVar = mSymbolTable.getOrConstructBodyVar(identifier, sort); mBodyVars.add(auxVar); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index a4df8ed3d55..88ac04b657f 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -42,6 +42,7 @@ import java.util.stream.Stream; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; +import de.uni_freiburg.informatik.ultimate.lib.chc.HcBodyVar; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; @@ -668,8 +669,15 @@ private static void prepareSubstitution(final HornClauseBuilder clause, final Un } final TermVariable outVar = tf.getOutVars().get(pv); + final var dummyOutVars = new HashMap(); if (outVar != null && !Objects.equals(inVar, outVar)) { - substitution.put(outVar, clause.getHeadVar(rv).getTerm()); + final var headPred = clause.getHeadPredicate(); + if (headPred != null && headPred.hasParameter(rv)) { + substitution.put(outVar, clause.getHeadVar(rv).getTerm()); + } else { + final var bodyVar = dummyOutVars.computeIfAbsent(rv, x -> clause.getFreshBodyVar(x, x.getSort())); + substitution.put(outVar, bodyVar.getTerm()); + } } if (canBeUpdated && tf.getAssignedVars().contains(pv)) { From 611e7b951651c1ec494690095038f179f416777b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 17 May 2023 17:38:37 +0200 Subject: [PATCH 036/114] add alternative assert encoding The assertion condition need not be handled as an assume statement. Instead, we can include it as constraint in the error clause. This simplifies the CHC system slightly. The largest benefit is likely for sleep sets, as we do not need to consider commutativity wrt the assume statement. --- ...eepSetThreadModularHornClauseProvider.java | 3 ++ .../ThreadModularHornClauseProvider.java | 49 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java index a78ba7da910..4cfdf27c461 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java @@ -316,6 +316,9 @@ protected Term getCommutativityConstraint(final ThreadInstance instance, final T if (loc.getOutgoingEdges().stream() // ignore spec edges: the original edges are replaced, and the replacing transitions commute .filter(e -> !isPreConditionSpecEdge(e) && !isPostConditionSpecEdge(e)) + // ignore assert edges if option is set + .filter(e -> SKIP_ASSERTION_EDGES + && mIcfg.getProcedureErrorNodes().get(e.getSucceedingProcedure()).contains(e.getTarget())) .allMatch(e -> mIndependence.isIndependent(null, e, currentEdge) == Dependence.INDEPENDENT)) { commLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 88ac04b657f..114c7f1afe7 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -83,6 +83,7 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvider { private static final String FUNCTION_NAME = "Inv"; private static final int INTERFERING_INSTANCE_ID = -1; + protected static final boolean SKIP_ASSERTION_EDGES = true; protected final IUltimateServiceProvider mServices; protected final IIcfg mIcfg; @@ -254,18 +255,29 @@ protected List buildAllClauses() { final var entryNodes = mIcfg.getProcedureEntryNodes(); for (final String proc : mTemplates) { final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); + final var errorNodes = mIcfg.getProcedureErrorNodes().get(proc); while (edges.hasNext()) { final IcfgEdge original = edges.next(); - result.addAll(buildClausesForTransition(original)); + if (!SKIP_ASSERTION_EDGES || !errorNodes.contains(original.getTarget())) { + result.addAll(buildClausesForTransition(original)); + } } } // add safety clauses switch (mPrefs.specMode()) { case ASSERT_VIOLATIONS: - for (final var pair : getErrorLocations()) { - final var safetyClause = buildErrorSafetyClause(pair.getFirst(), pair.getSecond()); - result.add(safetyClause); + if (SKIP_ASSERTION_EDGES) { + for (final var triple : getErrorConditions()) { + final var safetyClause = + buildErrorSafetyClause(triple.getFirst(), triple.getSecond(), triple.getThird()); + result.add(safetyClause); + } + } else { + for (final var pair : getErrorLocations()) { + final var safetyClause = buildErrorSafetyClause(pair.getFirst(), pair.getSecond()); + result.add(safetyClause); + } } break; case POSTCONDITION: @@ -392,6 +404,17 @@ private List> getErrorLocations() { .collect(Collectors.toList()); } + private List> getErrorConditions() { + return mIcfg.getProcedureErrorNodes().entrySet().stream() + .flatMap(e -> e.getValue().stream().map(l -> new Pair<>(e.getKey(), l))) + .flatMap(e -> e.getValue().getIncomingEdges().stream() + .map(t -> new Triple<>(e.getKey(), t.getSource(), t.getTransformula()))) + .flatMap(e -> mInstances.stream().filter(i -> i.getTemplateName().equals(e.getFirst())) + .> map( + i -> new Triple<>(i, e.getSecond(), e.getThird()))) + .collect(Collectors.toList()); + } + // Horn clause generation // ----------------------------------------------------------------------------------------------------------------- @@ -453,6 +476,24 @@ protected HornClauseBuilder buildErrorSafetyClause(final ThreadInstance thread, return clause; } + protected HornClauseBuilder buildErrorSafetyClause(final ThreadInstance thread, final IcfgLocation loc, + final UnmodifiableTransFormula guard) { + // create a clause with head "false" + final var clause = createBuilder("safety clause for location " + loc + " in thread instance " + thread); + + // add body clause + clause.addBodyPredicate(mInvariantPredicate, clause.getDefaultBodyArgs(mInvariantPredicate)); + + // location constraints + addInLocationConstraint(clause, thread, loc); + + // add transition guard + final var locals = mLocalVars.values().collect(Collectors.toList()); + addTransitionConstraint(clause, guard, thread, locals); + + return clause; + } + /** * Builds a safety clause specifying that if a given thread exits, and the numbers of started and exited threads are * equal, the postcondition holds. From 5535543499559d7c41203c8df806b1734da7c555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Sch=C3=BCssele?= Date: Tue, 23 May 2023 14:47:25 +0200 Subject: [PATCH 037/114] Fix NPE --- .../concurrent/ThreadModularHornClauseProvider.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 114c7f1afe7..ba931ad6fc3 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -254,8 +254,11 @@ protected List buildAllClauses() { final var entryNodes = mIcfg.getProcedureEntryNodes(); for (final String proc : mTemplates) { - final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); final var errorNodes = mIcfg.getProcedureErrorNodes().get(proc); + if (errorNodes == null) { + continue; + } + final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); while (edges.hasNext()) { final IcfgEdge original = edges.next(); if (!SKIP_ASSERTION_EDGES || !errorNodes.contains(original.getTarget())) { From 35689196a40e082a59703d1434e9afb326a5e217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Sch=C3=BCssele?= Date: Tue, 23 May 2023 15:49:59 +0200 Subject: [PATCH 038/114] Fix NPE properly --- .../concurrent/ThreadModularHornClauseProvider.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index ba931ad6fc3..2597542c723 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -254,14 +254,11 @@ protected List buildAllClauses() { final var entryNodes = mIcfg.getProcedureEntryNodes(); for (final String proc : mTemplates) { - final var errorNodes = mIcfg.getProcedureErrorNodes().get(proc); - if (errorNodes == null) { - continue; - } final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); + final var errorNodes = mIcfg.getProcedureErrorNodes().get(proc); while (edges.hasNext()) { final IcfgEdge original = edges.next(); - if (!SKIP_ASSERTION_EDGES || !errorNodes.contains(original.getTarget())) { + if (!SKIP_ASSERTION_EDGES || errorNodes == null || !errorNodes.contains(original.getTarget())) { result.addAll(buildClausesForTransition(original)); } } From 0e06dcb955370d5e5fcc9d366af6f1bd14c5ccde Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 24 May 2023 11:02:21 +0200 Subject: [PATCH 039/114] add some comments --- .../icfgtochc/concurrent/ThreadModularHornClauseProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 2597542c723..3f89525124e 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -249,9 +249,11 @@ protected List createThreadSpecificVars(final ThreadInstan protected List buildAllClauses() { final var result = new ArrayList(); + // add initial clause final var initialClause = buildInitialClause(); result.add(initialClause); + // add inductivity and non-interference clauses final var entryNodes = mIcfg.getProcedureEntryNodes(); for (final String proc : mTemplates) { final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); From 71759d31a682c9d89332c80717889a4df34fdd59 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 24 May 2023 11:04:25 +0200 Subject: [PATCH 040/114] create new package for POR-related classes --- .../ultimate/plugins/icfgtochc/IcfgToChcObserver.java | 2 +- .../icfgtochc/concurrent/{ => partialorder}/HcSleepVar.java | 5 ++++- .../concurrent/{ => partialorder}/HcThreadIdVar.java | 4 +++- .../SleepSetThreadModularHornClauseProvider.java | 6 +++++- 4 files changed, 13 insertions(+), 4 deletions(-) rename trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/{ => partialorder}/HcSleepVar.java (91%) rename trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/{ => partialorder}/HcThreadIdVar.java (93%) rename trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/{ => partialorder}/SleepSetThreadModularHornClauseProvider.java (97%) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index fb54afea2a6..38ad95514cc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -51,8 +51,8 @@ import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.SleepSetThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.SleepSetThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; /** diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java similarity index 91% rename from trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java rename to trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java index 1dbebc8f9ea..a972390d35d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java @@ -24,7 +24,7 @@ * licensors of the ULTIMATE IcfgToChc plug-in grant you additional permission * to convey the resulting work. */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; import java.util.Objects; import java.util.Set; @@ -34,6 +34,9 @@ import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcFiniteReplacementVar; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcThreadSpecificVar; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; public class HcSleepVar implements IHcThreadSpecificVar, IHcFiniteReplacementVar { private final Sort mSort; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java similarity index 93% rename from trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java rename to trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java index b00defe0ae3..4fe250bfcca 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadIdVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java @@ -24,13 +24,15 @@ * licensors of the ULTIMATE IcfgToChc plug-in grant you additional permission * to convey the resulting work. */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; import java.util.Objects; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcThreadSpecificVar; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; public class HcThreadIdVar implements IHcThreadSpecificVar { private final Sort mSort; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java similarity index 97% rename from trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java rename to trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 4cfdf27c461..64f614e79f2 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -24,7 +24,7 @@ * licensors of the ULTIMATE IcfgToChc plug-in grant you additional permission * to convey the resulting work. */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; import java.util.ArrayList; import java.util.Collection; @@ -47,6 +47,10 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcThreadSpecificVar; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; From bb523551a439bb9b6adeff55d4bc268895684d08 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 24 May 2023 19:12:38 +0200 Subject: [PATCH 041/114] add auxiliary method for skippable asserts --- .../ThreadModularHornClauseProvider.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 3f89525124e..302714f70f8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -257,10 +257,9 @@ protected List buildAllClauses() { final var entryNodes = mIcfg.getProcedureEntryNodes(); for (final String proc : mTemplates) { final IcfgEdgeIterator edges = new IcfgEdgeIterator(entryNodes.get(proc).getOutgoingEdges()); - final var errorNodes = mIcfg.getProcedureErrorNodes().get(proc); while (edges.hasNext()) { final IcfgEdge original = edges.next(); - if (!SKIP_ASSERTION_EDGES || errorNodes == null || !errorNodes.contains(original.getTarget())) { + if (!isSkippableAssertEdge(original)) { result.addAll(buildClausesForTransition(original)); } } @@ -370,6 +369,17 @@ protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { return edge.getTarget().equals(exitLoc); } + protected boolean isSkippableAssertEdge(final IcfgEdge edge) { + if (!SKIP_ASSERTION_EDGES) { + return false; + } + final var errorLocs = mIcfg.getProcedureErrorNodes().get(edge.getSucceedingProcedure()); + if (errorLocs == null) { + return false; + } + return errorLocs.contains(edge.getTarget()); + } + private List, Map, ThreadInstance>> getCartesianPrePostProduct(final IcfgEdge edge) { if (edge instanceof IIcfgForkTransitionThreadCurrent) { From 07ae11c7d39a3eb798c950c3a774e5429d64adaa Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 24 May 2023 19:16:03 +0200 Subject: [PATCH 042/114] fix handling of local variables Previously, local variables could be read from the wrong thread. This lead to an unsound encoding. We now only allow reading from and writing to local variables of the current thread. --- .../concurrent/ThreadModularHornClauseProvider.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 302714f70f8..0066c60b038 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -693,13 +693,15 @@ protected void addTransitionConstraint(final HornClauseBuilder clause, final Unm // deal with global variables for (final var global : mGlobalVars) { - prepareSubstitution(clause, tf, substitution, global, global.getVariable(), true); + prepareSubstitution(clause, tf, substitution, global, global.getVariable()); } // deal with local variables for (final HcLocalVar local : localVariables) { final var updatable = local.getThreadInstance().equals(updatedThread); - prepareSubstitution(clause, tf, substitution, local, local.getVariable(), updatable); + if (updatable) { + prepareSubstitution(clause, tf, substitution, local, local.getVariable()); + } } // replace all other variables with auxiliary variables @@ -714,8 +716,7 @@ protected void addTransitionConstraint(final HornClauseBuilder clause, final Unm } private static void prepareSubstitution(final HornClauseBuilder clause, final UnmodifiableTransFormula tf, - final Map substitution, final IHcReplacementVar rv, final IProgramVar pv, - final boolean canBeUpdated) { + final Map substitution, final IHcReplacementVar rv, final IProgramVar pv) { final TermVariable inVar = tf.getInVars().get(pv); if (inVar != null) { substitution.put(inVar, clause.getBodyVar(rv).getTerm()); @@ -733,7 +734,7 @@ private static void prepareSubstitution(final HornClauseBuilder clause, final Un } } - if (canBeUpdated && tf.getAssignedVars().contains(pv)) { + if (tf.getAssignedVars().contains(pv)) { clause.differentBodyHeadVar(rv); } } From 352794a64b7915282ebaf2ced70cb076b68e4020 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 11:29:26 +0200 Subject: [PATCH 043/114] readable toString for dummy edges (to help debugging) --- .../concurrent/ThreadModularHornClauseProvider.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 0066c60b038..3c8286412b7 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -330,6 +330,11 @@ protected IcfgEdge createDummyEdge(final IcfgEdge original) { public UnmodifiableTransFormula getTransformula() { return tf; } + + @Override + public String toString() { + return "<[ dummy edge: assume true; ]>"; + } }; } From 6a47de5a6c1d098a002c44f86452cd08a5067d65 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 11:31:08 +0200 Subject: [PATCH 044/114] SemanticIndependenceConditionGenerator: also output raw terms --- ...emanticIndependenceConditionGenerator.java | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java b/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java index c7894ba8bdf..8db2c3cfa51 100644 --- a/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java +++ b/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java @@ -104,6 +104,20 @@ public IPredicate generateCondition(final UnmodifiableTransFormula a, final Unmo return generateCondition(null, a, b); } + /** + * Generate a condition under which the given transitions are independent. + * + * @param a + * The first transition + * @param b + * The second transition + * + * @return a sufficient condition for independence + */ + public Term generateConditionTerm(final UnmodifiableTransFormula a, final UnmodifiableTransFormula b) { + return generateConditionTerm(null, a, b); + } + /** * Generate a condition under which the given transitions are independent. * @@ -118,6 +132,23 @@ public IPredicate generateCondition(final UnmodifiableTransFormula a, final Unmo */ public IPredicate generateCondition(final IPredicate context, final UnmodifiableTransFormula a, final UnmodifiableTransFormula b) { + return mFactory.newPredicate(generateConditionTerm(context, a, b)); + } + + /** + * Generate a condition term under which the given transitions are independent. + * + * @param context + * A context that is already known, but not sufficient for commutativity + * @param a + * The first transition + * @param b + * The second transition + * + * @return a sufficient condition for independence + */ + public Term generateConditionTerm(final IPredicate context, final UnmodifiableTransFormula a, + final UnmodifiableTransFormula b) { // Generate both compositions, possibly adding a guard where applicable final UnmodifiableTransFormula ab = withGuard(context, compose(a, b)); final UnmodifiableTransFormula ba = withGuard(mSymmetric ? context : null, compose(b, a)); @@ -146,10 +177,7 @@ public IPredicate generateCondition(final IPredicate context, final Unmodifiable assert !substitution.containsKey(entry.getValue()); substitution.put(entry.getValue(), entry.getKey().getTermVariable()); } - final Term restoredCondition = Substitution.apply(mMgdScript, substitution, condition); - - // Create a predicate - return mFactory.newPredicate(restoredCondition); + return Substitution.apply(mMgdScript, substitution, condition); } private final UnmodifiableTransFormula compose(final UnmodifiableTransFormula first, From 6c221206817f274df548f4f4b5271e2f32316f51 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 11:31:30 +0200 Subject: [PATCH 045/114] add SemanticIndependenceConditionGenerator::isSymmetric --- .../independence/SemanticIndependenceConditionGenerator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java b/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java index 8db2c3cfa51..a31e438bb94 100644 --- a/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java +++ b/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java @@ -90,6 +90,10 @@ public SemanticIndependenceConditionGenerator(final IUltimateServiceProvider ser mSymmetric = symmetric; } + public boolean isSymmetric() { + return mSymmetric; + } + /** * Generate a condition under which the given transitions are independent. * From 81cfd059fe36ef82eac1d6839de7777071702bbf Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 11:32:30 +0200 Subject: [PATCH 046/114] HcSymbolTable: add missing mapping of head variables --- .../uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java | 1 + 1 file changed, 1 insertion(+) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java index 015fb827bfe..a44155b43d1 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java @@ -299,6 +299,7 @@ public HcHeadVar getOrConstructHeadVar(final Object identifier, final Sort sort) final var result = new HcHeadVar(globallyUniqueId, DUMMY_PRED_NAME, DUMMY_PRED_INDEX, transferredSort, mManagedScript, this); mManagedScript.unlock(this); + mTermVarToProgramVar.put(result.getTermVariable(), result); return result; }); } From f838715ba95c4ef8deba7213ac5f62e839087bc5 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 11:48:41 +0200 Subject: [PATCH 047/114] add support for conditional independence (with precomputed commutativity conditions) --- .../plugins/icfgtochc/IcfgToChcObserver.java | 25 ++- .../ThreadModularHornClauseProvider.java | 6 +- ...itionSynthesizingIndependenceRelation.java | 86 ++++++++++ .../ExplicitSymbolicIndependenceRelation.java | 67 ++++++++ .../ISymbolicIndependenceRelation.java | 53 ++++++ .../partialorder/IndependenceChecker.java | 161 ++++++++++++++++++ ...eepSetThreadModularHornClauseProvider.java | 117 ++++++++----- .../IcfgToChcPreferenceInitializer.java | 11 +- .../preferences/IcfgToChcPreferences.java | 6 + 9 files changed, 485 insertions(+), 47 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 38ad95514cc..7374e9ded73 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -40,18 +40,24 @@ import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClauseAST; 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.IIcfgSummaryTransition; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.BasicPredicateFactory; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ConditionSynthesizingIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ExplicitSymbolicIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ISymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.SleepSetThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; @@ -176,7 +182,7 @@ private Collection getHornClauses(IIcfg icfg, final Ma } if (mPrefs.useSleepSets()) { - final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, true); + final var independence = getIndependence(icfg, mgdScript); return new SleepSetThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, independence, mPrefs).getClauses(); } @@ -184,4 +190,21 @@ private Collection getHornClauses(IIcfg icfg, final Ma } return new ChcProviderForCalls(mgdScript, hcSymbolTable).getHornClauses(icfg); } + + private ISymbolicIndependenceRelation getIndependence(final IIcfg icfg, final ManagedScript mgdScript) { + final boolean symmetric = true; + final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, symmetric); + + switch (mPrefs.conditionalIndependence()) { + case OFF: + return new ExplicitSymbolicIndependenceRelation<>(independence, mgdScript.getScript()); + case PRECOMPUTED_CONDITIONS: + final var factory = + new BasicPredicateFactory(mServices, mgdScript, icfg.getCfgSmtToolkit().getSymbolTable()); + final var generator = new SemanticIndependenceConditionGenerator(mServices, mgdScript, factory, symmetric); + return new ConditionSynthesizingIndependenceRelation<>(independence, generator, mgdScript.getScript()); + } + + throw new AssertionError("Unknown conditional independence setting: " + mPrefs.conditionalIndependence()); + } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 3c8286412b7..4face7f1fc8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -564,7 +564,7 @@ protected HornClauseBuilder buildPostconditionSafetyClause(final ThreadInstance * @param updatedThread * The primary active thread, whose local variables are updated by the transition. */ - protected HornClauseBuilder buildInductivityClause(final IIcfgTransition transition, + protected HornClauseBuilder buildInductivityClause(final IcfgEdge transition, final Map preds, final Map succs, final ThreadInstance updatedThread) { final var clause = createBuilder(mInvariantPredicate, @@ -592,7 +592,7 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran return clause; } - protected List buildNonInterferenceClauses(final IIcfgTransition transition) { + protected List buildNonInterferenceClauses(final IcfgEdge transition) { final var result = new ArrayList(); result.add(buildNonInterferenceClause(transition)); return result; @@ -601,7 +601,7 @@ protected List buildNonInterferenceClauses(final IIcfgTransit /** * Builds a noninterference clause for the given transition. */ - protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { + protected HornClauseBuilder buildNonInterferenceClause(final IcfgEdge transition) { // TODO support transitions with multiple predecessors (joins) final var interferingThread = getInterferingThread(transition); final var interferingVars = createThreadSpecificVars(interferingThread); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java new file mode 100644 index 00000000000..4b83b376685 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IAction; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +/** + * An {@link ISymbolicIndependenceRelation} that uses a {@link SemanticIndependenceConditionGenerator} to find a + * sufficient condition for commutativity. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + * @param + */ +public class ConditionSynthesizingIndependenceRelation implements ISymbolicIndependenceRelation { + + private final SemanticIndependenceRelation mExplicitIndependence; + private final SemanticIndependenceConditionGenerator mGenerator; + private final Script mScript; + + public ConditionSynthesizingIndependenceRelation(final SemanticIndependenceRelation explicitIndependence, + final SemanticIndependenceConditionGenerator generator, final Script script) { + mExplicitIndependence = explicitIndependence; + mGenerator = generator; + mScript = script; + + assert mExplicitIndependence.isSymmetric() == mGenerator + .isSymmetric() : "Independence relation and condition generator should both be symmetric, or neither."; + } + + @Override + public Term getIndependenceCondition(final L a, final L b) { + final var dependence = mExplicitIndependence.isIndependent(null, a, b); + switch (dependence) { + case INDEPENDENT: + // Statements always commute, no condition is needed. + return mScript.term(SMTLIBConstants.TRUE); + case UNKNOWN: + // Commutativity condition synthesis probably won't succeed. + return mScript.term(SMTLIBConstants.FALSE); + case DEPENDENT: + final var condition = mGenerator.generateConditionTerm(a.getTransformula(), b.getTransformula()); + if (condition == null) { + // No commutativity condition could be synthesized. + return mScript.term(SMTLIBConstants.FALSE); + } + return condition; + default: + throw new AssertionError("Unknown dependency value: " + dependence); + } + } + + @Override + public boolean isSymmetric() { + return mExplicitIndependence.isSymmetric(); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java new file mode 100644 index 00000000000..3d83a463194 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IAction; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +/** + * Implements {@link ISymbolicIndependenceRelation} by explicitly checking independence and returning either the term + * {@code true} or the term {@code false}. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + * @param + * The type of letters checked for independence + */ +public class ExplicitSymbolicIndependenceRelation implements ISymbolicIndependenceRelation { + private final IIndependenceRelation mUnderlying; + private final Script mScript; + + public ExplicitSymbolicIndependenceRelation(final IIndependenceRelation underlying, final Script script) { + mUnderlying = underlying; + mScript = script; + } + + @Override + public Term getIndependenceCondition(final L a, final L b) { + final var dependence = mUnderlying.isIndependent(null, a, b); + if (dependence == Dependence.INDEPENDENT) { + return mScript.term(SMTLIBConstants.TRUE); + } + return mScript.term(SMTLIBConstants.FALSE); + } + + @Override + public boolean isSymmetric() { + return mUnderlying.isSymmetric(); + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java new file mode 100644 index 00000000000..a9c1ece0144 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +/** + * Represents an independence (or "commutativity" relation). In spirit, this interface is similar to + * {@link IIndependenceRelation}, but instead of explicitly checking independence, it returns a symbolic condition (a + * boolean {@link Term}) such that, if the term evaluates to {@code true}, then the given letters are independent. + * + * Symbolic independence relations are inherently conditional: The returned {@link Term} is a formula over program + * variables that implies commutativity. However, symbolic independence relations currently do not support passing in a + * known context. + * + * Similar to {@link IIndependenceRelation}s, symbolic independence relations can be symmetric (i.e., describe a + * commutativity relation) or not (i.e., describe a semi-commutativity relation). + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + * @param + * The type of actions checked for independence + */ +public interface ISymbolicIndependenceRelation { + Term getIndependenceCondition(L a, L b); + + boolean isSymmetric(); +} \ No newline at end of file diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java new file mode 100644 index 00000000000..357be9b691b --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +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.IIcfgSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeFactory; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaBuilder; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramVarUtils; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.Substitution; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.logic.TermVariable; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcLocalVar; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; +import de.uni_freiburg.informatik.ultimate.util.datastructures.SerialProvider; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; + +/** + * Utility class that performs independence checks for {@link SleepSetThreadModularHornClauseProvider}. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + */ +class IndependenceChecker { + private final ILogger mLogger; + private final ManagedScript mMgdScript; + private final IIcfgSymbolTable mSymbolTable; + private final ISymbolicIndependenceRelation mIndependence; + private final IcfgEdgeFactory mEdgeFactory; + + private final Map, Term> mCache = new HashMap<>(); + + private final Map mLeftSubstitution; + private final Map mRightSubstitution; + + public IndependenceChecker(final IUltimateServiceProvider services, final CfgSmtToolkit csToolkit, + final ISymbolicIndependenceRelation independence) { + mLogger = services.getLoggingService().getLogger(getClass()); + mMgdScript = csToolkit.getManagedScript(); + mSymbolTable = csToolkit.getSymbolTable(); + mIndependence = independence; + mEdgeFactory = new IcfgEdgeFactory(new SerialProvider()); + + final var localVars = collectLocalVariables(csToolkit); + mLeftSubstitution = createVariableMapping("~~left~~", localVars); + mRightSubstitution = createVariableMapping("~~right~~", localVars); + } + + public Term getIndependenceCondition(final HornClauseBuilder clause, final ThreadInstance thread1, + final IcfgEdge action1, final ThreadInstance thread2, final IcfgEdge action2) { + // first check the cache + final var cached = mCache.get(new Pair<>(action1, action2)); + if (cached != null) { + return deinstantiate(clause, thread1, thread2, cached); + } + + // for symmetric relations, check the cache for the symmetric case as well + if (mIndependence.isSymmetric()) { + final var symCached = mCache.get(new Pair<>(action2, action1)); + if (symCached != null) { + // This needs a different deinstantiation than the cases above and below. + return deinstantiate(clause, thread2, thread1, symCached); + } + } + + final var instantiated = getInstantiatedIndependenceCondition(action1, action2); + return deinstantiate(clause, thread1, thread2, instantiated); + } + + private Term getInstantiatedIndependenceCondition(final IcfgEdge action1, final IcfgEdge action2) { + // compute the independence condition + final var inst1 = instantiate(action1, mLeftSubstitution); + final var inst2 = instantiate(action2, mRightSubstitution); + final var condition = mIndependence.getIndependenceCondition(inst1, inst2); + mLogger.info( + "instantiated independence condition for '" + action1 + "' and '" + action2 + "' is: " + condition); + + // cache the condition for future queries + mCache.put(new Pair<>(action1, action2), condition); + + return condition; + } + + private IcfgEdge instantiate(final IcfgEdge edge, final Map mapping) { + final var tf = edge.getTransformula(); + final var copyTf = TransFormulaBuilder.constructCopy(mMgdScript, tf, mapping); + return mEdgeFactory.createInternalTransition(edge.getSource(), edge.getTarget(), null, copyTf); + } + + private Term deinstantiate(final HornClauseBuilder clause, final ThreadInstance thread1, + final ThreadInstance thread2, final Term term) { + final var backSubstitution = new HashMap(); + addBackSubstitutionMappings(clause, mLeftSubstitution, backSubstitution, thread1); + addBackSubstitutionMappings(clause, mRightSubstitution, backSubstitution, thread2); + return Substitution.apply(mMgdScript, backSubstitution, term); + } + + private void addBackSubstitutionMappings(final HornClauseBuilder clause, + final Map substitution, final Map backSubstitution, + final ThreadInstance thread) { + for (final var local : mSymbolTable.getLocals(thread.getTemplateName())) { + final var hcVar = new HcLocalVar(local, thread); + final var bodyVar = clause.getBodyVar(hcVar); + final var instVar = substitution.get(local); + backSubstitution.put(instVar.getTermVariable(), bodyVar.getTermVariable()); + } + } + + private static Set collectLocalVariables(final CfgSmtToolkit csToolkit) { + final var symbolTable = csToolkit.getSymbolTable(); + return csToolkit.getProcedures().stream().flatMap(p -> symbolTable.getLocals(p).stream()) + .collect(Collectors.toSet()); + } + + private Map createVariableMapping(final String prefix, + final Set localVars) { + final var result = new HashMap(); + for (final var variable : localVars) { + final var identifier = prefix + variable.getIdentifier(); + final var copy = ProgramVarUtils.constructLocalProgramVar(identifier, variable.getProcedure(), + variable.getSort(), mMgdScript, null); + result.put(variable, copy); + } + return result; + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 64f614e79f2..e4b39039803 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -36,12 +35,11 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; 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.IcfgEdge; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; @@ -55,7 +53,7 @@ import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornClauseProvider { - private final IIndependenceRelation> mIndependence; + private final IndependenceChecker mIndependenceChecker; private final Map> mThreadLocations; private final Map mIdVars; @@ -63,9 +61,10 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornCl public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider services, final ManagedScript mgdScript, final IIcfg icfg, final HcSymbolTable symbolTable, - final IIndependenceRelation> independence, final IcfgToChcPreferences prefs) { + final ISymbolicIndependenceRelation> independence, + final IcfgToChcPreferences prefs) { super(services, mgdScript, icfg, symbolTable, prefs); - mIndependence = independence; + mIndependenceChecker = new IndependenceChecker(services, icfg.getCfgSmtToolkit(), independence); mThreadLocations = icfg.getProgramPoints().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); @@ -118,7 +117,7 @@ protected HornClauseBuilder buildInitialClause() { } @Override - protected HornClauseBuilder buildInductivityClause(final IIcfgTransition transition, + protected HornClauseBuilder buildInductivityClause(final IcfgEdge transition, final Map preds, final Map succs, final ThreadInstance updatedThread) { final var clause = super.buildInductivityClause(transition, preds, succs, updatedThread); @@ -138,7 +137,7 @@ protected HornClauseBuilder buildInductivityClause(final IIcfgTransition tran } @Override - protected List buildNonInterferenceClauses(final IIcfgTransition transition) { + protected List buildNonInterferenceClauses(final IcfgEdge transition) { if (!mPrefs.breakPreferenceOrderSymmetry()) { return super.buildNonInterferenceClauses(transition); } @@ -154,7 +153,7 @@ protected List buildNonInterferenceClauses(final IIcfgTransit // This overload constructs non-interference clauses where the preference order is treated symbolically. @Override - protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition) { + protected HornClauseBuilder buildNonInterferenceClause(final IcfgEdge transition) { if (mPrefs.breakPreferenceOrderSymmetry()) { throw new UnsupportedOperationException("This method does not support breaking preference order symmetry. " + "Call the other overload of this method instead."); @@ -176,9 +175,9 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); // update sleep variables - for (final var instance : mInstances) { - final var prefOrder = symbolicPreferenceOrderConstraint(clause, instance, interferingThread); - updateSleep(clause, transition, instance, prefOrder); + for (final var sleepingThread : mInstances) { + final var prefOrder = symbolicPreferenceOrderConstraint(clause, sleepingThread, interferingThread); + updateSleep(clause, interferingThread, transition, sleepingThread, prefOrder); } return clause; @@ -186,7 +185,7 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition // This overload constructs non-interference clauses where preference order symmetry is broken, and the preference // order is resolved statically. - protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition transition, final int index) { + protected HornClauseBuilder buildNonInterferenceClause(final IcfgEdge transition, final int index) { if (!mPrefs.breakPreferenceOrderSymmetry()) { throw new UnsupportedOperationException("This method breaks preference order symmetry, which is turned off." + " Call the other overload of this method instead."); @@ -232,10 +231,10 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition clause.addConstraint(SmtUtils.not(mScript, clause.getBodyVar(sleep).getTerm())); // update sleep variables - for (final var instance : mInstances) { - final var prefOrder = index < instance.getInstanceNumber() ? mScript.term(SMTLIBConstants.FALSE) + for (final var sleepingThread : mInstances) { + final var prefOrder = index < sleepingThread.getInstanceNumber() ? mScript.term(SMTLIBConstants.FALSE) : mScript.term(SMTLIBConstants.TRUE); - updateSleep(clause, transition, instance, prefOrder); + updateSleep(clause, interferingThread, transition, sleepingThread, prefOrder); } return clause; @@ -254,10 +253,10 @@ private void ensureUniqueThreadIDs(final HornClauseBuilder clause) { } // update sleep variable depending on commutativity and preference order - private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTransition transition, + private void updateSleepInductive(final HornClauseBuilder clause, final IcfgEdge transition, final Set activeThreads, final ThreadInstance primaryActiveThread, - final ThreadInstance current) { - if (activeThreads.contains(current)) { + final ThreadInstance updatedThread) { + if (activeThreads.contains(updatedThread)) { // no update of sleep variable return; } @@ -266,21 +265,22 @@ private void updateSleepInductive(final HornClauseBuilder clause, final IIcfgTra if (mPrefs.breakPreferenceOrderSymmetry()) { // We resolve the preference order statically. // For now, the preference order is non-positional, and given by the ordering in mInstances. - final int ordering = Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(current)); + final int ordering = + Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(updatedThread)); // Formula expressing whether current thread is BEFORE primary thread. prefOrder = ordering < 0 ? mScript.term(SMTLIBConstants.FALSE) : mScript.term(SMTLIBConstants.TRUE); } else { // We resolve the preference order symbolically, using ID variables. - prefOrder = symbolicPreferenceOrderConstraint(clause, current, primaryActiveThread); + prefOrder = symbolicPreferenceOrderConstraint(clause, updatedThread, primaryActiveThread); } - updateSleep(clause, transition, current, prefOrder); + updateSleep(clause, primaryActiveThread, transition, updatedThread, prefOrder); } // update sleep variable depending on commutativity and preference order - private void updateSleep(final HornClauseBuilder clause, final IIcfgTransition transition, - final ThreadInstance current, final Term prefOrder) { - final var sleep = mSleepVars.get(current); + private void updateSleep(final HornClauseBuilder clause, final ThreadInstance activeThread, + final IcfgEdge activeEdge, final ThreadInstance updatedThread, final Term prefOrder) { + final var sleep = mSleepVars.get(updatedThread); clause.differentBodyHeadVar(sleep); final var oldSleep = clause.getBodyVar(sleep); @@ -297,8 +297,9 @@ private void updateSleep(final HornClauseBuilder clause, final IIcfgTransition currentEdge) { - final var commLocations = new HashSet(); - for (final var loc : mThreadLocations.get(instance.getTemplateName())) { - // TODO can be optimized: if (= locVar loc) is false, don't check independence - if (loc.getOutgoingEdges().stream() - // ignore spec edges: the original edges are replaced, and the replacing transitions commute - .filter(e -> !isPreConditionSpecEdge(e) && !isPostConditionSpecEdge(e)) - // ignore assert edges if option is set - .filter(e -> SKIP_ASSERTION_EDGES - && mIcfg.getProcedureErrorNodes().get(e.getSucceedingProcedure()).contains(e.getTarget())) - .allMatch(e -> mIndependence.isIndependent(null, e, currentEdge) == Dependence.INDEPENDENT)) { - commLocations.add(getLocIndexTerm(loc, instance.getTemplateName())); + protected Term getCommutativityConstraint(final HornClauseBuilder clause, final ThreadInstance activeThread, + final IcfgEdge activeEdge, final ThreadInstance otherThread, final Term otherLocVar) { + final var disjuncts = new ArrayList(); + for (final var loc : mThreadLocations.get(otherThread.getTemplateName())) { + final var locEquality = + SmtUtils.binaryEquality(mScript, otherLocVar, getLocIndexTerm(loc, otherThread.getTemplateName())); + if (SmtUtils.isFalseLiteral(locEquality)) { + continue; + } + + final var commConstraint = getCommutativityConstraint(clause, activeThread, activeEdge, otherThread, loc); + if (SmtUtils.isFalseLiteral(commConstraint)) { + continue; + } + + final var disjunct = SmtUtils.and(mScript, locEquality, commConstraint); + if (SmtUtils.isTrueLiteral(disjunct)) { + // escape early if commutativity is guaranteed + return mScript.term(SMTLIBConstants.TRUE); + } + + disjuncts.add(disjunct); + } + return SmtUtils.or(mScript, disjuncts); + } + + protected Term getCommutativityConstraint(final HornClauseBuilder clause, final ThreadInstance activeThread, + final IcfgEdge activeEdge, final ThreadInstance otherThread, final IcfgLocation otherLoc) { + final var conjuncts = new ArrayList(); + for (final var edge : otherLoc.getOutgoingEdges()) { + if (isPreConditionSpecEdge(edge) || isPostConditionSpecEdge(edge)) { + // ignore spec edges: the original edges are replaced, and the replacing edges commute with everything + continue; + } + + if (isSkippableAssertEdge(edge)) { + // ignore assert edges if option is set + continue; + } + + final var conjunct = + mIndependenceChecker.getIndependenceCondition(clause, otherThread, edge, activeThread, activeEdge); + if (SmtUtils.isFalseLiteral(conjunct)) { + // escape early if one outgoing edge does not commute under any circumstances + return mScript.term(SMTLIBConstants.FALSE); } + conjuncts.add(conjunct); } - return SmtUtils.or(mScript, commLocations.stream().map(loc -> SmtUtils.binaryEquality(mScript, locVar, loc)) - .collect(Collectors.toList())); + return SmtUtils.and(mScript, conjuncts); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index d5f0e03855d..16fca7afe80 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -89,6 +89,13 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "or explicitly (by using different predicate symbols)."; public static final boolean DEF_EXPLICIT_SLEEP = false; + public static final String LABEL_CONDITIONAL_INDEPENDENCE = "Conditional Independence"; + public static final ConditionalIndependence DEF_CONDITIONAL_INDEPENDENCE = ConditionalIndependence.OFF; + + public enum ConditionalIndependence { + OFF, PRECOMPUTED_CONDITIONS + } + /** * Default constructor. */ @@ -117,7 +124,9 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DEF_BREAK_PREFORDER_SYMMETRY, DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, - PreferenceType.Boolean) }; + PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_CONDITIONAL_INDEPENDENCE, DEF_CONDITIONAL_INDEPENDENCE, + PreferenceType.Combo, ConditionalIndependence.values()) }; } public static IPreferenceProvider getPreferenceProvider(final IUltimateServiceProvider services) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 875371e0022..3289b5b6399 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -28,6 +28,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer.ConditionalIndependence; public class IcfgToChcPreferences { private final IPreferenceProvider mPrefs; @@ -75,4 +76,9 @@ public boolean breakPreferenceOrderSymmetry() { public boolean explicitSleep() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_SLEEP); } + + public ConditionalIndependence conditionalIndependence() { + return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_CONDITIONAL_INDEPENDENCE, + ConditionalIndependence.class); + } } From e388a02a65289251b401fde028ceb6dd639bcd8b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 12:01:07 +0200 Subject: [PATCH 048/114] minor preference cleanup: put sleep set settings in container --- .../IcfgToChcPreferenceInitializer.java | 30 ++++++++++++------- .../preferences/UltimatePreferenceItem.java | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 16fca7afe80..c47456a2e1e 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -28,9 +28,11 @@ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences; import de.uni_freiburg.informatik.ultimate.core.lib.preferences.UltimatePreferenceInitializer; +import de.uni_freiburg.informatik.ultimate.core.model.preferences.BaseUltimatePreferenceItem; import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; import de.uni_freiburg.informatik.ultimate.core.model.preferences.PreferenceType; import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItem; +import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItemContainer; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; @@ -104,8 +106,9 @@ public IcfgToChcPreferenceInitializer() { } @Override - protected UltimatePreferenceItem[] initDefaultPreferences() { - return new UltimatePreferenceItem[] { + protected BaseUltimatePreferenceItem[] initDefaultPreferences() { + + return new BaseUltimatePreferenceItem[] { // Settings for thread-modular proofs new UltimatePreferenceItem<>(LABEL_CONCURRENCY_MODE, DEF_CONCURRENCY_MODE, DESC_CONCURRENCY_MODE, PreferenceType.Combo, ConcurrencyMode.values()), @@ -119,14 +122,21 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, PreferenceType.Boolean), - new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, - DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean), - new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DEF_BREAK_PREFORDER_SYMMETRY, - DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean), - new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, - PreferenceType.Boolean), - new UltimatePreferenceItem<>(LABEL_CONDITIONAL_INDEPENDENCE, DEF_CONDITIONAL_INDEPENDENCE, - PreferenceType.Combo, ConditionalIndependence.values()) }; + + getSleepSetSettings() }; + } + + private UltimatePreferenceItemContainer getSleepSetSettings() { + final var container = new UltimatePreferenceItemContainer("Sleep Set Reduction"); + container.addItem(new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, + DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean)); + container.addItem(new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DEF_BREAK_PREFORDER_SYMMETRY, + DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean)); + container.addItem(new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, + PreferenceType.Boolean)); + container.addItem(new UltimatePreferenceItem<>(LABEL_CONDITIONAL_INDEPENDENCE, DEF_CONDITIONAL_INDEPENDENCE, + PreferenceType.Combo, ConditionalIndependence.values())); + return container; } public static IPreferenceProvider getPreferenceProvider(final IUltimateServiceProvider services) { diff --git a/trunk/source/Library-UltimateModel/src/de/uni_freiburg/informatik/ultimate/core/model/preferences/UltimatePreferenceItem.java b/trunk/source/Library-UltimateModel/src/de/uni_freiburg/informatik/ultimate/core/model/preferences/UltimatePreferenceItem.java index 69c322d6062..52bdb5959ad 100644 --- a/trunk/source/Library-UltimateModel/src/de/uni_freiburg/informatik/ultimate/core/model/preferences/UltimatePreferenceItem.java +++ b/trunk/source/Library-UltimateModel/src/de/uni_freiburg/informatik/ultimate/core/model/preferences/UltimatePreferenceItem.java @@ -32,7 +32,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.IController; /** - * An UltimatePReferenceItem describes exactly one setting of a preference. Based on its {@link PreferenceType}, the + * An UltimatePreferenceItem describes exactly one setting of a preference. Based on its {@link PreferenceType}, the * active {@link IController} will present it to users for modification. * * @author Daniel Dietsch (dietsch@informatik.uni-freiburg.de) From ef5fd2516eeb0ed95aee49c1e0ea5b344ed6a661 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 13:17:30 +0200 Subject: [PATCH 049/114] move CHC categorization to its own class --- .../plugins/icfgtochc/IcfgToChcObserver.java | 56 +---------- .../ultimate/lib/chc/ChcCategorizer.java | 95 +++++++++++++++++++ .../treeautomizer/TreeAutomizerChcScript.java | 5 +- 3 files changed, 103 insertions(+), 53 deletions(-) create mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcCategorizer.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 7374e9ded73..1b999b311bd 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -34,7 +34,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.models.ModelUtils; 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.chc.ChcCategoryInfo; +import de.uni_freiburg.informatik.ultimate.lib.chc.ChcCategorizer; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.chc.HornAnnot; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; @@ -47,11 +47,8 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.BasicPredicateFactory; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; @@ -100,11 +97,10 @@ private void processIcfg(final IIcfg icfg) { final HcSymbolTable hcSymbolTable = new HcSymbolTable(mgdScript); final Collection resultChcs = getHornClauses(icfg, mgdScript, hcSymbolTable); - final boolean isReturnReachable = isReturnReachable(icfg); - final boolean hasNonLinearClauses = isReturnReachable || !IcfgUtils.getForksInLoop(icfg).isEmpty() - || mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC; - final ChcCategoryInfo chcCategoryInfo = - new ChcCategoryInfo(getLogics(resultChcs, mgdScript), hasNonLinearClauses); + final var chcCategoryInfo = ChcCategorizer.categorize(resultChcs, mgdScript); + assert !chcCategoryInfo.containsNonLinearHornClauses() || isReturnReachable(icfg) + || !IcfgUtils.getForksInLoop(icfg).isEmpty() + || mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC : "Unexpected non-linear clauses"; final var bad = resultChcs.stream() .filter(chc -> chc.constructFormula(mgdScript, false).getFreeVars().length != 0).findAny(); @@ -117,48 +113,6 @@ private void processIcfg(final IIcfg icfg) { ModelUtils.copyAnnotations(icfg, mResult); } - private static Logics getLogics(final Collection resultChcs, final ManagedScript mgdScript) { - final TermClassifier termClassifierChcs = new TermClassifier(); - resultChcs.forEach(chc -> termClassifierChcs.checkTerm(chc.constructFormula(mgdScript, false))); - final TermClassifier termClassifierConstraints = new TermClassifier(); - resultChcs.forEach(chc -> termClassifierConstraints.checkTerm(chc.getConstraintFormula())); - - boolean hasArrays = false; - boolean hasReals = false; - boolean hasInts = false; - for (final String osn : termClassifierChcs.getOccuringSortNames()) { - hasArrays |= osn.contains(SmtSortUtils.ARRAY_SORT); - hasReals |= osn.contains(SmtSortUtils.REAL_SORT); - hasInts |= osn.contains(SmtSortUtils.INT_SORT); - } - - boolean hasArraysInConstraints = false; - boolean hasRealsInConstraints = false; - boolean hasIntsInConstraints = false; - for (final String osn : termClassifierConstraints.getOccuringSortNames()) { - hasArraysInConstraints |= osn.contains(SmtSortUtils.ARRAY_SORT); - hasRealsInConstraints |= osn.contains(SmtSortUtils.REAL_SORT); - hasIntsInConstraints |= osn.contains(SmtSortUtils.INT_SORT); - } - assert hasArrays == hasArraysInConstraints; - assert hasReals == hasRealsInConstraints; - assert hasInts == hasIntsInConstraints; - - final boolean hasQuantifiersInConstraints = !termClassifierConstraints.getOccuringQuantifiers().isEmpty(); - - if (!hasArrays && hasInts && !hasReals && !hasQuantifiersInConstraints) { - return Logics.QF_LIA; - } - if (!hasArrays && !hasInts && hasReals && !hasQuantifiersInConstraints) { - return Logics.QF_LRA; - } - if (hasArrays && hasInts && !hasReals && !hasQuantifiersInConstraints) { - return Logics.QF_ALIA; - } - // not a CHC-comp 2019 logic -- we don't care for more details right now - return Logics.ALL; - } - private static boolean isReturnReachable(final IIcfg icfg) { return new IcfgEdgeIterator(icfg).asStream().anyMatch(IIcfgSummaryTransition.class::isInstance); } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcCategorizer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcCategorizer.java new file mode 100644 index 00000000000..cbc903f1cc7 --- /dev/null +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcCategorizer.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 Alexander Nutz (nutz@informatik.uni-freiburg.de) + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2019-2023 University of Freiburg + * + * This file is part of the ULTIMATE CHC Library. + * + * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.lib.chc; + +import java.util.Collection; + +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.TermClassifier; +import de.uni_freiburg.informatik.ultimate.logic.Logics; + +public final class ChcCategorizer { + private ChcCategorizer() { + // static class cannot be instantiated + } + + public static ChcCategoryInfo categorize(final Collection clauses, final ManagedScript mgdScript) { + return new ChcCategoryInfo(getLogics(clauses, mgdScript), hasNonLinearClauses(clauses)); + } + + public static boolean hasNonLinearClauses(final Collection clauses) { + return clauses.stream().anyMatch(ChcCategorizer::isNonLinear); + } + + public static boolean isNonLinear(final HornClause clause) { + return clause.getBodyPredicates().size() >= 2; + } + + public static Logics getLogics(final Collection clauses, final ManagedScript mgdScript) { + final TermClassifier termClassifierChcs = new TermClassifier(); + clauses.forEach(chc -> termClassifierChcs.checkTerm(chc.constructFormula(mgdScript, false))); + final TermClassifier termClassifierConstraints = new TermClassifier(); + clauses.forEach(chc -> termClassifierConstraints.checkTerm(chc.getConstraintFormula())); + + boolean hasArrays = false; + boolean hasReals = false; + boolean hasInts = false; + for (final String osn : termClassifierChcs.getOccuringSortNames()) { + hasArrays |= osn.contains(SmtSortUtils.ARRAY_SORT); + hasReals |= osn.contains(SmtSortUtils.REAL_SORT); + hasInts |= osn.contains(SmtSortUtils.INT_SORT); + } + + boolean hasArraysInConstraints = false; + boolean hasRealsInConstraints = false; + boolean hasIntsInConstraints = false; + for (final String osn : termClassifierConstraints.getOccuringSortNames()) { + hasArraysInConstraints |= osn.contains(SmtSortUtils.ARRAY_SORT); + hasRealsInConstraints |= osn.contains(SmtSortUtils.REAL_SORT); + hasIntsInConstraints |= osn.contains(SmtSortUtils.INT_SORT); + } + assert hasArrays == hasArraysInConstraints; + assert hasReals == hasRealsInConstraints; + assert hasInts == hasIntsInConstraints; + + final boolean hasQuantifiersInConstraints = !termClassifierConstraints.getOccuringQuantifiers().isEmpty(); + + if (!hasArrays && hasInts && !hasReals && !hasQuantifiersInConstraints) { + return Logics.QF_LIA; + } + if (!hasArrays && !hasInts && hasReals && !hasQuantifiersInConstraints) { + return Logics.QF_LRA; + } + if (hasArrays && hasInts && !hasReals && !hasQuantifiersInConstraints) { + return Logics.QF_ALIA; + } + // not a CHC-comp 2019 logic -- we don't care for more details right now + return Logics.ALL; + } +} diff --git a/trunk/source/TreeAutomizer/src/de/uni_freiburg/informatik/ultimate/plugins/generator/treeautomizer/TreeAutomizerChcScript.java b/trunk/source/TreeAutomizer/src/de/uni_freiburg/informatik/ultimate/plugins/generator/treeautomizer/TreeAutomizerChcScript.java index 0370725a4cb..d1b888f1508 100644 --- a/trunk/source/TreeAutomizer/src/de/uni_freiburg/informatik/ultimate/plugins/generator/treeautomizer/TreeAutomizerChcScript.java +++ b/trunk/source/TreeAutomizer/src/de/uni_freiburg/informatik/ultimate/plugins/generator/treeautomizer/TreeAutomizerChcScript.java @@ -35,6 +35,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.results.IResult; 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.chc.ChcCategorizer; import de.uni_freiburg.informatik.ultimate.lib.chc.Derivation; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.chc.HornAnnot; @@ -92,8 +93,8 @@ private LBool solve(final IUltimateServiceProvider services, final HcSymbolTable final List system) { reset(); - // TODO missing parameter: category info - final var annot = new HornAnnot(DUMMY_FILENAME, mMgdScript, symbolTable, system, true, null); + final var categoryInfo = ChcCategorizer.categorize(system, mMgdScript); + final var annot = new HornAnnot(DUMMY_FILENAME, mMgdScript, symbolTable, system, true, categoryInfo); final var cegar = new TreeAutomizerCEGAR(services, annot, mPrefs, mLogger); try { final var result = cegar.iterate(); From 3b0b0112d59560fe511f2a787d247e4b3672c075 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 15:12:31 +0200 Subject: [PATCH 050/114] simpler postcondition encoding: only one thread counter --- .../concurrent/HcThreadCounterVar.java | 37 +++++-------------- .../ThreadModularHornClauseProvider.java | 35 ++++++++---------- 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java index 99cc78e0733..45cae313e01 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java @@ -26,35 +26,30 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; -import java.util.Objects; - import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; /** - * A variable that counts the number of started resp. of terminated threads. These variables are used for a - * thread-modular encoding of postconditions. + * A variable that counts the number of running threads. This variable is used for a thread-modular encoding of + * postconditions. * * The thread-modular encoding of postconditions works as follows: *
    - *
  1. The number of started threads is incremented each time one of the initially running threads takes its first + *
  2. The number of running threads is incremented each time one of the initially running threads takes its first * step.
  3. - *
  4. The number of terminated threads is incremented each time one of the initially running threads terminates.
  5. - *
  6. If an initially running thread has terminated, and the numbers of started and terminated threads are equal, then - * the postcondition must hold.
  7. + *
  8. The number of running threads is decremented each time one of the initially running threads terminates.
  9. + *
  10. If an initially running thread has terminated, and the number of running threads is 0, then the postcondition + * must hold.
  11. *
* * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) */ public class HcThreadCounterVar implements IHcReplacementVar { - // An instance either represents the number of started threads (if this boolean is true) or of terminated threads - private final boolean mIsStarted; private final Sort mSort; - public HcThreadCounterVar(final boolean isStarted, final Script script) { - mIsStarted = isStarted; + public HcThreadCounterVar(final Script script) { mSort = SmtSortUtils.getIntSort(script); } @@ -63,22 +58,14 @@ public Sort getSort() { return mSort; } - public boolean isStarted() { - return mIsStarted; - } - - public boolean isTerminated() { - return !mIsStarted; - } - @Override public String toString() { - return mIsStarted ? "~started" : "~terminated"; + return "~running"; } @Override public int hashCode() { - return Objects.hash(mIsStarted); + return 79; } @Override @@ -89,10 +76,6 @@ public boolean equals(final Object obj) { if (obj == null) { return false; } - if (getClass() != obj.getClass()) { - return false; - } - final HcThreadCounterVar other = (HcThreadCounterVar) obj; - return mIsStarted == other.mIsStarted; + return getClass() == obj.getClass(); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 4face7f1fc8..b16c7723ac0 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -105,8 +105,7 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide protected final PredicateInfo mInvariantPredicate; protected final Set mGlobalVars = new HashSet<>(); - protected final HcThreadCounterVar mStartedVar; - protected final HcThreadCounterVar mTerminatedVar; + protected final HcThreadCounterVar mRunningThreadsVar; protected final Map> mThreadSpecificVars = new HashMap<>(); protected final Map mLocationVars = new HashMap<>(); protected final NestedMap2 mLocalVars = new NestedMap2<>(); @@ -134,11 +133,9 @@ public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, mBottomLocation = numeral(-1); if (mPrefs.specMode() == SpecMode.POSTCONDITION) { - mStartedVar = new HcThreadCounterVar(true, mScript); - mTerminatedVar = new HcThreadCounterVar(false, mScript); + mRunningThreadsVar = new HcThreadCounterVar(mScript); } else { - mStartedVar = null; - mTerminatedVar = null; + mRunningThreadsVar = null; } mInvariantPredicate = createInvariantPredicate(); } @@ -186,8 +183,7 @@ protected List getInvariantParameters() { // add variables for thread-modular encoding of postconditions if (mPrefs.specMode() == SpecMode.POSTCONDITION) { - result.add(mStartedVar); - result.add(mTerminatedVar); + result.add(mRunningThreadsVar); } result.addAll(createGlobalVars()); @@ -341,17 +337,18 @@ public String toString() { // add actual constraints for spec edges, do nothing if not a spec edge protected void transformSpecEdgeClause(final IcfgEdge edge, final HornClauseBuilder clause) { if (isPreConditionSpecEdge(edge) && mPrefs.specMode() == SpecMode.POSTCONDITION) { - incrementThreadCounter(clause, mStartedVar); + incrementThreadCounter(clause, mRunningThreadsVar, 1L); } else if (isPostConditionSpecEdge(edge)) { - incrementThreadCounter(clause, mTerminatedVar); + incrementThreadCounter(clause, mRunningThreadsVar, -1L); } } - protected void incrementThreadCounter(final HornClauseBuilder clause, final HcThreadCounterVar counter) { - // add constraint counter' = counter + 1 + protected void incrementThreadCounter(final HornClauseBuilder clause, final HcThreadCounterVar counter, + final long delta) { + // add constraint counter' = counter + delta clause.differentBodyHeadVar(counter); clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getHeadVar(counter).getTerm(), - SmtUtils.sum(mScript, getIntSort(), clause.getBodyVar(counter).getTerm(), numeral(1L)))); + SmtUtils.sum(mScript, getIntSort(), clause.getBodyVar(counter).getTerm(), numeral(delta)))); } protected boolean isPreConditionSpecEdge(final IcfgEdge edge) { @@ -449,11 +446,9 @@ protected HornClauseBuilder buildInitialClause() { } if (mPrefs.specMode() == SpecMode.POSTCONDITION) { - // add constraints that thread counters (for thread-modular encoding of postconditions) are initially 0 + // add constraints that thread counter (for thread-modular encoding of postconditions) is initially 0 clause.addConstraint( - SmtUtils.binaryEquality(mScript, clause.getHeadVar(mStartedVar).getTerm(), numeral(0))); - clause.addConstraint( - SmtUtils.binaryEquality(mScript, clause.getHeadVar(mTerminatedVar).getTerm(), numeral(0))); + SmtUtils.binaryEquality(mScript, clause.getHeadVar(mRunningThreadsVar).getTerm(), numeral(0))); } if (mPrefs.hasPreconditions()) { @@ -529,9 +524,9 @@ protected HornClauseBuilder buildPostconditionSafetyClause(final ThreadInstance final var exitLoc = mIcfg.getProcedureExitNodes().get(thread.getTemplateName()); addInLocationConstraint(clause, thread, exitLoc); - // add thread counter constraint: started == terminated - clause.addConstraint(SmtUtils.binaryEquality(mScript, clause.getBodyVar(mStartedVar).getTerm(), - clause.getBodyVar(mTerminatedVar).getTerm())); + // add thread counter constraint: running == 0 + clause.addConstraint( + SmtUtils.binaryEquality(mScript, clause.getBodyVar(mRunningThreadsVar).getTerm(), numeral(0L))); // add negated postcondition final var postcondition = DataStructureUtils From 9a82c7054acca23fefba4c5b776a0487c847030c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 18:23:31 +0200 Subject: [PATCH 051/114] implement support for different preference orders For now, sequential composition as well as an approximation of lockstep are supported. --- .../plugins/icfgtochc/IcfgToChcObserver.java | 18 +- .../icfgtochc/concurrent/ThreadInstance.java | 40 ++++- .../ThreadModularHornClauseProvider.java | 42 +++-- .../ApproximateLockstepPreferenceOrder.java | 155 ++++++++++++++++++ .../ExplicitPreferenceOrderManager.java | 67 ++++++++ .../partialorder/IPreferenceOrderManager.java | 49 ++++++ .../IThreadModularPreferenceOrder.java | 57 +++++++ .../SequentialCompositionPreferenceOrder.java | 53 ++++++ ...eepSetThreadModularHornClauseProvider.java | 102 ++++-------- .../SymbolicPreferenceOrderManager.java | 77 +++++++++ .../IcfgToChcPreferenceInitializer.java | 22 ++- .../preferences/IcfgToChcPreferences.java | 5 + 12 files changed, 602 insertions(+), 85 deletions(-) create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IPreferenceOrderManager.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java create mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 1b999b311bd..5663c467f2b 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -49,12 +49,16 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ApproximateLockstepPreferenceOrder; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ConditionSynthesizingIndependenceRelation; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ExplicitSymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ISymbolicIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.IThreadModularPreferenceOrder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.SequentialCompositionPreferenceOrder; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.SleepSetThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; @@ -137,8 +141,9 @@ private Collection getHornClauses(IIcfg icfg, final Ma if (mPrefs.useSleepSets()) { final var independence = getIndependence(icfg, mgdScript); + final var preforder = getPreferenceOrder(mgdScript.getScript(), icfg); return new SleepSetThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, - independence, mPrefs).getClauses(); + independence, preforder, mPrefs).getClauses(); } return new ThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, mPrefs).getClauses(); } @@ -161,4 +166,15 @@ private ISymbolicIndependenceRelation getIndependence(final IIcfg ic throw new AssertionError("Unknown conditional independence setting: " + mPrefs.conditionalIndependence()); } + + private IThreadModularPreferenceOrder getPreferenceOrder(final Script script, final IIcfg icfg) { + switch (mPrefs.preferenceOrder()) { + case SEQ_COMP: + return new SequentialCompositionPreferenceOrder(script); + case LOCKSTEP: + return ApproximateLockstepPreferenceOrder.create(script, icfg); + } + + throw new AssertionError("Unknown preference order setting: " + mPrefs.preferenceOrder()); + } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java index 70df1092830..eb255726034 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadInstance.java @@ -26,9 +26,10 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; +import java.util.Comparator; import java.util.Objects; -public final class ThreadInstance { +public final class ThreadInstance implements Comparable { private final String mTemplateName; private final int mInstanceNumber; @@ -45,6 +46,18 @@ public int getInstanceNumber() { return mInstanceNumber; } + @Override + public int compareTo(final ThreadInstance o) { + if (mInstanceNumber < 0 || o.mInstanceNumber < 0) { + throw new UnsupportedOperationException("Must not compare interfering thread with this method."); + } + final var templateComparison = mTemplateName.compareTo(o.mTemplateName); + if (templateComparison != 0) { + return templateComparison; + } + return Integer.compare(mInstanceNumber, o.mInstanceNumber); + } + @Override public String toString() { return IcfgToChcConcurrentUtils.getReadableString(mTemplateName) + "_" + (mInstanceNumber + 1); @@ -69,4 +82,29 @@ public boolean equals(final Object obj) { final ThreadInstance other = (ThreadInstance) obj; return mInstanceNumber == other.mInstanceNumber && Objects.equals(mTemplateName, other.mTemplateName); } + + public static Comparator getNonInterferenceComparator(final int interferingIndex) { + return (t1, t2) -> { + if (t1.getInstanceNumber() >= 0 && t2.getInstanceNumber() >= 0) { + // If not considering an interfering thread, use the usual ordering + return t1.compareTo(t2); + } + + // between threads of different templates, keep the same ordering as #compareTo + // (i.e. order by template name) + if (!t1.getTemplateName().equals(t2.getTemplateName())) { + return t1.getTemplateName().compareTo(t2.getTemplateName()); + } + if (t1.getInstanceNumber() >= 0) { + // t2 is the interfering thread + return t1.getInstanceNumber() < interferingIndex ? -1 : 1; + } + if (t2.getInstanceNumber() >= 0) { + // t1 is the interfering thread + return interferingIndex <= t2.getInstanceNumber() ? -1 : 1; + } + assert t1.equals(t2); + return 0; + }; + } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index b16c7723ac0..01549301530 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -91,9 +91,9 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvide private final IIcfgSymbolTable mCfgSymbolTable; private final Predicate mVariableFilter; - // maps a procedure name and a location (in the procedure) to an integer, such that the location variable has this - // integer as value iff control is in the given location - private final NestedMap2 mLocationIndices = new NestedMap2<>(); + // Maps each location to an integer, such that the location variable has this integer as value iff control is in the + // given location. Locations in different procedures may be mapped to the same value. + protected final Map mLocationIndices; // used as location for threads that are not currently running private final Term mBottomLocation; @@ -131,7 +131,9 @@ public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, mInstances = getInstances(threadInfo.getFirst()); mUnboundedTemplates = threadInfo.getSecond(); + mLocationIndices = createLocationMap(icfg); mBottomLocation = numeral(-1); + if (mPrefs.specMode() == SpecMode.POSTCONDITION) { mRunningThreadsVar = new HcThreadCounterVar(mScript); } else { @@ -170,6 +172,25 @@ private PredicateInfo createInvariantPredicate() { return new PredicateInfo(predicate, parameters); } + protected Map createLocationMap(final IIcfg icfg) { + final var result = new HashMap(); + for (final var entry : icfg.getProcedureEntryNodes().values()) { + int counter = 0; + result.put(entry, counter); + counter++; + final var iterator = new IcfgEdgeIterator(entry.getOutgoingEdges()); + while (iterator.hasNext()) { + final var edge = iterator.next(); + assert result.containsKey(edge.getSource()) : "edge with unknown source loc"; + if (!result.containsKey(edge.getTarget())) { + result.put(edge.getTarget(), counter); + counter++; + } + } + } + return result; + } + /** * Constructs the sequence of parameters for the invariant predicate. * @@ -656,8 +677,7 @@ protected Map getInitialLocations() { protected void addInLocationConstraint(final HornClauseBuilder clause, final ThreadInstance threadInstance, final IcfgLocation location) { - final var locTerm = - location == null ? mBottomLocation : getLocIndexTerm(location, threadInstance.getTemplateName()); + final var locTerm = location == null ? mBottomLocation : getLocIndexTerm(location); final HcLocationVar locVar = new HcLocationVar(threadInstance, mScript); final Term term = clause.getBodyVar(locVar).getTerm(); clause.addConstraint(SmtUtils.binaryEquality(mScript, term, locTerm)); @@ -665,20 +685,14 @@ protected void addInLocationConstraint(final HornClauseBuilder clause, final Thr protected void addOutLocationConstraint(final HornClauseBuilder clause, final ThreadInstance threadInstance, final IcfgLocation location) { - final var locTerm = - location == null ? mBottomLocation : getLocIndexTerm(location, threadInstance.getTemplateName()); + final var locTerm = location == null ? mBottomLocation : getLocIndexTerm(location); final HcLocationVar locVar = mLocationVars.get(threadInstance); final Term term = clause.getHeadVar(locVar).getTerm(); clause.addConstraint(SmtUtils.binaryEquality(mScript, term, locTerm)); } - protected Term getLocIndexTerm(final IcfgLocation loc, final String proc) { - Integer index = mLocationIndices.get(proc, loc); - if (index == null) { - final Map otherIndices = mLocationIndices.get(proc); - index = otherIndices == null ? 0 : otherIndices.size(); - mLocationIndices.put(proc, loc, index); - } + protected Term getLocIndexTerm(final IcfgLocation loc) { + final int index = mLocationIndices.get(loc); return numeral(index); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java new file mode 100644 index 00000000000..85c5ed00bd7 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; + +public class ApproximateLockstepPreferenceOrder implements IThreadModularPreferenceOrder { + private final Script mScript; + private final Map mDepth; + + protected ApproximateLockstepPreferenceOrder(final Script script, final Map depth) { + mScript = script; + mDepth = depth; + } + + @Override + public Term getOrderConstraint(final IcfgLocation lesserLoc, final Term lesserLocTerm, + final IcfgLocation greaterLoc, final Term greaterLocTerm, final Map locationMap) { + if (lesserLoc != null && greaterLoc != null) { + return getOrderConstraint(lesserLoc, greaterLoc); + } + + if (lesserLoc != null) { + return getOrderConstraint(lesserLoc, greaterLocTerm, locationMap); + } + + assert greaterLoc != null : "At least one location must be fixed"; + final var constraint = getOrderConstraint(greaterLoc, lesserLocTerm, locationMap); + + // invert the constraint, because we flipped greaterLoc and lesserLocTerm + return SmtUtils.not(mScript, constraint); + } + + private Term getOrderConstraint(final IcfgLocation lesserLoc, final IcfgLocation greaterLoc) { + if (mDepth.get(lesserLoc) <= mDepth.get(greaterLoc)) { + return mScript.term(SMTLIBConstants.TRUE); + } + return mScript.term(SMTLIBConstants.FALSE); + } + + private Term getOrderConstraint(final IcfgLocation fixedLoc, final Term otherLoc, + final Map locationMap) { + final var fixedDepth = mDepth.get(fixedLoc); + + final var greaterLocs = mDepth.entrySet().stream().filter(e -> e.getValue() >= fixedDepth) + .map(e -> mDepth.get(e.getKey())).sorted().collect(Collectors.toList()); + final var locRanges = rangify(greaterLocs); + + final var disjuncts = new ArrayList(); + for (final var range : locRanges) { + final var disjunct = getIntervalConstraint(otherLoc, range.getFirst(), range.getSecond()); + if (SmtUtils.isTrueLiteral(disjunct)) { + return mScript.term(SMTLIBConstants.TRUE); + } + disjuncts.add(disjunct); + } + return SmtUtils.or(mScript, disjuncts); + } + + // Partitions a sorted list of integers into a sequence of (inclusive) intervals. + private static List> rangify(final List sortedValues) { + final var result = new ArrayList>(); + for (int idx = 0; idx < sortedValues.size();) { + final int start = sortedValues.get(idx); + int current = start; + do { + idx++; + current++; + } while (idx < sortedValues.size() && sortedValues.get(idx) == current); + + result.add(new Pair<>(start, current - 1)); + } + + return result; + } + + private Term getIntervalConstraint(final Term element, final int lowerBound, final int upperBound) { + assert lowerBound <= upperBound : "empty interval encountered"; + final Term upperTerm = SmtUtils.constructIntValue(mScript, BigInteger.valueOf(upperBound)); + + if (lowerBound == upperBound) { + return SmtUtils.binaryEquality(mScript, element, upperTerm); + } + + final Term lowerTerm = SmtUtils.constructIntValue(mScript, BigInteger.valueOf(lowerBound)); + return SmtUtils.and(mScript, SmtUtils.leq(mScript, lowerTerm, element), + SmtUtils.leq(mScript, element, upperTerm)); + } + + @Override + public boolean isPositional() { + return true; + } + + public static ApproximateLockstepPreferenceOrder create(final Script script, final IIcfg icfg) { + return new ApproximateLockstepPreferenceOrder(script, computeDepthMap(icfg)); + } + + protected static Map computeDepthMap(final IIcfg icfg) { + final var result = new HashMap(); + for (final var entry : icfg.getProcedureEntryNodes().values()) { + computeDepthMap(result, entry); + } + return result; + } + + private static void computeDepthMap(final Map map, final IcfgLocation entry) { + map.put(entry, 0); + final var iterator = new IcfgEdgeIterator(entry.getOutgoingEdges()); + while (iterator.hasNext()) { + final var edge = iterator.next(); + assert map.containsKey(edge.getSource()) : "depth of edge source node is unknown"; + final int sourceDepth = map.get(edge.getSource()); + map.merge(edge.getTarget(), sourceDepth + 1, Integer::min); + } + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java new file mode 100644 index 00000000000..056e0277ba6 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; + +class ExplicitPreferenceOrderManager implements IPreferenceOrderManager { + private final IThreadModularPreferenceOrder mPreferenceOrder; + private final Script mScript; + private final Map mLocationMap; + + public ExplicitPreferenceOrderManager(final IThreadModularPreferenceOrder preferenceOrder, final Script script, + final Map locationMap) { + mPreferenceOrder = preferenceOrder; + mScript = script; + mLocationMap = locationMap; + } + + @Override + public Term getOrderConstraint(final HornClauseBuilder clause, final Comparator comp, + final ThreadInstance thread1, final IcfgLocation loc1, final Term locTerm1, final ThreadInstance thread2, + final IcfgLocation loc2, final Term locTerm2) { + final int ordering = comp.compare(thread1, thread2); + if (ordering >= 0) { + return mScript.term(SMTLIBConstants.FALSE); + } + return mPreferenceOrder.getOrderConstraint(loc1, locTerm1, loc2, locTerm2, mLocationMap); + } + + @Override + public void ensureUniqueThreadIDs(final HornClauseBuilder clause, final List instances) { + // nothing to do + } +} \ No newline at end of file diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IPreferenceOrderManager.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IPreferenceOrderManager.java new file mode 100644 index 00000000000..94bae198719 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IPreferenceOrderManager.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.util.Comparator; +import java.util.List; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; + +interface IPreferenceOrderManager { + Term getOrderConstraint(HornClauseBuilder clause, Comparator comp, final ThreadInstance thread1, + final IcfgLocation loc1, final Term locTerm1, final ThreadInstance thread2, final IcfgLocation loc2, + final Term locTerm2); + + default Term getInductiveOrderConstraint(final HornClauseBuilder clause, final ThreadInstance thread1, + final IcfgLocation loc1, final Term locTerm1, final ThreadInstance thread2, final IcfgLocation loc2, + final Term locTerm2) { + return getOrderConstraint(clause, Comparator.naturalOrder(), thread1, loc1, locTerm1, thread2, loc2, locTerm2); + } + + void ensureUniqueThreadIDs(HornClauseBuilder clause, List instances); +} \ No newline at end of file diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java new file mode 100644 index 00000000000..5f6ed34c0ae --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.util.Map; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +public interface IThreadModularPreferenceOrder { + /** + * Constructs a boolean constraint expressing the ordering between two threads. If the constraint evaluates to + * {@code true}, then the "lesser" thread is preferred. Otherwise, the "greater" thread is preferred. + * + * At least one of {@code lesserLoc} and {@code greaterLoc} is guaranteed to be non-null. + * + * @param lesserLoc + * The location of the thread with a lower thread ID. May be null. + * @param lesserLocTerm + * A term denoting the location of the thread with a lower thread ID. + * @param greaterLoc + * The location of the thread with a greater thread ID. May be null. + * @param greaterLocTerm + * A term denoting the location of the thread with a greater thread ID. + * @param locationTerms + * A mapping from locations to the integer value used to represent that location. + * @return a constraint over the given terms (including the terms in {@code locationTerms}) + */ + Term getOrderConstraint(IcfgLocation lesserLoc, Term lesserLocTerm, IcfgLocation greaterLoc, Term greaterLocTerm, + Map locationMap); + + boolean isPositional(); +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java new file mode 100644 index 00000000000..15ba73fafb8 --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.util.Map; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Term; + +public class SequentialCompositionPreferenceOrder implements IThreadModularPreferenceOrder { + private final Script mScript; + + public SequentialCompositionPreferenceOrder(final Script script) { + mScript = script; + } + + @Override + public Term getOrderConstraint(final IcfgLocation lesserLoc, final Term lesserLocTerm, + final IcfgLocation greaterLoc, final Term greaterLocTerm, final Map locationMap) { + return mScript.term(SMTLIBConstants.TRUE); + } + + @Override + public boolean isPositional() { + return false; + } +} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index e4b39039803..0ad0cac89dc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -28,10 +28,10 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -45,6 +45,7 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcLocationVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcThreadSpecificVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; @@ -54,6 +55,7 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornClauseProvider { private final IndependenceChecker mIndependenceChecker; + private final IPreferenceOrderManager mPreferenceManager; private final Map> mThreadLocations; private final Map mIdVars; @@ -62,16 +64,18 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornCl public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider services, final ManagedScript mgdScript, final IIcfg icfg, final HcSymbolTable symbolTable, final ISymbolicIndependenceRelation> independence, - final IcfgToChcPreferences prefs) { + final IThreadModularPreferenceOrder preferenceOrder, final IcfgToChcPreferences prefs) { super(services, mgdScript, icfg, symbolTable, prefs); mIndependenceChecker = new IndependenceChecker(services, icfg.getCfgSmtToolkit(), independence); mThreadLocations = icfg.getProgramPoints().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); - if (!mPrefs.breakPreferenceOrderSymmetry()) { - mIdVars = extractThreadVars(HcThreadIdVar.class); - } else { + if (mPrefs.breakPreferenceOrderSymmetry()) { mIdVars = null; + mPreferenceManager = new ExplicitPreferenceOrderManager(preferenceOrder, mScript, mLocationIndices); + } else { + mIdVars = extractThreadVars(HcThreadIdVar.class); + mPreferenceManager = new SymbolicPreferenceOrderManager(preferenceOrder, mScript, mLocationIndices); } mSleepVars = extractThreadVars(HcSleepVar.class); } @@ -103,9 +107,7 @@ protected HornClauseBuilder buildInitialClause() { final var clause = super.buildInitialClause(); // thread IDs are pairwise different - if (!mPrefs.breakPreferenceOrderSymmetry()) { - ensureUniqueThreadIDs(clause); - } + mPreferenceManager.ensureUniqueThreadIDs(clause, mInstances); // all sleep variables are initialized to false for (final var instance : mInstances) { @@ -130,7 +132,11 @@ protected HornClauseBuilder buildInductivityClause(final IcfgEdge transition, // update sleep variables for (final var instance : mInstances) { - updateSleepInductive(clause, transition, preds.keySet(), updatedThread, instance); + if (preds.containsKey(updatedThread)) { + // no update of sleep variable + continue; + } + updateSleep(clause, updatedThread, transition, instance, Comparator.naturalOrder()); } return clause; @@ -176,8 +182,7 @@ protected HornClauseBuilder buildNonInterferenceClause(final IcfgEdge transition // update sleep variables for (final var sleepingThread : mInstances) { - final var prefOrder = symbolicPreferenceOrderConstraint(clause, sleepingThread, interferingThread); - updateSleep(clause, interferingThread, transition, sleepingThread, prefOrder); + updateSleep(clause, interferingThread, transition, sleepingThread, null); } return clause; @@ -193,7 +198,6 @@ protected HornClauseBuilder buildNonInterferenceClause(final IcfgEdge transition // TODO support transitions with multiple predecessors (joins) final var interferingThread = getInterferingThread(transition); - // final var interferingVars = createThreadSpecificVars(interferingThread); final var instances = getInstances(interferingThread.getTemplateName()); final var clause = buildNonInterferenceClause(transition, (c, replacedInstance) -> { @@ -232,93 +236,59 @@ protected HornClauseBuilder buildNonInterferenceClause(final IcfgEdge transition // update sleep variables for (final var sleepingThread : mInstances) { - final var prefOrder = index < sleepingThread.getInstanceNumber() ? mScript.term(SMTLIBConstants.FALSE) - : mScript.term(SMTLIBConstants.TRUE); - updateSleep(clause, interferingThread, transition, sleepingThread, prefOrder); + updateSleep(clause, interferingThread, transition, sleepingThread, + ThreadInstance.getNonInterferenceComparator(index)); } return clause; } - private void ensureUniqueThreadIDs(final HornClauseBuilder clause) { - for (final var first : mInstances) { - final var firstId = clause.getHeadVar(mIdVars.get(first)); - for (final var second : mInstances) { - if (!Objects.equals(first, second)) { - final var secondId = clause.getHeadVar(mIdVars.get(second)); - clause.addConstraint(SmtUtils.distinct(mScript, firstId.getTerm(), secondId.getTerm())); - } - } - } - } - - // update sleep variable depending on commutativity and preference order - private void updateSleepInductive(final HornClauseBuilder clause, final IcfgEdge transition, - final Set activeThreads, final ThreadInstance primaryActiveThread, - final ThreadInstance updatedThread) { - if (activeThreads.contains(updatedThread)) { - // no update of sleep variable - return; - } - - final Term prefOrder; - if (mPrefs.breakPreferenceOrderSymmetry()) { - // We resolve the preference order statically. - // For now, the preference order is non-positional, and given by the ordering in mInstances. - final int ordering = - Integer.compare(mInstances.indexOf(primaryActiveThread), mInstances.indexOf(updatedThread)); - // Formula expressing whether current thread is BEFORE primary thread. - prefOrder = ordering < 0 ? mScript.term(SMTLIBConstants.FALSE) : mScript.term(SMTLIBConstants.TRUE); - } else { - // We resolve the preference order symbolically, using ID variables. - prefOrder = symbolicPreferenceOrderConstraint(clause, updatedThread, primaryActiveThread); - } - - updateSleep(clause, primaryActiveThread, transition, updatedThread, prefOrder); - } - // update sleep variable depending on commutativity and preference order private void updateSleep(final HornClauseBuilder clause, final ThreadInstance activeThread, - final IcfgEdge activeEdge, final ThreadInstance updatedThread, final Term prefOrder) { + final IcfgEdge activeEdge, final ThreadInstance updatedThread, + final Comparator comparator) { + // The sleep variable of updatedThread is modified. final var sleep = mSleepVars.get(updatedThread); clause.differentBodyHeadVar(sleep); - final var oldSleep = clause.getBodyVar(sleep); final var newSleep = clause.getHeadVar(sleep); + // Determine the preference order constraint, expressing that updatedThread is preferable to activeThread. + // updatedThread < activeThread + final var updatedLocTerm = clause.getBodyVar(new HcLocationVar(updatedThread, mScript)).getTerm(); + final var activeLoc = activeEdge.getSource(); + final var activeLocTerm = getLocIndexTerm(activeLoc); + final var prefOrder = mPreferenceManager.getOrderConstraint(clause, comparator, updatedThread, null, + updatedLocTerm, activeThread, activeLoc, activeLocTerm); + + // Determine if updatedThread can be put to sleep (or continue to sleep). + // (updatedThread < activeThread) \/ sleep final var canBePutToSleep = SmtUtils.or(mScript, prefOrder, oldSleep.getTerm()); if (SmtUtils.isFalseLiteral(canBePutToSleep)) { - // optimization: If commutativity does not play a role, skip computation of commutativity constraint + // Optimization: If commutativity does not play a role, skip computation of commutativity constraint. // sleep' = false clause.addConstraint( SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), mScript.term(SMTLIBConstants.FALSE))); return; } - // get constraint describing commutativity + // Get constraint describing commutativity. final var currentLoc = clause.getBodyVar(mLocationVars.get(updatedThread)); final Term commConstr = getCommutativityConstraint(clause, activeThread, activeEdge, updatedThread, currentLoc.getTerm()); - // sleep' = (current < interfering \/ sleep) /\ commConstr + // Update the sleep variable of updatedThread, according to the sleep set rule. + // sleep' = ((updatedThread < activeThread) \/ sleep) /\ commConstr clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), SmtUtils.and(mScript, canBePutToSleep, commConstr))); } - private Term symbolicPreferenceOrderConstraint(final HornClauseBuilder clause, final ThreadInstance current, - final ThreadInstance active) { - final var currentId = clause.getBodyVar(new HcThreadIdVar(current, mScript)); - final var activeId = clause.getBodyVar(new HcThreadIdVar(active, mScript)); - return SmtUtils.less(mScript, currentId.getTerm(), activeId.getTerm()); - } - protected Term getCommutativityConstraint(final HornClauseBuilder clause, final ThreadInstance activeThread, final IcfgEdge activeEdge, final ThreadInstance otherThread, final Term otherLocVar) { final var disjuncts = new ArrayList(); for (final var loc : mThreadLocations.get(otherThread.getTemplateName())) { - final var locEquality = - SmtUtils.binaryEquality(mScript, otherLocVar, getLocIndexTerm(loc, otherThread.getTemplateName())); + final var locEquality = SmtUtils.binaryEquality(mScript, otherLocVar, getLocIndexTerm(loc)); if (SmtUtils.isFalseLiteral(locEquality)) { continue; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java new file mode 100644 index 00000000000..6f80ff290cb --- /dev/null +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE IcfgToChc plug-in. + * + * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; + +class SymbolicPreferenceOrderManager implements IPreferenceOrderManager { + private final IThreadModularPreferenceOrder mPreferenceOrder; + private final Script mScript; + private final Map mLocationMap; + + public SymbolicPreferenceOrderManager(final IThreadModularPreferenceOrder preferenceOrder, final Script script, + final Map locationMap) { + mPreferenceOrder = preferenceOrder; + mScript = script; + mLocationMap = locationMap; + } + + @Override + public Term getOrderConstraint(final HornClauseBuilder clause, final Comparator comp, + final ThreadInstance thread1, final IcfgLocation loc1, final Term locTerm1, final ThreadInstance thread2, + final IcfgLocation loc2, final Term locTerm2) { + final var id1 = clause.getBodyVar(new HcThreadIdVar(thread1, mScript)); + final var id2 = clause.getBodyVar(new HcThreadIdVar(thread2, mScript)); + final var lesserConstraint = SmtUtils.less(mScript, id1.getTerm(), id2.getTerm()); + + final var locConstraint = mPreferenceOrder.getOrderConstraint(loc1, locTerm1, loc2, locTerm2, mLocationMap); + return SmtUtils.and(mScript, lesserConstraint, locConstraint); + } + + @Override + public void ensureUniqueThreadIDs(final HornClauseBuilder clause, final List instances) { + for (final var first : instances) { + final var firstId = clause.getHeadVar(new HcThreadIdVar(first, mScript)); + for (final var second : instances) { + if (!Objects.equals(first, second)) { + final var secondId = clause.getHeadVar(new HcThreadIdVar(second, mScript)); + clause.addConstraint(SmtUtils.distinct(mScript, firstId.getTerm(), secondId.getTerm())); + } + } + } + } +} \ No newline at end of file diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index c47456a2e1e..69fe7909b8d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -46,6 +46,9 @@ */ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitializer { + // SETTINGS FOR CONCURRENT PROGRAMS + // ------------------------------------------------------------------------ + public static final String LABEL_CONCURRENCY_MODE = "Concurrency mode"; public static final String DESC_CONCURRENCY_MODE = "Whether the program starts as a single thread, which may dynamically fork and join new threads, " @@ -62,6 +65,9 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize public static final String DESC_SPEC_MODE = "Describes how the specification for the program is given."; public static final SpecMode DEF_SPEC_MODE = SpecMode.POSTCONDITION; + // SETTINGS FOR THREAD-MODULAR PROOFS + // ------------------------------------------------------------------------ + public static final String LABEL_THREADMODULAR_LEVEL = "Thread-Modular Proof Level"; public static final String DESC_THREADMODULAR_LEVEL = "The level at which thread-modular proofs should be computed"; public static final int DEF_THREADMODULAR_LEVEL = 2; @@ -76,6 +82,9 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "templates, before a thread-modular proof is computed."; public static final boolean DEF_LIPTON_REDUCTION = false; + // SETTINGS FOR SLEEP SET REDUCTION + // ------------------------------------------------------------------------ + public static final String LABEL_SLEEP_SET_REDUCTION = "Enable sleep set reduction"; public static final String DESC_SLEEP_SET_REDUCTION = "If enabled, symbolic sleep set reduction is applied to the " + "program. This allows for more programs to be proven correct."; @@ -91,9 +100,16 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "or explicitly (by using different predicate symbols)."; public static final boolean DEF_EXPLICIT_SLEEP = false; + public static final String LABEL_PREFERENCE_ORDER = "Preference order used for reduction"; + public static final PreferenceOrder DEF_PREFERENCE_ORDER = PreferenceOrder.SEQ_COMP; + public static final String LABEL_CONDITIONAL_INDEPENDENCE = "Conditional Independence"; public static final ConditionalIndependence DEF_CONDITIONAL_INDEPENDENCE = ConditionalIndependence.OFF; + public enum PreferenceOrder { + SEQ_COMP, LOCKSTEP + } + public enum ConditionalIndependence { OFF, PRECOMPUTED_CONDITIONS } @@ -107,7 +123,6 @@ public IcfgToChcPreferenceInitializer() { @Override protected BaseUltimatePreferenceItem[] initDefaultPreferences() { - return new BaseUltimatePreferenceItem[] { // Settings for thread-modular proofs new UltimatePreferenceItem<>(LABEL_CONCURRENCY_MODE, DEF_CONCURRENCY_MODE, DESC_CONCURRENCY_MODE, @@ -122,11 +137,10 @@ protected BaseUltimatePreferenceItem[] initDefaultPreferences() { PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, PreferenceType.Boolean), - getSleepSetSettings() }; } - private UltimatePreferenceItemContainer getSleepSetSettings() { + private static UltimatePreferenceItemContainer getSleepSetSettings() { final var container = new UltimatePreferenceItemContainer("Sleep Set Reduction"); container.addItem(new UltimatePreferenceItem<>(LABEL_SLEEP_SET_REDUCTION, DEF_SLEEP_SET_REDUCTION, DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean)); @@ -134,6 +148,8 @@ private UltimatePreferenceItemContainer getSleepSetSettings() { DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean)); container.addItem(new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, PreferenceType.Boolean)); + container.addItem(new UltimatePreferenceItem<>(LABEL_PREFERENCE_ORDER, DEF_PREFERENCE_ORDER, + PreferenceType.Combo, PreferenceOrder.values())); container.addItem(new UltimatePreferenceItem<>(LABEL_CONDITIONAL_INDEPENDENCE, DEF_CONDITIONAL_INDEPENDENCE, PreferenceType.Combo, ConditionalIndependence.values())); return container; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 3289b5b6399..0dadfbeb972 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -29,6 +29,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer.ConditionalIndependence; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer.PreferenceOrder; public class IcfgToChcPreferences { private final IPreferenceProvider mPrefs; @@ -77,6 +78,10 @@ public boolean explicitSleep() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_SLEEP); } + public PreferenceOrder preferenceOrder() { + return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_PREFERENCE_ORDER, PreferenceOrder.class); + } + public ConditionalIndependence conditionalIndependence() { return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_CONDITIONAL_INDEPENDENCE, ConditionalIndependence.class); From d18db27d183986e19bb155d7a887c6d7dbebf9f3 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 18:34:38 +0200 Subject: [PATCH 052/114] ChcSmtPrinter: use configured file name as prefix for automatic naming --- .../ultimate/chcprinter/ChcSmtPrinterObserver.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trunk/source/ChcSmtPrinter/src/de/uni_freiburg/informatik/ultimate/chcprinter/ChcSmtPrinterObserver.java b/trunk/source/ChcSmtPrinter/src/de/uni_freiburg/informatik/ultimate/chcprinter/ChcSmtPrinterObserver.java index a40875f66f9..3396f79c561 100644 --- a/trunk/source/ChcSmtPrinter/src/de/uni_freiburg/informatik/ultimate/chcprinter/ChcSmtPrinterObserver.java +++ b/trunk/source/ChcSmtPrinter/src/de/uni_freiburg/informatik/ultimate/chcprinter/ChcSmtPrinterObserver.java @@ -167,8 +167,13 @@ private File openTempFile(final IElement root) { try { if (mServices.getPreferenceProvider(Activator.PLUGIN_ID) .getBoolean(ChcSmtPrinterPreferenceInitializer.UNIQUE_NAME_LABEL)) { + String prefix = mServices.getPreferenceProvider(Activator.PLUGIN_ID) + .getString(ChcSmtPrinterPreferenceInitializer.FILE_NAME_LABEL); + if (prefix.endsWith(".smt2")) { + prefix = prefix.substring(0, prefix.length() - ".smt2".length()); + } file = File.createTempFile( - "ChcSmtPrinter_" + new File(ILocation.getAnnotation(root).getFileName()).getName() + "_UID", + prefix + "_" + new File(ILocation.getAnnotation(root).getFileName()).getName() + "_UID", ".smt2", new File(path)); } else { filename = mServices.getPreferenceProvider(Activator.PLUGIN_ID) From 9bb48000b52d0746a9eafa030741d150295423eb Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 21:58:55 +0200 Subject: [PATCH 053/114] IndependenceChecker: properly substitute global variables --- .../concurrent/partialorder/IndependenceChecker.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java index 357be9b691b..ccba6f29c16 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -44,6 +44,7 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.Substitution; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcGlobalVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcLocalVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; @@ -127,6 +128,13 @@ private Term deinstantiate(final HornClauseBuilder clause, final ThreadInstance final var backSubstitution = new HashMap(); addBackSubstitutionMappings(clause, mLeftSubstitution, backSubstitution, thread1); addBackSubstitutionMappings(clause, mRightSubstitution, backSubstitution, thread2); + + for (final var global : mSymbolTable.getGlobals()) { + final var hcVar = new HcGlobalVar(global); + final var bodyVar = clause.getBodyVar(hcVar); + backSubstitution.put(global.getTermVariable(), bodyVar.getTermVariable()); + } + return Substitution.apply(mMgdScript, backSubstitution, term); } From b12de366c0be5a44a7f60b9354b82617efa91808 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 25 May 2023 21:59:19 +0200 Subject: [PATCH 054/114] better checking of CHCs --- .../plugins/icfgtochc/IcfgToChcObserver.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 5663c467f2b..9e3efc2ae9c 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -27,6 +27,7 @@ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import de.uni_freiburg.informatik.ultimate.core.lib.observers.BaseObserver; @@ -106,9 +107,7 @@ private void processIcfg(final IIcfg icfg) { || !IcfgUtils.getForksInLoop(icfg).isEmpty() || mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC : "Unexpected non-linear clauses"; - final var bad = resultChcs.stream() - .filter(chc -> chc.constructFormula(mgdScript, false).getFreeVars().length != 0).findAny(); - assert bad.isEmpty() : bad; + assert checkFreeVariables(resultChcs, mgdScript) : "Some clauses have free variables"; final HornAnnot annot = new HornAnnot(icfg.getIdentifier(), mgdScript, hcSymbolTable, new ArrayList<>(resultChcs), true, chcCategoryInfo); @@ -117,6 +116,18 @@ private void processIcfg(final IIcfg icfg) { ModelUtils.copyAnnotations(icfg, mResult); } + private static boolean checkFreeVariables(final Collection system, final ManagedScript mgdScript) { + for (final var clause : system) { + final var formula = clause.constructFormula(mgdScript, false); + final var freevars = formula.getFreeVars(); + if (freevars.length > 0) { + assert false : "free variables " + Arrays.toString(freevars) + " in clause " + clause; + return false; + } + } + return true; + } + private static boolean isReturnReachable(final IIcfg icfg) { return new IcfgEdgeIterator(icfg).asStream().anyMatch(IIcfgSummaryTransition.class::isInstance); } From 621497e98e83f8463a0d4950763a42bcb69f9bdb Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 26 May 2023 11:03:06 +0200 Subject: [PATCH 055/114] fix copy-paste error --- .../partialorder/SleepSetThreadModularHornClauseProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 0ad0cac89dc..5964bf36f8a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -132,7 +132,7 @@ protected HornClauseBuilder buildInductivityClause(final IcfgEdge transition, // update sleep variables for (final var instance : mInstances) { - if (preds.containsKey(updatedThread)) { + if (preds.containsKey(instance)) { // no update of sleep variable continue; } From fe2097d14844500a2ca2549c8e1a957903853f24 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 26 May 2023 11:08:31 +0200 Subject: [PATCH 056/114] add setting to allow semi-commutativity (default: true) --- .../ultimate/plugins/icfgtochc/IcfgToChcObserver.java | 2 +- .../preferences/IcfgToChcPreferenceInitializer.java | 5 +++++ .../plugins/icfgtochc/preferences/IcfgToChcPreferences.java | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 9e3efc2ae9c..b3c7a3fe855 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -162,7 +162,7 @@ private Collection getHornClauses(IIcfg icfg, final Ma } private ISymbolicIndependenceRelation getIndependence(final IIcfg icfg, final ManagedScript mgdScript) { - final boolean symmetric = true; + final boolean symmetric = !mPrefs.useSemicommutativity(); final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, symmetric); switch (mPrefs.conditionalIndependence()) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 69fe7909b8d..f4d23113601 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -106,6 +106,9 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize public static final String LABEL_CONDITIONAL_INDEPENDENCE = "Conditional Independence"; public static final ConditionalIndependence DEF_CONDITIONAL_INDEPENDENCE = ConditionalIndependence.OFF; + public static final String LABEL_SEMICOMMUTATIVITY = "Use semi-commutativity"; + public static final boolean DEF_SEMICOMMUTATIVITY = true; + public enum PreferenceOrder { SEQ_COMP, LOCKSTEP } @@ -152,6 +155,8 @@ private static UltimatePreferenceItemContainer getSleepSetSettings() { PreferenceType.Combo, PreferenceOrder.values())); container.addItem(new UltimatePreferenceItem<>(LABEL_CONDITIONAL_INDEPENDENCE, DEF_CONDITIONAL_INDEPENDENCE, PreferenceType.Combo, ConditionalIndependence.values())); + container.addItem( + new UltimatePreferenceItem<>(LABEL_SEMICOMMUTATIVITY, DEF_SEMICOMMUTATIVITY, PreferenceType.Boolean)); return container; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 0dadfbeb972..fe305fb85d0 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -86,4 +86,8 @@ public ConditionalIndependence conditionalIndependence() { return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_CONDITIONAL_INDEPENDENCE, ConditionalIndependence.class); } + + public boolean useSemicommutativity() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SEMICOMMUTATIVITY); + } } From d5022d5e9b24534c3b625c6a8ac71c1ac274db00 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 31 May 2023 11:28:30 +0200 Subject: [PATCH 057/114] prepare evaluation --- .../default/benchexec/sleep-threadmodular.xml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 releaseScripts/default/benchexec/sleep-threadmodular.xml diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml new file mode 100644 index 00000000000..5da9da01f9f --- /dev/null +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -0,0 +1,48 @@ + + + ${inputfile_path}/CHC_*.smt2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ../../../trunk/examples/threadmodular/regression/*/*.yml + ../../../trunk/examples/svcomp/properties/unreach-call.prp + + \ No newline at end of file From cab6167ce2391e67e59302329983cdbfc084bf56 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 31 May 2023 11:32:43 +0200 Subject: [PATCH 058/114] fix usage of benchexec variables --- releaseScripts/default/benchexec/sleep-threadmodular.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index 5da9da01f9f..41f9d2a8973 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -1,9 +1,9 @@ - ${inputfile_path}/CHC_*.smt2 + ${taskdef_path}/CHC_*.smt2 + From b79fc11d646c5418ee548bb10527e068f2354129 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 31 May 2023 17:25:29 +0200 Subject: [PATCH 059/114] add golem during build --- releaseScripts/default/makeZip.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/releaseScripts/default/makeZip.sh b/releaseScripts/default/makeZip.sh index adafdb93068..805b4e8cdef 100755 --- a/releaseScripts/default/makeZip.sh +++ b/releaseScripts/default/makeZip.sh @@ -48,7 +48,7 @@ if [ "$2" == "linux" ]; then echo "Building .zip for linux..." ARCH="linux" ARCHPATH="products/CLI-E4/linux/gtk/x86_64" - ADDS+=("adds/z3" "adds/cvc4nyu" "adds/cvc4" "adds/mathsat") + ADDS+=("adds/z3" "adds/cvc4nyu" "adds/cvc4" "adds/mathsat" "adds/golem") elif [ "$2" == "win32" ]; then echo "Building .zip for win32..." ARCH="win32" From 30509f967a259899c3d17e25b1ce1777af0053d2 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 31 May 2023 17:26:00 +0200 Subject: [PATCH 060/114] TreeAutomizer: must not use Z3 (no longer supports interpolation) --- releaseScripts/default/benchexec/sleep-threadmodular.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index 41f9d2a8973..c325a66db38 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -35,6 +35,7 @@ + From 645efe7f51fb341dede3cd5950a2f22405dd04ec Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 31 May 2023 17:46:34 +0200 Subject: [PATCH 061/114] temporarily disable check that crashes UniHorn --- .../coreplugin/services/ModelTranslationContainer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java b/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java index 7a0a60c4de5..64888c17525 100644 --- a/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java +++ b/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java @@ -60,9 +60,11 @@ public void addTranslator(final ITranslator 0) { final ITranslator last = mTranslationSequence.getLast(); if (!isAllowedNext(last, translator)) { - throw new IllegalArgumentException( - "The supplied ITranslator is not compatible with the existing ones. It has to be compatible with " - + last + ", but it is " + translator); + // TODO a temporary change to allow UniHorn to run on generated CHCs + // throw new IllegalArgumentException( + // "The supplied ITranslator is not compatible with the existing ones. It has to be compatible with " + // + last + ", but it is " + translator); + return; } } mTranslationSequence.addLast(translator); From ff2fe8766f4565c79bcb155b21cb08dc19cbd358 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 6 Jun 2023 15:21:34 +0200 Subject: [PATCH 062/114] improve Z3 CHC integration - ChcSolver: create a fresh Z3 instance - SmtChcScript: support clauses built with a different script than the backend solver, by transferring them if necessary. Backtranslation of models is still missing. - ChcSolver: allow specifying a timeout --- .../plugins/chcsolver/ChcSolverObserver.java | 38 +++- .../ChcSolverPreferenceInitializer.java | 7 + .../preferences/ChcSolverPreferences.java | 4 + .../ultimate/lib/chc/ChcTransferrer.java | 205 ++++++++++++++++++ .../ultimate/lib/chc/SmtChcScript.java | 28 ++- 5 files changed, 275 insertions(+), 7 deletions(-) create mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java index 7a8f66a40d5..04f84aafadb 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java @@ -45,6 +45,11 @@ import de.uni_freiburg.informatik.ultimate.lib.chc.results.ChcSatResult; import de.uni_freiburg.informatik.ultimate.lib.chc.results.ChcUnknownResult; import de.uni_freiburg.informatik.ultimate.lib.chc.results.ChcUnsatResult; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.solverbuilder.SolverBuilder; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.solverbuilder.SolverBuilder.ExternalSolver; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.solverbuilder.SolverBuilder.SolverMode; +import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.logic.Model; import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; import de.uni_freiburg.informatik.ultimate.plugins.chcsolver.preferences.ChcSolverPreferences; @@ -74,7 +79,13 @@ public boolean process(final IElement root) throws Throwable { final IChcScript chcScript = getBackend(annot); configureBackend(chcScript); - final var satisfiability = chcScript.solve(annot.getSymbolTable(), annot.getHornClauses()); + final LBool satisfiability; + if (mPrefs.getTimeout() > 0) { + satisfiability = chcScript.solve(annot.getSymbolTable(), annot.getHornClauses(), mPrefs.getTimeout()); + } else { + satisfiability = chcScript.solve(annot.getSymbolTable(), annot.getHornClauses()); + } + final IResult result = createResult(chcScript, satisfiability); mServices.getResultService().reportResult(Activator.PLUGIN_ID, result); @@ -90,9 +101,7 @@ private IChcScript getBackend(final HornAnnot annotation) { case ELDARICA: return new EldaricaChcScript(mServices, annotation.getScript().getScript()); case Z3: - // We use the script given in the annotation. For this to work, that script should use Z3. - // To use a fresh Z3 instance for solving instead, one has to transfer the Horn clause terms to that script. - return new SmtChcScript(annotation.getScript()); + return createZ3Backend(); case TREEAUTOMIZER: // NOTE: TAPreferences (last parameter) currently unused by TreeAutomizer return new TreeAutomizerChcScript(mServices, annotation.getScript(), null); @@ -103,6 +112,27 @@ private IChcScript getBackend(final HornAnnot annotation) { } } + private SmtChcScript createZ3Backend() { + // We use a fresh Z3 instance to solve the system. + // In typical toolchains, the solver in the HornAnnot is often unsuitable: + // + // (1) It may not be a Z3 instance. + // (2) The query timeout may be very low. + // (3) Another logic may have been set. + // + // SmtChcScript internally detects that a different script was used, and transfers the terms. + + final var timeout = mPrefs.getTimeout() > 0 ? mPrefs.getTimeout() : -1L; + final var mode = mPrefs.produceModels() ? SolverMode.External_ModelsMode : SolverMode.External_DefaultMode; + final var settings = SolverBuilder.constructSolverSettings().setSolverMode(mode) + .setUseExternalSolver(ExternalSolver.Z3, Logics.HORN, timeout); + + final var solver = SolverBuilder.buildAndInitializeSolver(mServices, settings, "Z3-CHC"); + final var mgdSolver = new ManagedScript(mServices, solver); + + return new SmtChcScript(mgdSolver); + } + private void configureBackend(final IChcScript backend) { if (backend.supportsModelProduction()) { backend.produceModels(mPrefs.produceModels()); diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java index 7be255e1b5c..faa51061e31 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java @@ -46,6 +46,11 @@ public enum SolverBackend { public static final String LABEL_CHC_BACKEND = "CHC solver backend"; private static final SolverBackend DEF_CHC_BACKEND = SolverBackend.ELDARICA; + public static final String LABEL_SOLVER_TIMEOUT = "Timeout"; + private static final String DESC_SOLVER_TIMEOUT = + "Timeout for solving an entire CHC system (in ms). 0 means no timeout."; + private static final int DEF_SOLVER_TIMEOUT = 0; + public static final String LABEL_PRODUCE_MODEL = "Produce CHC model if query is SAT"; private static final boolean DEF_PRODUCE_MODEL = true; @@ -64,6 +69,8 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { return new UltimatePreferenceItem[] { new UltimatePreferenceItem<>(LABEL_CHC_BACKEND, DEF_CHC_BACKEND, PreferenceType.Combo, SolverBackend.values()), + new UltimatePreferenceItem<>(LABEL_SOLVER_TIMEOUT, DEF_SOLVER_TIMEOUT, DESC_SOLVER_TIMEOUT, + PreferenceType.Integer), new UltimatePreferenceItem<>(LABEL_PRODUCE_MODEL, DEF_PRODUCE_MODEL, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_PRODUCE_DERIVATION, DEF_PRODUCE_DERIVATION, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_PRODUCE_UNSAT_CORES, DEF_PRODUCE_UNSAT_CORES, diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java index 62d4f81fe57..4a98f94dd64 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java @@ -52,4 +52,8 @@ public boolean produceDerivation() { public boolean produceUnsatCore() { return mPrefs.getBoolean(ChcSolverPreferenceInitializer.LABEL_PRODUCE_UNSAT_CORES); } + + public long getTimeout() { + return mPrefs.getInt(ChcSolverPreferenceInitializer.LABEL_SOLVER_TIMEOUT); + } } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java new file mode 100644 index 00000000000..c1282353bd6 --- /dev/null +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE CHC Library. + * + * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.lib.chc; + +import java.util.List; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.scripttransfer.TermTransferrer; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.logic.Model; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Sort; +import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; + +/** + * A class to transfer CHC systems between scripts, and to transfer back the results of CHC satisfiability checks. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + */ +public class ChcTransferrer { + private final Script mOriginalScript; + private final ManagedScript mTargetScript; + + private final HcSymbolTable mOriginalSymbolTable; + private final HcSymbolTable mTargetSymbolTable; + + private final TermTransferrer mTransferrer; + private final BidirectionalMap mPredMapping = new BidirectionalMap<>(); + private final BidirectionalMap mClauseMapping = new BidirectionalMap<>(); + + public ChcTransferrer(final Script originalScript, final ManagedScript targetScript, + final HcSymbolTable symbolTable) { + mOriginalScript = originalScript; + mTargetScript = targetScript; + mTransferrer = new TermTransferrer(originalScript, targetScript.getScript()); + + mOriginalSymbolTable = symbolTable; + mTargetSymbolTable = transfer(symbolTable); + } + + public HornAnnot transfer(final HornAnnot annot) { + assert annot.getSymbolTable() == mOriginalSymbolTable; + final var clauses = annot.getHornClauses().stream().map(this::transfer).collect(Collectors.toList()); + return new HornAnnot(annot.getFileName(), mTargetScript, mTargetSymbolTable, clauses, annot.hasCheckSat(), + annot.getChcCategoryInfo()); + } + + private HcSymbolTable transfer(final HcSymbolTable symbolTable) { + final var transferredTable = new HcSymbolTable(mTargetScript); + // TODO transfer components? + return transferredTable; + } + + public HcPredicateSymbol transfer(final HcPredicateSymbol predicate) { + final var sorts = + predicate.getParameterSorts().stream().map(mTransferrer::transferSort).collect(Collectors.toList()); + return mTargetSymbolTable.getOrConstructHornClausePredicateSymbol(predicate.getName(), sorts); + } + + public T transfer(final T var) { + if (var instanceof HcBodyAuxVar) { + throw new UnsupportedOperationException("HcBodyAuxVar not yet supported"); + } + if (var instanceof HcBodyVar) { + return (T) transfer((HcBodyVar) var); + } + if (var instanceof HcHeadVar) { + return (T) transfer((HcHeadVar) var); + } + throw new AssertionError( + "Unknown type of variable: " + (var == null ? "null" : var.getClass().getSimpleName())); + } + + public HcBodyVar transfer(final HcBodyVar var) { + return transfer(var, mTargetSymbolTable::getOrConstructBodyVar); + } + + public HcHeadVar transfer(final HcHeadVar var) { + return transfer(var, mTargetSymbolTable::getOrConstructHeadVar); + } + + private T transfer(final T var, final BiFunction getOrConstruct) { + final var copy = getOrConstruct.apply(var, mTransferrer.transferSort(var.getSort())); + final var oldMapping = mTransferrer.getTransferMapping().get(var.getTermVariable()); + if (oldMapping != null && oldMapping != copy.getTermVariable()) { + throw new IllegalStateException("Variable already mapped: " + var); + } + mTransferrer.getTransferMapping().put(var.getTermVariable(), copy.getTermVariable()); + return copy; + + } + + public HornClause transfer(final HornClause clause) { + return mClauseMapping.computeIfAbsent(clause, c -> { + final var bodyVars = clause.getBodyVariables().stream().map(this::transfer).collect(Collectors.toSet()); + final List headVars; + if (!clause.isHeadFalse()) { + headVars = + clause.getTermVariablesForHeadPred().stream().map(this::transfer).collect(Collectors.toList()); + + } else { + headVars = null; + } + + final var constraint = transfer(clause.getConstraintFormula()); + final var bodyPreds = clause.getBodyPredicates().stream().map(this::transfer).collect(Collectors.toList()); + final var bodyArgs = clause.getBodyPredToArgs().stream() + .map(args -> args.stream().map(this::transfer).collect(Collectors.toList())) + .collect(Collectors.toList()); + if (clause.isHeadFalse()) { + return new HornClause(mTargetScript, mTargetSymbolTable, constraint, bodyPreds, bodyArgs, bodyVars); + } + + final var head = transfer(clause.getHeadPredicate()); + return new HornClause(mTargetScript, mTargetSymbolTable, constraint, head, headVars, bodyPreds, bodyArgs, + bodyVars); + }); + } + + private Term transfer(final Term term) { + return mTransferrer.transform(term); + } + + public ChcSolution transferBack(final ChcSolution solution) { + switch (solution.getSatisfiability()) { + case UNKNOWN: + // nothing to transfer + return solution; + case SAT: + final var originalModel = solution.getModel(); + final var model = originalModel == null ? null : transferBack(originalModel); + return ChcSolution.sat(model); + case UNSAT: + final var originalDerivation = solution.getDerivation(); + final var derivation = originalDerivation == null ? null : transferBack(originalDerivation); + final var originalUnsatCore = solution.getUnsatCore(); + final var unsatCore = originalUnsatCore == null ? null : transferBack(originalUnsatCore); + return ChcSolution.unsat(derivation, unsatCore); + } + throw new AssertionError("unknown satisfiability value: " + solution.getSatisfiability()); + } + + public Model transferBack(final Model model) { + // TODO + throw new UnsupportedOperationException("not yet implemented"); + } + + public Derivation transferBack(final Derivation derivation) { + final var predicate = transferBack(derivation.getPredicate()); + final var arguments = derivation.getArguments().stream().map(this::transferBack).collect(Collectors.toList()); + final var clause = transferBack(derivation.getClause()); + final var children = derivation.getChildren().stream().map(this::transferBack).collect(Collectors.toList()); + return new Derivation(predicate, arguments, clause, children); + } + + public Set transferBack(final Set unsatCore) { + return unsatCore.stream().map(this::transferBack).collect(Collectors.toSet()); + } + + public HornClause transferBack(final HornClause clause) { + if (!mClauseMapping.containsValue(clause)) { + throw new IllegalArgumentException("Clause was not transferred by this instance: " + clause); + } + return mClauseMapping.inverse().get(clause); + } + + public HcPredicateSymbol transferBack(final HcPredicateSymbol predicate) { + if (!mPredMapping.containsValue(predicate)) { + throw new IllegalArgumentException("Predicate symbol was not transferred by this instance: " + predicate); + } + return mPredMapping.inverse().get(predicate); + } + + private Term transferBack(final Term term) { + // TODO + throw new UnsupportedOperationException("not yet implemented"); + } +} diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java index 3089a118290..42174734667 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; @@ -57,6 +58,7 @@ public class SmtChcScript implements IChcScript, AutoCloseable { private boolean mProduceUnsatCores; private boolean mIsPushed; + private ChcTransferrer mTransferrer; private Map mName2Clause; public SmtChcScript(final ManagedScript mgdScript) { @@ -76,9 +78,18 @@ public LBool solve(final HcSymbolTable symbolTable, final List syste mIsPushed = true; mMgdScript.unlock(this); + + final List assertedSystem; + if (mMgdScript == symbolTable.getManagedScript()) { + assertedSystem = system; + } else { + mTransferrer = new ChcTransferrer(symbolTable.getManagedScript().getScript(), mMgdScript, symbolTable); + assertedSystem = system.stream().map(mTransferrer::transfer).collect(Collectors.toList()); + } + final var asserter = new ChcAsserter(mMgdScript, getScript(), mProduceUnsatCores, ADD_COMMENTS, DECLARE_FUNCTIONS); - asserter.assertClauses(symbolTable, system); + asserter.assertClauses(symbolTable, assertedSystem); mMgdScript.lock(this); mName2Clause = asserter.getName2Clause(); @@ -114,7 +125,14 @@ public void produceModels(final boolean enable) { @Override public Optional getModel() { - return Optional.ofNullable(getScript().getModel()); + final var model = getScript().getModel(); + if (model == null) { + return Optional.empty(); + } + if (mTransferrer == null) { + return Optional.of(model); + } + return Optional.of(mTransferrer.transferBack(model)); } @Override @@ -150,13 +168,17 @@ public Optional> getUnsatCore() { for (final var term : core) { assert term instanceof ApplicationTerm : "Expected only term names in UNSAT core, but got " + term; final var name = ((ApplicationTerm) term).getFunction().getName(); - result.add(mName2Clause.get(name)); + final var assertedClause = mName2Clause.get(name); + final var originalClause = + mTransferrer == null ? assertedClause : mTransferrer.transferBack(assertedClause); + result.add(originalClause); } return Optional.of(result); } private void reset() { mName2Clause = null; + mTransferrer = null; if (mIsPushed) { mMgdScript.pop(this, 1); } From 1f01ed6afdf0a8b0a8640238a164df6272a52deb Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 7 Jun 2023 10:06:00 +0200 Subject: [PATCH 063/114] SmtChcScript: avoid push/pop push/pop leads to more UNKNOWN results for Z3. Instead, we use reset. --- .../ultimate/lib/chc/SmtChcScript.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java index 42174734667..b754e4c774b 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java @@ -35,6 +35,7 @@ import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; +import de.uni_freiburg.informatik.ultimate.logic.Logics; import de.uni_freiburg.informatik.ultimate.logic.Model; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Script; @@ -55,9 +56,9 @@ public class SmtChcScript implements IChcScript, AutoCloseable { private static final boolean DECLARE_FUNCTIONS = false; private final ManagedScript mMgdScript; + private boolean mProduceModels; private boolean mProduceUnsatCores; - private boolean mIsPushed; private ChcTransferrer mTransferrer; private Map mName2Clause; @@ -74,9 +75,6 @@ public Script getScript() { @Override public LBool solve(final HcSymbolTable symbolTable, final List system) { reset(); - mMgdScript.push(this, 1); - mIsPushed = true; - mMgdScript.unlock(this); final List assertedSystem; @@ -120,7 +118,7 @@ public boolean supportsModelProduction() { @Override public void produceModels(final boolean enable) { - getScript().setOption(SMTLIBConstants.PRODUCE_MODELS, enable); + mProduceModels = enable; } @Override @@ -157,7 +155,6 @@ public boolean supportsUnsatCores() { @Override public void produceUnsatCores(final boolean enable) { - getScript().setOption(SMTLIBConstants.PRODUCE_UNSAT_CORES, enable); mProduceUnsatCores = enable; } @@ -179,9 +176,11 @@ public Optional> getUnsatCore() { private void reset() { mName2Clause = null; mTransferrer = null; - if (mIsPushed) { - mMgdScript.pop(this, 1); - } + + getScript().reset(); + getScript().setLogic(Logics.HORN); + getScript().setOption(SMTLIBConstants.PRODUCE_MODELS, mProduceModels); + getScript().setOption(SMTLIBConstants.PRODUCE_UNSAT_CORES, mProduceUnsatCores); } @Override From 27c56ed58b70aad5e2a2df4f5b5ba84c745a1f2c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 8 Jun 2023 09:02:14 +0200 Subject: [PATCH 064/114] fix typos in method names --- .../plugins/chctoboogie/GenerateBoogieAstHelper.java | 2 +- .../ultimate/plugins/chctoboogie/GenerateGotoBoogieAst.java | 2 +- .../uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java | 2 +- .../informatik/ultimate/lib/chc/HcSymbolTable.java | 2 +- .../informatik/ultimate/lib/chc/HornUtilConstants.java | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateBoogieAstHelper.java b/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateBoogieAstHelper.java index 8c53b898e97..9dbca46b284 100644 --- a/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateBoogieAstHelper.java +++ b/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateBoogieAstHelper.java @@ -262,7 +262,7 @@ public Expression getDummyArgForArraySort(final Sort sort) { String varName = mArraySortToDummyVarName.get(sort); if (varName == null) { final String dummyArrayPrefix = "#dummy~"; - varName = dummyArrayPrefix + HornUtilConstants.sanitzeSortNameForBoogie(sort); + varName = dummyArrayPrefix + HornUtilConstants.sanitizeSortNameForBoogie(sort); mArraySortToDummyVarName.put(sort, varName); } return ExpressionFactory.constructIdentifierExpression(mLocation, getType(sort), varName, DeclarationInformation.DECLARATIONINFO_GLOBAL); diff --git a/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateGotoBoogieAst.java b/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateGotoBoogieAst.java index f3354878f9f..0f5cea114e6 100644 --- a/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateGotoBoogieAst.java +++ b/trunk/source/ChcToBoogie/src/de/uni_freiburg/informatik/ultimate/plugins/chctoboogie/GenerateGotoBoogieAst.java @@ -497,7 +497,7 @@ Expression getArgumentVarExp(final int index, final Sort sort) { private boolean constructArgumentVarId(final int index, final Sort sort) { String result = mIndexToSortToGotoProcArgId.get(index, sort); if (result == null) { - result = "gpav_" + index + "_" + HornUtilConstants.sanitzeSortNameForBoogie(sort); + result = "gpav_" + index + "_" + HornUtilConstants.sanitizeSortNameForBoogie(sort); mIndexToSortToGotoProcArgId.put(index, sort, result); return true; } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java index 450c99a65f0..d525ae9191e 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcPredVar.java @@ -24,7 +24,7 @@ public abstract class HcPredVar extends HcVar { super(globallyUniqueId, mgdScript.variable(globallyUniqueId, sort), ProgramVarUtils.constructDefaultConstant(mgdScript, lockOwner, sort, globallyUniqueId), ProgramVarUtils.constructPrimedConstant(mgdScript, lockOwner, sort, globallyUniqueId), headNotBody, - HornUtilConstants.sanitzePredName(procName)); + HornUtilConstants.sanitizePredName(procName)); mIndex = index; } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java index a44155b43d1..193311f58f0 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java @@ -419,7 +419,7 @@ public ILocation getLocation(final IProgramVar pv) { } public String getMethodNameForPredSymbol(final HcPredicateSymbol predSym) { - return HornUtilConstants.sanitzePredName(predSym.getName()); + return HornUtilConstants.sanitizePredName(predSym.getName()); } public List getHcHeadVarsForPredSym(final HcPredicateSymbol bodySymbol, diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java index a05281d3395..d762a16b26e 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornUtilConstants.java @@ -60,7 +60,7 @@ private HornUtilConstants() { public static String computeNameForHcVar(final String prefix, final HcPredicateSymbol predSym, final int index, final String identifier) { - final String name = HornUtilConstants.sanitzePredName(predSym.getName()); + final String name = HornUtilConstants.sanitizePredName(predSym.getName()); final String identifierString = identifier.replaceAll(" ", "_").replaceAll("[()]", ""); return String.format("%s_%s_%s_%d", prefix, name, identifierString, index); } @@ -76,7 +76,7 @@ public static String computeNameForHcVar(final String prefix, final String ident * @param headPredSymProcNameRaw * @return */ - public static String sanitzePredName(final String headPredSymProcNameRaw) { + public static String sanitizePredName(final String headPredSymProcNameRaw) { assert !headPredSymProcNameRaw.contains(".CLN") : "naming might clash"; assert !headPredSymProcNameRaw.contains(".DLR") : "naming might clash"; assert !headPredSymProcNameRaw.contains(".AT") : "naming might clash"; @@ -86,7 +86,7 @@ public static String sanitzePredName(final String headPredSymProcNameRaw) { .replaceAll("\\$", ".DLR").replaceAll(":", ".CLN"); } - public static String sanitzeSortNameForBoogie(final Sort sort) { + public static String sanitizeSortNameForBoogie(final Sort sort) { assert !sort.toString().contains(".OP") : "naming might clash"; assert !sort.toString().contains(".CP") : "naming might clash"; return sort.toString().replaceAll("\\(", ".OP").replaceAll("\\)", ".CP").replaceAll(" ", "_"); From 7dddfbb61321e0830090c5a384d3d82015ed829c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 8 Jun 2023 09:10:33 +0200 Subject: [PATCH 065/114] bugfix: record HcBodyVar for each term variable --- .../informatik/ultimate/lib/chc/HcSymbolTable.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java index 193311f58f0..241619094b6 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java @@ -337,6 +337,7 @@ public HcBodyVar getOrConstructBodyVar(final Object identifier, final Sort sort) final var result = new HcBodyVar(globallyUniqueId, DUMMY_PRED_NAME, DUMMY_PRED_INDEX, transferredSort, mManagedScript, this); mManagedScript.unlock(this); + mTermVarToProgramVar.put(result.getTermVariable(), result); return result; }); } @@ -392,7 +393,7 @@ public Map getSmtFunction2BoogieFunction() { @Override public IProgramVar getProgramVar(final TermVariable tv) { final IProgramVar result = mTermVarToProgramVar.get(tv); - assert result != null; + assert result != null : "No IProgramVar found for term variable: " + tv; return result; } From 15814dd4be1574fb49d0ab918d1407d1bd8eec9f Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 8 Jun 2023 09:18:25 +0200 Subject: [PATCH 066/114] construct HcHeadVars that reference the proper predicate and index Our own solvers (UniHorn and TreeAutomizer) heavily rely on the predicate and index stored in HcPredVars. Thus they fail on the clauses generated so far. This commit corrects the creation of HcHeadVars. --- .../concurrent/HornClauseBuilder.java | 7 ++++- .../icfgtochc/concurrent/PredicateInfo.java | 3 +- .../ultimate/lib/chc/ChcTransferrer.java | 28 +++++++++++++++++-- .../ultimate/lib/chc/HcSymbolTable.java | 16 +---------- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 37b178ddd4b..9eef5ef7916 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -92,7 +92,12 @@ public HcHeadVar getHeadVar(final IHcReplacementVar variable) { assert mHeadPredicate != null : "Clause does not have head predicate"; assert mHeadPredicate.hasParameter(variable) : "Predicate " + mHeadPredicate.getPredicate() + " does not have parameter " + variable; - return mSymbolTable.getOrConstructHeadVar(variable, variable.getSort()); + + final int index = mHeadPredicate.getParameters().indexOf(variable); + assert index >= 0 && index < mHeadPredicate.getParamCount() : "Invalid parameter index for " + variable + + " in predicate " + mHeadPredicate.getPredicate(); + + return mSymbolTable.getOrConstructHeadVar(mHeadPredicate.getPredicate(), index, variable.getSort(), variable); } public void differentBodyHeadVar(final IHcReplacementVar variable) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java index 08a271885d8..00a3da3eabb 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/PredicateInfo.java @@ -26,7 +26,6 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent; -import java.util.Collection; import java.util.List; import java.util.Objects; @@ -45,7 +44,7 @@ public HcPredicateSymbol getPredicate() { return mPredicate; } - public Collection getParameters() { + public List getParameters() { return mParameters; } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index c1282353bd6..29e628b6cc0 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -99,14 +99,37 @@ public T transfer(final T var) { } public HcBodyVar transfer(final HcBodyVar var) { - return transfer(var, mTargetSymbolTable::getOrConstructBodyVar); + return transferOld(var, mTargetSymbolTable::getOrConstructBodyVar); } public HcHeadVar transfer(final HcHeadVar var) { return transfer(var, mTargetSymbolTable::getOrConstructHeadVar); } - private T transfer(final T var, final BiFunction getOrConstruct) { + private interface IHcVarConstructor { + T getOrConstruct(HcPredicateSymbol pred, int index, Sort sort, Object identifier); + } + + private T transfer(final T variable, final IHcVarConstructor constructor) { + final var optPredicate = mPredMapping.entrySet().stream() + .filter(e -> HornUtilConstants.sanitizePredName(e.getKey().getName()).equals(variable.getProcedure())) + .findAny(); + assert optPredicate.isPresent() : "Could not find predicate for " + variable; + final var predicate = optPredicate.get().getValue(); + + final var sort = mTransferrer.transferSort(variable.getSort()); + final var copy = constructor.getOrConstruct(predicate, variable.getIndex(), sort, variable); + + final var oldMapping = mTransferrer.getTransferMapping().get(variable.getTermVariable()); + if (oldMapping != null && oldMapping != copy.getTermVariable()) { + throw new IllegalStateException("Variable already mapped: " + variable); + } + mTransferrer.getTransferMapping().put(variable.getTermVariable(), copy.getTermVariable()); + return copy; + } + + @Deprecated + private T transferOld(final T var, final BiFunction getOrConstruct) { final var copy = getOrConstruct.apply(var, mTransferrer.transferSort(var.getSort())); final var oldMapping = mTransferrer.getTransferMapping().get(var.getTermVariable()); if (oldMapping != null && oldMapping != copy.getTermVariable()) { @@ -114,7 +137,6 @@ private T transfer(final T var, final BiFunction g } mTransferrer.getTransferMapping().put(var.getTermVariable(), copy.getTermVariable()); return copy; - } public HornClause transfer(final HornClause clause) { diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java index 241619094b6..5ab311d3f79 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HcSymbolTable.java @@ -59,7 +59,6 @@ public class HcSymbolTable extends DefaultIcfgSymbolTable implements ITerm2Expre final Map mVersionsMap; private final Map mBodyVars = new HashMap<>(); - private final Map mHeadVars = new HashMap<>(); private final NestedMap3 mPredSymNameToIndexToSortToHcHeadVar; private final NestedMap3 mPredSymNameToIndexToSortToHcBodyVar; private final Map mTermVariableToHcBodyAuxVar; @@ -290,20 +289,6 @@ public HcHeadVar getOrConstructHeadVar(final HcPredicateSymbol predSym, final in return getOrConstructHeadVar(predSym, index, pv.getSort(), pv); } - public HcHeadVar getOrConstructHeadVar(final Object identifier, final Sort sort) { - return mHeadVars.computeIfAbsent(identifier, id -> { - final Sort transferredSort = transferSort(sort); - final String globallyUniqueId = - HornUtilConstants.computeNameForHcVar(HornUtilConstants.HEADVARPREFIX, id.toString()); - mManagedScript.lock(this); - final var result = new HcHeadVar(globallyUniqueId, DUMMY_PRED_NAME, DUMMY_PRED_INDEX, transferredSort, - mManagedScript, this); - mManagedScript.unlock(this); - mTermVarToProgramVar.put(result.getTermVariable(), result); - return result; - }); - } - public HcBodyVar getOrConstructBodyVar(final HcPredicateSymbol predSym, final int index, final Sort sort, final Object identfier) { final Sort transferredSort = transferSort(sort); @@ -328,6 +313,7 @@ public HcBodyVar getOrConstructBodyVar(final HcPredicateSymbol predSym, final in return getOrConstructBodyVar(predSym, index, pv.getSort(), pv); } + @Deprecated public HcBodyVar getOrConstructBodyVar(final Object identifier, final Sort sort) { return mBodyVars.computeIfAbsent(identifier, id -> { final Sort transferredSort = transferSort(sort); From dca59feabafc2057d95efcd162767a45ea577f9c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 8 Jun 2023 10:22:57 +0200 Subject: [PATCH 067/114] eldarica: properly handle scala objects --- .../ultimate/lib/chc/eldarica/EldaricaChcScript.java | 4 ++-- .../informatik/ultimate/lib/chc/eldarica/Translator.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java index 9932ad1d324..18ac2a765cf 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java @@ -129,7 +129,7 @@ public LBool solve(final HcSymbolTable symbolTable, final java.util.List actualTimeout.get())) { // Nasty hack to trick java into throwing TimeoutException, a checked exception. // (This is necessary, because scala does not declare checked exceptions.) - throwUnchecked(new lazabs.Main.TimeoutException$()); + throwUnchecked(lazabs.Main.TimeoutException$.MODULE$); } return scala.runtime.BoxedUnit.UNIT; } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java index 1418f0fcd3b..e895fb5d84c 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java @@ -139,10 +139,10 @@ private Predicate createPredicate(final HcPredicateSymbol pred) { private ap.types.Sort translateSort(final Sort sort) { if (SmtSortUtils.isIntSort(sort)) { - return new ap.types.Sort.Integer$(); + return ap.types.Sort.Integer$.MODULE$; } if (SmtSortUtils.isBoolSort(sort)) { - return new ap.types.Sort.MultipleValueBool$(); + return ap.types.Sort.MultipleValueBool$.MODULE$; } if (SmtSortUtils.isArraySort(sort)) { return getArrayTheory(sort).sort(); @@ -169,7 +169,7 @@ private ExtArray getArrayTheory(final Sort arraySort) { public IFormula translateFormula(final Term term) { final var expr = translateExpression(term); if (expr instanceof ITerm) { - return new ap.types.Sort.MultipleValueBool$().isTrue((ITerm) expr); + return ap.types.Sort.MultipleValueBool$.MODULE$.isTrue((ITerm) expr); } return (IFormula) translateExpression(term); } @@ -177,7 +177,7 @@ public IFormula translateFormula(final Term term) { public ITerm translateTerm(final Term term) { final var expr = translateExpression(term); if (expr instanceof IFormula) { - final var bool = new ap.types.Sort.MultipleValueBool$(); + final var bool = ap.types.Sort.MultipleValueBool$.MODULE$; return IExpression.ite((IFormula) expr, bool.True(), bool.False()); } return (ITerm) translateExpression(term); From 7573845932786a91e6e9d4d8b27408aac62c2125 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 8 Jun 2023 12:15:20 +0200 Subject: [PATCH 068/114] fix SMT solver setting: TreeAutomizer ignores its own settings --- releaseScripts/default/benchexec/sleep-threadmodular.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index c325a66db38..d2f2d9fb903 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -35,7 +35,7 @@ - + From a13f12b084de4b50ffc47cd038d5c14ab54fe97b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 9 Jun 2023 10:31:08 +0200 Subject: [PATCH 069/114] add an IChcScript to invoke eldarica via command line The current EldaricaChcScript does not work well, we are using the wrong entry point to eldarica. Until we have figured out the right one, invoking eldarica via command line will seemingly give better results. This is a temporary solution. We should ideally find the right entry point, or at least some other way that is not this platform-dependent. --- .../plugins/chcsolver/ChcSolverObserver.java | 5 +- .../lib/chc/EldaricaCliChcScript.java | 185 ++++++++++++++++++ 2 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java index 04f84aafadb..a3e47198161 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java @@ -35,13 +35,13 @@ import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.ChcSolution; import de.uni_freiburg.informatik.ultimate.lib.chc.Derivation; +import de.uni_freiburg.informatik.ultimate.lib.chc.EldaricaCliChcScript; import de.uni_freiburg.informatik.ultimate.lib.chc.GolemChcScript; import de.uni_freiburg.informatik.ultimate.lib.chc.HornAnnot; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClauseAST; import de.uni_freiburg.informatik.ultimate.lib.chc.IChcScript; import de.uni_freiburg.informatik.ultimate.lib.chc.SmtChcScript; -import de.uni_freiburg.informatik.ultimate.lib.chc.eldarica.EldaricaChcScript; import de.uni_freiburg.informatik.ultimate.lib.chc.results.ChcSatResult; import de.uni_freiburg.informatik.ultimate.lib.chc.results.ChcUnknownResult; import de.uni_freiburg.informatik.ultimate.lib.chc.results.ChcUnsatResult; @@ -99,7 +99,8 @@ public boolean process(final IElement root) throws Throwable { private IChcScript getBackend(final HornAnnot annotation) { switch (mPrefs.getBackend()) { case ELDARICA: - return new EldaricaChcScript(mServices, annotation.getScript().getScript()); + // return new EldaricaChcScript(mServices, annotation.getScript().getScript()); + return new EldaricaCliChcScript(mServices, annotation.getScript()); case Z3: return createZ3Backend(); case TREEAUTOMIZER: diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java new file mode 100644 index 00000000000..f2851450731 --- /dev/null +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE CHC Library. + * + * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.lib.chc; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Optional; +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.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.logic.LoggingScript; +import de.uni_freiburg.informatik.ultimate.logic.Logics; +import de.uni_freiburg.informatik.ultimate.logic.Model; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.Executor; + +public class EldaricaCliChcScript implements IChcScript { + private static final boolean ADD_CLAUSE_NAMES = false; + private static final boolean ADD_COMMENTS = false; + private static final boolean DECLARE_FUNCTIONS = true; + private static final boolean USE_PORTFOLIO = false; + private static final boolean USE_DISJUNCTIVE_INTERP = true; + + private final IUltimateServiceProvider mServices; + private final ILogger mLogger; + private final ManagedScript mMgdScript; + private final long mDefaultQueryTimeout; + + private boolean mProduceModels = false; + + private LBool mLastResult; + private Model mLastModel = null; + + public EldaricaCliChcScript(final IUltimateServiceProvider services, final ManagedScript mgdScript) { + this(services, mgdScript, -1L); + } + + public EldaricaCliChcScript(final IUltimateServiceProvider services, final ManagedScript mgdScript, + final long defaultTimeout) { + mServices = services; + mLogger = services.getLoggingService().getLogger(getClass()); + mMgdScript = mgdScript; + mDefaultQueryTimeout = defaultTimeout; + } + + @Override + public Script getScript() { + return mMgdScript.getScript(); + } + + @Override + public LBool solve(final HcSymbolTable symbolTable, final List system) { + return solve(symbolTable, system, -1L); + } + + @Override + public LBool solve(final HcSymbolTable symbolTable, final List system, final long timeout) { + // generate file with Horn clauses + final File tmpFile; + try { + tmpFile = File.createTempFile("eldarica_", ".smt2"); + mLogger.info("Writing script to file " + tmpFile.getAbsolutePath()); + + final var dumperScript = new LoggingScript(tmpFile.getAbsolutePath(), true); + dumperScript.setLogic(Logics.HORN); + + new ChcAsserter(mMgdScript, dumperScript, ADD_CLAUSE_NAMES, ADD_COMMENTS, DECLARE_FUNCTIONS) + .assertClauses(symbolTable, system); + dumperScript.checkSat(); + } catch (final IOException e) { + throw new RuntimeException(e); + } + + try { + // run eldarica on file + final var executor = new Executor(getCommand(tmpFile), mMgdScript.getScript(), mLogger, mServices, + "eldarica", null, null, null, determineTimeout(timeout)); + + mLastResult = executor.parseCheckSatResult(); + mLastModel = (mLastResult == LBool.SAT && mProduceModels) ? executor.parseGetModelResult() : null; + + return mLastResult; + + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + private String getCommand(final File file) { + var command = "eld"; + if (USE_PORTFOLIO) { + command += " -portfolio"; + } + if (USE_DISJUNCTIVE_INTERP) { + command += " -disj"; + } + if (mProduceModels) { + command += " -ssol"; + } + return command + " " + file.getAbsolutePath(); + } + + @Override + public boolean supportsModelProduction() { + return true; + } + + @Override + public void produceModels(final boolean enable) { + mProduceModels = enable; + } + + @Override + public Optional getModel() { + if (mLastResult != LBool.SAT) { + throw new UnsupportedOperationException("No model available: last query was " + mLastResult); + } + return Optional.ofNullable(mLastModel); + } + + @Override + public boolean supportsDerivationProduction() { + return false; + } + + @Override + public void produceDerivations(final boolean enable) { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getDerivation() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean supportsUnsatCores() { + return false; + } + + @Override + public void produceUnsatCores(final boolean enable) { + throw new UnsupportedOperationException(); + } + + @Override + public Optional> getUnsatCore() { + throw new UnsupportedOperationException(); + } + + private long determineTimeout(final long queryTimeout) { + final var globalTimeout = mServices.getProgressMonitorService().remainingTime(); + final var currentTimeout = queryTimeout <= 0 ? mDefaultQueryTimeout : queryTimeout; + final var actualTimeout = currentTimeout <= 0 ? globalTimeout : Long.min(currentTimeout, globalTimeout); + return actualTimeout; + } +} From 968a27039536b44ae7f24cef5aeca1a17fa1ad43 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 9 Jun 2023 10:37:45 +0200 Subject: [PATCH 070/114] log model if found --- .../ultimate/plugins/chcsolver/ChcSolverObserver.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java index a3e47198161..568a5c68b1b 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java @@ -172,6 +172,8 @@ private ChcSatResult createSatResult(final IChcScript chcScript) { final Model model; if (mPrefs.produceModels() && chcScript.supportsModelProduction()) { model = chcScript.getModel().orElse(null); + mLogger.info("ChcSolver found model:"); + mLogger.info(model); } else { model = null; } From 011ae38f00a0387166e19f2590c7173006f4c0d1 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 9 Jun 2023 11:17:02 +0200 Subject: [PATCH 071/114] ChcTransferrer: fix resolution of head variables --- .../ultimate/lib/chc/ChcTransferrer.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index 29e628b6cc0..1eb537bd83b 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -79,9 +79,11 @@ private HcSymbolTable transfer(final HcSymbolTable symbolTable) { } public HcPredicateSymbol transfer(final HcPredicateSymbol predicate) { - final var sorts = - predicate.getParameterSorts().stream().map(mTransferrer::transferSort).collect(Collectors.toList()); - return mTargetSymbolTable.getOrConstructHornClausePredicateSymbol(predicate.getName(), sorts); + return mPredMapping.computeIfAbsent(predicate, p -> { + final var sorts = + p.getParameterSorts().stream().map(mTransferrer::transferSort).collect(Collectors.toList()); + return mTargetSymbolTable.getOrConstructHornClausePredicateSymbol(p.getName(), sorts); + }); } public T transfer(final T var) { @@ -141,26 +143,30 @@ private T transferOld(final T var, final BiFunction { - final var bodyVars = clause.getBodyVariables().stream().map(this::transfer).collect(Collectors.toSet()); + // head is transferred first, so all HcHeadVars exist when body arguments and constraint are transferred + final HcPredicateSymbol head; final List headVars; if (!clause.isHeadFalse()) { + head = transfer(clause.getHeadPredicate()); headVars = clause.getTermVariablesForHeadPred().stream().map(this::transfer).collect(Collectors.toList()); - } else { + head = null; headVars = null; } - final var constraint = transfer(clause.getConstraintFormula()); + // transfer body final var bodyPreds = clause.getBodyPredicates().stream().map(this::transfer).collect(Collectors.toList()); + final var bodyVars = clause.getBodyVariables().stream().map(this::transfer).collect(Collectors.toSet()); final var bodyArgs = clause.getBodyPredToArgs().stream() .map(args -> args.stream().map(this::transfer).collect(Collectors.toList())) .collect(Collectors.toList()); + + final var constraint = transfer(clause.getConstraintFormula()); if (clause.isHeadFalse()) { return new HornClause(mTargetScript, mTargetSymbolTable, constraint, bodyPreds, bodyArgs, bodyVars); } - final var head = transfer(clause.getHeadPredicate()); return new HornClause(mTargetScript, mTargetSymbolTable, constraint, head, headVars, bodyPreds, bodyArgs, bodyVars); }); From d2af6b79dd5320ea67416cf117a04974bc963180 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 9 Jun 2023 11:17:46 +0200 Subject: [PATCH 072/114] ChcTransferrer: implement transferBack(Model) --- .../ultimate/lib/chc/ChcTransferrer.java | 39 ++++++++++++++++--- .../smtsolver/external/ModelDescription.java | 2 +- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index 1eb537bd83b..5db937049c1 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -26,6 +26,8 @@ */ package de.uni_freiburg.informatik.ultimate.lib.chc; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.BiFunction; @@ -37,6 +39,9 @@ import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; +import de.uni_freiburg.informatik.ultimate.logic.TermVariable; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.FunctionDefinition; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.ModelDescription; import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; /** @@ -52,6 +57,9 @@ public class ChcTransferrer { private final HcSymbolTable mTargetSymbolTable; private final TermTransferrer mTransferrer; + private final TermTransferrer mBackTransferrer; + + private final BidirectionalMap mTransferMap = new BidirectionalMap<>(); private final BidirectionalMap mPredMapping = new BidirectionalMap<>(); private final BidirectionalMap mClauseMapping = new BidirectionalMap<>(); @@ -59,7 +67,8 @@ public ChcTransferrer(final Script originalScript, final ManagedScript targetScr final HcSymbolTable symbolTable) { mOriginalScript = originalScript; mTargetScript = targetScript; - mTransferrer = new TermTransferrer(originalScript, targetScript.getScript()); + mTransferrer = new TermTransferrer(originalScript, targetScript.getScript(), mTransferMap, false); + mBackTransferrer = new TermTransferrer(targetScript.getScript(), originalScript, mTransferMap.inverse(), false); mOriginalSymbolTable = symbolTable; mTargetSymbolTable = transfer(symbolTable); @@ -196,8 +205,25 @@ public ChcSolution transferBack(final ChcSolution solution) { } public Model transferBack(final Model model) { - // TODO - throw new UnsupportedOperationException("not yet implemented"); + if (!(model instanceof ModelDescription)) { + // TODO support other types of models by wrapping in a "TransferredModel" class? + throw new UnsupportedOperationException("Can currently only transfer models of type ModelDescription"); + } + return transferBack((ModelDescription) model); + } + + private ModelDescription transferBack(final ModelDescription model) { + final var functions = new HashSet(); + for (final var func : model.getDefinedFunctions()) { + final var funcSym = mTargetScript.getScript().getFunctionSymbol(func.getName()); + final var funDesc = model.getFunctionDefinition(func.getName()); + final var params = Arrays.stream(funDesc.getParams()) + .map(x -> mTargetScript.getScript().variable(x.getName(), transferBack(x.getSort()))) + .toArray(TermVariable[]::new); + final var body = transferBack(funDesc.getBody()); + functions.add(new FunctionDefinition(funcSym, params, body)); + } + return new ModelDescription(functions); } public Derivation transferBack(final Derivation derivation) { @@ -227,7 +253,10 @@ public HcPredicateSymbol transferBack(final HcPredicateSymbol predicate) { } private Term transferBack(final Term term) { - // TODO - throw new UnsupportedOperationException("not yet implemented"); + return mBackTransferrer.transform(term); + } + + private Sort transferBack(final Sort sort) { + return mBackTransferrer.transferSort(sort); } } diff --git a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/ModelDescription.java b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/ModelDescription.java index 11ee3fde07f..861d0e51443 100644 --- a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/ModelDescription.java +++ b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/ModelDescription.java @@ -85,7 +85,7 @@ public Term getFunctionDefinition(final String func, final TermVariable[] args) return unletter.transform(def.getBody()); } - private FunctionDefinition getFunctionDefinition(final String func) { + public FunctionDefinition getFunctionDefinition(final String func) { return mDefinitions.get(func); } From 3a8dd60cf02acb0a838750519162eb0dee502a36 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 12 Jun 2023 09:42:04 +0200 Subject: [PATCH 073/114] prepare more extensive evaluation --- .../default/benchexec/sleep-threadmodular.xml | 84 +++++++++++++++++-- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index d2f2d9fb903..a9691a0dab5 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -5,7 +5,7 @@ - + @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -38,6 +38,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -46,4 +120,4 @@ ../../../trunk/examples/threadmodular/regression/*/*.yml ../../../trunk/examples/svcomp/properties/unreach-call.prp - \ No newline at end of file + From bc7f6ac4256c6a735557ddfc68d5b8994373fc2b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 13 Jun 2023 19:37:45 +0200 Subject: [PATCH 074/114] ChcTransferrer: fix model backtranslation - only transfer Horn predicate symbols (Z3 also gives models for constants corresponding to HcVars) - fix transferring term variables - properly transfer function symbol --- .../ultimate/lib/chc/ChcTransferrer.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index 5db937049c1..f0364bf4054 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -35,6 +35,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.scripttransfer.TermTransferrer; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; +import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.Model; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Sort; @@ -215,17 +216,22 @@ public Model transferBack(final Model model) { private ModelDescription transferBack(final ModelDescription model) { final var functions = new HashSet(); for (final var func : model.getDefinedFunctions()) { - final var funcSym = mTargetScript.getScript().getFunctionSymbol(func.getName()); + if (!isHcPredicate(func)) { + continue; + } + final var funcSym = mOriginalScript.getFunctionSymbol(func.getName()); final var funDesc = model.getFunctionDefinition(func.getName()); - final var params = Arrays.stream(funDesc.getParams()) - .map(x -> mTargetScript.getScript().variable(x.getName(), transferBack(x.getSort()))) - .toArray(TermVariable[]::new); + final var params = Arrays.stream(funDesc.getParams()).map(this::transferBack).toArray(TermVariable[]::new); final var body = transferBack(funDesc.getBody()); functions.add(new FunctionDefinition(funcSym, params, body)); } return new ModelDescription(functions); } + private boolean isHcPredicate(final FunctionSymbol fun) { + return mPredMapping.values().stream().anyMatch(p -> p.getFunctionSymbol().equals(fun)); + } + public Derivation transferBack(final Derivation derivation) { final var predicate = transferBack(derivation.getPredicate()); final var arguments = derivation.getArguments().stream().map(this::transferBack).collect(Collectors.toList()); @@ -252,6 +258,11 @@ public HcPredicateSymbol transferBack(final HcPredicateSymbol predicate) { return mPredMapping.inverse().get(predicate); } + private TermVariable transferBack(final TermVariable tv) { + return (TermVariable) mTransferMap.inverse().computeIfAbsent(tv, + y -> mOriginalScript.variable(((TermVariable) y).getName(), transferBack(y.getSort()))); + } + private Term transferBack(final Term term) { return mBackTransferrer.transform(term); } From e6bf6e30f8a4adbfaafd2e972a6b8e8e57b4efa5 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 15 Jun 2023 19:05:50 +0200 Subject: [PATCH 075/114] ApproximateLockstepPreferenceOrder: do not confuse locations with their depth --- .../partialorder/ApproximateLockstepPreferenceOrder.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java index 85c5ed00bd7..33f024ba0c8 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java @@ -80,8 +80,13 @@ private Term getOrderConstraint(final IcfgLocation fixedLoc, final Term otherLoc final Map locationMap) { final var fixedDepth = mDepth.get(fixedLoc); - final var greaterLocs = mDepth.entrySet().stream().filter(e -> e.getValue() >= fixedDepth) - .map(e -> mDepth.get(e.getKey())).sorted().collect(Collectors.toList()); + final var greaterLocs = mDepth.entrySet().stream() + // consider only locations with greater depth + .filter(e -> e.getValue() >= fixedDepth) + // replace locations by the integers representing the, + .map(e -> locationMap.get(e.getKey())) + // sort (to simplify #rangify below) and collect + .sorted().collect(Collectors.toList()); final var locRanges = rangify(greaterLocs); final var disjuncts = new ArrayList(); From e9a7c2ea729111faddd2c9e6f8287940aec9ce53 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 15 Jun 2023 19:46:27 +0200 Subject: [PATCH 076/114] fix implementation of thread-modular preference orders This reflects a change in the previously erroneous (i.e. way too restrictive) definition. --- .../ApproximateLockstepPreferenceOrder.java | 38 +++++++++++------- .../ExplicitPreferenceOrderManager.java | 17 ++++++-- .../IThreadModularPreferenceOrder.java | 39 ++++++++++++------- .../SequentialCompositionPreferenceOrder.java | 4 +- .../SymbolicPreferenceOrderManager.java | 5 ++- 5 files changed, 67 insertions(+), 36 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java index 33f024ba0c8..c9480effe72 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.BiPredicate; import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; @@ -52,21 +53,18 @@ protected ApproximateLockstepPreferenceOrder(final Script script, final Map locationMap) { - if (lesserLoc != null && greaterLoc != null) { - return getOrderConstraint(lesserLoc, greaterLoc); + public Term getOrderConstraint(final IcfgLocation loc1, final Term loc1Term, final IcfgLocation loc2, + final Term loc2Term, final Map locationMap) { + if (loc1 != null && loc2 != null) { + return getOrderConstraint(loc1, loc2); } - if (lesserLoc != null) { - return getOrderConstraint(lesserLoc, greaterLocTerm, locationMap); + if (loc1 != null) { + return getOrderConstraint(loc1, loc2Term, locationMap); } - assert greaterLoc != null : "At least one location must be fixed"; - final var constraint = getOrderConstraint(greaterLoc, lesserLocTerm, locationMap); - - // invert the constraint, because we flipped greaterLoc and lesserLocTerm - return SmtUtils.not(mScript, constraint); + assert loc2 != null : "At least one location must be fixed"; + return getOrderConstraint(loc1Term, loc2, locationMap); } private Term getOrderConstraint(final IcfgLocation lesserLoc, final IcfgLocation greaterLoc) { @@ -76,13 +74,23 @@ private Term getOrderConstraint(final IcfgLocation lesserLoc, final IcfgLocation return mScript.term(SMTLIBConstants.FALSE); } - private Term getOrderConstraint(final IcfgLocation fixedLoc, final Term otherLoc, + private Term getOrderConstraint(final IcfgLocation loc1, final Term loc2, + final Map locationMap) { + return getOrderConstraint(loc1, loc2, (x, y) -> x >= y, locationMap); + } + + private Term getOrderConstraint(final Term loc1, final IcfgLocation loc2, final Map locationMap) { - final var fixedDepth = mDepth.get(fixedLoc); + return getOrderConstraint(loc2, loc1, (x, y) -> x <= y, locationMap); + } + + private Term getOrderConstraint(final IcfgLocation loc1, final Term loc2, + final BiPredicate comparator, final Map locationMap) { + final var loc1Depth = mDepth.get(loc1); final var greaterLocs = mDepth.entrySet().stream() // consider only locations with greater depth - .filter(e -> e.getValue() >= fixedDepth) + .filter(e -> comparator.test(e.getValue(), loc1Depth)) // replace locations by the integers representing the, .map(e -> locationMap.get(e.getKey())) // sort (to simplify #rangify below) and collect @@ -91,7 +99,7 @@ private Term getOrderConstraint(final IcfgLocation fixedLoc, final Term otherLoc final var disjuncts = new ArrayList(); for (final var range : locRanges) { - final var disjunct = getIntervalConstraint(otherLoc, range.getFirst(), range.getSecond()); + final var disjunct = getIntervalConstraint(loc2, range.getFirst(), range.getSecond()); if (SmtUtils.isTrueLiteral(disjunct)) { return mScript.term(SMTLIBConstants.TRUE); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java index 056e0277ba6..97cad10b67a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitPreferenceOrderManager.java @@ -31,7 +31,7 @@ import java.util.Map; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; -import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; @@ -53,11 +53,20 @@ public ExplicitPreferenceOrderManager(final IThreadModularPreferenceOrder prefer public Term getOrderConstraint(final HornClauseBuilder clause, final Comparator comp, final ThreadInstance thread1, final IcfgLocation loc1, final Term locTerm1, final ThreadInstance thread2, final IcfgLocation loc2, final Term locTerm2) { + // (loc1, loc2) in R + final var locConstraint1 = mPreferenceOrder.getOrderConstraint(loc1, locTerm1, loc2, locTerm2, mLocationMap); + final int ordering = comp.compare(thread1, thread2); - if (ordering >= 0) { - return mScript.term(SMTLIBConstants.FALSE); + if (ordering < 0) { + // implication "(loc2, loc1) in R ==> thread1 < thread2" trivially true + return locConstraint1; } - return mPreferenceOrder.getOrderConstraint(loc1, locTerm1, loc2, locTerm2, mLocationMap); + + // (loc2, loc1) in R + final var locConstraint2 = mPreferenceOrder.getOrderConstraint(loc2, locTerm2, loc1, locTerm1, mLocationMap); + + // (loc1, loc2) in R /\ (loc2, loc1) not in R + return SmtUtils.and(mScript, locConstraint1, SmtUtils.not(mScript, locConstraint2)); } @Override diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java index 5f6ed34c0ae..a7c22595481 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IThreadModularPreferenceOrder.java @@ -31,26 +31,39 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; import de.uni_freiburg.informatik.ultimate.logic.Term; +/** + * A thread-modular preference order is used to select the representatives present in the reduction, i.e., those + * interleavings that are not pruned. This interface is used for CHC-based sleep set reduction, and is somewhat + * analogous to {@link de.uni_freiburg.informatik.ultimate.automata.partialorder.IDfsOrder.IDfsOrder} in automata-based + * reduction algorithms. + * + * However, thread-modular preference orders are somewhat more restrictive, to allow their usage in parametrized + * programs, and they are symbolic, to allow usage in the CHC encoding. A thread-modular preference order is given by a + * transitive binary relation R between CFG locations. If threads i and j are in locations l_i and l_j, respectively, + * then thread i is preferable to thread j iff (l_i,l_j) in R, and (l_j, l_i) in R implies i < j. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + */ public interface IThreadModularPreferenceOrder { /** - * Constructs a boolean constraint expressing the ordering between two threads. If the constraint evaluates to - * {@code true}, then the "lesser" thread is preferred. Otherwise, the "greater" thread is preferred. + * Constructs a boolean constraint expressing membership of a pair of CFG locations in the relation underlying this + * preference order. * - * At least one of {@code lesserLoc} and {@code greaterLoc} is guaranteed to be non-null. + * At least one of {@code loc1} and {@code loc2} is guaranteed to be non-null. * - * @param lesserLoc - * The location of the thread with a lower thread ID. May be null. - * @param lesserLocTerm - * A term denoting the location of the thread with a lower thread ID. - * @param greaterLoc - * The location of the thread with a greater thread ID. May be null. - * @param greaterLocTerm - * A term denoting the location of the thread with a greater thread ID. - * @param locationTerms + * @param loc1 + * The first location of the pair to be considered. May be null. + * @param loc1Term + * A term denoting the first location of the pair to be considered. + * @param loc2 + * The second location of the pair to be considered. May be null. + * @param loc2Term + * A term denoting the second location of the pair to be considered. + * @param locationMap * A mapping from locations to the integer value used to represent that location. * @return a constraint over the given terms (including the terms in {@code locationTerms}) */ - Term getOrderConstraint(IcfgLocation lesserLoc, Term lesserLocTerm, IcfgLocation greaterLoc, Term greaterLocTerm, + Term getOrderConstraint(IcfgLocation loc1, Term loc1Term, IcfgLocation loc2, Term loc2Term, Map locationMap); boolean isPositional(); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java index 15ba73fafb8..e2f842b9635 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SequentialCompositionPreferenceOrder.java @@ -41,8 +41,8 @@ public SequentialCompositionPreferenceOrder(final Script script) { } @Override - public Term getOrderConstraint(final IcfgLocation lesserLoc, final Term lesserLocTerm, - final IcfgLocation greaterLoc, final Term greaterLocTerm, final Map locationMap) { + public Term getOrderConstraint(final IcfgLocation loc1, final Term loc1Term, final IcfgLocation loc2, + final Term loc2Term, final Map locationMap) { return mScript.term(SMTLIBConstants.TRUE); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java index 6f80ff290cb..ebe541e2ea4 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SymbolicPreferenceOrderManager.java @@ -58,8 +58,9 @@ public Term getOrderConstraint(final HornClauseBuilder clause, final Comparator< final var id2 = clause.getBodyVar(new HcThreadIdVar(thread2, mScript)); final var lesserConstraint = SmtUtils.less(mScript, id1.getTerm(), id2.getTerm()); - final var locConstraint = mPreferenceOrder.getOrderConstraint(loc1, locTerm1, loc2, locTerm2, mLocationMap); - return SmtUtils.and(mScript, lesserConstraint, locConstraint); + final var locConstraint1 = mPreferenceOrder.getOrderConstraint(loc1, locTerm1, loc2, locTerm2, mLocationMap); + final var locConstraint2 = mPreferenceOrder.getOrderConstraint(loc2, locTerm2, loc1, locTerm1, mLocationMap); + return SmtUtils.and(mScript, locConstraint1, SmtUtils.implies(mScript, locConstraint2, lesserConstraint)); } @Override From 66e461b249ea783403d6e4bc3eda2ceb48907ecd Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 16 Jun 2023 10:27:14 +0200 Subject: [PATCH 077/114] add setting for SKIP_ASSERTION_EDGES --- .../concurrent/ThreadModularHornClauseProvider.java | 5 ++--- .../preferences/IcfgToChcPreferenceInitializer.java | 10 +++++++++- .../icfgtochc/preferences/IcfgToChcPreferences.java | 4 ++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 01549301530..7748f1ee811 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -83,7 +83,6 @@ public class ThreadModularHornClauseProvider extends ExtensibleHornClauseProvider { private static final String FUNCTION_NAME = "Inv"; private static final int INTERFERING_INSTANCE_ID = -1; - protected static final boolean SKIP_ASSERTION_EDGES = true; protected final IUltimateServiceProvider mServices; protected final IIcfg mIcfg; @@ -285,7 +284,7 @@ protected List buildAllClauses() { // add safety clauses switch (mPrefs.specMode()) { case ASSERT_VIOLATIONS: - if (SKIP_ASSERTION_EDGES) { + if (mPrefs.skipAssertEdges()) { for (final var triple : getErrorConditions()) { final var safetyClause = buildErrorSafetyClause(triple.getFirst(), triple.getSecond(), triple.getThird()); @@ -393,7 +392,7 @@ protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { } protected boolean isSkippableAssertEdge(final IcfgEdge edge) { - if (!SKIP_ASSERTION_EDGES) { + if (!mPrefs.skipAssertEdges()) { return false; } final var errorLocs = mIcfg.getProcedureErrorNodes().get(edge.getSucceedingProcedure()); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index f4d23113601..89d4d6a70ff 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -82,6 +82,11 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "templates, before a thread-modular proof is computed."; public static final boolean DEF_LIPTON_REDUCTION = false; + public static final String LABEL_SKIP_ASSERT_EDGES = "Skip assert edges"; + private static final String DESC_SKIP_ASSERT_EDGES = "If enabled, we do not directly encode unreachability of " + + "error locations. Instead, the assertion condition is part of the safety clause."; + private static final boolean DEF_SKIP_ASSERT_EDGES = true; + // SETTINGS FOR SLEEP SET REDUCTION // ------------------------------------------------------------------------ @@ -127,19 +132,22 @@ public IcfgToChcPreferenceInitializer() { @Override protected BaseUltimatePreferenceItem[] initDefaultPreferences() { return new BaseUltimatePreferenceItem[] { - // Settings for thread-modular proofs + // Settings for concurrent programs new UltimatePreferenceItem<>(LABEL_CONCURRENCY_MODE, DEF_CONCURRENCY_MODE, DESC_CONCURRENCY_MODE, PreferenceType.Combo, ConcurrencyMode.values()), new UltimatePreferenceItem<>(LABEL_HAS_PRECONDITION, DEF_HAS_PRECONDITION, DESC_HAS_PRECONDITION, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SPEC_MODE, DEF_SPEC_MODE, DESC_SPEC_MODE, PreferenceType.Combo, SpecMode.values()), + // Settings for thread-modular proofs new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, DESC_THREADMODULAR_LEVEL, PreferenceType.Integer), new UltimatePreferenceItem<>(LABEL_EXPLICIT_LOCATIONS, DEF_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_SKIP_ASSERT_EDGES, DEF_SKIP_ASSERT_EDGES, DESC_SKIP_ASSERT_EDGES, + PreferenceType.Boolean), getSleepSetSettings() }; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index fe305fb85d0..9bdf4bb0a28 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -66,6 +66,10 @@ public boolean useLiptonReduction() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_LIPTON_REDUCTION); } + public boolean skipAssertEdges() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SKIP_ASSERT_EDGES); + } + public boolean useSleepSets() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SLEEP_SET_REDUCTION); } From 806d74d43d3d56f786c9b15a3445e44c58dba766 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 16 Jun 2023 10:27:59 +0200 Subject: [PATCH 078/114] ensure models are in Ultimate normal form --- .../lib/chc/ChcSolutionNormalizer.java | 83 +++++++++++++++++++ .../ultimate/lib/chc/ChcTransferrer.java | 4 + .../lib/chc/EldaricaCliChcScript.java | 7 +- .../ultimate/lib/chc/GolemChcScript.java | 7 +- .../ultimate/lib/chc/SmtChcScript.java | 17 +++- 5 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcSolutionNormalizer.java diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcSolutionNormalizer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcSolutionNormalizer.java new file mode 100644 index 00000000000..c69baf729da --- /dev/null +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcSolutionNormalizer.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2023 University of Freiburg + * + * This file is part of the ULTIMATE CHC Library. + * + * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.lib.chc; + +import java.util.stream.Collectors; + +import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.normalforms.UnfTransformer; +import de.uni_freiburg.informatik.ultimate.logic.Model; +import de.uni_freiburg.informatik.ultimate.logic.Script; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.FunctionDefinition; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.ModelDescription; + +/** + * Transforms CHC solutions into Ultimate normal form. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + */ +public class ChcSolutionNormalizer { + private final Script mScript; + + public ChcSolutionNormalizer(final Script script) { + mScript = script; + } + + public ChcSolution normalize(final ChcSolution solution) { + switch (solution.getSatisfiability()) { + case SAT: + if (solution.getModel() == null) { + return solution; + } + return ChcSolution.sat(normalize((ModelDescription) solution.getModel())); + case UNSAT: + if (solution.getDerivation() == null) { + return solution; + } + return ChcSolution.unsat(normalize(solution.getDerivation()), solution.getUnsatCore()); + case UNKNOWN: + return solution; + default: + throw new AssertionError(); + } + } + + public Model normalize(final ModelDescription model) { + return new ModelDescription(model.getDefinedFunctions().stream() + .map(fun -> normalize(model.getFunctionDefinition(fun.getName()))).collect(Collectors.toSet())); + } + + public FunctionDefinition normalize(final FunctionDefinition definition) { + final var body = new UnfTransformer(mScript).transform(definition.getBody()); + return new FunctionDefinition(definition.getName(), definition.getParams(), body); + } + + public Derivation normalize(final Derivation derivation) { + // TODO + return derivation; + } +} diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index f0364bf4054..e67600d34c2 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -270,4 +270,8 @@ private Term transferBack(final Term term) { private Sort transferBack(final Sort sort) { return mBackTransferrer.transferSort(sort); } + + public ManagedScript getTargetScript() { + return mTargetScript; + } } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java index f2851450731..b900dff513e 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java @@ -41,6 +41,7 @@ import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; import de.uni_freiburg.informatik.ultimate.smtsolver.external.Executor; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.ModelDescription; public class EldaricaCliChcScript implements IChcScript { private static final boolean ADD_CLAUSE_NAMES = false; @@ -143,7 +144,11 @@ public Optional getModel() { if (mLastResult != LBool.SAT) { throw new UnsupportedOperationException("No model available: last query was " + mLastResult); } - return Optional.ofNullable(mLastModel); + if (mLastModel == null) { + return Optional.empty(); + } + final var normalizedModel = new ChcSolutionNormalizer(getScript()).normalize((ModelDescription) mLastModel); + return Optional.of(normalizedModel); } @Override diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/GolemChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/GolemChcScript.java index 602dd6097e3..ffc78d83f72 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/GolemChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/GolemChcScript.java @@ -41,6 +41,7 @@ import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; import de.uni_freiburg.informatik.ultimate.smtsolver.external.Executor; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.ModelDescription; public class GolemChcScript implements IChcScript { private static final boolean ADD_CLAUSE_NAMES = false; @@ -137,7 +138,11 @@ public Optional getModel() { if (mLastResult != LBool.SAT) { throw new UnsupportedOperationException("No model available: last query was " + mLastResult); } - return Optional.ofNullable(mLastModel); + if (mLastModel == null) { + return Optional.empty(); + } + final var normalizedModel = new ChcSolutionNormalizer(getScript()).normalize((ModelDescription) mLastModel); + return Optional.of(normalizedModel); } @Override diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java index b754e4c774b..acf2e9f8352 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java @@ -40,6 +40,7 @@ import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; +import de.uni_freiburg.informatik.ultimate.smtsolver.external.ModelDescription; /** * Used to access a constraint Horn solver via the {@link Script} interface. This can e.g. be used to access Z3's CHC @@ -127,10 +128,22 @@ public Optional getModel() { if (model == null) { return Optional.empty(); } + + // back-transfer model if necessary + final Model transferredModel; + final Script outputScript; if (mTransferrer == null) { - return Optional.of(model); + transferredModel = model; + outputScript = getScript(); + } else { + transferredModel = mTransferrer.transferBack(model); + outputScript = mTransferrer.getTargetScript().getScript(); } - return Optional.of(mTransferrer.transferBack(model)); + + // ensure Ultimate normal form + final var normalizedModel = + new ChcSolutionNormalizer(outputScript).normalize((ModelDescription) transferredModel); + return Optional.of(normalizedModel); } @Override From 90a251ae725c5fb0039cae1db4661aeea27da028 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 16 Jun 2023 10:28:22 +0200 Subject: [PATCH 079/114] temporarily (for evaluation) avoid let terms in models --- .../ultimate/smtsolver/external/FunctionDefinition.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java index 7a1a880cb67..a5847c35135 100644 --- a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java +++ b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java @@ -80,7 +80,8 @@ public String toString() { builder.append(") "); builder.append(getReturnSort()); builder.append(" "); - builder.append(mBody); + // TODO temporary change, revert to toString in the future + builder.append(mBody.toStringDirect()); builder.append(")"); return builder.toString(); } From f271ee5d1d44fa8b247343efcb5cfe870d73ff08 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 16 Jun 2023 14:33:43 +0200 Subject: [PATCH 080/114] SmtChcScript: transfer models to the proper script --- .../informatik/ultimate/lib/chc/ChcTransferrer.java | 8 ++++++-- .../informatik/ultimate/lib/chc/SmtChcScript.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index e67600d34c2..c582560abcd 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -271,7 +271,11 @@ private Sort transferBack(final Sort sort) { return mBackTransferrer.transferSort(sort); } - public ManagedScript getTargetScript() { - return mTargetScript; + public Script getSourceScript() { + return mOriginalScript; + } + + public Script getTargetScript() { + return mTargetScript.getScript(); } } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java index acf2e9f8352..7c58711a7fa 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/SmtChcScript.java @@ -137,7 +137,7 @@ public Optional getModel() { outputScript = getScript(); } else { transferredModel = mTransferrer.transferBack(model); - outputScript = mTransferrer.getTargetScript().getScript(); + outputScript = mTransferrer.getSourceScript(); } // ensure Ultimate normal form From c8ff3af4ef27e1d87e51f19215fd2756e119c30d Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 21 Jun 2023 16:32:58 +0200 Subject: [PATCH 081/114] throw error for joins even without -ea --- .../icfgtochc/concurrent/ThreadModularHornClauseProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 7748f1ee811..38bad299eef 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -422,7 +422,7 @@ protected boolean isSkippableAssertEdge(final IcfgEdge edge) { return result; } if (edge instanceof IIcfgJoinTransitionThreadCurrent) { - assert false : "Joins not supported"; + throw new UnsupportedOperationException("Joins not supported"); } return getInstances(edge.getPrecedingProcedure()).stream() From 78f44351ff595463d26470196a61fb6f7c10bf74 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 22 Jun 2023 11:33:28 +0200 Subject: [PATCH 082/114] parametric programs: support multiple templates and single-instance threads --- .../icfgtochc/concurrent/ConcurrencyMode.java | 44 +++++++++++++++---- .../ThreadModularHornClauseProvider.java | 5 +-- .../IcfgToChcPreferenceInitializer.java | 16 +++++++ .../preferences/IcfgToChcPreferences.java | 20 +++++++++ 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java index 8ba4d826ebb..eb26ffe6b19 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ConcurrencyMode.java @@ -33,10 +33,12 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IcfgUtils; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IIcfg; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; public enum ConcurrencyMode { @@ -63,12 +65,25 @@ public enum ConcurrencyMode { * the second component contains all threads that may have more than {@code level} instances. */ public Pair, Set> getThreadNumbersAndUnboundedThreads(final IIcfg icfg, - final int level) { + final IcfgToChcPreferences prefs) { + final int level = prefs.getThreadModularProofLevel(); + if (this == ConcurrencyMode.PARAMETRIC) { - final var numberOfThreads = - icfg.getInitialNodes().stream().collect(Collectors.toMap(loc -> loc.getProcedure(), loc -> level)); - final var unbounded = Set.copyOf(numberOfThreads.keySet()); - return new Pair<>(numberOfThreads, unbounded); + // get templates either from setting, or initial locs of ICFG + final var prefTemplates = prefs.getParametricTemplates(); + final var templates = prefTemplates == null + ? icfg.getInitialNodes().stream().map(IcfgLocation::getProcedure).collect(Collectors.toList()) + : prefTemplates; + final var templateInstances = templates.stream().map(proc -> new Pair<>(proc, level)); + + // get single-instance threads from settings, if any + final var prefSingleThreads = prefs.getParametricSingleThreads(); + final Stream> singleThreads = prefSingleThreads == null ? Stream.empty() + : prefSingleThreads.stream().map(proc -> new Pair<>(proc, 1)); + + final var numberOfThreads = Stream.concat(templateInstances, singleThreads) + .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); + return new Pair<>(numberOfThreads, Set.copyOf(templates)); } assert this == ConcurrencyMode.SINGLE_MAIN_THREAD : "Unknown mode: " + this; @@ -108,12 +123,23 @@ public Pair, Set> getThreadNumbersAndUnboundedThrea * @return A mapping from initially running thread instances to their initial locations */ public Map getInitialLocations(final IIcfg icfg, - final List instances) { + final List instances, final IcfgToChcPreferences prefs) { switch (this) { case PARAMETRIC: - // combine each initial location (usually there is only one) with ALL instances of its template - return icfg - .getInitialNodes().stream().flatMap(l -> instances.stream() + // get templates either from setting, or initial locs of ICFG + final var prefTemplates = prefs.getParametricTemplates(); + final Stream templateInitLocs = + prefTemplates == null ? icfg.getInitialNodes().stream() + : prefTemplates.stream().map(proc -> icfg.getProcedureEntryNodes().get(proc)); + + // get single-instance threads from settings, if any + final var prefSingleThreads = prefs.getParametricSingleThreads(); + final Stream singleThreadInitLocs = prefSingleThreads == null ? Stream.empty() + : prefSingleThreads.stream().map(proc -> icfg.getProcedureEntryNodes().get(proc)); + + // combine each initial location with ALL instances of its template + return Stream + .concat(templateInitLocs, singleThreadInitLocs).flatMap(l -> instances.stream() .filter(i -> i.getTemplateName().equals(l.getProcedure())).map(i -> new Pair<>(i, l))) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); case SINGLE_MAIN_THREAD: diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 38bad299eef..1a1a896c434 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -124,8 +124,7 @@ public ThreadModularHornClauseProvider(final IUltimateServiceProvider services, mCfgSymbolTable = mIcfg.getCfgSmtToolkit().getSymbolTable(); mVariableFilter = variableFilter; - final var threadInfo = - mPrefs.concurrencyMode().getThreadNumbersAndUnboundedThreads(icfg, mPrefs.getThreadModularProofLevel()); + final var threadInfo = mPrefs.concurrencyMode().getThreadNumbersAndUnboundedThreads(icfg, mPrefs); mTemplates = Set.copyOf(threadInfo.getFirst().keySet()); mInstances = getInstances(threadInfo.getFirst()); mUnboundedTemplates = threadInfo.getSecond(); @@ -671,7 +670,7 @@ protected void replaceThreadVariables(final List parameters, // ----------------------------------------------------------------------------------------------------------------- protected Map getInitialLocations() { - return mPrefs.concurrencyMode().getInitialLocations(mIcfg, mInstances); + return mPrefs.concurrencyMode().getInitialLocations(mIcfg, mInstances, mPrefs); } protected void addInLocationConstraint(final HornClauseBuilder clause, final ThreadInstance threadInstance, diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 89d4d6a70ff..8e0dc07dea6 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -87,6 +87,18 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "error locations. Instead, the assertion condition is part of the safety clause."; private static final boolean DEF_SKIP_ASSERT_EDGES = true; + // TODO Introduce PreferenceType.List? + public static final String LABEL_PARAMETRIC_TEMPLATES = "Templates for parametric program"; + private static final String DESC_PARAMETRIC_TEMPLATES = "Comma-separated list of procedures denoting thread " + + "templates of the parametric program. Leave empty for default behaviour (i.e., single template given " + + "by ULTIMATE.start in Boogie, main in C)."; + private static final String DEF_PARAMETRIC_TEMPLATES = ""; + + public static final String LABEL_PARAMETRIC_SINGLE_THREADS = "Single-instance threads"; + private static final String DESC_PARAMETRIC_SINGLE_THREADS = + "Comma-separated list of procedures for which a single thread is running in a parametric program."; + private static final String DEF_PARAMETRIC_SINGLE_THREADS = ""; + // SETTINGS FOR SLEEP SET REDUCTION // ------------------------------------------------------------------------ @@ -148,6 +160,10 @@ protected BaseUltimatePreferenceItem[] initDefaultPreferences() { PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SKIP_ASSERT_EDGES, DEF_SKIP_ASSERT_EDGES, DESC_SKIP_ASSERT_EDGES, PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_PARAMETRIC_TEMPLATES, DEF_PARAMETRIC_TEMPLATES, + DESC_PARAMETRIC_TEMPLATES, PreferenceType.String), + new UltimatePreferenceItem<>(LABEL_PARAMETRIC_SINGLE_THREADS, DEF_PARAMETRIC_SINGLE_THREADS, + DESC_PARAMETRIC_SINGLE_THREADS, PreferenceType.String), getSleepSetSettings() }; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 9bdf4bb0a28..3c16512bd78 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -26,6 +26,10 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer.ConditionalIndependence; @@ -94,4 +98,20 @@ public ConditionalIndependence conditionalIndependence() { public boolean useSemicommutativity() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SEMICOMMUTATIVITY); } + + public List getParametricTemplates() { + return getList(IcfgToChcPreferenceInitializer.LABEL_PARAMETRIC_TEMPLATES); + } + + public List getParametricSingleThreads() { + return getList(IcfgToChcPreferenceInitializer.LABEL_PARAMETRIC_SINGLE_THREADS); + } + + private List getList(final String key) { + final var value = mPrefs.getString(key); + if (value == null || value.isBlank()) { + return null; + } + return Arrays.stream(value.split(",")).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); + } } From a63ceb3d232f0cb684a4ef68a3b3075531324300 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 22 Jun 2023 11:46:43 +0200 Subject: [PATCH 083/114] fix pre/post detection for multiple templates --- .../concurrent/ThreadModularHornClauseProvider.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 1a1a896c434..028f28c1b8d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -374,18 +374,21 @@ protected boolean isPreConditionSpecEdge(final IcfgEdge edge) { if (!mPrefs.hasPreconditions()) { return false; } - - final var template = edge.getPrecedingProcedure(); - final var entryLoc = mIcfg.getProcedureEntryNodes().get(template); - return edge.getSource().equals(entryLoc); + return mIcfg.getInitialNodes().contains(edge.getSource()); } protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { if (mPrefs.specMode() != SpecMode.POSTCONDITION) { return false; } - final var template = edge.getPrecedingProcedure(); + + // only the initial procedure contains the postcondition + final var entryLoc = mIcfg.getProcedureEntryNodes().get(template); + if (!mIcfg.getInitialNodes().contains(entryLoc)) { + return false; + } + final var exitLoc = mIcfg.getProcedureExitNodes().get(template); return edge.getTarget().equals(exitLoc); } From c5b3d182b767b82da423702f6902dd31fba44a11 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Sat, 24 Jun 2023 15:41:32 +0200 Subject: [PATCH 084/114] skip error locations if "skip assert edges" enabled --- .../ThreadModularHornClauseProvider.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 028f28c1b8d..5415ec6bd00 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -172,16 +172,27 @@ private PredicateInfo createInvariantPredicate() { protected Map createLocationMap(final IIcfg icfg) { final var result = new HashMap(); - for (final var entry : icfg.getProcedureEntryNodes().values()) { + for (final var entry : icfg.getProcedureEntryNodes().entrySet()) { + final var errorNodes = icfg.getProcedureErrorNodes().get(entry.getKey()); + final var initial = entry.getValue(); + int counter = 0; - result.put(entry, counter); + result.put(initial, counter); counter++; - final var iterator = new IcfgEdgeIterator(entry.getOutgoingEdges()); + + final var iterator = new IcfgEdgeIterator(initial.getOutgoingEdges()); while (iterator.hasNext()) { final var edge = iterator.next(); assert result.containsKey(edge.getSource()) : "edge with unknown source loc"; - if (!result.containsKey(edge.getTarget())) { - result.put(edge.getTarget(), counter); + final var loc = edge.getTarget(); + + if (mPrefs.skipAssertEdges() && errorNodes.contains(loc)) { + // do not map error locations to an integer (they do not appear in the CHC system) + continue; + } + + if (!result.containsKey(loc)) { + result.put(loc, counter); counter++; } } From ccadeded50500d9a93749e0a48a83c2ebb9a9f56 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 28 Jun 2023 16:58:04 +0200 Subject: [PATCH 085/114] properly filter error locs from CHC system --- .../concurrent/ThreadModularHornClauseProvider.java | 12 ++++++++++-- .../ApproximateLockstepPreferenceOrder.java | 4 +++- .../SleepSetThreadModularHornClauseProvider.java | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 5415ec6bd00..e488ced23de 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -186,8 +186,7 @@ protected Map createLocationMap(final IIcfg icfg) { assert result.containsKey(edge.getSource()) : "edge with unknown source loc"; final var loc = edge.getTarget(); - if (mPrefs.skipAssertEdges() && errorNodes.contains(loc)) { - // do not map error locations to an integer (they do not appear in the CHC system) + if (!isRelevantLocation(loc)) { continue; } @@ -200,6 +199,15 @@ protected Map createLocationMap(final IIcfg icfg) { return result; } + // do not map error locations to an integer if they do not appear in the CHC system + protected boolean isRelevantLocation(final IcfgLocation loc) { + if (!mPrefs.skipAssertEdges()) { + return true; + } + final var errorNodes = mIcfg.getProcedureErrorNodes().get(loc.getProcedure()); + return errorNodes == null || !errorNodes.contains(loc); + } + /** * Constructs the sequence of parameters for the invariant predicate. * diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java index c9480effe72..9ca82ca04bc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ApproximateLockstepPreferenceOrder.java @@ -91,8 +91,10 @@ private Term getOrderConstraint(final IcfgLocation loc1, final Term loc2, final var greaterLocs = mDepth.entrySet().stream() // consider only locations with greater depth .filter(e -> comparator.test(e.getValue(), loc1Depth)) - // replace locations by the integers representing the, + // replace locations by the integers representing them .map(e -> locationMap.get(e.getKey())) + // skip locations not represented in the CHC system + .filter(i -> i != null) // sort (to simplify #rangify below) and collect .sorted().collect(Collectors.toList()); final var locRanges = rangify(greaterLocs); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 5964bf36f8a..41056c10999 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -67,8 +67,8 @@ public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider se final IThreadModularPreferenceOrder preferenceOrder, final IcfgToChcPreferences prefs) { super(services, mgdScript, icfg, symbolTable, prefs); mIndependenceChecker = new IndependenceChecker(services, icfg.getCfgSmtToolkit(), independence); - mThreadLocations = icfg.getProgramPoints().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values())); + mThreadLocations = icfg.getProgramPoints().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, + e -> e.getValue().values().stream().filter(this::isRelevantLocation).collect(Collectors.toList()))); if (mPrefs.breakPreferenceOrderSymmetry()) { mIdVars = null; From fa7c49176b61004e4257558d5d9e8ee3513c61cb Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 28 Jun 2023 16:58:29 +0200 Subject: [PATCH 086/114] fix order for semicommutativity --- .../partialorder/SleepSetThreadModularHornClauseProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 41056c10999..ea2f9b76380 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -324,7 +324,7 @@ protected Term getCommutativityConstraint(final HornClauseBuilder clause, final } final var conjunct = - mIndependenceChecker.getIndependenceCondition(clause, otherThread, edge, activeThread, activeEdge); + mIndependenceChecker.getIndependenceCondition(clause, activeThread, activeEdge, otherThread, edge); if (SmtUtils.isFalseLiteral(conjunct)) { // escape early if one outgoing edge does not commute under any circumstances return mScript.term(SMTLIBConstants.FALSE); From 1b4337833ea7a0525cfa45a7af8a55adcf264edd Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 28 Jun 2023 17:03:23 +0200 Subject: [PATCH 087/114] more work on pre/post for parametric programs --- .../ThreadModularHornClauseProvider.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index e488ced23de..0d3ccc3e57b 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -374,6 +374,14 @@ public String toString() { // add actual constraints for spec edges, do nothing if not a spec edge protected void transformSpecEdgeClause(final IcfgEdge edge, final HornClauseBuilder clause) { + // TODO Fix this for + // - parametric programs with some single-instance threads: + // ---> i.e. only modify counter for unbounded templates; make sure bounded threads all at exit loc + // - parametric programs with multiple unbounded templates: + // ---> should there be one counter per template? + // - fork/join programs + // ---> i.e. we don't need the counter, just assert post after main thread has exited + if (isPreConditionSpecEdge(edge) && mPrefs.specMode() == SpecMode.POSTCONDITION) { incrementThreadCounter(clause, mRunningThreadsVar, 1L); } else if (isPostConditionSpecEdge(edge)) { @@ -393,7 +401,9 @@ protected boolean isPreConditionSpecEdge(final IcfgEdge edge) { if (!mPrefs.hasPreconditions()) { return false; } - return mIcfg.getInitialNodes().contains(edge.getSource()); + final var template = edge.getPrecedingProcedure(); + final var entryLoc = mIcfg.getProcedureEntryNodes().get(template); + return edge.getSource().equals(entryLoc); } protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { @@ -401,13 +411,6 @@ protected boolean isPostConditionSpecEdge(final IcfgEdge edge) { return false; } final var template = edge.getPrecedingProcedure(); - - // only the initial procedure contains the postcondition - final var entryLoc = mIcfg.getProcedureEntryNodes().get(template); - if (!mIcfg.getInitialNodes().contains(entryLoc)) { - return false; - } - final var exitLoc = mIcfg.getProcedureExitNodes().get(template); return edge.getTarget().equals(exitLoc); } From 5ab1b013f7ff8dd113669afd8038dd118722ab00 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 3 Jul 2023 11:02:27 +0200 Subject: [PATCH 088/114] temporarily hardcode some conditions for eval purposes --- .../partialorder/IndependenceChecker.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java index ccba6f29c16..503b55e0b9e 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -26,6 +26,7 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -41,6 +42,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramVarUtils; 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.Substitution; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; @@ -84,6 +86,73 @@ public IndependenceChecker(final IUltimateServiceProvider services, final CfgSmt public Term getIndependenceCondition(final HornClauseBuilder clause, final ThreadInstance thread1, final IcfgEdge action1, final ThreadInstance thread2, final IcfgEdge action2) { + // Hardcoded conditions for line-queue example + // TODO remove after evaluation + Term hardcoded = null; + if ("value := queue[id - 1][read_ptr];".equals(action1.toString()) + && "queue := queue[0 := queue[0][write_ptr[0] := idx]];".equals(action2.toString())) { + final var idLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() + .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); + final var readPtrLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() + .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); + final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) + .findAny().get(); + hardcoded = SmtUtils.or(mMgdScript.getScript(), + SmtUtils.distinct(mMgdScript.getScript(), idLeft.getTerm(), + SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)), + SmtUtils.distinct(mMgdScript.getScript(), readPtrLeft.getTerm(), + SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), + SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ZERO)))); + } else if ("value := queue[id - 1][read_ptr];".equals(action1.toString()) + && "queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action2.toString())) { + final var idLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() + .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); + final var readPtrLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() + .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); + final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) + .findAny().get(); + hardcoded = SmtUtils.distinct(mMgdScript.getScript(), readPtrLeft.getTerm(), + SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), SmtUtils.minus(mMgdScript.getScript(), + idLeft.getTerm(), SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)))); + } else if ("queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action1.toString()) + && "queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action2.toString())) { + final var idLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() + .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); + final var idRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() + .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); + hardcoded = SmtUtils.distinct(mMgdScript.getScript(), idLeft.getTerm(), idRight.getTerm()); + } else if ("queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action1.toString()) + && "value := queue[id - 1][read_ptr];".equals(action2.toString())) { + final var idRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() + .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); + final var readPtrRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() + .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); + final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) + .findAny().get(); + hardcoded = SmtUtils.distinct(mMgdScript.getScript(), readPtrRight.getTerm(), + SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), SmtUtils.minus(mMgdScript.getScript(), + idRight.getTerm(), SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)))); + } else if ("queue := queue[0 := queue[0][write_ptr[0] := idx]];".equals(action1.toString()) + && "value := queue[id - 1][read_ptr];".equals(action2.toString())) { + final var idRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() + .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); + final var readPtrRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() + .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); + final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) + .findAny().get(); + hardcoded = SmtUtils.or(mMgdScript.getScript(), + SmtUtils.distinct(mMgdScript.getScript(), idRight.getTerm(), + SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)), + SmtUtils.distinct(mMgdScript.getScript(), readPtrRight.getTerm(), + SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), + SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ZERO)))); + } + if (hardcoded != null) { + mLogger.warn( + "Hardcoded independence condition for '" + action1 + "' and '" + action2 + "' is: " + hardcoded); + return deinstantiate(clause, thread1, thread2, hardcoded); + } + // first check the cache final var cached = mCache.get(new Pair<>(action1, action2)); if (cached != null) { From 436ddf1782a44b1bf13045f0c04064dd56b94a76 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Sat, 22 Jul 2023 14:33:56 +0200 Subject: [PATCH 089/114] remove unused variable --- .../icfgtochc/concurrent/ThreadModularHornClauseProvider.java | 1 - 1 file changed, 1 deletion(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index 0d3ccc3e57b..e78a1549959 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -173,7 +173,6 @@ private PredicateInfo createInvariantPredicate() { protected Map createLocationMap(final IIcfg icfg) { final var result = new HashMap(); for (final var entry : icfg.getProcedureEntryNodes().entrySet()) { - final var errorNodes = icfg.getProcedureErrorNodes().get(entry.getKey()); final var initial = entry.getValue(); int counter = 0; From 25ec55fc6d2edca5d7e37461a3538ca5e1363a66 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 8 Sep 2023 15:58:13 +0200 Subject: [PATCH 090/114] mark unimplemented settings --- .../icfgtochc/preferences/IcfgToChcPreferenceInitializer.java | 2 ++ .../plugins/icfgtochc/preferences/IcfgToChcPreferences.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 8e0dc07dea6..47dc3db449a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -72,6 +72,7 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize public static final String DESC_THREADMODULAR_LEVEL = "The level at which thread-modular proofs should be computed"; public static final int DEF_THREADMODULAR_LEVEL = 2; + // TODO Currently unused public static final String LABEL_EXPLICIT_LOCATIONS = "Encode control locations explicitly"; public static final String DESC_EXPLICIT_LOCATIONS = "Control locations can be encoded symbolically " + "(as CHC variables), or explicitly (by using different predicate symbols)."; @@ -112,6 +113,7 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "all symmetric preference orders. If we break symmetry, more proofs are accepted."; public static final boolean DEF_BREAK_PREFORDER_SYMMETRY = true; + // TODO Currently unused public static final String LABEL_EXPLICIT_SLEEP = "Encode sleep sets explicitly"; public static final String DESC_EXPLICIT_SLEEP = "Sleep sets can be encoded symbolically (as CHC variables), " + "or explicitly (by using different predicate symbols)."; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 3c16512bd78..395b05afffa 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -62,6 +62,7 @@ public int getThreadModularProofLevel() { return mPrefs.getInt(IcfgToChcPreferenceInitializer.LABEL_THREADMODULAR_LEVEL); } + // TODO Currently unused public boolean explicitLocations() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_LOCATIONS); } @@ -82,6 +83,7 @@ public boolean breakPreferenceOrderSymmetry() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_BREAK_PREFORDER_SYMMETRY); } + // TODO Currently unused public boolean explicitSleep() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_SLEEP); } From 711267059bb6726c091e6b983d0c7d2437d38ad1 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 11 Sep 2023 11:30:50 +0200 Subject: [PATCH 091/114] small settings cleanup --- .../IcfgToChcPreferenceInitializer.java | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 47dc3db449a..c934fddc767 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -65,68 +65,69 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize public static final String DESC_SPEC_MODE = "Describes how the specification for the program is given."; public static final SpecMode DEF_SPEC_MODE = SpecMode.POSTCONDITION; + // TODO Introduce PreferenceType.List? + public static final String LABEL_PARAMETRIC_TEMPLATES = "Templates for parametric program"; + private static final String DESC_PARAMETRIC_TEMPLATES = "Comma-separated list of procedures denoting thread " + + "templates of the parametric program. Leave empty for default behaviour (i.e., single template given " + + "by ULTIMATE.start in Boogie, main in C)."; + private static final String DEF_PARAMETRIC_TEMPLATES = ""; + + public static final String LABEL_PARAMETRIC_SINGLE_THREADS = "Single-instance threads"; + private static final String DESC_PARAMETRIC_SINGLE_THREADS = + "Comma-separated list of procedures for which a single thread is running in a parametric program."; + private static final String DEF_PARAMETRIC_SINGLE_THREADS = ""; + // SETTINGS FOR THREAD-MODULAR PROOFS // ------------------------------------------------------------------------ public static final String LABEL_THREADMODULAR_LEVEL = "Thread-Modular Proof Level"; - public static final String DESC_THREADMODULAR_LEVEL = "The level at which thread-modular proofs should be computed"; - public static final int DEF_THREADMODULAR_LEVEL = 2; + private static final String DESC_THREADMODULAR_LEVEL = + "The level at which thread-modular proofs should be computed"; + private static final int DEF_THREADMODULAR_LEVEL = 2; // TODO Currently unused public static final String LABEL_EXPLICIT_LOCATIONS = "Encode control locations explicitly"; - public static final String DESC_EXPLICIT_LOCATIONS = "Control locations can be encoded symbolically " + private static final String DESC_EXPLICIT_LOCATIONS = "Control locations can be encoded symbolically " + "(as CHC variables), or explicitly (by using different predicate symbols)."; - public static final boolean DEF_EXPLICIT_LOCATIONS = false; + private static final boolean DEF_EXPLICIT_LOCATIONS = false; public static final String LABEL_LIPTON_REDUCTION = "Apply Lipton reduction"; - public static final String DESC_LIPTON_REDUCTION = "If enabled, Lipton reduction is applied to simplify thread " + private static final String DESC_LIPTON_REDUCTION = "If enabled, Lipton reduction is applied to simplify thread " + "templates, before a thread-modular proof is computed."; - public static final boolean DEF_LIPTON_REDUCTION = false; + private static final boolean DEF_LIPTON_REDUCTION = false; public static final String LABEL_SKIP_ASSERT_EDGES = "Skip assert edges"; private static final String DESC_SKIP_ASSERT_EDGES = "If enabled, we do not directly encode unreachability of " + "error locations. Instead, the assertion condition is part of the safety clause."; private static final boolean DEF_SKIP_ASSERT_EDGES = true; - // TODO Introduce PreferenceType.List? - public static final String LABEL_PARAMETRIC_TEMPLATES = "Templates for parametric program"; - private static final String DESC_PARAMETRIC_TEMPLATES = "Comma-separated list of procedures denoting thread " - + "templates of the parametric program. Leave empty for default behaviour (i.e., single template given " - + "by ULTIMATE.start in Boogie, main in C)."; - private static final String DEF_PARAMETRIC_TEMPLATES = ""; - - public static final String LABEL_PARAMETRIC_SINGLE_THREADS = "Single-instance threads"; - private static final String DESC_PARAMETRIC_SINGLE_THREADS = - "Comma-separated list of procedures for which a single thread is running in a parametric program."; - private static final String DEF_PARAMETRIC_SINGLE_THREADS = ""; - // SETTINGS FOR SLEEP SET REDUCTION // ------------------------------------------------------------------------ public static final String LABEL_SLEEP_SET_REDUCTION = "Enable sleep set reduction"; - public static final String DESC_SLEEP_SET_REDUCTION = "If enabled, symbolic sleep set reduction is applied to the " + private static final String DESC_SLEEP_SET_REDUCTION = "If enabled, symbolic sleep set reduction is applied to the " + "program. This allows for more programs to be proven correct."; - public static final boolean DEF_SLEEP_SET_REDUCTION = true; + private static final boolean DEF_SLEEP_SET_REDUCTION = true; public static final String LABEL_BREAK_PREFORDER_SYMMETRY = "Break symmetry of preference order"; - public static final String DESC_BREAK_PREFORDER_SYMMETRY = "A straightforward encoding forces proofs to consider " + private static final String DESC_BREAK_PREFORDER_SYMMETRY = "A straightforward encoding forces proofs to consider " + "all symmetric preference orders. If we break symmetry, more proofs are accepted."; - public static final boolean DEF_BREAK_PREFORDER_SYMMETRY = true; + private static final boolean DEF_BREAK_PREFORDER_SYMMETRY = true; // TODO Currently unused public static final String LABEL_EXPLICIT_SLEEP = "Encode sleep sets explicitly"; - public static final String DESC_EXPLICIT_SLEEP = "Sleep sets can be encoded symbolically (as CHC variables), " + private static final String DESC_EXPLICIT_SLEEP = "Sleep sets can be encoded symbolically (as CHC variables), " + "or explicitly (by using different predicate symbols)."; - public static final boolean DEF_EXPLICIT_SLEEP = false; + private static final boolean DEF_EXPLICIT_SLEEP = false; public static final String LABEL_PREFERENCE_ORDER = "Preference order used for reduction"; - public static final PreferenceOrder DEF_PREFERENCE_ORDER = PreferenceOrder.SEQ_COMP; + private static final PreferenceOrder DEF_PREFERENCE_ORDER = PreferenceOrder.SEQ_COMP; public static final String LABEL_CONDITIONAL_INDEPENDENCE = "Conditional Independence"; - public static final ConditionalIndependence DEF_CONDITIONAL_INDEPENDENCE = ConditionalIndependence.OFF; + private static final ConditionalIndependence DEF_CONDITIONAL_INDEPENDENCE = ConditionalIndependence.OFF; public static final String LABEL_SEMICOMMUTATIVITY = "Use semi-commutativity"; - public static final boolean DEF_SEMICOMMUTATIVITY = true; + private static final boolean DEF_SEMICOMMUTATIVITY = true; public enum PreferenceOrder { SEQ_COMP, LOCKSTEP @@ -153,6 +154,10 @@ protected BaseUltimatePreferenceItem[] initDefaultPreferences() { PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SPEC_MODE, DEF_SPEC_MODE, DESC_SPEC_MODE, PreferenceType.Combo, SpecMode.values()), + new UltimatePreferenceItem<>(LABEL_PARAMETRIC_TEMPLATES, DEF_PARAMETRIC_TEMPLATES, + DESC_PARAMETRIC_TEMPLATES, PreferenceType.String), + new UltimatePreferenceItem<>(LABEL_PARAMETRIC_SINGLE_THREADS, DEF_PARAMETRIC_SINGLE_THREADS, + DESC_PARAMETRIC_SINGLE_THREADS, PreferenceType.String), // Settings for thread-modular proofs new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, DESC_THREADMODULAR_LEVEL, PreferenceType.Integer), @@ -162,10 +167,6 @@ protected BaseUltimatePreferenceItem[] initDefaultPreferences() { PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_SKIP_ASSERT_EDGES, DEF_SKIP_ASSERT_EDGES, DESC_SKIP_ASSERT_EDGES, PreferenceType.Boolean), - new UltimatePreferenceItem<>(LABEL_PARAMETRIC_TEMPLATES, DEF_PARAMETRIC_TEMPLATES, - DESC_PARAMETRIC_TEMPLATES, PreferenceType.String), - new UltimatePreferenceItem<>(LABEL_PARAMETRIC_SINGLE_THREADS, DEF_PARAMETRIC_SINGLE_THREADS, - DESC_PARAMETRIC_SINGLE_THREADS, PreferenceType.String), getSleepSetSettings() }; } From 4561965d29f6b909ac5d776c5b6fbcda72420434 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 11 Sep 2023 15:39:48 +0200 Subject: [PATCH 092/114] add setting for symmetry clauses --- .../ExtensibleHornClauseProvider.java | 4 +- .../ThreadModularHornClauseProvider.java | 59 ++++++++++++++++++- ...eepSetThreadModularHornClauseProvider.java | 4 ++ .../IcfgToChcPreferenceInitializer.java | 4 ++ .../preferences/IcfgToChcPreferences.java | 4 ++ 5 files changed, 70 insertions(+), 5 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java index f98e406ad01..9002db4af77 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ExtensibleHornClauseProvider.java @@ -51,8 +51,8 @@ public ExtensibleHornClauseProvider(final ManagedScript mgdScript, final HcSymbo mSymbolTable = symbolTable; } - protected final HornClauseBuilder createBuilder(final PredicateInfo predicate, final String comment) { - return new HornClauseBuilder(mManagedScript, mSymbolTable, Objects.requireNonNull(predicate), comment); + protected final HornClauseBuilder createBuilder(final PredicateInfo headPredicate, final String comment) { + return new HornClauseBuilder(mManagedScript, mSymbolTable, Objects.requireNonNull(headPredicate), comment); } protected final HornClauseBuilder createBuilder(final String comment) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index e78a1549959..d9ae6fdd513 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -298,6 +298,11 @@ protected List buildAllClauses() { } } + // add symmetry clauses, if enabled + if (mPrefs.useSymmetryClauses()) { + result.addAll(buildSymmetryClauses()); + } + // add safety clauses switch (mPrefs.specMode()) { case ASSERT_VIOLATIONS: @@ -425,6 +430,15 @@ protected boolean isSkippableAssertEdge(final IcfgEdge edge) { return errorLocs.contains(edge.getTarget()); } + private List getCandidateInstancesForClause(final String templateName) { + if (mPrefs.useSymmetryClauses()) { + // If symmetry clauses are used, we only generate clauses for the first instance. + return getInstances(templateName).stream().limit(1L).collect(Collectors.toList()); + } + // Otherwise we generate clauses for each instance. + return getInstances(templateName); + } + private List, Map, ThreadInstance>> getCartesianPrePostProduct(final IcfgEdge edge) { if (edge instanceof IIcfgForkTransitionThreadCurrent) { @@ -432,9 +446,9 @@ protected boolean isSkippableAssertEdge(final IcfgEdge edge) { final var forkEntry = mIcfg.getProcedureEntryNodes().get(forkCurrent.getNameOfForkedProcedure()); final var result = new ArrayList, Map, ThreadInstance>>(); - for (final var instance : getInstances(edge.getPrecedingProcedure())) { + for (final var instance : getCandidateInstancesForClause(edge.getPrecedingProcedure())) { final var preds = Map.of(instance, edge.getSource()); - for (final var forked : getInstances(forkCurrent.getNameOfForkedProcedure())) { + for (final var forked : getCandidateInstancesForClause(forkCurrent.getNameOfForkedProcedure())) { if (Objects.equals(instance, forked)) { continue; } @@ -448,7 +462,7 @@ protected boolean isSkippableAssertEdge(final IcfgEdge edge) { throw new UnsupportedOperationException("Joins not supported"); } - return getInstances(edge.getPrecedingProcedure()).stream() + return getCandidateInstancesForClause(edge.getPrecedingProcedure()).stream() .map(t -> new Triple<>(Map.of(t, edge.getSource()), Map.of(t, edge.getTarget()), t)) .collect(Collectors.toList()); } @@ -679,6 +693,45 @@ protected HornClauseBuilder buildNonInterferenceClause(final IIcfgTransition return clause; } + protected List buildSymmetryClauses() { + final var result = new ArrayList(); + + final var groups = mInstances.stream().collect(Collectors.groupingBy(ThreadInstance::getTemplateName)); + for (final var group : groups.values()) { + // skip trivial groups + if (group.size() <= 1) { + continue; + } + + for (int i = 0; i < group.size() - 1; ++i) { + final var current = group.get(i); + final var next = group.get(i + 1); + final var transposition = Map.of(current, next, next, current); + result.add(buildSymmetryClause(transposition)); + } + } + + return result; + } + + protected HornClauseBuilder buildSymmetryClause(final Map permutation) { + final var clause = createBuilder(mInvariantPredicate, "symmetry clause"); + final var bodyArgs = new ArrayList<>(mInvariantPredicate.getParameters()); + + for (final var entry : permutation.entrySet()) { + assert !entry.getKey().equals(entry.getValue()) : "Identity permutations should be omitted"; + assert entry.getKey().getTemplateName() + .equals(entry.getValue().getTemplateName()) : "Must not permute threads with different templates"; + assert permutation.containsKey(entry.getValue()) : "Not a permutation: " + permutation; + replaceThreadVariables(bodyArgs, entry.getValue(), mThreadSpecificVars.get(entry.getKey())); + } + + final var bodyTerms = bodyArgs.stream().map(v -> clause.getBodyVar(v).getTerm()).collect(Collectors.toList()); + clause.addBodyPredicate(mInvariantPredicate, bodyTerms); + + return clause; + } + protected void replaceThreadVariables(final List parameters, final ThreadInstance oldInstance, final List newVariables) { final var oldVariables = mThreadSpecificVars.get(oldInstance); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index ea2f9b76380..065bd322007 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -71,6 +71,10 @@ public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider se e -> e.getValue().values().stream().filter(this::isRelevantLocation).collect(Collectors.toList()))); if (mPrefs.breakPreferenceOrderSymmetry()) { + if (mPrefs.useSymmetryClauses()) { + throw new UnsupportedOperationException( + "Symmetry clauses cannot be combined with preference order symmetry breaking"); + } mIdVars = null; mPreferenceManager = new ExplicitPreferenceOrderManager(preferenceOrder, mScript, mLocationIndices); } else { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index c934fddc767..95ab8097031 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -85,6 +85,9 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize "The level at which thread-modular proofs should be computed"; private static final int DEF_THREADMODULAR_LEVEL = 2; + public static final String LABEL_SYMMETRY_CLAUSES = "Use symmetry clauses"; + private static final boolean DEF_SYMMETRY_CLAUSES = false; + // TODO Currently unused public static final String LABEL_EXPLICIT_LOCATIONS = "Encode control locations explicitly"; private static final String DESC_EXPLICIT_LOCATIONS = "Control locations can be encoded symbolically " @@ -161,6 +164,7 @@ protected BaseUltimatePreferenceItem[] initDefaultPreferences() { // Settings for thread-modular proofs new UltimatePreferenceItem<>(LABEL_THREADMODULAR_LEVEL, DEF_THREADMODULAR_LEVEL, DESC_THREADMODULAR_LEVEL, PreferenceType.Integer), + new UltimatePreferenceItem<>(LABEL_SYMMETRY_CLAUSES, DEF_SYMMETRY_CLAUSES, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_EXPLICIT_LOCATIONS, DEF_EXPLICIT_LOCATIONS, DESC_EXPLICIT_LOCATIONS, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_LIPTON_REDUCTION, DEF_LIPTON_REDUCTION, DESC_LIPTON_REDUCTION, diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index 395b05afffa..dd5c7319a70 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -62,6 +62,10 @@ public int getThreadModularProofLevel() { return mPrefs.getInt(IcfgToChcPreferenceInitializer.LABEL_THREADMODULAR_LEVEL); } + public boolean useSymmetryClauses() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_SYMMETRY_CLAUSES); + } + // TODO Currently unused public boolean explicitLocations() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_LOCATIONS); From dcd3a62bdbcf86332dc6e610dcfddfd7cf52d467 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 11 Sep 2023 15:42:29 +0200 Subject: [PATCH 093/114] prepare evaluation with symmetry clauses --- .../default/benchexec/sleep-threadmodular.xml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index a9691a0dab5..e8523d5e181 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -75,6 +75,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b633ca11446b3993a955c0d91cfa290e2877857f Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 12 Sep 2023 10:23:57 +0200 Subject: [PATCH 094/114] fix NullPointerException for clause without constraint --- .../plugins/icfgtochc/concurrent/HornClauseBuilder.java | 3 ++- .../uni_freiburg/informatik/ultimate/lib/chc/HornClause.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 9eef5ef7916..91432321bab 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -43,6 +43,7 @@ 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.Substitution; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; @@ -166,7 +167,7 @@ private Term substitute(final Term term) { private Term getSubstitutedConstraint() { if (mConstraints.isEmpty()) { - return null; + return mManagedScript.getScript().term(SMTLIBConstants.TRUE); } return substitute(SmtUtils.and(mManagedScript.getScript(), mConstraints)); } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java index 0d36237fcbc..67b1f6add19 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -122,7 +123,7 @@ private HornClause(final ManagedScript script, final HcSymbolTable symbolTable, mHornClauseSymbolTable = symbolTable; - mFormula = constraint; + mFormula = Objects.requireNonNull(constraint, "Constraint must not be null (use 'true' instead)"); mHeadIsFalse = headPred == null; mHeadPredicate = headPred; From 6de61bb98f6b045c198751dd76abc0c78fe4e16c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 12 Sep 2023 10:37:03 +0200 Subject: [PATCH 095/114] HornClause: remove unused ManagedScript parameter --- .../icfgtochc/ChcProviderForCalls.java | 18 ++++++++--------- .../concurrent/HornClauseBuilder.java | 7 +++---- .../ultimate/lib/chc/ChcTransferrer.java | 5 ++--- .../ultimate/lib/chc/HornClause.java | 20 ++++++++----------- .../source/smtparser/chc/HornClauseHead.java | 8 ++++---- 5 files changed, 26 insertions(+), 32 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java index c70c9a88b3f..60c6baa785d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/ChcProviderForCalls.java @@ -198,7 +198,7 @@ private void computeClausesForEntryPoints(final IIcfg throw new UnsupportedOperationException("implement this"); } - final HornClause chc = new HornClause(mMgdScript, mHcSymbolTable, constraintFinal, headPred, headVars, + final HornClause chc = new HornClause(mHcSymbolTable, constraintFinal, headPred, headVars, Collections.emptyList(), Collections.emptyList(), Collections.emptySet()); chc.setComment("Type: (not V) -> procEntry"); resultChcs.add(chc); @@ -243,8 +243,8 @@ private void computeClausesForExitPoints(final IIcfg< throw new UnsupportedOperationException("implement this"); } - final HornClause chc = new HornClause(mMgdScript, mHcSymbolTable, constraint, - Collections.singletonList(bodyPred), Collections.singletonList(firstPredArgs), bodyVars); + final HornClause chc = new HornClause(mHcSymbolTable, constraint, Collections.singletonList(bodyPred), + Collections.singletonList(firstPredArgs), bodyVars); chc.setComment("Type: entryProcExit(..., V) /\\ V -> false"); resultChcs.add(chc); @@ -492,8 +492,8 @@ private Collection computeChcForReturnEdge(final IIcfgReturnTransiti /* construct the horn clause and add it to the resulting chc set */ final Collection chcs = new ArrayList<>(); - chcs.add(new HornClause(mMgdScript, mHcSymbolTable, constraintFinal, headPred, headVars, bodyPreds, - bodyPredToArguments, bodyVars)); + chcs.add(new HornClause(mHcSymbolTable, constraintFinal, headPred, headVars, bodyPreds, bodyPredToArguments, + bodyVars)); return chcs; } @@ -644,8 +644,8 @@ private boolean assertNoFreeVars(final List headVars, final Set chcs = new ArrayList<>(); - chcs.add(new HornClause(mMgdScript, mHcSymbolTable, constraintFinal, headPred, headVars, bodyPreds, - bodyPredToArguments, bodyVars)); + chcs.add(new HornClause(mHcSymbolTable, constraintFinal, headPred, headVars, bodyPreds, bodyPredToArguments, + bodyVars)); return chcs; } @@ -781,8 +781,8 @@ private boolean assertNoFreeVars(final List headVars, final Set chcs = new ArrayList<>(2); - chcs.add(new HornClause(mMgdScript, mHcSymbolTable, constraintFinal, headPred, headVars, bodyPreds, - bodyPredToArguments, bodyVars)); + chcs.add(new HornClause(mHcSymbolTable, constraintFinal, headPred, headVars, bodyPreds, bodyPredToArguments, + bodyVars)); return chcs; } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java index 91432321bab..43a55b0d63a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HornClauseBuilder.java @@ -131,13 +131,12 @@ public HornClause build() { HornClause clause; if (mHeadPredicate == null) { - clause = new HornClause(mManagedScript, mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, - mBodyVars); + clause = new HornClause(mSymbolTable, constraint, mBodyPreds, substitutedBodyArgs, mBodyVars); } else { final var headArgs = mHeadPredicate.getParameters().stream().map(this::getHeadVar).collect(Collectors.toList()); - clause = new HornClause(mManagedScript, mSymbolTable, constraint, mHeadPredicate.getPredicate(), headArgs, - mBodyPreds, substitutedBodyArgs, mBodyVars); + clause = new HornClause(mSymbolTable, constraint, mHeadPredicate.getPredicate(), headArgs, mBodyPreds, + substitutedBodyArgs, mBodyVars); } if (mComment != null) { clause.setComment(mComment); diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java index c582560abcd..7efb2678413 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/ChcTransferrer.java @@ -174,11 +174,10 @@ public HornClause transfer(final HornClause clause) { final var constraint = transfer(clause.getConstraintFormula()); if (clause.isHeadFalse()) { - return new HornClause(mTargetScript, mTargetSymbolTable, constraint, bodyPreds, bodyArgs, bodyVars); + return new HornClause(mTargetSymbolTable, constraint, bodyPreds, bodyArgs, bodyVars); } - return new HornClause(mTargetScript, mTargetSymbolTable, constraint, head, headVars, bodyPreds, bodyArgs, - bodyVars); + return new HornClause(mTargetSymbolTable, constraint, head, headVars, bodyPreds, bodyArgs, bodyVars); }); } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java index 67b1f6add19..ef1fbb37f0b 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/HornClause.java @@ -88,17 +88,15 @@ public class HornClause implements IRankedLetter { * @param bodyPreds * @param bodyPredToArguments */ - public HornClause(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, final Term constraint, - final List bodyPreds, final List> bodyPredToArguments, - final Set bodyVars) { - this(mgdScript, hcSymbolTable, constraint, null, Collections.emptyList(), bodyPreds, bodyPredToArguments, - bodyVars, false); + public HornClause(final HcSymbolTable hcSymbolTable, final Term constraint, final List bodyPreds, + final List> bodyPredToArguments, final Set bodyVars) { + this(hcSymbolTable, constraint, null, Collections.emptyList(), bodyPreds, bodyPredToArguments, bodyVars, false); } - public HornClause(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTable, final Term constraint, - final HcPredicateSymbol headPred, final List headVars, final List bodyPreds, + public HornClause(final HcSymbolTable hcSymbolTable, final Term constraint, final HcPredicateSymbol headPred, + final List headVars, final List bodyPreds, final List> bodyPredToArguments, final Set bodyVars) { - this(mgdScript, hcSymbolTable, constraint, headPred, headVars, bodyPreds, bodyPredToArguments, bodyVars, false); + this(hcSymbolTable, constraint, headPred, headVars, bodyPreds, bodyPredToArguments, bodyVars, false); assert headPred != null : "use other constructor for '... -> False' case"; } @@ -106,8 +104,6 @@ public HornClause(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTab * Constructor for a Horn clause of the form b1 /\ ... /\ bn /\ constraint --> h. Where b1 .. bn, and h, are * uninterpreted predicates and constraint is a Term. * - * @param script - * The script that will be used in TreeAutomizer (not the HornClauseParserScript) * @param symbolTable * @param constraint * @param headPred @@ -117,8 +113,8 @@ public HornClause(final ManagedScript mgdScript, final HcSymbolTable hcSymbolTab * @param dummy * dummy parameter to allow for an extra constructor */ - private HornClause(final ManagedScript script, final HcSymbolTable symbolTable, final Term constraint, - final HcPredicateSymbol headPred, final List headVars, final List bodyPreds, + private HornClause(final HcSymbolTable symbolTable, final Term constraint, final HcPredicateSymbol headPred, + final List headVars, final List bodyPreds, final List> bodyPredToArgs, final Set bodyVars, final boolean dummy) { mHornClauseSymbolTable = symbolTable; diff --git a/trunk/source/SmtParser/src/de/uni_freiburg/informatik/ultimate/source/smtparser/chc/HornClauseHead.java b/trunk/source/SmtParser/src/de/uni_freiburg/informatik/ultimate/source/smtparser/chc/HornClauseHead.java index f3d22bfa915..2d55f16a4af 100644 --- a/trunk/source/SmtParser/src/de/uni_freiburg/informatik/ultimate/source/smtparser/chc/HornClauseHead.java +++ b/trunk/source/SmtParser/src/de/uni_freiburg/informatik/ultimate/source/smtparser/chc/HornClauseHead.java @@ -110,14 +110,14 @@ public HornClause convertToHornClause(final ManagedScript solverScript, final Hc final List> bodyArgs = mBody.getPredicateToVars(symbolTable); if (mHead == null) { - return new HornClause(solverScript, symbolTable, getTransitionFormula(solverScript.getScript()), - bodySymbols, bodyArgs, bodyVars); + return new HornClause(symbolTable, getTransitionFormula(solverScript.getScript()), bodySymbols, bodyArgs, + bodyVars); } final List headVars = symbolTable.getHcHeadVarsForPredSym(headSymbol, false); - return new HornClause(solverScript, symbolTable, getTransitionFormula(solverScript.getScript()), headSymbol, - headVars, bodySymbols, bodyArgs, bodyVars); + return new HornClause(symbolTable, getTransitionFormula(solverScript.getScript()), headSymbol, headVars, + bodySymbols, bodyArgs, bodyVars); } /** From dd9be6704745c4ec6205fb0b53bdcf1582bcfc9a Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 12 Sep 2023 10:44:36 +0200 Subject: [PATCH 096/114] prepare evaluation --- .../default/benchexec/sleep-threadmodular.xml | 218 ++++++++++-------- 1 file changed, 124 insertions(+), 94 deletions(-) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index e8523d5e181..23ba38016fa 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -2,161 +2,191 @@ ${taskdef_path}/CHC_*.smt2 - - - - - + + + + - - - - + + + + - - - - + + + + - + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + ../../../trunk/examples/threadmodular/regression/*/*.yml ../../../trunk/examples/svcomp/properties/unreach-call.prp From 413081681f424fe05429144cce149eb7144d0d9b Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 13 Sep 2023 11:20:25 +0200 Subject: [PATCH 097/114] prepare evaluation of yet-unsolved tasks --- releaseScripts/default/benchexec/sleep-threadmodular.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index 23ba38016fa..9fbba9a5983 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -1,5 +1,5 @@ - + ${taskdef_path}/CHC_*.smt2 + + + ../../../trunk/examples/threadmodular/regression/unsolved.set + ../../../trunk/examples/svcomp/properties/unreach-call.prp + From f7999944384403c1ceeb3e695afb93b2418579f9 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 14 Sep 2023 10:28:19 +0200 Subject: [PATCH 098/114] ChcSolver: support passing predicate hints to eldarica --- .../plugins/chcsolver/ChcSolverObserver.java | 18 +++++++++++++++- .../ChcSolverPreferenceInitializer.java | 5 ++++- .../preferences/ChcSolverPreferences.java | 11 ++++++++++ .../lib/chc/EldaricaCliChcScript.java | 21 +++++++++++++++++-- .../ultimate/smtsolver/external/Executor.java | 14 +++++++++++-- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java index 568a5c68b1b..1a25602d105 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/ChcSolverObserver.java @@ -26,6 +26,8 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.chcsolver; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Set; import de.uni_freiburg.informatik.ultimate.core.lib.observers.BaseObserver; @@ -100,7 +102,7 @@ private IChcScript getBackend(final HornAnnot annotation) { switch (mPrefs.getBackend()) { case ELDARICA: // return new EldaricaChcScript(mServices, annotation.getScript().getScript()); - return new EldaricaCliChcScript(mServices, annotation.getScript()); + return new EldaricaCliChcScript(mServices, annotation.getScript(), getHintsFile()); case Z3: return createZ3Backend(); case TREEAUTOMIZER: @@ -113,6 +115,20 @@ private IChcScript getBackend(final HornAnnot annotation) { } } + private Path getHintsFile() { + final var hintsPath = mPrefs.getEldaricaHints(); + if (hintsPath == null) { + return null; + } + if (!Files.exists(hintsPath)) { + mLogger.warn("Specified file with eldarica hints does not exist: %s", hintsPath); + mLogger.warn("Starting eldarica without hints..."); + return null; + } + mLogger.warn("Passing given hints to eldarica: %s", hintsPath); + return hintsPath; + } + private SmtChcScript createZ3Backend() { // We use a fresh Z3 instance to solve the system. // In typical toolchains, the solver in the HornAnnot is often unsuitable: diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java index faa51061e31..776069a8812 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferenceInitializer.java @@ -60,6 +60,8 @@ public enum SolverBackend { public static final String LABEL_PRODUCE_UNSAT_CORES = "Produce UNSAT core if query is UNSAT"; private static final boolean DEF_PRODUCE_UNSAT_CORES = false; + public static final String LABEL_ELDARICA_HINTS_FILE = "Hints for eldarica"; + public ChcSolverPreferenceInitializer() { super(Activator.PLUGIN_ID, Activator.PLUGIN_NAME); } @@ -74,7 +76,8 @@ protected UltimatePreferenceItem[] initDefaultPreferences() { new UltimatePreferenceItem<>(LABEL_PRODUCE_MODEL, DEF_PRODUCE_MODEL, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_PRODUCE_DERIVATION, DEF_PRODUCE_DERIVATION, PreferenceType.Boolean), new UltimatePreferenceItem<>(LABEL_PRODUCE_UNSAT_CORES, DEF_PRODUCE_UNSAT_CORES, - PreferenceType.Boolean) }; + PreferenceType.Boolean), + new UltimatePreferenceItem<>(LABEL_ELDARICA_HINTS_FILE, "", PreferenceType.File) }; } public static IPreferenceProvider getPreferenceProvider(final IUltimateServiceProvider services) { diff --git a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java index 4a98f94dd64..db59fa5a73d 100644 --- a/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java +++ b/trunk/source/ChcSolver/src/de/uni_freiburg/informatik/ultimate/plugins/chcsolver/preferences/ChcSolverPreferences.java @@ -26,6 +26,9 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.chcsolver.preferences; +import java.nio.file.Path; +import java.nio.file.Paths; + import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; import de.uni_freiburg.informatik.ultimate.plugins.chcsolver.preferences.ChcSolverPreferenceInitializer.SolverBackend; @@ -56,4 +59,12 @@ public boolean produceUnsatCore() { public long getTimeout() { return mPrefs.getInt(ChcSolverPreferenceInitializer.LABEL_SOLVER_TIMEOUT); } + + public Path getEldaricaHints() { + final String value = mPrefs.getString(ChcSolverPreferenceInitializer.LABEL_ELDARICA_HINTS_FILE); + if (value == null || value.isEmpty()) { + return null; + } + return Paths.get(value); + } } diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java index b900dff513e..f669b5ea89e 100644 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java +++ b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/EldaricaCliChcScript.java @@ -28,6 +28,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.Set; @@ -54,6 +55,7 @@ public class EldaricaCliChcScript implements IChcScript { private final ILogger mLogger; private final ManagedScript mMgdScript; private final long mDefaultQueryTimeout; + private final Path mPredicates; private boolean mProduceModels = false; @@ -61,15 +63,21 @@ public class EldaricaCliChcScript implements IChcScript { private Model mLastModel = null; public EldaricaCliChcScript(final IUltimateServiceProvider services, final ManagedScript mgdScript) { - this(services, mgdScript, -1L); + this(services, mgdScript, null); } public EldaricaCliChcScript(final IUltimateServiceProvider services, final ManagedScript mgdScript, - final long defaultTimeout) { + final Path predicates) { + this(services, mgdScript, -1L, predicates); + } + + public EldaricaCliChcScript(final IUltimateServiceProvider services, final ManagedScript mgdScript, + final long defaultTimeout, final Path predicates) { mServices = services; mLogger = services.getLoggingService().getLogger(getClass()); mMgdScript = mgdScript; mDefaultQueryTimeout = defaultTimeout; + mPredicates = predicates; } @Override @@ -105,6 +113,12 @@ public LBool solve(final HcSymbolTable symbolTable, final List syste final var executor = new Executor(getCommand(tmpFile), mMgdScript.getScript(), mLogger, mServices, "eldarica", null, null, null, determineTimeout(timeout)); + if (mPredicates != null) { + // Skip the line in stdout that says: + // "---------------------------- Loading CEGAR hints -------------------------------" + executor.skipLine(); + } + mLastResult = executor.parseCheckSatResult(); mLastModel = (mLastResult == LBool.SAT && mProduceModels) ? executor.parseGetModelResult() : null; @@ -126,6 +140,9 @@ private String getCommand(final File file) { if (mProduceModels) { command += " -ssol"; } + if (mPredicates != null) { + command += " -hints:" + mPredicates; + } return command + " " + file.getAbsolutePath(); } diff --git a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/Executor.java b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/Executor.java index 37a8e707389..9533f8dd798 100644 --- a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/Executor.java +++ b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/Executor.java @@ -27,6 +27,7 @@ */ package de.uni_freiburg.informatik.ultimate.smtsolver.external; +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; @@ -69,6 +70,7 @@ public class Executor { private BufferedWriter mWriter; private InputStream mStdErr; + private InputStream mStdOut; private final Script mScript; private final Parser mParser; @@ -132,7 +134,7 @@ private void createProcess() throws IOException { } final OutputStream stdin = mProcess.getOutputStream(); - final InputStream stdout = mProcess.getInputStream(); + mStdOut = mProcess.getInputStream(); if (mTimeout > 0) { mProcess.setCountdownToTermination(mTimeout); @@ -143,7 +145,7 @@ private void createProcess() throws IOException { mStdErr = mProcess.getErrorStream(); final SimpleSymbolFactory symfactory = new SimpleSymbolFactory(); - mLexer = new Lexer(new InputStreamReader(stdout)); + mLexer = new Lexer(new InputStreamReader(mStdOut)); mLexer.setSymbolFactory(symfactory); final OutputStream underlying; @@ -163,6 +165,14 @@ private void createProcess() throws IOException { } } + public String skipLine() { + try { + return new BufferedReader(new InputStreamReader(mStdOut)).readLine(); + } catch (final IOException e) { + throw convertIOException(e); + } + } + public void input(final String in) { if (mLogger.isDebugEnabled()) { mLogger.debug(getLogStringPrefix() + " " + in); From 2ffed6393be955fcd53afda63505905ba59b16ed Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 00:55:00 +0100 Subject: [PATCH 099/114] add test suite for thread-modular proofs with sleep set reduction --- .gitignore | 1 + .../parameterized/SleepExplicit-Eldarica.epf | 41 ++++ .../bpl/parameterized/SleepExplicit-Golem.epf | 41 ++++ .../bpl/parameterized/SleepExplicit-Z3.epf | 41 ++++ .../parameterized/ThreadModularVerifier.xml | 10 + .../bpl/parameterized/add-sub-k/add-sub-k.bpl | 15 ++ .../bpl/parameterized/add-sub-k/add-sub-k.yml | 22 ++ .../add-sub-positive-k/add-sub-positive-k.bpl | 16 ++ .../add-sub-positive-k/add-sub-positive-k.yml | 22 ++ .../bluetooth-better/bluetooth-better.bpl | 44 ++++ .../bluetooth-better/bluetooth-better.yml | 22 ++ .../equalsum-fork/equalsum-fork.bpl | 50 +++++ .../equalsum-fork/equalsum-fork.yml | 23 ++ .../equalsum-ghost/equalsum-ghost.bpl | 32 +++ .../equalsum-ghost/equalsum-ghost.yml | 22 ++ .../bpl/parameterized/inc-bdec/inc-bdec.bpl | 15 ++ .../bpl/parameterized/inc-bdec/inc-bdec.yml | 21 ++ .../inc-dec-eq0-locked-assert.bpl | 22 ++ .../inc-dec-eq0-locked-assert.yml | 22 ++ .../inc-dec-eq0-locked/inc-dec-eq0-locked.bpl | 22 ++ .../inc-dec-eq0-locked/inc-dec-eq0-locked.yml | 22 ++ .../parameterized/inc-dec-eq0/inc-dec-eq0.bpl | 13 ++ .../parameterized/inc-dec-eq0/inc-dec-eq0.yml | 22 ++ .../inc-dec-geq0/inc-dec-geq0.bpl | 13 ++ .../inc-dec-geq0/inc-dec-geq0.yml | 22 ++ .../parameterized/line-queue/line-queue.bpl | 59 +++++ .../parameterized/line-queue/line-queue.yml | 24 ++ .../bpl/parameterized/lock/lock.bpl | 30 +++ .../bpl/parameterized/lock/lock.yml | 22 ++ .../bpl/parameterized/mutex-3/mutex-3.bpl | 17 ++ .../bpl/parameterized/mutex-3/mutex-3.yml | 22 ++ .../bpl/parameterized/mutex-4/mutex-4.bpl | 17 ++ .../bpl/parameterized/mutex-4/mutex-4.yml | 22 ++ .../bpl/parameterized/mutex-5/mutex-5.bpl | 17 ++ .../bpl/parameterized/mutex-5/mutex-5.yml | 22 ++ .../mutex-unbounded/mutex-unbounded.bpl | 14 ++ .../mutex-unbounded/mutex-unbounded.yml | 22 ++ .../notify-listeners/notify-listeners.bpl | 44 ++++ .../notify-listeners/notify-listeners.yml | 23 ++ .../numbered-array/numbered-array.bpl | 17 ++ .../numbered-array/numbered-array.yml | 21 ++ .../thread-pooling/thread-pooling.bpl | 46 ++++ .../thread-pooling/thread-pooling.yml | 21 ++ .../bpl/parameterized/ticket/ticket.bpl | 32 +++ .../bpl/parameterized/ticket/ticket.yml | 22 ++ .../test/decider/ChcTestResultDecider.java | 2 +- .../SleepThreadModularChcTestSuite.java | 206 ++++++++++++++++++ 47 files changed, 1317 insertions(+), 1 deletion(-) create mode 100644 trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf create mode 100644 trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf create mode 100644 trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf create mode 100644 trunk/examples/concurrent/bpl/parameterized/ThreadModularVerifier.xml create mode 100644 trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/lock/lock.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/lock/lock.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/ticket/ticket.bpl create mode 100644 trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml create mode 100644 trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java diff --git a/.gitignore b/.gitignore index cc8c2c9e8ce..b888d587d14 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ trunk/examples/concurrent/bpl/VMCAI2021/generated/*.yml trunk/examples/concurrent/bpl/weaver-benchmarks/generated/**/*.bpl trunk/examples/concurrent/bpl/weaver-benchmarks/generated/**/*.yml trunk/examples/concurrent/bpl/weaver-benchmarks/weaver +trunk/examples/concurrent/bpl/parameterized/*/CHC*.smt2 **/.metadata/* **/.settings/* **/target/* diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf new file mode 100644 index 00000000000..d06257bb32e --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf @@ -0,0 +1,41 @@ +#Thu May 25 14:24:13 CEST 2023 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc= +# Settings for the program +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC +# Settings for sleep sets +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=PRECOMPUTED_CONDITIONS +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true +# Other settings +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Apply\ Lipton\ reduction=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ control\ locations\ explicitly=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ sleep\ sets\ explicitly=false +@de.uni_freiburg.informatik.ultimate.plugins.icfgtochc=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver= +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/CHC\ solver\ backend=ELDARICA +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ CHC\ model\ if\ query\ is\ SAT=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ UNSAT\ core\ if\ query\ is\ UNSAT=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ derivation\ if\ query\ is\ UNSAT=true +@de.uni_freiburg.informatik.ultimate.plugins.chcsolver=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.chcprinter= +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/File\ name=CHC +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Use\ automatic\ naming=true +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Save\ file\ in\ source\ directory=true +@de.uni_freiburg.informatik.ultimate.chcprinter=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder= +/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Add\ additional\ assume\ for\ each\ assert=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Size\ of\ a\ code\ block=OneNontrivialStatement +@de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder=0.2.3 +file_export_version=3.0 diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf new file mode 100644 index 00000000000..204060959c6 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf @@ -0,0 +1,41 @@ +#Thu May 25 14:24:13 CEST 2023 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc= +# Settings for the program +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC +# Settings for sleep sets +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=PRECOMPUTED_CONDITIONS +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true +# Other settings +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Apply\ Lipton\ reduction=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ control\ locations\ explicitly=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ sleep\ sets\ explicitly=false +@de.uni_freiburg.informatik.ultimate.plugins.icfgtochc=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver= +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/CHC\ solver\ backend=GOLEM +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ CHC\ model\ if\ query\ is\ SAT=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ UNSAT\ core\ if\ query\ is\ UNSAT=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ derivation\ if\ query\ is\ UNSAT=false +@de.uni_freiburg.informatik.ultimate.plugins.chcsolver=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.chcprinter= +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/File\ name=CHC +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Use\ automatic\ naming=true +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Save\ file\ in\ source\ directory=true +@de.uni_freiburg.informatik.ultimate.chcprinter=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder= +/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Add\ additional\ assume\ for\ each\ assert=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Size\ of\ a\ code\ block=OneNontrivialStatement +@de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder=0.2.3 +file_export_version=3.0 diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf new file mode 100644 index 00000000000..dca3cb84999 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf @@ -0,0 +1,41 @@ +#Thu May 25 14:24:13 CEST 2023 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc= +# Settings for the program +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC +# Settings for sleep sets +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=PRECOMPUTED_CONDITIONS +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true +# Other settings +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Apply\ Lipton\ reduction=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ control\ locations\ explicitly=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ sleep\ sets\ explicitly=false +@de.uni_freiburg.informatik.ultimate.plugins.icfgtochc=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver= +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/CHC\ solver\ backend=Z3 +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ CHC\ model\ if\ query\ is\ SAT=true +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ UNSAT\ core\ if\ query\ is\ UNSAT=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ derivation\ if\ query\ is\ UNSAT=false +@de.uni_freiburg.informatik.ultimate.plugins.chcsolver=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.chcprinter= +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/File\ name=CHC +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Use\ automatic\ naming=true +/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Save\ file\ in\ source\ directory=true +@de.uni_freiburg.informatik.ultimate.chcprinter=0.2.3 +file_export_version=3.0 + + +\!/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder= +/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Add\ additional\ assume\ for\ each\ assert=false +/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Size\ of\ a\ code\ block=OneNontrivialStatement +@de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder=0.2.3 +file_export_version=3.0 diff --git a/trunk/examples/concurrent/bpl/parameterized/ThreadModularVerifier.xml b/trunk/examples/concurrent/bpl/parameterized/ThreadModularVerifier.xml new file mode 100644 index 00000000000..ebd05ee0c64 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/ThreadModularVerifier.xml @@ -0,0 +1,10 @@ + + Ultimate Toolchain + + + + + + + + diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.bpl b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.bpl new file mode 100644 index 00000000000..6901d6774d5 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.bpl @@ -0,0 +1,15 @@ +//#Safe + +var x : int; + +procedure ULTIMATE.start() +modifies x; +free requires x == 0; +free ensures x == 0; +{ + var k : int; + + havoc k; + x := x + k; + x := x - k; +} diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml new file mode 100644 index 00000000000..ec88e261555 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'add-sub-k.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.bpl b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.bpl new file mode 100644 index 00000000000..92c4ec1eb66 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.bpl @@ -0,0 +1,16 @@ +//#Safe + +var x : int; + +procedure ULTIMATE.start() +modifies x; +free requires x == 0; +free ensures x == 0; +{ + var k : int; + + havoc k; + assume k >= 0; + x := x + k; + x := x - k; +} diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml new file mode 100644 index 00000000000..c069c28c28a --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'add-sub-positive-k.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.bpl b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.bpl new file mode 100644 index 00000000000..0ca93ed8328 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.bpl @@ -0,0 +1,44 @@ +//#Safe + +var stoppingFlag, stoppingEvent, stopped : bool; +var pendingIo : int; + +procedure ULTIMATE.start() +free requires pendingIo == 1 && !stopped && !stoppingEvent && !stoppingFlag; +modifies stoppingEvent, pendingIo; +{ + // enter + atomic { + assume !stoppingFlag; + pendingIo := pendingIo + 1; + } + + // do work + assert !stopped; + + // exit + atomic { + pendingIo := pendingIo - 1; + if (pendingIo == 0) { + stoppingEvent := true; + } + } +} + +procedure server() +free requires !stopped; +modifies stoppingFlag, stoppingEvent, stopped, pendingIo; +{ + stoppingFlag := true; + + // close + atomic { + pendingIo := pendingIo - 1; + if (pendingIo == 0) { + stoppingEvent := true; + } + } + + assume stoppingEvent; + stopped := true; +} diff --git a/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml new file mode 100644 index 00000000000..b0e8fba9413 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'bluetooth-better.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: server + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.bpl b/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.bpl new file mode 100644 index 00000000000..a265eda45ab --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.bpl @@ -0,0 +1,50 @@ +//#Safe + +var A : [int]int; +var n : int; + +var x, y, i, j, m : int; + +procedure ULTIMATE.start() +modifies x,y; +{ + var c : int; + + assume 0 <= i && i < j && j < m; + + // fork m threads + c := 0; + while (c < m) { + fork c thread(c); + c := c + 1; + } + + // join m threads + c := 0; + while (c < m) { + join c; + c := c + 1; + } + + assert x == y; +} + +procedure thread(id : int) +modifies x, y; +{ + var sum, idx : int; + sum := 0; + idx := 0; + + while (idx < n) { + sum := sum + A[idx]; + idx := idx + 1; + } + + if (id == i) { + x := sum; + } + if (id == j) { + y := sum; + } +} diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml b/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml new file mode 100644 index 00000000000..a8ac04404ca --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml @@ -0,0 +1,23 @@ +format_version: '2.0' + +input_files: 'equalsum-fork.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + Concurrency mode: SINGLE_MAIN_THREAD + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.bpl b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.bpl new file mode 100644 index 00000000000..af4c5113b26 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.bpl @@ -0,0 +1,32 @@ +//#Safe + +var A : [int]int; +var n : int; + +var id_ctr : int; +var i, sum_i : int; +var terminated_i : bool; + +procedure ULTIMATE.start() +free requires !terminated_i; +modifies id_ctr, sum_i, terminated_i; +{ + var id, sum, idx : int; + atomic { id := id_ctr; id_ctr := id_ctr + 1; } + + sum := 0; + idx := 0; + + while (idx < n) { + sum := sum + A[idx]; + idx := idx + 1; + } + + atomic { + if (id == i) { + sum_i := sum; + terminated_i := true; + } + } + assert (terminated_i ==> sum == sum_i); +} diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml new file mode 100644 index 00000000000..93d3235a312 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'equalsum-ghost.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.bpl b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.bpl new file mode 100644 index 00000000000..f1ec76411e6 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.bpl @@ -0,0 +1,15 @@ +//#Safe + +var x : int; + +procedure ULTIMATE.start() +modifies x; +free requires x == 0; +free ensures x == 0; +{ + x := x + 1; + atomic { + assume x > 0; + x := x - 1; + } +} diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml new file mode 100644 index 00000000000..3df1a227646 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml @@ -0,0 +1,21 @@ +format_version: '2.0' + +input_files: 'inc-bdec.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.bpl b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.bpl new file mode 100644 index 00000000000..44e92278dde --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.bpl @@ -0,0 +1,22 @@ +//#Safe + +var x : int; +var lock : bool; + +procedure thread() +free requires x == 0; +modifies x, lock; +{ + atomic { assume !lock; lock := true; } + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + x := x - 1; + x := x - 1; + x := x - 1; + x := x - 1; + assert x == 0; + lock := false; +} + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml new file mode 100644 index 00000000000..9c8a7388451 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'inc-dec-eq0-locked-assert.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.bpl b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.bpl new file mode 100644 index 00000000000..2f2dd0932f6 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.bpl @@ -0,0 +1,22 @@ +//#Safe + +var x : int; +var lock : bool; + +procedure thread() +free requires x == 0; +free ensures x == 0; +modifies x, lock; +{ + atomic { assume !lock; lock := true; } + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + x := x - 1; + x := x - 1; + x := x - 1; + x := x - 1; + lock := false; +} + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml new file mode 100644 index 00000000000..e79199cc0af --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'inc-dec-eq0-locked.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.bpl b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.bpl new file mode 100644 index 00000000000..362c51e977e --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.bpl @@ -0,0 +1,13 @@ +//#Safe + +var x : int; + +procedure thread() +free requires x == 0; +free ensures x == 0; +modifies x; +{ + x := x + 1; + x := x - 1; +} + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml new file mode 100644 index 00000000000..161f8bd6eee --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'inc-dec-eq0.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.bpl b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.bpl new file mode 100644 index 00000000000..d1469865325 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.bpl @@ -0,0 +1,13 @@ +//#Safe + +var x : int; + +procedure thread() +free requires x == 0; +modifies x; +{ + x := x + 1; + x := x - 1; + assert x >= 0; +} + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml new file mode 100644 index 00000000000..d9481da80d6 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'inc-dec-geq0.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.bpl b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.bpl new file mode 100644 index 00000000000..f8723a14581 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.bpl @@ -0,0 +1,59 @@ +//#Safe + +var ctr : int; + +var queue : [int][int]int; +var write_ptr : [int]int; + +function { :const_array } init(value : int) returns ([int]int); + +procedure source() +free requires ctr == 1 && write_ptr == init(0); +modifies queue, write_ptr; +{ + var idx : int; + + idx := 0; + while (true) { + // enqueue values 0, 1, 2, ... + queue[0][write_ptr[0]] := idx; + write_ptr[0] := write_ptr[0] + 1; + + idx := idx + 1; + } +} + +procedure ULTIMATE.start() +free requires ctr == 1 && write_ptr == init(0); +modifies ctr, queue, write_ptr; +{ + var id : int; + var read_ptr : int; + var value : int; + var prev : int; + + // take thread ID + atomic { + id := ctr; + ctr := ctr + 1; + } + + // initialize pointer to input queue + read_ptr := 0; + + prev := -1; + while (true) { + // dequeue from input queue + assume read_ptr < write_ptr[id-1]; + value := queue[id-1][read_ptr]; + read_ptr := read_ptr + 1; + + // check values are increasing + assert value > prev; + prev := value; + + // forward value to output queue + queue[id][write_ptr[id]] := value; + write_ptr[id] := write_ptr[id]+1; + } +} \ No newline at end of file diff --git a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml new file mode 100644 index 00000000000..d59dfddef4a --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml @@ -0,0 +1,24 @@ +format_version: '2.0' + +input_files: 'line-queue.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: source + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Conditional Independence: "PRECOMPUTED_CONDITIONS" + Use semi-commutativity: true + diff --git a/trunk/examples/concurrent/bpl/parameterized/lock/lock.bpl b/trunk/examples/concurrent/bpl/parameterized/lock/lock.bpl new file mode 100644 index 00000000000..0704db9b794 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/lock/lock.bpl @@ -0,0 +1,30 @@ +//#Safe + +var lock : bool; +var ctr : int; +var x : int; + +procedure ULTIMATE.start() +free requires ctr == 0; +modifies ctr, lock, x; +{ + atomic { + assume !lock; + lock := true; + ctr := ctr + 1; + } + + // critical section + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + + // no one else is in the critical section + assert ctr < 2; + + atomic { + lock := false; + ctr := ctr - 1; + } +} diff --git a/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml b/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml new file mode 100644 index 00000000000..409db7ff3c9 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'lock.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 1 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "PRECOMPUTED_CONDITIONS" + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.bpl b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.bpl new file mode 100644 index 00000000000..c5d04234790 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.bpl @@ -0,0 +1,17 @@ +//#Safe + +var ctr : int; + +procedure ULTIMATE.start() +free requires ctr == 0; +modifies ctr; +{ + while (*) { + atomic { + assume ctr < 3; + ctr := ctr + 1; + } + assert ctr != 0; + ctr := ctr - 1; + } +} \ No newline at end of file diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml new file mode 100644 index 00000000000..df8ab0a0bcd --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'mutex-3.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.bpl b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.bpl new file mode 100644 index 00000000000..4862288edcd --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.bpl @@ -0,0 +1,17 @@ +//#Safe + +var ctr : int; + +procedure ULTIMATE.start() +free requires ctr == 0; +modifies ctr; +{ + while (*) { + atomic { + assume ctr < 4; + ctr := ctr + 1; + } + assert ctr != 0; + ctr := ctr - 1; + } +} \ No newline at end of file diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml new file mode 100644 index 00000000000..89ee3beea97 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'mutex-4.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.bpl b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.bpl new file mode 100644 index 00000000000..f8c89ac9d46 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.bpl @@ -0,0 +1,17 @@ +//#Safe + +var ctr : int; + +procedure ULTIMATE.start() +free requires ctr == 0; +modifies ctr; +{ + while (*) { + atomic { + assume ctr < 5; + ctr := ctr + 1; + } + assert ctr != 0; + ctr := ctr - 1; + } +} \ No newline at end of file diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml new file mode 100644 index 00000000000..5f057126526 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'mutex-5.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.bpl b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.bpl new file mode 100644 index 00000000000..fe59f8c0c71 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.bpl @@ -0,0 +1,14 @@ +//#Safe + +var ctr : int; + +procedure ULTIMATE.start() +free requires ctr == 0; +modifies ctr; +{ + while (*) { + ctr := ctr + 1; + assert ctr != 0; + ctr := ctr - 1; + } +} diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml new file mode 100644 index 00000000000..3efe21a5986 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'mutex-unbounded.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.bpl b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.bpl new file mode 100644 index 00000000000..3b948543b17 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.bpl @@ -0,0 +1,44 @@ +//#Safe + +var notifications : [int]int; +var current : int; + +procedure notifier() +modifies notifications, current; +{ + var prev, data : int; + prev := 0; + + while (*) { + // generate data + havoc data; + assume data > prev; + prev := data; + + // notify listeners of new data + notifications[current] := data; + current := current + 1; + } +} + +// listener threads +procedure ULTIMATE.start() +{ + var idx : int; + var prev, msg : int; + + // begin listening + idx := current; + prev := 0; + + while (*) { + // receive notification of new data (msg) + assume idx < current; + msg := notifications[idx]; + idx := idx + 1; + + // check that notifications are as expected + assert prev < msg; + prev := msg; + } +} \ No newline at end of file diff --git a/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml new file mode 100644 index 00000000000..655c86c9658 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml @@ -0,0 +1,23 @@ +format_version: '2.0' + +input_files: 'notify-listeners.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: notifier + + # Thread modularity level + Thread-Modular Proof Level: 1 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Use semi-commutativity: true + diff --git a/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.bpl b/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.bpl new file mode 100644 index 00000000000..d8aae1a480b --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.bpl @@ -0,0 +1,17 @@ +//#Safe + +var a : [int]int; +var ctr : int; + +procedure ULTIMATE.start() +modifies ctr, a; +{ + var id : int; + atomic { + id := ctr; + ctr := ctr + 1; + } + + a[id] := id; + assert a[id] == id; +} diff --git a/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml b/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml new file mode 100644 index 00000000000..3b5745d7b28 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml @@ -0,0 +1,21 @@ +format_version: '2.0' + +input_files: 'numbered-array.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + diff --git a/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.bpl b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.bpl new file mode 100644 index 00000000000..fe1c8535de8 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.bpl @@ -0,0 +1,46 @@ +//#Safe +// Source: https://dl.acm.org/doi/10.1145/2676726.2677012 + +var len : int; // total number of tasks +var tasks : [int]int; // array of tasks +var next : int; // position of next available task block +var m : bool; // lock protecting next + +procedure ULTIMATE.start() +modifies next, m, tasks; +{ + var c : int; // position of current task + var end : int; // position of last task in acquired block + + var x : int; // local variable for task processing + + // acquire block of tasks + atomic { assume m == false; m := true; } // lock(m) + c := next; + next := next + 10; + if (next <= len) { + end := next; + } else { + end := len; + } + m := false; // unlock(m) + + // perform block of tasks + while (c < end) { + tasks[c] := 0; // mark task c as started + + // work on task c + x := c; + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + x := x + 1; + + tasks[c] := 1; // mark task c as finished + assert tasks[c] == 1; // no other thread has started task c + c := c + 1; + } +} diff --git a/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml new file mode 100644 index 00000000000..f09530c7a4f --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml @@ -0,0 +1,21 @@ +format_version: '2.0' + +input_files: 'thread-pooling.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + diff --git a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.bpl b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.bpl new file mode 100644 index 00000000000..611b8d9ab84 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.bpl @@ -0,0 +1,32 @@ +//#Safe + +var s, t : int; +var crit : bool; + +procedure ULTIMATE.start() +free requires s <= t && !crit; +modifies s, t, crit; +{ + var m : int; + + // request + atomic { + m := t; + t := t + 1; + } + + // failure + assert m > s || !crit; + + // enter + atomic { + assume m <= s; + crit := true; + } + + // leave + atomic { + s := s + 1; + crit := false; + } +} diff --git a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml new file mode 100644 index 00000000000..0e645c5de74 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml @@ -0,0 +1,22 @@ +format_version: '2.0' + +input_files: 'ticket.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "OFF" + diff --git a/trunk/source/Library-UltimateTest/src/de/uni_freiburg/informatik/ultimate/test/decider/ChcTestResultDecider.java b/trunk/source/Library-UltimateTest/src/de/uni_freiburg/informatik/ultimate/test/decider/ChcTestResultDecider.java index 4571e2119cf..d07354bc5c3 100644 --- a/trunk/source/Library-UltimateTest/src/de/uni_freiburg/informatik/ultimate/test/decider/ChcTestResultDecider.java +++ b/trunk/source/Library-UltimateTest/src/de/uni_freiburg/informatik/ultimate/test/decider/ChcTestResultDecider.java @@ -49,7 +49,7 @@ public ChcTestResultDecider(final UltimateRunDefinition ultimateRunDefinition, } @Override - public SMTLibExpectedResultFinder constructExpectedResultFinder() { + public IExpectedResultFinder constructExpectedResultFinder() { return new SMTLibExpectedResultFinder<>(ChcOverallResult.UNKNOWN, ChcOverallResult.SAT, ChcOverallResult.UNSAT); } diff --git a/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java b/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java new file mode 100644 index 00000000000..eb67a2121af --- /dev/null +++ b/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2024 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * Copyright (C) 2024 University of Freiburg + * + * This file is part of the ULTIMATE Regression Test Library. + * + * The ULTIMATE Regression Test 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 Regression Test 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 Regression Test Library. If not, see . + * + * Additional permission under GNU GPL version 3 section 7: + * If you modify the ULTIMATE Regression Test 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 Regression Test Library grant you additional permission + * to convey the resulting work. + */ +package de.uni_freiburg.informatik.ultimate.regressiontest.generic; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.Yaml; + +import de.uni_freiburg.informatik.ultimate.test.UltimateRunDefinition; +import de.uni_freiburg.informatik.ultimate.test.UltimateRunDefinition.NamedServiceCallback; +import de.uni_freiburg.informatik.ultimate.test.UltimateTestCase; +import de.uni_freiburg.informatik.ultimate.test.UltimateTestSuite; +import de.uni_freiburg.informatik.ultimate.test.decider.ChcTestResultDecider; +import de.uni_freiburg.informatik.ultimate.test.decider.ITestResultDecider; +import de.uni_freiburg.informatik.ultimate.test.decider.expectedresult.IExpectedResultFinder; +import de.uni_freiburg.informatik.ultimate.test.decider.overallresult.ChcOverallResult; +import de.uni_freiburg.informatik.ultimate.test.reporting.IIncrementalLog; +import de.uni_freiburg.informatik.ultimate.test.reporting.ITestSummary; +import de.uni_freiburg.informatik.ultimate.test.util.TestUtil; +import de.uni_freiburg.informatik.ultimate.test.util.UltimateRunDefinitionGenerator; + +public class SleepThreadModularChcTestSuite extends UltimateTestSuite { + // @formatter:off + private static final String[] SETTINGS = { + "examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf", + "examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf", + "examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf", + }; + // @formatter:on + private static final String TOOLCHAIN = "examples/concurrent/bpl/parameterized/ThreadModularVerifier.xml"; + private static final String DIRECTORY = "examples/concurrent/bpl/parameterized/"; + private static final String TASKDEF_REGEX = ".*\\.yml"; + private static final int DEFAULT_TIMEOUT = 60; + + @Override + protected Collection createTestCases() { + final File toolchainFile = UltimateRunDefinitionGenerator.getFileFromTrunkDir(TOOLCHAIN); + final Collection selectedYamlFiles = TestUtil.getFilesRegex( + UltimateRunDefinitionGenerator.getFileFromTrunkDir(DIRECTORY), new String[] { TASKDEF_REGEX }); + + final List result = new ArrayList<>(); + for (final var taskDefFile : selectedYamlFiles) { + final var taskDefinition = parseTaskDefinition(taskDefFile); + final String bplFilename = (String) taskDefinition.get("input_files"); + final Path bplPath = taskDefFile.toPath().getParent().resolve(bplFilename); + + for (final String settingsPath : SETTINGS) { + final File settingsFile = UltimateRunDefinitionGenerator.getFileFromTrunkDir(settingsPath); + final var urd = new UltimateRunDefinition(bplPath.toFile(), settingsFile, toolchainFile, + getTimeout(taskDefinition), applySettings(taskDefFile, taskDefinition)); + result.add(new UltimateTestCase(constructITestResultDecider(urd, taskDefinition), urd, List.of())); + } + } + + return result; + } + + private static Map parseTaskDefinition(final File taskDefFile) { + try (var stream = new FileInputStream(taskDefFile)) { + return new Yaml().load(stream); + } catch (final IOException e) { + throw new AssertionError(e); + } + } + + private static ITestResultDecider constructITestResultDecider(final UltimateRunDefinition ultimateRunDefinition, + final Map taskDefinition) { + return new ChcTestResultDecider(ultimateRunDefinition, false) { + @Override + public IExpectedResultFinder constructExpectedResultFinder() { + return new ExpectedResultFinder(taskDefinition); + } + }; + } + + private static class ExpectedResultFinder implements IExpectedResultFinder { + private final ExpectedResultFinderStatus mStatus; + private final ChcOverallResult mExpected; + + public ExpectedResultFinder(final Map taskDefinition) { + final var propertyDef = ((Collection>) taskDefinition.get("properties")).stream() + .filter(propEntry -> ((String) propEntry.get("property_file")).endsWith("unreach-call.prp")) + .findFirst(); + if (propertyDef.isEmpty()) { + mStatus = ExpectedResultFinderStatus.NO_EXPECTED_RESULT_FOUND; + mExpected = null; + } else { + final var expected = propertyDef.get().get("expected_verdict").toString(); + switch (expected) { + case "sat": + case "true": + mExpected = ChcOverallResult.SAT; + mStatus = ExpectedResultFinderStatus.EXPECTED_RESULT_FOUND; + break; + case "unsat": + mExpected = ChcOverallResult.UNSAT; + mStatus = ExpectedResultFinderStatus.EXPECTED_RESULT_FOUND; + break; + case "unknown": + mExpected = ChcOverallResult.UNKNOWN; + mStatus = ExpectedResultFinderStatus.EXPECTED_RESULT_FOUND; + break; + default: + mExpected = null; + mStatus = ExpectedResultFinderStatus.NO_EXPECTED_RESULT_FOUND; + } + } + } + + @Override + public void findExpectedResult(final UltimateRunDefinition ultimateRunDefinition) { + // already done in constructor + } + + @Override + public ExpectedResultFinderStatus getExpectedResultFinderStatus() { + return mStatus; + } + + @Override + public String getExpectedResultFinderMessage() { + return mExpected.toString(); + } + + @Override + public ChcOverallResult getExpectedResult() { + return mExpected; + } + } + + @Override + protected ITestSummary[] constructTestSummaries() { + return new ITestSummary[0]; + } + + @Override + protected IIncrementalLog[] constructIncrementalLog() { + return new IIncrementalLog[0]; + } + + private static long getTimeout(final Map taskDefinition) { + if (taskDefinition.containsKey("options")) { + final var options = (Map) taskDefinition.get("options"); + if (options.containsKey("timeout")) { + return (int) options.get("timeout") * 1000L; + } + } + return DEFAULT_TIMEOUT * 1000L; + } + + private NamedServiceCallback applySettings(final File taskDefFile, final Map taskDefinition) { + final var options = (Map) taskDefinition.get("options"); + if (options == null) { + return null; + } + final String[] pluginIds = options.keySet().stream() + .filter(s -> s.startsWith("de.uni_freiburg.informatik.ultimate")).toArray(String[]::new); + return new NamedServiceCallback(taskDefFile.getName(), services -> { + final var layer = services.registerPreferenceLayer(getClass(), pluginIds); + for (final var plugin : pluginIds) { + final var preferences = layer.getPreferenceProvider(plugin); + for (final var entry : ((Map) options.get(plugin)).entrySet()) { + final Object value; + if (entry.getValue() instanceof Map || entry.getValue() instanceof List) { + value = new Yaml().dump(entry.getValue()); + } else { + value = entry.getValue(); + } + preferences.put(entry.getKey(), value); + } + } + return layer; + }); + } +} From 9d470712b834817d52600b0204fc6898a9fdd5e8 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 02:11:29 +0100 Subject: [PATCH 100/114] switch to new ISymbolicIndependenceRelation --- .../parameterized/SleepExplicit-Eldarica.epf | 2 +- .../bpl/parameterized/SleepExplicit-Golem.epf | 2 +- .../bpl/parameterized/SleepExplicit-Z3.epf | 2 +- .../bpl/parameterized/add-sub-k/add-sub-k.yml | 2 +- .../add-sub-positive-k/add-sub-positive-k.yml | 2 +- .../equalsum-fork/equalsum-fork.yml | 2 +- .../equalsum-ghost/equalsum-ghost.yml | 2 +- .../inc-dec-eq0-locked-assert.yml | 2 +- .../inc-dec-eq0-locked/inc-dec-eq0-locked.yml | 2 +- .../parameterized/inc-dec-eq0/inc-dec-eq0.yml | 2 +- .../inc-dec-geq0/inc-dec-geq0.yml | 2 +- .../parameterized/line-queue/line-queue.yml | 1 - .../bpl/parameterized/lock/lock.yml | 1 - .../bpl/parameterized/mutex-3/mutex-3.yml | 2 +- .../bpl/parameterized/mutex-4/mutex-4.yml | 2 +- .../bpl/parameterized/mutex-5/mutex-5.yml | 2 +- .../mutex-unbounded/mutex-unbounded.yml | 2 +- .../bpl/parameterized/ticket/ticket.yml | 2 +- .../plugins/icfgtochc/IcfgToChcObserver.java | 30 +++---- ...itionSynthesizingIndependenceRelation.java | 86 ------------------- .../ISymbolicIndependenceRelation.java | 53 ------------ .../partialorder/IndependenceChecker.java | 16 +++- ...eepSetThreadModularHornClauseProvider.java | 4 +- .../IcfgToChcPreferenceInitializer.java | 9 +- .../preferences/IcfgToChcPreferences.java | 6 +- .../ExplicitSymbolicIndependenceRelation.java | 45 +++++----- ...emanticIndependenceConditionGenerator.java | 36 +------- 27 files changed, 80 insertions(+), 239 deletions(-) delete mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java delete mode 100644 trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java rename trunk/source/{IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder => Library-Automata/src/de/uni_freiburg/informatik/ultimate/automata/partialorder/independence}/ExplicitSymbolicIndependenceRelation.java (51%) diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf index d06257bb32e..3ec289208c6 100644 --- a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf +++ b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf @@ -6,7 +6,7 @@ /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC # Settings for sleep sets /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=PRECOMPUTED_CONDITIONS +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=SUFFICIENT /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true # Other settings diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf index 204060959c6..5ac3b628870 100644 --- a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf +++ b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf @@ -6,7 +6,7 @@ /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC # Settings for sleep sets /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=PRECOMPUTED_CONDITIONS +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=SUFFICIENT /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true # Other settings diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf index dca3cb84999..8add18286c0 100644 --- a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf +++ b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf @@ -6,7 +6,7 @@ /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC # Settings for sleep sets /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=PRECOMPUTED_CONDITIONS +/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=SUFFICIENT /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true /instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true # Other settings diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml index ec88e261555..4887dfc3794 100644 --- a/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml index c069c28c28a..b865ebe20d7 100644 --- a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml b/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml index a8ac04404ca..21b9bc00dac 100644 --- a/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml @@ -19,5 +19,5 @@ options: # Settings for reduction Preference order used for reduction: LOCKSTEP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml index 93d3235a312..a8f3e843f1a 100644 --- a/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: LOCKSTEP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml index 9c8a7388451..26b26f60faa 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml index e79199cc0af..b84c76129d0 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml index 161f8bd6eee..6e22e6ca7ad 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml index d9481da80d6..2919c493383 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml index d59dfddef4a..1b790d0a686 100644 --- a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml +++ b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml @@ -19,6 +19,5 @@ options: # Settings for reduction Preference order used for reduction: LOCKSTEP - Conditional Independence: "PRECOMPUTED_CONDITIONS" Use semi-commutativity: true diff --git a/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml b/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml index 409db7ff3c9..6dc9c1d51f7 100644 --- a/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml +++ b/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml @@ -18,5 +18,4 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "PRECOMPUTED_CONDITIONS" diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml index df8ab0a0bcd..8f14987930e 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml index 89ee3beea97..0636913a356 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml index 5f057126526..14b9c973106 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml index 3efe21a5986..82f651214ac 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml index 0e645c5de74..459eb305ecb 100644 --- a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml +++ b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml @@ -18,5 +18,5 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP - Conditional Independence: "OFF" + Conditional Independence: "NONE" diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index b3c7a3fe855..58e7eea8720 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -30,6 +30,8 @@ import java.util.Arrays; import java.util.Collection; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ExplicitSymbolicIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.core.lib.observers.BaseObserver; import de.uni_freiburg.informatik.ultimate.core.model.models.IElement; import de.uni_freiburg.informatik.ultimate.core.model.models.ModelUtils; @@ -47,17 +49,16 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; 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.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation.IndependenceConditions; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadModularHornClauseProvider; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ApproximateLockstepPreferenceOrder; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ConditionSynthesizingIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ExplicitSymbolicIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.ISymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.IThreadModularPreferenceOrder; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.SequentialCompositionPreferenceOrder; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder.SleepSetThreadModularHornClauseProvider; @@ -161,21 +162,18 @@ private Collection getHornClauses(IIcfg icfg, final Ma return new ChcProviderForCalls(mgdScript, hcSymbolTable).getHornClauses(icfg); } - private ISymbolicIndependenceRelation getIndependence(final IIcfg icfg, final ManagedScript mgdScript) { + private ISymbolicIndependenceRelation getIndependence(final IIcfg icfg, + final ManagedScript mgdScript) { final boolean symmetric = !mPrefs.useSemicommutativity(); - final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, symmetric); - - switch (mPrefs.conditionalIndependence()) { - case OFF: - return new ExplicitSymbolicIndependenceRelation<>(independence, mgdScript.getScript()); - case PRECOMPUTED_CONDITIONS: - final var factory = - new BasicPredicateFactory(mServices, mgdScript, icfg.getCfgSmtToolkit().getSymbolTable()); - final var generator = new SemanticIndependenceConditionGenerator(mServices, mgdScript, factory, symmetric); - return new ConditionSynthesizingIndependenceRelation<>(independence, generator, mgdScript.getScript()); - } + final var factory = new BasicPredicateFactory(mServices, mgdScript, icfg.getCfgSmtToolkit().getSymbolTable()); + final var generator = new SemanticIndependenceConditionGenerator(mServices, mgdScript, factory, symmetric); + final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, symmetric, + mPrefs.conditionalIndependence(), factory, generator); - throw new AssertionError("Unknown conditional independence setting: " + mPrefs.conditionalIndependence()); + if (mPrefs.conditionalIndependence() == IndependenceConditions.NONE) { + return new ExplicitSymbolicIndependenceRelation<>(independence, factory.and(), factory.or()); + } + return independence.getSymbolicRelation(); } private IThreadModularPreferenceOrder getPreferenceOrder(final Script script, final IIcfg icfg) { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java deleted file mode 100644 index 4b83b376685..00000000000 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ConditionSynthesizingIndependenceRelation.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * Copyright (C) 2023 University of Freiburg - * - * This file is part of the ULTIMATE IcfgToChc plug-in. - * - * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . - * - * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission - * to convey the resulting work. - */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; - -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IAction; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; -import de.uni_freiburg.informatik.ultimate.logic.Script; -import de.uni_freiburg.informatik.ultimate.logic.Term; - -/** - * An {@link ISymbolicIndependenceRelation} that uses a {@link SemanticIndependenceConditionGenerator} to find a - * sufficient condition for commutativity. - * - * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * - * @param - */ -public class ConditionSynthesizingIndependenceRelation implements ISymbolicIndependenceRelation { - - private final SemanticIndependenceRelation mExplicitIndependence; - private final SemanticIndependenceConditionGenerator mGenerator; - private final Script mScript; - - public ConditionSynthesizingIndependenceRelation(final SemanticIndependenceRelation explicitIndependence, - final SemanticIndependenceConditionGenerator generator, final Script script) { - mExplicitIndependence = explicitIndependence; - mGenerator = generator; - mScript = script; - - assert mExplicitIndependence.isSymmetric() == mGenerator - .isSymmetric() : "Independence relation and condition generator should both be symmetric, or neither."; - } - - @Override - public Term getIndependenceCondition(final L a, final L b) { - final var dependence = mExplicitIndependence.isIndependent(null, a, b); - switch (dependence) { - case INDEPENDENT: - // Statements always commute, no condition is needed. - return mScript.term(SMTLIBConstants.TRUE); - case UNKNOWN: - // Commutativity condition synthesis probably won't succeed. - return mScript.term(SMTLIBConstants.FALSE); - case DEPENDENT: - final var condition = mGenerator.generateConditionTerm(a.getTransformula(), b.getTransformula()); - if (condition == null) { - // No commutativity condition could be synthesized. - return mScript.term(SMTLIBConstants.FALSE); - } - return condition; - default: - throw new AssertionError("Unknown dependency value: " + dependence); - } - } - - @Override - public boolean isSymmetric() { - return mExplicitIndependence.isSymmetric(); - } -} diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java deleted file mode 100644 index a9c1ece0144..00000000000 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ISymbolicIndependenceRelation.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * Copyright (C) 2023 University of Freiburg - * - * This file is part of the ULTIMATE IcfgToChc plug-in. - * - * The ULTIMATE IcfgToChc plug-in 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 IcfgToChc plug-in 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 IcfgToChc plug-in. If not, see . - * - * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE IcfgToChc plug-in, 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 IcfgToChc plug-in grant you additional permission - * to convey the resulting work. - */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; - -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.logic.Term; - -/** - * Represents an independence (or "commutativity" relation). In spirit, this interface is similar to - * {@link IIndependenceRelation}, but instead of explicitly checking independence, it returns a symbolic condition (a - * boolean {@link Term}) such that, if the term evaluates to {@code true}, then the given letters are independent. - * - * Symbolic independence relations are inherently conditional: The returned {@link Term} is a formula over program - * variables that implies commutativity. However, symbolic independence relations currently do not support passing in a - * known context. - * - * Similar to {@link IIndependenceRelation}s, symbolic independence relations can be symmetric (i.e., describe a - * commutativity relation) or not (i.e., describe a semi-commutativity relation). - * - * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * - * @param - * The type of actions checked for independence - */ -public interface ISymbolicIndependenceRelation { - Term getIndependenceCondition(L a, L b); - - boolean isSymmetric(); -} \ No newline at end of file diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java index 503b55e0b9e..e9f33cb0d59 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -32,6 +32,7 @@ import java.util.Set; import java.util.stream.Collectors; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; 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; @@ -41,9 +42,11 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaBuilder; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramVarUtils; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate; 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.Substitution; +import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcGlobalVar; @@ -63,7 +66,7 @@ class IndependenceChecker { private final ILogger mLogger; private final ManagedScript mMgdScript; private final IIcfgSymbolTable mSymbolTable; - private final ISymbolicIndependenceRelation mIndependence; + private final ISymbolicIndependenceRelation mIndependence; private final IcfgEdgeFactory mEdgeFactory; private final Map, Term> mCache = new HashMap<>(); @@ -72,7 +75,7 @@ class IndependenceChecker { private final Map mRightSubstitution; public IndependenceChecker(final IUltimateServiceProvider services, final CfgSmtToolkit csToolkit, - final ISymbolicIndependenceRelation independence) { + final ISymbolicIndependenceRelation independence) { mLogger = services.getLoggingService().getLogger(getClass()); mMgdScript = csToolkit.getManagedScript(); mSymbolTable = csToolkit.getSymbolTable(); @@ -176,7 +179,14 @@ private Term getInstantiatedIndependenceCondition(final IcfgEdge action1, final // compute the independence condition final var inst1 = instantiate(action1, mLeftSubstitution); final var inst2 = instantiate(action2, mRightSubstitution); - final var condition = mIndependence.getIndependenceCondition(inst1, inst2); + final var rawCondition = mIndependence.getCommutativityCondition(null, inst1, inst2); + final Term condition; + if (rawCondition == null) { + condition = mMgdScript.getScript().term(SMTLIBConstants.FALSE); + } else { + condition = rawCondition.getFormula(); + } + mLogger.info( "instantiated independence condition for '" + action1 + "' and '" + action2 + "' is: " + condition); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 065bd322007..00d8f9f3185 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -35,12 +35,14 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; 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.IcfgEdge; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; @@ -63,7 +65,7 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornCl public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider services, final ManagedScript mgdScript, final IIcfg icfg, final HcSymbolTable symbolTable, - final ISymbolicIndependenceRelation> independence, + final ISymbolicIndependenceRelation, IPredicate> independence, final IThreadModularPreferenceOrder preferenceOrder, final IcfgToChcPreferences prefs) { super(services, mgdScript, icfg, symbolTable, prefs); mIndependenceChecker = new IndependenceChecker(services, icfg.getCfgSmtToolkit(), independence); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 95ab8097031..17e7289f147 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -34,6 +34,7 @@ import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItem; import de.uni_freiburg.informatik.ultimate.core.model.preferences.UltimatePreferenceItemContainer; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation.IndependenceConditions; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.Activator; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferences.SpecMode; @@ -127,7 +128,7 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize private static final PreferenceOrder DEF_PREFERENCE_ORDER = PreferenceOrder.SEQ_COMP; public static final String LABEL_CONDITIONAL_INDEPENDENCE = "Conditional Independence"; - private static final ConditionalIndependence DEF_CONDITIONAL_INDEPENDENCE = ConditionalIndependence.OFF; + private static final IndependenceConditions DEF_CONDITIONAL_INDEPENDENCE = IndependenceConditions.NONE; public static final String LABEL_SEMICOMMUTATIVITY = "Use semi-commutativity"; private static final boolean DEF_SEMICOMMUTATIVITY = true; @@ -136,10 +137,6 @@ public enum PreferenceOrder { SEQ_COMP, LOCKSTEP } - public enum ConditionalIndependence { - OFF, PRECOMPUTED_CONDITIONS - } - /** * Default constructor. */ @@ -185,7 +182,7 @@ private static UltimatePreferenceItemContainer getSleepSetSettings() { container.addItem(new UltimatePreferenceItem<>(LABEL_PREFERENCE_ORDER, DEF_PREFERENCE_ORDER, PreferenceType.Combo, PreferenceOrder.values())); container.addItem(new UltimatePreferenceItem<>(LABEL_CONDITIONAL_INDEPENDENCE, DEF_CONDITIONAL_INDEPENDENCE, - PreferenceType.Combo, ConditionalIndependence.values())); + PreferenceType.Combo, IndependenceConditions.values())); container.addItem( new UltimatePreferenceItem<>(LABEL_SEMICOMMUTATIVITY, DEF_SEMICOMMUTATIVITY, PreferenceType.Boolean)); return container; diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index dd5c7319a70..ff16c2b876d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -31,8 +31,8 @@ import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.core.model.preferences.IPreferenceProvider; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation.IndependenceConditions; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer.ConditionalIndependence; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.preferences.IcfgToChcPreferenceInitializer.PreferenceOrder; public class IcfgToChcPreferences { @@ -96,9 +96,9 @@ public PreferenceOrder preferenceOrder() { return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_PREFERENCE_ORDER, PreferenceOrder.class); } - public ConditionalIndependence conditionalIndependence() { + public IndependenceConditions conditionalIndependence() { return mPrefs.getEnum(IcfgToChcPreferenceInitializer.LABEL_CONDITIONAL_INDEPENDENCE, - ConditionalIndependence.class); + IndependenceConditions.class); } public boolean useSemicommutativity() { diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java b/trunk/source/Library-Automata/src/de/uni_freiburg/informatik/ultimate/automata/partialorder/independence/ExplicitSymbolicIndependenceRelation.java similarity index 51% rename from trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java rename to trunk/source/Library-Automata/src/de/uni_freiburg/informatik/ultimate/automata/partialorder/independence/ExplicitSymbolicIndependenceRelation.java index 3d83a463194..c371f78bce9 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/ExplicitSymbolicIndependenceRelation.java +++ b/trunk/source/Library-Automata/src/de/uni_freiburg/informatik/ultimate/automata/partialorder/independence/ExplicitSymbolicIndependenceRelation.java @@ -2,36 +2,31 @@ * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) * Copyright (C) 2023 University of Freiburg * - * This file is part of the ULTIMATE IcfgToChc plug-in. + * This file is part of the ULTIMATE Automata Library. * - * The ULTIMATE IcfgToChc plug-in is free software: you can redistribute it and/or modify + * The ULTIMATE Automata 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 IcfgToChc plug-in is distributed in the hope that it will be useful, + * The ULTIMATE Automata 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 IcfgToChc plug-in. If not, see . + * along with the ULTIMATE Automata Library. If not, see . * * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE IcfgToChc plug-in, or any covered work, by linking + * If you modify the ULTIMATE Automata 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 IcfgToChc plug-in grant you additional permission + * licensors of the ULTIMATE Automata Library grant you additional permission * to convey the resulting work. */ -package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; +package de.uni_freiburg.informatik.ultimate.automata.partialorder.independence; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.IIndependenceRelation.Dependence; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IAction; -import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; -import de.uni_freiburg.informatik.ultimate.logic.Script; -import de.uni_freiburg.informatik.ultimate.logic.Term; /** * Implements {@link ISymbolicIndependenceRelation} by explicitly checking independence and returning either the term @@ -42,26 +37,34 @@ * @param * The type of letters checked for independence */ -public class ExplicitSymbolicIndependenceRelation implements ISymbolicIndependenceRelation { - private final IIndependenceRelation mUnderlying; - private final Script mScript; +public class ExplicitSymbolicIndependenceRelation implements ISymbolicIndependenceRelation { + private final IIndependenceRelation mUnderlying; + private final S mTrueCondition; + private final S mFalseCondition; - public ExplicitSymbolicIndependenceRelation(final IIndependenceRelation underlying, final Script script) { + public ExplicitSymbolicIndependenceRelation(final IIndependenceRelation underlying, final S trueCondition, + final S falseCondition) { mUnderlying = underlying; - mScript = script; + mTrueCondition = trueCondition; + mFalseCondition = falseCondition; } @Override - public Term getIndependenceCondition(final L a, final L b) { - final var dependence = mUnderlying.isIndependent(null, a, b); + public S getCommutativityCondition(final S condition, final L a, final L b) { + final var dependence = mUnderlying.isIndependent(condition, a, b); if (dependence == Dependence.INDEPENDENT) { - return mScript.term(SMTLIBConstants.TRUE); + return mTrueCondition; } - return mScript.term(SMTLIBConstants.FALSE); + return mFalseCondition; } @Override public boolean isSymmetric() { return mUnderlying.isSymmetric(); } + + @Override + public boolean isConditional() { + return mUnderlying.isConditional(); + } } diff --git a/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java b/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java index 0cf6545c205..1ad9ae70430 100644 --- a/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java +++ b/trunk/source/Library-TraceCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/tracecheckerutils/partialorder/independence/SemanticIndependenceConditionGenerator.java @@ -127,20 +127,6 @@ public IPredicate generateCondition(final UnmodifiableTransFormula a, final Unmo return generateCondition(null, a, b); } - /** - * Generate a condition under which the given transitions are independent. - * - * @param a - * The first transition - * @param b - * The second transition - * - * @return a sufficient condition for independence - */ - public Term generateConditionTerm(final UnmodifiableTransFormula a, final UnmodifiableTransFormula b) { - return generateConditionTerm(null, a, b); - } - /** * Generate a condition under which the given transitions are independent. * @@ -155,23 +141,6 @@ public Term generateConditionTerm(final UnmodifiableTransFormula a, final Unmodi */ public IPredicate generateCondition(final IPredicate context, final UnmodifiableTransFormula a, final UnmodifiableTransFormula b) { - return mFactory.newPredicate(generateConditionTerm(context, a, b)); - } - - /** - * Generate a condition term under which the given transitions are independent. - * - * @param context - * A context that is already known, but not sufficient for commutativity - * @param a - * The first transition - * @param b - * The second transition - * - * @return a sufficient condition for independence - */ - public Term generateConditionTerm(final IPredicate context, final UnmodifiableTransFormula a, - final UnmodifiableTransFormula b) { // Generate both compositions, possibly adding a guard where applicable final UnmodifiableTransFormula ab = withGuard(context, compose(a, b)); final UnmodifiableTransFormula ba = withGuard(mSymmetric ? context : null, compose(b, a)); @@ -202,7 +171,10 @@ public Term generateConditionTerm(final IPredicate context, final UnmodifiableTr assert !substitution.containsKey(entry.getValue()); substitution.put(entry.getValue(), entry.getKey().getTermVariable()); } - return Substitution.apply(mMgdScript, substitution, condition); + final Term restoredCondition = Substitution.apply(mMgdScript, substitution, condition); + + // Create a predicate + return mFactory.newPredicate(restoredCondition); } private final UnmodifiableTransFormula compose(final UnmodifiableTransFormula first, From a0c725d78f0e63b8ad3a7fb525c0b845421e325e Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 14:45:23 +0100 Subject: [PATCH 101/114] IndependenceChecker: decouple from HornClauseBuilder --- .../partialorder/IndependenceChecker.java | 30 +++++++++---------- ...eepSetThreadModularHornClauseProvider.java | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java index e9f33cb0d59..a0749a6b1fa 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; @@ -51,7 +52,7 @@ import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcGlobalVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HcLocalVar; -import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.HornClauseBuilder; +import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcReplacementVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; import de.uni_freiburg.informatik.ultimate.util.datastructures.SerialProvider; import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; @@ -87,8 +88,9 @@ public IndependenceChecker(final IUltimateServiceProvider services, final CfgSmt mRightSubstitution = createVariableMapping("~~right~~", localVars); } - public Term getIndependenceCondition(final HornClauseBuilder clause, final ThreadInstance thread1, - final IcfgEdge action1, final ThreadInstance thread2, final IcfgEdge action2) { + public Term getIndependenceCondition(final Function getTermVariable, + final ThreadInstance thread1, final IcfgEdge action1, final ThreadInstance thread2, + final IcfgEdge action2) { // Hardcoded conditions for line-queue example // TODO remove after evaluation Term hardcoded = null; @@ -153,13 +155,13 @@ public Term getIndependenceCondition(final HornClauseBuilder clause, final Threa if (hardcoded != null) { mLogger.warn( "Hardcoded independence condition for '" + action1 + "' and '" + action2 + "' is: " + hardcoded); - return deinstantiate(clause, thread1, thread2, hardcoded); + return deinstantiate(getTermVariable, thread1, thread2, hardcoded); } // first check the cache final var cached = mCache.get(new Pair<>(action1, action2)); if (cached != null) { - return deinstantiate(clause, thread1, thread2, cached); + return deinstantiate(getTermVariable, thread1, thread2, cached); } // for symmetric relations, check the cache for the symmetric case as well @@ -167,12 +169,12 @@ public Term getIndependenceCondition(final HornClauseBuilder clause, final Threa final var symCached = mCache.get(new Pair<>(action2, action1)); if (symCached != null) { // This needs a different deinstantiation than the cases above and below. - return deinstantiate(clause, thread2, thread1, symCached); + return deinstantiate(getTermVariable, thread2, thread1, symCached); } } final var instantiated = getInstantiatedIndependenceCondition(action1, action2); - return deinstantiate(clause, thread1, thread2, instantiated); + return deinstantiate(getTermVariable, thread1, thread2, instantiated); } private Term getInstantiatedIndependenceCondition(final IcfgEdge action1, final IcfgEdge action2) { @@ -202,29 +204,27 @@ private IcfgEdge instantiate(final IcfgEdge edge, final Map getTermVariable, final ThreadInstance thread1, final ThreadInstance thread2, final Term term) { final var backSubstitution = new HashMap(); - addBackSubstitutionMappings(clause, mLeftSubstitution, backSubstitution, thread1); - addBackSubstitutionMappings(clause, mRightSubstitution, backSubstitution, thread2); + addBackSubstitutionMappings(getTermVariable, mLeftSubstitution, backSubstitution, thread1); + addBackSubstitutionMappings(getTermVariable, mRightSubstitution, backSubstitution, thread2); for (final var global : mSymbolTable.getGlobals()) { final var hcVar = new HcGlobalVar(global); - final var bodyVar = clause.getBodyVar(hcVar); - backSubstitution.put(global.getTermVariable(), bodyVar.getTermVariable()); + backSubstitution.put(global.getTermVariable(), getTermVariable.apply(hcVar)); } return Substitution.apply(mMgdScript, backSubstitution, term); } - private void addBackSubstitutionMappings(final HornClauseBuilder clause, + private void addBackSubstitutionMappings(final Function getTermVariable, final Map substitution, final Map backSubstitution, final ThreadInstance thread) { for (final var local : mSymbolTable.getLocals(thread.getTemplateName())) { final var hcVar = new HcLocalVar(local, thread); - final var bodyVar = clause.getBodyVar(hcVar); final var instVar = substitution.get(local); - backSubstitution.put(instVar.getTermVariable(), bodyVar.getTermVariable()); + backSubstitution.put(instVar.getTermVariable(), getTermVariable.apply(hcVar)); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 00d8f9f3185..f48b24afb55 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -329,8 +329,8 @@ protected Term getCommutativityConstraint(final HornClauseBuilder clause, final continue; } - final var conjunct = - mIndependenceChecker.getIndependenceCondition(clause, activeThread, activeEdge, otherThread, edge); + final var conjunct = mIndependenceChecker.getIndependenceCondition( + v -> clause.getBodyVar(v).getTermVariable(), activeThread, activeEdge, otherThread, edge); if (SmtUtils.isFalseLiteral(conjunct)) { // escape early if one outgoing edge does not commute under any circumstances return mScript.term(SMTLIBConstants.FALSE); From a1d30175662d647495a31d9368efe56f4083dbae Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 14:51:08 +0100 Subject: [PATCH 102/114] fix assert failure for clauses without head (safety clauses) --- .../concurrent/ThreadModularHornClauseProvider.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index d9ae6fdd513..a523d606605 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -811,21 +811,25 @@ private static void prepareSubstitution(final HornClauseBuilder clause, final Un substitution.put(inVar, clause.getBodyVar(rv).getTerm()); } + // We rely on the internal normal form, namely that all assigned variables have outvars and are handled below. + assert TransFormulaUtils.hasInternalNormalForm(tf) : "Transition formula is not in internal normal form"; + final TermVariable outVar = tf.getOutVars().get(pv); final var dummyOutVars = new HashMap(); if (outVar != null && !Objects.equals(inVar, outVar)) { final var headPred = clause.getHeadPredicate(); if (headPred != null && headPred.hasParameter(rv)) { substitution.put(outVar, clause.getHeadVar(rv).getTerm()); + + // If we get here, pv must be an assigned variable of the transition formula. + // Hence the variable used to represent rv in the clause body and head must differ. + assert tf.getAssignedVars().contains(pv) : "invars / outvars / assigned vars inconsistent"; + clause.differentBodyHeadVar(rv); } else { final var bodyVar = dummyOutVars.computeIfAbsent(rv, x -> clause.getFreshBodyVar(x, x.getSort())); substitution.put(outVar, bodyVar.getTerm()); } } - - if (tf.getAssignedVars().contains(pv)) { - clause.differentBodyHeadVar(rv); - } } protected ThreadInstance getInterferingThread(final IIcfgTransition transition) { From e5f34f831bb61e5407d824b32a1b675cd4f22070 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 15:24:44 +0100 Subject: [PATCH 103/114] fix bug with unknown variables in predicate factory Move the creation of the symbolic independence relations to IndependenceChecker, and create a suitable symbol table for the relations as they work on instantiated conditions. --- .../plugins/icfgtochc/IcfgToChcObserver.java | 31 ++----------- .../partialorder/IndependenceChecker.java | 46 +++++++++++++++++-- ...eepSetThreadModularHornClauseProvider.java | 8 ++-- 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java index 58e7eea8720..5034c85432a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/IcfgToChcObserver.java @@ -30,8 +30,6 @@ import java.util.Arrays; import java.util.Collection; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ExplicitSymbolicIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.core.lib.observers.BaseObserver; import de.uni_freiburg.informatik.ultimate.core.model.models.IElement; import de.uni_freiburg.informatik.ultimate.core.model.models.ModelUtils; @@ -43,17 +41,11 @@ import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; import de.uni_freiburg.informatik.ultimate.lib.chc.HornClauseAST; 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.IIcfgSummaryTransition; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeIterator; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; -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.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; -import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation.IndependenceConditions; import de.uni_freiburg.informatik.ultimate.logic.Script; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ConcurrencyMode; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IcfgLiptonReducer; @@ -105,8 +97,8 @@ private void processIcfg(final IIcfg icfg) { final var chcCategoryInfo = ChcCategorizer.categorize(resultChcs, mgdScript); assert !chcCategoryInfo.containsNonLinearHornClauses() || isReturnReachable(icfg) - || !IcfgUtils.getForksInLoop(icfg).isEmpty() - || mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC : "Unexpected non-linear clauses"; + || !IcfgUtils.getForksInLoop(icfg).isEmpty() || mPrefs.concurrencyMode() == ConcurrencyMode.PARAMETRIC + : "Unexpected non-linear clauses"; assert checkFreeVariables(resultChcs, mgdScript) : "Some clauses have free variables"; @@ -152,30 +144,15 @@ private Collection getHornClauses(IIcfg icfg, final Ma } if (mPrefs.useSleepSets()) { - final var independence = getIndependence(icfg, mgdScript); final var preforder = getPreferenceOrder(mgdScript.getScript(), icfg); - return new SleepSetThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, - independence, preforder, mPrefs).getClauses(); + return new SleepSetThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, preforder, + mPrefs).getClauses(); } return new ThreadModularHornClauseProvider(mServices, mgdScript, icfg, hcSymbolTable, mPrefs).getClauses(); } return new ChcProviderForCalls(mgdScript, hcSymbolTable).getHornClauses(icfg); } - private ISymbolicIndependenceRelation getIndependence(final IIcfg icfg, - final ManagedScript mgdScript) { - final boolean symmetric = !mPrefs.useSemicommutativity(); - final var factory = new BasicPredicateFactory(mServices, mgdScript, icfg.getCfgSmtToolkit().getSymbolTable()); - final var generator = new SemanticIndependenceConditionGenerator(mServices, mgdScript, factory, symmetric); - final var independence = new SemanticIndependenceRelation<>(mServices, mgdScript, false, symmetric, - mPrefs.conditionalIndependence(), factory, generator); - - if (mPrefs.conditionalIndependence() == IndependenceConditions.NONE) { - return new ExplicitSymbolicIndependenceRelation<>(independence, factory.and(), factory.or()); - } - return independence.getSymbolicRelation(); - } - private IThreadModularPreferenceOrder getPreferenceOrder(final Script script, final IIcfg icfg) { switch (mPrefs.preferenceOrder()) { case SEQ_COMP: diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java index a0749a6b1fa..ea7421a79d7 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -33,20 +33,27 @@ import java.util.function.Function; import java.util.stream.Collectors; +import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ExplicitSymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; 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.DefaultIcfgSymbolTable; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.IIcfgSymbolTable; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IAction; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdge; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeFactory; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaBuilder; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramVarUtils; +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.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.Substitution; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; +import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation.IndependenceConditions; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; @@ -76,16 +83,47 @@ class IndependenceChecker { private final Map mRightSubstitution; public IndependenceChecker(final IUltimateServiceProvider services, final CfgSmtToolkit csToolkit, - final ISymbolicIndependenceRelation independence) { + final boolean useSemicommutativity, final IndependenceConditions independenceConditions) { mLogger = services.getLoggingService().getLogger(getClass()); mMgdScript = csToolkit.getManagedScript(); mSymbolTable = csToolkit.getSymbolTable(); - mIndependence = independence; mEdgeFactory = new IcfgEdgeFactory(new SerialProvider()); final var localVars = collectLocalVariables(csToolkit); mLeftSubstitution = createVariableMapping("~~left~~", localVars); mRightSubstitution = createVariableMapping("~~right~~", localVars); + + mIndependence = createIndependence(services, useSemicommutativity, independenceConditions); + } + + private ISymbolicIndependenceRelation createIndependence( + final IUltimateServiceProvider services, final boolean useSemicommutativity, + final IndependenceConditions independenceConditions) { + // Create a symbol table with the instantiated local variables and the original global variables. + final var instantiatedSymbolTable = new DefaultIcfgSymbolTable(); + for (final var global : mSymbolTable.getGlobals()) { + instantiatedSymbolTable.add(global); + } + for (final var leftLocal : mLeftSubstitution.values()) { + instantiatedSymbolTable.add(leftLocal); + } + for (final var rightLocal : mRightSubstitution.values()) { + instantiatedSymbolTable.add(rightLocal); + } + + // Create a predicate factory for the instantiated conditions, using the new symbol table. + final var factory = new BasicPredicateFactory(services, mMgdScript, instantiatedSymbolTable); + + final var generator = independenceConditions.requiresConditionGenerator() + ? new SemanticIndependenceConditionGenerator(services, mMgdScript, factory, !useSemicommutativity) + : null; + final var independence = new SemanticIndependenceRelation<>(services, mMgdScript, false, !useSemicommutativity, + independenceConditions, factory, generator); + + if (independenceConditions == IndependenceConditions.NONE) { + return new ExplicitSymbolicIndependenceRelation<>(independence, factory.and(), factory.or()); + } + return independence.getSymbolicRelation(); } public Term getIndependenceCondition(final Function getTermVariable, @@ -204,8 +242,8 @@ private IcfgEdge instantiate(final IcfgEdge edge, final Map getTermVariable, final ThreadInstance thread1, - final ThreadInstance thread2, final Term term) { + private Term deinstantiate(final Function getTermVariable, + final ThreadInstance thread1, final ThreadInstance thread2, final Term term) { final var backSubstitution = new HashMap(); addBackSubstitutionMappings(getTermVariable, mLeftSubstitution, backSubstitution, thread1); addBackSubstitutionMappings(getTermVariable, mRightSubstitution, backSubstitution, thread2); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index f48b24afb55..0bfe18d8d19 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -35,14 +35,11 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import de.uni_freiburg.informatik.ultimate.automata.partialorder.independence.ISymbolicIndependenceRelation; import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider; import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; 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.IcfgEdge; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgLocation; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; @@ -65,10 +62,11 @@ public class SleepSetThreadModularHornClauseProvider extends ThreadModularHornCl public SleepSetThreadModularHornClauseProvider(final IUltimateServiceProvider services, final ManagedScript mgdScript, final IIcfg icfg, final HcSymbolTable symbolTable, - final ISymbolicIndependenceRelation, IPredicate> independence, final IThreadModularPreferenceOrder preferenceOrder, final IcfgToChcPreferences prefs) { super(services, mgdScript, icfg, symbolTable, prefs); - mIndependenceChecker = new IndependenceChecker(services, icfg.getCfgSmtToolkit(), independence); + + mIndependenceChecker = new IndependenceChecker(services, icfg.getCfgSmtToolkit(), prefs.useSemicommutativity(), + prefs.conditionalIndependence()); mThreadLocations = icfg.getProgramPoints().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().values().stream().filter(this::isRelevantLocation).collect(Collectors.toList()))); From 921d0ad24111ab1d3912db80ca2ab6c8fd40a343 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 15:46:21 +0100 Subject: [PATCH 104/114] remove hardcoded commutativity conditions (reverts 5ab1b01) --- .../partialorder/IndependenceChecker.java | 69 ------------------- 1 file changed, 69 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java index ea7421a79d7..5f14740d56d 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/IndependenceChecker.java @@ -26,7 +26,6 @@ */ package de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.partialorder; -import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -49,7 +48,6 @@ 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.smtlibutils.ManagedScript; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.Substitution; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceConditionGenerator; import de.uni_freiburg.informatik.ultimate.lib.tracecheckerutils.partialorder.independence.SemanticIndependenceRelation; @@ -129,73 +127,6 @@ private ISymbolicIndependenceRelation createIndependence( public Term getIndependenceCondition(final Function getTermVariable, final ThreadInstance thread1, final IcfgEdge action1, final ThreadInstance thread2, final IcfgEdge action2) { - // Hardcoded conditions for line-queue example - // TODO remove after evaluation - Term hardcoded = null; - if ("value := queue[id - 1][read_ptr];".equals(action1.toString()) - && "queue := queue[0 := queue[0][write_ptr[0] := idx]];".equals(action2.toString())) { - final var idLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() - .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); - final var readPtrLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() - .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); - final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) - .findAny().get(); - hardcoded = SmtUtils.or(mMgdScript.getScript(), - SmtUtils.distinct(mMgdScript.getScript(), idLeft.getTerm(), - SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)), - SmtUtils.distinct(mMgdScript.getScript(), readPtrLeft.getTerm(), - SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), - SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ZERO)))); - } else if ("value := queue[id - 1][read_ptr];".equals(action1.toString()) - && "queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action2.toString())) { - final var idLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() - .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); - final var readPtrLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() - .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); - final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) - .findAny().get(); - hardcoded = SmtUtils.distinct(mMgdScript.getScript(), readPtrLeft.getTerm(), - SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), SmtUtils.minus(mMgdScript.getScript(), - idLeft.getTerm(), SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)))); - } else if ("queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action1.toString()) - && "queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action2.toString())) { - final var idLeft = mLeftSubstitution.get(mSymbolTable.getLocals(thread1.getTemplateName()).stream() - .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); - final var idRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() - .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); - hardcoded = SmtUtils.distinct(mMgdScript.getScript(), idLeft.getTerm(), idRight.getTerm()); - } else if ("queue := queue[id := queue[id][write_ptr[id] := value]];".equals(action1.toString()) - && "value := queue[id - 1][read_ptr];".equals(action2.toString())) { - final var idRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() - .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); - final var readPtrRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() - .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); - final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) - .findAny().get(); - hardcoded = SmtUtils.distinct(mMgdScript.getScript(), readPtrRight.getTerm(), - SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), SmtUtils.minus(mMgdScript.getScript(), - idRight.getTerm(), SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)))); - } else if ("queue := queue[0 := queue[0][write_ptr[0] := idx]];".equals(action1.toString()) - && "value := queue[id - 1][read_ptr];".equals(action2.toString())) { - final var idRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() - .filter(v -> "id".equals(v.getIdentifier())).findAny().get()); - final var readPtrRight = mRightSubstitution.get(mSymbolTable.getLocals(thread2.getTemplateName()).stream() - .filter(v -> "read_ptr".equals(v.getIdentifier())).findAny().get()); - final var writePtr = mSymbolTable.getGlobals().stream().filter(v -> "write_ptr".equals(v.getIdentifier())) - .findAny().get(); - hardcoded = SmtUtils.or(mMgdScript.getScript(), - SmtUtils.distinct(mMgdScript.getScript(), idRight.getTerm(), - SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ONE)), - SmtUtils.distinct(mMgdScript.getScript(), readPtrRight.getTerm(), - SmtUtils.select(mMgdScript.getScript(), writePtr.getTerm(), - SmtUtils.constructIntValue(mMgdScript.getScript(), BigInteger.ZERO)))); - } - if (hardcoded != null) { - mLogger.warn( - "Hardcoded independence condition for '" + action1 + "' and '" + action2 + "' is: " + hardcoded); - return deinstantiate(getTermVariable, thread1, thread2, hardcoded); - } - // first check the cache final var cached = mCache.get(new Pair<>(action1, action2)); if (cached != null) { From 21e81a6ad898278afb774f0d8e228e79b2ccc5dc Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 12 Dec 2024 17:59:03 +0100 Subject: [PATCH 105/114] SleepThreadModularChcTestSuite: specify solver in task definition --- .../parameterized/SleepExplicit-Eldarica.epf | 41 ------------------- .../bpl/parameterized/SleepExplicit-Golem.epf | 41 ------------------- ...SleepExplicit-Z3.epf => SleepExplicit.epf} | 0 .../{add-sub-k.yml => add-sub-k.GOLEM.yml} | 5 +++ .../add-sub-positive-k.ELDARICA.yml | 26 ++++++++++++ .../add-sub-positive-k.GOLEM.yml | 26 ++++++++++++ ...sitive-k.yml => add-sub-positive-k.Z3.yml} | 4 ++ .../bluetooth-better.ELDARICA.yml | 25 +++++++++++ .../bluetooth-better.GOLEM.yml | 25 +++++++++++ ...oth-better.yml => bluetooth-better.Z3.yml} | 3 ++ .../equalsum-ghost.ELDARICA.yml} | 9 ++-- ...ualsum-ghost.yml => equalsum-ghost.Z3.yml} | 4 ++ .../inc-bdec/inc-bdec.ELDARICA.yml | 25 +++++++++++ .../parameterized/inc-bdec/inc-bdec.GOLEM.yml | 25 +++++++++++ .../{inc-bdec.yml => inc-bdec.Z3.yml} | 4 ++ .../inc-dec-eq0-locked-assert.ELDARICA.yml} | 6 ++- .../inc-dec-eq0-locked-assert.GOLEM.yml} | 5 ++- ...t.yml => inc-dec-eq0-locked-assert.Z3.yml} | 3 ++ ...ed.yml => inc-dec-eq0-locked.ELDARICA.yml} | 4 ++ .../inc-dec-eq0-locked.GOLEM.yml | 26 ++++++++++++ .../inc-dec-eq0-locked.Z3.yml | 26 ++++++++++++ ...{inc-dec-eq0.yml => inc-dec-eq0.GOLEM.yml} | 5 +++ .../inc-dec-geq0/inc-dec-geq0.GOLEM.yml | 26 ++++++++++++ .../line-queue/line-queue.ELDARICA.yml | 27 ++++++++++++ .../line-queue/line-queue.GOLEM.yml | 27 ++++++++++++ .../{line-queue.yml => line-queue.Z3.yml} | 4 ++ .../lock/{lock.yml => lock.Z3.yml} | 5 +++ .../{mutex-3.yml => mutex-3.GOLEM.yml} | 5 +++ .../parameterized/mutex-4/mutex-4.GOLEM.yml | 27 ++++++++++++ .../{mutex-5.yml => mutex-5.GOLEM.yml} | 5 +++ ...nbounded.yml => mutex-unbounded.GOLEM.yml} | 5 +++ .../notify-listeners.ELDARICA.yml | 27 ++++++++++++ .../notify-listeners.GOLEM.yml | 27 ++++++++++++ ...-listeners.yml => notify-listeners.Z3.yml} | 4 ++ ...mbered-array.yml => numbered-array.Z3.yml} | 5 +++ .../thread-pooling.ELDARICA.yml | 25 +++++++++++ ...read-pooling.yml => thread-pooling.Z3.yml} | 4 ++ .../parameterized/ticket/ticket.ELDARICA.yml | 26 ++++++++++++ .../bpl/parameterized/ticket/ticket.GOLEM.yml | 26 ++++++++++++ .../ticket/{ticket.yml => ticket.Z3.yml} | 4 ++ .../SleepThreadModularChcTestSuite.java | 21 +++------- 41 files changed, 536 insertions(+), 102 deletions(-) delete mode 100644 trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf delete mode 100644 trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf rename trunk/examples/concurrent/bpl/parameterized/{SleepExplicit-Z3.epf => SleepExplicit.epf} (100%) rename trunk/examples/concurrent/bpl/parameterized/add-sub-k/{add-sub-k.yml => add-sub-k.GOLEM.yml} (77%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.ELDARICA.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/{add-sub-positive-k.yml => add-sub-positive-k.Z3.yml} (81%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.ELDARICA.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/bluetooth-better/{bluetooth-better.yml => bluetooth-better.Z3.yml} (86%) rename trunk/examples/concurrent/bpl/parameterized/{equalsum-fork/equalsum-fork.yml => equalsum-ghost/equalsum-ghost.ELDARICA.yml} (68%) rename trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/{equalsum-ghost.yml => equalsum-ghost.Z3.yml} (81%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/inc-bdec/{inc-bdec.yml => inc-bdec.Z3.yml} (79%) rename trunk/examples/concurrent/bpl/parameterized/{inc-dec-geq0/inc-dec-geq0.yml => inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.ELDARICA.yml} (78%) rename trunk/examples/concurrent/bpl/parameterized/{mutex-4/mutex-4.yml => inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.GOLEM.yml} (79%) rename trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/{inc-dec-eq0-locked-assert.yml => inc-dec-eq0-locked-assert.Z3.yml} (86%) rename trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/{inc-dec-eq0-locked.yml => inc-dec-eq0-locked.ELDARICA.yml} (80%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.GOLEM.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.Z3.yml rename trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/{inc-dec-eq0.yml => inc-dec-eq0.GOLEM.yml} (77%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.GOLEM.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.ELDARICA.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/line-queue/{line-queue.yml => line-queue.Z3.yml} (81%) rename trunk/examples/concurrent/bpl/parameterized/lock/{lock.yml => lock.Z3.yml} (76%) rename trunk/examples/concurrent/bpl/parameterized/mutex-3/{mutex-3.yml => mutex-3.GOLEM.yml} (77%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/mutex-5/{mutex-5.yml => mutex-5.GOLEM.yml} (77%) rename trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/{mutex-unbounded.yml => mutex-unbounded.GOLEM.yml} (78%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.ELDARICA.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/notify-listeners/{notify-listeners.yml => notify-listeners.Z3.yml} (81%) rename trunk/examples/concurrent/bpl/parameterized/numbered-array/{numbered-array.yml => numbered-array.Z3.yml} (77%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.ELDARICA.yml rename trunk/examples/concurrent/bpl/parameterized/thread-pooling/{thread-pooling.yml => thread-pooling.Z3.yml} (79%) create mode 100644 trunk/examples/concurrent/bpl/parameterized/ticket/ticket.ELDARICA.yml create mode 100644 trunk/examples/concurrent/bpl/parameterized/ticket/ticket.GOLEM.yml rename trunk/examples/concurrent/bpl/parameterized/ticket/{ticket.yml => ticket.Z3.yml} (80%) diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf deleted file mode 100644 index 3ec289208c6..00000000000 --- a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf +++ /dev/null @@ -1,41 +0,0 @@ -#Thu May 25 14:24:13 CEST 2023 - - -\!/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc= -# Settings for the program -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC -# Settings for sleep sets -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=SUFFICIENT -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true -# Other settings -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Apply\ Lipton\ reduction=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ control\ locations\ explicitly=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ sleep\ sets\ explicitly=false -@de.uni_freiburg.informatik.ultimate.plugins.icfgtochc=0.2.3 -file_export_version=3.0 - - -\!/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver= -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/CHC\ solver\ backend=ELDARICA -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ CHC\ model\ if\ query\ is\ SAT=true -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ UNSAT\ core\ if\ query\ is\ UNSAT=true -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ derivation\ if\ query\ is\ UNSAT=true -@de.uni_freiburg.informatik.ultimate.plugins.chcsolver=0.2.3 -file_export_version=3.0 - - -\!/instance/de.uni_freiburg.informatik.ultimate.chcprinter= -/instance/de.uni_freiburg.informatik.ultimate.chcprinter/File\ name=CHC -/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Use\ automatic\ naming=true -/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Save\ file\ in\ source\ directory=true -@de.uni_freiburg.informatik.ultimate.chcprinter=0.2.3 -file_export_version=3.0 - - -\!/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder= -/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Add\ additional\ assume\ for\ each\ assert=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Size\ of\ a\ code\ block=OneNontrivialStatement -@de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder=0.2.3 -file_export_version=3.0 diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf deleted file mode 100644 index 5ac3b628870..00000000000 --- a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf +++ /dev/null @@ -1,41 +0,0 @@ -#Thu May 25 14:24:13 CEST 2023 - - -\!/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc= -# Settings for the program -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Concurrency\ mode=PARAMETRIC -# Settings for sleep sets -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Preference\ order\ used\ for\ reduction=SEQ_COMP -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Conditional\ Independence=SUFFICIENT -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Break\ symmetry\ of\ preference\ order=true -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Enable\ sleep\ set\ reduction=true -# Other settings -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Apply\ Lipton\ reduction=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ control\ locations\ explicitly=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.icfgtochc/Encode\ sleep\ sets\ explicitly=false -@de.uni_freiburg.informatik.ultimate.plugins.icfgtochc=0.2.3 -file_export_version=3.0 - - -\!/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver= -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/CHC\ solver\ backend=GOLEM -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ CHC\ model\ if\ query\ is\ SAT=true -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ UNSAT\ core\ if\ query\ is\ UNSAT=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.chcsolver/Produce\ derivation\ if\ query\ is\ UNSAT=false -@de.uni_freiburg.informatik.ultimate.plugins.chcsolver=0.2.3 -file_export_version=3.0 - - -\!/instance/de.uni_freiburg.informatik.ultimate.chcprinter= -/instance/de.uni_freiburg.informatik.ultimate.chcprinter/File\ name=CHC -/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Use\ automatic\ naming=true -/instance/de.uni_freiburg.informatik.ultimate.chcprinter/Save\ file\ in\ source\ directory=true -@de.uni_freiburg.informatik.ultimate.chcprinter=0.2.3 -file_export_version=3.0 - - -\!/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder= -/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Add\ additional\ assume\ for\ each\ assert=false -/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder/Size\ of\ a\ code\ block=OneNontrivialStatement -@de.uni_freiburg.informatik.ultimate.plugins.generator.rcfgbuilder=0.2.3 -file_export_version=3.0 diff --git a/trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf b/trunk/examples/concurrent/bpl/parameterized/SleepExplicit.epf similarity index 100% rename from trunk/examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf rename to trunk/examples/concurrent/bpl/parameterized/SleepExplicit.epf diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.GOLEM.yml similarity index 77% rename from trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml rename to trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.GOLEM.yml index 4887dfc3794..d64defa17db 100644 --- a/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.yml +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-k/add-sub-k.GOLEM.yml @@ -20,3 +20,8 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 250000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.ELDARICA.yml new file mode 100644 index 00000000000..09f570f8f05 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.ELDARICA.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'add-sub-positive-k.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.GOLEM.yml new file mode 100644 index 00000000000..cded7bed46c --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.GOLEM.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'add-sub-positive-k.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.Z3.yml similarity index 81% rename from trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml rename to trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.Z3.yml index b865ebe20d7..ded9a4adfa3 100644 --- a/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.yml +++ b/trunk/examples/concurrent/bpl/parameterized/add-sub-positive-k/add-sub-positive-k.Z3.yml @@ -20,3 +20,7 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.ELDARICA.yml new file mode 100644 index 00000000000..0f9e14635db --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.ELDARICA.yml @@ -0,0 +1,25 @@ +format_version: '2.0' + +input_files: 'bluetooth-better.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: server + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.GOLEM.yml new file mode 100644 index 00000000000..a5738594830 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.GOLEM.yml @@ -0,0 +1,25 @@ +format_version: '2.0' + +input_files: 'bluetooth-better.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: server + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.Z3.yml similarity index 86% rename from trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml rename to trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.Z3.yml index b0e8fba9413..5d3c97abff3 100644 --- a/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.yml +++ b/trunk/examples/concurrent/bpl/parameterized/bluetooth-better/bluetooth-better.Z3.yml @@ -20,3 +20,6 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.ELDARICA.yml similarity index 68% rename from trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml rename to trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.ELDARICA.yml index 21b9bc00dac..42f8cd21f34 100644 --- a/trunk/examples/concurrent/bpl/parameterized/equalsum-fork/equalsum-fork.yml +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.ELDARICA.yml @@ -1,6 +1,6 @@ format_version: '2.0' -input_files: 'equalsum-fork.bpl' +input_files: 'equalsum-ghost.bpl' properties: - property_file: ../../../svcomp/properties/unreach-call.prp @@ -10,9 +10,8 @@ options: language: Boogie de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: # Settings for the program - Assume program has a precondition: false + Assume program has a precondition: true Specification mode: ASSERT_VIOLATIONS - Concurrency mode: SINGLE_MAIN_THREAD # Thread modularity level Thread-Modular Proof Level: 2 @@ -21,3 +20,7 @@ options: Preference order used for reduction: LOCKSTEP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.Z3.yml similarity index 81% rename from trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml rename to trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.Z3.yml index a8f3e843f1a..b4db0e3215e 100644 --- a/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.yml +++ b/trunk/examples/concurrent/bpl/parameterized/equalsum-ghost/equalsum-ghost.Z3.yml @@ -20,3 +20,7 @@ options: Preference order used for reduction: LOCKSTEP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml new file mode 100644 index 00000000000..cbb1d465d82 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml @@ -0,0 +1,25 @@ +format_version: '2.0' + +input_files: 'inc-bdec.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml new file mode 100644 index 00000000000..5723fb6fed2 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml @@ -0,0 +1,25 @@ +format_version: '2.0' + +input_files: 'inc-bdec.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml similarity index 79% rename from trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml rename to trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml index 3df1a227646..4e075f9880a 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml @@ -19,3 +19,7 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.ELDARICA.yml similarity index 78% rename from trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml rename to trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.ELDARICA.yml index 2919c493383..c0efb6d4df4 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.ELDARICA.yml @@ -1,6 +1,6 @@ format_version: '2.0' -input_files: 'inc-dec-geq0.bpl' +input_files: 'inc-dec-eq0-locked-assert.bpl' properties: - property_file: ../../../svcomp/properties/unreach-call.prp @@ -20,3 +20,7 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.GOLEM.yml similarity index 79% rename from trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml rename to trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.GOLEM.yml index 0636913a356..4b1b6c885f8 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.GOLEM.yml @@ -1,6 +1,6 @@ format_version: '2.0' -input_files: 'mutex-4.bpl' +input_files: 'inc-dec-eq0-locked-assert.bpl' properties: - property_file: ../../../svcomp/properties/unreach-call.prp @@ -20,3 +20,6 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.Z3.yml similarity index 86% rename from trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml rename to trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.Z3.yml index 26b26f60faa..d2c2e3e802b 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked-assert/inc-dec-eq0-locked-assert.Z3.yml @@ -20,3 +20,6 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.ELDARICA.yml similarity index 80% rename from trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml rename to trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.ELDARICA.yml index b84c76129d0..ffc6c5c12ad 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.ELDARICA.yml @@ -20,3 +20,7 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.GOLEM.yml new file mode 100644 index 00000000000..ffc6c5c12ad --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.GOLEM.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'inc-dec-eq0-locked.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.Z3.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.Z3.yml new file mode 100644 index 00000000000..ffc6c5c12ad --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0-locked/inc-dec-eq0-locked.Z3.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'inc-dec-eq0-locked.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: POSTCONDITION + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.GOLEM.yml similarity index 77% rename from trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml rename to trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.GOLEM.yml index 6e22e6ca7ad..1f3f2f2dfe8 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-eq0/inc-dec-eq0.GOLEM.yml @@ -20,3 +20,8 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 60000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.GOLEM.yml new file mode 100644 index 00000000000..437a26e9191 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/inc-dec-geq0/inc-dec-geq0.GOLEM.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'inc-dec-geq0.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 5000 #ms diff --git a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.ELDARICA.yml new file mode 100644 index 00000000000..928d39ad8a9 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.ELDARICA.yml @@ -0,0 +1,27 @@ +format_version: '2.0' + +input_files: 'line-queue.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: source + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Use semi-commutativity: true + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.GOLEM.yml new file mode 100644 index 00000000000..a41e124cf67 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.GOLEM.yml @@ -0,0 +1,27 @@ +format_version: '2.0' + +input_files: 'line-queue.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: source + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Use semi-commutativity: true + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.Z3.yml similarity index 81% rename from trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml rename to trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.Z3.yml index 1b790d0a686..fd669ebe1ec 100644 --- a/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.yml +++ b/trunk/examples/concurrent/bpl/parameterized/line-queue/line-queue.Z3.yml @@ -21,3 +21,7 @@ options: Preference order used for reduction: LOCKSTEP Use semi-commutativity: true + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml b/trunk/examples/concurrent/bpl/parameterized/lock/lock.Z3.yml similarity index 76% rename from trunk/examples/concurrent/bpl/parameterized/lock/lock.yml rename to trunk/examples/concurrent/bpl/parameterized/lock/lock.Z3.yml index 6dc9c1d51f7..e38ac493f7d 100644 --- a/trunk/examples/concurrent/bpl/parameterized/lock/lock.yml +++ b/trunk/examples/concurrent/bpl/parameterized/lock/lock.Z3.yml @@ -19,3 +19,8 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + Timeout: 5000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.GOLEM.yml similarity index 77% rename from trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml rename to trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.GOLEM.yml index 8f14987930e..6ab3e07936f 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-3/mutex-3.GOLEM.yml @@ -20,3 +20,8 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 5000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.GOLEM.yml new file mode 100644 index 00000000000..477215f908d --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-4/mutex-4.GOLEM.yml @@ -0,0 +1,27 @@ +format_version: '2.0' + +input_files: 'mutex-4.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 5000 # ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.GOLEM.yml similarity index 77% rename from trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml rename to trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.GOLEM.yml index 14b9c973106..9a095d50b81 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-5/mutex-5.GOLEM.yml @@ -20,3 +20,8 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 5000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.GOLEM.yml similarity index 78% rename from trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml rename to trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.GOLEM.yml index 82f651214ac..552cac4b883 100644 --- a/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.yml +++ b/trunk/examples/concurrent/bpl/parameterized/mutex-unbounded/mutex-unbounded.GOLEM.yml @@ -20,3 +20,8 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + Timeout: 5000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.ELDARICA.yml new file mode 100644 index 00000000000..a2c2442cec8 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.ELDARICA.yml @@ -0,0 +1,27 @@ +format_version: '2.0' + +input_files: 'notify-listeners.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: notifier + + # Thread modularity level + Thread-Modular Proof Level: 1 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Use semi-commutativity: true + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.GOLEM.yml new file mode 100644 index 00000000000..608a615ca68 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.GOLEM.yml @@ -0,0 +1,27 @@ +format_version: '2.0' + +input_files: 'notify-listeners.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + Single-instance threads: notifier + + # Thread modularity level + Thread-Modular Proof Level: 1 + + # Settings for reduction + Preference order used for reduction: LOCKSTEP + Use semi-commutativity: true + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.Z3.yml similarity index 81% rename from trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml rename to trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.Z3.yml index 655c86c9658..adc2b5cad93 100644 --- a/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.yml +++ b/trunk/examples/concurrent/bpl/parameterized/notify-listeners/notify-listeners.Z3.yml @@ -21,3 +21,7 @@ options: Preference order used for reduction: LOCKSTEP Use semi-commutativity: true + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml b/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.Z3.yml similarity index 77% rename from trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml rename to trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.Z3.yml index 3b5745d7b28..669a4fcbcce 100644 --- a/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.yml +++ b/trunk/examples/concurrent/bpl/parameterized/numbered-array/numbered-array.Z3.yml @@ -19,3 +19,8 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + Timeout: 5000 #ms + diff --git a/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.ELDARICA.yml new file mode 100644 index 00000000000..05371a21403 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.ELDARICA.yml @@ -0,0 +1,25 @@ +format_version: '2.0' + +input_files: 'thread-pooling.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: false + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.Z3.yml similarity index 79% rename from trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml rename to trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.Z3.yml index f09530c7a4f..0a2084dc8d3 100644 --- a/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.yml +++ b/trunk/examples/concurrent/bpl/parameterized/thread-pooling/thread-pooling.Z3.yml @@ -19,3 +19,7 @@ options: # Settings for reduction Preference order used for reduction: SEQ_COMP + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.ELDARICA.yml new file mode 100644 index 00000000000..7778216d5a6 --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.ELDARICA.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'ticket.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: ELDARICA + diff --git a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.GOLEM.yml new file mode 100644 index 00000000000..ea3f0d5a92c --- /dev/null +++ b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.GOLEM.yml @@ -0,0 +1,26 @@ +format_version: '2.0' + +input_files: 'ticket.bpl' + +properties: + - property_file: ../../../svcomp/properties/unreach-call.prp + expected_verdict: true + +options: + language: Boogie + de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: + # Settings for the program + Assume program has a precondition: true + Specification mode: ASSERT_VIOLATIONS + + # Thread modularity level + Thread-Modular Proof Level: 2 + + # Settings for reduction + Preference order used for reduction: SEQ_COMP + Conditional Independence: "NONE" + + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: GOLEM + diff --git a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.Z3.yml similarity index 80% rename from trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml rename to trunk/examples/concurrent/bpl/parameterized/ticket/ticket.Z3.yml index 459eb305ecb..0b6f4826bd5 100644 --- a/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.yml +++ b/trunk/examples/concurrent/bpl/parameterized/ticket/ticket.Z3.yml @@ -20,3 +20,7 @@ options: Preference order used for reduction: SEQ_COMP Conditional Independence: "NONE" + # Fix the best solver for this benchmark + de.uni_freiburg.informatik.ultimate.plugins.chcsolver: + CHC solver backend: Z3 + diff --git a/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java b/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java index eb67a2121af..5d734c4a05d 100644 --- a/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java +++ b/trunk/source/UltimateRegressionTest/src/de/uni_freiburg/informatik/ultimate/regressiontest/generic/SleepThreadModularChcTestSuite.java @@ -51,17 +51,11 @@ import de.uni_freiburg.informatik.ultimate.test.util.UltimateRunDefinitionGenerator; public class SleepThreadModularChcTestSuite extends UltimateTestSuite { - // @formatter:off - private static final String[] SETTINGS = { - "examples/concurrent/bpl/parameterized/SleepExplicit-Z3.epf", - "examples/concurrent/bpl/parameterized/SleepExplicit-Golem.epf", - "examples/concurrent/bpl/parameterized/SleepExplicit-Eldarica.epf", - }; - // @formatter:on + private static final String SETTINGS = "examples/concurrent/bpl/parameterized/SleepExplicit.epf"; private static final String TOOLCHAIN = "examples/concurrent/bpl/parameterized/ThreadModularVerifier.xml"; private static final String DIRECTORY = "examples/concurrent/bpl/parameterized/"; private static final String TASKDEF_REGEX = ".*\\.yml"; - private static final int DEFAULT_TIMEOUT = 60; + private static final int DEFAULT_TIMEOUT = 600; @Override protected Collection createTestCases() { @@ -71,16 +65,13 @@ protected Collection createTestCases() { final List result = new ArrayList<>(); for (final var taskDefFile : selectedYamlFiles) { + final File settingsFile = UltimateRunDefinitionGenerator.getFileFromTrunkDir(SETTINGS); final var taskDefinition = parseTaskDefinition(taskDefFile); final String bplFilename = (String) taskDefinition.get("input_files"); final Path bplPath = taskDefFile.toPath().getParent().resolve(bplFilename); - - for (final String settingsPath : SETTINGS) { - final File settingsFile = UltimateRunDefinitionGenerator.getFileFromTrunkDir(settingsPath); - final var urd = new UltimateRunDefinition(bplPath.toFile(), settingsFile, toolchainFile, - getTimeout(taskDefinition), applySettings(taskDefFile, taskDefinition)); - result.add(new UltimateTestCase(constructITestResultDecider(urd, taskDefinition), urd, List.of())); - } + final var urd = new UltimateRunDefinition(bplPath.toFile(), settingsFile, toolchainFile, + getTimeout(taskDefinition), applySettings(taskDefFile, taskDefinition)); + result.add(new UltimateTestCase(constructITestResultDecider(urd, taskDefinition), urd, List.of())); } return result; From 4aa7bf474e82a9115802ba251f732d736b489f32 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 13 Dec 2024 20:56:05 +0100 Subject: [PATCH 106/114] remove some redundant tests, fix expected timeout --- .../inc-bdec/inc-bdec.ELDARICA.yml | 25 ------------------- .../parameterized/inc-bdec/inc-bdec.GOLEM.yml | 1 + .../parameterized/inc-bdec/inc-bdec.Z3.yml | 25 ------------------- 3 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml delete mode 100644 trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml deleted file mode 100644 index cbb1d465d82..00000000000 --- a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.ELDARICA.yml +++ /dev/null @@ -1,25 +0,0 @@ -format_version: '2.0' - -input_files: 'inc-bdec.bpl' - -properties: - - property_file: ../../../svcomp/properties/unreach-call.prp - expected_verdict: true - -options: - language: Boogie - de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: - # Settings for the program - Assume program has a precondition: true - Specification mode: POSTCONDITION - - # Thread modularity level - Thread-Modular Proof Level: 2 - - # Settings for reduction - Preference order used for reduction: SEQ_COMP - - # Fix the best solver for this benchmark - de.uni_freiburg.informatik.ultimate.plugins.chcsolver: - CHC solver backend: ELDARICA - diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml index 5723fb6fed2..eec190e7640 100644 --- a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml +++ b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.GOLEM.yml @@ -22,4 +22,5 @@ options: # Fix the best solver for this benchmark de.uni_freiburg.informatik.ultimate.plugins.chcsolver: CHC solver backend: GOLEM + Timeout: 90000 #ms diff --git a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml b/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml deleted file mode 100644 index 4e075f9880a..00000000000 --- a/trunk/examples/concurrent/bpl/parameterized/inc-bdec/inc-bdec.Z3.yml +++ /dev/null @@ -1,25 +0,0 @@ -format_version: '2.0' - -input_files: 'inc-bdec.bpl' - -properties: - - property_file: ../../../svcomp/properties/unreach-call.prp - expected_verdict: true - -options: - language: Boogie - de.uni_freiburg.informatik.ultimate.plugins.icfgtochc: - # Settings for the program - Assume program has a precondition: true - Specification mode: POSTCONDITION - - # Thread modularity level - Thread-Modular Proof Level: 2 - - # Settings for reduction - Preference order used for reduction: SEQ_COMP - - # Fix the best solver for this benchmark - de.uni_freiburg.informatik.ultimate.plugins.chcsolver: - CHC solver backend: Z3 - From 019bfb41adff312c5120a80a5104b8d0bc84cada Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 19 Dec 2024 15:46:49 +0100 Subject: [PATCH 107/114] add setting for nondeterministic sleep updates --- ...eepSetThreadModularHornClauseProvider.java | 23 ++++++++++++++++--- .../IcfgToChcPreferenceInitializer.java | 10 ++++++++ .../preferences/IcfgToChcPreferences.java | 4 ++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java index 0bfe18d8d19..38e244b87fc 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/SleepSetThreadModularHornClauseProvider.java @@ -282,10 +282,27 @@ private void updateSleep(final HornClauseBuilder clause, final ThreadInstance ac final Term commConstr = getCommutativityConstraint(clause, activeThread, activeEdge, updatedThread, currentLoc.getTerm()); + // Combine the conjuncts to determine whether the thread can be added to the sleep set. + // ((updatedThread < activeThread) \/ sleep) /\ commConstr + final Term sleepConstr = SmtUtils.and(mScript, canBePutToSleep, commConstr); + // Update the sleep variable of updatedThread, according to the sleep set rule. - // sleep' = ((updatedThread < activeThread) \/ sleep) /\ commConstr - clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), - SmtUtils.and(mScript, canBePutToSleep, commConstr))); + if (mPrefs.useNondetSleepUpdates()) { + // This encoding allows to nondeterministically add the thread to the sleep set or not, if the required + // conditions are not satisfied. As we always prove the program correct for all resolutions of such + // nondeterminism, we also cover the case that the thread is not added. Hence, this mode is still sound. + // Overall, the satisfiability of the CHC system should not be affected. + // + // However, we generate a slightly simpler constraint which might be easier to solve. In particular, if the + // commutativity constraint contains universally quantified variables, this form allows to lift these + // quantified variables to the clause level. + // + // ((updatedThread < activeThread) \/ sleep) /\ commConstr -> sleep' + clause.addConstraint(SmtUtils.implies(mScript, sleepConstr, newSleep.getTerm())); + } else { + // sleep' = ((updatedThread < activeThread) \/ sleep) /\ commConstr + clause.addConstraint(SmtUtils.binaryBooleanEquality(mScript, newSleep.getTerm(), sleepConstr)); + } } protected Term getCommutativityConstraint(final HornClauseBuilder clause, final ThreadInstance activeThread, diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java index 17e7289f147..39356b9662a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferenceInitializer.java @@ -118,6 +118,14 @@ public class IcfgToChcPreferenceInitializer extends UltimatePreferenceInitialize + "all symmetric preference orders. If we break symmetry, more proofs are accepted."; private static final boolean DEF_BREAK_PREFORDER_SYMMETRY = true; + public static final String LABEL_NONDET_SLEEP_UPDATES = "Use nondeterministic sleep update encoding"; + private static final String DESC_NONDET_SLEEP_UPDATES = """ + If enabled, sleep set updates are encoded such that non-deterministically, \ + non-commuting edges may or may not be added to the sleep set. \ + This does not affect CHC satisfiability but may sometimes be simpler for the CHC solver. \ + It is particularly recommended in connection with necessary-and-complete conditional independence."""; + private static final boolean DEF_NONDET_SLEEP_UPDATES = false; + // TODO Currently unused public static final String LABEL_EXPLICIT_SLEEP = "Encode sleep sets explicitly"; private static final String DESC_EXPLICIT_SLEEP = "Sleep sets can be encoded symbolically (as CHC variables), " @@ -177,6 +185,8 @@ private static UltimatePreferenceItemContainer getSleepSetSettings() { DESC_SLEEP_SET_REDUCTION, PreferenceType.Boolean)); container.addItem(new UltimatePreferenceItem<>(LABEL_BREAK_PREFORDER_SYMMETRY, DEF_BREAK_PREFORDER_SYMMETRY, DESC_BREAK_PREFORDER_SYMMETRY, PreferenceType.Boolean)); + container.addItem(new UltimatePreferenceItem<>(LABEL_NONDET_SLEEP_UPDATES, DEF_NONDET_SLEEP_UPDATES, + DESC_NONDET_SLEEP_UPDATES, PreferenceType.Boolean)); container.addItem(new UltimatePreferenceItem<>(LABEL_EXPLICIT_SLEEP, DEF_EXPLICIT_SLEEP, DESC_EXPLICIT_SLEEP, PreferenceType.Boolean)); container.addItem(new UltimatePreferenceItem<>(LABEL_PREFERENCE_ORDER, DEF_PREFERENCE_ORDER, diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java index ff16c2b876d..8f2619f28e5 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/preferences/IcfgToChcPreferences.java @@ -87,6 +87,10 @@ public boolean breakPreferenceOrderSymmetry() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_BREAK_PREFORDER_SYMMETRY); } + public boolean useNondetSleepUpdates() { + return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_NONDET_SLEEP_UPDATES); + } + // TODO Currently unused public boolean explicitSleep() { return mPrefs.getBoolean(IcfgToChcPreferenceInitializer.LABEL_EXPLICIT_SLEEP); From 07d314644a786a4adf2c21f873ca162a9379365c Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Thu, 19 Dec 2024 16:48:44 +0100 Subject: [PATCH 108/114] prepare evaluation --- .../default/benchexec/sleep-threadmodular.xml | 126 +++++++++++++----- ...epf => ThreadModularVerifier.Settings.epf} | 2 +- .../SleepThreadModularChcTestSuite.java | 2 +- 3 files changed, 97 insertions(+), 33 deletions(-) rename trunk/examples/concurrent/bpl/parameterized/{SleepExplicit.epf => ThreadModularVerifier.Settings.epf} (98%) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index 9fbba9a5983..4cd8aca1a21 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -3,30 +3,94 @@ ${taskdef_path}/CHC_*.smt2 + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -90,9 +154,9 @@ - + @@ -100,9 +164,9 @@ - + - + - + @@ -168,9 +232,9 @@ - + @@ -178,9 +242,9 @@ - + - + - + @@ -150,7 +150,7 @@ - + @@ -160,7 +160,7 @@ - + @@ -170,7 +170,7 @@ - + - + @@ -228,7 +228,7 @@ - + @@ -238,7 +238,7 @@ - + @@ -248,16 +248,16 @@ - ../../../trunk/examples/threadmodular/regression/*/*.yml + ../../../trunk/examples/concurrent/bpl/parameterized/*/*.yml ../../../trunk/examples/svcomp/properties/unreach-call.prp - ../../../trunk/examples/threadmodular/regression/unsolved.set + ../../../trunk/examples/concurrent/bpl/parameterized/unsolved.set ../../../trunk/examples/svcomp/properties/unreach-call.prp From 3f1e3e5f2c01fe8e0d99795e221f1d880efe1315 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Mon, 30 Dec 2024 12:18:30 +0100 Subject: [PATCH 110/114] fix benchmark file: command line parameters --- .../default/benchexec/sleep-threadmodular.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index 48ef14d7598..738413dab4d 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -32,7 +32,7 @@ - + @@ -41,7 +41,7 @@ - + @@ -50,7 +50,7 @@ - + @@ -59,8 +59,8 @@ - - + + @@ -69,7 +69,7 @@ - + @@ -78,7 +78,7 @@ - + @@ -87,7 +87,7 @@ - + From 85b1de34df3bf5c1e2d3493c58790842c0380e02 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Fri, 3 Jan 2025 16:35:10 +0100 Subject: [PATCH 111/114] undo temporary debugging changes --- .../coreplugin/services/ModelTranslationContainer.java | 8 +++----- .../ultimate/smtsolver/external/FunctionDefinition.java | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java b/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java index 980bad6f708..ff7051987c3 100644 --- a/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java +++ b/trunk/source/CoreRCP/src/de/uni_freiburg/informatik/ultimate/core/coreplugin/services/ModelTranslationContainer.java @@ -62,11 +62,9 @@ protected ModelTranslationContainer(final ModelTranslationContainer other) { if (mTranslationSequence.size() > 0) { final ITranslator last = mTranslationSequence.getLast(); if (!isAllowedNext(last, translator)) { - // TODO a temporary change to allow UniHorn to run on generated CHCs - // throw new IllegalArgumentException( - // "The supplied ITranslator is not compatible with the existing ones. It has to be compatible with " - // + last + ", but it is " + translator); - return; + throw new IllegalArgumentException( + "The supplied ITranslator is not compatible with the existing ones. It has to be compatible with " + + last + ", but it is " + translator); } } mTranslationSequence.addLast(translator); diff --git a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java index a5847c35135..7a1a880cb67 100644 --- a/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java +++ b/trunk/source/SMTSolverBridge/src/de/uni_freiburg/informatik/ultimate/smtsolver/external/FunctionDefinition.java @@ -80,8 +80,7 @@ public String toString() { builder.append(") "); builder.append(getReturnSort()); builder.append(" "); - // TODO temporary change, revert to toString in the future - builder.append(mBody.toStringDirect()); + builder.append(mBody); builder.append(")"); return builder.toString(); } From 52675bbfc71e78569f657f112f2cc5eedd72b4d6 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 7 Jan 2025 15:31:18 +0100 Subject: [PATCH 112/114] remove EldaricaChcScript and related classes (for now) Currently, the implementation does not work well: CHC systems that are easily solved by eldarica via the command line cannot be solved by this implementation. We are probably using the eldarica classes incorrectly. It's also not clear that eldarica provides a stable API, we are just accessing some implementation details here that might change at any time. --- trunk/source/Library-CHC/META-INF/MANIFEST.MF | 1 - .../lib/chc/eldarica/Backtranslator.java | 229 ----------- .../lib/chc/eldarica/EldaricaChcScript.java | 372 ------------------ .../ultimate/lib/chc/eldarica/Translator.java | 278 ------------- 4 files changed, 880 deletions(-) delete mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Backtranslator.java delete mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java delete mode 100644 trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java diff --git a/trunk/source/Library-CHC/META-INF/MANIFEST.MF b/trunk/source/Library-CHC/META-INF/MANIFEST.MF index 037693b9ef5..cd7a3c5de95 100644 --- a/trunk/source/Library-CHC/META-INF/MANIFEST.MF +++ b/trunk/source/Library-CHC/META-INF/MANIFEST.MF @@ -17,6 +17,5 @@ Require-Bundle: de.uni_freiburg.informatik.ultimate.lib.smtlibutils, wrapped.io.github.uuverifiers.princess_2.12, org.scala-lang.scala-library Export-Package: de.uni_freiburg.informatik.ultimate.lib.chc, - de.uni_freiburg.informatik.ultimate.lib.chc.eldarica, de.uni_freiburg.informatik.ultimate.lib.chc.results Automatic-Module-Name: de.uni.freiburg.informatik.ultimate.lib.chc diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Backtranslator.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Backtranslator.java deleted file mode 100644 index 39993d3debe..00000000000 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Backtranslator.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * Copyright (C) 2023 University of Freiburg - * - * This file is part of the ULTIMATE CHC Library. - * - * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . - * - * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission - * to convey the resulting work. - */ -package de.uni_freiburg.informatik.ultimate.lib.chc.eldarica; - -import java.math.BigInteger; - -import ap.parser.IBinFormula; -import ap.parser.IBinJunctor; -import ap.parser.IEquation; -import ap.parser.IFormula; -import ap.parser.IFunApp; -import ap.parser.IIntFormula; -import ap.parser.IIntLit; -import ap.parser.IIntRelation; -import ap.parser.IPlus; -import ap.parser.ISortedVariable; -import ap.parser.ITerm; -import ap.parser.ITimes; -import ap.terfor.preds.Predicate; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; -import de.uni_freiburg.informatik.ultimate.logic.Rational; -import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; -import de.uni_freiburg.informatik.ultimate.logic.Script; -import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.logic.Term; -import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; - -/** - * Backtranslation from eldarica terms and formulas to Ultimate terms. - * - * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * - */ -class Backtranslator { - private final Script mScript; - private final BidirectionalMap mPredicateMap; - - Backtranslator(final Script script, final BidirectionalMap predicateMap) { - mScript = script; - mPredicateMap = predicateMap; - } - - public HcPredicateSymbol translatePredicate(final Predicate predicate) { - return mPredicateMap.inverse().get(predicate); - } - - public Term translateFormula(final IFormula formula, final IBoundVariableContext ctx) { - if (formula instanceof IBinFormula) { - return translateBinFormula((IBinFormula) formula, ctx); - } - if (formula instanceof IIntFormula) { - return translateIntFormula((IIntFormula) formula, ctx); - } - if (formula instanceof IEquation) { - return translateEquation((IEquation) formula, ctx); - } - throw new UnsupportedOperationException(formula.toString()); - } - - private Term translateEquation(final IEquation equation, final IBoundVariableContext ctx) { - // We don't know the intended sort of the terms here. But it does not matter, equality works for all sorts. - final var left = translateTermInternal(equation.left(), ctx); - final var right = translateTermInternal(equation.right(), ctx); - return SmtUtils.binaryEquality(mScript, left, right); - } - - private Term translateIntFormula(final IIntFormula formula, final IBoundVariableContext ctx) { - final var operand = translateTerm(formula.t(), getIntSort(), ctx); - final var rel = formula.rel(); - if (IIntRelation.EqZero().equals(rel)) { - return SmtUtils.binaryEquality(mScript, operand, numeral(BigInteger.ZERO)); - } - if (IIntRelation.GeqZero().equals(rel)) { - return SmtUtils.geq(mScript, operand, numeral(BigInteger.ZERO)); - } - throw new UnsupportedOperationException("Unknown integer relation: " + rel); - } - - private Term translateBinFormula(final IBinFormula formula, final IBoundVariableContext ctx) { - final var left = translateFormula(formula.f1(), ctx); - final var right = translateFormula(formula.f2(), ctx); - - final var op = formula.j(); - if (IBinJunctor.Or().equals(op)) { - return SmtUtils.or(mScript, left, right); - } - if (IBinJunctor.And().equals(op)) { - return SmtUtils.and(mScript, left, right); - } - if (IBinJunctor.Eqv().equals(op)) { - return SmtUtils.binaryBooleanEquality(mScript, left, right); - } - throw new UnsupportedOperationException("Unknown binary operator: " + op); - } - - public Term translateTerm(final ITerm term, final Sort sort, final IBoundVariableContext ctx) { - // sort conversion for booleans: bool expected, but term given - if (SmtSortUtils.isBoolSort(sort)) { - final var formula = new ap.types.Sort.MultipleValueBool$().isTrue(term); - return translateFormula(formula, ctx); - } - - final var translated = translateTermInternal(term, ctx); - - // sort conversion for booleans: term expected, but translated sort is bool - if (SmtSortUtils.isBoolSort(translated.getSort())) { - // zero is true, non-zero is false - // http://www.philipp.ruemmer.org/princess/doc/#ap.types.Sort$$MultipleValueBool$ - final var trueTerm = numeral(BigInteger.ZERO); - final var falseTerm = numeral(BigInteger.ONE); - return SmtUtils.ite(mScript, translated, trueTerm, falseTerm); - } - - assert translated.getSort().equals(sort) : "Translated term has sort " + translated.getSort() + " instead of " - + sort; - return translated; - } - - private Term translateTermInternal(final ITerm term, final IBoundVariableContext ctx) { - if (term instanceof IPlus) { - final var plus = (IPlus) term; - final var left = translateTerm(plus.t1(), getIntSort(), ctx); - final var right = translateTerm(plus.t2(), getIntSort(), ctx); - return SmtUtils.sum(mScript, getIntSort(), left, right); - } - if (term instanceof ITimes) { - final var times = (ITimes) term; - final var left = Rational.valueOf(times.coeff().bigIntValue(), BigInteger.ONE); - final var right = translateTerm(times.subterm(), getIntSort(), ctx); - return SmtUtils.mul(mScript, left, right); - } - if (term instanceof ISortedVariable) { - final var variable = (ISortedVariable) term; - return ctx.getBoundVariable(variable.index()); - } - if (term instanceof IFunApp) { - final var app = (IFunApp) term; - final var storeTerm = translateStore(app, ctx); - if (storeTerm != null) { - return storeTerm; - } - final var constTerm = translateConstArray(app, ctx); - if (constTerm != null) { - return constTerm; - } - final var boolLit = translateBoolLit(app); - if (boolLit != null) { - return boolLit; - } - } - if (term instanceof IIntLit) { - final var value = ((IIntLit) term).value(); - return numeral(value.bigIntValue()); - } - throw new IllegalArgumentException("Unknown term: " + term.toString()); - } - - private Term translateStore(final IFunApp store, final IBoundVariableContext ctx) { - if (!SMTLIBConstants.STORE.equals(store.fun().name()) || store.fun().arity() != 3) { - return null; - } - - final var array = translateTermInternal(store.args().apply(0), ctx); - final var index = translateTermInternal(store.args().apply(1), ctx); - final var value = translateTermInternal(store.args().apply(2), ctx); - - return SmtUtils.store(mScript, array, index, value); - } - - private Term translateConstArray(final IFunApp constArray, final IBoundVariableContext ctx) { - if (!SMTLIBConstants.CONST.equals(constArray.fun().name()) || constArray.fun().arity() != 1) { - return null; - } - - final var value = translateTermInternal(constArray.args().apply(0), ctx); - return mScript.term(SMTLIBConstants.CONST, null, - SmtSortUtils.getArraySort(mScript, getIntSort(), value.getSort()), value); - } - - private Term translateBoolLit(final IFunApp boolLit) { - final var name = boolLit.fun().name(); - switch (name) { - case SMTLIBConstants.TRUE: - case SMTLIBConstants.FALSE: - assert boolLit.args().isEmpty() : "unexpected parameters for function " + name; - return mScript.term(name); - default: - return null; - } - } - - private Term numeral(final BigInteger value) { - return SmtUtils.constructIntegerValue(mScript, getIntSort(), value); - } - - private Sort getIntSort() { - return SmtSortUtils.getIntSort(mScript); - } - - public interface IBoundVariableContext { - Term getBoundVariable(int index); - } -} diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java deleted file mode 100644 index d4474c4396b..00000000000 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/EldaricaChcScript.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * Copyright (C) 2023 University of Freiburg - * - * This file is part of the ULTIMATE CHC Library. - * - * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . - * - * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission - * to convey the resulting work. - */ -package de.uni_freiburg.informatik.ultimate.lib.chc.eldarica; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import ap.api.SimpleAPI; -import ap.basetypes.Tree; -import ap.parser.IAtom; -import ap.parser.IFormula; -import ap.terfor.preds.Predicate; -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.lib.chc.Derivation; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcSymbolTable; -import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.chc.IChcScript; -import de.uni_freiburg.informatik.ultimate.lib.chc.eldarica.Backtranslator.IBoundVariableContext; -import de.uni_freiburg.informatik.ultimate.logic.Model; -import de.uni_freiburg.informatik.ultimate.logic.Script; -import de.uni_freiburg.informatik.ultimate.logic.Script.LBool; -import de.uni_freiburg.informatik.ultimate.logic.Term; -import de.uni_freiburg.informatik.ultimate.logic.TermVariable; -import de.uni_freiburg.informatik.ultimate.smtsolver.external.FunctionDefinition; -import de.uni_freiburg.informatik.ultimate.smtsolver.external.ModelDescription; -import de.uni_freiburg.informatik.ultimate.util.Lazy; -import lazabs.GlobalParameters; -import lazabs.horn.bottomup.HornClauses.Clause; -import lazabs.horn.bottomup.SimpleWrapper; -import scala.Option; -import scala.Tuple2; -import scala.collection.JavaConverters; -import scala.collection.Seq; -import scala.collection.immutable.List; - -/** - * Provides access to the eldarica constraint Horn solver. - * - * https://github.com/uuverifiers/eldarica/ - * - * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - */ -public class EldaricaChcScript implements IChcScript, AutoCloseable { - private final IUltimateServiceProvider mServices; - private final ILogger mLogger; - private final Script mScript; - private final SimpleAPI mPrincess; - - private final long mDefaultQueryTimeout; - private boolean mProduceModels = false; - private boolean mProduceDerivations = false; - private boolean mProduceUnsatCores = false; - - private Translator mTranslator; - private Map mClauseMap; - - private LBool mLastResult = null; - private Lazy mLastModel; - private Lazy mLastDerivation; - private Lazy> mLastUnsatCore; - - public EldaricaChcScript(final IUltimateServiceProvider services, final Script script) { - this(services, script, -1L); - } - - public EldaricaChcScript(final IUltimateServiceProvider services, final Script script, - final long defaultQueryTimeout) { - mServices = services; - mLogger = services.getLoggingService().getLogger(getClass()); - mScript = script; - mPrincess = SimpleAPI.apply(SimpleAPI.apply$default$1(), SimpleAPI.apply$default$2(), - SimpleAPI.apply$default$3(), SimpleAPI.apply$default$4(), SimpleAPI.apply$default$5(), - SimpleAPI.apply$default$6(), SimpleAPI.apply$default$7(), SimpleAPI.apply$default$8(), - SimpleAPI.apply$default$9(), SimpleAPI.apply$default$10(), SimpleAPI.apply$default$11()); - mDefaultQueryTimeout = defaultQueryTimeout; - } - - @Override - public Script getScript() { - return mScript; - } - - @Override - public LBool solve(final HcSymbolTable symbolTable, final java.util.List system) { - return solve(symbolTable, system, -1L); - } - - @Override - public LBool solve(final HcSymbolTable symbolTable, final java.util.List system, final long timeout) { - reset(); - setupTimeout(timeout); - - final var translatedClauses = translateSystem(system); - try { - if (0 == 1) { - // Unreachable dummy code so Java doesn't think the catch block is unreachable. - // Necessary because the scala API does not declare checked exceptions. - throw lazabs.Main.TimeoutException$.MODULE$; - } - - mLogger.info("starting eldarica solver..."); - final var result = SimpleWrapper.solveLazily(translatedClauses, SimpleWrapper.solve$default$2(), - SimpleWrapper.solve$default$3(), SimpleWrapper.solve$default$4(), SimpleWrapper.solve$default$6()); - mLogger.info("eldarica has returned successfully."); - - final var backtranslator = mTranslator.createBacktranslator(mScript); - - if (result.isLeft()) { - mLastResult = LBool.SAT; - if (mProduceModels) { - final var modelBuilder = result.left().get(); - mLastModel = new Lazy<>(() -> translateModel(backtranslator, modelBuilder.apply())); - } - } else { - mLastResult = LBool.UNSAT; - if (mProduceDerivations || mProduceUnsatCores) { - final var derivationBuilder = result.right().get(); - final var clauseMap = mClauseMap; - if (mProduceDerivations) { - mLastDerivation = new Lazy<>(() -> translateDerivation(backtranslator, clauseMap, - derivationBuilder.apply().toTree())); - } - if (mProduceUnsatCores) { - mLastUnsatCore = - new Lazy<>(() -> extractUnsatCore(clauseMap, derivationBuilder.apply().toTree())); - } - } - } - } catch (final lazabs.Main.TimeoutException$ e) { - if (!mServices.getProgressMonitorService().continueProcessing()) { - throw new ToolchainCanceledException(getClass(), "solving CHC system"); - } - mLogger.warn("Eldarica timed out, returning UNKNOWN: %s", e); - mLastResult = LBool.UNKNOWN; - } - return mLastResult; - } - - private List translateSystem(final java.util.Collection system) { - final var translatedClauses = new ArrayList(system.size()); - for (final var clause : system) { - final var translated = mTranslator.translateClause(clause); - mClauseMap.put(translated, clause); - translatedClauses.add(translated); - } - return toList(translatedClauses); - } - - @Override - public boolean supportsModelProduction() { - return true; - } - - @Override - public void produceModels(final boolean enable) { - mProduceModels = enable; - } - - @Override - public Optional getModel() { - if (mLastResult != LBool.SAT) { - throw new UnsupportedOperationException("No model available: last query was " + mLastResult); - } - if (mLastModel == null) { - return Optional.empty(); - } - return Optional.of(mLastModel.get()); - } - - private ModelDescription translateModel(final Backtranslator backtranslator, - final scala.collection.Map model) { - final var translatedDefs = new HashSet(); - for (final var entry : ofMap(model).entrySet()) { - final var pred = backtranslator.translatePredicate(entry.getKey()); - final var ctx = new PredicateContext(mScript, pred); - final var body = backtranslator.translateFormula(entry.getValue(), ctx); - translatedDefs.add(new FunctionDefinition(pred.getFunctionSymbol(), ctx.getParameters(), body)); - } - return new ModelDescription(translatedDefs); - } - - @Override - public boolean supportsDerivationProduction() { - return true; - } - - @Override - public void produceDerivations(final boolean enable) { - mProduceDerivations = enable; - } - - @Override - public Optional getDerivation() { - if (mLastResult != LBool.UNSAT) { - throw new UnsupportedOperationException("No derivation available: last query was " + mLastResult); - } - if (mLastDerivation == null) { - return Optional.empty(); - } - return Optional.of(mLastDerivation.get()); - } - - private static Derivation translateDerivation(final Backtranslator backtranslator, - final Map clauseMap, final Tree> tree) { - final var atom = tree.d()._1(); - final var pred = backtranslator.translatePredicate(atom.pred()); - - final var args = new ArrayList(atom.args().length()); - int i = 0; - for (final var arg : ofList(atom.args())) { - final var sort = pred.getParameterSorts().get(i); - final var term = backtranslator.translateTerm(arg, sort, null); - args.add(term); - i++; - } - - final var children = ofList(tree.children()).stream() - .map(c -> translateDerivation(backtranslator, clauseMap, c)).collect(Collectors.toList()); - return new Derivation(pred, args, clauseMap.get(tree.d()._2()), children); - } - - @Override - public boolean supportsUnsatCores() { - return true; - } - - @Override - public void produceUnsatCores(final boolean enable) { - mProduceUnsatCores = enable; - } - - @Override - public Optional> getUnsatCore() { - if (mLastResult != LBool.UNSAT) { - throw new UnsupportedOperationException("No UNSAT core available: last query was " + mLastResult); - } - if (mLastUnsatCore == null) { - return Optional.empty(); - } - return Optional.of(mLastUnsatCore.get()); - } - - private static Set extractUnsatCore(final Map clauseMap, - final Tree> derivation) { - final var worklist = new ArrayDeque>>(); - worklist.add(derivation); - - final var result = new HashSet(); - while (!worklist.isEmpty()) { - final var tree = worklist.pop(); - final var clause = tree.d()._2(); - result.add(clauseMap.get(clause)); - worklist.addAll(ofList(tree.children())); - } - return result; - } - - private void reset() { - mClauseMap = new HashMap<>(); - mTranslator = new Translator(mPrincess); - - mLastModel = null; - mLastDerivation = null; - mLastUnsatCore = null; - } - - @Override - public void close() throws Exception { - mPrincess.shutDown(); - } - - private void setupTimeout(final long queryTimeout) { - // set the timeout parameter itself - final var actualTimeout = determineTimeout(queryTimeout); - mLogger.info("setting eldarica timeout (in ms) to %s", actualTimeout); - GlobalParameters.get().timeout_$eq((Option) actualTimeout); - - // we need to override the timeout checking logic, because eldarica only does this in its main() method - final var pms = mServices.getProgressMonitorService(); - final long startTime = System.currentTimeMillis(); - GlobalParameters.get().timeoutChecker_$eq(new scala.runtime.AbstractFunction0<>() { - @Override - public scala.runtime.BoxedUnit apply() { - if (!pms.continueProcessing() || (actualTimeout.isDefined() - && System.currentTimeMillis() - startTime > actualTimeout.get())) { - // Nasty hack to trick java into throwing TimeoutException, a checked exception. - // (This is necessary, because scala does not declare checked exceptions.) - throwUnchecked(lazabs.Main.TimeoutException$.MODULE$); - } - return scala.runtime.BoxedUnit.UNIT; - } - }); - } - - private Option determineTimeout(final long queryTimeout) { - final var globalTimeout = mServices.getProgressMonitorService().remainingTime(); - final var currentTimeout = queryTimeout <= 0 ? mDefaultQueryTimeout : queryTimeout; - final var actualTimeout = currentTimeout <= 0 ? globalTimeout : Long.min(currentTimeout, globalTimeout); - return actualTimeout < 0 ? Option.empty() : Option.apply((int) actualTimeout); - } - - private static void throwUnchecked(final Throwable e) throws T { - throw (T) e; - } - - private static List toList(final java.util.List list) { - return JavaConverters.asScalaIteratorConverter(list.iterator()).asScala().toList(); - } - - private static java.util.List ofList(final Seq list) { - return JavaConverters.seqAsJavaListConverter(list).asJava(); - } - - private static Map ofMap(final scala.collection.Map map) { - return JavaConverters.mapAsJavaMapConverter(map).asJava(); - } - - private static class PredicateContext implements IBoundVariableContext { - private final Script mScript; - private final HcPredicateSymbol mPredicate; - - public PredicateContext(final Script script, final HcPredicateSymbol predicate) { - mScript = script; - mPredicate = predicate; - } - - @Override - public TermVariable getBoundVariable(final int index) { - final var sort = mPredicate.getParameterSorts().get(index); - return mScript.variable("~~" + mPredicate.getFunctionSymbol() + "~" + index, sort); - } - - public TermVariable[] getParameters() { - return IntStream.range(0, mPredicate.getArity()).mapToObj(this::getBoundVariable) - .toArray(TermVariable[]::new); - } - } -} diff --git a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java b/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java deleted file mode 100644 index dd196a82a1c..00000000000 --- a/trunk/source/Library-CHC/src/de/uni_freiburg/informatik/ultimate/lib/chc/eldarica/Translator.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2023 Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * Copyright (C) 2023 University of Freiburg - * - * This file is part of the ULTIMATE CHC Library. - * - * The ULTIMATE CHC 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 CHC 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 CHC Library. If not, see . - * - * Additional permission under GNU GPL version 3 section 7: - * If you modify the ULTIMATE CHC 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 CHC Library grant you additional permission - * to convey the resulting work. - */ -package de.uni_freiburg.informatik.ultimate.lib.chc.eldarica; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.stream.Collectors; - -import ap.api.SimpleAPI; -import ap.basetypes.IdealInt; -import ap.parser.IAtom; -import ap.parser.IBoolLit; -import ap.parser.IExpression; -import ap.parser.IFormula; -import ap.parser.IFunApp; -import ap.parser.IIntLit; -import ap.parser.ITerm; -import ap.terfor.preds.Predicate; -import ap.theories.arrays.ExtArray; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcHeadVar; -import de.uni_freiburg.informatik.ultimate.lib.chc.HcPredicateSymbol; -import de.uni_freiburg.informatik.ultimate.lib.chc.HornClause; -import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils; -import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; -import de.uni_freiburg.informatik.ultimate.logic.ConstantTerm; -import de.uni_freiburg.informatik.ultimate.logic.Rational; -import de.uni_freiburg.informatik.ultimate.logic.SMTLIBConstants; -import de.uni_freiburg.informatik.ultimate.logic.Script; -import de.uni_freiburg.informatik.ultimate.logic.Sort; -import de.uni_freiburg.informatik.ultimate.logic.Term; -import de.uni_freiburg.informatik.ultimate.logic.TermVariable; -import de.uni_freiburg.informatik.ultimate.util.datastructures.BidirectionalMap; -import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.NestedMap2; -import lazabs.horn.bottomup.HornClauses; -import lazabs.horn.bottomup.HornClauses.Clause; -import scala.collection.JavaConverters; -import scala.collection.immutable.List; - -/** - * Translates {@link HornClause}s to eldarica's {@link Clause}s. - * - * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) - * - */ -class Translator { - private static final Map> BINARY_EXPRESSION_TRANSLATION = Map.of( - // equality - SMTLIBConstants.EQUALS, ITerm::$eq$eq$eq, - // disequality - SMTLIBConstants.DISTINCT, ITerm::$eq$div$eq, - // less-than - SMTLIBConstants.LT, ITerm::$less, - // less-or-equal - SMTLIBConstants.LEQ, ITerm::$less$eq, - // greater-than - SMTLIBConstants.GT, ITerm::$greater, - // greater-or-equal - SMTLIBConstants.GEQ, ITerm::$greater$eq, - // addition - SMTLIBConstants.PLUS, ITerm::$plus, - // subtraction - SMTLIBConstants.MINUS, ITerm::$minus); - - private final SimpleAPI mPrincess; - private final BidirectionalMap mPredicateMap = new BidirectionalMap<>(); - private final BidirectionalMap mVariableMap = new BidirectionalMap<>(); - private final NestedMap2, ap.types.Sort, ExtArray> mArrayTheories = new NestedMap2<>(); - - public Translator(final SimpleAPI princess) { - mPrincess = princess; - } - - public Backtranslator createBacktranslator(final Script script) { - return new Backtranslator(script, mPredicateMap); - } - - public Clause translateClause(final HornClause clause) { - final IAtom head; - if (clause.isHeadFalse()) { - head = new IAtom(HornClauses.FALSE(), toList(java.util.List.of())); - } else { - final var headPred = getPredicateSymbol(clause.getHeadPredicate()); - final var headArgs = clause.getTermVariablesForHeadPred().stream().map(HcHeadVar::getTermVariable) - .map(this::translateTerm).collect(Collectors.toList()); - head = new IAtom(headPred, toList(headArgs)); - } - - final ArrayList body = new ArrayList<>(clause.getRank()); - for (int i = 0; i < clause.getRank(); ++i) { - final var pred = getPredicateSymbol(clause.getBodyPredicates().get(i)); - final var args = - clause.getBodyPredToArgs().get(i).stream().map(this::translateTerm).collect(Collectors.toList()); - body.add(new IAtom(pred, toList(args))); - } - - final var constraint = translateFormula(clause.getConstraintFormula()); - return new Clause(head, toList(body), constraint); - } - - private static List toList(final java.util.List list) { - return JavaConverters.asScalaIteratorConverter(list.iterator()).asScala().toList(); - } - - private Predicate getPredicateSymbol(final HcPredicateSymbol pred) { - return mPredicateMap.computeIfAbsent(pred, this::createPredicate); - } - - private Predicate createPredicate(final HcPredicateSymbol pred) { - final var sorts = pred.getParameterSorts().stream().map(this::translateSort).collect(Collectors.toList()); - return mPrincess.createRelation(pred.getName(), toList(sorts)); - } - - private ap.types.Sort translateSort(final Sort sort) { - if (SmtSortUtils.isIntSort(sort)) { - return ap.types.Sort.Integer$.MODULE$; - } - if (SmtSortUtils.isBoolSort(sort)) { - return ap.types.Sort.MultipleValueBool$.MODULE$; - } - if (SmtSortUtils.isArraySort(sort)) { - return getArrayTheory(sort).sort(); - } - throw new IllegalArgumentException(sort.getName()); - } - - private ExtArray getArrayTheory(final Sort arraySort) { - final var params = arraySort.getArguments(); - assert params.length >= 2 : "arrays should have at least one index sort, and one domain sort"; - - final var indices = toList( - Arrays.stream(params).limit(params.length - 1).map(this::translateSort).collect(Collectors.toList())); - final var range = translateSort(params[params.length - 1]); - - var theory = mArrayTheories.get(indices, range); - if (theory == null) { - theory = new ExtArray(indices, range); - mArrayTheories.put(indices, range, theory); - } - return theory; - } - - public IFormula translateFormula(final Term term) { - final var expr = translateExpression(term); - if (expr instanceof ITerm) { - return ap.types.Sort.MultipleValueBool$.MODULE$.isTrue((ITerm) expr); - } - return (IFormula) translateExpression(term); - } - - public ITerm translateTerm(final Term term) { - final var expr = translateExpression(term); - if (expr instanceof IFormula) { - final var bool = ap.types.Sort.MultipleValueBool$.MODULE$; - return IExpression.ite((IFormula) expr, bool.True(), bool.False()); - } - return (ITerm) translateExpression(term); - } - - private IExpression translateExpression(final Term term) { - if (term instanceof TermVariable) { - return translateVariable((TermVariable) term); - } - if (term instanceof ApplicationTerm) { - return translateApplication((ApplicationTerm) term); - } - if (term instanceof ConstantTerm) { - return translateConstant((ConstantTerm) term); - } - throw new IllegalArgumentException(term.toString()); - } - - private IExpression translateVariable(final TermVariable variable) { - return mVariableMap.computeIfAbsent(variable, this::createVariable); - } - - private ITerm createVariable(final TermVariable variable) { - final var sort = variable.getSort(); - return mPrincess.createConstant(variable.getName(), translateSort(sort)); - } - - private IExpression translateApplication(final ApplicationTerm term) { - final var function = term.getFunction().getName(); - - final var binaryTranslation = BINARY_EXPRESSION_TRANSLATION.get(function); - if (binaryTranslation != null) { - return translateBinaryExpression(term, binaryTranslation); - } - - switch (term.getFunction().getName()) { - case SMTLIBConstants.TRUE: - case SMTLIBConstants.FALSE: - final var name = term.getFunction().getName(); - assert term.getParameters().length == 0 : "Unexpected parameters for function " + name; - return new IBoolLit(Boolean.parseBoolean(name)); - case SMTLIBConstants.AND: - final var conjuncts = - Arrays.stream(term.getParameters()).map(this::translateFormula).collect(Collectors.toList()); - return IExpression.and(toList(conjuncts)); - case SMTLIBConstants.OR: - final var disjuncts = - Arrays.stream(term.getParameters()).map(this::translateFormula).collect(Collectors.toList()); - return IExpression.or(toList(disjuncts)); - case SMTLIBConstants.IMPLIES: - final var first = translateFormula(term.getParameters()[0]); - final var second = translateFormula(term.getParameters()[1]); - return first.$eq$eq$greater(second); - case SMTLIBConstants.NOT: - return translateFormula(term.getParameters()[0]).unary_$bang(); - case SMTLIBConstants.ITE: - final var cond = translateFormula(term.getParameters()[0]); - final var thenCase = translateTerm(term.getParameters()[1]); - final var elseCase = translateTerm(term.getParameters()[2]); - return IExpression.ite(cond, thenCase, elseCase); - case SMTLIBConstants.STORE: - final var array = translateTerm(term.getParameters()[0]); - final var index = translateTerm(term.getParameters()[1]); - final var value = translateTerm(term.getParameters()[2]); - return new IFunApp(getArrayTheory(term.getParameters()[0].getSort()).store(), - toList(java.util.List.of(array, index, value))); - case SMTLIBConstants.SELECT: - final var selectArray = translateTerm(term.getParameters()[0]); - final var selectIndex = translateTerm(term.getParameters()[1]); - return new IFunApp(getArrayTheory(term.getParameters()[0].getSort()).select(), - toList(java.util.List.of(selectArray, selectIndex))); - default: - throw new IllegalArgumentException(term.toString()); - } - } - - private IExpression translateBinaryExpression(final ApplicationTerm term, - final BiFunction combinator) { - assert term.getParameters().length == 2; - final var first = translateTerm(term.getParameters()[0]); - final var second = translateTerm(term.getParameters()[1]); - return combinator.apply(first, second); - } - - private static ITerm translateConstant(final ConstantTerm constant) { - final var value = constant.getValue(); - BigInteger bigint; - if (value instanceof Rational) { - assert ((Rational) value).denominator().equals(BigInteger.ONE); - bigint = ((Rational) value).numerator(); - } else if (value instanceof BigInteger) { - bigint = (BigInteger) value; - } else { - throw new IllegalArgumentException(constant.toString()); - } - return new IIntLit(IdealInt.apply(bigint)); - } -} From ca714d1b9d39c63cae6ba4f0eca788072c361088 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Tue, 7 Jan 2025 16:21:22 +0100 Subject: [PATCH 113/114] improvements to IHcReplacementVar implementations - document usage of different prime numbers for distinct hash codes - document purpose of classes - make implementations final - additional integrity checks (null checks, refined types of program variables) - updated & simplified equals() --- .../icfgtochc/concurrent/HcGlobalVar.java | 29 +++++++-------- .../icfgtochc/concurrent/HcLocalVar.java | 33 ++++++++--------- .../icfgtochc/concurrent/HcLocationVar.java | 26 ++++++-------- .../concurrent/HcThreadCounterVar.java | 15 ++++---- .../concurrent/IHcReplacementVar.java | 8 +++++ .../ThreadModularHornClauseProvider.java | 5 +-- .../concurrent/partialorder/HcSleepVar.java | 36 ++++++++++--------- .../partialorder/HcThreadIdVar.java | 26 ++++++-------- 8 files changed, 88 insertions(+), 90 deletions(-) diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java index ae84542e662..24849d724a3 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcGlobalVar.java @@ -2,22 +2,26 @@ import java.util.Objects; -import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramNonOldVar; import de.uni_freiburg.informatik.ultimate.logic.Sort; /** + * Represents a global variable of a program. * * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) - * */ -public class HcGlobalVar implements IHcReplacementVar { - private final IProgramVar mVariable; +public final class HcGlobalVar implements IHcReplacementVar { + // Hash codes are multiplied by this number to reduce likelihood of collisions with other IHcReplacementVar + // implementations. Each implementation uses a different value. + private static final int HASH_PRIME = 59; + + private final IProgramNonOldVar mVariable; - public HcGlobalVar(final IProgramVar variable) { - mVariable = variable; + public HcGlobalVar(final IProgramNonOldVar variable) { + mVariable = Objects.requireNonNull(variable); } - public IProgramVar getVariable() { + public IProgramNonOldVar getVariable() { return mVariable; } @@ -33,18 +37,11 @@ public String toString() { @Override public int hashCode() { - return mVariable.hashCode(); + return HASH_PRIME * mVariable.hashCode(); } @Override public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof HcGlobalVar)) { - return false; - } - final HcGlobalVar other = (HcGlobalVar) obj; - return Objects.equals(mVariable, other.mVariable); + return this == obj || obj instanceof final HcGlobalVar other && mVariable.equals(other.mVariable); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java index fe0f8fbaec4..1a099cc37c4 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocalVar.java @@ -2,22 +2,30 @@ import java.util.Objects; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.logic.Sort; /** + * Represents a (procedure-)local variable of a program. * - * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) + * As we model thread templates of concurrent programs as procedures, this class also implements + * {@link IHcThreadSpecificVar}. * + * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) */ -public class HcLocalVar implements IHcThreadSpecificVar { - private final IProgramVar mVariable; +public final class HcLocalVar implements IHcThreadSpecificVar { + // Hash codes are multiplied by this number to reduce likelihood of collisions with other IHcReplacementVar + // implementations. Each implementation uses a different value. + private static final int HASH_PRIME = 97; + + private final ILocalProgramVar mVariable; private final ThreadInstance mInstance; - public HcLocalVar(final IProgramVar variable, final ThreadInstance instance) { + public HcLocalVar(final ILocalProgramVar variable, final ThreadInstance instance) { assert variable.getProcedure().equals(instance.getTemplateName()); - mVariable = variable; - mInstance = instance; + mVariable = Objects.requireNonNull(variable); + mInstance = Objects.requireNonNull(instance); } public IProgramVar getVariable() { @@ -46,8 +54,7 @@ public String toString() { @Override public int hashCode() { - final int prime = 97; - return prime * Objects.hash(mInstance, mVariable); + return HASH_PRIME * Objects.hash(mInstance, mVariable); } @Override @@ -55,13 +62,7 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final HcLocalVar other = (HcLocalVar) obj; - return Objects.equals(mInstance, other.mInstance) && Objects.equals(mVariable, other.mVariable); + return obj instanceof final HcLocalVar other && mInstance.equals(other.mInstance) + && mVariable.equals(other.mVariable); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java index 5e067058f32..77e53099e54 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcLocationVar.java @@ -7,11 +7,16 @@ import de.uni_freiburg.informatik.ultimate.logic.Sort; /** + * Models the program counter of a program. I.e., this variable is used to store an integer encoding the current control + * location of a sequential program resp. the current control location of a thread in a concurrent program. * * @author Frank Schüssele (schuessf@informatik.uni-freiburg.de) - * */ -public class HcLocationVar implements IHcThreadSpecificVar { +public final class HcLocationVar implements IHcThreadSpecificVar { + // Hash codes are multiplied by this number to reduce likelihood of collisions with other IHcReplacementVar + // implementations. Each implementation uses a different value. + private static final int HASH_PRIME = 79; + private final ThreadInstance mInstance; private final Sort mSort; @@ -20,7 +25,7 @@ public HcLocationVar(final ThreadInstance instance, final Script script) { } private HcLocationVar(final ThreadInstance instance, final Sort sort) { - mInstance = instance; + mInstance = Objects.requireNonNull(instance); mSort = sort; } @@ -46,22 +51,11 @@ public String toString() { @Override public int hashCode() { - final int prime = 79; - return prime * Objects.hash(mInstance); + return HASH_PRIME * Objects.hash(mInstance); } @Override public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final HcLocationVar other = (HcLocationVar) obj; - return Objects.equals(mInstance, other.mInstance); + return this == obj || obj instanceof final HcLocationVar other && mInstance.equals(other.mInstance); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java index 45cae313e01..0fef2c18323 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/HcThreadCounterVar.java @@ -45,7 +45,10 @@ * * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) */ -public class HcThreadCounterVar implements IHcReplacementVar { +public final class HcThreadCounterVar implements IHcReplacementVar { + // Hash codes are multiplied by this number to reduce likelihood of collisions with other IHcReplacementVar + // implementations. Each implementation uses a different value. + private static final int HASH_PRIME = 61; private final Sort mSort; @@ -65,17 +68,11 @@ public String toString() { @Override public int hashCode() { - return 79; + return HASH_PRIME; } @Override public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - return getClass() == obj.getClass(); + return this == obj || obj instanceof HcThreadCounterVar; } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java index 33a3033da31..3c1698c348a 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/IHcReplacementVar.java @@ -28,6 +28,14 @@ import de.uni_freiburg.informatik.ultimate.logic.Sort; +/** + * A variable that is useful to model a program in CHC clauses. It might directly correspond to a program variable (like + * {@link HcGlobalVar} and {@code HcLocalVar}), or it might be introduced specifically for the CHC model (like + * {@link HcLocationVar}). + * + * These variables are a useful intermediate construct for the translation. In the final CHC clauses, they are always + * replaced by some term variable (or term). + */ public interface IHcReplacementVar { Sort getSort(); } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java index a523d606605..53fd8ba0bce 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/ThreadModularHornClauseProvider.java @@ -55,6 +55,7 @@ import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaBuilder; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaUtils; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.UnmodifiableTransFormula; +import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ILocalProgramVar; import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript; import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils; @@ -264,9 +265,9 @@ protected List createThreadSpecificVars(final ThreadInstan mLocationVars.put(instance, location); result.add(location); - final List localVars = mCfgSymbolTable.getLocals(instance.getTemplateName()).stream() + final List localVars = mCfgSymbolTable.getLocals(instance.getTemplateName()).stream() .filter(mVariableFilter).collect(Collectors.toList()); - for (final IProgramVar pv : localVars) { + for (final ILocalProgramVar pv : localVars) { final var local = new HcLocalVar(pv, instance); mLocalVars.put(instance, pv, local); result.add(local); diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java index a972390d35d..d92ea5fdca4 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcSleepVar.java @@ -38,7 +38,22 @@ import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcThreadSpecificVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; -public class HcSleepVar implements IHcThreadSpecificVar, IHcFiniteReplacementVar { +/** + * Thread-specific boolean variable used in the sleep set-reduced encoding of concurrent programs. + * + * If this variable is {@code true}, then the actions of its thread are currently in the sleep set, and therefore the + * thread is not allowed to perform a step. To achieve this, all transitions of the thread have a guard requiring that + * this variable is {@code false}. + * + * @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de) + * + * @see SleepSetThreadModularHornClauseProvider + */ +public final class HcSleepVar implements IHcThreadSpecificVar, IHcFiniteReplacementVar { + // Hash codes are multiplied by this number to reduce likelihood of collisions with other IHcReplacementVar + // implementations. Each implementation uses a different value. + private static final int HASH_PRIME = 83; + private final Sort mSort; private final ThreadInstance mInstance; private final Set mValues; @@ -49,8 +64,8 @@ public HcSleepVar(final ThreadInstance instance, final Script script) { } private HcSleepVar(final ThreadInstance instance, final Sort sort, final Set values) { - mInstance = instance; - mSort = sort; + mInstance = Objects.requireNonNull(instance); + mSort = Objects.requireNonNull(sort); mValues = values; } @@ -81,22 +96,11 @@ public String toString() { @Override public int hashCode() { - final int prime = 31; - return prime * Objects.hash(mInstance); + return HASH_PRIME * mInstance.hashCode(); } @Override public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final HcSleepVar other = (HcSleepVar) obj; - return Objects.equals(mInstance, other.mInstance); + return this == obj || obj instanceof final HcSleepVar other && mInstance.equals(other.mInstance); } } diff --git a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java index 4fe250bfcca..6aed4cf63b5 100644 --- a/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java +++ b/trunk/source/IcfgToChc/src/de/uni_freiburg/informatik/ultimate/plugins/icfgtochc/concurrent/partialorder/HcThreadIdVar.java @@ -34,7 +34,14 @@ import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.IHcThreadSpecificVar; import de.uni_freiburg.informatik.ultimate.plugins.icfgtochc.concurrent.ThreadInstance; -public class HcThreadIdVar implements IHcThreadSpecificVar { +/** + * Thread-specific variable that represents a unique ID of each thread in a concurrent program. + */ +public final class HcThreadIdVar implements IHcThreadSpecificVar { + // Hash codes are multiplied by this number to reduce likelihood of collisions with other IHcReplacementVar + // implementations. Each implementation uses a different value. + private static final int HASH_PRIME = 43; + private final Sort mSort; private final ThreadInstance mInstance; @@ -43,7 +50,7 @@ public HcThreadIdVar(final ThreadInstance instance, final Script script) { } private HcThreadIdVar(final ThreadInstance instance, final Sort sort) { - mInstance = instance; + mInstance = Objects.requireNonNull(instance); mSort = sort; } @@ -69,22 +76,11 @@ public String toString() { @Override public int hashCode() { - final int prime = 59; - return prime * Objects.hash(mInstance); + return HASH_PRIME * Objects.hash(mInstance); } @Override public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final HcThreadIdVar other = (HcThreadIdVar) obj; - return Objects.equals(mInstance, other.mInstance); + return this == obj || obj instanceof final HcThreadIdVar other && mInstance.equals(other.mInstance); } } From 972bd96717c3aa2b659520a1dc393186b38f3797 Mon Sep 17 00:00:00 2001 From: "maul.esel" Date: Wed, 8 Jan 2025 21:40:30 +0100 Subject: [PATCH 114/114] add missing benchmark rundefinitions --- .../default/benchexec/sleep-threadmodular.xml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/releaseScripts/default/benchexec/sleep-threadmodular.xml b/releaseScripts/default/benchexec/sleep-threadmodular.xml index 738413dab4d..4347e905079 100644 --- a/releaseScripts/default/benchexec/sleep-threadmodular.xml +++ b/releaseScripts/default/benchexec/sleep-threadmodular.xml @@ -66,6 +66,26 @@ + + + + + + + + + + + + + + + +