Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added releaseScripts/default/adds/mus_enumerator
Binary file not shown.
2 changes: 1 addition & 1 deletion releaseScripts/default/createReqCheckZip.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,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/mus_enumerator")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does mus_enumerator have a licence? You also need to add some info to our READMEs.

elif [ "$2" == "win32" ]; then
echo "Building .zip for win32..."
ARCH="win32"
Expand Down
12 changes: 8 additions & 4 deletions trunk/examples/settings/reqanalyzer/RTINC-badger-allatonce.epf

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the name still meaningful?

Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,18 @@ file_export_version=3.0
/instance/de.uni_freiburg.informatik.ultimate.plugins.generator.traceabstraction/Trace\ refinement\ exception\ blacklist=UNKNOWN
@de.uni_freiburg.informatik.ultimate.plugins.generator.traceabstraction=0.1.23

#Thu Jan 18 16:49:04 CET 2024
#Tue Aug 26 15:21:09 CEST 2025
\!/instance/de.uni_freiburg.informatik.ultimate.pea2boogie=
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Always\ use\ all\ invariants\ during\ rt-inconsistency\ checks=false
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Check\ consistency=false
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Check\ if\ two\ PEAs\ are\ complements\ of\ each\ other=false
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Check\ rt-inconsistency=true
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Check\ vacuity=false
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Use\ epsilon\ transformation\ during\ rt-inconsistency\ check=false
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Generate\ history\ vars\ ('v)\ in\ Encoding=false
@de.uni_freiburg.informatik.ultimate.pea2boogie=0.2.3
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Report\ trivial\ rt-consistency=true
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Rt-inconsistency\ range=2
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/Use\ epsilon\ transformation\ during\ rt-inconsistency\ check=false
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/number\ of\ chain-link\ requirements\ for\ rt-inconsistency=5
/instance/de.uni_freiburg.informatik.ultimate.pea2boogie/rt-inconsistency\ pre-check=false
@de.uni_freiburg.informatik.ultimate.pea2boogie=0.3.0
file_export_version=3.0

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public class CddToSmt {
private final Term mFalse;
private final IIdentifierTranslator[] mIdentifierTranslators;
private final IReqSymbolTable mReqSymboltable;
private final Boogie2SMT mBoogieToSmt;
protected final Boogie2SMT mBoogieToSmt;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No

private final PeaResultUtil mResultUtil;

public CddToSmt(final IUltimateServiceProvider services, final PeaResultUtil resultUtil, final Script script,
Expand Down Expand Up @@ -164,7 +164,7 @@ public Term toSmt(final CDD cdd) {
return rtr;
}

private Term toSmtForRange(final int childIdx, final String varname, final int[] limits) {
public Term toSmtForRange(final int childIdx, final String varname, final int[] limits) {
final Term var = getTermVarTerm(varname);

if (childIdx == 0) {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
/*
* Copyright (C) 2026 Nico Hauff (hauffn@informatik.uni-freiburg.de)
* Copyright (C) 2026 University of Freiburg
*
* This file is part of the ULTIMATE PEAtoBoogie plug-in.
*
* The ULTIMATE PEAtoBoogie 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 PEAtoBoogie 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 PEAtoBoogie plug-in. If not, see <http://www.gnu.org/licenses/>.
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE PEAtoBoogie 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 PEAtoBoogie plug-in grant you additional permission
* to convey the resulting work.
*/

package de.uni_freiburg.informatik.ultimate.pea2boogie.generator;

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 de.uni_freiburg.informatik.ultimate.core.model.services.ILogger;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils;
import de.uni_freiburg.informatik.ultimate.logic.Annotation;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol;
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.logic.Sort;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.TermVariable;
import de.uni_freiburg.informatik.ultimate.smtinterpol.smtlib2.SMTInterpol;

/**
* Java translation of the Z3 Python example "Enumeration of Minimal Unsatisfiable Cores and Maximal Satisfying Subsets"
* https://microsoft.github.io/z3guide/programming/Example%20Programs/Cores%20and%20Satisfying%20Subsets/
*/
public class MusEnumerator {

public record MusEnumeratorResult(Type type, Set<Integer> indices, List<Term> terms) {
public enum Type {
MUS, MSS
}
}

public static List<MusEnumeratorResult> enumerate(final SubsetSolver csolver, final MapSolver msolver,
final ILogger logger) {
final List<MusEnumeratorResult> results = new ArrayList<>();

while (true) {
final Set<Integer> seed = msolver.nextSeed(); // MSolver -> checkSat / getModel

if (seed == null) {
break;
}

if (csolver.checkSubset(seed)) { // CSolver -> checkSat
// Found MSS
final Set<Integer> mss = csolver.grow(new HashSet<>(seed));

if (!mss.isEmpty()) {
results.add(new MusEnumeratorResult(MusEnumeratorResult.Type.MSS, mss,
mss.stream().map(i -> csolver.mConstraints.get(i)).toList()));
}
msolver.blockDown(mss);
} else {
// Found MUS
final Set<Integer> mus = csolver.shrink(seed); // CSolver -> seedFromCore -> getUnsatCore

if (!mus.isEmpty()) {
results.add(new MusEnumeratorResult(MusEnumeratorResult.Type.MUS, mus,
mus.stream().map(i -> csolver.mConstraints.get(i)).toList()));
}
msolver.blockUp(mus);
}
}

return results;
}

public static class SubsetSolver {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its weird to have that as public static class -- are you sure you need to expose both solvers and cannot hide them completely?

private final Script mScript;
private final List<Term> mConstraints;
private final Map<Integer, Term> mVarCache = new HashMap<>();

public SubsetSolver(final Script script, final List<Term> constraints) {
mScript = script;
mConstraints = constraints;

for (int i = 0; i < mConstraints.size(); i++) {
final Term cVar = cVar(i);
final Term annotated = script.annotate(script.term("=>", cVar, constraints.get(i)),
new Annotation(":named", "n" + String.valueOf(i)));

script.assertTerm(annotated);
}
}

private Term cVar(final int i) {
assert i >= 0 && i < mConstraints.size();

if (!mVarCache.containsKey(i)) {
final String name = "c" + String.valueOf(i);
mScript.declareFun(name, new Sort[0], mScript.getTheory().getBooleanSort());
final Term v = mScript.term(name);

mVarCache.put(i, v);
}

return mVarCache.get(i);
}

public boolean checkSubset(final Set<Integer> seed) {
return checkSubset(seed, false);
}

public boolean checkSubset(final Set<Integer> seed, final boolean doNotPopIfUnsat) { // <--- CSolver checkSat
final Term[] assumptions = seed.stream().map(this::cVar).toArray(Term[]::new);

mScript.push(1);

for (final Term assumption : assumptions) {
mScript.assertTerm(assumption);
}

// TODO: CheckSatAssuming would be better, but is not available for z3
// final LBool result = mScript.checkSatAssuming(assumptions);
final LBool result = mScript.checkSat();
assert result != LBool.UNKNOWN;

if (!doNotPopIfUnsat || result != LBool.UNSAT) {
mScript.pop(1);
}

return result == LBool.SAT;
}

public Set<Integer> complement(final Set<Integer> set) {
final Set<Integer> result = new HashSet<>();

for (int i = 0; i < mConstraints.size(); i++) {
if (!set.contains(i)) {
result.add(i);
}
}

return result;
}

private List<Integer> seedFromCore() {
final List<Integer> result = new ArrayList<>();
final Term[] core = mScript.getUnsatCore();

mScript.pop(1);

for (final Term t : core) {
final String name = ((ApplicationTerm) t).getFunction().getName().substring(1);
final Integer i = Integer.parseInt(name);
result.add(i);
}

return result;
}

public Set<Integer> shrink(final Set<Integer> seed) {
Set<Integer> current = new HashSet<>(seed);

for (final int i : seed) {
if (!current.contains(i)) {
continue;
}

current.remove(i);

if (!checkSubset(current, true)) {
current = new HashSet<>(seedFromCore());
} else {
current.add(i);
}
}

return current;
}

public Set<Integer> grow(final Set<Integer> seed) {
final Set<Integer> current = new HashSet<>(seed);

for (final int i : complement(seed)) {
current.add(i);

if (!checkSubset(current)) {
current.remove(i);
}
}

return current;
}
}

public static class MapSolver {
private final Script mScript;
private final Set<Integer> mAllN = new HashSet<>();

public MapSolver(final Script script, final int n) {
mScript = script;

if (mScript instanceof SMTInterpol) {
mScript.setLogic(Logics.ALL);
}

for (int i = 0; i < n; i++) {
mAllN.add(i);
}
}

public Set<Integer> nextSeed() {
final LBool res = mScript.checkSat();
assert res != LBool.UNKNOWN;

if (res == LBool.UNSAT) {
return null;
}

final Model model = mScript.getModel();
final Map<Integer, Term> evaluations = new HashMap<>();
for (final FunctionSymbol fs : model.getDefinedFunctions()) {
assert fs.getParameterSorts().length == 0
&& fs.getReturnSort().equals(mScript.getTheory().getBooleanSort());

final Term valueTerm = model.getFunctionDefinition(fs.getName(), new TermVariable[0]);
evaluations.put(Integer.valueOf(fs.getName()), valueTerm);
}

final Set<Integer> seed = new HashSet<>(mAllN);
final Set<Integer> toRemove = new HashSet<>();
for (final Integer i : evaluations.keySet()) {
final Term valueTerm = evaluations.get(i);

if (valueTerm.equals(mScript.getTheory().mFalse)) {
toRemove.add(i);
}
}
seed.removeAll(toRemove);

return seed;
}

private Set<Integer> complement(final Set<Integer> set) {
final Set<Integer> result = new HashSet<>(mAllN);
result.removeAll(set);

return result;
}

public void blockDown(final Set<Integer> fromPoint) {
final Set<Integer> complement = complement(fromPoint);

final List<Term> lits = new ArrayList<>();
for (final int i : complement) {
if (mScript.getTheory().getFunctionSymbol(String.valueOf(i)) == null) {
mScript.declareFun(Integer.toString(i), new Sort[0], mScript.getTheory().getBooleanSort());
}
lits.add(mScript.term(Integer.toString(i)));
}

mScript.assertTerm(SmtUtils.or(mScript, lits));
}

public void blockUp(final Set<Integer> fromPoint) {
final List<Term> lits = new ArrayList<>();
for (final int i : fromPoint) {
if (mScript.getTheory().getFunctionSymbol(String.valueOf(i)) == null) {
mScript.declareFun(Integer.toString(i), new Sort[0], mScript.getTheory().getBooleanSort());
}
lits.add(mScript.term("not", mScript.term(Integer.toString(i))));
}

mScript.assertTerm(SmtUtils.or(mScript, lits));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import de.uni_freiburg.informatik.ultimate.pea2boogie.IReqSymbolTable;
import de.uni_freiburg.informatik.ultimate.pea2boogie.PeaResultUtil;
import de.uni_freiburg.informatik.ultimate.pea2boogie.preferences.Pea2BoogiePreferences;
import de.uni_freiburg.informatik.ultimate.pea2boogie.preferences.Pea2BoogiePreferences.CompleteRtInconsistencyCheckMode;
import de.uni_freiburg.informatik.ultimate.pea2boogie.translator.EpsilonTransformer;
import de.uni_freiburg.informatik.ultimate.pea2boogie.translator.IEpsilonTransformer;
import de.uni_freiburg.informatik.ultimate.smtinterpol.util.DAGSize;
Expand Down Expand Up @@ -130,6 +131,8 @@ public class RtInconcistencyConditionGenerator {
private final IUltimateServiceProvider mServices;
private final ILogger mLogger;
private final boolean mSeparateInvariantHandling;
private final PeaResultUtil mPeaResultUtil;
private final BoogieDeclarations mBoogieDeclarations;
private final CddToSmt mCddToSmt;

private final ConstructionCache<Term, Term> mProjectionCache;
Expand Down Expand Up @@ -186,7 +189,10 @@ public RtInconcistencyConditionGenerator(final ILogger logger, final IUltimateSe
mGeneratedChecks = 0;
mQuantifiedQuery = 0;
mQelimQuery = 0;
mCddToSmt = new CddToSmt(services, peaResultUtil, mScript, mBoogie2Smt, boogieDeclarations, mReqSymboltable);

mPeaResultUtil = peaResultUtil;
mBoogieDeclarations = boogieDeclarations;
mCddToSmt = new CddToSmt(mServices, mPeaResultUtil, mScript, mBoogie2Smt, mBoogieDeclarations, mReqSymboltable);

final boolean useEpsilon =
services.getPreferenceProvider(Activator.PLUGIN_ID).getBoolean(Pea2BoogiePreferences.LABEL_USE_EPSILON);
Expand Down Expand Up @@ -268,7 +274,6 @@ private boolean filterReqs(final PhaseEventAutomata pea) {
}

private static Script buildSolver(final IUltimateServiceProvider services) throws AssertionError {

SolverSettings settings = SolverBuilder.constructSolverSettings()
.setSolverMode(SolverMode.External_ModelsAndUnsatCoreMode).setUseExternalSolver(ExternalSolver.Z3);
if (SOLVER_LOG_DIR != null) {
Expand Down Expand Up @@ -648,4 +653,11 @@ public Collection<PatternType<?>> getResponsibleRequirements() {

}

public List<Entry<PatternType<?>, PhaseEventAutomata>[]> doRtiPreCheck(final List<ReqPeas> reqPeas,
final CompleteRtInconsistencyCheckMode mode) {
return new CompleteRtInconsistencyCheck(reqPeas, mPeaResultUtil, mBoogie2Smt, mBoogieDeclarations,
mReqSymboltable, mScript, mServices, mLogger, mode).check();

}

}
Loading