From 0e4656f98b369707e34edd64b0188a28a21677c4 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 14 Aug 2025 13:12:08 +0200 Subject: [PATCH 001/233] Trace: Add API tracing --- .../java_smt/SolverContextFactory.java | 9 + .../trace/TraceArrayFormulaManager.java | 92 ++++++++ .../trace/TraceBitvectorFormulaManager.java | 194 +++++++++++++++++ .../trace/TraceBooleanFormulaManager.java | 188 ++++++++++++++++ .../delegate/trace/TraceFormulaManager.java | 203 ++++++++++++++++++ .../trace/TraceIntegerFormulaManager.java | 198 +++++++++++++++++ .../java_smt/delegate/trace/TraceLogger.java | 105 +++++++++ .../trace/TraceProverEnvironment.java | 92 ++++++++ .../delegate/trace/TraceSolverContext.java | 69 ++++++ .../delegate/trace/TraceUFManager.java | 78 +++++++ .../java_smt/delegate/trace/package-info.java | 15 ++ 11 files changed, 1243 insertions(+) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/package-info.java diff --git a/src/org/sosy_lab/java_smt/SolverContextFactory.java b/src/org/sosy_lab/java_smt/SolverContextFactory.java index 34c547ae28..b5aa969e8c 100644 --- a/src/org/sosy_lab/java_smt/SolverContextFactory.java +++ b/src/org/sosy_lab/java_smt/SolverContextFactory.java @@ -30,6 +30,7 @@ import org.sosy_lab.java_smt.delegate.logging.LoggingSolverContext; import org.sosy_lab.java_smt.delegate.statistics.StatisticsSolverContext; import org.sosy_lab.java_smt.delegate.synchronize.SynchronizedSolverContext; +import org.sosy_lab.java_smt.delegate.trace.TraceSolverContext; import org.sosy_lab.java_smt.solvers.bitwuzla.BitwuzlaSolverContext; import org.sosy_lab.java_smt.solvers.boolector.BoolectorSolverContext; import org.sosy_lab.java_smt.solvers.cvc4.CVC4SolverContext; @@ -95,6 +96,11 @@ public enum Solvers { @Option(secure = true, description = "Apply additional checks to catch common user errors.") private boolean useDebugMode = false; + @Option( + secure = true, + description = "Enable API tracing to record all calls to the JavaSMT library") + private boolean trace = false; + @Option( secure = true, description = "Counts all operations and interactions towards the SMT solver.") @@ -230,6 +236,9 @@ public SolverContext generateContext(Solvers solverToCreate) if (useDebugMode) { context = new DebuggingSolverContext(solverToCreate, config, context); } + if (trace) { + context = new TraceSolverContext(context); + } if (collectStatistics) { // statistics need to be the most outer wrapping layer. context = new StatisticsSolverContext(context); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java new file mode 100644 index 0000000000..24ee2c74b4 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java @@ -0,0 +1,92 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import org.sosy_lab.java_smt.api.ArrayFormula; +import org.sosy_lab.java_smt.api.ArrayFormulaManager; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaType; + +public class TraceArrayFormulaManager implements ArrayFormulaManager { + private final ArrayFormulaManager delegate; + private final TraceLogger logger; + + TraceArrayFormulaManager(ArrayFormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public TE select( + ArrayFormula pArray, TI pIndex) { + return logger.logDef( + "mgr.getArrayFormulaManager()", + String.format("select(%s, %s)", logger.toVariable(pArray), logger.toVariable(pIndex)), + () -> delegate.select(pArray, pIndex)); + } + + @Override + public ArrayFormula store( + ArrayFormula pArray, TI pIndex, TE pValue) { + return logger.logDef( + "mgr.getArrayFormulaManager()", + String.format( + "store(%s, %s, %s)", + logger.toVariable(pArray), logger.toVariable(pIndex), logger.toVariable(pValue)), + () -> delegate.store(pArray, pIndex, pValue)); + } + + @Override + public < + TI extends Formula, + TE extends Formula, + FTI extends FormulaType, + FTE extends FormulaType> + ArrayFormula makeArray(String pName, FTI pIndexType, FTE pElementType) { + return logger.logDef( + "mgr.getArrayFormulaManager()", + String.format( + "makeArray(\"%s\", %s, %s)", + pName, logger.printFormulaType(pIndexType), logger.printFormulaType(pElementType)), + () -> delegate.makeArray(pName, pIndexType, pElementType)); + } + + @Override + public < + TI extends Formula, + TE extends Formula, + FTI extends FormulaType, + FTE extends FormulaType> + ArrayFormula makeArray(FTI pIndexType, FTE pElementType, TE defaultElement) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula equivalence( + ArrayFormula pArray1, ArrayFormula pArray2) { + return logger.logDef( + "mgr.getArrayFormulaManager", + String.format( + "equivalence(%s, %s)", logger.toVariable(pArray1), logger.toVariable(pArray2)), + () -> delegate.equivalence(pArray1, pArray2)); + } + + @Override + public FormulaType getIndexType(ArrayFormula pArray) { + return delegate.getIndexType(pArray); + } + + @Override + public FormulaType getElementType(ArrayFormula pArray) { + return delegate.getElementType(pArray); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java new file mode 100644 index 0000000000..db5c044a2f --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -0,0 +1,194 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.math.BigInteger; +import java.util.List; +import org.sosy_lab.java_smt.api.BitvectorFormula; +import org.sosy_lab.java_smt.api.BitvectorFormulaManager; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; + +public class TraceBitvectorFormulaManager implements BitvectorFormulaManager { + + @Override + public BitvectorFormula makeBitvector(int length, long pI) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula makeBitvector(int length, BigInteger pI) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula makeBitvector(int length, IntegerFormula pI) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula toIntegerFormula(BitvectorFormula pI, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula makeVariable(int length, String pVar) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula makeVariable(BitvectorType type, String pVar) { + throw new UnsupportedOperationException(); + } + + @Override + public int getLength(BitvectorFormula number) { + return 0; + } + + @Override + public BitvectorFormula negate(BitvectorFormula number) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula add(BitvectorFormula number1, BitvectorFormula number2) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula subtract(BitvectorFormula number1, BitvectorFormula number2) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula divide( + BitvectorFormula dividend, BitvectorFormula divisor, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula smodulo(BitvectorFormula dividend, BitvectorFormula divisor) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula remainder( + BitvectorFormula dividend, BitvectorFormula divisor, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula multiply(BitvectorFormula number1, BitvectorFormula number2) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula equal(BitvectorFormula number1, BitvectorFormula number2) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula greaterThan( + BitvectorFormula number1, BitvectorFormula number2, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula greaterOrEquals( + BitvectorFormula number1, BitvectorFormula number2, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula lessThan( + BitvectorFormula number1, BitvectorFormula number2, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula lessOrEquals( + BitvectorFormula number1, BitvectorFormula number2, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula not(BitvectorFormula bits) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula and(BitvectorFormula bits1, BitvectorFormula bits2) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula or(BitvectorFormula bits1, BitvectorFormula bits2) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula xor(BitvectorFormula bits1, BitvectorFormula bits2) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula shiftRight( + BitvectorFormula number, BitvectorFormula toShift, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula shiftLeft(BitvectorFormula number, BitvectorFormula toShift) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula rotateLeft(BitvectorFormula number, int toRotate) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula rotateLeft(BitvectorFormula number, BitvectorFormula toRotate) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula rotateRight(BitvectorFormula number, int toRotate) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula rotateRight(BitvectorFormula number, BitvectorFormula toRotate) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula concat(BitvectorFormula prefix, BitvectorFormula suffix) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula extract(BitvectorFormula number, int msb, int lsb) { + throw new UnsupportedOperationException(); + } + + @Override + public BitvectorFormula extend(BitvectorFormula number, int extensionBits, boolean signed) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula distinct(List pBits) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java new file mode 100644 index 0000000000..78ae819fe0 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -0,0 +1,188 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collector; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.BooleanFormulaManager; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.visitors.BooleanFormulaTransformationVisitor; +import org.sosy_lab.java_smt.api.visitors.BooleanFormulaVisitor; +import org.sosy_lab.java_smt.api.visitors.TraversalProcess; + +public class TraceBooleanFormulaManager implements BooleanFormulaManager { + private final BooleanFormulaManager delegate; + private final TraceLogger logger; + + TraceBooleanFormulaManager(BooleanFormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public BooleanFormula makeTrue() { + return logger.logDef("mgr.getBooleanFormulaManager()", "makeTrue()", delegate::makeTrue); + } + + @Override + public BooleanFormula makeFalse() { + return logger.logDef("mgr.getBooleanFormulaManager()", "makeFalse()", delegate::makeFalse); + } + + @Override + public BooleanFormula makeVariable(String pVar) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("makeVariable(\"%s\")", pVar), + () -> delegate.makeVariable(pVar)); + } + + @Override + public BooleanFormula equivalence(BooleanFormula formula1, BooleanFormula formula2) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format( + "equivalence(%s, %s)", logger.toVariable(formula1), logger.toVariable(formula2)), + () -> delegate.equivalence(formula1, formula2)); + } + + @Override + public BooleanFormula implication(BooleanFormula formula1, BooleanFormula formula2) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format( + "implication(%s, %s)", logger.toVariable(formula1), logger.toVariable(formula2)), + () -> delegate.implication(formula1, formula2)); + } + + @Override + public boolean isTrue(BooleanFormula formula) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("isTrue(%s)", logger.toVariable(formula)), + () -> delegate.isTrue(formula)); + } + + @Override + public boolean isFalse(BooleanFormula formula) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("isFalse(%s)", logger.toVariable(formula)), + () -> delegate.isFalse(formula)); + } + + @Override + public T ifThenElse(BooleanFormula cond, T f1, T f2) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format( + "ifThenElse(%s, %s, %s)", + logger.toVariable(cond), logger.toVariable(f1), logger.toVariable(f2)), + () -> delegate.ifThenElse(cond, f1, f2)); + } + + @Override + public BooleanFormula not(BooleanFormula formula) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("not(%s)", logger.toVariable(formula)), + () -> delegate.not(formula)); + } + + @Override + public BooleanFormula and(BooleanFormula formula1, BooleanFormula formula2) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("and(%s, %s)", logger.toVariable(formula1), logger.toVariable(formula2)), + () -> delegate.and(formula1, formula2)); + } + + @Override + public BooleanFormula and(Collection bits) { + BooleanFormula f = makeTrue(); + for (BooleanFormula bf : bits) { + f = and(bf, f); + } + return f; + } + + @Override + public BooleanFormula and(BooleanFormula... bits) { + return and(Arrays.asList(bits)); + } + + @Override + public Collector toConjunction() { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula or(BooleanFormula formula1, BooleanFormula formula2) { + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("or(%s, %s)", logger.toVariable(formula1), logger.toVariable(formula2)), + () -> delegate.or(formula1, formula2)); + } + + @Override + public BooleanFormula or(Collection bits) { + BooleanFormula f = makeFalse(); + for (BooleanFormula bf : bits) { + f = or(bf, f); + } + return f; + } + + @Override + public BooleanFormula or(BooleanFormula... bits) { + return or(Arrays.asList(bits)); + } + + @Override + public Collector toDisjunction() { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula xor(BooleanFormula bits1, BooleanFormula bits2) { + throw new UnsupportedOperationException(); + } + + @Override + public R visit(BooleanFormula pFormula, BooleanFormulaVisitor visitor) { + throw new UnsupportedOperationException(); + } + + @Override + public void visitRecursively( + BooleanFormula f, BooleanFormulaVisitor rFormulaVisitor) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula transformRecursively( + BooleanFormula f, BooleanFormulaTransformationVisitor pVisitor) { + throw new UnsupportedOperationException(); + } + + @Override + public Set toConjunctionArgs(BooleanFormula f, boolean flatten) { + throw new UnsupportedOperationException(); + } + + @Override + public Set toDisjunctionArgs(BooleanFormula f, boolean flatten) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java new file mode 100644 index 0000000000..96a31cf520 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -0,0 +1,203 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import java.util.List; +import java.util.Map; +import org.sosy_lab.common.Appender; +import org.sosy_lab.java_smt.api.ArrayFormulaManager; +import org.sosy_lab.java_smt.api.BitvectorFormulaManager; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.BooleanFormulaManager; +import org.sosy_lab.java_smt.api.EnumerationFormulaManager; +import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaManager; +import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.FunctionDeclaration; +import org.sosy_lab.java_smt.api.IntegerFormulaManager; +import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; +import org.sosy_lab.java_smt.api.RationalFormulaManager; +import org.sosy_lab.java_smt.api.SLFormulaManager; +import org.sosy_lab.java_smt.api.SolverException; +import org.sosy_lab.java_smt.api.StringFormulaManager; +import org.sosy_lab.java_smt.api.Tactic; +import org.sosy_lab.java_smt.api.UFManager; +import org.sosy_lab.java_smt.api.visitors.FormulaTransformationVisitor; +import org.sosy_lab.java_smt.api.visitors.FormulaVisitor; +import org.sosy_lab.java_smt.api.visitors.TraversalProcess; + +public class TraceFormulaManager implements FormulaManager { + private final FormulaManager delegate; + private final TraceLogger logger; + + TraceFormulaManager(FormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public IntegerFormulaManager getIntegerFormulaManager() { + return new TraceIntegerFormulaManager(delegate.getIntegerFormulaManager(), logger); + } + + @Override + public RationalFormulaManager getRationalFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormulaManager getBooleanFormulaManager() { + return new TraceBooleanFormulaManager(delegate.getBooleanFormulaManager(), logger); + } + + @Override + public ArrayFormulaManager getArrayFormulaManager() { + return new TraceArrayFormulaManager(delegate.getArrayFormulaManager(), logger); + } + + @Override + public BitvectorFormulaManager getBitvectorFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public FloatingPointFormulaManager getFloatingPointFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public UFManager getUFManager() { + return new TraceUFManager(delegate.getUFManager(), logger); + } + + @Override + public SLFormulaManager getSLFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public QuantifiedFormulaManager getQuantifiedFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public StringFormulaManager getStringFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public EnumerationFormulaManager getEnumerationFormulaManager() { + throw new UnsupportedOperationException(); + } + + @Override + public T makeVariable(FormulaType formulaType, String name) { + return logger.logDef( + "mgr", + String.format("makeVariable(%s, \"%s\")", logger.printFormulaType(formulaType), name), + () -> delegate.makeVariable(formulaType, name)); + } + + @Override + public T makeApplication( + FunctionDeclaration declaration, List args) { + throw new UnsupportedOperationException(); + } + + @Override + public T makeApplication( + FunctionDeclaration declaration, Formula... args) { + return makeApplication(declaration, ImmutableList.copyOf(args)); + } + + @Override + public FormulaType getFormulaType(T formula) { + // FIXME Add proper tracing + return delegate.getFormulaType(formula); + } + + @Override + public BooleanFormula parse(String s) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + @Override + public Appender dumpFormula(BooleanFormula pT) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) + throws InterruptedException, SolverException { + throw new UnsupportedOperationException(); + } + + @Override + public T simplify(T input) throws InterruptedException { + throw new UnsupportedOperationException(); + } + + @Override + public R visit(Formula f, FormulaVisitor rFormulaVisitor) { + throw new UnsupportedOperationException(); + } + + @Override + public void visitRecursively(Formula f, FormulaVisitor rFormulaVisitor) { + throw new UnsupportedOperationException(); + } + + @Override + public T transformRecursively( + T f, FormulaTransformationVisitor pFormulaVisitor) { + throw new UnsupportedOperationException(); + } + + @Override + public ImmutableMap extractVariables(Formula f) { + // FIXME Add proper tracing + return delegate.extractVariables(f); + } + + @Override + public ImmutableMap extractVariablesAndUFs(Formula f) { + throw new UnsupportedOperationException(); + } + + @Override + public T substitute( + T f, Map fromToMapping) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula translateFrom(BooleanFormula formula, FormulaManager otherManager) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isValidName(String variableName) { + throw new UnsupportedOperationException(); + } + + @Override + public String escape(String variableName) { + throw new UnsupportedOperationException(); + } + + @Override + public String unescape(String variableName) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java new file mode 100644 index 0000000000..338132499b --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -0,0 +1,198 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; +import org.sosy_lab.common.rationals.Rational; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.IntegerFormulaManager; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; + +public class TraceIntegerFormulaManager implements IntegerFormulaManager { + private final IntegerFormulaManager delegate; + private final TraceLogger logger; + + TraceIntegerFormulaManager(IntegerFormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public BooleanFormula modularCongruence( + IntegerFormula number1, IntegerFormula number2, BigInteger n) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "modularCongruence(%s, %s, new BigInteger(\"%s\"))", + logger.toVariable(number1), logger.toVariable(number2), n), + () -> delegate.modularCongruence(number1, number2, n)); + } + + @Override + public BooleanFormula modularCongruence(IntegerFormula number1, IntegerFormula number2, long n) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "modularCongruence(%s, %s, %s)", + logger.toVariable(number1), logger.toVariable(number2), n), + () -> delegate.modularCongruence(number1, number2, n)); + } + + @Override + public IntegerFormula modulo(IntegerFormula numerator, IntegerFormula denominator) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula makeNumber(long number) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(%s)", number), + () -> delegate.makeNumber(number)); + } + + @Override + public IntegerFormula makeNumber(BigInteger number) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(new BigInteger(\"%s\"))", number), + () -> delegate.makeNumber(number)); + } + + @Override + public IntegerFormula makeNumber(double number) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula makeNumber(BigDecimal number) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula makeNumber(String pI) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula makeNumber(Rational pRational) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula makeVariable(String pVar) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeVariable(\"%s\")", pVar), + () -> delegate.makeVariable(pVar)); + } + + @Override + public IntegerFormula negate(IntegerFormula number) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("negate(%s)", logger.toVariable(number)), + () -> delegate.negate(number)); + } + + @Override + public IntegerFormula add(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.add(number1, number2)); + } + + @Override + public IntegerFormula sum(List operands) { + throw new UnsupportedOperationException(); + } + + @Override + public IntegerFormula subtract(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.subtract(number1, number2)); + } + + @Override + public IntegerFormula divide(IntegerFormula numerator, IntegerFormula denominator) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "divide(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), + () -> delegate.divide(numerator, denominator)); + } + + @Override + public IntegerFormula multiply(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.multiply(number1, number2)); + } + + @Override + public BooleanFormula equal(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("equal(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.equal(number1, number2)); + } + + @Override + public BooleanFormula distinct(List pNumbers) { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula greaterThan(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "greaterThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.greaterThan(number1, number2)); + } + + @Override + public BooleanFormula greaterOrEquals(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "greaterOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.greaterOrEquals(number1, number2)); + } + + @Override + public BooleanFormula lessThan(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("lessThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.lessThan(number1, number2)); + } + + @Override + public BooleanFormula lessOrEquals(IntegerFormula number1, IntegerFormula number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "lessOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.lessOrEquals(number1, number2)); + } + + @Override + public IntegerFormula floor(IntegerFormula formula) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java new file mode 100644 index 0000000000..c8d28776f8 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -0,0 +1,105 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import com.google.common.base.Joiner; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaType; + +public class TraceLogger { + private long id = 0; + + private final Map valueMap = new HashMap<>(); + private final List trace = new ArrayList<>(); + + /** Returns a fresh variable */ + private String newVariable() { + return "var" + id++; + } + + /** + * Bind an object to a variable + * + *

Use {@link #toVariable(Object)} to get the variable name for a tracked object + */ + private void mapVariable(String pVar, Object f) { + valueMap.putIfAbsent(f, pVar); + } + + /** + * Returns the variable name of a tracked object + * + *

Use {@link #mapVariable(String, Object)} to bind an object to a variable + */ + public String toVariable(Object f) { + return valueMap.get(f); + } + + /** Add a definition to the log */ + private void appendDef(String pVar, String pExpr) { + trace.add(String.format("var %s = %s;", pVar, pExpr)); + } + + /** Add a statement to the log */ + private void appendStmt(String pStmt) { + trace.add(String.format("%s;", pStmt)); + } + + /** Log an API call with return value */ + public TE logDef(String prefix, String method, Callable closure) { + String var = newVariable(); + appendDef(var, prefix + "." + method); + try { + TE f = closure.call(); + mapVariable(var, f); + return f; + + } catch (Exception pE) { + throw new RuntimeException(pE); + } + } + + /** Just like {@link Runnable}, but allows checked exceptions */ + public interface CheckedRunnable { + void run() throws Exception; + } + + /** Log an API call without return value */ + public void logStmt(String prefix, String method, CheckedRunnable closure) { + appendStmt(prefix + "." + method); + try { + closure.run(); + } catch (Exception pE) { + throw new RuntimeException(pE); + } + } + + /** + * Takes a {@link org.sosy_lab.java_smt.api.FormulaType} and returns a Java expression to + * construct this type + */ + public String printFormulaType(FormulaType pType) { + if (pType.isIntegerType()) { + return "FormulaType.IntegerType"; + } + // FIXME Handle other cases + throw new IllegalArgumentException("Unsupported formula type: " + pType); + } + + public String getLog() { + return Joiner.on('\n').join(trace); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java new file mode 100644 index 0000000000..ed8240ce0f --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java @@ -0,0 +1,92 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.Model; +import org.sosy_lab.java_smt.api.ProverEnvironment; +import org.sosy_lab.java_smt.api.SolverException; + +public class TraceProverEnvironment implements ProverEnvironment { + private final ProverEnvironment delegate; + private final TraceLogger logger; + + TraceProverEnvironment(ProverEnvironment pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public void pop() { + logger.logStmt(logger.toVariable(this), "pop()", delegate::pop); + } + + @Override + public @Nullable Void addConstraint(BooleanFormula constraint) throws InterruptedException { + return logger.logDef( + logger.toVariable(this), + String.format("addConstraint(%s)", logger.toVariable(constraint)), + () -> delegate.addConstraint(constraint)); + } + + @Override + public void push() throws InterruptedException { + logger.logStmt(logger.toVariable(this), "push()", delegate::push); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isUnsat() throws SolverException, InterruptedException { + return logger.logDef(logger.toVariable(this), "isUnsat()", delegate::isUnsat); + } + + @Override + public boolean isUnsatWithAssumptions(Collection assumptions) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException(); + } + + @Override + public Model getModel() throws SolverException { + // FIXME Add tracing for the model + return logger.logDef(logger.toVariable(this), "getModel()", delegate::getModel); + } + + @Override + public List getUnsatCore() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional> unsatCoreOverAssumptions( + Collection assumptions) throws SolverException, InterruptedException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() { + logger.logStmt(logger.toVariable(this), "close()", delegate::close); + } + + @Override + public R allSat(AllSatCallback callback, List important) + throws InterruptedException, SolverException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java new file mode 100644 index 0000000000..984f508287 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -0,0 +1,69 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + + +import org.sosy_lab.java_smt.SolverContextFactory.Solvers; +import org.sosy_lab.java_smt.api.FormulaManager; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; +import org.sosy_lab.java_smt.api.OptimizationProverEnvironment; +import org.sosy_lab.java_smt.api.ProverEnvironment; +import org.sosy_lab.java_smt.api.SolverContext; + +public class TraceSolverContext implements SolverContext { + private final SolverContext delegate; + private final TraceLogger logger; + + public TraceSolverContext(SolverContext pDelegate) { + + delegate = pDelegate; + logger = new TraceLogger(); + } + + @Override + public FormulaManager getFormulaManager() { + return new TraceFormulaManager(delegate.getFormulaManager(), logger); + } + + @SuppressWarnings("resource") + @Override + public ProverEnvironment newProverEnvironment(ProverOptions... options) { + return new TraceProverEnvironment(delegate.newProverEnvironment(options), logger); + } + + @SuppressWarnings("resource") + @Override + public InterpolatingProverEnvironment newProverEnvironmentWithInterpolation( + ProverOptions... options) { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("resource") + @Override + public OptimizationProverEnvironment newOptimizationProverEnvironment(ProverOptions... options) { + throw new UnsupportedOperationException(); + } + + @Override + public String getVersion() { + return delegate.getVersion(); + } + + @Override + public Solvers getSolverName() { + return delegate.getSolverName(); + } + + @Override + public void close() { + delegate.close(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java new file mode 100644 index 0000000000..835ab82103 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -0,0 +1,78 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; +import java.util.Arrays; +import java.util.List; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.FunctionDeclaration; +import org.sosy_lab.java_smt.api.UFManager; + +public class TraceUFManager implements UFManager { + private final UFManager delegate; + private final TraceLogger logger; + + TraceUFManager(UFManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public FunctionDeclaration declareUF( + String name, FormulaType returnType, List> args) { + return logger.logDef( + "mgr.getUFManager()", + String.format( + "declareUF(\"%s\", %s, ImmutableList.of(%s))", + name, + logger.printFormulaType(returnType), + Joiner.on(", ").join(FluentIterable.from(args).transform(logger::printFormulaType))), + () -> delegate.declareUF(name, returnType, args)); + } + + @Override + public FunctionDeclaration declareUF( + String name, FormulaType returnType, FormulaType... args) { + return declareUF(name, returnType, Arrays.asList(args)); + } + + @Override + public T callUF( + FunctionDeclaration funcType, List args) { + return logger.logDef( + "mgr.getUFManager()", + String.format( + "callUF(%s, ImmutableList.of(%s))", + logger.toVariable(funcType), + Joiner.on(", ").join(FluentIterable.from(args).transform(logger::toVariable))), + () -> delegate.callUF(funcType, args)); + } + + @Override + public T callUF(FunctionDeclaration funcType, Formula... args) { + return callUF(funcType, Arrays.asList(args)); + } + + @Override + public T declareAndCallUF( + String name, FormulaType pReturnType, List pArgs) { + throw new UnsupportedOperationException(); + } + + @Override + public T declareAndCallUF( + String name, FormulaType pReturnType, Formula... pArgs) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/package-info.java b/src/org/sosy_lab/java_smt/delegate/trace/package-info.java new file mode 100644 index 0000000000..1b69a33f5b --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/package-info.java @@ -0,0 +1,15 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +@com.google.errorprone.annotations.CheckReturnValue +@javax.annotation.ParametersAreNonnullByDefault +@org.sosy_lab.common.annotations.FieldsAreNonnullByDefault +@org.sosy_lab.common.annotations.ReturnValuesAreNonnullByDefault +package org.sosy_lab.java_smt.delegate.trace; From f7ef298d26c4e1acf01beefc8ff564849c0a26ab Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 14 Aug 2025 13:46:29 +0200 Subject: [PATCH 002/233] Trace: Apply error-prone patch --- src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 835ab82103..a01af0a494 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -37,7 +37,7 @@ public FunctionDeclaration declareUF( "declareUF(\"%s\", %s, ImmutableList.of(%s))", name, logger.printFormulaType(returnType), - Joiner.on(", ").join(FluentIterable.from(args).transform(logger::printFormulaType))), + FluentIterable.from(args).transform(logger::printFormulaType).join(Joiner.on(", "))), () -> delegate.declareUF(name, returnType, args)); } @@ -55,7 +55,7 @@ public T callUF( String.format( "callUF(%s, ImmutableList.of(%s))", logger.toVariable(funcType), - Joiner.on(", ").join(FluentIterable.from(args).transform(logger::toVariable))), + FluentIterable.from(args).transform(logger::toVariable).join(Joiner.on(", "))), () -> delegate.callUF(funcType, args)); } From 9acb1d78c8b7409f7dd40d98724062403dfb1aae Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 14 Aug 2025 13:59:09 +0200 Subject: [PATCH 003/233] Trace: Fix checkstyle issues --- .../trace/TraceArrayFormulaManager.java | 1 + .../java_smt/delegate/trace/TraceLogger.java | 30 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java index 24ee2c74b4..951f671900 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java @@ -16,6 +16,7 @@ import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; +@SuppressWarnings("MethodTypeParameterName") public class TraceArrayFormulaManager implements ArrayFormulaManager { private final ArrayFormulaManager delegate; private final TraceLogger logger; diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index c8d28776f8..c80a0c2e42 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -25,13 +25,13 @@ public class TraceLogger { private final Map valueMap = new HashMap<>(); private final List trace = new ArrayList<>(); - /** Returns a fresh variable */ + /** Returns a fresh variable. */ private String newVariable() { return "var" + id++; } /** - * Bind an object to a variable + * Bind an object to a variable. * *

Use {@link #toVariable(Object)} to get the variable name for a tracked object */ @@ -40,7 +40,7 @@ private void mapVariable(String pVar, Object f) { } /** - * Returns the variable name of a tracked object + * Returns the variable name of a tracked object. * *

Use {@link #mapVariable(String, Object)} to bind an object to a variable */ @@ -48,48 +48,48 @@ public String toVariable(Object f) { return valueMap.get(f); } - /** Add a definition to the log */ + /** Add a definition to the log. */ private void appendDef(String pVar, String pExpr) { trace.add(String.format("var %s = %s;", pVar, pExpr)); } - /** Add a statement to the log */ + /** Add a statement to the log. */ private void appendStmt(String pStmt) { trace.add(String.format("%s;", pStmt)); } - /** Log an API call with return value */ - public TE logDef(String prefix, String method, Callable closure) { + /** Log an API call with return value. */ + public R logDef(String prefix, String method, Callable closure) { String var = newVariable(); appendDef(var, prefix + "." + method); try { - TE f = closure.call(); + R f = closure.call(); mapVariable(var, f); return f; - } catch (Exception pE) { - throw new RuntimeException(pE); + } catch (Exception e) { + throw new RuntimeException(e); } } - /** Just like {@link Runnable}, but allows checked exceptions */ + /** Just like {@link Runnable}, but allows checked exceptions. */ public interface CheckedRunnable { void run() throws Exception; } - /** Log an API call without return value */ + /** Log an API call without return value. */ public void logStmt(String prefix, String method, CheckedRunnable closure) { appendStmt(prefix + "." + method); try { closure.run(); - } catch (Exception pE) { - throw new RuntimeException(pE); + } catch (Exception e) { + throw new RuntimeException(e); } } /** * Takes a {@link org.sosy_lab.java_smt.api.FormulaType} and returns a Java expression to - * construct this type + * construct this type. */ public String printFormulaType(FormulaType pType) { if (pType.isIntegerType()) { From 63f28641321737ee83aef671b103200a42152cc6 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 14 Aug 2025 14:42:42 +0200 Subject: [PATCH 004/233] Trace: Log prover creation --- .../java_smt/delegate/trace/TraceSolverContext.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 984f508287..0f686d7799 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -10,7 +10,8 @@ package org.sosy_lab.java_smt.delegate.trace; - +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; @@ -36,7 +37,12 @@ public FormulaManager getFormulaManager() { @SuppressWarnings("resource") @Override public ProverEnvironment newProverEnvironment(ProverOptions... options) { - return new TraceProverEnvironment(delegate.newProverEnvironment(options), logger); + return logger.logDef( + "context", + String.format( + "newProverEnvironment(%s)", + Joiner.on(", ").join(FluentIterable.from(options).transform(Enum::toString))), + () -> new TraceProverEnvironment(delegate.newProverEnvironment(options), logger)); } @SuppressWarnings("resource") @@ -64,6 +70,6 @@ public Solvers getSolverName() { @Override public void close() { - delegate.close(); + logger.logStmt("context", "close()", delegate::close); } } From 0b0e604091219e4fbbedd72cba1c54cd8b99ef66 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 11:24:28 +0200 Subject: [PATCH 005/233] Trace: Write trace directly to a file --- .../java_smt/delegate/trace/TraceLogger.java | 37 ++++++++++++------- .../delegate/trace/TraceSolverContext.java | 6 ++- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index c80a0c2e42..f484a8eaeb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -10,10 +10,12 @@ package org.sosy_lab.java_smt.delegate.trace; -import com.google.common.base.Joiner; -import java.util.ArrayList; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import org.sosy_lab.java_smt.api.Formula; @@ -23,7 +25,16 @@ public class TraceLogger { private long id = 0; private final Map valueMap = new HashMap<>(); - private final List trace = new ArrayList<>(); + private final BufferedWriter output; + + TraceLogger(String pFile) { + // FIXME Check if the file already exists + try { + output = Files.newBufferedWriter(Paths.get(pFile), Charset.defaultCharset()); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } /** Returns a fresh variable. */ private String newVariable() { @@ -49,20 +60,22 @@ public String toVariable(Object f) { } /** Add a definition to the log. */ - private void appendDef(String pVar, String pExpr) { - trace.add(String.format("var %s = %s;", pVar, pExpr)); + private void appendDef(String pVar, String pExpr) throws IOException { + output.append(String.format("var %s = %s;%n", pVar, pExpr)); + output.flush(); } /** Add a statement to the log. */ - private void appendStmt(String pStmt) { - trace.add(String.format("%s;", pStmt)); + private void appendStmt(String pStmt) throws IOException { + output.append(String.format("%s;%n", pStmt)); + output.flush(); } /** Log an API call with return value. */ public R logDef(String prefix, String method, Callable closure) { String var = newVariable(); - appendDef(var, prefix + "." + method); try { + appendDef(var, prefix + "." + method); R f = closure.call(); mapVariable(var, f); return f; @@ -79,8 +92,8 @@ public interface CheckedRunnable { /** Log an API call without return value. */ public void logStmt(String prefix, String method, CheckedRunnable closure) { - appendStmt(prefix + "." + method); try { + appendStmt(prefix + "." + method); closure.run(); } catch (Exception e) { throw new RuntimeException(e); @@ -98,8 +111,4 @@ public String printFormulaType(FormulaType pType) { // FIXME Handle other cases throw new IllegalArgumentException("Unsupported formula type: " + pType); } - - public String getLog() { - return Joiner.on('\n').join(trace); - } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 0f686d7799..75fddc4f09 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -24,9 +24,11 @@ public class TraceSolverContext implements SolverContext { private final TraceLogger logger; public TraceSolverContext(SolverContext pDelegate) { - delegate = pDelegate; - logger = new TraceLogger(); + // FIXME Move the files to the output folder? + logger = + new TraceLogger( + "trace" + Integer.toUnsignedString(System.identityHashCode(this)) + ".java"); } @Override From 4080a59b438c87ef058bedc7211ea44268bdf0eb Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 12:50:03 +0200 Subject: [PATCH 006/233] Trace: Fix prefix in ArrayFormulaManager.equivalence --- .../java_smt/delegate/trace/TraceArrayFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java index 951f671900..d641eea34f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java @@ -75,7 +75,7 @@ ArrayFormula makeArray(FTI pIndexType, FTE pElementType, TE defaultEleme public BooleanFormula equivalence( ArrayFormula pArray1, ArrayFormula pArray2) { return logger.logDef( - "mgr.getArrayFormulaManager", + "mgr.getArrayFormulaManager()", String.format( "equivalence(%s, %s)", logger.toVariable(pArray1), logger.toVariable(pArray2)), () -> delegate.equivalence(pArray1, pArray2)); From 40d81d2ef95227a85548e58d11ac53721d59e79b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 13:07:08 +0200 Subject: [PATCH 007/233] Trace: Use full path when printing ProverOptions in the trace --- .../sosy_lab/java_smt/delegate/trace/TraceSolverContext.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 75fddc4f09..41f9c3038d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -43,7 +43,10 @@ public ProverEnvironment newProverEnvironment(ProverOptions... options) { "context", String.format( "newProverEnvironment(%s)", - Joiner.on(", ").join(FluentIterable.from(options).transform(Enum::toString))), + Joiner.on(", ") + .join( + FluentIterable.from(options) + .transform(v -> "SolverContext" + ".ProverOptions." + v.name()))), () -> new TraceProverEnvironment(delegate.newProverEnvironment(options), logger)); } From 84c71434a90b76049f82348ce8724ba16b9cfd74 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 13:07:40 +0200 Subject: [PATCH 008/233] Trace: Log creation of the solver context --- .../java_smt/SolverContextFactory.java | 2 +- .../java_smt/delegate/trace/TraceLogger.java | 4 +- .../delegate/trace/TraceSolverContext.java | 41 ++++++++++++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/SolverContextFactory.java b/src/org/sosy_lab/java_smt/SolverContextFactory.java index b5aa969e8c..8d9cc34dfb 100644 --- a/src/org/sosy_lab/java_smt/SolverContextFactory.java +++ b/src/org/sosy_lab/java_smt/SolverContextFactory.java @@ -237,7 +237,7 @@ public SolverContext generateContext(Solvers solverToCreate) context = new DebuggingSolverContext(solverToCreate, config, context); } if (trace) { - context = new TraceSolverContext(context); + context = new TraceSolverContext(context, config); } if (collectStatistics) { // statistics need to be the most outer wrapping layer. diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index f484a8eaeb..f4fd504975 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -60,13 +60,13 @@ public String toVariable(Object f) { } /** Add a definition to the log. */ - private void appendDef(String pVar, String pExpr) throws IOException { + public void appendDef(String pVar, String pExpr) throws IOException { output.append(String.format("var %s = %s;%n", pVar, pExpr)); output.flush(); } /** Add a statement to the log. */ - private void appendStmt(String pStmt) throws IOException { + public void appendStmt(String pStmt) throws IOException { output.append(String.format("%s;%n", pStmt)); output.flush(); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 41f9c3038d..80c06bca35 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -11,7 +11,13 @@ package org.sosy_lab.java_smt.delegate.trace; import com.google.common.base.Joiner; +import com.google.common.base.Splitter; import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableMap; +import java.io.IOException; +import java.util.List; +import java.util.Map.Entry; +import org.sosy_lab.common.configuration.Configuration; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; @@ -23,12 +29,45 @@ public class TraceSolverContext implements SolverContext { private final SolverContext delegate; private final TraceLogger logger; - public TraceSolverContext(SolverContext pDelegate) { + public TraceSolverContext(SolverContext pDelegate, Configuration config) { delegate = pDelegate; // FIXME Move the files to the output folder? logger = new TraceLogger( "trace" + Integer.toUnsignedString(System.identityHashCode(this)) + ".java"); + + // Get relevant options from the configuration + String props = config.asPropertiesString(); + ImmutableMap.Builder options = ImmutableMap.builder(); + for (String s : props.lines().toArray(String[]::new)) { + List parts = Splitter.on(" = ").splitToList(s); + ; + if (parts.get(0).startsWith("solver") && !parts.get(0).equals("solver.trace")) { + options.put(parts.get(0), parts.get(1)); + } + } + + // Write code for creating a solver context to the trace log + try { + logger.appendDef( + "config", + "Configuration.builder()." + + Joiner.on(".") + .join( + FluentIterable.from(options.build().entrySet()) + .transform( + (Entry e) -> + String.format( + "setOption(\"%s\", \"%s\")", e.getKey(), e.getValue()))) + + ".build()"); + logger.appendDef("logger", "LogManager.createNullLogManager()"); + logger.appendDef("notifier", "ShutdownNotifier.createDummy()"); + logger.appendDef( + "context", "SolverContextFactory.createSolverContext(config, logger, notifier)"); + logger.appendDef("mgr", "context.getFormulaManager()"); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override From 28575ebb9212fc1d504ad8d2bb93a1a26d32fb4b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 13:36:01 +0200 Subject: [PATCH 009/233] Trace: Log access to the model --- .../java_smt/delegate/trace/TraceModel.java | 120 ++++++++++++++++++ .../trace/TraceProverEnvironment.java | 4 +- 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java new file mode 100644 index 0000000000..6b6cc1e123 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java @@ -0,0 +1,120 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import com.google.common.collect.ImmutableList; +import java.math.BigInteger; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.sosy_lab.common.rationals.Rational; +import org.sosy_lab.java_smt.api.BitvectorFormula; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.EnumerationFormula; +import org.sosy_lab.java_smt.api.FloatingPointFormula; +import org.sosy_lab.java_smt.api.FloatingPointNumber; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.Model; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; +import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula; +import org.sosy_lab.java_smt.api.StringFormula; + +public class TraceModel implements Model { + private final Model delegate; + private final TraceLogger logger; + + TraceModel(Model pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public ImmutableList asList() { + // FIXME We need to introduce local variables for all terms in the model so that they can be + // referenced later + return logger.logDef(logger.toVariable(this), "asList()", delegate::asList); + } + + @Override + public @Nullable T eval(T formula) { + return logger.logDef( + logger.toVariable(this), + String.format("eval(%s)", logger.toVariable(formula)), + () -> delegate.eval(formula)); + } + + @Override + public @Nullable Object evaluate(Formula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable BigInteger evaluate(IntegerFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable Rational evaluate(RationalFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable Boolean evaluate(BooleanFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable BigInteger evaluate(BitvectorFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable String evaluate(StringFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable String evaluate(EnumerationFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public @Nullable FloatingPointNumber evaluate(FloatingPointFormula formula) { + return logger.logDef( + logger.toVariable(this), + String.format("evaluate(%s)", logger.toVariable(formula)), + () -> delegate.evaluate(formula)); + } + + @Override + public void close() { + logger.logStmt(logger.toVariable(this), "close()", delegate::close); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java index ed8240ce0f..64ac1d39f4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java @@ -64,8 +64,8 @@ public boolean isUnsatWithAssumptions(Collection assumptions) @Override public Model getModel() throws SolverException { - // FIXME Add tracing for the model - return logger.logDef(logger.toVariable(this), "getModel()", delegate::getModel); + return logger.logDef( + logger.toVariable(this), "getModel()", () -> new TraceModel(delegate.getModel(), logger)); } @Override From e7dfc700f747390e014bc2a2a50499206085e9e0 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 13:50:54 +0200 Subject: [PATCH 010/233] Trace: Apply error-prone patch --- .../java_smt/delegate/trace/TraceLogger.java | 4 ++-- .../delegate/trace/TraceSolverContext.java | 19 ++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index f4fd504975..bfbe53da3e 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -14,7 +14,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; @@ -30,7 +30,7 @@ public class TraceLogger { TraceLogger(String pFile) { // FIXME Check if the file already exists try { - output = Files.newBufferedWriter(Paths.get(pFile), Charset.defaultCharset()); + output = Files.newBufferedWriter(Path.of(pFile), Charset.defaultCharset()); } catch (IOException e) { throw new IllegalArgumentException(e); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 80c06bca35..f3ae08abd4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -52,13 +52,11 @@ public TraceSolverContext(SolverContext pDelegate, Configuration config) { logger.appendDef( "config", "Configuration.builder()." - + Joiner.on(".") - .join( - FluentIterable.from(options.build().entrySet()) - .transform( - (Entry e) -> - String.format( - "setOption(\"%s\", \"%s\")", e.getKey(), e.getValue()))) + + FluentIterable.from(options.build().entrySet()) + .transform( + (Entry e) -> + String.format("setOption(\"%s\", \"%s\")", e.getKey(), e.getValue())) + .join(Joiner.on(".")) + ".build()"); logger.appendDef("logger", "LogManager.createNullLogManager()"); logger.appendDef("notifier", "ShutdownNotifier.createDummy()"); @@ -82,10 +80,9 @@ public ProverEnvironment newProverEnvironment(ProverOptions... options) { "context", String.format( "newProverEnvironment(%s)", - Joiner.on(", ") - .join( - FluentIterable.from(options) - .transform(v -> "SolverContext" + ".ProverOptions." + v.name()))), + FluentIterable.from(options) + .transform(v -> "SolverContext" + ".ProverOptions." + v.name()) + .join(Joiner.on(", "))), () -> new TraceProverEnvironment(delegate.newProverEnvironment(options), logger)); } From 010fb1e3741655958a0a9d82a50bf907fc7c7831 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 13:52:26 +0200 Subject: [PATCH 011/233] Trace: Remove ; --- src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index f3ae08abd4..fa5b5a7122 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -41,7 +41,6 @@ public TraceSolverContext(SolverContext pDelegate, Configuration config) { ImmutableMap.Builder options = ImmutableMap.builder(); for (String s : props.lines().toArray(String[]::new)) { List parts = Splitter.on(" = ").splitToList(s); - ; if (parts.get(0).startsWith("solver") && !parts.get(0).equals("solver.trace")) { options.put(parts.get(0), parts.get(1)); } From 8ac6c0cf9fc9291b2c613fc213e5b08c365c6895 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 13:58:17 +0200 Subject: [PATCH 012/233] Trace: Add "resource" annotation for TraceModel.getModel --- .../sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java index 64ac1d39f4..ab5abb2992 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java @@ -62,6 +62,7 @@ public boolean isUnsatWithAssumptions(Collection assumptions) throw new UnsupportedOperationException(); } + @SuppressWarnings("resource") @Override public Model getModel() throws SolverException { return logger.logDef( From d2958ed154cf6008186e2494e56e131a6ebf10b8 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 14:04:36 +0200 Subject: [PATCH 013/233] Trace: Add a superclass TraceBasicProverEnvironment for TraceProverEnvironment (and later TraceInterpolatingProverEnvironment) --- .../trace/TraceBasicProverEnvironment.java | 93 +++++++++++++++++++ .../trace/TraceProverEnvironment.java | 82 +--------------- 2 files changed, 98 insertions(+), 77 deletions(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java new file mode 100644 index 0000000000..dfcb804b96 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -0,0 +1,93 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.sosy_lab.java_smt.api.BasicProverEnvironment; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.Model; +import org.sosy_lab.java_smt.api.SolverException; + +public class TraceBasicProverEnvironment implements BasicProverEnvironment { + private final BasicProverEnvironment delegate; + private final TraceLogger logger; + + TraceBasicProverEnvironment(BasicProverEnvironment pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public void pop() { + logger.logStmt(logger.toVariable(this), "pop()", delegate::pop); + } + + @Override + public @Nullable T addConstraint(BooleanFormula constraint) throws InterruptedException { + return logger.logDef( + logger.toVariable(this), + String.format("addConstraint(%s)", logger.toVariable(constraint)), + () -> delegate.addConstraint(constraint)); + } + + @Override + public void push() throws InterruptedException { + logger.logStmt(logger.toVariable(this), "push()", delegate::push); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isUnsat() throws SolverException, InterruptedException { + return logger.logDef(logger.toVariable(this), "isUnsat()", delegate::isUnsat); + } + + @Override + public boolean isUnsatWithAssumptions(Collection assumptions) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("resource") + @Override + public Model getModel() throws SolverException { + return logger.logDef( + logger.toVariable(this), "getModel()", () -> new TraceModel(delegate.getModel(), logger)); + } + + @Override + public List getUnsatCore() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional> unsatCoreOverAssumptions( + Collection assumptions) throws SolverException, InterruptedException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() { + logger.logStmt(logger.toVariable(this), "close()", delegate::close); + } + + @Override + public R allSat(AllSatCallback callback, List important) + throws InterruptedException, SolverException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java index ab5abb2992..d8c1e79ef6 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java @@ -10,84 +10,12 @@ package org.sosy_lab.java_smt.delegate.trace; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.sosy_lab.java_smt.api.BooleanFormula; -import org.sosy_lab.java_smt.api.Model; +import org.sosy_lab.java_smt.api.BasicProverEnvironment; import org.sosy_lab.java_smt.api.ProverEnvironment; -import org.sosy_lab.java_smt.api.SolverException; -public class TraceProverEnvironment implements ProverEnvironment { - private final ProverEnvironment delegate; - private final TraceLogger logger; - - TraceProverEnvironment(ProverEnvironment pDelegate, TraceLogger pLogger) { - delegate = pDelegate; - logger = pLogger; - } - - @Override - public void pop() { - logger.logStmt(logger.toVariable(this), "pop()", delegate::pop); - } - - @Override - public @Nullable Void addConstraint(BooleanFormula constraint) throws InterruptedException { - return logger.logDef( - logger.toVariable(this), - String.format("addConstraint(%s)", logger.toVariable(constraint)), - () -> delegate.addConstraint(constraint)); - } - - @Override - public void push() throws InterruptedException { - logger.logStmt(logger.toVariable(this), "push()", delegate::push); - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public boolean isUnsat() throws SolverException, InterruptedException { - return logger.logDef(logger.toVariable(this), "isUnsat()", delegate::isUnsat); - } - - @Override - public boolean isUnsatWithAssumptions(Collection assumptions) - throws SolverException, InterruptedException { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("resource") - @Override - public Model getModel() throws SolverException { - return logger.logDef( - logger.toVariable(this), "getModel()", () -> new TraceModel(delegate.getModel(), logger)); - } - - @Override - public List getUnsatCore() { - throw new UnsupportedOperationException(); - } - - @Override - public Optional> unsatCoreOverAssumptions( - Collection assumptions) throws SolverException, InterruptedException { - throw new UnsupportedOperationException(); - } - - @Override - public void close() { - logger.logStmt(logger.toVariable(this), "close()", delegate::close); - } - - @Override - public R allSat(AllSatCallback callback, List important) - throws InterruptedException, SolverException { - throw new UnsupportedOperationException(); +public class TraceProverEnvironment extends TraceBasicProverEnvironment + implements ProverEnvironment { + TraceProverEnvironment(BasicProverEnvironment pDelegate, TraceLogger pLogger) { + super(pDelegate, pLogger); } } From fb252cdddd6f307f37727101476a7802323fd6c7 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 15 Aug 2025 14:26:30 +0200 Subject: [PATCH 014/233] Trace: Apply error-prone patch --- .../sosy_lab/java_smt/delegate/trace/TraceSolverContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index fa5b5a7122..38bac71956 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -51,7 +51,7 @@ public TraceSolverContext(SolverContext pDelegate, Configuration config) { logger.appendDef( "config", "Configuration.builder()." - + FluentIterable.from(options.build().entrySet()) + + FluentIterable.from(options.buildOrThrow().entrySet()) .transform( (Entry e) -> String.format("setOption(\"%s\", \"%s\")", e.getKey(), e.getValue())) From fef163534d0793a39cd424bdbc5a30b14ad1b05e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 19 Aug 2025 12:46:23 +0200 Subject: [PATCH 015/233] Trace: Add bitvector support --- .../trace/TraceBitvectorFormulaManager.java | 189 +++++++++++++++--- .../delegate/trace/TraceFormulaManager.java | 2 +- .../java_smt/delegate/trace/TraceLogger.java | 5 + 3 files changed, 162 insertions(+), 34 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java index db5c044a2f..a247ec978b 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -10,6 +10,8 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; import java.math.BigInteger; import java.util.List; import org.sosy_lab.java_smt.api.BitvectorFormula; @@ -19,176 +21,297 @@ import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; public class TraceBitvectorFormulaManager implements BitvectorFormulaManager { + private final BitvectorFormulaManager delegate; + private final TraceLogger logger; + + TraceBitvectorFormulaManager(BitvectorFormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } @Override public BitvectorFormula makeBitvector(int length, long pI) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("makeBitvector(%s, %s)", length, pI), + () -> delegate.makeBitvector(length, pI)); } @Override public BitvectorFormula makeBitvector(int length, BigInteger pI) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("makeBitvector(%s, new BigInteger(\"%s\"))", length, pI), + () -> delegate.makeBitvector(length, pI)); } @Override public BitvectorFormula makeBitvector(int length, IntegerFormula pI) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("makeBitvector(%s, %s)", length, logger.toVariable(pI)), + () -> delegate.makeBitvector(length, pI)); } @Override public IntegerFormula toIntegerFormula(BitvectorFormula pI, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("toIntegerFormula(%s, %s)", logger.toVariable(pI), signed), + () -> delegate.toIntegerFormula(pI, signed)); } @Override public BitvectorFormula makeVariable(int length, String pVar) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("makeVariable(%s, \"%s\")", length, pVar), + () -> delegate.makeVariable(length, pVar)); } @Override public BitvectorFormula makeVariable(BitvectorType type, String pVar) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("makeVariable(%s, \"%s\")", logger.printFormulaType(type), pVar), + () -> delegate.makeVariable(type, pVar)); } @Override public int getLength(BitvectorFormula number) { - return 0; + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("getLength(%s)", logger.toVariable(number)), + () -> delegate.getLength(number)); } @Override public BitvectorFormula negate(BitvectorFormula number) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("negate(%s)", logger.toVariable(number)), + () -> delegate.negate(number)); } @Override public BitvectorFormula add(BitvectorFormula number1, BitvectorFormula number2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.add(number1, number2)); } @Override public BitvectorFormula subtract(BitvectorFormula number1, BitvectorFormula number2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.subtract(number1, number2)); } @Override public BitvectorFormula divide( BitvectorFormula dividend, BitvectorFormula divisor, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "divide(%s, %s, %s)", logger.toVariable(dividend), logger.toVariable(divisor), signed), + () -> delegate.divide(dividend, divisor, signed)); } @Override public BitvectorFormula smodulo(BitvectorFormula dividend, BitvectorFormula divisor) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("smodulo(%s, %s)", logger.toVariable(dividend), logger.toVariable(dividend)), + () -> delegate.smodulo(dividend, divisor)); } @Override public BitvectorFormula remainder( BitvectorFormula dividend, BitvectorFormula divisor, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "remainder(%s, %s, %s)", + logger.toVariable(dividend), logger.toVariable(divisor), signed), + () -> delegate.remainder(dividend, divisor, signed)); } @Override public BitvectorFormula multiply(BitvectorFormula number1, BitvectorFormula number2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.multiply(number1, number2)); } @Override public BooleanFormula equal(BitvectorFormula number1, BitvectorFormula number2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("equal(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.equal(number1, number2)); } @Override public BooleanFormula greaterThan( BitvectorFormula number1, BitvectorFormula number2, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "greaterThan(%s, %s, %s)", + logger.toVariable(number1), logger.toVariable(number2), signed), + () -> delegate.greaterThan(number1, number2, signed)); } @Override public BooleanFormula greaterOrEquals( BitvectorFormula number1, BitvectorFormula number2, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "greaterOrEquals(%s, %s, %s)", + logger.toVariable(number1), logger.toVariable(number2), signed), + () -> delegate.greaterOrEquals(number1, number2, signed)); } @Override public BooleanFormula lessThan( BitvectorFormula number1, BitvectorFormula number2, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "lessThan(%s, %s, %s)", logger.toVariable(number1), logger.toVariable(number2), signed), + () -> delegate.lessThan(number1, number2, signed)); } @Override public BooleanFormula lessOrEquals( BitvectorFormula number1, BitvectorFormula number2, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "lessOrEquals(%s, %s, %s)", + logger.toVariable(number1), logger.toVariable(number2), signed), + () -> delegate.lessOrEquals(number1, number2, signed)); } @Override public BitvectorFormula not(BitvectorFormula bits) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("not(%s)", logger.toVariable(bits)), + () -> delegate.not(bits)); } @Override public BitvectorFormula and(BitvectorFormula bits1, BitvectorFormula bits2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("and(%s, %s)", logger.toVariable(bits1), logger.toVariable(bits2)), + () -> delegate.and(bits1, bits2)); } @Override public BitvectorFormula or(BitvectorFormula bits1, BitvectorFormula bits2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("or(%s, %s)", logger.toVariable(bits1), logger.toVariable(bits2)), + () -> delegate.or(bits1, bits2)); } @Override public BitvectorFormula xor(BitvectorFormula bits1, BitvectorFormula bits2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("xor(%s, %s)", logger.toVariable(bits1), logger.toVariable(bits2)), + () -> delegate.xor(bits1, bits2)); } @Override public BitvectorFormula shiftRight( BitvectorFormula number, BitvectorFormula toShift, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "shiftRight(%s, %s, %s)", + logger.toVariable(number), logger.toVariable(toShift), signed), + () -> delegate.shiftRight(number, toShift, signed)); } @Override public BitvectorFormula shiftLeft(BitvectorFormula number, BitvectorFormula toShift) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("shiftLeft(%s, %s)", logger.toVariable(number), logger.toVariable(toShift)), + () -> delegate.shiftLeft(number, toShift)); } @Override public BitvectorFormula rotateLeft(BitvectorFormula number, int toRotate) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("rotateLeft(%s, %s)", logger.toVariable(number), toRotate), + () -> delegate.rotateLeft(number, toRotate)); } @Override public BitvectorFormula rotateLeft(BitvectorFormula number, BitvectorFormula toRotate) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("rotateLeft(%s, %s)", logger.toVariable(number), logger.toVariable(toRotate)), + () -> delegate.rotateLeft(number, toRotate)); } @Override public BitvectorFormula rotateRight(BitvectorFormula number, int toRotate) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("rotateRight(%s, %s)", logger.toVariable(number), toRotate), + () -> delegate.rotateRight(number, toRotate)); } @Override public BitvectorFormula rotateRight(BitvectorFormula number, BitvectorFormula toRotate) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "rotateRight(%s, %s)", logger.toVariable(number), logger.toVariable(toRotate)), + () -> delegate.rotateRight(number, toRotate)); } @Override public BitvectorFormula concat(BitvectorFormula prefix, BitvectorFormula suffix) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("concat(%s, %s)", logger.toVariable(prefix), logger.toVariable(prefix)), + () -> delegate.concat(prefix, suffix)); } @Override public BitvectorFormula extract(BitvectorFormula number, int msb, int lsb) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("extract(%s, %s, %s)", logger.toVariable(number), msb, lsb), + () -> delegate.extract(number, msb, lsb)); } @Override public BitvectorFormula extend(BitvectorFormula number, int extensionBits, boolean signed) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("extend(%s, %s, %s)", logger.toVariable(number), extensionBits, signed), + () -> delegate.extend(number, extensionBits, signed)); } @Override public BooleanFormula distinct(List pBits) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format( + "distinct(ImmutableList.of(%s))", + FluentIterable.from(pBits).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.distinct(pBits)); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 96a31cf520..63789f8a7c 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -68,7 +68,7 @@ public ArrayFormulaManager getArrayFormulaManager() { @Override public BitvectorFormulaManager getBitvectorFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceBitvectorFormulaManager(delegate.getBitvectorFormulaManager(), logger); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index bfbe53da3e..74178540ed 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -20,6 +20,7 @@ import java.util.concurrent.Callable; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; public class TraceLogger { private long id = 0; @@ -108,6 +109,10 @@ public String printFormulaType(FormulaType pType) { if (pType.isIntegerType()) { return "FormulaType.IntegerType"; } + if (pType.isBitvectorType()) { + BitvectorType bvType = (BitvectorType) pType; + return String.format("FormulaType.getBitvectorTypeWithSize(%s)", bvType.getSize()); + } // FIXME Handle other cases throw new IllegalArgumentException("Unsupported formula type: " + pType); } From cb7a7d27fc13094dd287765da07c9bf72fd3284b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 19 Aug 2025 14:03:08 +0200 Subject: [PATCH 016/233] Trace: Add floating point support --- .../TraceFloatingPointFormulaManager.java | 451 ++++++++++++++++++ .../delegate/trace/TraceFormulaManager.java | 2 +- .../java_smt/delegate/trace/TraceLogger.java | 7 + 3 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java new file mode 100644 index 0000000000..4d4746caff --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -0,0 +1,451 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.math.BigDecimal; +import java.math.BigInteger; +import org.sosy_lab.common.rationals.Rational; +import org.sosy_lab.java_smt.api.BitvectorFormula; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.FloatingPointFormula; +import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; +import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; +import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; + +public class TraceFloatingPointFormulaManager implements FloatingPointFormulaManager { + private final FloatingPointFormulaManager delegate; + private final TraceLogger logger; + + public TraceFloatingPointFormulaManager( + FloatingPointFormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public FloatingPointFormula makeNumber(double n, FloatingPointType type) { + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + private String printRoundingMode(FloatingPointRoundingMode pRoundingMode) { + return "FloatingPointRoundingMode." + pRoundingMode.name(); + } + + @Override + public FloatingPointFormula makeNumber( + double n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeNumber(%s, %s, %s)", + n, logger.printFormulaType(type), printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula makeNumber(BigDecimal n, FloatingPointType type) { + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_AWAY); + } + + @Override + public FloatingPointFormula makeNumber( + BigDecimal n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { + throw new UnsupportedOperationException(); + } + + @Override + public FloatingPointFormula makeNumber(String n, FloatingPointType type) { + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula makeNumber( + String n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeNumber(\"%s\", %s, %s)", + n, logger.printFormulaType(type), printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula makeNumber(Rational n, FloatingPointType type) { + throw new UnsupportedOperationException(); + } + + @Override + public FloatingPointFormula makeNumber( + Rational n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { + throw new UnsupportedOperationException(); + } + + private String printSign(Sign pSign) { + return "FloatingPointNumber.Sign." + pSign.name(); + } + + @Override + public FloatingPointFormula makeNumber( + BigInteger exponent, BigInteger mantissa, Sign sign, FloatingPointType type) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeNumber(new BigInteger(\"%s\"), new BigInteger(\"%s\"), %s, %s)", + exponent, mantissa, printSign(sign), logger.printFormulaType(type)), + () -> delegate.makeNumber(exponent, mantissa, sign, type)); + } + + @Override + public FloatingPointFormula makeVariable(String pVar, FloatingPointType type) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeVariable(\"%s\", %s)", pVar, logger.printFormulaType(type)), + () -> delegate.makeVariable(pVar, type)); + } + + @Override + public FloatingPointFormula makePlusInfinity(FloatingPointType type) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makePlusInfinity(%s)", logger.printFormulaType(type)), + () -> delegate.makePlusInfinity(type)); + } + + @Override + public FloatingPointFormula makeMinusInfinity(FloatingPointType type) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeMinusInfinity(%s)", logger.printFormulaType(type)), + () -> delegate.makeMinusInfinity(type)); + } + + @Override + public FloatingPointFormula makeNaN(FloatingPointType type) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeNaN(%s)", logger.printFormulaType(type)), + () -> delegate.makeNaN(type)); + } + + @Override + public T castTo( + FloatingPointFormula source, boolean signed, FormulaType targetType) { + return castTo(source, signed, targetType, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public T castTo( + FloatingPointFormula source, + boolean signed, + FormulaType targetType, + FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "castTo(%s, %s, %s, %s)", + logger.toVariable(source), + signed, + logger.printFormulaType(targetType), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.castTo(source, signed, targetType, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula castFrom( + Formula source, boolean signed, FloatingPointType targetType) { + return castFrom(source, signed, targetType, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula castFrom( + Formula source, + boolean signed, + FloatingPointType targetType, + FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "castFrom(%s, %s, %s, %s)", + logger.toVariable(source), + signed, + logger.printFormulaType(targetType), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.castFrom(source, signed, targetType, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula fromIeeeBitvector( + BitvectorFormula number, FloatingPointType pTargetType) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "fromIeeeBitvector(%s, %s)", + logger.toVariable(number), logger.printFormulaType(pTargetType)), + () -> delegate.fromIeeeBitvector(number, pTargetType)); + } + + @Override + public BitvectorFormula toIeeeBitvector(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("toIeeeBitvector(%s)", logger.toVariable(number)), + () -> delegate.toIeeeBitvector(number)); + } + + @Override + public FloatingPointFormula round( + FloatingPointFormula formula, FloatingPointRoundingMode roundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("round(%s, %s)", logger.toVariable(formula), printRoundingMode(roundingMode)), + () -> delegate.round(formula, roundingMode)); + } + + @Override + public FloatingPointFormula negate(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("negate(%s)", logger.toVariable(number)), + () -> delegate.negate(number)); + } + + @Override + public FloatingPointFormula abs(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("abs(%s)", logger.toVariable(number)), + () -> delegate.abs(number)); + } + + @Override + public FloatingPointFormula max(FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("max(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.max(number1, number2)); + } + + @Override + public FloatingPointFormula min(FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("min(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.min(number1, number2)); + } + + @Override + public FloatingPointFormula sqrt(FloatingPointFormula number) { + return sqrt(number, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula sqrt( + FloatingPointFormula number, FloatingPointRoundingMode roundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("sqrt(%s, %s)", logger.toVariable(number), printRoundingMode(roundingMode)), + () -> delegate.sqrt(number, roundingMode)); + } + + @Override + public FloatingPointFormula add(FloatingPointFormula number1, FloatingPointFormula number2) { + return add(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula add( + FloatingPointFormula number1, + FloatingPointFormula number2, + FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "add(%s, %s, %s)", + logger.toVariable(number1), + logger.toVariable(number2), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.add(number1, number2, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula subtract(FloatingPointFormula number1, FloatingPointFormula number2) { + return subtract(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula subtract( + FloatingPointFormula number1, + FloatingPointFormula number2, + FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "subtract(%s, %s, %s)", + logger.toVariable(number1), + logger.toVariable(number2), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.subtract(number1, number2, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula divide(FloatingPointFormula number1, FloatingPointFormula number2) { + return divide(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula divide( + FloatingPointFormula number1, + FloatingPointFormula number2, + FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "divide(%s, %s, %s)", + logger.toVariable(number1), + logger.toVariable(number2), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.divide(number1, number2, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula multiply(FloatingPointFormula number1, FloatingPointFormula number2) { + return multiply(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public FloatingPointFormula multiply( + FloatingPointFormula number1, + FloatingPointFormula number2, + FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "multiply(%s, %s, %s)", + logger.toVariable(number1), + logger.toVariable(number2), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.multiply(number1, number2, pFloatingPointRoundingMode)); + } + + @Override + public FloatingPointFormula remainder( + FloatingPointFormula dividend, FloatingPointFormula divisor) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("remainder(%s, %s)", logger.toVariable(dividend), logger.toVariable(divisor)), + () -> delegate.remainder(dividend, divisor)); + } + + @Override + public BooleanFormula assignment(FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("assignment(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.assignment(number1, number2)); + } + + @Override + public BooleanFormula equalWithFPSemantics( + FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "equalWithFPSemantics(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.equalWithFPSemantics(number1, number2)); + } + + @Override + public BooleanFormula greaterThan(FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "greaterThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.greaterThan(number1, number2)); + } + + @Override + public BooleanFormula greaterOrEquals( + FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "greaterOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.greaterOrEquals(number1, number2)); + } + + @Override + public BooleanFormula lessThan(FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("lessThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.lessThan(number1, number2)); + } + + @Override + public BooleanFormula lessOrEquals(FloatingPointFormula number1, FloatingPointFormula number2) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "lessOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.lessOrEquals(number1, number2)); + } + + @Override + public BooleanFormula isNaN(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("isNaN(%s)", logger.toVariable(number)), + () -> delegate.isNaN(number)); + } + + @Override + public BooleanFormula isInfinity(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("isInfinity(%s)", logger.toVariable(number)), + () -> delegate.isInfinity(number)); + } + + @Override + public BooleanFormula isZero(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("isZero(%s)", logger.toVariable(number)), + () -> delegate.isZero(number)); + } + + @Override + public BooleanFormula isNormal(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("isNormal(%s)", logger.toVariable(number)), + () -> delegate.isNormal(number)); + } + + @Override + public BooleanFormula isSubnormal(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("isSubnormal(%s)", logger.toVariable(number)), + () -> delegate.isSubnormal(number)); + } + + @Override + public BooleanFormula isNegative(FloatingPointFormula number) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("isNegative(%s)", logger.toVariable(number)), + () -> delegate.isNegative(number)); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 63789f8a7c..c01e252624 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -73,7 +73,7 @@ public BitvectorFormulaManager getBitvectorFormulaManager() { @Override public FloatingPointFormulaManager getFloatingPointFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceFloatingPointFormulaManager(delegate.getFloatingPointFormulaManager(), logger); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 74178540ed..5748383bd5 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -21,6 +21,7 @@ import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; +import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; public class TraceLogger { private long id = 0; @@ -113,6 +114,12 @@ public String printFormulaType(FormulaType pType) { BitvectorType bvType = (BitvectorType) pType; return String.format("FormulaType.getBitvectorTypeWithSize(%s)", bvType.getSize()); } + if (pType.isFloatingPointType()) { + FloatingPointType fpType = (FloatingPointType) pType; + return String.format( + "FormulaType.getFloatingPointType(%s, %s)", + fpType.getExponentSize(), fpType.getMantissaSize()); + } // FIXME Handle other cases throw new IllegalArgumentException("Unsupported formula type: " + pType); } From 7c432fc1cf5b1119a6abfad7501f8dfa1a07534f Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 19 Aug 2025 14:53:37 +0200 Subject: [PATCH 017/233] Trace: Specify the solver backend in the trace when creating a new context --- src/org/sosy_lab/java_smt/SolverContextFactory.java | 2 +- .../java_smt/delegate/trace/TraceSolverContext.java | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/SolverContextFactory.java b/src/org/sosy_lab/java_smt/SolverContextFactory.java index 8d9cc34dfb..cda52a0f09 100644 --- a/src/org/sosy_lab/java_smt/SolverContextFactory.java +++ b/src/org/sosy_lab/java_smt/SolverContextFactory.java @@ -237,7 +237,7 @@ public SolverContext generateContext(Solvers solverToCreate) context = new DebuggingSolverContext(solverToCreate, config, context); } if (trace) { - context = new TraceSolverContext(context, config); + context = new TraceSolverContext(solverToCreate, config, context); } if (collectStatistics) { // statistics need to be the most outer wrapping layer. diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 38bac71956..5cc71a17b9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -29,7 +29,7 @@ public class TraceSolverContext implements SolverContext { private final SolverContext delegate; private final TraceLogger logger; - public TraceSolverContext(SolverContext pDelegate, Configuration config) { + public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext pDelegate) { delegate = pDelegate; // FIXME Move the files to the output folder? logger = @@ -41,7 +41,9 @@ public TraceSolverContext(SolverContext pDelegate, Configuration config) { ImmutableMap.Builder options = ImmutableMap.builder(); for (String s : props.lines().toArray(String[]::new)) { List parts = Splitter.on(" = ").splitToList(s); - if (parts.get(0).startsWith("solver") && !parts.get(0).equals("solver.trace")) { + if (parts.get(0).startsWith("solver") + && !parts.get(0).equals("solver.trace") + && !parts.get(0).equals("solver.solver")) { options.put(parts.get(0), parts.get(1)); } } @@ -60,7 +62,11 @@ public TraceSolverContext(SolverContext pDelegate, Configuration config) { logger.appendDef("logger", "LogManager.createNullLogManager()"); logger.appendDef("notifier", "ShutdownNotifier.createDummy()"); logger.appendDef( - "context", "SolverContextFactory.createSolverContext(config, logger, notifier)"); + "context", + "SolverContextFactory.createSolverContext(config, logger, notifier, " + + "SolverContextFactory.Solvers." + + pSolver.name() + + ")"); logger.appendDef("mgr", "context.getFormulaManager()"); } catch (IOException e) { throw new RuntimeException(e); From c676391690e785a075df90978e0f72cc42d0a314 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 19 Aug 2025 15:12:53 +0200 Subject: [PATCH 018/233] Trace: Add a note --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index c01e252624..97f7596ec6 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -183,6 +183,7 @@ public T substitute( @Override public BooleanFormula translateFrom(BooleanFormula formula, FormulaManager otherManager) { + // TODO Write API calls from all contexts into one file to allow us to support this method throw new UnsupportedOperationException(); } From 299c901ab12f455c0407cccbc866e4b55803d212 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 20 Aug 2025 11:49:48 +0200 Subject: [PATCH 019/233] Trace: Add printing support for ArrayFormulaTypes --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 5748383bd5..e3e149e406 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -20,6 +20,7 @@ import java.util.concurrent.Callable; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; @@ -110,6 +111,12 @@ public String printFormulaType(FormulaType pType) { if (pType.isIntegerType()) { return "FormulaType.IntegerType"; } + if (pType.isArrayType()) { + ArrayFormulaType arrayType = (ArrayFormulaType) pType; + return String.format( + "FormulaType.getArrayType(%s, %s)", + printFormulaType(arrayType.getIndexType()), printFormulaType(arrayType.getElementType())); + } if (pType.isBitvectorType()) { BitvectorType bvType = (BitvectorType) pType; return String.format("FormulaType.getBitvectorTypeWithSize(%s)", bvType.getSize()); From d2292192b5354beb2ae0b2e6dd716090cedb86ce Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 20 Aug 2025 16:32:50 +0200 Subject: [PATCH 020/233] Trace: Catch I/O exceptions directly in the logger --- .../java_smt/delegate/trace/TraceLogger.java | 20 ++++++--- .../delegate/trace/TraceSolverContext.java | 41 ++++++++----------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index e3e149e406..d3618c480f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -63,15 +63,23 @@ public String toVariable(Object f) { } /** Add a definition to the log. */ - public void appendDef(String pVar, String pExpr) throws IOException { - output.append(String.format("var %s = %s;%n", pVar, pExpr)); - output.flush(); + public void appendDef(String pVar, String pExpr) { + try { + output.append(String.format("var %s = %s;%n", pVar, pExpr)); + output.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } } /** Add a statement to the log. */ - public void appendStmt(String pStmt) throws IOException { - output.append(String.format("%s;%n", pStmt)); - output.flush(); + public void appendStmt(String pStmt) { + try { + output.append(String.format("%s;%n", pStmt)); + output.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } } /** Log an API call with return value. */ diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 5cc71a17b9..ffbd4a7e8e 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -14,7 +14,6 @@ import com.google.common.base.Splitter; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; -import java.io.IOException; import java.util.List; import java.util.Map.Entry; import org.sosy_lab.common.configuration.Configuration; @@ -49,28 +48,24 @@ public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext p } // Write code for creating a solver context to the trace log - try { - logger.appendDef( - "config", - "Configuration.builder()." - + FluentIterable.from(options.buildOrThrow().entrySet()) - .transform( - (Entry e) -> - String.format("setOption(\"%s\", \"%s\")", e.getKey(), e.getValue())) - .join(Joiner.on(".")) - + ".build()"); - logger.appendDef("logger", "LogManager.createNullLogManager()"); - logger.appendDef("notifier", "ShutdownNotifier.createDummy()"); - logger.appendDef( - "context", - "SolverContextFactory.createSolverContext(config, logger, notifier, " - + "SolverContextFactory.Solvers." - + pSolver.name() - + ")"); - logger.appendDef("mgr", "context.getFormulaManager()"); - } catch (IOException e) { - throw new RuntimeException(e); - } + logger.appendDef( + "config", + "Configuration.builder()." + + FluentIterable.from(options.buildOrThrow().entrySet()) + .transform( + (Entry e) -> + String.format("setOption(\"%s\", \"%s\")", e.getKey(), e.getValue())) + .join(Joiner.on(".")) + + ".build()"); + logger.appendDef("logger", "LogManager.createNullLogManager()"); + logger.appendDef("notifier", "ShutdownNotifier.createDummy()"); + logger.appendDef( + "context", + "SolverContextFactory.createSolverContext(config, logger, notifier, " + + "SolverContextFactory.Solvers." + + pSolver.name() + + ")"); + logger.appendDef("mgr", "context.getFormulaManager()"); } @Override From a187568373176f16e7f3aff9966b7b4ca908a776 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 20 Aug 2025 16:33:53 +0200 Subject: [PATCH 021/233] Trace: Add support for visitors --- .../delegate/trace/TraceFormulaManager.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 97f7596ec6..43f1a66de8 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -27,6 +27,7 @@ import org.sosy_lab.java_smt.api.FunctionDeclaration; import org.sosy_lab.java_smt.api.IntegerFormulaManager; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; +import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; import org.sosy_lab.java_smt.api.RationalFormulaManager; import org.sosy_lab.java_smt.api.SLFormulaManager; import org.sosy_lab.java_smt.api.SolverException; @@ -148,14 +149,65 @@ public T simplify(T input) throws InterruptedException { throw new UnsupportedOperationException(); } + private class TraceVisitor implements FormulaVisitor { + private final FormulaVisitor delegateVisitor; + + private TraceVisitor(FormulaVisitor pDelegate) { + delegateVisitor = pDelegate; + } + + @Override + public T visitFreeVariable(Formula f, String name) { + return delegateVisitor.visitFreeVariable(f, name); + } + + @Override + public T visitConstant(Formula f, Object value) { + return delegateVisitor.visitConstant(f, value); + } + + @SuppressWarnings("unused") + @Override + public T visitFunction( + Formula f, List args, FunctionDeclaration functionDeclaration) { + for (int i = 0; i <= args.size(); i++) { + var value = i == 0 ? functionDeclaration : args.get(i - 1); + var unused = + logger.logDef( + "mgr", + String.format("visit(%s, new ExtractingVisitor(%s))", logger.toVariable(f), i), + () -> value); + } + return delegateVisitor.visitFunction(f, args, functionDeclaration); + } + + @SuppressWarnings("unused") + @Override + public T visitQuantifier( + BooleanFormula f, + Quantifier quantifier, + List boundVariables, + BooleanFormula body) { + for (int i = 0; i <= boundVariables.size(); i++) { + var value = i == boundVariables.size() ? body : boundVariables.get(i - 1); + var unused = + logger.logDef( + "mgr", + String.format("visit(%s, new ExtractingVisitor(%s))", logger.toVariable(f), i), + () -> value); + } + return delegateVisitor.visitQuantifier(f, quantifier, boundVariables, body); + } + } + @Override public R visit(Formula f, FormulaVisitor rFormulaVisitor) { - throw new UnsupportedOperationException(); + return delegate.visit(f, new TraceVisitor<>(rFormulaVisitor)); } @Override public void visitRecursively(Formula f, FormulaVisitor rFormulaVisitor) { - throw new UnsupportedOperationException(); + delegate.visitRecursively(f, new TraceVisitor<>(rFormulaVisitor)); } @Override From 0590364fa2fc1f6b86c7b668521597a31831699b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 20 Aug 2025 16:36:40 +0200 Subject: [PATCH 022/233] Trace: Allow parsing and printing --- .../java_smt/delegate/trace/TraceFormulaManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 43f1a66de8..5465a39564 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -130,12 +130,15 @@ public FormulaType getFormulaType(T formula) { @Override public BooleanFormula parse(String s) throws IllegalArgumentException { - throw new UnsupportedOperationException(); + return logger.logDef("mgr", String.format("parse(\"%s\")", s), () -> delegate.parse(s)); } @Override public Appender dumpFormula(BooleanFormula pT) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr", + String.format("dumpFormula(%s)", logger.toVariable(pT)), + () -> delegate.dumpFormula(pT)); } @Override From b0dd829a459abf18f18430e7c219671f1ba978bf Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 21 Aug 2025 12:32:17 +0200 Subject: [PATCH 023/233] Trace: Fix checkstyle issue --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 5465a39564..9649aa4cd2 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -152,7 +152,7 @@ public T simplify(T input) throws InterruptedException { throw new UnsupportedOperationException(); } - private class TraceVisitor implements FormulaVisitor { + private final class TraceVisitor implements FormulaVisitor { private final FormulaVisitor delegateVisitor; private TraceVisitor(FormulaVisitor pDelegate) { From 2ed82e59cebeb831a7bada01003855cc08d8eff1 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 21 Aug 2025 12:33:01 +0200 Subject: [PATCH 024/233] Trace: Throw an exception when trying to get the variable for an object that is not tracked --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index d3618c480f..08553bd8b4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -59,7 +59,11 @@ private void mapVariable(String pVar, Object f) { *

Use {@link #mapVariable(String, Object)} to bind an object to a variable */ public String toVariable(Object f) { - return valueMap.get(f); + String r = valueMap.get(f); + if (r == null) { + throw new IllegalArgumentException("Object not tracked"); + } + return r; } /** Add a definition to the log. */ From 3ce7e7b93aaa57d30b5469cc21aeb6abf35f103b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 21 Aug 2025 12:37:11 +0200 Subject: [PATCH 025/233] Trace: Make TraceLogger package-private --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 08553bd8b4..696db63dac 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -24,7 +24,7 @@ import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; -public class TraceLogger { +class TraceLogger { private long id = 0; private final Map valueMap = new HashMap<>(); From 2d35c3d18ef95ed762ae585f1f7089c61e3bcfd2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 21 Aug 2025 13:40:29 +0200 Subject: [PATCH 026/233] Trace: Add support for printing more formula types --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 696db63dac..120990a0ba 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -120,9 +120,15 @@ public void logStmt(String prefix, String method, CheckedRunnable closure) { * construct this type. */ public String printFormulaType(FormulaType pType) { + if (pType.isBooleanType()) { + return "FormulaType.BooleanType"; + } if (pType.isIntegerType()) { return "FormulaType.IntegerType"; } + if (pType.isRationalType()) { + return "FormulaType.RationalType"; + } if (pType.isArrayType()) { ArrayFormulaType arrayType = (ArrayFormulaType) pType; return String.format( From b273c253d0b45fb392e2e5ed00271002374b2e8d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 21 Aug 2025 21:32:41 +0200 Subject: [PATCH 027/233] Trace: Apply refaster patch --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 120990a0ba..c60317ca6d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -10,6 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Preconditions; import java.io.BufferedWriter; import java.io.IOException; import java.nio.charset.Charset; @@ -60,9 +61,7 @@ private void mapVariable(String pVar, Object f) { */ public String toVariable(Object f) { String r = valueMap.get(f); - if (r == null) { - throw new IllegalArgumentException("Object not tracked"); - } + Preconditions.checkArgument(r != null, "Object not tracked"); return r; } From c7c15bfe5413a485a172d8a29d715b689ed5e966 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 23 Aug 2025 15:44:18 +0200 Subject: [PATCH 028/233] Trace: Remove duplicate "." when creating a trace for the configuration builder --- .../java_smt/delegate/trace/TraceSolverContext.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index ffbd4a7e8e..858ac04ee7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -50,12 +50,12 @@ public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext p // Write code for creating a solver context to the trace log logger.appendDef( "config", - "Configuration.builder()." + "Configuration.builder()" + FluentIterable.from(options.buildOrThrow().entrySet()) .transform( (Entry e) -> - String.format("setOption(\"%s\", \"%s\")", e.getKey(), e.getValue())) - .join(Joiner.on(".")) + String.format(".setOption(\"%s\", \"%s\")", e.getKey(), e.getValue())) + .join(Joiner.on("")) + ".build()"); logger.appendDef("logger", "LogManager.createNullLogManager()"); logger.appendDef("notifier", "ShutdownNotifier.createDummy()"); From 01cb338674005e64703f34c4e83f0ae797c5eb3b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:01:50 +0200 Subject: [PATCH 029/233] Trace: Refactor code and rebuild all terms that are returned by the solver Rebuilding the terms makes sure that we don't encounter any unknown subformulas in the visitors --- .../trace/TraceBasicProverEnvironment.java | 6 +- .../trace/TraceBitvectorFormulaManager.java | 2 +- .../trace/TraceBooleanFormulaManager.java | 4 +- .../delegate/trace/TraceFormulaManager.java | 624 ++++++++++++++++-- .../java_smt/delegate/trace/TraceLogger.java | 84 ++- .../java_smt/delegate/trace/TraceModel.java | 18 +- .../delegate/trace/TraceSolverContext.java | 9 +- .../delegate/trace/TraceUFManager.java | 32 +- 8 files changed, 671 insertions(+), 108 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index dfcb804b96..fe202cc466 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -35,7 +35,7 @@ public void pop() { @Override public @Nullable T addConstraint(BooleanFormula constraint) throws InterruptedException { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("addConstraint(%s)", logger.toVariable(constraint)), () -> delegate.addConstraint(constraint)); @@ -53,7 +53,7 @@ public int size() { @Override public boolean isUnsat() throws SolverException, InterruptedException { - return logger.logDef(logger.toVariable(this), "isUnsat()", delegate::isUnsat); + return logger.logDefKeep(logger.toVariable(this), "isUnsat()", delegate::isUnsat); } @Override @@ -65,7 +65,7 @@ public boolean isUnsatWithAssumptions(Collection assumptions) @SuppressWarnings("resource") @Override public Model getModel() throws SolverException { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), "getModel()", () -> new TraceModel(delegate.getModel(), logger)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java index a247ec978b..936a12f33c 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -79,7 +79,7 @@ public BitvectorFormula makeVariable(BitvectorType type, String pVar) { @Override public int getLength(BitvectorFormula number) { - return logger.logDef( + return logger.logDefDiscard( "mgr.getBitvectorFormulaManager()", String.format("getLength(%s)", logger.toVariable(number)), () -> delegate.getLength(number)); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 78ae819fe0..3a8179a0c6 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -68,7 +68,7 @@ public BooleanFormula implication(BooleanFormula formula1, BooleanFormula formul @Override public boolean isTrue(BooleanFormula formula) { - return logger.logDef( + return logger.logDefDiscard( "mgr.getBooleanFormulaManager()", String.format("isTrue(%s)", logger.toVariable(formula)), () -> delegate.isTrue(formula)); @@ -76,7 +76,7 @@ public boolean isTrue(BooleanFormula formula) { @Override public boolean isFalse(BooleanFormula formula) { - return logger.logDef( + return logger.logDefDiscard( "mgr.getBooleanFormulaManager()", String.format("isFalse(%s)", logger.toVariable(formula)), () -> delegate.isFalse(formula)); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 9649aa4cd2..bf8152a7aa 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -10,22 +10,33 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import java.math.BigInteger; import java.util.List; import java.util.Map; import org.sosy_lab.common.Appender; +import org.sosy_lab.java_smt.api.ArrayFormula; import org.sosy_lab.java_smt.api.ArrayFormulaManager; +import org.sosy_lab.java_smt.api.BitvectorFormula; import org.sosy_lab.java_smt.api.BitvectorFormulaManager; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.BooleanFormulaManager; import org.sosy_lab.java_smt.api.EnumerationFormulaManager; +import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; +import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; +import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; import org.sosy_lab.java_smt.api.FunctionDeclaration; +import org.sosy_lab.java_smt.api.FunctionDeclarationKind; import org.sosy_lab.java_smt.api.IntegerFormulaManager; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; import org.sosy_lab.java_smt.api.RationalFormulaManager; @@ -40,10 +51,13 @@ public class TraceFormulaManager implements FormulaManager { private final FormulaManager delegate; - private final TraceLogger logger; + private TraceLogger logger; - TraceFormulaManager(FormulaManager pDelegate, TraceLogger pLogger) { + TraceFormulaManager(FormulaManager pDelegate) { delegate = pDelegate; + } + + void setLogger(TraceLogger pLogger) { logger = pLogger; } @@ -102,17 +116,544 @@ public EnumerationFormulaManager getEnumerationFormulaManager() { throw new UnsupportedOperationException(); } + private class Rebuilder extends FormulaTransformationVisitor { + protected Rebuilder(FormulaManager fmgr) { + super(fmgr); + } + + @Override + public Formula visitFreeVariable(Formula f, String name) { + if (!logger.isTracked(f)) { + var g = + logger.logDef( + "mgr", + String.format( + "makeVariable(%s, %s)", + logger.printFormulaType(delegate.getFormulaType(f)), name), + () -> delegate.makeVariable(delegate.getFormulaType(f), name)); + Preconditions.checkArgument(g.equals(f)); + } + return f; + } + + @Override + public Formula visitConstant(Formula f, Object value) { + if (!logger.isTracked(f)) { + if (f instanceof BooleanFormula && value instanceof Boolean) { + var g = + logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("makeBoolean(%s)", value), + () -> delegate.getBooleanFormulaManager().makeBoolean((Boolean) value)); + Preconditions.checkArgument(g.equals(f)); + } else if (f instanceof BitvectorFormula && value instanceof BigInteger) { + var bvSize = delegate.getBitvectorFormulaManager().getLength((BitvectorFormula) f); + var g = + logger.logDef( + "mgr.getBitvectorFormulaManager()", + String.format("makeBitvector(%s, %s)", bvSize, value), + () -> + delegate + .getBitvectorFormulaManager() + .makeBitvector(bvSize, (BigInteger) value)); + Preconditions.checkArgument(g.equals(f)); + } else if (f instanceof IntegerFormula && value instanceof BigInteger) { + var g = + logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(%s)", value), + () -> delegate.getIntegerFormulaManager().makeNumber((BigInteger) value)); + Preconditions.checkArgument(g.equals(f)); + } else { + throw new IllegalArgumentException( + String.format( + "Unsupported value: Formula=%s, Value=%s", + delegate.getFormulaType(f), value.getClass().getName())); + } + } + return f; + } + + @Override + public Formula visitFunction( + Formula f, List args, FunctionDeclaration functionDeclaration) { + if (!logger.isTracked(f)) { + Formula g = makeApplication(functionDeclaration, args); + // FIXME Remove the assertion? Argument order can change, f.ex (and a b) becomes (and b a) + // Preconditions.checkArgument(g.equals(f)); + } + return f; + } + + @Override + public BooleanFormula visitQuantifier( + BooleanFormula f, + Quantifier quantifier, + List boundVariables, + BooleanFormula body) { + throw new UnsupportedOperationException(); + } + } + + public T rebuild(T f) { + return delegate.transformRecursively(f, new TraceFormulaManager.Rebuilder(this)); + } + @Override public T makeVariable(FormulaType formulaType, String name) { - return logger.logDef( - "mgr", - String.format("makeVariable(%s, \"%s\")", logger.printFormulaType(formulaType), name), - () -> delegate.makeVariable(formulaType, name)); + String var = logger.newVariable(); + logger.appendDef( + var, + String.format("mgr.makeVariable(%s, \"%s\")", logger.printFormulaType(formulaType), name)); + T f = delegate.makeVariable(formulaType, name); + if (logger.isTracked(f)) { + logger.undoLast(); + } + return f; } + @SuppressWarnings("unchecked") @Override public T makeApplication( FunctionDeclaration declaration, List args) { + if (declaration.getKind().equals(FunctionDeclarationKind.UF)) { + var uf = + getUFManager() + .declareUF( + declaration.getName(), declaration.getType(), declaration.getArgumentTypes()); + return getUFManager().callUF(uf, args); + } else { + // TODO Check that the number of arguments matches the arity of the operation + // TODO Figure out how to handle rounding mode for floats + switch (declaration.getKind()) { + case AND: + return (T) + getBooleanFormulaManager() + .and((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + case NOT: + return (T) getBooleanFormulaManager().not((BooleanFormula) args.get(0)); + case OR: + return (T) + getBooleanFormulaManager() + .or((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + case IFF: + return (T) + getBooleanFormulaManager() + .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + case ITE: + return getBooleanFormulaManager() + .ifThenElse((BooleanFormula) args.get(0), (T) args.get(1), (T) args.get(2)); + case XOR: + return (T) + getBooleanFormulaManager() + .xor((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + case IMPLIES: + return (T) + getBooleanFormulaManager() + .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + case DISTINCT: + // TODO We only have 'distinct' for some theories + break; + case STORE: + return (T) + getArrayFormulaManager().store((ArrayFormula) args.get(0), args.get(1), args.get(2)); + case SELECT: + return (T) getArrayFormulaManager().select((ArrayFormula) args.get(0), args.get(1)); + case CONST: + return (T) + getArrayFormulaManager() + .makeArray((ArrayFormulaType) declaration.getType(), args.get(0)); + case UMINUS: + // FIXME Handle rational formulas + return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); + case SUB: + return (T) + getIntegerFormulaManager() + .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case ADD: + return (T) + getIntegerFormulaManager() + .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case DIV: + return (T) + getIntegerFormulaManager() + .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case MUL: + return (T) + getIntegerFormulaManager() + .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case MODULO: + return (T) + getIntegerFormulaManager() + .modulo((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case LT: + return (T) + getIntegerFormulaManager() + .lessThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case LTE: + return (T) + getIntegerFormulaManager() + .lessOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case GT: + return (T) + getIntegerFormulaManager() + .greaterThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case GTE: + return (T) + getIntegerFormulaManager() + .greaterOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + case EQ: + { + if (declaration.getArgumentTypes().get(0).isBooleanType()) { + return (T) + getBooleanFormulaManager() + .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(1).isIntegerType()) { + return (T) + getIntegerFormulaManager() + .equal((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(1).isBitvectorType()) { + return (T) + getBitvectorFormulaManager() + .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } else { + throw new UnsupportedOperationException( + String.format( + "EQ not supported for theory " + "%s", + declaration.getArgumentTypes().get(0))); + } + } + /* + case EQ_ZERO: + break; + case GTE_ZERO: + break; + case FLOOR: + break; + case TO_REAL: + break; + */ + case BV_EXTRACT: + { + String[] tokens = declaration.getName().split("_"); + return (T) + getBitvectorFormulaManager() + .extract( + (BitvectorFormula) args.get(0), + Integer.parseInt(tokens[1]), + Integer.parseInt(tokens[2])); + } + case BV_CONCAT: + return (T) + getBitvectorFormulaManager() + .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_SIGN_EXTENSION: + // TODO + break; + case BV_ZERO_EXTENSION: + // TODO + break; + case BV_NOT: + return (T) getBitvectorFormulaManager().not((BitvectorFormula) args.get(0)); + case BV_NEG: + return (T) getBitvectorFormulaManager().negate((BitvectorFormula) args.get(0)); + case BV_OR: + return (T) + getBitvectorFormulaManager() + .or((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_AND: + return (T) + getBitvectorFormulaManager() + .and((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_XOR: + return (T) + getBitvectorFormulaManager() + .xor((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_SUB: + return (T) + getBitvectorFormulaManager() + .subtract((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_ADD: + return (T) + getBitvectorFormulaManager() + .add((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_SDIV: + return (T) + getBitvectorFormulaManager() + .divide((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_UDIV: + return (T) + getBitvectorFormulaManager() + .divide((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_SREM: + return (T) + getBitvectorFormulaManager() + .remainder((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_UREM: + return (T) + getBitvectorFormulaManager() + .remainder((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_SMOD: + return (T) + getBitvectorFormulaManager() + .smodulo((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_MUL: + return (T) + getBitvectorFormulaManager() + .multiply((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_ULT: + return (T) + getBitvectorFormulaManager() + .lessThan((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_SLT: + return (T) + getBitvectorFormulaManager() + .lessThan((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_ULE: + return (T) + getBitvectorFormulaManager() + .lessOrEquals( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_SLE: + return (T) + getBitvectorFormulaManager() + .lessOrEquals( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_UGT: + return (T) + getBitvectorFormulaManager() + .greaterThan( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_SGT: + return (T) + getBitvectorFormulaManager() + .greaterThan( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_UGE: + return (T) + getBitvectorFormulaManager() + .greaterOrEquals( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_SGE: + return (T) + getBitvectorFormulaManager() + .greaterOrEquals( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_EQ: // FIXME Why is this a separate symbol? + return (T) + getBitvectorFormulaManager() + .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_SHL: + return (T) + getBitvectorFormulaManager() + .shiftLeft((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_LSHR: + return (T) + getBitvectorFormulaManager() + .shiftRight( + (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), false); + case BV_ASHR: + return (T) + getBitvectorFormulaManager() + .shiftRight((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); + case BV_ROTATE_LEFT: + return (T) + getBitvectorFormulaManager() + .rotateLeft((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_ROTATE_RIGHT: + return (T) + getBitvectorFormulaManager() + .rotateRight((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + case BV_ROTATE_LEFT_BY_INT: + // TODO + break; + case BV_ROTATE_RIGHT_BY_INT: + // TODO + break; + case BV_UCASTTO_FP: + return (T) + getFloatingPointFormulaManager() + .castFrom(args.get(0), false, (FloatingPointType) declaration.getType()); + case BV_SCASTTO_FP: + return (T) + getFloatingPointFormulaManager() + .castFrom(args.get(0), true, (FloatingPointType) declaration.getType()); + case FP_NEG: + return (T) getFloatingPointFormulaManager().negate((FloatingPointFormula) args.get(0)); + case FP_ABS: + return (T) getFloatingPointFormulaManager().abs((FloatingPointFormula) args.get(0)); + case FP_MAX: + return (T) + getFloatingPointFormulaManager() + .max((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_MIN: + return (T) + getFloatingPointFormulaManager() + .min((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_SQRT: + return (T) getFloatingPointFormulaManager().sqrt((FloatingPointFormula) args.get(0)); + case FP_SUB: + return (T) + getFloatingPointFormulaManager() + .subtract((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_ADD: + return (T) + getFloatingPointFormulaManager() + .add((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_DIV: + return (T) + getFloatingPointFormulaManager() + .divide((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_REM: + return (T) + getFloatingPointFormulaManager() + .remainder( + (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_MUL: + return (T) + getFloatingPointFormulaManager() + .multiply((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_LT: + return (T) + getFloatingPointFormulaManager() + .lessThan((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_LE: + return (T) + getFloatingPointFormulaManager() + .lessOrEquals( + (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_GE: + return (T) + getFloatingPointFormulaManager() + .greaterOrEquals( + (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_GT: + return (T) + getFloatingPointFormulaManager() + .greaterThan( + (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_EQ: + return (T) + getFloatingPointFormulaManager() + .equalWithFPSemantics( + (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + case FP_ROUND_EVEN: + break; + case FP_ROUND_AWAY: + break; + case FP_ROUND_POSITIVE: + break; + case FP_ROUND_NEGATIVE: + break; + case FP_ROUND_ZERO: + break; + case FP_ROUND_TO_INTEGRAL: + { + var rm = (FloatingPointRoundingModeFormula) args.get(1); + System.out.println("Rounding Mode: " + rm); + return (T) + getFloatingPointFormulaManager() + .round( + (FloatingPointFormula) args.get(0), + FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + case FP_IS_NAN: + return (T) getFloatingPointFormulaManager().isNaN((FloatingPointFormula) args.get(0)); + case FP_IS_INF: + return (T) + getFloatingPointFormulaManager().isInfinity((FloatingPointFormula) args.get(0)); + case FP_IS_ZERO: + return (T) getFloatingPointFormulaManager().isZero((FloatingPointFormula) args.get(0)); + case FP_IS_NEGATIVE: + return (T) + getFloatingPointFormulaManager().isNegative((FloatingPointFormula) args.get(0)); + case FP_IS_SUBNORMAL: + return (T) + getFloatingPointFormulaManager().isSubnormal((FloatingPointFormula) args.get(0)); + case FP_IS_NORMAL: + return (T) getFloatingPointFormulaManager().isNormal((FloatingPointFormula) args.get(0)); + case FP_CASTTO_FP: + return getFloatingPointFormulaManager() + .castTo((FloatingPointFormula) args.get(0), true, declaration.getType()); + case FP_CASTTO_SBV: + return getFloatingPointFormulaManager() + .castTo((FloatingPointFormula) args.get(0), true, declaration.getType()); + case FP_CASTTO_UBV: + return getFloatingPointFormulaManager() + .castTo((FloatingPointFormula) args.get(0), false, declaration.getType()); + case FP_AS_IEEEBV: + return (T) + getFloatingPointFormulaManager().toIeeeBitvector((FloatingPointFormula) args.get(0)); + case FP_FROM_IEEEBV: + return (T) + getFloatingPointFormulaManager() + .fromIeeeBitvector( + (BitvectorFormula) args.get(0), (FloatingPointType) declaration.getType()); + /* + case STR_CONCAT: + break; + case STR_PREFIX: + break; + case STR_SUFFIX: + break; + case STR_CONTAINS: + break; + case STR_SUBSTRING: + break; + case STR_REPLACE: + break; + case STR_REPLACE_ALL: + break; + case STR_CHAR_AT: + break; + case STR_LENGTH: + break; + case STR_INDEX_OF: + break; + case STR_TO_RE: + break; + case STR_IN_RE: + break; + case STR_TO_INT: + break; + case INT_TO_STR: + break; + case STR_FROM_CODE: + break; + case STR_TO_CODE: + break; + case STR_LT: + break; + case STR_LE: + break; + case RE_PLUS: + break; + case RE_STAR: + break; + case RE_OPTIONAL: + break; + case RE_CONCAT: + break; + case RE_UNION: + break; + case RE_RANGE: + break; + case RE_INTERSECT: + break; + case RE_COMPLEMENT: + break; + case RE_DIFFERENCE: + break; + case OTHER: + break; + */ + default: + throw new UnsupportedOperationException( + String.format( + "Operation not supported: %s, (%s)", + declaration.getKind(), declaration.getName())); + } + } throw new UnsupportedOperationException(); } @@ -130,15 +671,18 @@ public FormulaType getFormulaType(T formula) { @Override public BooleanFormula parse(String s) throws IllegalArgumentException { - return logger.logDef("mgr", String.format("parse(\"%s\")", s), () -> delegate.parse(s)); + logger.appendStmt(String.format("mgr.parse(\"%s\")", s)); + BooleanFormula f = delegate.parse(s); + logger.undoLast(); + return rebuild(f); } @Override public Appender dumpFormula(BooleanFormula pT) { - return logger.logDef( - "mgr", - String.format("dumpFormula(%s)", logger.toVariable(pT)), - () -> delegate.dumpFormula(pT)); + logger.appendStmt(String.format("mgr.dumpFormula(%s)", logger.toVariable(pT))); + Appender str = delegate.dumpFormula(pT); + logger.undoLast(); + return str; } @Override @@ -152,76 +696,24 @@ public T simplify(T input) throws InterruptedException { throw new UnsupportedOperationException(); } - private final class TraceVisitor implements FormulaVisitor { - private final FormulaVisitor delegateVisitor; - - private TraceVisitor(FormulaVisitor pDelegate) { - delegateVisitor = pDelegate; - } - - @Override - public T visitFreeVariable(Formula f, String name) { - return delegateVisitor.visitFreeVariable(f, name); - } - - @Override - public T visitConstant(Formula f, Object value) { - return delegateVisitor.visitConstant(f, value); - } - - @SuppressWarnings("unused") - @Override - public T visitFunction( - Formula f, List args, FunctionDeclaration functionDeclaration) { - for (int i = 0; i <= args.size(); i++) { - var value = i == 0 ? functionDeclaration : args.get(i - 1); - var unused = - logger.logDef( - "mgr", - String.format("visit(%s, new ExtractingVisitor(%s))", logger.toVariable(f), i), - () -> value); - } - return delegateVisitor.visitFunction(f, args, functionDeclaration); - } - - @SuppressWarnings("unused") - @Override - public T visitQuantifier( - BooleanFormula f, - Quantifier quantifier, - List boundVariables, - BooleanFormula body) { - for (int i = 0; i <= boundVariables.size(); i++) { - var value = i == boundVariables.size() ? body : boundVariables.get(i - 1); - var unused = - logger.logDef( - "mgr", - String.format("visit(%s, new ExtractingVisitor(%s))", logger.toVariable(f), i), - () -> value); - } - return delegateVisitor.visitQuantifier(f, quantifier, boundVariables, body); - } - } - @Override public R visit(Formula f, FormulaVisitor rFormulaVisitor) { - return delegate.visit(f, new TraceVisitor<>(rFormulaVisitor)); + return delegate.visit(f, rFormulaVisitor); } @Override public void visitRecursively(Formula f, FormulaVisitor rFormulaVisitor) { - delegate.visitRecursively(f, new TraceVisitor<>(rFormulaVisitor)); + delegate.visitRecursively(f, rFormulaVisitor); } @Override public T transformRecursively( T f, FormulaTransformationVisitor pFormulaVisitor) { - throw new UnsupportedOperationException(); + return delegate.transformRecursively(f, pFormulaVisitor); } @Override public ImmutableMap extractVariables(Formula f) { - // FIXME Add proper tracing return delegate.extractVariables(f); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index c60317ca6d..39d9e85c2d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -11,11 +11,9 @@ package org.sosy_lab.java_smt.delegate.trace; import com.google.common.base.Preconditions; -import java.io.BufferedWriter; import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.RandomAccessFile; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; @@ -26,22 +24,26 @@ import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; class TraceLogger { + private final TraceFormulaManager mgr; private long id = 0; private final Map valueMap = new HashMap<>(); - private final BufferedWriter output; + private final RandomAccessFile output; - TraceLogger(String pFile) { + private long backtrackPoint = -1; + + TraceLogger(TraceFormulaManager pMgr, String pFile) { + mgr = pMgr; // FIXME Check if the file already exists try { - output = Files.newBufferedWriter(Path.of(pFile), Charset.defaultCharset()); + output = new RandomAccessFile(pFile, "rw"); } catch (IOException e) { throw new IllegalArgumentException(e); } } /** Returns a fresh variable. */ - private String newVariable() { + public String newVariable() { return "var" + id++; } @@ -50,10 +52,15 @@ private String newVariable() { * *

Use {@link #toVariable(Object)} to get the variable name for a tracked object */ - private void mapVariable(String pVar, Object f) { + public void mapVariable(String pVar, Object f) { valueMap.putIfAbsent(f, pVar); } + /** Returns true if the object is tracked. */ + public boolean isTracked(Object f) { + return valueMap.containsKey(f); + } + /** * Returns the variable name of a tracked object. * @@ -61,15 +68,15 @@ private void mapVariable(String pVar, Object f) { */ public String toVariable(Object f) { String r = valueMap.get(f); - Preconditions.checkArgument(r != null, "Object not tracked"); + Preconditions.checkArgument(r != null, "Object not tracked: %s", f); return r; } /** Add a definition to the log. */ public void appendDef(String pVar, String pExpr) { try { - output.append(String.format("var %s = %s;%n", pVar, pExpr)); - output.flush(); + backtrackPoint = output.length(); + output.write(String.format("var %s = %s;%n", pVar, pExpr).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new RuntimeException(e); } @@ -78,22 +85,69 @@ public void appendDef(String pVar, String pExpr) { /** Add a statement to the log. */ public void appendStmt(String pStmt) { try { - output.append(String.format("%s;%n", pStmt)); - output.flush(); + backtrackPoint = output.length(); + output.write(String.format("%s;%n", pStmt).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new RuntimeException(e); } } + public void undoLast() { + Preconditions.checkArgument(backtrackPoint >= 0, "Cannot undo last trace"); + try { + output.setLength(backtrackPoint); + } catch (IOException pE) { + throw new RuntimeException(pE); + } + backtrackPoint = -1; + } + /** Log an API call with return value. */ - public R logDef(String prefix, String method, Callable closure) { + public R logDef(String prefix, String method, Callable closure) { + String var = newVariable(); + try { + appendDef(var, prefix + "." + method); + R f = closure.call(); + if (!isTracked(f)) { + mapVariable(var, f); + return f; + } else { + undoLast(); + return mgr.rebuild(f); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Variant of {@link #logDef(String, String, Callable)} that will always keep the call in the log. + * + *

Use this version if the called function has side effects + */ + public R logDefKeep(String prefix, String method, Callable closure) { String var = newVariable(); try { appendDef(var, prefix + "." + method); R f = closure.call(); mapVariable(var, f); return f; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + /** + * Variant of {@link #logDef(String, String, Callable)} that will always remove the call from the + * log after it returned successfully. + */ + public R logDefDiscard(String prefix, String method, Callable closure) { + String var = newVariable(); + try { + appendDef(var, prefix + "." + method); + R f = closure.call(); + undoLast(); + return f; } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java index 6b6cc1e123..e884b1a0a3 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java @@ -38,7 +38,7 @@ public class TraceModel implements Model { public ImmutableList asList() { // FIXME We need to introduce local variables for all terms in the model so that they can be // referenced later - return logger.logDef(logger.toVariable(this), "asList()", delegate::asList); + return logger.logDefKeep(logger.toVariable(this), "asList()", delegate::asList); } @Override @@ -51,7 +51,7 @@ public ImmutableList asList() { @Override public @Nullable Object evaluate(Formula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -59,7 +59,7 @@ public ImmutableList asList() { @Override public @Nullable BigInteger evaluate(IntegerFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -67,7 +67,7 @@ public ImmutableList asList() { @Override public @Nullable Rational evaluate(RationalFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -75,7 +75,7 @@ public ImmutableList asList() { @Override public @Nullable Boolean evaluate(BooleanFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -83,7 +83,7 @@ public ImmutableList asList() { @Override public @Nullable BigInteger evaluate(BitvectorFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -91,7 +91,7 @@ public ImmutableList asList() { @Override public @Nullable String evaluate(StringFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -99,7 +99,7 @@ public ImmutableList asList() { @Override public @Nullable String evaluate(EnumerationFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -107,7 +107,7 @@ public ImmutableList asList() { @Override public @Nullable FloatingPointNumber evaluate(FloatingPointFormula formula) { - return logger.logDef( + return logger.logDefKeep( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 858ac04ee7..3524b6c0c2 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -27,13 +27,16 @@ public class TraceSolverContext implements SolverContext { private final SolverContext delegate; private final TraceLogger logger; + private final TraceFormulaManager mgr; public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext pDelegate) { delegate = pDelegate; // FIXME Move the files to the output folder? + mgr = new TraceFormulaManager(delegate.getFormulaManager()); logger = new TraceLogger( - "trace" + Integer.toUnsignedString(System.identityHashCode(this)) + ".java"); + mgr, "trace" + Integer.toUnsignedString(System.identityHashCode(this)) + ".java"); + mgr.setLogger(logger); // Get relevant options from the configuration String props = config.asPropertiesString(); @@ -70,13 +73,13 @@ public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext p @Override public FormulaManager getFormulaManager() { - return new TraceFormulaManager(delegate.getFormulaManager(), logger); + return mgr; } @SuppressWarnings("resource") @Override public ProverEnvironment newProverEnvironment(ProverOptions... options) { - return logger.logDef( + return logger.logDefKeep( "context", String.format( "newProverEnvironment(%s)", diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index a01af0a494..fd76ac16c4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -31,14 +31,21 @@ public class TraceUFManager implements UFManager { @Override public FunctionDeclaration declareUF( String name, FormulaType returnType, List> args) { - return logger.logDef( - "mgr.getUFManager()", + String var = logger.newVariable(); + logger.appendDef( + var, String.format( - "declareUF(\"%s\", %s, ImmutableList.of(%s))", + "mgr.getUFManager().declareUF(\"%s\", %s, ImmutableList.of(%s))", name, logger.printFormulaType(returnType), - FluentIterable.from(args).transform(logger::printFormulaType).join(Joiner.on(", "))), - () -> delegate.declareUF(name, returnType, args)); + FluentIterable.from(args).transform(logger::printFormulaType).join(Joiner.on(", ")))); + FunctionDeclaration f = delegate.declareUF(name, returnType, args); + if (logger.isTracked(f)) { + logger.undoLast(); + } else { + logger.mapVariable(var, f); + } + return f; } @Override @@ -50,13 +57,20 @@ public FunctionDeclaration declareUF( @Override public T callUF( FunctionDeclaration funcType, List args) { - return logger.logDef( - "mgr.getUFManager()", + String var = logger.newVariable(); + logger.appendDef( + var, String.format( "callUF(%s, ImmutableList.of(%s))", logger.toVariable(funcType), - FluentIterable.from(args).transform(logger::toVariable).join(Joiner.on(", "))), - () -> delegate.callUF(funcType, args)); + FluentIterable.from(args).transform(logger::toVariable).join(Joiner.on(", ")))); + T f = delegate.callUF(funcType, args); + if (logger.isTracked(f)) { + logger.undoLast(); + } else { + logger.mapVariable(var, f); + } + return f; } @Override From 3df3d88297beeefe61f9ac76c890bd811fe2b0e2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:06:57 +0200 Subject: [PATCH 030/233] Trace: Add support for array constants --- .../delegate/trace/TraceArrayFormulaManager.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java index d641eea34f..666320e1b2 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java @@ -68,7 +68,14 @@ ArrayFormula makeArray(String pName, FTI pIndexType, FTE pElementType) { FTI extends FormulaType, FTE extends FormulaType> ArrayFormula makeArray(FTI pIndexType, FTE pElementType, TE defaultElement) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getArrayFormulaManager()", + String.format( + "makeArray(\"%s\", %s, %s)", + logger.printFormulaType(pIndexType), + logger.printFormulaType(pElementType), + logger.toVariable(defaultElement)), + () -> delegate.makeArray(pIndexType, pElementType, defaultElement)); } @Override From 6ad67ab9a1683cd4e6262cc31f344f7f6ca579ea Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:14:26 +0200 Subject: [PATCH 031/233] Trace: Avoid catching runtime exceptions while logging --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 39d9e85c2d..d2db0dcdb3 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -11,6 +11,7 @@ package org.sosy_lab.java_smt.delegate.trace; import com.google.common.base.Preconditions; +import com.google.common.base.Throwables; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; @@ -116,6 +117,7 @@ public R logDef(String prefix, String method, Callable cl return mgr.rebuild(f); } } catch (Exception e) { + Throwables.throwIfUnchecked(e); throw new RuntimeException(e); } } @@ -133,6 +135,7 @@ public R logDefKeep(String prefix, String method, Callable closure) { mapVariable(var, f); return f; } catch (Exception e) { + Throwables.throwIfUnchecked(e); throw new RuntimeException(e); } } @@ -149,6 +152,7 @@ public R logDefDiscard(String prefix, String method, Callable closure) { undoLast(); return f; } catch (Exception e) { + Throwables.throwIfUnchecked(e); throw new RuntimeException(e); } } @@ -164,6 +168,7 @@ public void logStmt(String prefix, String method, CheckedRunnable closure) { appendStmt(prefix + "." + method); closure.run(); } catch (Exception e) { + Throwables.throwIfUnchecked(e); throw new RuntimeException(e); } } From ab245e7980246b456f373ff5f003d7dc179ad8a2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:25:15 +0200 Subject: [PATCH 032/233] Trace: Add support for BooleanFormulaManager.xor --- .../java_smt/delegate/trace/TraceBooleanFormulaManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 3a8179a0c6..62734b7ac7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -156,7 +156,10 @@ public BooleanFormula or(BooleanFormula... bits) { @Override public BooleanFormula xor(BooleanFormula bits1, BooleanFormula bits2) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format("xor(%s, %s)", logger.toVariable(bits1), logger.toVariable(bits2)), + () -> delegate.xor(bits1, bits2)); } @Override From f5f8f0f1ca11552c8327325cc3fd6f7f107b1725 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:25:40 +0200 Subject: [PATCH 033/233] Trace: Add support for BooleanFormulaManager.extractVariablesAndUFs --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index bf8152a7aa..22bbf3e5a4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -719,7 +719,7 @@ public ImmutableMap extractVariables(Formula f) { @Override public ImmutableMap extractVariablesAndUFs(Formula f) { - throw new UnsupportedOperationException(); + return delegate.extractVariablesAndUFs(f); } @Override From 018dbb8194deb975a06af05d580ca9dd99fb0c2f Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:26:10 +0200 Subject: [PATCH 034/233] Trace: Add support for creating integer constants from Strings --- .../java_smt/delegate/trace/TraceIntegerFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java index 338132499b..2c32ed34d7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -81,7 +81,7 @@ public IntegerFormula makeNumber(BigDecimal number) { @Override public IntegerFormula makeNumber(String pI) { - throw new UnsupportedOperationException(); + return makeNumber(new BigInteger(pI)); } @Override From 01871aca7837d0ad66782e70883c67b6abfae3ef Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 16:49:31 +0200 Subject: [PATCH 035/233] Trace: Add some missing logging for methods in TraceFormulaManager --- .../delegate/trace/TraceFormulaManager.java | 43 ++++++++++++++++--- .../java_smt/delegate/trace/TraceLogger.java | 15 +++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 22bbf3e5a4..379a5f95a7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -665,8 +665,10 @@ public T makeApplication( @Override public FormulaType getFormulaType(T formula) { - // FIXME Add proper tracing - return delegate.getFormulaType(formula); + return logger.logDefDiscard( + "mgr", + String.format("getFormulaType(%s)", logger.toVariable(formula)), + () -> delegate.getFormulaType(formula)); } @Override @@ -698,28 +700,55 @@ public T simplify(T input) throws InterruptedException { @Override public R visit(Formula f, FormulaVisitor rFormulaVisitor) { - return delegate.visit(f, rFormulaVisitor); + return logger.logDefDiscard( + "mgr", + String.format( + "visit(%s, new DefaultFormulaVisitor<>() {" + + "protected Formula visitDefault(Formula f) {" + + "return f;" + + "}})", + logger.toVariable(f)), + () -> delegate.visit(f, rFormulaVisitor)); } @Override public void visitRecursively(Formula f, FormulaVisitor rFormulaVisitor) { - delegate.visitRecursively(f, rFormulaVisitor); + logger.logStmtDiscard( + "mgr", + String.format( + "visitRecursively(%s, new DefaultFormulaVisitor<>() {" + + "protected TraversalProcess visitDefault(Formula f) {" + + "return TraversalProcess.CONTINUE;" + + "}})", + logger.toVariable(f)), + () -> delegate.visitRecursively(f, rFormulaVisitor)); } @Override public T transformRecursively( T f, FormulaTransformationVisitor pFormulaVisitor) { - return delegate.transformRecursively(f, pFormulaVisitor); + return logger.logDefDiscard( + "mgr", + String.format( + "transformRecursively(%s, new FormulaTransformationVisitor(%s) {})", + logger.toVariable(f), "mgr"), + () -> delegate.transformRecursively(f, pFormulaVisitor)); } @Override public ImmutableMap extractVariables(Formula f) { - return delegate.extractVariables(f); + return logger.logDefDiscard( + "mgr", + String.format("extractVariables(%s)", logger.toVariable(f)), + () -> delegate.extractVariables(f)); } @Override public ImmutableMap extractVariablesAndUFs(Formula f) { - return delegate.extractVariablesAndUFs(f); + return logger.logDefDiscard( + "mgr", + String.format("extractVariablesAndUFs(%s)", logger.toVariable(f)), + () -> delegate.extractVariablesAndUFs(f)); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index d2db0dcdb3..ab7f7e48b0 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -173,6 +173,21 @@ public void logStmt(String prefix, String method, CheckedRunnable closure) { } } + /** + * Variant of {@link #logStmt(String, String, CheckedRunnable)} that will remove the call from the + * log after it returned successfully. + */ + public void logStmtDiscard(String prefix, String method, CheckedRunnable closure) { + try { + appendStmt(prefix + "." + method); + closure.run(); + undoLast(); + } catch (Exception e) { + Throwables.throwIfUnchecked(e); + throw new RuntimeException(e); + } + } + /** * Takes a {@link org.sosy_lab.java_smt.api.FormulaType} and returns a Java expression to * construct this type. From bfc4a760525c6e666abec6ec6d6bac5b2db07d62 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:01:33 +0200 Subject: [PATCH 036/233] Trace: Make constructor for TraceFloatingPointFormulaManager package-private --- .../delegate/trace/TraceFloatingPointFormulaManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index 4d4746caff..1e2cc67695 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -27,8 +27,7 @@ public class TraceFloatingPointFormulaManager implements FloatingPointFormulaMan private final FloatingPointFormulaManager delegate; private final TraceLogger logger; - public TraceFloatingPointFormulaManager( - FloatingPointFormulaManager pDelegate, TraceLogger pLogger) { + TraceFloatingPointFormulaManager(FloatingPointFormulaManager pDelegate, TraceLogger pLogger) { delegate = pDelegate; logger = pLogger; } From adb0cbc2049337f382df9a95f5a3508faadccd16 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:01:58 +0200 Subject: [PATCH 037/233] Trace: Add support for creating FloatingPointFormulas from BigDecimals --- .../delegate/trace/TraceFloatingPointFormulaManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index 1e2cc67695..d2a003a11a 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -60,7 +60,12 @@ public FloatingPointFormula makeNumber(BigDecimal n, FloatingPointType type) { @Override public FloatingPointFormula makeNumber( BigDecimal n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeNumber(new BigDecimal(\"%s\"), %s, %s)", + n, logger.printFormulaType(type), printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); } @Override From 73f67971fddc88d379ee2cfc391d894af4f428b9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:02:19 +0200 Subject: [PATCH 038/233] Trace: Fix default rounding mode for BigDecimals --- .../delegate/trace/TraceFloatingPointFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index d2a003a11a..8a82039fc1 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -54,7 +54,7 @@ public FloatingPointFormula makeNumber( @Override public FloatingPointFormula makeNumber(BigDecimal n, FloatingPointType type) { - return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_AWAY); + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override From 69f637eb16f78170c571227eddfa42b09a8fdbc7 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:04:55 +0200 Subject: [PATCH 039/233] Trace: Add support for equality on array formulas --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 379a5f95a7..5f711bb768 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -316,6 +316,10 @@ public T makeApplication( return (T) getBitvectorFormulaManager() .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(1).isArrayType()) { + return (T) + getArrayFormulaManager() + .equivalence((ArrayFormula) args.get(0), (ArrayFormula) args.get(1)); } else { throw new UnsupportedOperationException( String.format( From 9208bb362ecb4aa31a613c3af73dbd94e5fd6c7c Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:15:33 +0200 Subject: [PATCH 040/233] Trace: Add support for boolean formula visitors --- .../trace/TraceBooleanFormulaManager.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 62734b7ac7..6540552a06 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -164,19 +164,40 @@ public BooleanFormula xor(BooleanFormula bits1, BooleanFormula bits2) { @Override public R visit(BooleanFormula pFormula, BooleanFormulaVisitor visitor) { - throw new UnsupportedOperationException(); + return logger.logDefDiscard( + "mgr", + String.format( + "visit(%s, new DefaultBooleanFormulaVisitor<>() {" + + "protected Formula visitDefault(Formula f) {" + + "return %s;" + + "}})", + logger.toVariable(pFormula), logger.toVariable(pFormula)), + () -> delegate.visit(pFormula, visitor)); } @Override public void visitRecursively( BooleanFormula f, BooleanFormulaVisitor rFormulaVisitor) { - throw new UnsupportedOperationException(); + logger.logStmtDiscard( + "mgr", + String.format( + "visitRecursively(%s, new DefaultBooleanFormulaVisitor<>() {" + + "protected TraversalProcess visitDefault(Formula f) {" + + "return TraversalProcess.CONTINUE;" + + "}})", + logger.toVariable(f)), + () -> delegate.visitRecursively(f, rFormulaVisitor)); } @Override public BooleanFormula transformRecursively( BooleanFormula f, BooleanFormulaTransformationVisitor pVisitor) { - throw new UnsupportedOperationException(); + return logger.logDefDiscard( + "mgr", + String.format( + "transformRecursively(%s, new BooleanFormulaTransformationVisitor(%s) {})", + logger.toVariable(f), "mgr"), + () -> delegate.transformRecursively(f, pVisitor)); } @Override From 9065812048112e53ea50efd6fa7c7b95d634a833 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:17:47 +0200 Subject: [PATCH 041/233] Trace: Add FormulaManager.simplify --- .../java_smt/delegate/trace/TraceFormulaManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 5f711bb768..2c461d5bf9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -699,7 +699,10 @@ public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) @Override public T simplify(T input) throws InterruptedException { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr", + String.format("simplify(%s)", logger.toVariable(input)), + () -> delegate.simplify(input)); } @Override From 2c2ca359af116ebbdc5a305c05e7f0cede9a55d4 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:27:35 +0200 Subject: [PATCH 042/233] Trace: Add UFManager.declareAndCallUF --- .../delegate/trace/TraceFormulaManager.java | 2 +- .../java_smt/delegate/trace/TraceUFManager.java | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 2c461d5bf9..406b0b67ca 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -93,7 +93,7 @@ public FloatingPointFormulaManager getFloatingPointFormulaManager() { @Override public UFManager getUFManager() { - return new TraceUFManager(delegate.getUFManager(), logger); + return new TraceUFManager(delegate.getUFManager(), this, logger); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index fd76ac16c4..b0bd5e0bdf 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -12,19 +12,24 @@ import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.List; import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FunctionDeclaration; import org.sosy_lab.java_smt.api.UFManager; public class TraceUFManager implements UFManager { private final UFManager delegate; + + private final FormulaManager mgr; private final TraceLogger logger; - TraceUFManager(UFManager pDelegate, TraceLogger pLogger) { + TraceUFManager(UFManager pDelegate, FormulaManager pMgr, TraceLogger pLogger) { delegate = pDelegate; + mgr = pMgr; logger = pLogger; } @@ -81,12 +86,16 @@ public T callUF(FunctionDeclaration funcType, Formula... @Override public T declareAndCallUF( String name, FormulaType pReturnType, List pArgs) { - throw new UnsupportedOperationException(); + ImmutableList.Builder> builder = ImmutableList.builder(); + for (Formula f : pArgs) { + builder.add(mgr.getFormulaType(f)); + } + return callUF(declareUF(name, pReturnType, builder.build()), pArgs); } @Override public T declareAndCallUF( String name, FormulaType pReturnType, Formula... pArgs) { - throw new UnsupportedOperationException(); + return declareAndCallUF(name, pReturnType, Arrays.asList(pArgs)); } } From 47e937683a540df52ffa68c0e77b6bbed8f0b5a7 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:35:42 +0200 Subject: [PATCH 043/233] Trace: Add modulo, distinct and sum from IntegerFormulaManager --- .../trace/TraceIntegerFormulaManager.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java index 2c32ed34d7..119181dd26 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -10,6 +10,8 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; @@ -50,7 +52,11 @@ public BooleanFormula modularCongruence(IntegerFormula number1, IntegerFormula n @Override public IntegerFormula modulo(IntegerFormula numerator, IntegerFormula denominator) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "modulo(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), + () -> delegate.modulo(numerator, denominator)); } @Override @@ -115,7 +121,12 @@ public IntegerFormula add(IntegerFormula number1, IntegerFormula number2) { @Override public IntegerFormula sum(List operands) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "sum(%s)", + FluentIterable.from(operands).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.sum(operands)); } @Override @@ -153,7 +164,12 @@ public BooleanFormula equal(IntegerFormula number1, IntegerFormula number2) { @Override public BooleanFormula distinct(List pNumbers) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "distinct(%s)", + FluentIterable.from(pNumbers).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.distinct(pNumbers)); } @Override From ac6486dee7c67dfbfd2c462310340194c6200762 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 17:58:47 +0200 Subject: [PATCH 044/233] Trace: Add FormulaManager.substitute --- .../delegate/trace/TraceFormulaManager.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 406b0b67ca..c67ffe12af 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -10,7 +10,9 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.math.BigInteger; @@ -761,7 +763,19 @@ public ImmutableMap extractVariablesAndUFs(Formula f) { @Override public T substitute( T f, Map fromToMapping) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr", + String.format( + "substitute(%s, ImmutableMap.ofEntries(%s))", + logger.toVariable(f), + FluentIterable.from(fromToMapping.entrySet()) + .transform( + entry -> + String.format( + "Map.entry(%s, %s)", + logger.toVariable(entry.getKey()), logger.toVariable(entry.getValue()))) + .join(Joiner.on(", "))), + () -> delegate.substitute(f, fromToMapping)); } @Override From 01cc106fd963222d24dea6be90bdb34238797535 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:03:45 +0200 Subject: [PATCH 045/233] Trace: Add ProverEnvironment.isUnsatWithAssumptions --- .../delegate/trace/TraceBasicProverEnvironment.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index fe202cc466..d046908a3e 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -10,6 +10,8 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -59,7 +61,12 @@ public boolean isUnsat() throws SolverException, InterruptedException { @Override public boolean isUnsatWithAssumptions(Collection assumptions) throws SolverException, InterruptedException { - throw new UnsupportedOperationException(); + return logger.logDefKeep( + logger.toVariable(this), + String.format( + "isUnsatWithAssumptions" + "(ImmutableList.of(%s))", + FluentIterable.from(assumptions).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.isUnsatWithAssumptions(assumptions)); } @SuppressWarnings("resource") From ff2faf23c2a7038d8caf08fd64815a5a502b4760 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:10:22 +0200 Subject: [PATCH 046/233] Trace: Add FormulaManager.applyTactic --- .../java_smt/delegate/trace/TraceFormulaManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index c67ffe12af..951d25b8b4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -696,7 +696,10 @@ public Appender dumpFormula(BooleanFormula pT) { @Override public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) throws InterruptedException, SolverException { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr", + String.format("applyTactic(%s, %s)", logger.toVariable(input), "Tactic" + tactic.name()), + () -> delegate.applyTactic(input, tactic)); } @Override From cb53d5966d7a368bf1393ae9c084cf01e8ada651 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:14:19 +0200 Subject: [PATCH 047/233] Trace: Add isValidName, escape and unescape from FormulaManager --- .../java_smt/delegate/trace/TraceFormulaManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 951d25b8b4..a74a83aa41 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -789,16 +789,16 @@ public BooleanFormula translateFrom(BooleanFormula formula, FormulaManager other @Override public boolean isValidName(String variableName) { - throw new UnsupportedOperationException(); + return delegate.isValidName(variableName); } @Override public String escape(String variableName) { - throw new UnsupportedOperationException(); + return delegate.escape(variableName); } @Override public String unescape(String variableName) { - throw new UnsupportedOperationException(); + return delegate.unescape(variableName); } } From 22d532cf8b2dee0b4ae03b9da58109b574c42edf Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:20:46 +0200 Subject: [PATCH 048/233] Trace: Avoid using String.split --- .../java_smt/delegate/trace/TraceFormulaManager.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index a74a83aa41..eabea24175 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -12,6 +12,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -341,13 +342,13 @@ public T makeApplication( */ case BV_EXTRACT: { - String[] tokens = declaration.getName().split("_"); + List tokens = Splitter.on('_').splitToList(declaration.getName()); return (T) getBitvectorFormulaManager() .extract( (BitvectorFormula) args.get(0), - Integer.parseInt(tokens[1]), - Integer.parseInt(tokens[2])); + Integer.parseInt(tokens.get(1)), + Integer.parseInt(tokens.get(2))); } case BV_CONCAT: return (T) From f30f6944c35ef548f81a445ff43dd9d57d9dda39 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:39:27 +0200 Subject: [PATCH 049/233] Trace: Add toConjunctionArgs and toDisjunctionArgs from BooleanFormulaManager --- .../trace/TraceBooleanFormulaManager.java | 19 ++++++++++++++++--- .../delegate/trace/TraceFormulaManager.java | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 6540552a06..336620e767 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -10,6 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.collect.FluentIterable; import java.util.Arrays; import java.util.Collection; import java.util.Set; @@ -23,10 +24,14 @@ public class TraceBooleanFormulaManager implements BooleanFormulaManager { private final BooleanFormulaManager delegate; + + private final TraceFormulaManager mgr; private final TraceLogger logger; - TraceBooleanFormulaManager(BooleanFormulaManager pDelegate, TraceLogger pLogger) { + TraceBooleanFormulaManager( + BooleanFormulaManager pDelegate, TraceFormulaManager pMgr, TraceLogger pLogger) { delegate = pDelegate; + mgr = pMgr; logger = pLogger; } @@ -202,11 +207,19 @@ public BooleanFormula transformRecursively( @Override public Set toConjunctionArgs(BooleanFormula f, boolean flatten) { - throw new UnsupportedOperationException(); + logger.appendStmt( + String.format("mgr.toConjunctionArgs(%s, %s)", logger.toVariable(f), flatten)); + Set set = delegate.toConjunctionArgs(f, flatten); + logger.undoLast(); + return FluentIterable.from(set).transform(mgr::rebuild).toSet(); } @Override public Set toDisjunctionArgs(BooleanFormula f, boolean flatten) { - throw new UnsupportedOperationException(); + logger.appendStmt( + String.format("mgr.toDisjunctionArgs(%s, %s)", logger.toVariable(f), flatten)); + Set set = delegate.toDisjunctionArgs(f, flatten); + logger.undoLast(); + return FluentIterable.from(set).transform(mgr::rebuild).toSet(); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index eabea24175..56a4929728 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -76,7 +76,7 @@ public RationalFormulaManager getRationalFormulaManager() { @Override public BooleanFormulaManager getBooleanFormulaManager() { - return new TraceBooleanFormulaManager(delegate.getBooleanFormulaManager(), logger); + return new TraceBooleanFormulaManager(delegate.getBooleanFormulaManager(), this, logger); } @Override From 0b36ff27af221f4d494baced9eb83c493108f8a8 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:39:43 +0200 Subject: [PATCH 050/233] Trace: Add toConjunction and toDisjunction --- .../java_smt/delegate/trace/TraceBooleanFormulaManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 336620e767..77d62414ef 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -15,6 +15,7 @@ import java.util.Collection; import java.util.Set; import java.util.stream.Collector; +import java.util.stream.Collectors; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.BooleanFormulaManager; import org.sosy_lab.java_smt.api.Formula; @@ -129,7 +130,7 @@ public BooleanFormula and(BooleanFormula... bits) { @Override public Collector toConjunction() { - throw new UnsupportedOperationException(); + return Collectors.collectingAndThen(Collectors.toList(), this::and); } @Override @@ -156,7 +157,7 @@ public BooleanFormula or(BooleanFormula... bits) { @Override public Collector toDisjunction() { - throw new UnsupportedOperationException(); + return Collectors.collectingAndThen(Collectors.toList(), this::or); } @Override From d57db88d57fac45053f6203c29282947dbb26c93 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:56:27 +0200 Subject: [PATCH 051/233] Trace: Extract terms from to model --- .../trace/TraceBasicProverEnvironment.java | 12 +++++++-- .../java_smt/delegate/trace/TraceModel.java | 27 ++++++++++++++++--- .../trace/TraceProverEnvironment.java | 7 +++-- .../delegate/trace/TraceSolverContext.java | 2 +- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index d046908a3e..5fde85c0e2 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -23,10 +23,16 @@ public class TraceBasicProverEnvironment implements BasicProverEnvironment { private final BasicProverEnvironment delegate; + + private final TraceFormulaManager mgr; private final TraceLogger logger; - TraceBasicProverEnvironment(BasicProverEnvironment pDelegate, TraceLogger pLogger) { + TraceBasicProverEnvironment( + BasicProverEnvironment pDelegate, + TraceFormulaManager pFormulaManager, + TraceLogger pLogger) { delegate = pDelegate; + mgr = pFormulaManager; logger = pLogger; } @@ -73,7 +79,9 @@ public boolean isUnsatWithAssumptions(Collection assumptions) @Override public Model getModel() throws SolverException { return logger.logDefKeep( - logger.toVariable(this), "getModel()", () -> new TraceModel(delegate.getModel(), logger)); + logger.toVariable(this), + "getModel()", + () -> new TraceModel(delegate.getModel(), mgr, logger)); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java index e884b1a0a3..7c188037b4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java @@ -10,6 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import java.math.BigInteger; import org.checkerframework.checker.nullness.qual.Nullable; @@ -27,18 +28,36 @@ public class TraceModel implements Model { private final Model delegate; + + private final TraceFormulaManager mgr; private final TraceLogger logger; - TraceModel(Model pDelegate, TraceLogger pLogger) { + TraceModel(Model pDelegate, TraceFormulaManager pMgr, TraceLogger pLogger) { delegate = pDelegate; + mgr = pMgr; logger = pLogger; } @Override public ImmutableList asList() { - // FIXME We need to introduce local variables for all terms in the model so that they can be - // referenced later - return logger.logDefKeep(logger.toVariable(this), "asList()", delegate::asList); + logger.appendStmt(String.format("%s.asList()", logger.toVariable(this))); + ImmutableList result = delegate.asList(); + logger.undoLast(); + return FluentIterable.from(result) + .transform( + (ValueAssignment assigment) -> { + var key = mgr.rebuild(assigment.getKey()); + var val = mgr.rebuild(assigment.getValueAsFormula()); + var map = mgr.rebuild(assigment.getAssignmentAsFormula()); + return new ValueAssignment( + key, + val, + map, + assigment.getName(), + assigment.getValue(), + assigment.getArgumentsInterpretation()); + }) + .toList(); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java index d8c1e79ef6..ec11ef5710 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceProverEnvironment.java @@ -15,7 +15,10 @@ public class TraceProverEnvironment extends TraceBasicProverEnvironment implements ProverEnvironment { - TraceProverEnvironment(BasicProverEnvironment pDelegate, TraceLogger pLogger) { - super(pDelegate, pLogger); + TraceProverEnvironment( + BasicProverEnvironment pDelegate, + TraceFormulaManager pFormulaManager, + TraceLogger pLogger) { + super(pDelegate, pFormulaManager, pLogger); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 3524b6c0c2..0205f5d45d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -86,7 +86,7 @@ public ProverEnvironment newProverEnvironment(ProverOptions... options) { FluentIterable.from(options) .transform(v -> "SolverContext" + ".ProverOptions." + v.name()) .join(Joiner.on(", "))), - () -> new TraceProverEnvironment(delegate.newProverEnvironment(options), logger)); + () -> new TraceProverEnvironment(delegate.newProverEnvironment(options), mgr, logger)); } @SuppressWarnings("resource") From 49cb3bdd2db4fda3686d32f65142d083babe256c Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 18:57:58 +0200 Subject: [PATCH 052/233] Trace: Always print the term kind if we encounter an unsupported term in the visitor --- .../delegate/trace/TraceFormulaManager.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 56a4929728..2482de7597 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -228,6 +228,7 @@ public T makeApplication( } else { // TODO Check that the number of arguments matches the arity of the operation // TODO Figure out how to handle rounding mode for floats + // FIXME Handle rational formulas switch (declaration.getKind()) { case AND: return (T) @@ -254,9 +255,11 @@ public T makeApplication( return (T) getBooleanFormulaManager() .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + // TODO We only have 'distinct' for some theories + /* case DISTINCT: - // TODO We only have 'distinct' for some theories break; + */ case STORE: return (T) getArrayFormulaManager().store((ArrayFormula) args.get(0), args.get(1), args.get(2)); @@ -267,7 +270,6 @@ public T makeApplication( getArrayFormulaManager() .makeArray((ArrayFormulaType) declaration.getType(), args.get(0)); case UMINUS: - // FIXME Handle rational formulas return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); case SUB: return (T) @@ -330,6 +332,7 @@ public T makeApplication( declaration.getArgumentTypes().get(0))); } } + // TODO /* case EQ_ZERO: break; @@ -354,12 +357,12 @@ public T makeApplication( return (T) getBitvectorFormulaManager() .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - case BV_SIGN_EXTENSION: - // TODO + // TODO + /*case BV_SIGN_EXTENSION: break; case BV_ZERO_EXTENSION: - // TODO break; + */ case BV_NOT: return (T) getBitvectorFormulaManager().not((BitvectorFormula) args.get(0)); case BV_NEG: @@ -471,12 +474,13 @@ public T makeApplication( return (T) getBitvectorFormulaManager() .rotateRight((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + // TODO + /* case BV_ROTATE_LEFT_BY_INT: - // TODO break; case BV_ROTATE_RIGHT_BY_INT: - // TODO break; + */ case BV_UCASTTO_FP: return (T) getFloatingPointFormulaManager() @@ -544,6 +548,8 @@ public T makeApplication( getFloatingPointFormulaManager() .equalWithFPSemantics( (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + // TODO + /* case FP_ROUND_EVEN: break; case FP_ROUND_AWAY: @@ -554,6 +560,7 @@ public T makeApplication( break; case FP_ROUND_ZERO: break; + */ case FP_ROUND_TO_INTEGRAL: { var rm = (FloatingPointRoundingModeFormula) args.get(1); @@ -596,6 +603,7 @@ public T makeApplication( getFloatingPointFormulaManager() .fromIeeeBitvector( (BitvectorFormula) args.get(0), (FloatingPointType) declaration.getType()); + // TODO /* case STR_CONCAT: break; @@ -661,7 +669,6 @@ public T makeApplication( declaration.getKind(), declaration.getName())); } } - throw new UnsupportedOperationException(); } @Override From b2fda6ddc7226684d7cc416d251aa74ebf8bbae9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 19:10:40 +0200 Subject: [PATCH 053/233] Trace: Store backtracking points for the logger on a stack --- .../java_smt/delegate/trace/TraceLogger.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index ab7f7e48b0..2f2f1a57be 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -17,6 +17,7 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.Stack; import java.util.concurrent.Callable; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; @@ -31,7 +32,7 @@ class TraceLogger { private final Map valueMap = new HashMap<>(); private final RandomAccessFile output; - private long backtrackPoint = -1; + private final Stack lastLines = new Stack<>(); TraceLogger(TraceFormulaManager pMgr, String pFile) { mgr = pMgr; @@ -76,7 +77,7 @@ public String toVariable(Object f) { /** Add a definition to the log. */ public void appendDef(String pVar, String pExpr) { try { - backtrackPoint = output.length(); + lastLines.push(output.length()); output.write(String.format("var %s = %s;%n", pVar, pExpr).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new RuntimeException(e); @@ -86,7 +87,7 @@ public void appendDef(String pVar, String pExpr) { /** Add a statement to the log. */ public void appendStmt(String pStmt) { try { - backtrackPoint = output.length(); + lastLines.push(output.length()); output.write(String.format("%s;%n", pStmt).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new RuntimeException(e); @@ -94,13 +95,12 @@ public void appendStmt(String pStmt) { } public void undoLast() { - Preconditions.checkArgument(backtrackPoint >= 0, "Cannot undo last trace"); + Preconditions.checkArgument(!lastLines.isEmpty(), "Cannot undo last trace"); try { - output.setLength(backtrackPoint); + output.setLength(lastLines.pop()); } catch (IOException pE) { throw new RuntimeException(pE); } - backtrackPoint = -1; } /** Log an API call with return value. */ From 3e3540eb573fde16aec826e08ac52575b4f3b5cb Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 19:20:57 +0200 Subject: [PATCH 054/233] Trace: Add support for unsat core --- .../trace/TraceBasicProverEnvironment.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index 5fde85c0e2..396ca37337 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -86,13 +86,23 @@ public Model getModel() throws SolverException { @Override public List getUnsatCore() { - throw new UnsupportedOperationException(); + logger.appendStmt(String.format("%s.getUnsatCore()", logger.toVariable(this))); + List core = delegate.getUnsatCore(); + logger.undoLast(); + return FluentIterable.from(core).transform(mgr::rebuild).toList(); } @Override public Optional> unsatCoreOverAssumptions( Collection assumptions) throws SolverException, InterruptedException { - throw new UnsupportedOperationException(); + logger.appendStmt( + String.format( + "%s.getUnsatCoreOverAssumptions(ImmutableList.of(%s))", + logger.toVariable(this), + FluentIterable.from(assumptions).transform(logger::toVariable).join(Joiner.on(", ")))); + Optional> maybeCore = delegate.unsatCoreOverAssumptions(assumptions); + logger.undoLast(); + return maybeCore.map(core -> FluentIterable.from(core).transform(mgr::rebuild).toList()); } @Override From 959abe9e88766abe1fde6091e9f47aaddf87a8ca Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 19:48:01 +0200 Subject: [PATCH 055/233] Trace: Inline logger calls in addConstraint, isUnsat, isUnstaWithAssumptions and getModel to make sure we're not catching Solver/InterruptedExceptions --- .../trace/TraceBasicProverEnvironment.java | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index 396ca37337..56d104fd50 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -43,10 +43,14 @@ public void pop() { @Override public @Nullable T addConstraint(BooleanFormula constraint) throws InterruptedException { - return logger.logDefKeep( - logger.toVariable(this), - String.format("addConstraint(%s)", logger.toVariable(constraint)), - () -> delegate.addConstraint(constraint)); + String var = logger.newVariable(); + logger.appendDef( + var, + String.format( + "%s.addConstraint(%s)", logger.toVariable(this), logger.toVariable(constraint))); + T f = delegate.addConstraint(constraint); + logger.mapVariable(var, f); + return f; } @Override @@ -61,27 +65,36 @@ public int size() { @Override public boolean isUnsat() throws SolverException, InterruptedException { - return logger.logDefKeep(logger.toVariable(this), "isUnsat()", delegate::isUnsat); + String var = logger.newVariable(); + logger.appendDef(var, String.format("%s.isUnsat()", logger.toVariable(this))); + boolean unsat = delegate.isUnsat(); + logger.mapVariable(var, unsat); + return unsat; } @Override public boolean isUnsatWithAssumptions(Collection assumptions) throws SolverException, InterruptedException { - return logger.logDefKeep( - logger.toVariable(this), + String var = logger.newVariable(); + logger.appendDef( + var, String.format( - "isUnsatWithAssumptions" + "(ImmutableList.of(%s))", - FluentIterable.from(assumptions).transform(logger::toVariable).join(Joiner.on(", "))), - () -> delegate.isUnsatWithAssumptions(assumptions)); + "%s.isUnsatWithAssumptions(ImmutableList.of(%s))", + logger.toVariable(this), + FluentIterable.from(assumptions).transform(logger::toVariable).join(Joiner.on(", ")))); + boolean unsat = delegate.isUnsatWithAssumptions(assumptions); + logger.mapVariable(var, unsat); + return unsat; } @SuppressWarnings("resource") @Override public Model getModel() throws SolverException { - return logger.logDefKeep( - logger.toVariable(this), - "getModel()", - () -> new TraceModel(delegate.getModel(), mgr, logger)); + String var = logger.newVariable(); + logger.appendDef(var, String.format("%s.getModel()", logger.toVariable(this))); + Model model = new TraceModel(delegate.getModel(), mgr, logger); + logger.mapVariable(var, model); + return model; } @Override From e7fae4efa665d67f7be1202777aea737ea20c1cc Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 22:47:14 +0200 Subject: [PATCH 056/233] Trace: Check operator arity in the visitor --- .../delegate/trace/TraceFormulaManager.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 2482de7597..bdeee3292d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -215,6 +215,115 @@ public T makeVariable(FormulaType formulaType, String nam return f; } + private int getArity(FunctionDeclarationKind pKind) { + switch (pKind) { + case AND: + case OR: + case IFF: + case XOR: + case IMPLIES: + case DISTINCT: + case SUB: + case ADD: + case DIV: + case MUL: + case LT: + case LTE: + case GT: + case GTE: + case EQ: + case BV_CONCAT: + case BV_OR: + case BV_AND: + case BV_XOR: + case BV_SUB: + case BV_ADD: + case BV_MUL: + return -1; + + case FP_ROUND_EVEN: + case FP_ROUND_AWAY: + case FP_ROUND_POSITIVE: + case FP_ROUND_NEGATIVE: + case FP_ROUND_ZERO: + return 0; + + case NOT: + case UMINUS: + case EQ_ZERO: + case GTE_ZERO: + case FLOOR: + case TO_REAL: + case CONST: + case BV_EXTRACT: + case BV_SIGN_EXTENSION: + case BV_ZERO_EXTENSION: + case BV_NOT: + case BV_NEG: + case BV_ROTATE_LEFT_BY_INT: + case BV_ROTATE_RIGHT_BY_INT: + case FP_NEG: + case FP_ABS: + case FP_IS_NAN: + case FP_IS_INF: + case FP_IS_ZERO: + case FP_IS_NEGATIVE: + case FP_IS_SUBNORMAL: + case FP_IS_NORMAL: + case FP_AS_IEEEBV: + case FP_FROM_IEEEBV: + return 1; + + case SELECT: + case MODULO: + case BV_SDIV: + case BV_UDIV: + case BV_SREM: + case BV_UREM: + case BV_SMOD: + case BV_ULT: + case BV_SLT: + case BV_ULE: + case BV_SLE: + case BV_UGT: + case BV_SGT: + case BV_UGE: + case BV_SGE: + case BV_SHL: + case BV_LSHR: + case BV_ASHR: + case BV_ROTATE_LEFT: + case BV_ROTATE_RIGHT: + case BV_UCASTTO_FP: + case BV_SCASTTO_FP: + case FP_MAX: + case FP_MIN: + case FP_SQRT: + case FP_REM: + case FP_LT: + case FP_LE: + case FP_GE: + case FP_GT: + case FP_EQ: + case FP_ROUND_TO_INTEGRAL: + case FP_CASTTO_FP: + case FP_CASTTO_SBV: + case FP_CASTTO_UBV: + return 2; + + case ITE: + case STORE: + case FP_SUB: + case FP_ADD: + case FP_DIV: + case FP_MUL: + return 3; + + default: + throw new IllegalArgumentException(String.format("Unsupported kind: %s", pKind)); + } + } + @SuppressWarnings("unchecked") @Override public T makeApplication( @@ -229,6 +338,15 @@ public T makeApplication( // TODO Check that the number of arguments matches the arity of the operation // TODO Figure out how to handle rounding mode for floats // FIXME Handle rational formulas + Preconditions.checkArgument( + getArity(declaration.getKind()) == -1 + ? args.size() > 1 + : args.size() == getArity(declaration.getKind()), + "Term \"%s\" (%s): expecting %s arguments, but found %s", + declaration.getName(), + declaration.getKind(), + getArity(declaration.getKind()), + args.size()); switch (declaration.getKind()) { case AND: return (T) From feb9e8f064ec36950d402e72ed6e9f153c1f0f48 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 23:07:46 +0200 Subject: [PATCH 057/233] Trace: Add guards for binary operators that should really allow an arbitrary number of arguments --- .../delegate/trace/TraceFormulaManager.java | 186 ++++++++++++------ 1 file changed, 121 insertions(+), 65 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index bdeee3292d..30ce6e1571 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -335,9 +335,9 @@ public T makeApplication( declaration.getName(), declaration.getType(), declaration.getArgumentTypes()); return getUFManager().callUF(uf, args); } else { - // TODO Check that the number of arguments matches the arity of the operation + // TODO Handle operations with a variable number of arguments // TODO Figure out how to handle rounding mode for floats - // FIXME Handle rational formulas + // TODO Handle rational formulas Preconditions.checkArgument( getArity(declaration.getKind()) == -1 ? args.size() > 1 @@ -349,30 +349,36 @@ public T makeApplication( args.size()); switch (declaration.getKind()) { case AND: - return (T) - getBooleanFormulaManager() - .and((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + return (T) getBooleanFormulaManager().and((List) args); case NOT: return (T) getBooleanFormulaManager().not((BooleanFormula) args.get(0)); case OR: - return (T) - getBooleanFormulaManager() - .or((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + return (T) getBooleanFormulaManager().or((List) args); case IFF: - return (T) - getBooleanFormulaManager() - .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBooleanFormulaManager() + .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + } case ITE: return getBooleanFormulaManager() .ifThenElse((BooleanFormula) args.get(0), (T) args.get(1), (T) args.get(2)); case XOR: - return (T) - getBooleanFormulaManager() - .xor((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + + return (T) + getBooleanFormulaManager() + .xor((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + } case IMPLIES: - return (T) - getBooleanFormulaManager() - .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBooleanFormulaManager() + .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + } // TODO We only have 'distinct' for some theories /* case DISTINCT: @@ -390,43 +396,69 @@ public T makeApplication( case UMINUS: return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); case SUB: - return (T) - getIntegerFormulaManager() - .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case ADD: - return (T) - getIntegerFormulaManager() - .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case DIV: - return (T) - getIntegerFormulaManager() - .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + + return (T) + getIntegerFormulaManager() + .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case MUL: - return (T) - getIntegerFormulaManager() - .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case MODULO: return (T) getIntegerFormulaManager() .modulo((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); case LT: - return (T) - getIntegerFormulaManager() - .lessThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .lessThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case LTE: - return (T) - getIntegerFormulaManager() - .lessOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .lessOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case GT: - return (T) - getIntegerFormulaManager() - .greaterThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .greaterThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case GTE: - return (T) - getIntegerFormulaManager() - .greaterOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getIntegerFormulaManager() + .greaterOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } case EQ: { + Preconditions.checkArgument(args.size() == 2); if (declaration.getArgumentTypes().get(0).isBooleanType()) { return (T) getBooleanFormulaManager() @@ -472,9 +504,12 @@ public T makeApplication( Integer.parseInt(tokens.get(2))); } case BV_CONCAT: - return (T) - getBitvectorFormulaManager() - .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } // TODO /*case BV_SIGN_EXTENSION: break; @@ -486,25 +521,40 @@ public T makeApplication( case BV_NEG: return (T) getBitvectorFormulaManager().negate((BitvectorFormula) args.get(0)); case BV_OR: - return (T) - getBitvectorFormulaManager() - .or((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .or((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_AND: - return (T) - getBitvectorFormulaManager() - .and((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .and((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_XOR: - return (T) - getBitvectorFormulaManager() - .xor((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .xor((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_SUB: - return (T) - getBitvectorFormulaManager() - .subtract((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .subtract((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_ADD: - return (T) - getBitvectorFormulaManager() - .add((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .add((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_SDIV: return (T) getBitvectorFormulaManager() @@ -526,9 +576,12 @@ public T makeApplication( getBitvectorFormulaManager() .smodulo((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_MUL: - return (T) - getBitvectorFormulaManager() - .multiply((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .multiply((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_ULT: return (T) getBitvectorFormulaManager() @@ -568,9 +621,12 @@ public T makeApplication( .greaterOrEquals( (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); case BV_EQ: // FIXME Why is this a separate symbol? - return (T) - getBitvectorFormulaManager() - .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + { + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } case BV_SHL: return (T) getBitvectorFormulaManager() From 3a56e85583ba327490a24614a2fded0dd31945b8 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 23:12:44 +0200 Subject: [PATCH 058/233] Trace: Add missing "." when printing the names of Tactics to the log --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 30ce6e1571..76aa2a239f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -880,7 +880,7 @@ public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) throws InterruptedException, SolverException { return logger.logDef( "mgr", - String.format("applyTactic(%s, %s)", logger.toVariable(input), "Tactic" + tactic.name()), + String.format("applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name()), () -> delegate.applyTactic(input, tactic)); } From f00a5a07ff3141d91e1826a83705d2c447e6b596 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 23:23:14 +0200 Subject: [PATCH 059/233] Trace: Fix a bug in TraceLogger.logDef We need to rebuild the term when it's *not* already tracked --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 2f2f1a57be..3394f16fb7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -109,11 +109,11 @@ public R logDef(String prefix, String method, Callable cl try { appendDef(var, prefix + "." + method); R f = closure.call(); - if (!isTracked(f)) { - mapVariable(var, f); + if (isTracked(f)) { + undoLast(); return f; } else { - undoLast(); + mapVariable(var, f); return mgr.rebuild(f); } } catch (Exception e) { From da00665c7dd23c292c4689679e8fae7583b9ba54 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 23:29:44 +0200 Subject: [PATCH 060/233] Trace: Improve error messages when checking the arity of an unknown operator --- .../delegate/trace/TraceFormulaManager.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 76aa2a239f..f9af6ac520 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -215,8 +215,8 @@ public T makeVariable(FormulaType formulaType, String nam return f; } - private int getArity(FunctionDeclarationKind pKind) { - switch (pKind) { + private int getArity(FunctionDeclaration pDeclaration) { + switch (pDeclaration.getKind()) { case AND: case OR: case IFF: @@ -320,7 +320,9 @@ private int getArity(FunctionDeclarationKind pKind) { return 3; default: - throw new IllegalArgumentException(String.format("Unsupported kind: %s", pKind)); + throw new IllegalArgumentException( + String.format( + "Unsupported kind: \"%s\" (%s)", pDeclaration.getName(), pDeclaration.getKind())); } } @@ -339,13 +341,11 @@ public T makeApplication( // TODO Figure out how to handle rounding mode for floats // TODO Handle rational formulas Preconditions.checkArgument( - getArity(declaration.getKind()) == -1 - ? args.size() > 1 - : args.size() == getArity(declaration.getKind()), + getArity(declaration) == -1 ? args.size() > 1 : args.size() == getArity(declaration), "Term \"%s\" (%s): expecting %s arguments, but found %s", declaration.getName(), declaration.getKind(), - getArity(declaration.getKind()), + getArity(declaration), args.size()); switch (declaration.getKind()) { case AND: From 7bcef2f0a44aa81b289cbf03181a4c4d929e4f38 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 24 Aug 2025 23:43:31 +0200 Subject: [PATCH 061/233] Trace: Don't rewrite and/or terms with more than 2 arguments --- .../trace/TraceBooleanFormulaManager.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 77d62414ef..710e2f577c 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -10,6 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; import java.util.Arrays; import java.util.Collection; @@ -116,11 +117,12 @@ public BooleanFormula and(BooleanFormula formula1, BooleanFormula formula2) { @Override public BooleanFormula and(Collection bits) { - BooleanFormula f = makeTrue(); - for (BooleanFormula bf : bits) { - f = and(bf, f); - } - return f; + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format( + "and(%s)", + FluentIterable.from(bits).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.and(bits)); } @Override @@ -143,11 +145,12 @@ public BooleanFormula or(BooleanFormula formula1, BooleanFormula formula2) { @Override public BooleanFormula or(Collection bits) { - BooleanFormula f = makeFalse(); - for (BooleanFormula bf : bits) { - f = or(bf, f); - } - return f; + return logger.logDef( + "mgr.getBooleanFormulaManager()", + String.format( + "or(%s)", + FluentIterable.from(bits).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.or(bits)); } @Override From 7169aca8f4aaeb76198990dcc38041fe5cec5130 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 25 Aug 2025 02:55:43 +0200 Subject: [PATCH 062/233] Trace: Fix a bug in TraceFormulaManager.makeVariable --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index f9af6ac520..ce29854aad 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -211,6 +211,8 @@ public T makeVariable(FormulaType formulaType, String nam T f = delegate.makeVariable(formulaType, name); if (logger.isTracked(f)) { logger.undoLast(); + } else { + logger.mapVariable(var, f); } return f; } From 10c38f6ab0988cfc26ebec863a439c12c6e10a0f Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 25 Aug 2025 03:52:44 +0200 Subject: [PATCH 063/233] Trace: Add support for rational formulas --- .../delegate/trace/TraceFormulaManager.java | 105 ++++++++--- .../trace/TraceIntegerFormulaManager.java | 175 +++--------------- .../trace/TraceNumeralFormulaManager.java | 170 +++++++++++++++++ .../trace/TraceRationalFormulaManager.java | 56 ++++++ 4 files changed, 323 insertions(+), 183 deletions(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index ce29854aad..1184f7daff 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import org.sosy_lab.common.Appender; +import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.api.ArrayFormula; import org.sosy_lab.java_smt.api.ArrayFormulaManager; import org.sosy_lab.java_smt.api.BitvectorFormula; @@ -39,7 +40,9 @@ import org.sosy_lab.java_smt.api.FunctionDeclaration; import org.sosy_lab.java_smt.api.FunctionDeclarationKind; import org.sosy_lab.java_smt.api.IntegerFormulaManager; +import org.sosy_lab.java_smt.api.NumeralFormula; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; +import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; import org.sosy_lab.java_smt.api.RationalFormulaManager; @@ -71,7 +74,7 @@ public IntegerFormulaManager getIntegerFormulaManager() { @Override public RationalFormulaManager getRationalFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceRationalFormulaManager(delegate.getRationalFormulaManager(), logger); } @Override @@ -167,6 +170,13 @@ public Formula visitConstant(Formula f, Object value) { String.format("makeNumber(%s)", value), () -> delegate.getIntegerFormulaManager().makeNumber((BigInteger) value)); Preconditions.checkArgument(g.equals(f)); + } else if (f instanceof RationalFormula && value instanceof Rational) { + var g = + logger.logDef( + "mgr.getRationalFormulaManager()", + String.format("makeNumber(%s)", value), + () -> delegate.getRationalFormulaManager().makeNumber((Rational) value)); + Preconditions.checkArgument(g.equals(f)); } else { throw new IllegalArgumentException( String.format( @@ -396,35 +406,64 @@ public T makeApplication( getArrayFormulaManager() .makeArray((ArrayFormulaType) declaration.getType(), args.get(0)); case UMINUS: - return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); + { + if (declaration.getType().isIntegerType()) { + return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); + } else { + return (T) getRationalFormulaManager().negate((NumeralFormula) args.get(0)); + } + } case SUB: { Preconditions.checkArgument(args.size() == 2); - return (T) - getIntegerFormulaManager() - .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .subtract((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } } case ADD: { Preconditions.checkArgument(args.size() == 2); - return (T) - getIntegerFormulaManager() - .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .add((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } } case DIV: { Preconditions.checkArgument(args.size() == 2); - - return (T) - getIntegerFormulaManager() - .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .divide((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } } case MUL: { Preconditions.checkArgument(args.size() == 2); - return (T) - getIntegerFormulaManager() - .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .multiply((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } } case MODULO: return (T) @@ -434,29 +473,29 @@ public T makeApplication( { Preconditions.checkArgument(args.size() == 2); return (T) - getIntegerFormulaManager() - .lessThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + getRationalFormulaManager() + .lessThan((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case LTE: { Preconditions.checkArgument(args.size() == 2); return (T) - getIntegerFormulaManager() - .lessOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + getRationalFormulaManager() + .lessOrEquals((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case GT: { Preconditions.checkArgument(args.size() == 2); return (T) - getIntegerFormulaManager() - .greaterThan((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + getRationalFormulaManager() + .greaterThan((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case GTE: { Preconditions.checkArgument(args.size() == 2); return (T) - getIntegerFormulaManager() - .greaterOrEquals((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + getRationalFormulaManager() + .greaterOrEquals((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case EQ: { @@ -465,15 +504,15 @@ public T makeApplication( return (T) getBooleanFormulaManager() .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - } else if (declaration.getArgumentTypes().get(1).isIntegerType()) { + } else if (declaration.getArgumentTypes().get(0).isNumeralType()) { return (T) - getIntegerFormulaManager() - .equal((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); - } else if (declaration.getArgumentTypes().get(1).isBitvectorType()) { + getRationalFormulaManager() + .equal((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(0).isBitvectorType()) { return (T) getBitvectorFormulaManager() .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } else if (declaration.getArgumentTypes().get(1).isArrayType()) { + } else if (declaration.getArgumentTypes().get(0).isArrayType()) { return (T) getArrayFormulaManager() .equivalence((ArrayFormula) args.get(0), (ArrayFormula) args.get(1)); @@ -490,11 +529,17 @@ public T makeApplication( break; case GTE_ZERO: break; - case FLOOR: - break; case TO_REAL: break; */ + case FLOOR: + { + if (args.get(0) instanceof IntegerFormula) { + return (T) getIntegerFormulaManager().floor((IntegerFormula) args.get(0)); + } else { + return (T) getRationalFormulaManager().floor((NumeralFormula) args.get(0)); + } + } case BV_EXTRACT: { List tokens = Splitter.on('_').splitToList(declaration.getName()); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java index 119181dd26..6a413d9238 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -10,205 +10,74 @@ package org.sosy_lab.java_smt.delegate.trace; -import com.google.common.base.Joiner; -import com.google.common.collect.FluentIterable; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.List; import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.IntegerFormulaManager; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; -public class TraceIntegerFormulaManager implements IntegerFormulaManager { +public class TraceIntegerFormulaManager + extends TraceNumeralFormulaManager + implements IntegerFormulaManager { private final IntegerFormulaManager delegate; private final TraceLogger logger; TraceIntegerFormulaManager(IntegerFormulaManager pDelegate, TraceLogger pLogger) { + super(pDelegate, pLogger); delegate = pDelegate; logger = pLogger; } - @Override - public BooleanFormula modularCongruence( - IntegerFormula number1, IntegerFormula number2, BigInteger n) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format( - "modularCongruence(%s, %s, new BigInteger(\"%s\"))", - logger.toVariable(number1), logger.toVariable(number2), n), - () -> delegate.modularCongruence(number1, number2, n)); - } - - @Override - public BooleanFormula modularCongruence(IntegerFormula number1, IntegerFormula number2, long n) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format( - "modularCongruence(%s, %s, %s)", - logger.toVariable(number1), logger.toVariable(number2), n), - () -> delegate.modularCongruence(number1, number2, n)); - } - - @Override - public IntegerFormula modulo(IntegerFormula numerator, IntegerFormula denominator) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format( - "modulo(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), - () -> delegate.modulo(numerator, denominator)); - } - - @Override - public IntegerFormula makeNumber(long number) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(%s)", number), - () -> delegate.makeNumber(number)); - } - - @Override - public IntegerFormula makeNumber(BigInteger number) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(new BigInteger(\"%s\"))", number), - () -> delegate.makeNumber(number)); - } - @Override public IntegerFormula makeNumber(double number) { - throw new UnsupportedOperationException(); + return makeNumber(BigDecimal.valueOf(number)); } @Override public IntegerFormula makeNumber(BigDecimal number) { - throw new UnsupportedOperationException(); + return makeNumber(Rational.ofBigDecimal(number)); } @Override public IntegerFormula makeNumber(String pI) { - return makeNumber(new BigInteger(pI)); + return makeNumber(new BigDecimal(pI)); } @Override public IntegerFormula makeNumber(Rational pRational) { - throw new UnsupportedOperationException(); - } - - @Override - public IntegerFormula makeVariable(String pVar) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeVariable(\"%s\")", pVar), - () -> delegate.makeVariable(pVar)); - } - - @Override - public IntegerFormula negate(IntegerFormula number) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("negate(%s)", logger.toVariable(number)), - () -> delegate.negate(number)); - } - - @Override - public IntegerFormula add(IntegerFormula number1, IntegerFormula number2) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.add(number1, number2)); - } - - @Override - public IntegerFormula sum(List operands) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format( - "sum(%s)", - FluentIterable.from(operands).transform(logger::toVariable).join(Joiner.on(", "))), - () -> delegate.sum(operands)); - } - - @Override - public IntegerFormula subtract(IntegerFormula number1, IntegerFormula number2) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.subtract(number1, number2)); - } - - @Override - public IntegerFormula divide(IntegerFormula numerator, IntegerFormula denominator) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format( - "divide(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), - () -> delegate.divide(numerator, denominator)); - } - - @Override - public IntegerFormula multiply(IntegerFormula number1, IntegerFormula number2) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.multiply(number1, number2)); - } - - @Override - public BooleanFormula equal(IntegerFormula number1, IntegerFormula number2) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("equal(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.equal(number1, number2)); - } - - @Override - public BooleanFormula distinct(List pNumbers) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format( - "distinct(%s)", - FluentIterable.from(pNumbers).transform(logger::toVariable).join(Joiner.on(", "))), - () -> delegate.distinct(pNumbers)); + var num = makeNumber(pRational.getNum()); + var den = makeNumber(pRational.getDen()); + return divide(num, den); } @Override - public BooleanFormula greaterThan(IntegerFormula number1, IntegerFormula number2) { + public BooleanFormula modularCongruence( + IntegerFormula number1, IntegerFormula number2, BigInteger n) { return logger.logDef( "mgr.getIntegerFormulaManager()", String.format( - "greaterThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.greaterThan(number1, number2)); + "modularCongruence(%s, %s, new BigInteger(\"%s\"))", + logger.toVariable(number1), logger.toVariable(number2), n), + () -> delegate.modularCongruence(number1, number2, n)); } @Override - public BooleanFormula greaterOrEquals(IntegerFormula number1, IntegerFormula number2) { + public BooleanFormula modularCongruence(IntegerFormula number1, IntegerFormula number2, long n) { return logger.logDef( "mgr.getIntegerFormulaManager()", String.format( - "greaterOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.greaterOrEquals(number1, number2)); - } - - @Override - public BooleanFormula lessThan(IntegerFormula number1, IntegerFormula number2) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("lessThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.lessThan(number1, number2)); + "modularCongruence(%s, %s, %s)", + logger.toVariable(number1), logger.toVariable(number2), n), + () -> delegate.modularCongruence(number1, number2, n)); } @Override - public BooleanFormula lessOrEquals(IntegerFormula number1, IntegerFormula number2) { + public IntegerFormula modulo(IntegerFormula numerator, IntegerFormula denominator) { return logger.logDef( "mgr.getIntegerFormulaManager()", String.format( - "lessOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.lessOrEquals(number1, number2)); - } - - @Override - public IntegerFormula floor(IntegerFormula formula) { - throw new UnsupportedOperationException(); + "modulo(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), + () -> delegate.modulo(numerator, denominator)); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java new file mode 100644 index 0000000000..8a0503ef71 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -0,0 +1,170 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; +import java.math.BigInteger; +import java.util.List; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.NumeralFormula; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; +import org.sosy_lab.java_smt.api.NumeralFormulaManager; + +@SuppressWarnings("InterfaceTypeParameterName") +public abstract class TraceNumeralFormulaManager< + ParamFormulaType extends NumeralFormula, ResultFormulaType extends NumeralFormula> + implements NumeralFormulaManager { + private final NumeralFormulaManager delegate; + private final TraceLogger logger; + + TraceNumeralFormulaManager( + NumeralFormulaManager pDelegate, TraceLogger pLogger) { + delegate = pDelegate; + logger = pLogger; + } + + @Override + public ResultFormulaType makeNumber(long number) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(%s)", number), + () -> delegate.makeNumber(number)); + } + + @Override + public ResultFormulaType makeNumber(BigInteger number) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(new BigInteger(\"%s\"))", number), + () -> delegate.makeNumber(number)); + } + + @Override + public ResultFormulaType makeVariable(String pVar) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeVariable(\"%s\")", pVar), + () -> delegate.makeVariable(pVar)); + } + + @Override + public ResultFormulaType negate(ParamFormulaType number) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("negate(%s)", logger.toVariable(number)), + () -> delegate.negate(number)); + } + + @Override + public ResultFormulaType add(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.add(number1, number2)); + } + + @Override + public ResultFormulaType sum(List operands) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "sum(%s)", + FluentIterable.from(operands).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.sum(operands)); + } + + @Override + public ResultFormulaType subtract(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.subtract(number1, number2)); + } + + @Override + public ResultFormulaType divide(ParamFormulaType numerator, ParamFormulaType denominator) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "divide(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), + () -> delegate.divide(numerator, denominator)); + } + + @Override + public ResultFormulaType multiply(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.multiply(number1, number2)); + } + + @Override + public BooleanFormula equal(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("equal(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.equal(number1, number2)); + } + + @Override + public BooleanFormula distinct(List pNumbers) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "distinct(%s)", + FluentIterable.from(pNumbers).transform(logger::toVariable).join(Joiner.on(", "))), + () -> delegate.distinct(pNumbers)); + } + + @Override + public BooleanFormula greaterThan(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "greaterThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.greaterThan(number1, number2)); + } + + @Override + public BooleanFormula greaterOrEquals(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "greaterOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.greaterOrEquals(number1, number2)); + } + + @Override + public BooleanFormula lessThan(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("lessThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.lessThan(number1, number2)); + } + + @Override + public BooleanFormula lessOrEquals(ParamFormulaType number1, ParamFormulaType number2) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format( + "lessOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.lessOrEquals(number1, number2)); + } + + @Override + public IntegerFormula floor(ParamFormulaType formula) { + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("floor(%s)", logger.toVariable(formula)), + () -> delegate.floor(formula)); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java new file mode 100644 index 0000000000..cf03d5f5f2 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java @@ -0,0 +1,56 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.math.BigDecimal; +import org.sosy_lab.common.rationals.Rational; +import org.sosy_lab.java_smt.api.NumeralFormula; +import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula; +import org.sosy_lab.java_smt.api.RationalFormulaManager; + +public class TraceRationalFormulaManager + extends TraceNumeralFormulaManager + implements RationalFormulaManager { + final RationalFormulaManager delegate; + final TraceLogger logger; + + TraceRationalFormulaManager(RationalFormulaManager pDelegate, TraceLogger pLogger) { + super(pDelegate, pLogger); + delegate = pDelegate; + logger = pLogger; + } + + @Override + public RationalFormula makeNumber(double number) { + return logger.logDef( + "mgr.getRationalFormulaManager()", + String.format("makeNumber(%s))", number), + () -> delegate.makeNumber(number)); + } + + @Override + public RationalFormula makeNumber(BigDecimal number) { + return makeNumber(Rational.ofBigDecimal(number)); + } + + @Override + public RationalFormula makeNumber(String pI) { + return makeNumber(new BigDecimal(pI)); + } + + @Override + public RationalFormula makeNumber(Rational pRational) { + return logger.logDef( + "mgr.getRationalFormulaManager()", + String.format("makeNumber(Rational.of(\"%s\"))", pRational), + () -> delegate.makeNumber(pRational)); + } +} From e1dff26a1c5eb8a2ed7d30d8e30060d9912e5de3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 25 Aug 2025 04:36:52 +0200 Subject: [PATCH 064/233] Trace: Inline logging in FormulaManager.applyTactic to avoid catching InterruptedExceptions --- .../delegate/trace/TraceFormulaManager.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 1184f7daff..dbbfb75212 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -925,10 +925,19 @@ public Appender dumpFormula(BooleanFormula pT) { @Override public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) throws InterruptedException, SolverException { - return logger.logDef( - "mgr", - String.format("applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name()), - () -> delegate.applyTactic(input, tactic)); + String var = logger.newVariable(); + logger.appendDef( + var, + String.format( + "mgr.applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name())); + BooleanFormula f = delegate.applyTactic(input, tactic); + if (logger.isTracked(f)) { + logger.undoLast(); + return f; + } else { + logger.mapVariable(var, f); + return rebuild(f); + } } @Override From f6f477fd05399b6df56e40d084cb06d711ae4891 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 25 Aug 2025 12:11:05 +0200 Subject: [PATCH 065/233] Trace: Suppress warnings --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index dbbfb75212..9934c752fc 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -187,6 +187,7 @@ public Formula visitConstant(Formula f, Object value) { return f; } + @SuppressWarnings("unused") @Override public Formula visitFunction( Formula f, List args, FunctionDeclaration functionDeclaration) { @@ -338,7 +339,7 @@ private int getArity(FunctionDeclaration pDeclaration) { } } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public T makeApplication( FunctionDeclaration declaration, List args) { From e79a09e299e3da42c64c7921b4d4fa4cf3dc432a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 25 Aug 2025 12:11:25 +0200 Subject: [PATCH 066/233] Trace: Use ArrayDeque instead of Stack --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 3394f16fb7..e5a93123ca 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -15,9 +15,10 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.HashMap; import java.util.Map; -import java.util.Stack; import java.util.concurrent.Callable; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; @@ -32,7 +33,7 @@ class TraceLogger { private final Map valueMap = new HashMap<>(); private final RandomAccessFile output; - private final Stack lastLines = new Stack<>(); + private final Deque lastLines = new ArrayDeque<>(); TraceLogger(TraceFormulaManager pMgr, String pFile) { mgr = pMgr; From bdf22c0c2fc7cc9de74c10de233dd3f8ee317465 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Thu, 28 Aug 2025 23:44:10 +0200 Subject: [PATCH 067/233] TraceLogger: improve tracefiles with FileOption, and id with UniqueIdGenerator. --- .../java_smt/delegate/trace/TraceLogger.java | 12 ++++-- .../delegate/trace/TraceSolverContext.java | 42 ++++++++++++++++--- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index e5a93123ca..1e6a89e51d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -12,6 +12,7 @@ import com.google.common.base.Preconditions; import com.google.common.base.Throwables; +import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; @@ -20,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; +import org.sosy_lab.common.UniqueIdGenerator; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; @@ -28,15 +30,17 @@ class TraceLogger { private final TraceFormulaManager mgr; - private long id = 0; + private UniqueIdGenerator id = new UniqueIdGenerator(); private final Map valueMap = new HashMap<>(); private final RandomAccessFile output; private final Deque lastLines = new ArrayDeque<>(); - TraceLogger(TraceFormulaManager pMgr, String pFile) { + TraceLogger(TraceFormulaManager pMgr, File pFile) { mgr = pMgr; + mgr.setLogger(this); + // FIXME Check if the file already exists try { output = new RandomAccessFile(pFile, "rw"); @@ -47,7 +51,7 @@ class TraceLogger { /** Returns a fresh variable. */ public String newVariable() { - return "var" + id++; + return "var" + id.getFreshId(); } /** @@ -75,7 +79,7 @@ public String toVariable(Object f) { return r; } - /** Add a definition to the log. */ + /** Add a definition of a new object to the log. */ public void appendDef(String pVar, String pExpr) { try { lastLines.push(output.length()); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 0205f5d45d..6cbd093e66 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -14,9 +14,18 @@ import com.google.common.base.Splitter; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; +import com.google.common.io.MoreFiles; +import java.io.IOException; +import java.nio.file.Path; import java.util.List; import java.util.Map.Entry; +import org.checkerframework.checker.nullness.qual.Nullable; import org.sosy_lab.common.configuration.Configuration; +import org.sosy_lab.common.configuration.FileOption; +import org.sosy_lab.common.configuration.InvalidConfigurationException; +import org.sosy_lab.common.configuration.Option; +import org.sosy_lab.common.configuration.Options; +import org.sosy_lab.common.io.PathTemplate; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; @@ -24,20 +33,41 @@ import org.sosy_lab.java_smt.api.ProverEnvironment; import org.sosy_lab.java_smt.api.SolverContext; +@Options public class TraceSolverContext implements SolverContext { private final SolverContext delegate; private final TraceLogger logger; private final TraceFormulaManager mgr; - public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext pDelegate) { + @Option( + secure = true, + name = "solver.tracefile", + description = "Export solver interaction as Java code into a file.") + @FileOption(FileOption.Type.OUTPUT_FILE) + private @Nullable PathTemplate tracefileTemplate = + PathTemplate.ofFormatString("traces/trace_%s.java"); + + public TraceSolverContext(Solvers pSolver, Configuration config, SolverContext pDelegate) + throws InvalidConfigurationException { + config.inject(this); delegate = pDelegate; - // FIXME Move the files to the output folder? mgr = new TraceFormulaManager(delegate.getFormulaManager()); - logger = - new TraceLogger( - mgr, "trace" + Integer.toUnsignedString(System.identityHashCode(this)) + ".java"); - mgr.setLogger(logger); + // initialize the trace logger and create the trace file, + // nanotime is used to avoid collisions, and it is sorted by time. + final Path tracefile = tracefileTemplate.getPath(String.valueOf(System.nanoTime())); + try { + MoreFiles.createParentDirectories(tracefile); + } catch (IOException e) { + throw new InvalidConfigurationException("Could not create directory for trace files", e); + } + logger = new TraceLogger(mgr, tracefile.toFile()); + + this.initializeJavaSMT(config, pSolver); + } + + /** Write the header code for using JavaSMT, e.g., to initialize the context and solver. */ + private void initializeJavaSMT(Configuration config, Solvers pSolver) { // Get relevant options from the configuration String props = config.asPropertiesString(); ImmutableMap.Builder options = ImmutableMap.builder(); From 33a9d03df9521582c8003661225ff8c93c5d7774 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Fri, 29 Aug 2025 00:05:19 +0200 Subject: [PATCH 068/233] fix Checkstyle warnings and improve code style --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 8 ++++---- .../delegate/trace/TraceNumeralFormulaManager.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 1e6a89e51d..65ded751bd 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -30,7 +30,7 @@ class TraceLogger { private final TraceFormulaManager mgr; - private UniqueIdGenerator id = new UniqueIdGenerator(); + private final UniqueIdGenerator id = new UniqueIdGenerator(); private final Map valueMap = new HashMap<>(); private final RandomAccessFile output; @@ -41,7 +41,7 @@ class TraceLogger { mgr = pMgr; mgr.setLogger(this); - // FIXME Check if the file already exists + // FIXME Check if the file already exists -> quite unlikely, lets ignore this case. try { output = new RandomAccessFile(pFile, "rw"); } catch (IOException e) { @@ -94,8 +94,8 @@ public void appendStmt(String pStmt) { try { lastLines.push(output.length()); output.write(String.format("%s;%n", pStmt).getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new RuntimeException(e); + } catch (IOException pIOException) { + throw new RuntimeException(pIOException); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index 8a0503ef71..d35c83edd4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -19,7 +19,7 @@ import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; import org.sosy_lab.java_smt.api.NumeralFormulaManager; -@SuppressWarnings("InterfaceTypeParameterName") +@SuppressWarnings("ClassTypeParameterName") public abstract class TraceNumeralFormulaManager< ParamFormulaType extends NumeralFormula, ResultFormulaType extends NumeralFormula> implements NumeralFormulaManager { From 2db414461809ce5934da92c5194b4695004a7cd4 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Fri, 29 Aug 2025 00:35:51 +0200 Subject: [PATCH 069/233] shorten some code with utility methods. --- .../trace/TraceBasicProverEnvironment.java | 12 ++++------ .../trace/TraceBitvectorFormulaManager.java | 6 +---- .../trace/TraceBooleanFormulaManager.java | 24 +++++-------------- .../delegate/trace/TraceFormulaManager.java | 9 +++++++ .../java_smt/delegate/trace/TraceLogger.java | 7 ++++++ .../trace/TraceNumeralFormulaManager.java | 10 ++------ .../delegate/trace/TraceSolverContext.java | 2 +- .../delegate/trace/TraceUFManager.java | 3 +-- 8 files changed, 31 insertions(+), 42 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index 56d104fd50..6329e4f65f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -10,8 +10,6 @@ package org.sosy_lab.java_smt.delegate.trace; -import com.google.common.base.Joiner; -import com.google.common.collect.FluentIterable; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -80,8 +78,7 @@ public boolean isUnsatWithAssumptions(Collection assumptions) var, String.format( "%s.isUnsatWithAssumptions(ImmutableList.of(%s))", - logger.toVariable(this), - FluentIterable.from(assumptions).transform(logger::toVariable).join(Joiner.on(", ")))); + logger.toVariable(this), logger.toVariables(assumptions))); boolean unsat = delegate.isUnsatWithAssumptions(assumptions); logger.mapVariable(var, unsat); return unsat; @@ -102,7 +99,7 @@ public List getUnsatCore() { logger.appendStmt(String.format("%s.getUnsatCore()", logger.toVariable(this))); List core = delegate.getUnsatCore(); logger.undoLast(); - return FluentIterable.from(core).transform(mgr::rebuild).toList(); + return mgr.rebuildAll(core); } @Override @@ -111,11 +108,10 @@ public Optional> unsatCoreOverAssumptions( logger.appendStmt( String.format( "%s.getUnsatCoreOverAssumptions(ImmutableList.of(%s))", - logger.toVariable(this), - FluentIterable.from(assumptions).transform(logger::toVariable).join(Joiner.on(", ")))); + logger.toVariable(this), logger.toVariables(assumptions))); Optional> maybeCore = delegate.unsatCoreOverAssumptions(assumptions); logger.undoLast(); - return maybeCore.map(core -> FluentIterable.from(core).transform(mgr::rebuild).toList()); + return maybeCore.map(mgr::rebuildAll); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java index 936a12f33c..3f8ec26677 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -10,8 +10,6 @@ package org.sosy_lab.java_smt.delegate.trace; -import com.google.common.base.Joiner; -import com.google.common.collect.FluentIterable; import java.math.BigInteger; import java.util.List; import org.sosy_lab.java_smt.api.BitvectorFormula; @@ -309,9 +307,7 @@ public BitvectorFormula extend(BitvectorFormula number, int extensionBits, boole public BooleanFormula distinct(List pBits) { return logger.logDef( "mgr.getBitvectorFormulaManager()", - String.format( - "distinct(ImmutableList.of(%s))", - FluentIterable.from(pBits).transform(logger::toVariable).join(Joiner.on(", "))), + String.format("distinct(ImmutableList.of(%s))", logger.toVariables(pBits)), () -> delegate.distinct(pBits)); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 710e2f577c..0f5d6ae9a1 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -10,8 +10,6 @@ package org.sosy_lab.java_smt.delegate.trace; -import com.google.common.base.Joiner; -import com.google.common.collect.FluentIterable; import java.util.Arrays; import java.util.Collection; import java.util.Set; @@ -109,19 +107,14 @@ public BooleanFormula not(BooleanFormula formula) { @Override public BooleanFormula and(BooleanFormula formula1, BooleanFormula formula2) { - return logger.logDef( - "mgr.getBooleanFormulaManager()", - String.format("and(%s, %s)", logger.toVariable(formula1), logger.toVariable(formula2)), - () -> delegate.and(formula1, formula2)); + return and(Arrays.asList(formula1, formula2)); } @Override public BooleanFormula and(Collection bits) { return logger.logDef( "mgr.getBooleanFormulaManager()", - String.format( - "and(%s)", - FluentIterable.from(bits).transform(logger::toVariable).join(Joiner.on(", "))), + String.format("and(%s)", logger.toVariables(bits)), () -> delegate.and(bits)); } @@ -137,19 +130,14 @@ public BooleanFormula and(BooleanFormula... bits) { @Override public BooleanFormula or(BooleanFormula formula1, BooleanFormula formula2) { - return logger.logDef( - "mgr.getBooleanFormulaManager()", - String.format("or(%s, %s)", logger.toVariable(formula1), logger.toVariable(formula2)), - () -> delegate.or(formula1, formula2)); + return or(Arrays.asList(formula1, formula2)); } @Override public BooleanFormula or(Collection bits) { return logger.logDef( "mgr.getBooleanFormulaManager()", - String.format( - "or(%s)", - FluentIterable.from(bits).transform(logger::toVariable).join(Joiner.on(", "))), + String.format("or(%s)", logger.toVariables(bits)), () -> delegate.or(bits)); } @@ -215,7 +203,7 @@ public Set toConjunctionArgs(BooleanFormula f, boolean flatten) String.format("mgr.toConjunctionArgs(%s, %s)", logger.toVariable(f), flatten)); Set set = delegate.toConjunctionArgs(f, flatten); logger.undoLast(); - return FluentIterable.from(set).transform(mgr::rebuild).toSet(); + return mgr.rebuildAll(set); } @Override @@ -224,6 +212,6 @@ public Set toDisjunctionArgs(BooleanFormula f, boolean flatten) String.format("mgr.toDisjunctionArgs(%s, %s)", logger.toVariable(f), flatten)); Set set = delegate.toDisjunctionArgs(f, flatten); logger.undoLast(); - return FluentIterable.from(set).transform(mgr::rebuild).toSet(); + return mgr.rebuildAll(set); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 9934c752fc..9218b023ef 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -19,6 +19,7 @@ import java.math.BigInteger; import java.util.List; import java.util.Map; +import java.util.Set; import org.sosy_lab.common.Appender; import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.api.ArrayFormula; @@ -213,6 +214,14 @@ public T rebuild(T f) { return delegate.transformRecursively(f, new TraceFormulaManager.Rebuilder(this)); } + public List rebuildAll(List formulas) { + return FluentIterable.from(formulas).transform(this::rebuild).toList(); + } + + public Set rebuildAll(Set formulas) { + return FluentIterable.from(formulas).transform(this::rebuild).toSet(); + } + @Override public T makeVariable(FormulaType formulaType, String name) { String var = logger.newVariable(); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 65ded751bd..1fdaf64a19 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -10,8 +10,10 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; +import com.google.common.collect.FluentIterable; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -79,6 +81,11 @@ public String toVariable(Object f) { return r; } + /** Returns a comma-separated list of variable names for the given objects. */ + public String toVariables(Iterable objects) { + return FluentIterable.from(objects).transform(this::toVariable).join(Joiner.on(", ")); + } + /** Add a definition of a new object to the log. */ public void appendDef(String pVar, String pExpr) { try { diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index d35c83edd4..a7cb340532 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -10,8 +10,6 @@ package org.sosy_lab.java_smt.delegate.trace; -import com.google.common.base.Joiner; -import com.google.common.collect.FluentIterable; import java.math.BigInteger; import java.util.List; import org.sosy_lab.java_smt.api.BooleanFormula; @@ -76,9 +74,7 @@ public ResultFormulaType add(ParamFormulaType number1, ParamFormulaType number2) public ResultFormulaType sum(List operands) { return logger.logDef( "mgr.getIntegerFormulaManager()", - String.format( - "sum(%s)", - FluentIterable.from(operands).transform(logger::toVariable).join(Joiner.on(", "))), + String.format("sum(%s)", logger.toVariables(operands)), () -> delegate.sum(operands)); } @@ -119,9 +115,7 @@ public BooleanFormula equal(ParamFormulaType number1, ParamFormulaType number2) public BooleanFormula distinct(List pNumbers) { return logger.logDef( "mgr.getIntegerFormulaManager()", - String.format( - "distinct(%s)", - FluentIterable.from(pNumbers).transform(logger::toVariable).join(Joiner.on(", "))), + String.format("distinct(%s)", logger.toVariables(pNumbers)), () -> delegate.distinct(pNumbers)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 6cbd093e66..236f6e1e42 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -114,7 +114,7 @@ public ProverEnvironment newProverEnvironment(ProverOptions... options) { String.format( "newProverEnvironment(%s)", FluentIterable.from(options) - .transform(v -> "SolverContext" + ".ProverOptions." + v.name()) + .transform(v -> "SolverContext.ProverOptions." + v.name()) .join(Joiner.on(", "))), () -> new TraceProverEnvironment(delegate.newProverEnvironment(options), mgr, logger)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index b0bd5e0bdf..349c30cf5e 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -67,8 +67,7 @@ public T callUF( var, String.format( "callUF(%s, ImmutableList.of(%s))", - logger.toVariable(funcType), - FluentIterable.from(args).transform(logger::toVariable).join(Joiner.on(", ")))); + logger.toVariable(funcType), logger.toVariables(args))); T f = delegate.callUF(funcType, args); if (logger.isTracked(f)) { logger.undoLast(); From 1c1108d8f7206474b4bc8e485ea38b69773237f3 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Fri, 29 Aug 2025 00:47:16 +0200 Subject: [PATCH 070/233] enable tracing for all unit tests, testwise. --- src/org/sosy_lab/java_smt/test/SolverBasedTest0.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index e96c7b39f1..b2a670f739 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -125,7 +125,9 @@ protected Logics logicToUse() { protected ConfigurationBuilder createTestConfigBuilder() { ConfigurationBuilder newConfig = - Configuration.builder().setOption("solver.solver", solverToUse().toString()); + Configuration.builder() + .setOption("solver.solver", solverToUse().toString()) + .setOption("solver.trace", "true"); if (solverToUse() == Solvers.OPENSMT) { newConfig.setOption("solver.opensmt.logic", logicToUse().toString()); } From 4129a90a960b7469f0769ad2c2dfc0a498e901ef Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Fri, 29 Aug 2025 00:58:40 +0200 Subject: [PATCH 071/233] fix invalid argument dump --- .../delegate/trace/TraceArrayFormulaManager.java | 2 +- .../trace/TraceBitvectorFormulaManager.java | 2 +- .../trace/TraceFloatingPointFormulaManager.java | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java index 666320e1b2..7a1da852dc 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java @@ -71,7 +71,7 @@ ArrayFormula makeArray(FTI pIndexType, FTE pElementType, TE defaultEleme return logger.logDef( "mgr.getArrayFormulaManager()", String.format( - "makeArray(\"%s\", %s, %s)", + "makeArray(%s, %s, %s)", logger.printFormulaType(pIndexType), logger.printFormulaType(pElementType), logger.toVariable(defaultElement)), diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java index 3f8ec26677..9b5d6b7f57 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -31,7 +31,7 @@ public class TraceBitvectorFormulaManager implements BitvectorFormulaManager { public BitvectorFormula makeBitvector(int length, long pI) { return logger.logDef( "mgr.getBitvectorFormulaManager()", - String.format("makeBitvector(%s, %s)", length, pI), + String.format("makeBitvector(%s, %sL)", length, pI), () -> delegate.makeBitvector(length, pI)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index 8a82039fc1..cee2b6de54 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -48,10 +48,23 @@ public FloatingPointFormula makeNumber( "mgr.getFloatingPointFormulaManager()", String.format( "makeNumber(%s, %s, %s)", - n, logger.printFormulaType(type), printRoundingMode(pFloatingPointRoundingMode)), + toString(n), logger.printFormulaType(type), + printRoundingMode(pFloatingPointRoundingMode)), () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); } + private String toString(double number) { + if (Double.isNaN(number)) { + return "Double.NaN"; + } else if (Double.isInfinite(number)) { + return number > 0 ? "Double.POSITIVE_INFINITY" : "Double.NEGATIVE_INFINITY"; + } else if (number == 0.0 && Double.doubleToRawLongBits(number) == Double.doubleToRawLongBits(-0.0)) { + return "-0.0"; + } else { + return Double.toString(number); + } + } + @Override public FloatingPointFormula makeNumber(BigDecimal n, FloatingPointType type) { return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); From 8bdc4752d4168eb869efe60096e62f1297d80ba6 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:45:46 +0200 Subject: [PATCH 072/233] Trace: Use makeApplication to handle non-UF calls to TraceUFManager.callUF --- .../delegate/trace/TraceUFManager.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 349c30cf5e..76d3950935 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -19,6 +19,7 @@ import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FunctionDeclaration; +import org.sosy_lab.java_smt.api.FunctionDeclarationKind; import org.sosy_lab.java_smt.api.UFManager; public class TraceUFManager implements UFManager { @@ -62,19 +63,23 @@ public FunctionDeclaration declareUF( @Override public T callUF( FunctionDeclaration funcType, List args) { - String var = logger.newVariable(); - logger.appendDef( - var, - String.format( - "callUF(%s, ImmutableList.of(%s))", - logger.toVariable(funcType), logger.toVariables(args))); - T f = delegate.callUF(funcType, args); - if (logger.isTracked(f)) { - logger.undoLast(); + if (funcType.getKind().equals(FunctionDeclarationKind.UF)) { + String var = logger.newVariable(); + logger.appendDef( + var, + String.format( + "callUF(%s, ImmutableList.of(%s))", + logger.toVariable(funcType), logger.toVariables(args))); + T f = delegate.callUF(funcType, args); + if (logger.isTracked(f)) { + logger.undoLast(); + } else { + logger.mapVariable(var, f); + } + return f; } else { - logger.mapVariable(var, f); + return mgr.makeApplication(funcType, args); } - return f; } @Override From 1168f3bf41620dba218a7ae6d1c5ccc8e3adcc42 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:46:42 +0200 Subject: [PATCH 073/233] Trace: Filter out values for local definitions from the Z3 model --- src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java index 7c188037b4..09a234625d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java @@ -44,6 +44,8 @@ public ImmutableList asList() { ImmutableList result = delegate.asList(); logger.undoLast(); return FluentIterable.from(result) + // TODO Fix this in the Z3 model + .filter((ValueAssignment assignment) -> !assignment.getName().startsWith("#")) .transform( (ValueAssignment assigment) -> { var key = mgr.rebuild(assigment.getKey()); From 62766eaa418e8ded992384a7c029475862fe5943 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:49:00 +0200 Subject: [PATCH 074/233] Trace: Skip the division when creating an IntegerFormula from a Rational that is really integer --- .../delegate/trace/TraceIntegerFormulaManager.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java index 6a413d9238..a20edf6d60 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -46,9 +46,13 @@ public IntegerFormula makeNumber(String pI) { @Override public IntegerFormula makeNumber(Rational pRational) { - var num = makeNumber(pRational.getNum()); - var den = makeNumber(pRational.getDen()); - return divide(num, den); + if (pRational.isIntegral()) { + return makeNumber(pRational.getNum()); + } else { + var num = makeNumber(pRational.getNum()); + var den = makeNumber(pRational.getDen()); + return divide(num, den); + } } @Override From 7ed9a909f4ffc720816d983cdada4d432dfb8d27 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:50:34 +0200 Subject: [PATCH 075/233] Trace: Handle BigInteger values for RationalFormula constants Some solvers will return these when the value is really integer --- .../java_smt/delegate/trace/TraceFormulaManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 9218b023ef..c0670e1962 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -171,6 +171,13 @@ public Formula visitConstant(Formula f, Object value) { String.format("makeNumber(%s)", value), () -> delegate.getIntegerFormulaManager().makeNumber((BigInteger) value)); Preconditions.checkArgument(g.equals(f)); + } else if (f instanceof RationalFormula && value instanceof BigInteger) { + var g = + logger.logDef( + "mgr.getRationalFormulaManager()", + String.format("makeNumber(%s)", value), + () -> delegate.getRationalFormulaManager().makeNumber((BigInteger) value)); + Preconditions.checkArgument(g.equals(f)); } else if (f instanceof RationalFormula && value instanceof Rational) { var g = logger.logDef( From 1f562f1f94fe134c03310136dffcbbfbcb11278c Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:51:10 +0200 Subject: [PATCH 076/233] Trace: Restore the check in the function visitor that makes sure the recreated formula is identical to the old formula --- .../java_smt/delegate/trace/TraceFormulaManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index c0670e1962..4b889be930 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -195,14 +195,14 @@ public Formula visitConstant(Formula f, Object value) { return f; } - @SuppressWarnings("unused") @Override public Formula visitFunction( Formula f, List args, FunctionDeclaration functionDeclaration) { if (!logger.isTracked(f)) { Formula g = makeApplication(functionDeclaration, args); - // FIXME Remove the assertion? Argument order can change, f.ex (and a b) becomes (and b a) - // Preconditions.checkArgument(g.equals(f)); + if (!g.equals(f)) { + Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); + } } return f; } From 243fdd904531ecad65a9124bbc9059541eb8527b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:52:16 +0200 Subject: [PATCH 077/233] Trace: Fix floating point operations and skip the rounding mode argument --- .../delegate/trace/TraceFormulaManager.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 4b889be930..7161603247 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -32,7 +32,6 @@ import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; -import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.FormulaType; @@ -740,19 +739,19 @@ public T makeApplication( getFloatingPointFormulaManager() .min((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); case FP_SQRT: - return (T) getFloatingPointFormulaManager().sqrt((FloatingPointFormula) args.get(0)); + return (T) getFloatingPointFormulaManager().sqrt((FloatingPointFormula) args.get(1)); case FP_SUB: return (T) getFloatingPointFormulaManager() - .subtract((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + .subtract((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); case FP_ADD: return (T) getFloatingPointFormulaManager() - .add((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + .add((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); case FP_DIV: return (T) getFloatingPointFormulaManager() - .divide((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + .divide((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); case FP_REM: return (T) getFloatingPointFormulaManager() @@ -761,7 +760,7 @@ public T makeApplication( case FP_MUL: return (T) getFloatingPointFormulaManager() - .multiply((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); + .multiply((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); case FP_LT: return (T) getFloatingPointFormulaManager() @@ -800,15 +799,11 @@ public T makeApplication( break; */ case FP_ROUND_TO_INTEGRAL: - { - var rm = (FloatingPointRoundingModeFormula) args.get(1); - System.out.println("Rounding Mode: " + rm); - return (T) - getFloatingPointFormulaManager() - .round( - (FloatingPointFormula) args.get(0), - FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); - } + return (T) + getFloatingPointFormulaManager() + .round( + (FloatingPointFormula) args.get(1), + FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); case FP_IS_NAN: return (T) getFloatingPointFormulaManager().isNaN((FloatingPointFormula) args.get(0)); case FP_IS_INF: From da7582ef8c296835fd525aa6c3e7e1744b217300 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 18:52:35 +0200 Subject: [PATCH 078/233] Trace: Remove a todo about rounding mode kinds --- .../delegate/trace/TraceFormulaManager.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 7161603247..8e18f3ba71 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -785,19 +785,6 @@ public T makeApplication( getFloatingPointFormulaManager() .equalWithFPSemantics( (FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); - // TODO - /* - case FP_ROUND_EVEN: - break; - case FP_ROUND_AWAY: - break; - case FP_ROUND_POSITIVE: - break; - case FP_ROUND_NEGATIVE: - break; - case FP_ROUND_ZERO: - break; - */ case FP_ROUND_TO_INTEGRAL: return (T) getFloatingPointFormulaManager() From 9d23d094fcc7a07e197e38238c7d2ce5fc4b4525 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Fri, 29 Aug 2025 14:41:21 +0200 Subject: [PATCH 079/233] add "/traces" to gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b1ff17c08b..b075b89ddb 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ solvers_maven_conf/*.asc /Javadoc /Javadoc-z3 /gh-pages +/traces .idea/ From 817ba2003b7e488765ff2ac7c57188840c7790c1 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Sat, 30 Aug 2025 23:23:47 +0200 Subject: [PATCH 080/233] Trace: implement tracing for EnumerationFMgr. --- .../trace/TraceEnumerationFormulaManager.java | 66 +++++++++++++++++++ .../delegate/trace/TraceFormulaManager.java | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java new file mode 100644 index 0000000000..0fc41909cc --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java @@ -0,0 +1,66 @@ +// This file is part of JavaSMT, +// an API wrapper for a collection of SMT solvers: +// https://github.com/sosy-lab/java-smt +// +// SPDX-FileCopyrightText: 2025 Dirk Beyer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.sosy_lab.java_smt.delegate.trace; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Joiner; +import java.util.Set; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.EnumerationFormula; +import org.sosy_lab.java_smt.api.EnumerationFormulaManager; +import org.sosy_lab.java_smt.api.FormulaType.EnumerationFormulaType; + +public class TraceEnumerationFormulaManager implements EnumerationFormulaManager { + + private final EnumerationFormulaManager delegate; + private final TraceLogger logger; + + TraceEnumerationFormulaManager(EnumerationFormulaManager pDelegate, TraceLogger pLogger) { + delegate = checkNotNull(pDelegate); + logger = checkNotNull(pLogger); + } + + @Override + public EnumerationFormulaType declareEnumeration(String name, Set elementNames) { + return logger.logDefKeep( + "mgr.getEnumerationFormulaManager()", + String.format( + "declareEnumeration(\"%s\", Set.of(\"%s\"))", + name, Joiner.on("\", \"").join(elementNames)), + () -> delegate.declareEnumeration(name, elementNames)); + } + + @Override + public EnumerationFormula makeConstant(String pName, EnumerationFormulaType pType) { + return logger.logDef( + "mgr.getEnumerationFormulaManager()", + String.format("makeConstant(\"%s\", %s)", pName, logger.toVariable(pType)), + () -> delegate.makeConstant(pName, pType)); + } + + @Override + public EnumerationFormula makeVariable(String pVar, EnumerationFormulaType pType) { + return logger.logDef( + "mgr.getEnumerationFormulaManager()", + String.format("makeVariable(\"%s\", %s)", pVar, logger.toVariable(pType)), + () -> delegate.makeVariable(pVar, pType)); + } + + @Override + public BooleanFormula equivalence( + EnumerationFormula pEnumeration1, EnumerationFormula pEnumeration2) { + return logger.logDef( + "mgr.getEnumerationFormulaManager()", + String.format( + "equivalence(%s, %s)", + logger.toVariable(pEnumeration1), logger.toVariable(pEnumeration2)), + () -> delegate.equivalence(pEnumeration1, pEnumeration2)); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 8e18f3ba71..a8a3647c67 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -119,7 +119,7 @@ public StringFormulaManager getStringFormulaManager() { @Override public EnumerationFormulaManager getEnumerationFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceEnumerationFormulaManager(delegate.getEnumerationFormulaManager(), logger); } private class Rebuilder extends FormulaTransformationVisitor { From e4bf4d57363893c3a13f3e264306226f4d3e934c Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 30 Aug 2025 22:43:23 +0200 Subject: [PATCH 081/233] Trace: Avoid upcasting to rational if both sides of an equation are integers --- .../delegate/trace/TraceFormulaManager.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index a8a3647c67..a3decef3c9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -520,10 +520,17 @@ public T makeApplication( return (T) getBooleanFormulaManager() .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - } else if (declaration.getArgumentTypes().get(0).isNumeralType()) { - return (T) - getRationalFormulaManager() - .equal((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(1).isNumeralType()) { + if (declaration.getArgumentTypes().get(0).isRationalType() + || declaration.getArgumentTypes().get(1).isRationalType()) { + return (T) + getRationalFormulaManager() + .equal((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + } else { + return (T) + getIntegerFormulaManager() + .equal((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } } else if (declaration.getArgumentTypes().get(0).isBitvectorType()) { return (T) getBitvectorFormulaManager() From c593988d78f7d7ae0e06abedf1ec36f88ab7b089 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Sat, 30 Aug 2025 22:15:41 +0200 Subject: [PATCH 082/233] Add more methods for Trace-*-FormulaManager to directly dump usage of methods. --- .../TraceFloatingPointFormulaManager.java | 105 +++++++++++++----- .../trace/TraceIntegerFormulaManager.java | 26 +++-- 2 files changed, 92 insertions(+), 39 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index cee2b6de54..632b8073a1 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -32,42 +32,50 @@ public class TraceFloatingPointFormulaManager implements FloatingPointFormulaMan logger = pLogger; } - @Override - public FloatingPointFormula makeNumber(double n, FloatingPointType type) { - return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); - } - private String printRoundingMode(FloatingPointRoundingMode pRoundingMode) { return "FloatingPointRoundingMode." + pRoundingMode.name(); } - @Override - public FloatingPointFormula makeNumber( - double n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format( - "makeNumber(%s, %s, %s)", - toString(n), logger.printFormulaType(type), - printRoundingMode(pFloatingPointRoundingMode)), - () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); - } - private String toString(double number) { if (Double.isNaN(number)) { return "Double.NaN"; } else if (Double.isInfinite(number)) { return number > 0 ? "Double.POSITIVE_INFINITY" : "Double.NEGATIVE_INFINITY"; - } else if (number == 0.0 && Double.doubleToRawLongBits(number) == Double.doubleToRawLongBits(-0.0)) { + } else if (number == 0.0 + && Double.doubleToRawLongBits(number) == Double.doubleToRawLongBits(-0.0)) { return "-0.0"; } else { return Double.toString(number); } } + @Override + public FloatingPointFormula makeNumber(double n, FloatingPointType type) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeNumber(%s, %s)", toString(n), logger.printFormulaType(type)), + () -> delegate.makeNumber(n, type)); + } + + @Override + public FloatingPointFormula makeNumber( + double n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeNumber(%s, %s, %s)", + toString(n), + logger.printFormulaType(type), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); + } + @Override public FloatingPointFormula makeNumber(BigDecimal n, FloatingPointType type) { - return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeNumber(new BigDecimal(\"%s\"), %s)", n, logger.printFormulaType(type)), + () -> delegate.makeNumber(n, type)); } @Override @@ -83,7 +91,10 @@ public FloatingPointFormula makeNumber( @Override public FloatingPointFormula makeNumber(String n, FloatingPointType type) { - return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeNumber(\"%s\", %s)", n, logger.printFormulaType(type)), + () -> delegate.makeNumber(n, type)); } @Override @@ -99,13 +110,24 @@ public FloatingPointFormula makeNumber( @Override public FloatingPointFormula makeNumber(Rational n, FloatingPointType type) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeNumber(Rational.of(\"%s\"), %s)", n, logger.printFormulaType(type)), + () -> delegate.makeNumber(n, type)); } @Override public FloatingPointFormula makeNumber( Rational n, FloatingPointType type, FloatingPointRoundingMode pFloatingPointRoundingMode) { - throw new UnsupportedOperationException(); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeNumber(Rational.of(%s, %s), %s, %s)", + n.getNum(), + n.getDen(), + logger.printFormulaType(type), + printRoundingMode(pFloatingPointRoundingMode)), + () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); } private String printSign(Sign pSign) { @@ -158,7 +180,12 @@ public FloatingPointFormula makeNaN(FloatingPointType type) { @Override public T castTo( FloatingPointFormula source, boolean signed, FormulaType targetType) { - return castTo(source, signed, targetType, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "castTo(%s, %s, %s)", + logger.toVariable(source), signed, logger.printFormulaType(targetType)), + () -> delegate.castTo(source, signed, targetType)); } @Override @@ -181,7 +208,12 @@ public T castTo( @Override public FloatingPointFormula castFrom( Formula source, boolean signed, FloatingPointType targetType) { - return castFrom(source, signed, targetType, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "castFrom(%s, %s, %s)", + logger.toVariable(source), signed, logger.printFormulaType(targetType)), + () -> delegate.castFrom(source, signed, targetType)); } @Override @@ -263,7 +295,10 @@ public FloatingPointFormula min(FloatingPointFormula number1, FloatingPointFormu @Override public FloatingPointFormula sqrt(FloatingPointFormula number) { - return sqrt(number, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("sqrt(%s)", logger.toVariable(number)), + () -> delegate.sqrt(number)); } @Override @@ -277,7 +312,10 @@ public FloatingPointFormula sqrt( @Override public FloatingPointFormula add(FloatingPointFormula number1, FloatingPointFormula number2) { - return add(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.add(number1, number2)); } @Override @@ -297,7 +335,10 @@ public FloatingPointFormula add( @Override public FloatingPointFormula subtract(FloatingPointFormula number1, FloatingPointFormula number2) { - return subtract(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.subtract(number1, number2)); } @Override @@ -317,7 +358,10 @@ public FloatingPointFormula subtract( @Override public FloatingPointFormula divide(FloatingPointFormula number1, FloatingPointFormula number2) { - return divide(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("divide(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.divide(number1, number2)); } @Override @@ -337,7 +381,10 @@ public FloatingPointFormula divide( @Override public FloatingPointFormula multiply(FloatingPointFormula number1, FloatingPointFormula number2) { - return multiply(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), + () -> delegate.multiply(number1, number2)); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java index a20edf6d60..6d512f7dd9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -31,28 +31,34 @@ public class TraceIntegerFormulaManager @Override public IntegerFormula makeNumber(double number) { - return makeNumber(BigDecimal.valueOf(number)); + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(%s)", number), + () -> delegate.makeNumber(number)); } @Override public IntegerFormula makeNumber(BigDecimal number) { - return makeNumber(Rational.ofBigDecimal(number)); + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(new BigDecimal(\"%s\"))", number), + () -> delegate.makeNumber(number)); } @Override public IntegerFormula makeNumber(String pI) { - return makeNumber(new BigDecimal(pI)); + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(\"%s\")", pI), + () -> delegate.makeNumber(pI)); } @Override public IntegerFormula makeNumber(Rational pRational) { - if (pRational.isIntegral()) { - return makeNumber(pRational.getNum()); - } else { - var num = makeNumber(pRational.getNum()); - var den = makeNumber(pRational.getDen()); - return divide(num, den); - } + return logger.logDef( + "mgr.getIntegerFormulaManager()", + String.format("makeNumber(Rational.of(\"%s\"))", pRational), + () -> delegate.makeNumber(pRational)); } @Override From f3c083bd7fea4ba1d601e1cf99bacf5037b26d97 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 31 Aug 2025 00:15:17 +0200 Subject: [PATCH 083/233] Trace: Error-prone, checkstyle --- .../java_smt/delegate/trace/TraceFormulaManager.java | 7 +++++-- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index a3decef3c9..14f526df64 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -10,6 +10,9 @@ package org.sosy_lab.java_smt.delegate.trace; +import static org.sosy_lab.common.collect.Collections3.transformedImmutableListCopy; +import static org.sosy_lab.common.collect.Collections3.transformedImmutableSetCopy; + import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; @@ -221,11 +224,11 @@ public T rebuild(T f) { } public List rebuildAll(List formulas) { - return FluentIterable.from(formulas).transform(this::rebuild).toList(); + return transformedImmutableListCopy(formulas, this::rebuild); } public Set rebuildAll(Set formulas) { - return FluentIterable.from(formulas).transform(this::rebuild).toSet(); + return transformedImmutableSetCopy(formulas, this::rebuild); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 1fdaf64a19..a289ff9e5d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -101,8 +101,8 @@ public void appendStmt(String pStmt) { try { lastLines.push(output.length()); output.write(String.format("%s;%n", pStmt).getBytes(StandardCharsets.UTF_8)); - } catch (IOException pIOException) { - throw new RuntimeException(pIOException); + } catch (IOException e) { + throw new RuntimeException(e); } } @@ -110,8 +110,8 @@ public void undoLast() { Preconditions.checkArgument(!lastLines.isEmpty(), "Cannot undo last trace"); try { output.setLength(lastLines.pop()); - } catch (IOException pE) { - throw new RuntimeException(pE); + } catch (IOException e) { + throw new RuntimeException(e); } } From fc625ad7338bea2edaf196f23575346a2e3d71f5 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Sun, 31 Aug 2025 00:09:45 +0200 Subject: [PATCH 084/233] Trace: rename trace-files in Junit-tests to match the corresponding test-name. --- .../java_smt/test/ModelEvaluationTest.java | 3 ++- .../test/NonLinearArithmeticTest.java | 3 ++- .../NonLinearArithmeticWithModuloTest.java | 3 ++- .../java_smt/test/OptimizationTest.java | 3 ++- .../java_smt/test/SolverBasedTest0.java | 23 +++++++++++++++++-- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/org/sosy_lab/java_smt/test/ModelEvaluationTest.java b/src/org/sosy_lab/java_smt/test/ModelEvaluationTest.java index 8974490f3d..50730295c7 100644 --- a/src/org/sosy_lab/java_smt/test/ModelEvaluationTest.java +++ b/src/org/sosy_lab/java_smt/test/ModelEvaluationTest.java @@ -17,6 +17,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.Test; import org.sosy_lab.common.configuration.ConfigurationBuilder; +import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.BooleanFormula; @@ -51,7 +52,7 @@ public class ModelEvaluationTest extends SolverBasedTest0.ParameterizedSolverBas private static int problemSize; @Override - protected ConfigurationBuilder createTestConfigBuilder() { + protected ConfigurationBuilder createTestConfigBuilder() throws InvalidConfigurationException { problemSize = solverToUse() == Solvers.PRINCESS ? 10 : 50; // Princess is too slow. ConfigurationBuilder builder = super.createTestConfigBuilder(); if (solverToUse() == Solvers.MATHSAT5) { diff --git a/src/org/sosy_lab/java_smt/test/NonLinearArithmeticTest.java b/src/org/sosy_lab/java_smt/test/NonLinearArithmeticTest.java index 74e9fec1b9..b33bdab575 100644 --- a/src/org/sosy_lab/java_smt/test/NonLinearArithmeticTest.java +++ b/src/org/sosy_lab/java_smt/test/NonLinearArithmeticTest.java @@ -25,6 +25,7 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.sosy_lab.common.configuration.ConfigurationBuilder; +import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.FormulaType; @@ -91,7 +92,7 @@ public void chooseNumeralFormulaManager() { public NonLinearArithmetic nonLinearArithmetic; @Override - protected ConfigurationBuilder createTestConfigBuilder() { + protected ConfigurationBuilder createTestConfigBuilder() throws InvalidConfigurationException { return super.createTestConfigBuilder() .setOption("solver.nonLinearArithmetic", nonLinearArithmetic.name()); } diff --git a/src/org/sosy_lab/java_smt/test/NonLinearArithmeticWithModuloTest.java b/src/org/sosy_lab/java_smt/test/NonLinearArithmeticWithModuloTest.java index c4b595d93d..eff809358d 100644 --- a/src/org/sosy_lab/java_smt/test/NonLinearArithmeticWithModuloTest.java +++ b/src/org/sosy_lab/java_smt/test/NonLinearArithmeticWithModuloTest.java @@ -22,6 +22,7 @@ import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.sosy_lab.common.configuration.ConfigurationBuilder; +import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; @@ -53,7 +54,7 @@ protected Solvers solverToUse() { public NonLinearArithmetic nonLinearArithmetic; @Override - protected ConfigurationBuilder createTestConfigBuilder() { + protected ConfigurationBuilder createTestConfigBuilder() throws InvalidConfigurationException { return super.createTestConfigBuilder() .setOption("solver.nonLinearArithmetic", nonLinearArithmetic.name()); } diff --git a/src/org/sosy_lab/java_smt/test/OptimizationTest.java b/src/org/sosy_lab/java_smt/test/OptimizationTest.java index ca2beefc6d..efc7646b6e 100644 --- a/src/org/sosy_lab/java_smt/test/OptimizationTest.java +++ b/src/org/sosy_lab/java_smt/test/OptimizationTest.java @@ -16,6 +16,7 @@ import org.junit.Before; import org.junit.Test; import org.sosy_lab.common.configuration.ConfigurationBuilder; +import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; import org.sosy_lab.java_smt.api.Model; @@ -29,7 +30,7 @@ public class OptimizationTest extends SolverBasedTest0.ParameterizedSolverBasedTest0 { @Override - protected ConfigurationBuilder createTestConfigBuilder() { + protected ConfigurationBuilder createTestConfigBuilder() throws InvalidConfigurationException { return super.createTestConfigBuilder().setOption("solver.mathsat5.loadOptimathsat5", "true"); } diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index b2a670f739..2e970f93f1 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -19,6 +19,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.After; import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; @@ -27,7 +29,10 @@ import org.sosy_lab.common.ShutdownNotifier; import org.sosy_lab.common.configuration.Configuration; import org.sosy_lab.common.configuration.ConfigurationBuilder; +import org.sosy_lab.common.configuration.FileOption; import org.sosy_lab.common.configuration.InvalidConfigurationException; +import org.sosy_lab.common.configuration.converters.FileTypeConverter; +import org.sosy_lab.common.io.PathTemplate; import org.sosy_lab.common.log.LogManager; import org.sosy_lab.java_smt.SolverContextFactory; import org.sosy_lab.java_smt.SolverContextFactory.Solvers; @@ -88,6 +93,8 @@ @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "test code") public abstract class SolverBasedTest0 { + @Rule public TestName testName = new TestName(); + protected Configuration config; protected final LogManager logger = LogManager.createTestLogManager(); @@ -123,14 +130,26 @@ protected Logics logicToUse() { return Logics.QF_AUFLIRA; } - protected ConfigurationBuilder createTestConfigBuilder() { + protected ConfigurationBuilder createTestConfigBuilder() throws InvalidConfigurationException { + String tracefile = + String.format( + "traces/%s/trace_%s_%s.java", + this.getClass().getSimpleName(), testName.getMethodName(), System.nanoTime()); + ConfigurationBuilder newConfig = Configuration.builder() .setOption("solver.solver", solverToUse().toString()) - .setOption("solver.trace", "true"); + .setOption("solver.trace", "true") + .setOption("solver.tracefile", tracefile); if (solverToUse() == Solvers.OPENSMT) { newConfig.setOption("solver.opensmt.logic", logicToUse().toString()); } + + Configuration configForFiles = Configuration.builder().setOption("output.path", "./").build(); + FileTypeConverter fileTypeConverter = FileTypeConverter.create(configForFiles); + Configuration.getDefaultConverters().put(FileOption.class, fileTypeConverter); + newConfig.addConverter(PathTemplate.class, fileTypeConverter); + return newConfig; } From e4694aed612f9694e1cf8f0743fb10c5addf3868 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Sun, 31 Aug 2025 00:18:37 +0200 Subject: [PATCH 085/233] Trace: use traces as test artifact. --- .appveyor.yml | 4 ++++ build/gitlab-ci.yml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 797eb36576..d5be0d5474 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -77,6 +77,10 @@ on_finish: echo "Compressing and uploading JUnit HTML report..." 7z a JUnit.html.zip JUnit.html Push-AppveyorArtifact JUnit.html.zip -DeploymentName "JUnit Report" + - ps: | + echo "Compressing and uploading trace files..." + 7z a traces.zip .\traces + Push-AppveyorArtifact traces.zip -DeploymentName "Traces" cache: - C:\ant diff --git a/build/gitlab-ci.yml b/build/gitlab-ci.yml index 292167666f..98a5ebc0f2 100644 --- a/build/gitlab-ci.yml +++ b/build/gitlab-ci.yml @@ -130,6 +130,7 @@ spotbugs: - "JUnit.html" - "JUnit-coverage/" - "junit/coverage.xml" + - "traces/" when: always reports: junit: "junit/TESTS-TestSuites.xml" @@ -141,6 +142,7 @@ spotbugs: artifacts: paths: - "JUnit.html" # no coverage files available + - "traces/" unit-tests:x86_64:jdk-11: extends: .unit-tests From 0efb1531d2491b46f041e67bbb54d48ee7918768 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 31 Aug 2025 09:35:30 +0200 Subject: [PATCH 086/233] Trace: Add python script for trace reduction --- scripts/reduceTrace.py | 128 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100755 scripts/reduceTrace.py diff --git a/scripts/reduceTrace.py b/scripts/reduceTrace.py new file mode 100755 index 0000000000..1645b4c648 --- /dev/null +++ b/scripts/reduceTrace.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +# This file is part of JavaSMT, +# an API wrapper for a collection of SMT solvers: +# https://github.com/sosy-lab/java-smt +# +# SPDX-FileCopyrightText: 2025 Dirk Beyer +# +# SPDX-License-Identifier: Apache-2.0 + +import re +import sys +from collections import defaultdict +from pathlib import Path + + +# Read a trace file +def readTrace(path): + with open(path) as file: + return [line.rstrip() for line in file] + + +# Build a map with line numbers for all variable definitions +def getLinesForDefinitions(trace): + lineNumber = 1 + lineDefs = dict() + for line in trace: + if line.find('=') >= 0: + leftSide = line[0:(line.find('=') - 1)] + name = re.match('var (.*)', leftSide) + lineDefs[name.group(1)] = lineNumber + lineNumber = lineNumber + 1 + return lineDefs + + +# Build a dependency graph for the definitions +# Maps from variables to the places where they are used +def buildDependencies(lineDefs, trace): + lineNumber = 1 + deps = defaultdict(list) + for line in trace: + expr = line[(line.find('=') + 2):] if line.find('=') >= 0 else line + object = expr[0:expr.find('.')] + if object[0].islower(): + deps[lineDefs[object]].append(lineNumber) + # FIXME Parse the expression to get the variables + for m in re.finditer('(config|logger|notifier|var[0-9]+)', expr): + deps[lineDefs[m.group()]].append(lineNumber) + lineNumber += 1 + return deps + + +# Collect all top-level statements +# Top-level statements are: +# *.addConstraint(*) +# *.isUnsat() +# *.getModel() +# *.asList() +# FIXME Finish this list +def usedTopLevel(lineDefs, trace): + tl = set() + for line in trace: + m = re.fullmatch( + 'var (var[0-9]+) = (var[0-9]+).(isUnsat\\(\\)|getModel\\(\\)|asList\\(\\)|addConstraint\\((var[0-9]+)\\));', + line) + if m != None: + tl.add(lineDefs[m.group(1)]) + return tl + + +# Calculate the closure of all used definitions, starting with the top-level statements +def usedClosure(tl, deps): + cl = set() + st = set(tl) + while cl.union(st) != cl: + cl = cl.union(st) + st = set() + for (key, val) in deps.items(): + if set(val).intersection(cl) != set(): + st.add(key) + return cl + + +# Keep only statements and definitions that are used +def filterUnused(used, trace): + lineNumber = 1 + reduced = [] + for line in trace: + if line.find('=') == -1 or lineNumber in used: + reduced.append(line) + lineNumber += 1 + return reduced + + +# Remove all definitions that are not used (recursively) +def removeDeadCode(trace): + lineDefs = getLinesForDefinitions(trace) + deps = buildDependencies(lineDefs, trace) + tl = usedTopLevel(lineDefs, trace) + cl = usedClosure(tl, deps) + return filterUnused(cl, trace) + + +if __name__ == '__main__': + arg = sys.argv + if not len(sys.argv) == 2: + print('Expecting a path to a trace file as argument') + exit(-1) + + path = Path(sys.argv[1]) + if not (path.is_file()): + print(f'Could not find file "{path}"') + exit(-1) + + # We'll use multiple passes to reduce the size of the trace: + # 1. Read the trace + # 2. Remove unused code + # 3. Remove unnecessary toplevel commands + # 4. Loop: Remove aliasing (by duplicating the definitions) + # 5. Loop: Reduce terms + # 6. Remove unused prover environments + + # TODO Implement steps 3-6 + # TODO Check that the reduced trace still crashes + + trace = readTrace(path) + for line in removeDeadCode(trace): + print(line) From c34023fd082aad02fad37c969978074aebc0a135 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 31 Aug 2025 12:11:44 +0200 Subject: [PATCH 087/233] Trace: Rewrite to_real as unary sum --- .../java_smt/delegate/trace/TraceFormulaManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 14f526df64..a3664711c7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -555,9 +555,10 @@ public T makeApplication( break; case GTE_ZERO: break; - case TO_REAL: - break; */ + case TO_REAL: + return (T) + getRationalFormulaManager().sum(ImmutableList.of((NumeralFormula) args.get(0))); case FLOOR: { if (args.get(0) instanceof IntegerFormula) { From 4aa4c4eef72b25842b520629774bacd556cacf7a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 31 Aug 2025 12:20:39 +0200 Subject: [PATCH 088/233] Trace: Skip the 0 term when building sums --- .../basicimpl/AbstractNumeralFormulaManager.java | 13 +++++++++---- .../solvers/z3/Z3NumeralFormulaManager.java | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java index 72d3e65574..70318fea94 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java @@ -207,11 +207,16 @@ public ResultFormulaType sum(List operands) { } protected TFormulaInfo sumImpl(List operands) { - TFormulaInfo result = makeNumberImpl(0); - for (TFormulaInfo operand : operands) { - result = add(result, operand); + if (operands.isEmpty()) { + return makeNumberImpl(0); + } else { + TFormulaInfo result = operands.get(0); + ; + for (TFormulaInfo operand : operands.subList(1, operands.size())) { + result = add(result, operand); + } + return result; } - return result; } @Override diff --git a/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java index ea834fbdb1..218e50a8e1 100644 --- a/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java @@ -74,6 +74,8 @@ protected Long add(Long pNumber1, Long pNumber2) { protected Long sumImpl(List operands) { if (operands.isEmpty()) { return makeNumberImpl(0); + } else if (operands.size() == 1) { + return operands.get(0); } else { return Native.mkAdd(z3context, operands.size(), Longs.toArray(operands)); } From aa7d584184e7c7e2ab6069fd291d059a95377591 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 31 Aug 2025 12:21:16 +0200 Subject: [PATCH 089/233] Trace: Simplify the arguments in UF calls --- .../java_smt/delegate/trace/TraceUFManager.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 76d3950935..4620c6e8f9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -64,19 +64,12 @@ public FunctionDeclaration declareUF( public T callUF( FunctionDeclaration funcType, List args) { if (funcType.getKind().equals(FunctionDeclarationKind.UF)) { - String var = logger.newVariable(); - logger.appendDef( - var, + return logger.logDef( + "mgr.getUFManager", String.format( "callUF(%s, ImmutableList.of(%s))", - logger.toVariable(funcType), logger.toVariables(args))); - T f = delegate.callUF(funcType, args); - if (logger.isTracked(f)) { - logger.undoLast(); - } else { - logger.mapVariable(var, f); - } - return f; + logger.toVariable(funcType), logger.toVariables(args)), + () -> delegate.callUF(funcType, args)); } else { return mgr.makeApplication(funcType, args); } From 4b3f03f04edd4c9862d413f55ec9dd7418c550fd Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 21:05:19 +0200 Subject: [PATCH 090/233] fix compiler warning. --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index a3664711c7..3cd440081d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -126,7 +126,7 @@ public EnumerationFormulaManager getEnumerationFormulaManager() { } private class Rebuilder extends FormulaTransformationVisitor { - protected Rebuilder(FormulaManager fmgr) { + Rebuilder(FormulaManager fmgr) { super(fmgr); } From aa51b7e969905093c24abd0e5caebf49fd6d58d4 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Sat, 30 Aug 2025 23:00:26 +0200 Subject: [PATCH 091/233] simplify Trace*FormulaManagers by not overriding default methods from API. --- .../delegate/trace/TraceBooleanFormulaManager.java | 10 ---------- .../java_smt/delegate/trace/TraceUFManager.java | 11 ----------- 2 files changed, 21 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 0f5d6ae9a1..05b46103ca 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -118,11 +118,6 @@ public BooleanFormula and(Collection bits) { () -> delegate.and(bits)); } - @Override - public BooleanFormula and(BooleanFormula... bits) { - return and(Arrays.asList(bits)); - } - @Override public Collector toConjunction() { return Collectors.collectingAndThen(Collectors.toList(), this::and); @@ -141,11 +136,6 @@ public BooleanFormula or(Collection bits) { () -> delegate.or(bits)); } - @Override - public BooleanFormula or(BooleanFormula... bits) { - return or(Arrays.asList(bits)); - } - @Override public Collector toDisjunction() { return Collectors.collectingAndThen(Collectors.toList(), this::or); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 4620c6e8f9..baed704d4f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -54,12 +54,6 @@ public FunctionDeclaration declareUF( return f; } - @Override - public FunctionDeclaration declareUF( - String name, FormulaType returnType, FormulaType... args) { - return declareUF(name, returnType, Arrays.asList(args)); - } - @Override public T callUF( FunctionDeclaration funcType, List args) { @@ -75,11 +69,6 @@ public T callUF( } } - @Override - public T callUF(FunctionDeclaration funcType, Formula... args) { - return callUF(funcType, Arrays.asList(args)); - } - @Override public T declareAndCallUF( String name, FormulaType pReturnType, List pArgs) { From 52b2040e93f7df65d3302c88dc41b5e77086269a Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 21:00:29 +0200 Subject: [PATCH 092/233] Tracing: add TraceSLFormulaManager. --- .../java_smt/api/SLFormulaManager.java | 4 +- .../delegate/trace/TraceFormulaManager.java | 2 +- .../delegate/trace/TraceSLFormulaManager.java | 74 +++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java diff --git a/src/org/sosy_lab/java_smt/api/SLFormulaManager.java b/src/org/sosy_lab/java_smt/api/SLFormulaManager.java index 46cfcf7e01..15575fa119 100644 --- a/src/org/sosy_lab/java_smt/api/SLFormulaManager.java +++ b/src/org/sosy_lab/java_smt/api/SLFormulaManager.java @@ -80,8 +80,8 @@ public interface SLFormulaManager { * * @param the type of the address formula. * @param the type of the address formula type. - * @param pAdressType the type of the address formula. + * @param pAddressType the type of the address formula. * @return a formula representing the "nil" element for the given address type. */ - > AF makeNilElement(AT pAdressType); + > AF makeNilElement(AT pAddressType); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 3cd440081d..c2dcadb266 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -107,7 +107,7 @@ public UFManager getUFManager() { @Override public SLFormulaManager getSLFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceSLFormulaManager(delegate.getSLFormulaManager(), logger); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java new file mode 100644 index 0000000000..34e5034afd --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java @@ -0,0 +1,74 @@ +// This file is part of JavaSMT, +// an API wrapper for a collection of SMT solvers: +// https://github.com/sosy-lab/java-smt +// +// SPDX-FileCopyrightText: 2025 Dirk Beyer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.sosy_lab.java_smt.delegate.trace; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.SLFormulaManager; + +public class TraceSLFormulaManager implements SLFormulaManager { + + private final SLFormulaManager delegate; + private final TraceLogger logger; + + TraceSLFormulaManager(SLFormulaManager pDelegate, TraceLogger pLogger) { + delegate = checkNotNull(pDelegate); + logger = checkNotNull(pLogger); + } + + @Override + public BooleanFormula makeStar(BooleanFormula f1, BooleanFormula f2) { + return logger.logDef( + "mgr.getSLFormulaManager()", + String.format("makeStar(%s, %s)", logger.toVariable(f1), logger.toVariable(f2)), + () -> delegate.makeStar(f1, f2)); + } + + @Override + public BooleanFormula makePointsTo(AF ptr, VF to) { + return logger.logDef( + "mgr.getSLFormulaManager()", + String.format("makePointsTo(%s, %s)", logger.toVariable(ptr), logger.toVariable(to)), + () -> delegate.makePointsTo(ptr, to)); + } + + @Override + public BooleanFormula makeMagicWand(BooleanFormula f1, BooleanFormula f2) { + return logger.logDef( + "mgr.getSLFormulaManager()", + String.format("makeMagicWand(%s, %s)", logger.toVariable(f1), logger.toVariable(f2)), + () -> delegate.makeMagicWand(f1, f2)); + } + + @Override + public < + AF extends Formula, + VF extends Formula, + AT extends FormulaType, + VT extends FormulaType> + BooleanFormula makeEmptyHeap(AT pAddressType, VT pValueType) { + return logger.logDef( + "mgr.getSLFormulaManager()", + String.format( + "makeEmptyHeap(%s, %s)", + logger.printFormulaType(pAddressType), logger.printFormulaType(pValueType)), + () -> delegate.makeEmptyHeap(pAddressType, pValueType)); + } + + @Override + public > AF makeNilElement(AT pAddressType) { + return logger.logDef( + "mgr.getSLFormulaManager()", + String.format("makeNilElement(%s)", logger.printFormulaType(pAddressType)), + () -> delegate.makeNilElement(pAddressType)); + } +} From 691930591f4c7cda3aee695fa43b95cfe873472d Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 21:27:42 +0200 Subject: [PATCH 093/233] Tracing: add TraceQuantifiedFormulaManager. --- .../delegate/trace/TraceFormulaManager.java | 2 +- .../trace/TraceQuantifiedFormulaManager.java | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index c2dcadb266..5503034e9c 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -112,7 +112,7 @@ public SLFormulaManager getSLFormulaManager() { @Override public QuantifiedFormulaManager getQuantifiedFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceQuantifiedFormulaManager(delegate.getQuantifiedFormulaManager(), logger); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java new file mode 100644 index 0000000000..751da33644 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java @@ -0,0 +1,48 @@ +// This file is part of JavaSMT, +// an API wrapper for a collection of SMT solvers: +// https://github.com/sosy-lab/java-smt +// +// SPDX-FileCopyrightText: 2025 Dirk Beyer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.sosy_lab.java_smt.delegate.trace; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.Formula; +import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; +import org.sosy_lab.java_smt.api.SolverException; + +public class TraceQuantifiedFormulaManager implements QuantifiedFormulaManager { + + private final QuantifiedFormulaManager delegate; + private final TraceLogger logger; + + TraceQuantifiedFormulaManager(QuantifiedFormulaManager pDelegate, TraceLogger pLogger) { + delegate = checkNotNull(pDelegate); + logger = checkNotNull(pLogger); + } + + @Override + public BooleanFormula mkQuantifier( + Quantifier q, List pVariables, BooleanFormula pBody) { + return logger.logDef( + "mgr.getQuantifiedFormulaManager()", + String.format( + "mkQuantifier(Quantifier.%s, List.of(%s), %s)", + q, logger.toVariables(pVariables), logger.toVariable(pBody)), + () -> delegate.mkQuantifier(q, pVariables, pBody)); + } + + @Override + public BooleanFormula eliminateQuantifiers(BooleanFormula pF) + throws InterruptedException, SolverException { + return logger.logDef( + "mgr.getQuantifiedFormulaManager()", + String.format("eliminateQuantifiers(%s)", logger.toVariable(pF)), + () -> delegate.eliminateQuantifiers(pF)); + } +} From 9dd1f3ef374e29d53e552fd840e755fd91544e84 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 21:59:09 +0200 Subject: [PATCH 094/233] Tracing: add TraceStringFormulaManager. --- .../delegate/trace/TraceFormulaManager.java | 3 +- .../trace/TraceStringFormulaManager.java | 320 ++++++++++++++++++ 2 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 5503034e9c..f517283979 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -51,6 +51,7 @@ import org.sosy_lab.java_smt.api.RationalFormulaManager; import org.sosy_lab.java_smt.api.SLFormulaManager; import org.sosy_lab.java_smt.api.SolverException; +import org.sosy_lab.java_smt.api.StringFormula; import org.sosy_lab.java_smt.api.StringFormulaManager; import org.sosy_lab.java_smt.api.Tactic; import org.sosy_lab.java_smt.api.UFManager; @@ -117,7 +118,7 @@ public QuantifiedFormulaManager getQuantifiedFormulaManager() { @Override public StringFormulaManager getStringFormulaManager() { - throw new UnsupportedOperationException(); + return new TraceStringFormulaManager(delegate.getStringFormulaManager(), logger); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java new file mode 100644 index 0000000000..6881e35914 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java @@ -0,0 +1,320 @@ +// This file is part of JavaSMT, +// an API wrapper for a collection of SMT solvers: +// https://github.com/sosy-lab/java-smt +// +// SPDX-FileCopyrightText: 2025 Dirk Beyer +// +// SPDX-License-Identifier: Apache-2.0 + +package org.sosy_lab.java_smt.delegate.trace; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; +import org.sosy_lab.java_smt.api.RegexFormula; +import org.sosy_lab.java_smt.api.StringFormula; +import org.sosy_lab.java_smt.api.StringFormulaManager; + +public class TraceStringFormulaManager implements StringFormulaManager { + + private final StringFormulaManager delegate; + private final TraceLogger logger; + + TraceStringFormulaManager(StringFormulaManager pDelegate, TraceLogger pLogger) { + delegate = checkNotNull(pDelegate); + logger = checkNotNull(pLogger); + } + + @Override + public StringFormula makeString(String value) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("makeString(\"%s\")", value), + () -> delegate.makeString(value)); + } + + @Override + public StringFormula makeVariable(String pVar) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("makeVariable(\"%s\")", pVar), + () -> delegate.makeVariable(pVar)); + } + + @Override + public BooleanFormula equal(StringFormula str1, StringFormula str2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("equal(%s, %s)", logger.toVariable(str1), logger.toVariable(str2)), + () -> delegate.equal(str1, str2)); + } + + @Override + public BooleanFormula greaterThan(StringFormula str1, StringFormula str2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("greaterThan(%s, %s)", logger.toVariable(str1), logger.toVariable(str2)), + () -> delegate.greaterThan(str1, str2)); + } + + @Override + public BooleanFormula greaterOrEquals(StringFormula str1, StringFormula str2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("greaterOrEquals(%s, %s)", logger.toVariable(str1), logger.toVariable(str2)), + () -> delegate.greaterOrEquals(str1, str2)); + } + + @Override + public BooleanFormula lessThan(StringFormula str1, StringFormula str2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("lessThan(%s, %s)", logger.toVariable(str1), logger.toVariable(str2)), + () -> delegate.lessThan(str1, str2)); + } + + @Override + public BooleanFormula lessOrEquals(StringFormula str1, StringFormula str2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("lessOrEquals(%s, %s)", logger.toVariable(str1), logger.toVariable(str2)), + () -> delegate.lessOrEquals(str1, str2)); + } + + @Override + public BooleanFormula prefix(StringFormula prefix, StringFormula str) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("prefix(%s, %s)", logger.toVariable(prefix), logger.toVariable(str)), + () -> delegate.prefix(prefix, str)); + } + + @Override + public BooleanFormula suffix(StringFormula suffix, StringFormula str) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("suffix(%s, %s)", logger.toVariable(suffix), logger.toVariable(str)), + () -> delegate.suffix(suffix, str)); + } + + @Override + public BooleanFormula contains(StringFormula str, StringFormula part) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("contains(%s, %s)", logger.toVariable(str), logger.toVariable(part)), + () -> delegate.contains(str, part)); + } + + @Override + public IntegerFormula indexOf(StringFormula str, StringFormula part, IntegerFormula startIndex) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format( + "indexOf(%s, %s, %s)", + logger.toVariable(str), logger.toVariable(part), logger.toVariable(startIndex)), + () -> delegate.indexOf(str, part, startIndex)); + } + + @Override + public StringFormula charAt(StringFormula str, IntegerFormula index) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("charAt(%s, %s)", logger.toVariable(str), logger.toVariable(index)), + () -> delegate.charAt(str, index)); + } + + @Override + public StringFormula substring(StringFormula str, IntegerFormula index, IntegerFormula length) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format( + "substring(%s, %s, %s)", + logger.toVariable(str), logger.toVariable(index), logger.toVariable(length)), + () -> delegate.substring(str, index, length)); + } + + @Override + public StringFormula replace( + StringFormula fullStr, StringFormula target, StringFormula replacement) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format( + "replace(%s, %s, %s)", + logger.toVariable(fullStr), logger.toVariable(target), logger.toVariable(replacement)), + () -> delegate.replace(fullStr, target, replacement)); + } + + @Override + public StringFormula replaceAll( + StringFormula fullStr, StringFormula target, StringFormula replacement) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format( + "replaceAll(%s, %s, %s)", + logger.toVariable(fullStr), logger.toVariable(target), logger.toVariable(replacement)), + () -> delegate.replaceAll(fullStr, target, replacement)); + } + + @Override + public IntegerFormula length(StringFormula str) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("length(%s)", logger.toVariable(str)), + () -> delegate.length(str)); + } + + @Override + public StringFormula concat(List parts) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format( + "concat(%s)", + parts.stream().map(logger::toVariable).reduce((a, b) -> a + ", " + b).orElse("")), + () -> delegate.concat(parts)); + } + + @Override + public BooleanFormula in(StringFormula str, RegexFormula regex) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("in(%s, %s)", logger.toVariable(str), logger.toVariable(regex)), + () -> delegate.in(str, regex)); + } + + @Override + public RegexFormula makeRegex(String value) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("makeRegex(\"%s\")", value), + () -> delegate.makeRegex(value)); + } + + @Override + public RegexFormula none() { + return logger.logDef("mgr.getStringFormulaManager()", "none()", delegate::none); + } + + @Override + public RegexFormula all() { + return logger.logDef("mgr.getStringFormulaManager()", "all()", delegate::all); + } + + @Override + public RegexFormula allChar() { + return logger.logDef("mgr.getStringFormulaManager()", "allChar()", delegate::allChar); + } + + @Override + public RegexFormula range(StringFormula start, StringFormula end) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("range(%s, %s)", logger.toVariable(start), logger.toVariable(end)), + () -> delegate.range(start, end)); + } + + @Override + public RegexFormula concatRegex(List parts) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("concatRegex(%s)", logger.toVariables(parts)), + () -> delegate.concatRegex(parts)); + } + + @Override + public RegexFormula union(RegexFormula regex1, RegexFormula regex2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("union(%s, %s)", logger.toVariable(regex1), logger.toVariable(regex2)), + () -> delegate.union(regex1, regex2)); + } + + @Override + public RegexFormula intersection(RegexFormula regex1, RegexFormula regex2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("intersection(%s, %s)", logger.toVariable(regex1), logger.toVariable(regex2)), + () -> delegate.intersection(regex1, regex2)); + } + + @Override + public RegexFormula complement(RegexFormula regex) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("complement(%s)", logger.toVariable(regex)), + () -> delegate.complement(regex)); + } + + @Override + public RegexFormula closure(RegexFormula regex) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("closure(%s)", logger.toVariable(regex)), + () -> delegate.closure(regex)); + } + + @Override + public RegexFormula difference(RegexFormula regex1, RegexFormula regex2) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("difference(%s, %s)", logger.toVariable(regex1), logger.toVariable(regex2)), + () -> delegate.difference(regex1, regex2)); + } + + @Override + public RegexFormula cross(RegexFormula regex) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("cross(%s)", logger.toVariable(regex)), + () -> delegate.cross(regex)); + } + + @Override + public RegexFormula optional(RegexFormula regex) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("optional(%s)", logger.toVariable(regex)), + () -> delegate.optional(regex)); + } + + @Override + public RegexFormula times(RegexFormula regex, int repetitions) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("times(%s, %d)", logger.toVariable(regex), repetitions), + () -> delegate.times(regex, repetitions)); + } + + @Override + public IntegerFormula toIntegerFormula(StringFormula str) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("toIntegerFormula(%s)", logger.toVariable(str)), + () -> delegate.toIntegerFormula(str)); + } + + @Override + public StringFormula toStringFormula(IntegerFormula number) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("toStringFormula(%s)", logger.toVariable(number)), + () -> delegate.toStringFormula(number)); + } + + @Override + public IntegerFormula toCodePoint(StringFormula str) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("toCodePoint(%s)", logger.toVariable(str)), + () -> delegate.toCodePoint(str)); + } + + @Override + public StringFormula fromCodePoint(IntegerFormula codePoint) { + return logger.logDef( + "mgr.getStringFormulaManager()", + String.format("fromCodePoint(%s)", logger.toVariable(codePoint)), + () -> delegate.fromCodePoint(codePoint)); + } +} From 78a11761f75113f889383b40fad0081f03dec541 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 22:00:03 +0200 Subject: [PATCH 095/233] Tracing: initial application for String formulas. --- .../delegate/trace/TraceFormulaManager.java | 70 +++++++++++++++---- .../java_smt/delegate/trace/TraceLogger.java | 3 +- .../java_smt/solvers/z3/Z3FormulaCreator.java | 3 +- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index f517283979..c50cf5f8ca 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -188,6 +188,13 @@ public Formula visitConstant(Formula f, Object value) { String.format("makeNumber(%s)", value), () -> delegate.getRationalFormulaManager().makeNumber((Rational) value)); Preconditions.checkArgument(g.equals(f)); + } else if (f instanceof StringFormula && value instanceof String) { + var g = + logger.logDef( + "mgr.getStringFormulaManager()", + String.format("makeString(%s)", value), + () -> delegate.getStringFormulaManager().makeString((String) value)); + Preconditions.checkArgument(g.equals(f)); } else { throw new IllegalArgumentException( String.format( @@ -304,6 +311,7 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_IS_NORMAL: case FP_AS_IEEEBV: case FP_FROM_IEEEBV: + case RE_COMPLEMENT: return 1; case SELECT: @@ -341,6 +349,7 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_CASTTO_FP: case FP_CASTTO_SBV: case FP_CASTTO_UBV: + case STR_CONCAT: return 2; case ITE: @@ -835,28 +844,65 @@ public T makeApplication( getFloatingPointFormulaManager() .fromIeeeBitvector( (BitvectorFormula) args.get(0), (FloatingPointType) declaration.getType()); - // TODO - /* case STR_CONCAT: - break; + Preconditions.checkArgument(args.size() >= 2); + return (T) getStringFormulaManager().concat((List) args); case STR_PREFIX: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .prefix((StringFormula) args.get(0), (StringFormula) args.get(1)); case STR_SUFFIX: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .suffix((StringFormula) args.get(0), (StringFormula) args.get(1)); case STR_CONTAINS: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .contains((StringFormula) args.get(0), (StringFormula) args.get(1)); case STR_SUBSTRING: - break; + Preconditions.checkArgument(args.size() == 3); + return (T) + getStringFormulaManager() + .substring( + (StringFormula) args.get(0), + (IntegerFormula) args.get(1), + (IntegerFormula) args.get(2)); case STR_REPLACE: - break; + Preconditions.checkArgument(args.size() == 3); + return (T) + getStringFormulaManager() + .replace( + (StringFormula) args.get(0), + (StringFormula) args.get(1), + (StringFormula) args.get(2)); case STR_REPLACE_ALL: - break; + Preconditions.checkArgument(args.size() == 3); + return (T) + getStringFormulaManager() + .replaceAll( + (StringFormula) args.get(0), + (StringFormula) args.get(1), + (StringFormula) args.get(2)); case STR_CHAR_AT: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .charAt((StringFormula) args.get(0), (IntegerFormula) args.get(1)); case STR_LENGTH: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().length((StringFormula) args.get(0)); case STR_INDEX_OF: - break; + Preconditions.checkArgument(args.size() == 3); + return (T) + getStringFormulaManager() + .indexOf( + (StringFormula) args.get(0), + (StringFormula) args.get(1), + (IntegerFormula) args.get(2)); + /* case STR_TO_RE: break; case STR_IN_RE: diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index a289ff9e5d..003eb7da77 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -231,6 +231,7 @@ public String printFormulaType(FormulaType pType) { fpType.getExponentSize(), fpType.getMantissaSize()); } // FIXME Handle other cases - throw new IllegalArgumentException("Unsupported formula type: " + pType); + throw new IllegalArgumentException( + String.format("Unsupported formula type %s of class %s.", pType, pType.getClass())); } } diff --git a/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java index edd4da657d..69ec1a07a9 100644 --- a/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java @@ -9,7 +9,6 @@ package org.sosy_lab.java_smt.solvers.z3; import static com.google.common.base.Preconditions.checkArgument; -import static com.microsoft.z3.enumerations.Z3_decl_kind.Z3_OP_DISTINCT; import com.google.common.base.Preconditions; import com.google.common.collect.HashBasedTable; @@ -621,7 +620,7 @@ private FunctionDeclarationKind getDeclarationKind(long f) { Z3_decl_kind decl = Z3_decl_kind.fromInt(Native.getDeclKind(environment, Native.getAppDecl(environment, f))); - assert (arity > 0) || (arity == 0 && decl == Z3_OP_DISTINCT) + assert arity >= 0 : String.format( "Unexpected arity '%s' for formula '%s' for handling a function application.", arity, Native.astToString(environment, f)); From 1262c6522d401bdb62c9c7992c20bf9babb57d3f Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 22:59:05 +0200 Subject: [PATCH 096/233] Tracing: support more string operations. --- .../java_smt/api/FunctionDeclarationKind.java | 2 + .../delegate/trace/TraceFormulaManager.java | 69 ++++++++++++++----- .../solvers/cvc5/CVC5FormulaCreator.java | 1 + .../princess/PrincessFormulaCreator.java | 2 + 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java index a203fa1f2d..e3920a4395 100644 --- a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java +++ b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java @@ -304,6 +304,8 @@ public enum FunctionDeclarationKind { STR_TO_CODE, STR_LT, STR_LE, + + RE_NONE, RE_PLUS, RE_STAR, RE_OPTIONAL, diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index c50cf5f8ca..cd25c35bea 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -49,6 +49,7 @@ import org.sosy_lab.java_smt.api.QuantifiedFormulaManager; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; import org.sosy_lab.java_smt.api.RationalFormulaManager; +import org.sosy_lab.java_smt.api.RegexFormula; import org.sosy_lab.java_smt.api.SLFormulaManager; import org.sosy_lab.java_smt.api.SolverException; import org.sosy_lab.java_smt.api.StringFormula; @@ -278,6 +279,7 @@ private int getArity(FunctionDeclaration pDeclaration) { case BV_SUB: case BV_ADD: case BV_MUL: + case RE_CONCAT: return -1; case FP_ROUND_EVEN: @@ -285,6 +287,7 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_ROUND_POSITIVE: case FP_ROUND_NEGATIVE: case FP_ROUND_ZERO: + case RE_NONE: return 0; case NOT: @@ -311,6 +314,7 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_IS_NORMAL: case FP_AS_IEEEBV: case FP_FROM_IEEEBV: + case STR_LENGTH: case RE_COMPLEMENT: return 1; @@ -350,6 +354,7 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_CASTTO_SBV: case FP_CASTTO_UBV: case STR_CONCAT: + case RE_RANGE: return 2; case ITE: @@ -902,41 +907,73 @@ public T makeApplication( (StringFormula) args.get(0), (StringFormula) args.get(1), (IntegerFormula) args.get(2)); - /* + /* TODO case STR_TO_RE: break; case STR_IN_RE: break; + */ case STR_TO_INT: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().toIntegerFormula((StringFormula) args.get(0)); case INT_TO_STR: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().toStringFormula((IntegerFormula) args.get(0)); case STR_FROM_CODE: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().fromCodePoint((IntegerFormula) args.get(0)); case STR_TO_CODE: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().toCodePoint((StringFormula) args.get(0)); case STR_LT: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .lessThan((StringFormula) args.get(0), (StringFormula) args.get(1)); case STR_LE: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .lessOrEquals((StringFormula) args.get(0), (StringFormula) args.get(1)); + case RE_NONE: + Preconditions.checkArgument(args.isEmpty()); + return (T) getStringFormulaManager().none(); case RE_PLUS: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().cross((RegexFormula) args.get(0)); case RE_STAR: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().closure((RegexFormula) args.get(0)); case RE_OPTIONAL: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().optional((RegexFormula) args.get(0)); case RE_CONCAT: - break; + Preconditions.checkArgument(args.size() >= 2); + return (T) getStringFormulaManager().concatRegex((List) args); case RE_UNION: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .union((RegexFormula) args.get(0), (RegexFormula) args.get(1)); case RE_RANGE: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .range((StringFormula) args.get(0), (StringFormula) args.get(1)); case RE_INTERSECT: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .intersection((RegexFormula) args.get(0), (RegexFormula) args.get(1)); case RE_COMPLEMENT: - break; + Preconditions.checkArgument(args.size() == 1); + return (T) getStringFormulaManager().complement((RegexFormula) args.get(0)); case RE_DIFFERENCE: - break; + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager() + .difference((RegexFormula) args.get(0), (RegexFormula) args.get(1)); + /* TODO case OTHER: break; */ diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java index 946b6be069..6ff9f8f84a 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java @@ -624,6 +624,7 @@ private Term normalize(Term operator) { .put(Kind.STRING_FROM_CODE, FunctionDeclarationKind.STR_FROM_CODE) .put(Kind.STRING_LT, FunctionDeclarationKind.STR_LT) .put(Kind.STRING_LEQ, FunctionDeclarationKind.STR_LE) + .put(Kind.REGEXP_NONE, FunctionDeclarationKind.RE_NONE) .put(Kind.REGEXP_PLUS, FunctionDeclarationKind.RE_PLUS) .put(Kind.REGEXP_STAR, FunctionDeclarationKind.RE_STAR) .put(Kind.REGEXP_OPT, FunctionDeclarationKind.RE_OPTIONAL) diff --git a/src/org/sosy_lab/java_smt/solvers/princess/PrincessFormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/princess/PrincessFormulaCreator.java index 6f325cb173..9e4966cdad 100644 --- a/src/org/sosy_lab/java_smt/solvers/princess/PrincessFormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/princess/PrincessFormulaCreator.java @@ -602,6 +602,8 @@ private FunctionDeclarationKind getDeclarationKind(IExpression input) { return FunctionDeclarationKind.OTHER; } else if (fun == ModuloArithmetic.int_cast()) { return FunctionDeclarationKind.OTHER; + } else if (fun == PrincessEnvironment.stringTheory.re_none()) { + return FunctionDeclarationKind.RE_NONE; } else { return FunctionDeclarationKind.UF; } From b03045c056148cf41d256aaf7b74913e5f1d6867 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Tue, 16 Sep 2025 23:20:19 +0200 Subject: [PATCH 097/233] Tracing: simplify inherited methods. --- .../java_smt/delegate/trace/TraceBooleanFormulaManager.java | 6 +++--- .../sosy_lab/java_smt/delegate/trace/TraceUFManager.java | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 05b46103ca..2cba7a01f3 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -10,7 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; -import java.util.Arrays; +import com.google.common.collect.ImmutableList; import java.util.Collection; import java.util.Set; import java.util.stream.Collector; @@ -107,7 +107,7 @@ public BooleanFormula not(BooleanFormula formula) { @Override public BooleanFormula and(BooleanFormula formula1, BooleanFormula formula2) { - return and(Arrays.asList(formula1, formula2)); + return and(ImmutableList.of(formula1, formula2)); } @Override @@ -125,7 +125,7 @@ public BooleanFormula and(Collection bits) { @Override public BooleanFormula or(BooleanFormula formula1, BooleanFormula formula2) { - return or(Arrays.asList(formula1, formula2)); + return or(ImmutableList.of(formula1, formula2)); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index baed704d4f..c5d0b7960d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -78,10 +78,4 @@ public T declareAndCallUF( } return callUF(declareUF(name, pReturnType, builder.build()), pArgs); } - - @Override - public T declareAndCallUF( - String name, FormulaType pReturnType, Formula... pArgs) { - return declareAndCallUF(name, pReturnType, Arrays.asList(pArgs)); - } } From 0766916400001ed74264ae1549c67979c59dd565 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 07:43:16 +0200 Subject: [PATCH 098/233] fix CheckStyle warnings. --- .../java_smt/basicimpl/AbstractNumeralFormulaManager.java | 1 - .../sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java | 1 + src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java index 70318fea94..b3fc78f24f 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractNumeralFormulaManager.java @@ -211,7 +211,6 @@ protected TFormulaInfo sumImpl(List operands) { return makeNumberImpl(0); } else { TFormulaInfo result = operands.get(0); - ; for (TFormulaInfo operand : operands.subList(1, operands.size())) { result = add(result, operand); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java index 34e5034afd..a458eb0815 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSLFormulaManager.java @@ -15,6 +15,7 @@ import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.SLFormulaManager; +@SuppressWarnings("MethodTypeParameterName") public class TraceSLFormulaManager implements SLFormulaManager { private final SLFormulaManager delegate; diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index c5d0b7960d..16ab4dc09c 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -13,7 +13,6 @@ import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; -import java.util.Arrays; import java.util.List; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; From 3be04cd6ec8a867b97229c1580022a18c7b53921 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 07:53:14 +0200 Subject: [PATCH 099/233] Tracing: more support for String theory. --- src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java | 3 +++ src/org/sosy_lab/java_smt/test/ArrayFormulaManagerTest.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 003eb7da77..c6372705b2 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -230,6 +230,9 @@ public String printFormulaType(FormulaType pType) { "FormulaType.getFloatingPointType(%s, %s)", fpType.getExponentSize(), fpType.getMantissaSize()); } + if (pType.isStringType()) { + return "FormulaType.StringType"; + } // FIXME Handle other cases throw new IllegalArgumentException( String.format("Unsupported formula type %s of class %s.", pType, pType.getClass())); diff --git a/src/org/sosy_lab/java_smt/test/ArrayFormulaManagerTest.java b/src/org/sosy_lab/java_smt/test/ArrayFormulaManagerTest.java index 667806203b..95ecf96cf2 100644 --- a/src/org/sosy_lab/java_smt/test/ArrayFormulaManagerTest.java +++ b/src/org/sosy_lab/java_smt/test/ArrayFormulaManagerTest.java @@ -88,9 +88,9 @@ public void testIntIndexStringValue() throws SolverException, InterruptedExcepti StringFormula stringTwo = smgr.makeString("two"); IntegerFormula intFour = imgr.makeNumber(4); ArrayFormula arr1 = - amgr.makeArray("arr1", FormulaType.IntegerType, StringType); + amgr.makeArray("arr1", IntegerType, StringType); ArrayFormula arr2 = - amgr.makeArray("arr2", FormulaType.IntegerType, StringType); + amgr.makeArray("arr2", IntegerType, StringType); BooleanFormula query = bmgr.and( amgr.equivalence(arr2, amgr.store(arr1, intFour, stringTwo)), From f2531f579a26141f2ea3f1b8d16a36384a60a107 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 12:12:51 +0200 Subject: [PATCH 100/233] Tracing: disable tracing for Boolector in tests. Boolector does not provide required formula visitation. --- .../java_smt/test/SolverBasedTest0.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java index a39753d56d..e9af265c7e 100644 --- a/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java +++ b/src/org/sosy_lab/java_smt/test/SolverBasedTest0.java @@ -131,25 +131,24 @@ protected Logics logicToUse() { } protected ConfigurationBuilder createTestConfigBuilder() throws InvalidConfigurationException { - String tracefile = - String.format( - "traces/%s/trace_%s_%s.java", - this.getClass().getSimpleName(), testName.getMethodName(), System.nanoTime()); - ConfigurationBuilder newConfig = - Configuration.builder() - .setOption("solver.solver", solverToUse().toString()) - .setOption("solver.trace", "true") - .setOption("solver.tracefile", tracefile); + Configuration.builder().setOption("solver.solver", solverToUse().toString()); + + if (solverToUse() != Solvers.BOOLECTOR) { // Boolector has no formula visitation. + String tracefile = + String.format( + "traces/%s/trace_%s_%s.java", + this.getClass().getSimpleName(), testName.getMethodName(), System.nanoTime()); + newConfig.setOption("solver.trace", "true").setOption("solver.tracefile", tracefile); + Configuration configForFiles = Configuration.builder().setOption("output.path", "./").build(); + FileTypeConverter fileTypeConverter = FileTypeConverter.create(configForFiles); + Configuration.getDefaultConverters().put(FileOption.class, fileTypeConverter); + newConfig.addConverter(PathTemplate.class, fileTypeConverter); + } if (solverToUse() == Solvers.OPENSMT) { newConfig.setOption("solver.opensmt.logic", logicToUse().toString()); } - Configuration configForFiles = Configuration.builder().setOption("output.path", "./").build(); - FileTypeConverter fileTypeConverter = FileTypeConverter.create(configForFiles); - Configuration.getDefaultConverters().put(FileOption.class, fileTypeConverter); - newConfig.addConverter(PathTemplate.class, fileTypeConverter); - return newConfig; } From 29101edae15b3145e2ef20aee9c56efd94bb1958 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 12:15:24 +0200 Subject: [PATCH 101/233] Tracing: extend FunctionDeclarationKind with UBV_TO_INT and SBV_TO_INT. --- .../sosy_lab/java_smt/api/FunctionDeclarationKind.java | 6 ++++++ .../java_smt/delegate/trace/TraceFormulaManager.java | 10 +++++++++- .../java_smt/solvers/cvc4/CVC4FormulaCreator.java | 1 + .../java_smt/solvers/cvc5/CVC5FormulaCreator.java | 2 ++ .../sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java | 4 ++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java index e3920a4395..83b83c776c 100644 --- a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java +++ b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java @@ -205,6 +205,12 @@ public enum FunctionDeclarationKind { /** Cast a signed bitvector to a floating-point number. */ BV_SCASTTO_FP, + /** Convert an unsigned bitvector to integer. The result is in [0, 2^size - 1]. */ + UBV_TO_INT, + + /** Convert a signed bitvector to integer. The result is in [-2^(size-1), 2^(size-1) - 1]. */ + SBV_TO_INT, + // Simple floating point operations /** Negation of a floating point. */ diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index cd25c35bea..4feafc8082 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -212,7 +212,7 @@ public Formula visitFunction( if (!logger.isTracked(f)) { Formula g = makeApplication(functionDeclaration, args); if (!g.equals(f)) { - Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); + // Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); } } return f; @@ -304,6 +304,8 @@ private int getArity(FunctionDeclaration pDeclaration) { case BV_NEG: case BV_ROTATE_LEFT_BY_INT: case BV_ROTATE_RIGHT_BY_INT: + case UBV_TO_INT: + case SBV_TO_INT: case FP_NEG: case FP_ABS: case FP_IS_NAN: @@ -752,6 +754,12 @@ public T makeApplication( return (T) getFloatingPointFormulaManager() .castFrom(args.get(0), true, (FloatingPointType) declaration.getType()); + case UBV_TO_INT: + return (T) + getBitvectorFormulaManager().toIntegerFormula((BitvectorFormula) args.get(0), false); + case SBV_TO_INT: + return (T) + getBitvectorFormulaManager().toIntegerFormula((BitvectorFormula) args.get(0), true); case FP_NEG: return (T) getFloatingPointFormulaManager().negate((FloatingPointFormula) args.get(0)); case FP_ABS: diff --git a/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java index 23e7328956..665d4f754f 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java @@ -467,6 +467,7 @@ private Expr normalize(Expr operator) { .put(Kind.BITVECTOR_NEG, FunctionDeclarationKind.BV_NEG) .put(Kind.BITVECTOR_EXTRACT, FunctionDeclarationKind.BV_EXTRACT) .put(Kind.BITVECTOR_CONCAT, FunctionDeclarationKind.BV_CONCAT) + .put(Kind.BITVECTOR_TO_NAT, FunctionDeclarationKind.UBV_TO_INT) .put(Kind.BITVECTOR_SIGN_EXTEND, FunctionDeclarationKind.BV_SIGN_EXTENSION) .put(Kind.BITVECTOR_ZERO_EXTEND, FunctionDeclarationKind.BV_ZERO_EXTENSION) // Floating-point theory diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java index 6ff9f8f84a..7578ab2cda 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java @@ -574,6 +574,8 @@ private Term normalize(Term operator) { .put(Kind.BITVECTOR_LSHR, FunctionDeclarationKind.BV_LSHR) .put(Kind.BITVECTOR_ROTATE_LEFT, FunctionDeclarationKind.BV_ROTATE_LEFT_BY_INT) .put(Kind.BITVECTOR_ROTATE_RIGHT, FunctionDeclarationKind.BV_ROTATE_RIGHT_BY_INT) + .put(Kind.BITVECTOR_UBV_TO_INT, FunctionDeclarationKind.UBV_TO_INT) + .put(Kind.BITVECTOR_SBV_TO_INT, FunctionDeclarationKind.SBV_TO_INT) // Floating-point theory .put(Kind.TO_INTEGER, FunctionDeclarationKind.FLOOR) .put(Kind.TO_REAL, FunctionDeclarationKind.TO_REAL) diff --git a/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java index 69ec1a07a9..c580f145c9 100644 --- a/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java @@ -762,6 +762,10 @@ private FunctionDeclarationKind getDeclarationKind(long f) { return FunctionDeclarationKind.BV_ROTATE_LEFT; case Z3_OP_EXT_ROTATE_RIGHT: return FunctionDeclarationKind.BV_ROTATE_RIGHT; + case Z3_OP_BV2INT: + return FunctionDeclarationKind.UBV_TO_INT; + case Z3_OP_SBV2INT: + return FunctionDeclarationKind.SBV_TO_INT; case Z3_OP_FPA_NEG: return FunctionDeclarationKind.FP_NEG; From 124d01cbfa72b9240246a5ce8d1762b41abe3da7 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 19:56:31 +0200 Subject: [PATCH 102/233] Tracing: extend FunctionDeclarationKind with SL operations. --- .../java_smt/api/FunctionDeclarationKind.java | 7 ++++ .../delegate/trace/TraceFormulaManager.java | 33 +++++++++++++++++++ .../solvers/cvc4/CVC4FormulaCreator.java | 6 ++++ .../solvers/cvc5/CVC5FormulaCreator.java | 6 ++++ 4 files changed, 52 insertions(+) diff --git a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java index 83b83c776c..46658b3554 100644 --- a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java +++ b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java @@ -322,6 +322,13 @@ public enum FunctionDeclarationKind { RE_COMPLEMENT, RE_DIFFERENCE, + // Separation logic + SEP_EMP, + SEP_NIL, + SEP_PTO, + SEP_STAR, + SEP_WAND, + // default case /** diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 4feafc8082..732ba3d4f0 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -317,7 +317,9 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_AS_IEEEBV: case FP_FROM_IEEEBV: case STR_LENGTH: + case STR_TO_RE: case RE_COMPLEMENT: + case SEP_NIL: return 1; case SELECT: @@ -357,6 +359,10 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_CASTTO_UBV: case STR_CONCAT: case RE_RANGE: + case SEP_PTO: + case SEP_EMP: + case SEP_STAR: + case SEP_WAND: return 2; case ITE: @@ -365,6 +371,8 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_ADD: case FP_DIV: case FP_MUL: + case STR_INDEX_OF: + case STR_SUBSTRING: return 3; default: @@ -981,6 +989,31 @@ public T makeApplication( return (T) getStringFormulaManager() .difference((RegexFormula) args.get(0), (RegexFormula) args.get(1)); + case SEP_EMP: + Preconditions.checkArgument(args.size() == 2); + return (T) + getSLFormulaManager() + .makeEmptyHeap( + (FormulaType) args.get(0), + (FormulaType) args.get(1)); + case SEP_NIL: + Preconditions.checkArgument(args.size() == 1); + return (T) + getSLFormulaManager().makeNilElement((FormulaType) args.get(0)); + case SEP_PTO: + Preconditions.checkArgument(args.size() == 2); + return (T) + getSLFormulaManager().makePointsTo((Formula) args.get(0), (Formula) args.get(1)); + case SEP_STAR: + Preconditions.checkArgument(args.size() == 2); + return (T) + getSLFormulaManager() + .makeStar((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + case SEP_WAND: + Preconditions.checkArgument(args.size() == 2); + return (T) + getSLFormulaManager() + .makeMagicWand((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); /* TODO case OTHER: break; diff --git a/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java index 665d4f754f..23265ed626 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java @@ -531,6 +531,12 @@ private Expr normalize(Expr operator) { .put(Kind.SELECT, FunctionDeclarationKind.SELECT) .put(Kind.STORE, FunctionDeclarationKind.STORE) .put(Kind.STORE_ALL, FunctionDeclarationKind.CONST) + // Separation logic + .put(Kind.SEP_EMP, FunctionDeclarationKind.SEP_EMP) + .put(Kind.SEP_NIL, FunctionDeclarationKind.SEP_NIL) + .put(Kind.SEP_PTO, FunctionDeclarationKind.SEP_PTO) + .put(Kind.SEP_STAR, FunctionDeclarationKind.SEP_STAR) + .put(Kind.SEP_WAND, FunctionDeclarationKind.SEP_WAND) .buildOrThrow(); private FunctionDeclarationKind getDeclarationKind(Expr f) { diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java index 7578ab2cda..2f211a271a 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java @@ -639,6 +639,12 @@ private Term normalize(Term operator) { .put(Kind.SELECT, FunctionDeclarationKind.SELECT) .put(Kind.STORE, FunctionDeclarationKind.STORE) .put(Kind.CONST_ARRAY, FunctionDeclarationKind.CONST) + // Separation logic + .put(Kind.SEP_EMP, FunctionDeclarationKind.SEP_EMP) + .put(Kind.SEP_NIL, FunctionDeclarationKind.SEP_NIL) + .put(Kind.SEP_PTO, FunctionDeclarationKind.SEP_PTO) + .put(Kind.SEP_STAR, FunctionDeclarationKind.SEP_STAR) + .put(Kind.SEP_WAND, FunctionDeclarationKind.SEP_WAND) .build(); private FunctionDeclarationKind getDeclarationKind(Term f) { From f60403bdbca51acc4aab287e437f8bd222194883 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 21:37:03 +0200 Subject: [PATCH 103/233] Tracing: removing unneeded brackets. --- .../delegate/trace/TraceFormulaManager.java | 328 ++++++++---------- 1 file changed, 141 insertions(+), 187 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 732ba3d4f0..4a3e2222a9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -210,10 +210,11 @@ public Formula visitConstant(Formula f, Object value) { public Formula visitFunction( Formula f, List args, FunctionDeclaration functionDeclaration) { if (!logger.isTracked(f)) { - Formula g = makeApplication(functionDeclaration, args); - if (!g.equals(f)) { - // Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); - } + // Formula g = + //noinspection ResultOfMethodCallIgnored + makeApplication(functionDeclaration, args); + // precondition is not helpful, as some solvers restructure their formulas. + // Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); } return f; } @@ -411,30 +412,24 @@ public T makeApplication( case OR: return (T) getBooleanFormulaManager().or((List) args); case IFF: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBooleanFormulaManager() - .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBooleanFormulaManager() + .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); case ITE: return getBooleanFormulaManager() .ifThenElse((BooleanFormula) args.get(0), (T) args.get(1), (T) args.get(2)); case XOR: - { - Preconditions.checkArgument(args.size() == 2); + Preconditions.checkArgument(args.size() == 2); - return (T) - getBooleanFormulaManager() - .xor((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - } + return (T) + getBooleanFormulaManager() + .xor((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); case IMPLIES: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBooleanFormulaManager() - .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBooleanFormulaManager() + .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); // TODO We only have 'distinct' for some theories /* case DISTINCT: @@ -450,129 +445,108 @@ public T makeApplication( getArrayFormulaManager() .makeArray((ArrayFormulaType) declaration.getType(), args.get(0)); case UMINUS: - { - if (declaration.getType().isIntegerType()) { - return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); - } else { - return (T) getRationalFormulaManager().negate((NumeralFormula) args.get(0)); - } + if (declaration.getType().isIntegerType()) { + return (T) getIntegerFormulaManager().negate((IntegerFormula) args.get(0)); + } else { + return (T) getRationalFormulaManager().negate((NumeralFormula) args.get(0)); } case SUB: - { - Preconditions.checkArgument(args.size() == 2); - if (declaration.getType().isIntegerType()) { - return (T) - getIntegerFormulaManager() - .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); - } else { - return (T) - getRationalFormulaManager() - .subtract((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .subtract((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .subtract((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case ADD: - { - Preconditions.checkArgument(args.size() == 2); - if (declaration.getType().isIntegerType()) { - return (T) - getIntegerFormulaManager() - .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); - } else { - return (T) - getRationalFormulaManager() - .add((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .add((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case DIV: - { - Preconditions.checkArgument(args.size() == 2); - if (declaration.getType().isIntegerType()) { - return (T) - getIntegerFormulaManager() - .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); - } else { - return (T) - getRationalFormulaManager() - .divide((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .divide((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .divide((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case MUL: - { - Preconditions.checkArgument(args.size() == 2); - if (declaration.getType().isIntegerType()) { - return (T) - getIntegerFormulaManager() - .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); - } else { - return (T) - getRationalFormulaManager() - .multiply((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + if (declaration.getType().isIntegerType()) { + return (T) + getIntegerFormulaManager() + .multiply((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + } else { + return (T) + getRationalFormulaManager() + .multiply((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case MODULO: return (T) getIntegerFormulaManager() .modulo((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); case LT: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getRationalFormulaManager() - .lessThan((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getRationalFormulaManager() + .lessThan((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); case LTE: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getRationalFormulaManager() - .lessOrEquals((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getRationalFormulaManager() + .lessOrEquals((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); case GT: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getRationalFormulaManager() - .greaterThan((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getRationalFormulaManager() + .greaterThan((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); case GTE: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getRationalFormulaManager() - .greaterOrEquals((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getRationalFormulaManager() + .greaterOrEquals((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); case EQ: - { - Preconditions.checkArgument(args.size() == 2); - if (declaration.getArgumentTypes().get(0).isBooleanType()) { - return (T) - getBooleanFormulaManager() - .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - } else if (declaration.getArgumentTypes().get(1).isNumeralType()) { - if (declaration.getArgumentTypes().get(0).isRationalType() - || declaration.getArgumentTypes().get(1).isRationalType()) { - return (T) - getRationalFormulaManager() - .equal((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); - } else { - return (T) - getIntegerFormulaManager() - .equal((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); - } - } else if (declaration.getArgumentTypes().get(0).isBitvectorType()) { - return (T) - getBitvectorFormulaManager() - .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } else if (declaration.getArgumentTypes().get(0).isArrayType()) { + Preconditions.checkArgument(args.size() == 2); + if (declaration.getArgumentTypes().get(0).isBooleanType()) { + return (T) + getBooleanFormulaManager() + .equivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(1).isNumeralType()) { + if (declaration.getArgumentTypes().get(0).isRationalType() + || declaration.getArgumentTypes().get(1).isRationalType()) { return (T) - getArrayFormulaManager() - .equivalence((ArrayFormula) args.get(0), (ArrayFormula) args.get(1)); + getRationalFormulaManager() + .equal((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } else { - throw new UnsupportedOperationException( - String.format( - "EQ not supported for theory " + "%s", - declaration.getArgumentTypes().get(0))); + return (T) + getIntegerFormulaManager() + .equal((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); } + } else if (declaration.getArgumentTypes().get(0).isBitvectorType()) { + return (T) + getBitvectorFormulaManager() + .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(0).isArrayType()) { + return (T) + getArrayFormulaManager() + .equivalence((ArrayFormula) args.get(0), (ArrayFormula) args.get(1)); + } else { + throw new UnsupportedOperationException( + String.format( + "EQ not supported for theory " + "%s", declaration.getArgumentTypes().get(0))); } // TODO /* @@ -585,30 +559,24 @@ public T makeApplication( return (T) getRationalFormulaManager().sum(ImmutableList.of((NumeralFormula) args.get(0))); case FLOOR: - { - if (args.get(0) instanceof IntegerFormula) { - return (T) getIntegerFormulaManager().floor((IntegerFormula) args.get(0)); - } else { - return (T) getRationalFormulaManager().floor((NumeralFormula) args.get(0)); - } + if (args.get(0) instanceof IntegerFormula) { + return (T) getIntegerFormulaManager().floor((IntegerFormula) args.get(0)); + } else { + return (T) getRationalFormulaManager().floor((NumeralFormula) args.get(0)); } case BV_EXTRACT: - { - List tokens = Splitter.on('_').splitToList(declaration.getName()); - return (T) - getBitvectorFormulaManager() - .extract( - (BitvectorFormula) args.get(0), - Integer.parseInt(tokens.get(1)), - Integer.parseInt(tokens.get(2))); - } + List tokens = Splitter.on('_').splitToList(declaration.getName()); + return (T) + getBitvectorFormulaManager() + .extract( + (BitvectorFormula) args.get(0), + Integer.parseInt(tokens.get(1)), + Integer.parseInt(tokens.get(2))); case BV_CONCAT: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); // TODO /*case BV_SIGN_EXTENSION: break; @@ -620,40 +588,30 @@ public T makeApplication( case BV_NEG: return (T) getBitvectorFormulaManager().negate((BitvectorFormula) args.get(0)); case BV_OR: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .or((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .or((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_AND: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .and((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .and((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_XOR: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .xor((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .xor((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_SUB: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .subtract((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .subtract((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_ADD: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .add((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .add((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_SDIV: return (T) getBitvectorFormulaManager() @@ -675,12 +633,10 @@ public T makeApplication( getBitvectorFormulaManager() .smodulo((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_MUL: - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .multiply((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .multiply((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_ULT: return (T) getBitvectorFormulaManager() @@ -720,12 +676,10 @@ public T makeApplication( .greaterOrEquals( (BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1), true); case BV_EQ: // FIXME Why is this a separate symbol? - { - Preconditions.checkArgument(args.size() == 2); - return (T) - getBitvectorFormulaManager() - .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - } + Preconditions.checkArgument(args.size() == 2); + return (T) + getBitvectorFormulaManager() + .equal((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); case BV_SHL: return (T) getBitvectorFormulaManager() From 304f064a33e46124172ff75e8bb5744c1c2e00c1 Mon Sep 17 00:00:00 2001 From: Karlheinz Friedberger Date: Wed, 17 Sep 2025 23:21:28 +0200 Subject: [PATCH 104/233] Tracing: add support for visiting quantified formulas. --- .../delegate/trace/TraceFormulaManager.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 4a3e2222a9..af038db214 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -206,6 +206,7 @@ public Formula visitConstant(Formula f, Object value) { return f; } + @SuppressWarnings("CheckReturnValue") @Override public Formula visitFunction( Formula f, List args, FunctionDeclaration functionDeclaration) { @@ -219,13 +220,26 @@ public Formula visitFunction( return f; } + @SuppressWarnings("CheckReturnValue") @Override public BooleanFormula visitQuantifier( BooleanFormula f, Quantifier quantifier, List boundVariables, BooleanFormula body) { - throw new UnsupportedOperationException(); + if (!logger.isTracked(f)) { + // final Formula g; + if (quantifier == Quantifier.EXISTS) { + // g = + getQuantifiedFormulaManager().exists(boundVariables, body); + } else { + // g = + getQuantifiedFormulaManager().forall(boundVariables, body); + } + // precondition is not helpful, as some solvers restructure their formulas. + // Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); + } + return f; } } @@ -997,9 +1011,10 @@ public FormulaType getFormulaType(T formula) { @Override public BooleanFormula parse(String s) throws IllegalArgumentException { - logger.appendStmt(String.format("mgr.parse(\"%s\")", s)); + String var = logger.newVariable(); + logger.appendDef(var, String.format("mgr.parse(\"%s\")", s)); BooleanFormula f = delegate.parse(s); - logger.undoLast(); + logger.mapVariable(var, f); return rebuild(f); } From d09750ba64532db2227379166edb947df61babca Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 25 Oct 2025 12:43:00 +0200 Subject: [PATCH 105/233] Tracing: Add allSat support --- .../trace/TraceBasicProverEnvironment.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index 6329e4f65f..6930c3d9e7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -122,6 +122,22 @@ public void close() { @Override public R allSat(AllSatCallback callback, List important) throws InterruptedException, SolverException { - throw new UnsupportedOperationException(); + // We don't log the call to allSat as it is hard to remove it later on. This is fine as long + // as the crash is not (immediately) caused by this call + // TODO Redesign the logger and add the call to the log + return delegate.allSat( + new AllSatCallback() { + @Override + public void apply(List model) { + var newModel = mgr.rebuildAll(model); + callback.apply(newModel); + } + + @Override + public R getResult() throws InterruptedException { + return callback.getResult(); + } + }, + important); } } From d84ed41e214c762543313a2fed255662c621d821 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 25 Oct 2025 12:49:12 +0200 Subject: [PATCH 106/233] Tracing: Add support for interpolation --- .../TraceInterpolatingProverEnvironment.java | 59 +++++++++++++++++++ .../delegate/trace/TraceSolverContext.java | 11 +++- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java new file mode 100644 index 0000000000..16e793fbb4 --- /dev/null +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java @@ -0,0 +1,59 @@ +/* + * This file is part of JavaSMT, + * an API wrapper for a collection of SMT solvers: + * https://github.com/sosy-lab/java-smt + * + * SPDX-FileCopyrightText: 2025 Dirk Beyer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.sosy_lab.java_smt.delegate.trace; + +import java.util.Collection; +import java.util.List; +import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; +import org.sosy_lab.java_smt.api.SolverException; + +public class TraceInterpolatingProverEnvironment extends TraceBasicProverEnvironment + implements InterpolatingProverEnvironment { + private final InterpolatingProverEnvironment delegate; + private final TraceFormulaManager mgr; + private final TraceLogger logger; + + TraceInterpolatingProverEnvironment( + InterpolatingProverEnvironment pDelegate, + TraceFormulaManager pFormulaManager, + TraceLogger pLogger) { + super(pDelegate, pFormulaManager, pLogger); + delegate = pDelegate; + mgr = pFormulaManager; + logger = pLogger; + } + + @Override + public List getSeqInterpolants(List> partitionedFormulas) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException(); + } + + @Override + public BooleanFormula getInterpolant(Collection formulasOfA) + throws SolverException, InterruptedException { + logger.appendStmt( + String.format( + "%s.getInterpolant(ImmutableList.of(%s))", + logger.toVariable(this), logger.toVariables(formulasOfA))); + BooleanFormula itp = delegate.getInterpolant(formulasOfA); + logger.undoLast(); + return mgr.rebuild(itp); + } + + @Override + public List getTreeInterpolants( + List> partitionedFormulas, int[] startOfSubTree) + throws SolverException, InterruptedException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 236f6e1e42..2e8cb618fb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -123,7 +123,16 @@ public ProverEnvironment newProverEnvironment(ProverOptions... options) { @Override public InterpolatingProverEnvironment newProverEnvironmentWithInterpolation( ProverOptions... options) { - throw new UnsupportedOperationException(); + return logger.logDefKeep( + "context", + String.format( + "newProverEnvironmentWithInterpolation(%s)", + FluentIterable.from(options) + .transform(v -> "SolverContext.ProverOptions." + v.name()) + .join(Joiner.on(", "))), + () -> + new TraceInterpolatingProverEnvironment<>( + delegate.newProverEnvironmentWithInterpolation(options), mgr, logger)); } @SuppressWarnings("resource") From af1493b06dfd2a8f627bd92a663046f4e9719550 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 2 Dec 2025 10:50:21 +0100 Subject: [PATCH 107/233] Trace: Remove reduceTrace script The script was incomplete and had a bug. We'll use ddSMT to reduce the trace for now --- scripts/reduceTrace.py | 128 ----------------------------------------- 1 file changed, 128 deletions(-) delete mode 100755 scripts/reduceTrace.py diff --git a/scripts/reduceTrace.py b/scripts/reduceTrace.py deleted file mode 100755 index 1645b4c648..0000000000 --- a/scripts/reduceTrace.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 - -# This file is part of JavaSMT, -# an API wrapper for a collection of SMT solvers: -# https://github.com/sosy-lab/java-smt -# -# SPDX-FileCopyrightText: 2025 Dirk Beyer -# -# SPDX-License-Identifier: Apache-2.0 - -import re -import sys -from collections import defaultdict -from pathlib import Path - - -# Read a trace file -def readTrace(path): - with open(path) as file: - return [line.rstrip() for line in file] - - -# Build a map with line numbers for all variable definitions -def getLinesForDefinitions(trace): - lineNumber = 1 - lineDefs = dict() - for line in trace: - if line.find('=') >= 0: - leftSide = line[0:(line.find('=') - 1)] - name = re.match('var (.*)', leftSide) - lineDefs[name.group(1)] = lineNumber - lineNumber = lineNumber + 1 - return lineDefs - - -# Build a dependency graph for the definitions -# Maps from variables to the places where they are used -def buildDependencies(lineDefs, trace): - lineNumber = 1 - deps = defaultdict(list) - for line in trace: - expr = line[(line.find('=') + 2):] if line.find('=') >= 0 else line - object = expr[0:expr.find('.')] - if object[0].islower(): - deps[lineDefs[object]].append(lineNumber) - # FIXME Parse the expression to get the variables - for m in re.finditer('(config|logger|notifier|var[0-9]+)', expr): - deps[lineDefs[m.group()]].append(lineNumber) - lineNumber += 1 - return deps - - -# Collect all top-level statements -# Top-level statements are: -# *.addConstraint(*) -# *.isUnsat() -# *.getModel() -# *.asList() -# FIXME Finish this list -def usedTopLevel(lineDefs, trace): - tl = set() - for line in trace: - m = re.fullmatch( - 'var (var[0-9]+) = (var[0-9]+).(isUnsat\\(\\)|getModel\\(\\)|asList\\(\\)|addConstraint\\((var[0-9]+)\\));', - line) - if m != None: - tl.add(lineDefs[m.group(1)]) - return tl - - -# Calculate the closure of all used definitions, starting with the top-level statements -def usedClosure(tl, deps): - cl = set() - st = set(tl) - while cl.union(st) != cl: - cl = cl.union(st) - st = set() - for (key, val) in deps.items(): - if set(val).intersection(cl) != set(): - st.add(key) - return cl - - -# Keep only statements and definitions that are used -def filterUnused(used, trace): - lineNumber = 1 - reduced = [] - for line in trace: - if line.find('=') == -1 or lineNumber in used: - reduced.append(line) - lineNumber += 1 - return reduced - - -# Remove all definitions that are not used (recursively) -def removeDeadCode(trace): - lineDefs = getLinesForDefinitions(trace) - deps = buildDependencies(lineDefs, trace) - tl = usedTopLevel(lineDefs, trace) - cl = usedClosure(tl, deps) - return filterUnused(cl, trace) - - -if __name__ == '__main__': - arg = sys.argv - if not len(sys.argv) == 2: - print('Expecting a path to a trace file as argument') - exit(-1) - - path = Path(sys.argv[1]) - if not (path.is_file()): - print(f'Could not find file "{path}"') - exit(-1) - - # We'll use multiple passes to reduce the size of the trace: - # 1. Read the trace - # 2. Remove unused code - # 3. Remove unnecessary toplevel commands - # 4. Loop: Remove aliasing (by duplicating the definitions) - # 5. Loop: Reduce terms - # 6. Remove unused prover environments - - # TODO Implement steps 3-6 - # TODO Check that the reduced trace still crashes - - trace = readTrace(path) - for line in removeDeadCode(trace): - print(line) From ccfdf542b3293ec6f42bff455816e45ab03f83a7 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 2 Dec 2025 11:36:32 +0100 Subject: [PATCH 108/233] Trace: Add a script to translate JavaSMT traces to SMTLIB traces --- scripts/requirements.txt | 9 + scripts/traceToSmtlib.py | 389 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 scripts/requirements.txt create mode 100755 scripts/traceToSmtlib.py diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 0000000000..f3addd0514 --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1,9 @@ +# This file is part of JavaSMT, +# an API wrapper for a collection of SMT solvers: +# https://github.com/sosy-lab/java-smt +# +# SPDX-FileCopyrightText: 2025 Dirk Beyer +# +# SPDX-License-Identifier: Apache-2.0 + +parsy~=2.2 diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py new file mode 100755 index 0000000000..bd7f2534e4 --- /dev/null +++ b/scripts/traceToSmtlib.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python3 + +# This file is part of JavaSMT, +# an API wrapper for a collection of SMT solvers: +# https://github.com/sosy-lab/java-smt +# +# SPDX-FileCopyrightText: 2025 Dirk Beyer +# +# SPDX-License-Identifier: Apache-2.0 + +import sys + +from dataclasses import dataclass +from pathlib import Path +from typing import List, Optional + +from parsy import regex, string, whitespace, eof, generate + +# TODO Simplify grammar and make sure it matches the parser rules +""" +Grammar: + +program ::= line+ +line ::= ws* (definition | statement) ";\n" +definition ::= "var" ws* variable ws* "=" ws* statement +statement ::= variable ("." variable "(" ws* args ws* ")")+ +args ::= arg ws* ("," ws* arg)* +arg ::= variable | boolean | integer | float | string + +boolean ::= "true" | "false" +integer ::= -?[0-9]+L? | "new" ws* "BigInteger(\"" -?[0-9]+ "\")" +float ::= ... +string ::= "\"" .* "\"" +""" + +litInt = (regex(r"-?[0-9]+").map(int) << string("L").optional() | + string("new") >> whitespace >> string("BigInteger(") >> whitespace.optional() >> + regex(r'"-?[0-9]+"').map(lambda str: int(str[1:-1])) + << whitespace.optional() << string(")")) + + +def test_integer(): + assert litInt.parse('123') == 123 + assert litInt.parse('-123') == -123 + assert litInt.parse('123L') == 123 + assert litInt.parse('new BigInteger("123")') == 123 + + +litBool = string("true").map(lambda str: True) | string("false").map(lambda str: False) + + +def test_bool(): + assert litBool.parse('true') == True + assert litBool.parse('false') == False + + +litString = string('"') >> regex(r'[^"]*') << string('"') + + +def test_string(): + assert litString.parse('"str"') == "str" + + +variable = regex(r"[A-Za-z][A-Za-z0-9]*") + + +def test_variable(): + assert variable.parse("var1") == "var1" + assert variable.parse("mgr") == "mgr" + + +@dataclass +class Call: + fn: str + args: Optional[List] = None + + +argument = litBool | litInt | litString | variable + + +@generate +def call(): + yield string(".") + fn = yield variable + yield string("(") + yield whitespace.optional() + arg0 = yield argument.optional().map(lambda p: [p] if p is not None else []) + args = [] + if (arg0 is not []): + args = yield (whitespace.optional() >> string(",") >> whitespace.optional() >> argument).many() + yield whitespace.optional() + yield string(")") + return Call(fn, arg0 + args) + + +@generate +def stmt(): + call0 = yield variable.map(lambda str: Call(str)) + calls = yield call.many() + return [call0] + calls + + +def test_stmt(): + assert stmt.parse("var1.method(123, false)") == [Call("var1"), Call("method", [123, False])] + assert (stmt.parse('mgr.getBitvectorFormulaManager().makeBitvector(8, new BigInteger("0"))') + == [Call("mgr"), Call("getBitvectorFormulaManager", []), Call("makeBitvector", [8, 0])]) + + +@dataclass +class Definition: + variable: Optional[str] + value: List[Call] + + def getCalls(self): + "Project the call chain on the right to just the method names" + return [call.fn for call in self.value] + + +@generate +def definition(): + yield string("var") + yield whitespace.optional() + var = yield variable + yield whitespace.optional() + yield string("=") + yield whitespace.optional() + value = yield stmt + return Definition(var, value) + + +line = whitespace.optional() >> (definition | stmt.map(lambda p: Definition(None, p))) << string(";\n") + + +def test_line(): + assert (line.parse( + 'var var5 = mgr.getBitvectorFormulaManager().makeBitvector(8, new BigInteger("0"));\n') + == Definition("var5", + [Call( + "mgr"), + Call( + "getBitvectorFormulaManager", + []), + Call( + "makeBitvector", + [8, + 0])])) + + +program = line.many() << whitespace.optional() << eof + + +def test_program(): + assert (program.parse( + """ + var var5 = mgr.getBitvectorFormulaManager().makeBitvector(8, new BigInteger("0")); + var var6 = mgr.getBitvectorFormulaManager().extend(var5, 24, false); + var var8 = mgr.getBitvectorFormulaManager().equal(var6, var6); + var var9 = mgr.getBitvectorFormulaManager().makeBitvector(32, 1L); + var2.push(); + var var21 = var2.addConstraint(var8); + var var22 = var2.isUnsat(); + var var23 = var2.getModel(); + var23.close(); + """) + == [Definition("var5", + [Call("mgr"), Call("getBitvectorFormulaManager", []), Call("makeBitvector", [8, 0])]), + Definition("var6", + [Call("mgr"), Call("getBitvectorFormulaManager", []), Call("extend", ["var5", 24, False])]), + Definition("var8", + [Call("mgr"), Call("getBitvectorFormulaManager", []), Call("equal", ["var6", "var6"])]), + Definition("var9", + [Call("mgr"), Call("getBitvectorFormulaManager", []), Call("makeBitvector", [32, 1])]), + Definition(None, [Call("var2"), Call("push", [])]), + Definition("var21", [Call("var2"), Call("addConstraint", ["var8"])]), + Definition("var22", [Call("var2"), Call("isUnsat", [])]), + Definition("var23", [Call("var2"), Call("getModel", [])]), + Definition(None, [Call("var23"), Call("close", [])])]) + + +@dataclass +class Type: + def toSmtlib(self): + "Print type in SMTLIB format" + raise NotImplementedError() + + +@dataclass +class BooleanType(Type): + def toSmtlib(self): + return "Bool" + + +@dataclass +class IntegerType(Type): + def toSmtlib(self): + return "Integer" + + +@dataclass +class BitvectorType(Type): + width: int + + def toSmtlib(self): + return f"(_ BitVec {self.width})" + + +@dataclass +class FloatType(Type): + exponent: int + significand: int + + def toSmtlib(self): + return f"(_ FloatingPoint {self.exponent} {self.significand})" + + +@dataclass +class ArrayType(Type): + index: Type + element: Type + + def toSmtlib(self): + return f"(Array {self.index.toSmtlib()} {self.element.toSmtlib()})" + + +def test_toSmtlib(): + assert (ArrayType(IntegerType(), ArrayType(BitvectorType(32), FloatType(8, 24))).toSmtlib() + == "(Array Integer (Array (_ BitVec 32) (_ FloatingPoint 8 24)))") + + +def printBitvector(width, value): + "Print a bitvector literal in SMTLIB format" + if value < 0: + raise Exception("Negative value") # TODO Rewrite as 2s complement + return '#b' + format(int(value), f'0{width}b') + + +def test_printBitvector(): + assert printBitvector(8, 5) == "#b00000101" + # assert printBitvector(8, -5) == "#b11111011" # FIXME + + +def translate(prog: List[Definition]): + "Convert a JavaSMT trace to a SMTLIB2 script" + sortMap = {} + output = [] + for stmt in prog: + if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: + if stmt.getCalls()[-1] == "and": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvand {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "equal": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "extend": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = BitvectorType(sortMap[arg1].width + arg2) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {"sign_extend" if arg3 else "zero_extend"} {arg2}) {arg1}))') + + elif stmt.getCalls()[-1] == "makeBitvector": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BitvectorType(arg1) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') + + elif stmt.getCalls()[-1] == "makeVariable": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + sortMap[stmt.variable] = BitvectorType(arg1) + output.append(f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + + elif stmt.getCalls()[-1] == "not": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = sortMap[arg1] + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvnot {arg1}))') + + elif stmt.getCalls()[-1] == "or": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvor {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "shiftLeft": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvshl {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "shiftRight": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvashr" if arg3 else "bvlshr"} {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "xor": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvxor {arg1} {arg2}))') + + else: + raise Exception() + + elif stmt.getCalls()[:-1] == ["mgr", "getBooleanFormulaManager"]: + if stmt.getCalls()[-1] == "ifThenElse": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg2] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (ite {arg1} {arg2} {arg3}))') + + elif stmt.getCalls()[-1] == "not": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = sortMap[arg1] + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (not {arg1}))') + + else: + raise Exception() + + elif stmt.getCalls()[-1] == "addConstraint": + arg1 = stmt.value[-1].args[0] + output.append(f'(assert {arg1})') + + elif stmt.getCalls()[-1] == "asList": + pass + + elif stmt.getCalls()[-1] == "close": + pass + + elif stmt.getCalls()[-1] == "getModel": + output.append(f'(get-model)') + + elif stmt.getCalls()[-1] == "isUnsat": + output.append(f'(check-sat)') + + elif stmt.getCalls()[-1] == "pop": + output.append(f'(pop 1)') + + elif stmt.getCalls()[-1] == "push": + output.append(f'(push 1)') + + else: + raise Exception() + + return '\n'.join(output) + + +""" +def collect(prog: List[Definition]): + "List JavaSMT functions that were used in the trace" + known = set() + for decl in prog: + if decl.value[0].fn == "mgr": + known.add((decl.value[-2].fn, decl.value[-1].fn)) + else: + known.add(("-", decl.value[-1].fn)) + for p in sorted(known): + print(p) +""" + +if __name__ == '__main__': + arg = sys.argv + if not len(sys.argv) == 2: + print('Expecting a path to a JavaSMT trace as argument') + exit(-1) + + path = Path(sys.argv[1]) + if not (path.is_file()): + print(f'Could not find file "{path}"') + exit(-1) + + # Translate the trace + print(translate(program.parse(open(path).read()))) From 742a499e5405a70df633ecbef59d658ac6df74a9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 2 Dec 2025 15:04:12 +0100 Subject: [PATCH 109/233] Trace: Fix merge --- .../TraceFloatingPointFormulaManager.java | 10 +++ .../delegate/trace/TraceFormulaManager.java | 64 +++++-------------- 2 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index 632b8073a1..161cc0eb3f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -19,6 +19,7 @@ import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; @@ -49,6 +50,15 @@ private String toString(double number) { } } + @Override + public FloatingPointRoundingModeFormula makeRoundingMode( + FloatingPointRoundingMode pRoundingMode) { + return logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format("makeRoundingMode(%s)", "FloatingPointRoundingMode." + pRoundingMode.name()), + () -> delegate.makeRoundingMode(pRoundingMode)); + } + @Override public FloatingPointFormula makeNumber(double n, FloatingPointType type) { return logger.logDef( diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index af038db214..224b9f1d83 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -15,7 +15,6 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -297,11 +296,6 @@ private int getArity(FunctionDeclaration pDeclaration) { case RE_CONCAT: return -1; - case FP_ROUND_EVEN: - case FP_ROUND_AWAY: - case FP_ROUND_POSITIVE: - case FP_ROUND_NEGATIVE: - case FP_ROUND_ZERO: case RE_NONE: return 0; @@ -445,10 +439,7 @@ public T makeApplication( getBooleanFormulaManager() .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); // TODO We only have 'distinct' for some theories - /* - case DISTINCT: - break; - */ + // case DISTINCT: case STORE: return (T) getArrayFormulaManager().store((ArrayFormula) args.get(0), args.get(1), args.get(2)); @@ -563,12 +554,8 @@ public T makeApplication( "EQ not supported for theory " + "%s", declaration.getArgumentTypes().get(0))); } // TODO - /* - case EQ_ZERO: - break; - case GTE_ZERO: - break; - */ + // case EQ_ZERO: + // case GTE_ZERO: case TO_REAL: return (T) getRationalFormulaManager().sum(ImmutableList.of((NumeralFormula) args.get(0))); @@ -578,25 +565,17 @@ public T makeApplication( } else { return (T) getRationalFormulaManager().floor((NumeralFormula) args.get(0)); } - case BV_EXTRACT: - List tokens = Splitter.on('_').splitToList(declaration.getName()); - return (T) - getBitvectorFormulaManager() - .extract( - (BitvectorFormula) args.get(0), - Integer.parseInt(tokens.get(1)), - Integer.parseInt(tokens.get(2))); + // FIXME Requires indexed functions + // case INT_TO_BV: + // case BV_EXTRACT: case BV_CONCAT: Preconditions.checkArgument(args.size() == 2); return (T) getBitvectorFormulaManager() .concat((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - // TODO - /*case BV_SIGN_EXTENSION: - break; - case BV_ZERO_EXTENSION: - break; - */ + // FIXME Requires indexed functions + // case BV_SIGN_EXTENSION: + // case BV_ZERO_EXTENSION: case BV_NOT: return (T) getBitvectorFormulaManager().not((BitvectorFormula) args.get(0)); case BV_NEG: @@ -715,13 +694,9 @@ public T makeApplication( return (T) getBitvectorFormulaManager() .rotateRight((BitvectorFormula) args.get(0), (BitvectorFormula) args.get(1)); - // TODO - /* - case BV_ROTATE_LEFT_BY_INT: - break; - case BV_ROTATE_RIGHT_BY_INT: - break; - */ + // FIXME Requires indexed functions + // case BV_ROTATE_LEFT_BY_INT: + // case BV_ROTATE_RIGHT_BY_INT: case BV_UCASTTO_FP: return (T) getFloatingPointFormulaManager() @@ -891,12 +866,9 @@ public T makeApplication( (StringFormula) args.get(0), (StringFormula) args.get(1), (IntegerFormula) args.get(2)); - /* TODO - case STR_TO_RE: - break; - case STR_IN_RE: - break; - */ + // TODO + // case STR_TO_RE: + // case STR_IN_RE: case STR_TO_INT: Preconditions.checkArgument(args.size() == 1); return (T) getStringFormulaManager().toIntegerFormula((StringFormula) args.get(0)); @@ -982,10 +954,8 @@ public T makeApplication( return (T) getSLFormulaManager() .makeMagicWand((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - /* TODO - case OTHER: - break; - */ + // TODO + // case OTHER: default: throw new UnsupportedOperationException( String.format( From 9af80d130b18b915233288c9cc6fec5890a9e270 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 2 Dec 2025 15:13:12 +0100 Subject: [PATCH 110/233] Trace: Add support for rounding-mode formulas --- .../delegate/trace/TraceFormulaManager.java | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 224b9f1d83..c46cb91a47 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -34,6 +34,7 @@ import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaManager; import org.sosy_lab.java_smt.api.FormulaType; @@ -188,6 +189,19 @@ public Formula visitConstant(Formula f, Object value) { String.format("makeNumber(%s)", value), () -> delegate.getRationalFormulaManager().makeNumber((Rational) value)); Preconditions.checkArgument(g.equals(f)); + } else if (f instanceof FloatingPointRoundingModeFormula + && value instanceof FloatingPointRoundingMode) { + @SuppressWarnings("unused") + var g = + logger.logDef( + "mgr.getFloatingPointFormulaManager()", + String.format( + "makeRoundingMode(%s)", + "FloatingPointRoundingMode." + ((FloatingPointRoundingMode) value).name()), + () -> + delegate + .getFloatingPointFormulaManager() + .makeRoundingMode((FloatingPointRoundingMode) value)); } else if (f instanceof StringFormula && value instanceof String) { var g = logger.logDef( @@ -724,19 +738,36 @@ public T makeApplication( getFloatingPointFormulaManager() .min((FloatingPointFormula) args.get(0), (FloatingPointFormula) args.get(1)); case FP_SQRT: - return (T) getFloatingPointFormulaManager().sqrt((FloatingPointFormula) args.get(1)); + return (T) + getFloatingPointFormulaManager() + .sqrt( + (FloatingPointFormula) args.get(1), + getFloatingPointFormulaManager() + .fromRoundingModeFormula((FloatingPointRoundingModeFormula) args.get(0))); case FP_SUB: return (T) getFloatingPointFormulaManager() - .subtract((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); + .subtract( + (FloatingPointFormula) args.get(1), + (FloatingPointFormula) args.get(2), + getFloatingPointFormulaManager() + .fromRoundingModeFormula((FloatingPointRoundingModeFormula) args.get(0))); case FP_ADD: return (T) getFloatingPointFormulaManager() - .add((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); + .add( + (FloatingPointFormula) args.get(1), + (FloatingPointFormula) args.get(2), + getFloatingPointFormulaManager() + .fromRoundingModeFormula((FloatingPointRoundingModeFormula) args.get(0))); case FP_DIV: return (T) getFloatingPointFormulaManager() - .divide((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); + .divide( + (FloatingPointFormula) args.get(1), + (FloatingPointFormula) args.get(2), + getFloatingPointFormulaManager() + .fromRoundingModeFormula((FloatingPointRoundingModeFormula) args.get(0))); case FP_REM: return (T) getFloatingPointFormulaManager() @@ -745,7 +776,11 @@ public T makeApplication( case FP_MUL: return (T) getFloatingPointFormulaManager() - .multiply((FloatingPointFormula) args.get(1), (FloatingPointFormula) args.get(2)); + .multiply( + (FloatingPointFormula) args.get(1), + (FloatingPointFormula) args.get(2), + getFloatingPointFormulaManager() + .fromRoundingModeFormula((FloatingPointRoundingModeFormula) args.get(0))); case FP_LT: return (T) getFloatingPointFormulaManager() @@ -775,7 +810,8 @@ public T makeApplication( getFloatingPointFormulaManager() .round( (FloatingPointFormula) args.get(1), - FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + getFloatingPointFormulaManager() + .fromRoundingModeFormula((FloatingPointRoundingModeFormula) args.get(0))); case FP_IS_NAN: return (T) getFloatingPointFormulaManager().isNaN((FloatingPointFormula) args.get(0)); case FP_IS_INF: From c549ce0454640e1480e0e5d4f1bbdef32268e7f0 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 10:42:18 +0100 Subject: [PATCH 111/233] Trace: Use varargs instead of ImmutableList.of() in the trace --- .../sosy_lab/java_smt/delegate/trace/TraceUFManager.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 16ab4dc09c..d4e067c341 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -40,7 +40,7 @@ public FunctionDeclaration declareUF( logger.appendDef( var, String.format( - "mgr.getUFManager().declareUF(\"%s\", %s, ImmutableList.of(%s))", + "mgr.getUFManager().declareUF(\"%s\", %s, %s)", name, logger.printFormulaType(returnType), FluentIterable.from(args).transform(logger::printFormulaType).join(Joiner.on(", ")))); @@ -59,9 +59,7 @@ public T callUF( if (funcType.getKind().equals(FunctionDeclarationKind.UF)) { return logger.logDef( "mgr.getUFManager", - String.format( - "callUF(%s, ImmutableList.of(%s))", - logger.toVariable(funcType), logger.toVariables(args)), + String.format("callUF(%s, %s)", logger.toVariable(funcType), logger.toVariables(args)), () -> delegate.callUF(funcType, args)); } else { return mgr.makeApplication(funcType, args); From 24741263c41728fffb659597771b579723393a99 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 10:44:50 +0100 Subject: [PATCH 112/233] traceToSmtlib: Add support for FormulaType arguments --- scripts/traceToSmtlib.py | 160 +++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 49 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index bd7f2534e4..57a4e3228f 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -14,7 +14,65 @@ from pathlib import Path from typing import List, Optional -from parsy import regex, string, whitespace, eof, generate +from parsy import regex, string, whitespace, eof, generate, alt, forward_declaration + + +@dataclass +class Type: + def toSmtlib(self): + "Print type in SMTLIB format" + raise NotImplementedError() + + +@dataclass +class BooleanType(Type): + def toSmtlib(self): + return "Bool" + + +@dataclass +class IntegerType(Type): + def toSmtlib(self): + return "Integer" + + +@dataclass +class RationalType(Type): + def toSmtlib(self): + return "Real" + + +@dataclass +class StringType(Type): + def toSmtlib(self): + return "String" + + +@dataclass +class BitvectorType(Type): + width: int + + def toSmtlib(self): + return f"(_ BitVec {self.width})" + + +@dataclass +class FloatType(Type): + exponent: int + significand: int + + def toSmtlib(self): + return f"(_ FloatingPoint {self.exponent} {self.significand})" + + +@dataclass +class ArrayType(Type): + index: Type + element: Type + + def toSmtlib(self): + return f"(Array {self.index.toSmtlib()} {self.element.toSmtlib()})" + # TODO Simplify grammar and make sure it matches the parser rules """ @@ -61,6 +119,55 @@ def test_string(): assert litString.parse('"str"') == "str" +litType = forward_declaration() + +litBoolType = string("FormulaType.BooleanType").map(lambda str: IntegerType()) +litIntegerType = string("FormulaType.IntegerType").map(lambda str: IntegerType()) +litRationalType = string("FormulaType.RationalType").map(lambda str: RationalType()) +litStringType = string("FormulaType.StringType").map(lambda str: StringType()) + + +@generate +def litBitvectorType(): + yield string("FormulaType.getBitvectorTypeWithSize(") >> whitespace.optional() + width = yield regex(r'[0-9]+').map(int) + yield whitespace.optional() << string(")") + return BitvectorType(width) + + +@generate +def litFloatType(): + yield string("FormulaType.getBitvectorTypeWithSize(") >> whitespace.optional() + exponent = yield regex(r'[0-9]+').map(int) + yield whitespace.optional() << string(",") << whitespace.optional() + significand = yield regex(r'[0-9]+').map(int) + yield whitespace.optional() << string(")") + return FloatType(exponent, significand) + + +@generate +def litArrayType(): + yield string("FormulaType.getArrayType(") + yield whitespace.optional() + index = yield litType + yield whitespace.optional() >> string(",") >> whitespace.optional() + elements = yield litType + yield whitespace.optional() >> string(")") + return ArrayType(index, elements) + + +litType.become( + alt(litBoolType, litIntegerType, litRationalType, litStringType, litBitvectorType, litFloatType, litArrayType)) + + +def test_sort(): + assert litType.parse("FormulaType.BooleanType") == IntegerType() + assert litType.parse("FormulaType.IntegerType") == IntegerType() + assert litType.parse("FormulaType.getBitvectorTypeWithSize(8)") == BitvectorType(8) + assert (litType.parse("FormulaType.getArrayType(FormulaType.IntegerType, FormulaType.IntegerType)") + == ArrayType(IntegerType(), IntegerType())) + + variable = regex(r"[A-Za-z][A-Za-z0-9]*") @@ -69,15 +176,15 @@ def test_variable(): assert variable.parse("mgr") == "mgr" +argument = litBool | litInt | litString | litType | variable + + @dataclass class Call: fn: str args: Optional[List] = None -argument = litBool | litInt | litString | variable - - @generate def call(): yield string(".") @@ -177,51 +284,6 @@ def test_program(): Definition(None, [Call("var23"), Call("close", [])])]) -@dataclass -class Type: - def toSmtlib(self): - "Print type in SMTLIB format" - raise NotImplementedError() - - -@dataclass -class BooleanType(Type): - def toSmtlib(self): - return "Bool" - - -@dataclass -class IntegerType(Type): - def toSmtlib(self): - return "Integer" - - -@dataclass -class BitvectorType(Type): - width: int - - def toSmtlib(self): - return f"(_ BitVec {self.width})" - - -@dataclass -class FloatType(Type): - exponent: int - significand: int - - def toSmtlib(self): - return f"(_ FloatingPoint {self.exponent} {self.significand})" - - -@dataclass -class ArrayType(Type): - index: Type - element: Type - - def toSmtlib(self): - return f"(Array {self.index.toSmtlib()} {self.element.toSmtlib()})" - - def test_toSmtlib(): assert (ArrayType(IntegerType(), ArrayType(BitvectorType(32), FloatType(8, 24))).toSmtlib() == "(Array Integer (Array (_ BitVec 32) (_ FloatingPoint 8 24)))") From 0f8add1a7f2a7b32ef1d8bc559937f349bbc30de Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 11:57:58 +0100 Subject: [PATCH 113/233] traceToSmtlib: Add support for ProverOptions as arguments --- scripts/traceToSmtlib.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 57a4e3228f..4e8b28cfc3 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -11,10 +11,11 @@ import sys from dataclasses import dataclass +from enum import Enum from pathlib import Path from typing import List, Optional -from parsy import regex, string, whitespace, eof, generate, alt, forward_declaration +from parsy import regex, string, whitespace, eof, generate, alt, forward_declaration, from_enum @dataclass @@ -168,6 +169,21 @@ def test_sort(): == ArrayType(IntegerType(), IntegerType())) +class ProverOptions(Enum): + GENERATE_MODELS = "SolverContext.ProverOptions.GENERATE_MODELS" + GENERATE_ALL_SAT = "SolverContext.ProverOptions.GENERATE_ALL_SAT" + GENERATE_UNSAT_CORE = "SolverContext.ProverOptions.GENERATE_UNSAT_CORE" + GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS = "SolverContext.ProverOptions.GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS" + ENABLE_SEPARATION_LOGIC = "SolverContext.ProverOptions.ENABLE_SEPARATION_LOGIC" + + +litProverOptions = from_enum(ProverOptions) + + +def test_proverOptions(): + assert litProverOptions.parse("SolverContext.ProverOptions.GENERATE_MODELS") == ProverOptions.GENERATE_MODELS + + variable = regex(r"[A-Za-z][A-Za-z0-9]*") @@ -176,7 +192,7 @@ def test_variable(): assert variable.parse("mgr") == "mgr" -argument = litBool | litInt | litString | litType | variable +argument = litBool | litInt | litString | litType | litProverOptions | variable @dataclass From 6eee07b50d12f7081ed8f842cd5ca0715ca8272b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 12:53:11 +0100 Subject: [PATCH 114/233] traceToSmtlib: Add missing methods from BV theory --- scripts/traceToSmtlib.py | 134 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 4 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 4e8b28cfc3..7f56cd3446 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -323,13 +323,41 @@ def translate(prog: List[Definition]): output = [] for stmt in prog: if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: - if stmt.getCalls()[-1] == "and": + if stmt.getCalls()[-1] == "add": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvadd {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "and": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvand {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "concat": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BitvectorType(sortMap[arg1].width + sortMap[arg2].width) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (concat {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "distinct": + args = stmt.value[-1].args + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') + + elif stmt.getCalls()[-1] == "divide": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvsdiv" if arg3 else "bvudiv"} {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -344,12 +372,50 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {"sign_extend" if arg3 else "zero_extend"} {arg2}) {arg1}))') + elif stmt.getCalls()[-1] == "extract": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = BitvectorType(arg2 - arg3 + 1) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ extract {arg2} {arg3}) {arg1}))') + + elif stmt.getCalls()[-1] == "greaterOrEquals": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (>= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "greaterThan": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (> {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "lessOrEquals": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (<= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "lessThan": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "makeBitvector": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BitvectorType(arg1) - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') + if arg2 is int: + # Create bv constant + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') + else: + # Convert integer formula to bv formula + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ int_to_bv {arg1}) {arg2}))') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] @@ -357,6 +423,19 @@ def translate(prog: List[Definition]): sortMap[stmt.variable] = BitvectorType(arg1) output.append(f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + elif stmt.getCalls()[-1] == "multiply": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvmul {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "negate": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvneg {arg1}))') + elif stmt.getCalls()[-1] == "not": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] @@ -369,6 +448,32 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvor {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "remainder": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvsrem" if arg3 else "bvurem"} {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "rotateLeft": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + if not isinstance(arg2, int): + raise Exception("rotateLeft is only supported for constant rotations") + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ rotate_left {arg2}) {arg1}))') + + elif stmt.getCalls()[-1] == "rotateRight": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + if not isinstance(arg2, int): + raise Exception("rotateRight is only supported for constant rotations") + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ rotate_right {arg2}) {arg1}))') + elif stmt.getCalls()[-1] == "shiftLeft": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -384,6 +489,27 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvashr" if arg3 else "bvlshr"} {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "smod": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvsmod {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "subtract": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvsub {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "toIntegerFormula": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"sbv_to_int" if arg2 else "ubv_to_int"} {arg1}))') + elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -392,7 +518,7 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvxor {arg1} {arg2}))') else: - raise Exception() + raise Exception(f'Unsupported call: {stmt.getCalls()}') elif stmt.getCalls()[:-1] == ["mgr", "getBooleanFormulaManager"]: if stmt.getCalls()[-1] == "ifThenElse": From 15628f0c502e56250df5d4e6d9c0a1343e329687 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 13:00:50 +0100 Subject: [PATCH 115/233] traceToSmtlib: Add missing methods from boolean theory --- scripts/traceToSmtlib.py | 56 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 7f56cd3446..0c0dae1320 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -521,7 +521,21 @@ def translate(prog: List[Definition]): raise Exception(f'Unsupported call: {stmt.getCalls()}') elif stmt.getCalls()[:-1] == ["mgr", "getBooleanFormulaManager"]: - if stmt.getCalls()[-1] == "ifThenElse": + if stmt.getCalls()[-1] == "and": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (and {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "equivalence": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "ifThenElse": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] @@ -529,13 +543,51 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (ite {arg1} {arg2} {arg3}))') + elif stmt.getCalls()[-1] == "implication": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (=> {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "makeFalse": + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} false)') + + elif stmt.getCalls()[-1] == "makeTrue": + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + + elif stmt.getCalls()[-1] == "makeVariable": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + sortMap[stmt.variable] = BooleanType() + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + elif stmt.getCalls()[-1] == "not": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (not {arg1}))') + elif stmt.getCalls()[-1] == "or": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (or {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "xor": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (xor {arg1} {arg2}))') + else: - raise Exception() + raise Exception(f'Unsupported call: {stmt.getCalls()}') elif stmt.getCalls()[-1] == "addConstraint": arg1 = stmt.value[-1].args[0] From aed5c877cfae18a760c0c0b3577c4d2cfd1ccf3d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 13:34:25 +0100 Subject: [PATCH 116/233] traceToSmtlib: Add support for integer theory --- scripts/traceToSmtlib.py | 116 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 0c0dae1320..f14fdb6992 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -589,6 +589,122 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getIntegerFormulaManager"]: + if stmt.getCalls()[-1] == "add": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "distinct": + # FIXME Requires list arguments + raise Exception("distinct not supported") + + elif stmt.getCalls()[-1] == "divide": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (div {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "equal": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "floor": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + + elif stmt.getCalls()[-1] == "greaterOrEquals": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (>= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "greaterThan": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (> {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "lessOrEquals": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (<= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "lessThan": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "makeNumber": + arg1 = stmt.value[-1].args[0] + if not isinstance(arg1, int): + raise Exception("makeNumber is only supported for constant integer arguments") + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + + elif stmt.getCalls()[-1] == "makeVariable": + arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + sortMap[stmt.variable] = IntegerType() + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + + elif stmt.getCalls()[-1] == "modularCongruence": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= (mod (- {arg1} {arg2}) {arg3}) 0))') + + elif stmt.getCalls()[-1] == "modulo": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (mod {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "multiply": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (* {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "negate": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {arg1}))') + + elif stmt.getCalls()[-1] == "subtract": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "sum": + # FIXME Requires list arguments + raise Exception("sum not supported") + + else: + raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[-1] == "addConstraint": arg1 = stmt.value[-1].args[0] output.append(f'(assert {arg1})') From d2925068039b5d6d4285e5085395cc7b34c1e7ae Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 14:05:35 +0100 Subject: [PATCH 117/233] traceToSmtlib: Add support for UF theory --- scripts/traceToSmtlib.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index f14fdb6992..160392e602 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -75,6 +75,15 @@ def toSmtlib(self): return f"(Array {self.index.toSmtlib()} {self.element.toSmtlib()})" +@dataclass +class FunctionType(Type): + arguments: List[Type] + value: Type + + def toSmtlib(self): + return f"({' '.join([arg.toSmtlib() for arg in self.arguments])}) {self.value.toSmtlib()}" + + # TODO Simplify grammar and make sure it matches the parser rules """ Grammar: @@ -705,6 +714,25 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getUFManager"]: + if stmt.getCalls()[-1] == "callUF": + arg0 = stmt.value[-1].args[0] + args = stmt.value[-1].args[1:] + sortMap[stmt.variable] = sortMap[arg0].value + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({arg0} {' '.join(args)}))') + + elif stmt.getCalls()[-1] == "declareUF": + arg0 = stmt.value[-1].args[0] + arg1 = stmt.value[-1].args[1] + args = stmt.value[-1].args[2:] + sortMap[arg0] = FunctionType(args, arg1) + output.append( + f'(declare-fun {arg0} {sortMap[arg0].toSmtlib()})') + + else: + raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[-1] == "addConstraint": arg1 = stmt.value[-1].args[0] output.append(f'(assert {arg1})') From dc8d6cbeb64b1f170cafd53c0bf31a4efcaa22ca Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 3 Dec 2025 22:38:35 +0100 Subject: [PATCH 118/233] traceToSmtlib: Add support for Array theory --- scripts/traceToSmtlib.py | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 160392e602..1bcf25581a 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -714,6 +714,47 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getArrayFormulaManager"]: + if stmt.getCalls()[-1] == "equivalence": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "makeArray": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + if arg1 is Type and arg2 is Type: + # Build a const array + sortMap[stmt.variable] = ArrayType(arg1, arg2) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((as const {sortMap[stmt.variable].toSmtlib()}) {arg3}))') + else: + # Declare a new variable + sortMap[stmt.variable] = ArrayType(arg2, arg3) + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + + elif stmt.getCalls()[-1] == "select": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1].element + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (select {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "store": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (store {arg1} {arg2} {arg3}))') + + else: + raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getUFManager"]: if stmt.getCalls()[-1] == "callUF": arg0 = stmt.value[-1].args[0] @@ -756,7 +797,7 @@ def translate(prog: List[Definition]): output.append(f'(push 1)') else: - raise Exception() + raise Exception(f'Unsupported call: {stmt.getCalls()}') return '\n'.join(output) From 95994ed8894ee2d475206e333cf4a7cfc01f1cb3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 4 Dec 2025 10:54:14 +0100 Subject: [PATCH 119/233] traceToSmtlib: Change 'Integer' to 'Int' in Smtlib output --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 1bcf25581a..1181954ef1 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -34,7 +34,7 @@ def toSmtlib(self): @dataclass class IntegerType(Type): def toSmtlib(self): - return "Integer" + return "Int" @dataclass From a61b452ab4760ac8f92955118b6df8193590f1f9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 4 Dec 2025 10:55:07 +0100 Subject: [PATCH 120/233] traceToSmtlib: Fix number of arguments in BooleanFormulaManager.makeVariable --- scripts/traceToSmtlib.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 1181954ef1..ebca711296 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -570,8 +570,7 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') elif stmt.getCalls()[-1] == "makeVariable": - arg1 = stmt.value[-1].args[0] - arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + arg1 = stmt.value[-1].args[0] # We ignore the actual variable name sortMap[stmt.variable] = BooleanType() output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') From bd37702c572726da808262f25483d32add7b2740 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 4 Dec 2025 11:05:57 +0100 Subject: [PATCH 121/233] traceToSmtlib: Remove all provers, except the last, from the trace --- scripts/traceToSmtlib.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index ebca711296..033a6345af 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -326,6 +326,16 @@ def test_printBitvector(): # assert printBitvector(8, -5) == "#b11111011" # FIXME +def filterProverEnvironments(prog: List[Definition]): + "Remove all provers, except the last, from the trace" + env = [stmt.variable for stmt in prog + if stmt.getCalls()[-1] == "newProverEnvironment" + or stmt.getCalls()[-1] == "newProverEnvironmentWithInterpolation"] + env = env[:-1] + return [stmt for stmt in prog + if not (stmt.getCalls()[0] in env or stmt.variable in env)] + + def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" sortMap = {} @@ -789,6 +799,14 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "isUnsat": output.append(f'(check-sat)') + elif stmt.getCalls()[-1] == "newProverEnvironment": + # TODO Apply options at the top of the file + pass + + elif stmt.getCalls()[-1] == "newProverEnvironmentWithInterpolation": + # TODO Apply options at the top of the file + pass + elif stmt.getCalls()[-1] == "pop": output.append(f'(pop 1)') @@ -826,4 +844,4 @@ def collect(prog: List[Definition]): exit(-1) # Translate the trace - print(translate(program.parse(open(path).read()))) + print(translate(filterProverEnvironments(program.parse(open(path).read())))) From 80ee39b150f11296991361a6a0d9f380a9a1d2a7 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 4 Dec 2025 11:34:17 +0100 Subject: [PATCH 122/233] Trace: Use proper formula manager for rational formulas in the trace --- .../trace/TraceNumeralFormulaManager.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index a7cb340532..b50b80e1fb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -13,6 +13,7 @@ import java.math.BigInteger; import java.util.List; import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.NumeralFormula; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; import org.sosy_lab.java_smt.api.NumeralFormulaManager; @@ -30,18 +31,22 @@ public abstract class TraceNumeralFormulaManager< logger = pLogger; } + private String getPrefix() { + return getFormulaType().equals(FormulaType.IntegerType) + ? "mgr.getIntegerFormulaManager()" + : "mgr.getRationalFormulaManager"; + } + @Override public ResultFormulaType makeNumber(long number) { return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(%s)", number), - () -> delegate.makeNumber(number)); + getPrefix(), String.format("makeNumber(%s)", number), () -> delegate.makeNumber(number)); } @Override public ResultFormulaType makeNumber(BigInteger number) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("makeNumber(new BigInteger(\"%s\"))", number), () -> delegate.makeNumber(number)); } @@ -49,7 +54,7 @@ public ResultFormulaType makeNumber(BigInteger number) { @Override public ResultFormulaType makeVariable(String pVar) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("makeVariable(\"%s\")", pVar), () -> delegate.makeVariable(pVar)); } @@ -57,7 +62,7 @@ public ResultFormulaType makeVariable(String pVar) { @Override public ResultFormulaType negate(ParamFormulaType number) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("negate(%s)", logger.toVariable(number)), () -> delegate.negate(number)); } @@ -65,7 +70,7 @@ public ResultFormulaType negate(ParamFormulaType number) { @Override public ResultFormulaType add(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.add(number1, number2)); } @@ -73,7 +78,7 @@ public ResultFormulaType add(ParamFormulaType number1, ParamFormulaType number2) @Override public ResultFormulaType sum(List operands) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("sum(%s)", logger.toVariables(operands)), () -> delegate.sum(operands)); } @@ -81,7 +86,7 @@ public ResultFormulaType sum(List operands) { @Override public ResultFormulaType subtract(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.subtract(number1, number2)); } @@ -89,7 +94,7 @@ public ResultFormulaType subtract(ParamFormulaType number1, ParamFormulaType num @Override public ResultFormulaType divide(ParamFormulaType numerator, ParamFormulaType denominator) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format( "divide(%s, %s)", logger.toVariable(numerator), logger.toVariable(denominator)), () -> delegate.divide(numerator, denominator)); @@ -98,7 +103,7 @@ public ResultFormulaType divide(ParamFormulaType numerator, ParamFormulaType den @Override public ResultFormulaType multiply(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.multiply(number1, number2)); } @@ -106,7 +111,7 @@ public ResultFormulaType multiply(ParamFormulaType number1, ParamFormulaType num @Override public BooleanFormula equal(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("equal(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.equal(number1, number2)); } @@ -114,7 +119,7 @@ public BooleanFormula equal(ParamFormulaType number1, ParamFormulaType number2) @Override public BooleanFormula distinct(List pNumbers) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("distinct(%s)", logger.toVariables(pNumbers)), () -> delegate.distinct(pNumbers)); } @@ -122,7 +127,7 @@ public BooleanFormula distinct(List pNumbers) { @Override public BooleanFormula greaterThan(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format( "greaterThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.greaterThan(number1, number2)); @@ -131,7 +136,7 @@ public BooleanFormula greaterThan(ParamFormulaType number1, ParamFormulaType num @Override public BooleanFormula greaterOrEquals(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format( "greaterOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.greaterOrEquals(number1, number2)); @@ -140,7 +145,7 @@ public BooleanFormula greaterOrEquals(ParamFormulaType number1, ParamFormulaType @Override public BooleanFormula lessThan(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("lessThan(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.lessThan(number1, number2)); } @@ -148,7 +153,7 @@ public BooleanFormula lessThan(ParamFormulaType number1, ParamFormulaType number @Override public BooleanFormula lessOrEquals(ParamFormulaType number1, ParamFormulaType number2) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format( "lessOrEquals(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), () -> delegate.lessOrEquals(number1, number2)); @@ -157,7 +162,7 @@ public BooleanFormula lessOrEquals(ParamFormulaType number1, ParamFormulaType nu @Override public IntegerFormula floor(ParamFormulaType formula) { return logger.logDef( - "mgr.getIntegerFormulaManager()", + getPrefix(), String.format("floor(%s)", logger.toVariable(formula)), () -> delegate.floor(formula)); } From 0009f0ba07db85a42aef429653223ffad765a035 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 4 Dec 2025 16:27:42 +0100 Subject: [PATCH 123/233] traceToSmtlib: Fix handling of and/or with more than 2 arguments --- scripts/traceToSmtlib.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 033a6345af..9de10ad72e 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -541,11 +541,10 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[:-1] == ["mgr", "getBooleanFormulaManager"]: if stmt.getCalls()[-1] == "and": - arg1 = stmt.value[-1].args[0] - arg2 = stmt.value[-1].args[1] + args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (and {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (and {' '.join(args)}))') elif stmt.getCalls()[-1] == "equivalence": arg1 = stmt.value[-1].args[0] @@ -591,11 +590,10 @@ def translate(prog: List[Definition]): output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (not {arg1}))') elif stmt.getCalls()[-1] == "or": - arg1 = stmt.value[-1].args[0] - arg2 = stmt.value[-1].args[1] + args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (or {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (or {' '.join(args)}))') elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] From 133dcc7b73f745cb0bbdc7abb7fbabdca9f0208e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 4 Dec 2025 16:28:41 +0100 Subject: [PATCH 124/233] traceToSmtlib: Flatten all provers into one global prover environment --- scripts/traceToSmtlib.py | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 9de10ad72e..144613c50b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -326,14 +326,33 @@ def test_printBitvector(): # assert printBitvector(8, -5) == "#b11111011" # FIXME -def filterProverEnvironments(prog: List[Definition]): - "Remove all provers, except the last, from the trace" - env = [stmt.variable for stmt in prog - if stmt.getCalls()[-1] == "newProverEnvironment" - or stmt.getCalls()[-1] == "newProverEnvironmentWithInterpolation"] - env = env[:-1] - return [stmt for stmt in prog - if not (stmt.getCalls()[0] in env or stmt.variable in env)] +def flattenProvers(prog: List[Definition]): + "Push all assertions onto the same global prover" + # We assume that the provers are not used "in parallel" + # FIXME Reorder the instructions to avoid overlapping prover instances + active = "" + levels = 0 + trace = [] + for stmt in prog: + if (stmt.getCalls()[-1] == "newProverEnvironment" + or stmt.getCalls()[-1] == "newProverEnvironmentWithInterpolation"): + if levels > 0: + raise Exception("Can't open new prover before closing the last instance") + active = stmt.variable + levels = 1 + trace.append(Definition(None, [Call(active), Call("push", [])])) + elif stmt.getCalls()[-1] == "push": + levels += 1 + trace.append(stmt) + elif stmt.getCalls()[-1] == "pop": + levels -= 1 + trace.append(stmt) + elif stmt.getCalls() == [active, "close"]: + trace.extend([Definition(None, [Call(active), Call("pop", [])])] * levels) + levels = 0 + else: + trace.append(stmt) + return trace def translate(prog: List[Definition]): @@ -842,4 +861,4 @@ def collect(prog: List[Definition]): exit(-1) # Translate the trace - print(translate(filterProverEnvironments(program.parse(open(path).read())))) + print(translate(flattenProvers(program.parse(open(path).read())))) From 24cb9d23c013674228eb69dc1eba1c3fb4c578b1 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 13:28:53 +0100 Subject: [PATCH 125/233] Trace: Fix logger.undoLast() if the last line is not at the end of the file --- .../java_smt/delegate/trace/TraceLogger.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index c6372705b2..8079f8d2b0 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -109,7 +109,21 @@ public void appendStmt(String pStmt) { public void undoLast() { Preconditions.checkArgument(!lastLines.isEmpty(), "Cannot undo last trace"); try { - output.setLength(lastLines.pop()); + var start = lastLines.pop(); + output.seek(start); + var line = output.readLine(); + if (start + line.length() + 1 == output.length()) { + // We need to remove the last line of the trace + // Just truncate the file + output.setLength(start); + } else { + // We need to remove a line somewhere in the middle + // Just overwrite it with whitespace to avoid having to move rest of the file around + output.seek(start); + output.write( + String.format("%s%n", " ".repeat(line.length())).getBytes(StandardCharsets.UTF_8)); + output.seek(output.length()); + } } catch (IOException e) { throw new RuntimeException(e); } @@ -126,6 +140,7 @@ public R logDef(String prefix, String method, Callable cl return f; } else { mapVariable(var, f); + lastLines.pop(); return mgr.rebuild(f); } } catch (Exception e) { From 0b5a6b159f42f52ea3cec4fb8036e8ff144f17c2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 13:52:56 +0100 Subject: [PATCH 126/233] Trace: Add missing '()' when logging calls to the rational formula manager --- .../java_smt/delegate/trace/TraceNumeralFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index b50b80e1fb..0361b9cfa9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -34,7 +34,7 @@ public abstract class TraceNumeralFormulaManager< private String getPrefix() { return getFormulaType().equals(FormulaType.IntegerType) ? "mgr.getIntegerFormulaManager()" - : "mgr.getRationalFormulaManager"; + : "mgr.getRationalFormulaManager()"; } @Override From 61d580eccc5014edd5ed2e83a8208077e3609b1e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 14:03:08 +0100 Subject: [PATCH 127/233] traceToSmtlib: Add support for parsing solver names --- scripts/traceToSmtlib.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 144613c50b..b281b00401 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -178,6 +178,22 @@ def test_sort(): == ArrayType(IntegerType(), IntegerType())) +class Solvers(Enum): + OPENSMT = "SolverContextFactory.Solvers.OPENSMT" + MATHSAT5 = "SolverContextFactory.Solvers.MATHSAT5" + SMTINTERPOL = "SolverContextFactory.Solvers.SMTINTERPOL" + Z3 = "SolverContextFactory.Solvers.Z3" + PRINCESS = "SolverContextFactory.Solvers.PRINCESS" + BOOLECTOR = "SolverContextFactory.Solvers.BOOLECTOR" + CVC4 = "SolverContextFactory.Solvers.CVC4" + CVC5 = "SolverContextFactory.Solvers.CVC5" + YICES2 = "SolverContextFactory.Solvers.OPENSMT" + BITWUZLA = "SolverContextFactory.Solvers.OPENSMT" + + +litSolvers = from_enum(Solvers) + + class ProverOptions(Enum): GENERATE_MODELS = "SolverContext.ProverOptions.GENERATE_MODELS" GENERATE_ALL_SAT = "SolverContext.ProverOptions.GENERATE_ALL_SAT" @@ -201,7 +217,7 @@ def test_variable(): assert variable.parse("mgr") == "mgr" -argument = litBool | litInt | litString | litType | litProverOptions | variable +argument = litBool | litInt | litString | litType | litSolvers | litProverOptions | variable @dataclass From 1b30c06a21aae655b7a7fe55f7a4bd13fd13e0bc Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 14:03:39 +0100 Subject: [PATCH 128/233] traceToSmtlib: Skip solver initialization during translation phase --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index b281b00401..387cd408d9 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -375,7 +375,7 @@ def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" sortMap = {} output = [] - for stmt in prog: + for stmt in prog[5:]: if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: if stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] From 07b929fa12881a0b0c184bceb0221e7c0b8dd635 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 14:31:20 +0100 Subject: [PATCH 129/233] traceToSmtlib: Add support for rational theory --- scripts/traceToSmtlib.py | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 387cd408d9..92cc56c5a1 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -640,7 +640,7 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') - elif stmt.getCalls()[:-1] == ["mgr", "getIntegerFormulaManager"]: + elif stmt.getCalls()[1] == "getIntegerFormulaManager" or stmt.getCalls()[1] == "getRationalFormulaManager": if stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -652,13 +652,20 @@ def translate(prog: List[Definition]): # FIXME Requires list arguments raise Exception("distinct not supported") - elif stmt.getCalls()[-1] == "divide": + elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "divide"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = IntegerType() output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (div {arg1} {arg2}))') + elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "divide"]: + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = RationalType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (/ {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -666,12 +673,18 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') - elif stmt.getCalls()[-1] == "floor": + elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "floor"]: arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = IntegerType() output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "floor"]: + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (to_int {arg1}))') + elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -700,7 +713,7 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {arg1} {arg2}))') - elif stmt.getCalls()[-1] == "makeNumber": + elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "makeNumber"]: arg1 = stmt.value[-1].args[0] if not isinstance(arg1, int): raise Exception("makeNumber is only supported for constant integer arguments") @@ -708,13 +721,22 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "makeNumber"]: + arg1 = stmt.value[-1].args[0] + if not isinstance(arg1, int): + # TODO Allow rational values + raise Exception("makeNumber is only supported for constant integer arguments") + sortMap[stmt.variable] = RationalType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name sortMap[stmt.variable] = IntegerType() output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') - elif stmt.getCalls()[-1] == "modularCongruence": + elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "modularCongruence"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] @@ -722,7 +744,7 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= (mod (- {arg1} {arg2}) {arg3}) 0))') - elif stmt.getCalls()[-1] == "modulo": + elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "modulo"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = IntegerType() From a544add51f6954f147cba563479fe165a4c8323e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 14:31:43 +0100 Subject: [PATCH 130/233] traceToSmtlib: Set default solver options --- scripts/traceToSmtlib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 92cc56c5a1..b2f57e0f4b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -374,7 +374,8 @@ def flattenProvers(prog: List[Definition]): def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" sortMap = {} - output = [] + output = ["(set-option :produce-models true)", + "(set-option :global-declarations true)"] for stmt in prog[5:]: if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: if stmt.getCalls()[-1] == "add": From f774fc18476ffe42c17cf6c505d075e308ed3d53 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 15:44:59 +0100 Subject: [PATCH 131/233] Trace: Fix mgr.parse() and rebuild the entire term --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index c46cb91a47..b09c507e68 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -1020,7 +1020,7 @@ public BooleanFormula parse(String s) throws IllegalArgumentException { String var = logger.newVariable(); logger.appendDef(var, String.format("mgr.parse(\"%s\")", s)); BooleanFormula f = delegate.parse(s); - logger.mapVariable(var, f); + logger.undoLast(); return rebuild(f); } From 9d7e653602336f8c5c487245266957e504263651 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 5 Dec 2025 16:16:06 +0100 Subject: [PATCH 132/233] traceToSmtlib: Allow negative bitvector constants --- scripts/traceToSmtlib.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index b2f57e0f4b..d9a7eb473c 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -332,14 +332,17 @@ def test_toSmtlib(): def printBitvector(width, value): "Print a bitvector literal in SMTLIB format" + digits = format(value, f'0{width}b') if value < 0: - raise Exception("Negative value") # TODO Rewrite as 2s complement - return '#b' + format(int(value), f'0{width}b') + # Convert to 2s complement + digits = ''.join(['0' if l == '1' else '1' for l in digits]) + digits = format(int(digits, 2) + 1, f'0{width}b') + return '#b' + digits def test_printBitvector(): assert printBitvector(8, 5) == "#b00000101" - # assert printBitvector(8, -5) == "#b11111011" # FIXME + assert printBitvector(8, -5) == "#b11111011" def flattenProvers(prog: List[Definition]): From 6938c8c2942c279c3c11e29521d459a7f87c8928 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 11:08:30 +0100 Subject: [PATCH 133/233] Trace: Add support for EQ_ZERO and GTE_ZERO in Princess --- .../delegate/trace/TraceFormulaManager.java | 25 ++++++++++++++++--- .../PrincessIntegerFormulaManager.java | 8 +++++- .../PrincessNumeralFormulaManager.java | 8 +++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index b09c507e68..5a320b6cda 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -567,9 +567,28 @@ public T makeApplication( String.format( "EQ not supported for theory " + "%s", declaration.getArgumentTypes().get(0))); } - // TODO - // case EQ_ZERO: - // case GTE_ZERO: + case EQ_ZERO: + if (args.get(0) instanceof IntegerFormula) { + return (T) + getIntegerFormulaManager() + .equal((IntegerFormula) args.get(0), getIntegerFormulaManager().makeNumber(0)); + } else { + return (T) + getRationalFormulaManager() + .equal((NumeralFormula) args.get(0), getRationalFormulaManager().makeNumber(0)); + } + case GTE_ZERO: + if (args.get(0) instanceof IntegerFormula) { + return (T) + getIntegerFormulaManager() + .greaterOrEquals( + (IntegerFormula) args.get(0), getIntegerFormulaManager().makeNumber(0)); + } else { + return (T) + getRationalFormulaManager() + .greaterOrEquals( + (NumeralFormula) args.get(0), getRationalFormulaManager().makeNumber(0)); + } case TO_REAL: return (T) getRationalFormulaManager().sum(ImmutableList.of((NumeralFormula) args.get(0))); diff --git a/src/org/sosy_lab/java_smt/solvers/princess/PrincessIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/princess/PrincessIntegerFormulaManager.java index 0ffa256696..656c3f55df 100644 --- a/src/org/sosy_lab/java_smt/solvers/princess/PrincessIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/princess/PrincessIntegerFormulaManager.java @@ -129,7 +129,13 @@ protected IFormula greaterThan(IExpression pNumber1, IExpression pNumber2) { @Override protected IFormula greaterOrEquals(IExpression pNumber1, IExpression pNumber2) { - return ((ITerm) pNumber1).$greater$eq((ITerm) pNumber2); + if (pNumber1.equals(IExpression.i(0))) { + return IExpression.geqZero((ITerm) pNumber2); + } else if (pNumber2.equals(IExpression.i(0))) { + return IExpression.geqZero((ITerm) pNumber1); + } else { + return ((ITerm) pNumber1).$greater$eq((ITerm) pNumber2); + } } @Override diff --git a/src/org/sosy_lab/java_smt/solvers/princess/PrincessNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/princess/PrincessNumeralFormulaManager.java index a73fbaee79..ca33ef7c76 100644 --- a/src/org/sosy_lab/java_smt/solvers/princess/PrincessNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/princess/PrincessNumeralFormulaManager.java @@ -37,7 +37,13 @@ abstract class PrincessNumeralFormulaManager< @Override protected IFormula equal(IExpression pNumber1, IExpression pNumber2) { - return ((ITerm) pNumber1).$eq$eq$eq((ITerm) pNumber2); + if (pNumber1.equals(IExpression.i(0))) { + return IExpression.eqZero((ITerm) pNumber2); + } else if (pNumber2.equals(IExpression.i(0))) { + return IExpression.eqZero((ITerm) pNumber1); + } else { + return ((ITerm) pNumber1).$eq$eq$eq((ITerm) pNumber2); + } } @Override From e006bd27a9403a86fb67d2d3bdbb4aa3352234ee Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 11:10:09 +0100 Subject: [PATCH 134/233] Trace: Add quotes around the variable name for mgr.makeVariable in the trace --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 5a320b6cda..d684cf03f4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -139,7 +139,7 @@ public Formula visitFreeVariable(Formula f, String name) { logger.logDef( "mgr", String.format( - "makeVariable(%s, %s)", + "makeVariable(%s, \"%s\")", logger.printFormulaType(delegate.getFormulaType(f)), name), () -> delegate.makeVariable(delegate.getFormulaType(f), name)); Preconditions.checkArgument(g.equals(f)); From 86a0006c127dc157f9723629494489f5be6effb2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 11:18:11 +0100 Subject: [PATCH 135/233] Trace: Add "QuantifiedFormulaManager." prefix when printing quantifier names --- .../delegate/trace/TraceQuantifiedFormulaManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java index 751da33644..d8df985975 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceQuantifiedFormulaManager.java @@ -26,14 +26,18 @@ public class TraceQuantifiedFormulaManager implements QuantifiedFormulaManager { logger = checkNotNull(pLogger); } + private String printQuantifier(Quantifier pQuantifier) { + return "QuantifiedFormulaManager.Quantifier." + pQuantifier.name(); + } + @Override public BooleanFormula mkQuantifier( Quantifier q, List pVariables, BooleanFormula pBody) { return logger.logDef( "mgr.getQuantifiedFormulaManager()", String.format( - "mkQuantifier(Quantifier.%s, List.of(%s), %s)", - q, logger.toVariables(pVariables), logger.toVariable(pBody)), + "mkQuantifier(%s, List.of(%s), %s)", + printQuantifier(q), logger.toVariables(pVariables), logger.toVariable(pBody)), () -> delegate.mkQuantifier(q, pVariables, pBody)); } From e8c63427f89dc064e3af6be1064d2261ee62aef7 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 11:40:53 +0100 Subject: [PATCH 136/233] traceToSmtlib: Add support for list arguments to the parser --- scripts/traceToSmtlib.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index d9a7eb473c..b438e51f67 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -101,6 +101,8 @@ def toSmtlib(self): string ::= "\"" .* "\"" """ +argument = forward_declaration() + litInt = (regex(r"-?[0-9]+").map(int) << string("L").optional() | string("new") >> whitespace >> string("BigInteger(") >> whitespace.optional() >> regex(r'"-?[0-9]+"').map(lambda str: int(str[1:-1])) @@ -208,6 +210,24 @@ class ProverOptions(Enum): def test_proverOptions(): assert litProverOptions.parse("SolverContext.ProverOptions.GENERATE_MODELS") == ProverOptions.GENERATE_MODELS +@generate +def litList(): + yield (string("List.of(") | string("ImmutableList.of(")) + yield whitespace.optional() + arg0 = yield argument.optional().map(lambda p: [p] if p is not None else []) + args = [] + if (arg0 is not []): + args = yield (whitespace.optional() >> string(",") >> whitespace.optional() >> argument).many() + yield whitespace.optional() + yield string(")") + return arg0 + args + + +def test_list(): + assert litList.parse("List.of(1, 2, var)") == [1, 2, "var"] + assert litList.parse("ImmutableList.of()") == [] + assert litList.parse("List.of(ImmutableList.of(1,2), ImmutableList.of(3,7))") == [[1, 2], [3, 7]] + variable = regex(r"[A-Za-z][A-Za-z0-9]*") @@ -217,7 +237,7 @@ def test_variable(): assert variable.parse("mgr") == "mgr" -argument = litBool | litInt | litString | litType | litSolvers | litProverOptions | variable +argument.become(litBool | litInt | litString | litType | litSolvers | litProverOptions | litList | variable) @dataclass From 642573d8c654912d3ee4a3bf378960f901af8644 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 12:04:03 +0100 Subject: [PATCH 137/233] traceToSmtlib: Add parsing support for quantifiers --- scripts/traceToSmtlib.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index b438e51f67..e64723bc84 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -210,6 +210,15 @@ class ProverOptions(Enum): def test_proverOptions(): assert litProverOptions.parse("SolverContext.ProverOptions.GENERATE_MODELS") == ProverOptions.GENERATE_MODELS + +class Quantifier(Enum): + FORALL = "QuantifiedFormulaManager.Quantifier.FORALL" + EXISTS = "QuantifiedFormulaManager.Quantifier.EXISTS" + + +litQuantifier = from_enum(Quantifier) + + @generate def litList(): yield (string("List.of(") | string("ImmutableList.of(")) @@ -237,7 +246,16 @@ def test_variable(): assert variable.parse("mgr") == "mgr" -argument.become(litBool | litInt | litString | litType | litSolvers | litProverOptions | litList | variable) +argument.become(alt( + litBool, + litInt, + litString, + litType, + litSolvers, + litProverOptions, + litQuantifier, + litList, + variable)) @dataclass From 4955db3820e34884696aabd89cf19480f5a5de43 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 12:08:36 +0100 Subject: [PATCH 138/233] traceToSmtlib: Add support for mgr.makeVariable --- scripts/traceToSmtlib.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index e64723bc84..01945fb9e4 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -896,6 +896,13 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "isUnsat": output.append(f'(check-sat)') + elif stmt.getCalls() == ["mgr", "makeVariable"]: + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + sortMap[stmt.variable] = arg1 + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + elif stmt.getCalls()[-1] == "newProverEnvironment": # TODO Apply options at the top of the file pass From 10f0b9e803e4f1a68fa90ee37083aec4c07d6def Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 13:31:05 +0100 Subject: [PATCH 139/233] traceToSmtlib: Fix handling of negative integer literals --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 01945fb9e4..dc73da52fd 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -761,7 +761,7 @@ def translate(prog: List[Definition]): raise Exception("makeNumber is only supported for constant integer arguments") sortMap[stmt.variable] = IntegerType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1 if arg1 >= 0 else f'(- {abs(arg1)})'})') elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "makeNumber"]: arg1 = stmt.value[-1].args[0] From 8b5ac8477fddb3aa5392f5847c65d020eacfad07 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 13:49:11 +0100 Subject: [PATCH 140/233] Trace: Add missing support for rounding mode formulas --- .../delegate/trace/TraceFloatingPointFormulaManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index 161cc0eb3f..e78d3dc0c8 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -59,6 +59,12 @@ public FloatingPointRoundingModeFormula makeRoundingMode( () -> delegate.makeRoundingMode(pRoundingMode)); } + @Override + public FloatingPointRoundingMode fromRoundingModeFormula( + FloatingPointRoundingModeFormula pRoundingModeFormula) { + return delegate.fromRoundingModeFormula(pRoundingModeFormula); + } + @Override public FloatingPointFormula makeNumber(double n, FloatingPointType type) { return logger.logDef( From 8dc2320e3682e6a2ae190704f373f57ae8dfaa8d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 13:54:41 +0100 Subject: [PATCH 141/233] Trace: Add missing kinds to getArity() from TraceFormulaManager --- .../delegate/trace/TraceFormulaManager.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index d684cf03f4..698787df99 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -307,12 +307,20 @@ private int getArity(FunctionDeclaration pDeclaration) { case BV_SUB: case BV_ADD: case BV_MUL: + case STR_CONCAT: + case STR_LT: + case STR_LE: case RE_CONCAT: + case RE_DIFFERENCE: + case RE_UNION: + case RE_INTERSECT: return -1; case RE_NONE: + case SEP_NIL: return 0; + case INT_TO_BV: case NOT: case UMINUS: case EQ_ZERO: @@ -339,10 +347,16 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_IS_NORMAL: case FP_AS_IEEEBV: case FP_FROM_IEEEBV: + case RE_PLUS: + case RE_STAR: + case INT_TO_STR: + case STR_FROM_CODE: + case STR_TO_CODE: case STR_LENGTH: + case STR_TO_INT: case STR_TO_RE: case RE_COMPLEMENT: - case SEP_NIL: + case RE_OPTIONAL: return 1; case SELECT: @@ -380,7 +394,11 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_CASTTO_FP: case FP_CASTTO_SBV: case FP_CASTTO_UBV: - case STR_CONCAT: + case STR_CHAR_AT: + case STR_CONTAINS: + case STR_IN_RE: + case STR_PREFIX: + case STR_SUFFIX: case RE_RANGE: case SEP_PTO: case SEP_EMP: @@ -395,6 +413,8 @@ private int getArity(FunctionDeclaration pDeclaration) { case FP_DIV: case FP_MUL: case STR_INDEX_OF: + case STR_REPLACE: + case STR_REPLACE_ALL: case STR_SUBSTRING: return 3; From b57d10f7ab27cfbaa8c97a543251abc9b0c4990b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 14:14:50 +0100 Subject: [PATCH 142/233] Trace: Add support for equality over Strings --- .../java_smt/delegate/trace/TraceFormulaManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 698787df99..90e86ca1ea 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -574,6 +574,11 @@ public T makeApplication( getIntegerFormulaManager() .equal((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); } + } else if (declaration.getArgumentTypes().get(0).isStringType()) { + return (T) + getStringFormulaManager() + .equal((StringFormula) args.get(0), (StringFormula) args.get(1)); + } else if (declaration.getArgumentTypes().get(0).isBitvectorType()) { return (T) getBitvectorFormulaManager() From 98f8e97a90c4a1ad1196e5eada9f8af782052978 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 20:43:04 +0100 Subject: [PATCH 143/233] Trace: Add support for str.to_re and str.in_re --- .../delegate/trace/TraceFormulaManager.java | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 90e86ca1ea..b34098c365 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -56,6 +56,7 @@ import org.sosy_lab.java_smt.api.StringFormulaManager; import org.sosy_lab.java_smt.api.Tactic; import org.sosy_lab.java_smt.api.UFManager; +import org.sosy_lab.java_smt.api.visitors.DefaultFormulaVisitor; import org.sosy_lab.java_smt.api.visitors.FormulaTransformationVisitor; import org.sosy_lab.java_smt.api.visitors.FormulaVisitor; import org.sosy_lab.java_smt.api.visitors.TraversalProcess; @@ -946,9 +947,30 @@ public T makeApplication( (StringFormula) args.get(0), (StringFormula) args.get(1), (IntegerFormula) args.get(2)); - // TODO - // case STR_TO_RE: - // case STR_IN_RE: + case STR_TO_RE: + // String to RE injection + // We only support this for constant Strings + Preconditions.checkArgument(args.size() == 1); + String str = + delegate.visit( + args.get(0), + new DefaultFormulaVisitor<>() { + @Override + protected String visitDefault(Formula f) { + throw new IllegalArgumentException( + "We only support constant Strings for str.to_re"); + } + + @Override + public String visitConstant(Formula f, Object value) { + return (String) value; + } + }); + return (T) getStringFormulaManager().makeRegex(str); + case STR_IN_RE: + Preconditions.checkArgument(args.size() == 2); + return (T) + getStringFormulaManager().in((StringFormula) args.get(0), (RegexFormula) args.get(1)); case STR_TO_INT: Preconditions.checkArgument(args.size() == 1); return (T) getStringFormulaManager().toIntegerFormula((StringFormula) args.get(0)); From 8dd10a967620d6376dacd52b50bff2b740d97d52 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 7 Dec 2025 20:44:43 +0100 Subject: [PATCH 144/233] Trace: Use sum() instead of add() to support addition with more than two arguments --- .../java_smt/delegate/trace/TraceFormulaManager.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index b34098c365..fa47e45fd3 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -502,15 +502,10 @@ public T makeApplication( .subtract((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); } case ADD: - Preconditions.checkArgument(args.size() == 2); if (declaration.getType().isIntegerType()) { - return (T) - getIntegerFormulaManager() - .add((IntegerFormula) args.get(0), (IntegerFormula) args.get(1)); + return (T) getIntegerFormulaManager().sum((List) args); } else { - return (T) - getRationalFormulaManager() - .add((NumeralFormula) args.get(0), (NumeralFormula) args.get(1)); + return (T) getRationalFormulaManager().sum((List) args); } case DIV: Preconditions.checkArgument(args.size() == 2); From 6843af3c07e70232198f6b2c327d28aacbab291d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 17:24:42 +0100 Subject: [PATCH 145/233] traceToSmtlib: Move bool parser --- scripts/traceToSmtlib.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index dc73da52fd..6f261df2af 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -103,6 +103,14 @@ def toSmtlib(self): argument = forward_declaration() +litBool = string("true").map(lambda str: True) | string("false").map(lambda str: False) + + +def test_bool(): + assert litBool.parse('true') == True + assert litBool.parse('false') == False + + litInt = (regex(r"-?[0-9]+").map(int) << string("L").optional() | string("new") >> whitespace >> string("BigInteger(") >> whitespace.optional() >> regex(r'"-?[0-9]+"').map(lambda str: int(str[1:-1])) @@ -116,14 +124,6 @@ def test_integer(): assert litInt.parse('new BigInteger("123")') == 123 -litBool = string("true").map(lambda str: True) | string("false").map(lambda str: False) - - -def test_bool(): - assert litBool.parse('true') == True - assert litBool.parse('false') == False - - litString = string('"') >> regex(r'[^"]*') << string('"') From a8b40730a65022327b36989f793172455bca0cb3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 17:25:33 +0100 Subject: [PATCH 146/233] traceToSmtlib: Remove an unused function --- scripts/traceToSmtlib.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 6f261df2af..028abffac0 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -923,19 +923,6 @@ def translate(prog: List[Definition]): return '\n'.join(output) -""" -def collect(prog: List[Definition]): - "List JavaSMT functions that were used in the trace" - known = set() - for decl in prog: - if decl.value[0].fn == "mgr": - known.add((decl.value[-2].fn, decl.value[-1].fn)) - else: - known.add(("-", decl.value[-1].fn)) - for p in sorted(known): - print(p) -""" - if __name__ == '__main__': arg = sys.argv if not len(sys.argv) == 2: From 16d893ce0c94c84d4ca63987bf4ee34166c1b593 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 17:57:37 +0100 Subject: [PATCH 147/233] traceToSmtlib: Fix broken test --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 028abffac0..8f45c751d5 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -365,7 +365,7 @@ def test_program(): def test_toSmtlib(): assert (ArrayType(IntegerType(), ArrayType(BitvectorType(32), FloatType(8, 24))).toSmtlib() - == "(Array Integer (Array (_ BitVec 32) (_ FloatingPoint 8 24)))") + == "(Array Int (Array (_ BitVec 32) (_ FloatingPoint 8 24)))") def printBitvector(width, value): From 7b4d1d5532268f3fd821b6686b216ffd6681135d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 19:10:23 +0100 Subject: [PATCH 148/233] traceToSmtlib: Fix parsing of floating point types --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 8f45c751d5..faa75b0c9f 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -149,7 +149,7 @@ def litBitvectorType(): @generate def litFloatType(): - yield string("FormulaType.getBitvectorTypeWithSize(") >> whitespace.optional() + yield string("FormulaType.getFloatingPointType(") >> whitespace.optional() exponent = yield regex(r'[0-9]+').map(int) yield whitespace.optional() << string(",") << whitespace.optional() significand = yield regex(r'[0-9]+').map(int) From 3e8d259469c65b327ca881d438abf35156fb2976 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 19:10:59 +0100 Subject: [PATCH 149/233] traceToSmtlib: Add support for fp theory --- scripts/traceToSmtlib.py | 279 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 270 insertions(+), 9 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index faa75b0c9f..e342fd481b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -111,17 +111,37 @@ def test_bool(): assert litBool.parse('false') == False -litInt = (regex(r"-?[0-9]+").map(int) << string("L").optional() | - string("new") >> whitespace >> string("BigInteger(") >> whitespace.optional() >> - regex(r'"-?[0-9]+"').map(lambda str: int(str[1:-1])) - << whitespace.optional() << string(")")) +@generate +def litBigInt(): + yield string("new") >> whitespace >> (string("BigInteger(") | string("BigDecimal(")) >> whitespace.optional() + integer = yield regex(r'"-?[0-9]+"').map(lambda str: int(str[1:-1])) + yield whitespace.optional() << string(")") + return integer + + +@generate +def litNum0(): + sign = yield string('-').optional().map(lambda opt: "+" if opt is None else "-") + integerPart = yield regex(r'[0-9]+') + dot = yield string('.').optional() + if dot is None: + yield string('L').optional() + return int(sign + integerPart) + else: + fractionPart = yield regex(r'[0-9]+') + return float(sign + integerPart + '.' + fractionPart) + + +litNum = litNum0 | litBigInt def test_integer(): - assert litInt.parse('123') == 123 - assert litInt.parse('-123') == -123 - assert litInt.parse('123L') == 123 - assert litInt.parse('new BigInteger("123")') == 123 + assert litNum.parse('123') == 123 + assert litNum.parse('-123') == -123 + assert litNum.parse('123L') == 123 + assert litNum.parse('new BigInteger("123")') == 123 + assert litNum.parse('123.4') == 123.4 + assert litNum.parse('-123.4') == -123.4 litString = string('"') >> regex(r'[^"]*') << string('"') @@ -131,6 +151,24 @@ def test_string(): assert litString.parse('"str"') == "str" +class RoundingMode(Enum): + NEAREST_TIES_TO_EVEN = "FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN" + NEAREST_TIES_AWAY = "FloatingPointRoundingMode.NEAREST_TIES_AWAY" + TOWARD_POSITIVE = "FloatingPointRoundingMode.TOWARDS_POSITIVE" + TOWARD_NEGATIVE = "FloatingPointRoundingMode.TOWARDS_NEGATIVE" + TOWARD_ZERO = "FloatingPointRoundingMode.TOWARDS_ZERO" + + +litRoundingMode = from_enum(RoundingMode) + + +class Sign(Enum): + POSITIVE = "FloatingPointNumber.Sign.POSITIVE" + NEGATIVE = "FloatingPointNumber.Sign.NEGATIVE" + + +litSign = from_enum(Sign) + litType = forward_declaration() litBoolType = string("FormulaType.BooleanType").map(lambda str: IntegerType()) @@ -248,7 +286,9 @@ def test_variable(): argument.become(alt( litBool, - litInt, + litNum, + litRoundingMode, + litSign, litString, litType, litSolvers, @@ -820,6 +860,227 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getFloatingPointFormulaManager"]: + if stmt.getCalls()[-1] == "abs": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.abs {arg1}))') + + elif stmt.getCalls()[-1] == "add": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.add {arg3} {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "assignment": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "castTo": + # Converts from float to bv/int, or convert between different fp precisions + arg1 = stmt.value[-1].args[0] # source (fp term) + arg2 = stmt.value[-1].args[1] # signed? + arg3 = stmt.value[-1].args[2] # target type (any type) + arg4 = stmt.value[-1].args[3] # rounding mode + sortMap[stmt.variable] = arg3 + if isinstance(arg3, FloatType): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4} {arg1})') + elif isinstance(arg3, IntegerType): + raise Exception("Converting from float to integer is not supported in SMTLIB") + elif isinstance(arg3, RationalType): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1})') + elif isinstance(arg3, BitvectorType): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4} {arg1})') + else: + raise Exception(f"Illegal cast from float to {arg3}") + + elif stmt.getCalls()[-1] == "castFrom": + # Converts from bv/int to float, or convert between different fp precisions + arg1 = stmt.value[-1].args[0] # source (any term) + arg2 = stmt.value[-1].args[1] # signed? + arg3 = stmt.value[-1].args[2] # target type (fp type) + arg4 = stmt.value[-1].args[3] # rounding mode + sortMap[stmt.variable] = arg3 + sourceType = sortMap[arg1] + if isinstance(sourceType, FloatType): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4} {arg1})') + elif isinstance(sourceType, IntegerType): + raise Exception("Converting from float to integer is not supported in SMTLIB") + elif isinstance(sourceType, RationalType): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg1})') + elif isinstance(sourceType, BitvectorType): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent}) {arg3.significand}) {arg3} {arg1})') + else: + raise Exception(f"Illegal cast from {sourceType} to float") + + elif stmt.getCalls()[-1] == "divide": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.div {arg3} {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "equalWithFPSemantics": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.eq {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "fromIeeeBitvector": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg2.exponent} {arg2.significand}) {arg1}))') + + elif stmt.getCalls()[-1] == "greaterOrEquals": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.geq {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "greaterThan": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.gt {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "lessOrEquals": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.leq {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "lessThan": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.lt {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "makeMinusInfinity": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = FloatType(arg1.exponent, arg1.significand) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ -oo {arg1.exponent} {arg1.significand}))') + + elif stmt.getCalls()[-1] == "makeNaN": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = FloatType(arg1.exponent, arg1.significand) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ NaN {arg1.exponent} {arg1.significand}))') + + elif stmt.getCalls()[-1] == "makeNumber": + if len(stmt.value[-1].args) < 4: + raise Exception(f'Expected 4 arguments to fp.makeNumber, got {len(stmt.value)}') + arg1 = stmt.value[-1].args[0] # exponent + arg2 = stmt.value[-1].args[1] # significand + arg3 = stmt.value[-1].args[2] # sign + arg4 = stmt.value[-1].args[3] # type + if not (isinstance(arg1, int) and + isinstance(arg2, int) and + isinstance(arg3, Sign) and + isinstance(arg4, FloatType)): + # TODO Support more value constructors + raise Exception( + "We currently only support fp.makeNumber when sign, exponent and mantissa are given explicitly") + sortMap[stmt.variable] = arg4 + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp {'#1' if arg3 == Sign.NEGATIVE else '#0'} {printBitvector(arg4.exponent, arg1)} {printBitvector(arg4.significand, arg2)}))') + + elif stmt.getCalls()[-1] == "makePlusInfinity": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = FloatType(arg1.exponent, arg1.significand) + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ +oo {arg1.exponent} {arg1.significand}))') + + elif stmt.getCalls()[-1] == "makeVariable": + arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = arg2 + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + + elif stmt.getCalls()[-1] == "max": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.max {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "min": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.min {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "multiply": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.mul {arg3} {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "negate": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.neg {arg1}))') + + elif stmt.getCalls()[-1] == "remainder": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.rem {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "round": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.roundToIntegral {arg2} {arg1}))') + + elif stmt.getCalls()[-1] == "sqrt": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sqrt {arg2} {arg1}))') + + elif stmt.getCalls()[-1] == "subtract": + arg1 = stmt.value[-1].args[0] + arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] + sortMap[stmt.variable] = sortMap[arg1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3} {arg1} {arg2}))') + + elif stmt.getCalls()[-1] == "toIeeBitvector": + raise Exception("Recasting from float to bitvector is not supported in SMTLIB") + + else: + raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getArrayFormulaManager"]: if stmt.getCalls()[-1] == "equivalence": arg1 = stmt.value[-1].args[0] From c7f9c3c9278376d2e048a4a80d2b25a2f2bb711a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 22:07:39 +0100 Subject: [PATCH 150/233] traceToSmtlib: Add BooleanFormulaManager.makeBoolean --- scripts/traceToSmtlib.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index e342fd481b..b23929ef51 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -695,6 +695,12 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + elif stmt.getCalls()[-1] == "makeBoolean": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {'true' if arg1 else 'false'})') + elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name sortMap[stmt.variable] = BooleanType() From 598d4e631cc3f47ead943e714923603439b1c3e1 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 22:10:37 +0100 Subject: [PATCH 151/233] traceToSmtlib: Add Model.evaluate --- scripts/traceToSmtlib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index b23929ef51..9ae9e1d237 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1157,6 +1157,10 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "close": pass + elif stmt.getCalls()[-1] == "evaluate": + arg1 = stmt.value[-1].args[0] + output.append(f'(get-values ({arg1}))') + elif stmt.getCalls()[-1] == "getModel": output.append(f'(get-model)') From 95a45dd357814d9603bf8dec468ebf870344c879 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 22:21:33 +0100 Subject: [PATCH 152/233] traceToSmtlib: Fix a bug in arrays.makeArray --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 9ae9e1d237..671d43318b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1099,7 +1099,7 @@ def translate(prog: List[Definition]): arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] - if arg1 is Type and arg2 is Type: + if isinstance(arg1, Type) and isinstance(arg2, Type): # Build a const array sortMap[stmt.variable] = ArrayType(arg1, arg2) output.append( From 4e868883478e0e0b503cc638a74a5491d4152dba Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 22:23:27 +0100 Subject: [PATCH 153/233] traceToSmtlib: Fix a bug in bv.smodulo --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 671d43318b..f6dd23fa53 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -625,7 +625,7 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvashr" if arg3 else "bvlshr"} {arg1} {arg2}))') - elif stmt.getCalls()[-1] == "smod": + elif stmt.getCalls()[-1] == "smodulo": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] From 22c534daabd711a12295f5ebbcd762b57a2eb344 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 22:39:39 +0100 Subject: [PATCH 154/233] traceToSmtlib: Fix a bug in bv.distinct The trace will always use a list here, and not the vararg version of the method --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index f6dd23fa53..878320f6d1 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -481,7 +481,7 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (concat {arg1} {arg2}))') elif stmt.getCalls()[-1] == "distinct": - args = stmt.value[-1].args + args = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') From 4b7bf4ffcdb991c2dfacc9edef533e418c194437 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 8 Dec 2025 23:03:41 +0100 Subject: [PATCH 155/233] traceToSmtlib: Fix UF declarations --- scripts/traceToSmtlib.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 878320f6d1..4c68217ad5 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -455,6 +455,7 @@ def flattenProvers(prog: List[Definition]): def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" sortMap = {} + nameMap = {} # Stores UF names for function declarations output = ["(set-option :produce-models true)", "(set-option :global-declarations true)"] for stmt in prog[5:]: @@ -1132,17 +1133,19 @@ def translate(prog: List[Definition]): if stmt.getCalls()[-1] == "callUF": arg0 = stmt.value[-1].args[0] args = stmt.value[-1].args[1:] + name = nameMap[arg0] sortMap[stmt.variable] = sortMap[arg0].value output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({arg0} {' '.join(args)}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(args)}))') elif stmt.getCalls()[-1] == "declareUF": arg0 = stmt.value[-1].args[0] arg1 = stmt.value[-1].args[1] args = stmt.value[-1].args[2:] - sortMap[arg0] = FunctionType(args, arg1) + sortMap[stmt.variable] = FunctionType(args, arg1) + nameMap[stmt.variable] = arg0 output.append( - f'(declare-fun {arg0} {sortMap[arg0].toSmtlib()})') + f'(declare-fun {arg0} {sortMap[stmt.variable].toSmtlib()})') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') From 49579476cb79a940eb02f5c76e34fa8bddfc7ef3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:27:01 +0100 Subject: [PATCH 156/233] traceToSmtlib: Clean up parsing of numeric values --- scripts/traceToSmtlib.py | 121 ++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 28 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 4c68217ad5..317488e46d 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -12,6 +12,7 @@ from dataclasses import dataclass from enum import Enum +from fractions import Fraction from pathlib import Path from typing import List, Optional @@ -103,6 +104,7 @@ def toSmtlib(self): argument = forward_declaration() +# Boolean constants litBool = string("true").map(lambda str: True) | string("false").map(lambda str: False) @@ -111,40 +113,102 @@ def test_bool(): assert litBool.parse('false') == False +litNumeral = regex(r'0|-?[1-9][0-9]*').map(int) + + @generate -def litBigInt(): - yield string("new") >> whitespace >> (string("BigInteger(") | string("BigDecimal(")) >> whitespace.optional() - integer = yield regex(r'"-?[0-9]+"').map(lambda str: int(str[1:-1])) - yield whitespace.optional() << string(")") - return integer +def litDecimal(): + sign = yield string('-').optional() + integer = yield regex(r'0|[1-9][0-9]*') + yield string(".") + fraction = yield regex(r'[0-9]*') + shift = len(fraction) + num = int(integer) * 10 ** shift + int(fraction) + den = 10 ** shift + return Fraction(num if sign is None else -num, den) @generate -def litNum0(): - sign = yield string('-').optional().map(lambda opt: "+" if opt is None else "-") +def litFpConstant(): + sign = yield string('-').optional("") integerPart = yield regex(r'[0-9]+') - dot = yield string('.').optional() - if dot is None: - yield string('L').optional() - return int(sign + integerPart) - else: - fractionPart = yield regex(r'[0-9]+') - return float(sign + integerPart + '.' + fractionPart) + yield string('.') + fractionPart = yield regex(r'[0-9]+') + exponentPart = "0" + hasExponent = yield string('E').optional() + if hasExponent is not None: + exponentPart = yield regex(r'-?[0-9]+') + return float(sign + integerPart + '.' + fractionPart + "e" + exponentPart) + +# Integer constants +litInt = litNumeral << string("L").optional() -litNum = litNum0 | litBigInt +# Double constants +litFloat = string("Double.NaN").map(lambda str: float('nan')) | \ + string("Double.POSITIVE_INFINITY").map(lambda str: float('inf')) | \ + string("Double.NEGATIVE_INFINITY").map(lambda str: float('-inf')) | \ + litFpConstant -def test_integer(): - assert litNum.parse('123') == 123 - assert litNum.parse('-123') == -123 - assert litNum.parse('123L') == 123 - assert litNum.parse('new BigInteger("123")') == 123 - assert litNum.parse('123.4') == 123.4 - assert litNum.parse('-123.4') == -123.4 +# BigInteger constants +@generate +def litBigInteger(): + yield string('new') >> whitespace >> string('BigInteger(') >> whitespace.optional() + yield string('"') + integer = yield litNumeral + yield string('"') + yield whitespace.optional() << string(')') + return integer + + +# BigDecimal constants +@generate +def litBigDecimal(): + yield string('new') >> whitespace >> (string('BigDecimal(')) >> whitespace.optional() + yield string('"') + number = yield (litDecimal | litNumeral) + yield string('"') + yield whitespace.optional() << string(')') + return number -litString = string('"') >> regex(r'[^"]*') << string('"') +# Rational constants +@generate +def litRational(): + yield string('Rational.of("') + num = yield regex(r'-?[0-9]+').map(int) + isFraction = yield string("/").optional() + den = 1 + if isFraction is not None: + den = yield regex(r'[0-9]+').map(int) + yield string('")') + return Fraction(num, den) + + +litNumber = litBigInteger | litBigDecimal | litRational | litFloat | litInt + + +def test_number(): + assert litNumber.parse('123') == 123 + assert litNumber.parse('-123') == -123 + assert litNumber.parse('123L') == 123 + assert litNumber.parse('0.0') == 0.0 + assert litNumber.parse('1.23') == 1.23 + assert litNumber.parse('-1.23') == -1.23 + assert litNumber.parse('12.3E1') == 123.0 + assert litNumber.parse('12.3E-1') == 1.23 + assert litNumber.parse('Double.NEGATIVE_INFINITY') == float('-inf') + assert litNumber.parse('new BigInteger("123")') == 123 + assert litNumber.parse('new BigDecimal("123")') == Fraction(123) + assert litNumber.parse('new BigDecimal("123.4")') == Fraction(1234, 10) + assert litNumber.parse('new BigDecimal("0.0625")') == Fraction(625, 10000) + assert litNumber.parse('Rational.of("4")') == Fraction(4) + assert litNumber.parse('Rational.of("1/4")') == Fraction(1, 4) + + +# String constants +litString = regex(r'"(\\"|[^"])*"').map(lambda str: str.replace(r'\"', '"').replace(r'\n', '\n')) def test_string(): @@ -154,9 +218,9 @@ def test_string(): class RoundingMode(Enum): NEAREST_TIES_TO_EVEN = "FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN" NEAREST_TIES_AWAY = "FloatingPointRoundingMode.NEAREST_TIES_AWAY" - TOWARD_POSITIVE = "FloatingPointRoundingMode.TOWARDS_POSITIVE" - TOWARD_NEGATIVE = "FloatingPointRoundingMode.TOWARDS_NEGATIVE" - TOWARD_ZERO = "FloatingPointRoundingMode.TOWARDS_ZERO" + TOWARD_POSITIVE = "FloatingPointRoundingMode.TOWARD_POSITIVE" + TOWARD_NEGATIVE = "FloatingPointRoundingMode.TOWARD_NEGATIVE" + TOWARD_ZERO = "FloatingPointRoundingMode.TOWARD_ZERO" litRoundingMode = from_enum(RoundingMode) @@ -259,7 +323,7 @@ class Quantifier(Enum): @generate def litList(): - yield (string("List.of(") | string("ImmutableList.of(")) + yield (string("List.of(") | string("ImmutableList.of(") | string("Set.of(")) yield whitespace.optional() arg0 = yield argument.optional().map(lambda p: [p] if p is not None else []) args = [] @@ -274,6 +338,7 @@ def test_list(): assert litList.parse("List.of(1, 2, var)") == [1, 2, "var"] assert litList.parse("ImmutableList.of()") == [] assert litList.parse("List.of(ImmutableList.of(1,2), ImmutableList.of(3,7))") == [[1, 2], [3, 7]] + assert litList.parse("Set.of(1,2)") == [1, 2] variable = regex(r"[A-Za-z][A-Za-z0-9]*") @@ -286,7 +351,7 @@ def test_variable(): argument.become(alt( litBool, - litNum, + litNumber, litRoundingMode, litSign, litString, From 775f8da6df3023ca8abc6821421de5693edafa18 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:28:49 +0100 Subject: [PATCH 157/233] traceToSmtlib: Support more types for integer.makeNumber and rational.makeNumber --- scripts/traceToSmtlib.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 317488e46d..9cecb6a05c 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -520,7 +520,7 @@ def flattenProvers(prog: List[Definition]): def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" sortMap = {} - nameMap = {} # Stores UF names for function declarations + nameMap = {} # Stores UF names for function declarations output = ["(set-option :produce-models true)", "(set-option :global-declarations true)"] for stmt in prog[5:]: @@ -869,20 +869,34 @@ def translate(prog: List[Definition]): elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "makeNumber"]: arg1 = stmt.value[-1].args[0] - if not isinstance(arg1, int): - raise Exception("makeNumber is only supported for constant integer arguments") sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1 if arg1 >= 0 else f'(- {abs(arg1)})'})') + if isinstance(arg1, int): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1 if arg1 >= 0 else f'(- {abs(arg1)})'})') + elif isinstance(arg1, Fraction): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (div {arg1.numerator} {arg1.denominator}))') + elif isinstance(arg1, float): + # FIXME We need to use euclidean division here. Converting with int() will (probably?) truncate + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {int(arg1)})') + else: + raise Exception("makeNumber is only supported for constant integer arguments") elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "makeNumber"]: arg1 = stmt.value[-1].args[0] - if not isinstance(arg1, int): - # TODO Allow rational values - raise Exception("makeNumber is only supported for constant integer arguments") sortMap[stmt.variable] = RationalType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + if isinstance(arg1, int): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + elif isinstance(arg1, Fraction): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (/ {arg1.numerator} {arg1.denominator}))') + elif isinstance(arg1, float): + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + else: + raise Exception("makeNumber is only supported for constant integer arguments") elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name From a183c95ddd7817530b5cd6aba3a4e7b4951d6b04 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:30:24 +0100 Subject: [PATCH 158/233] traceToSmtlib: Support integer.distinct and integer.sum --- scripts/traceToSmtlib.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 9cecb6a05c..57c6afa3a2 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -803,8 +803,10 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {arg1} {arg2}))') elif stmt.getCalls()[-1] == "distinct": - # FIXME Requires list arguments - raise Exception("distinct not supported") + args = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "divide"]: arg1 = stmt.value[-1].args[0] @@ -940,8 +942,10 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {arg1} {arg2}))') elif stmt.getCalls()[-1] == "sum": - # FIXME Requires list arguments - raise Exception("sum not supported") + args = stmt.value[-1].args[0] + sortMap[stmt.variable] = IntegerType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(args)}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') From d31705dc5f4776014226e08b4b6705e4a5a103cf Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:33:07 +0100 Subject: [PATCH 159/233] Trace: Escape quotes and newline characters when printing String literals --- .../trace/TraceBitvectorFormulaManager.java | 5 +++-- .../trace/TraceBooleanFormulaManager.java | 2 +- .../trace/TraceEnumerationFormulaManager.java | 10 ++++++---- .../trace/TraceFloatingPointFormulaManager.java | 3 ++- .../delegate/trace/TraceFormulaManager.java | 8 +++++--- .../java_smt/delegate/trace/TraceLogger.java | 15 +++++++++++++-- .../trace/TraceNumeralFormulaManager.java | 2 +- .../delegate/trace/TraceStringFormulaManager.java | 4 ++-- .../java_smt/delegate/trace/TraceUFManager.java | 4 ++-- 9 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java index 9b5d6b7f57..ac4623af31 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -63,7 +63,7 @@ public IntegerFormula toIntegerFormula(BitvectorFormula pI, boolean signed) { public BitvectorFormula makeVariable(int length, String pVar) { return logger.logDef( "mgr.getBitvectorFormulaManager()", - String.format("makeVariable(%s, \"%s\")", length, pVar), + String.format("makeVariable(%s, %s)", length, logger.printString(pVar)), () -> delegate.makeVariable(length, pVar)); } @@ -71,7 +71,8 @@ public BitvectorFormula makeVariable(int length, String pVar) { public BitvectorFormula makeVariable(BitvectorType type, String pVar) { return logger.logDef( "mgr.getBitvectorFormulaManager()", - String.format("makeVariable(%s, \"%s\")", logger.printFormulaType(type), pVar), + String.format( + "makeVariable(%s, %s)", logger.printFormulaType(type), logger.printString(pVar)), () -> delegate.makeVariable(type, pVar)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 2cba7a01f3..99c104d47e 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -49,7 +49,7 @@ public BooleanFormula makeFalse() { public BooleanFormula makeVariable(String pVar) { return logger.logDef( "mgr.getBooleanFormulaManager()", - String.format("makeVariable(\"%s\")", pVar), + String.format("makeVariable(%s)", logger.printString(pVar)), () -> delegate.makeVariable(pVar)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java index 0fc41909cc..cd31bdec3d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceEnumerationFormulaManager.java @@ -11,6 +11,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Joiner; +import com.google.common.collect.FluentIterable; import java.util.Set; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.EnumerationFormula; @@ -32,8 +33,9 @@ public EnumerationFormulaType declareEnumeration(String name, Set elemen return logger.logDefKeep( "mgr.getEnumerationFormulaManager()", String.format( - "declareEnumeration(\"%s\", Set.of(\"%s\"))", - name, Joiner.on("\", \"").join(elementNames)), + "declareEnumeration(%s, Set.of(%s))", + logger.printString(name), + FluentIterable.from(elementNames).transform(logger::printString).join(Joiner.on(", "))), () -> delegate.declareEnumeration(name, elementNames)); } @@ -41,7 +43,7 @@ public EnumerationFormulaType declareEnumeration(String name, Set elemen public EnumerationFormula makeConstant(String pName, EnumerationFormulaType pType) { return logger.logDef( "mgr.getEnumerationFormulaManager()", - String.format("makeConstant(\"%s\", %s)", pName, logger.toVariable(pType)), + String.format("makeConstant(%s, %s)", logger.printString(pName), logger.toVariable(pType)), () -> delegate.makeConstant(pName, pType)); } @@ -49,7 +51,7 @@ public EnumerationFormula makeConstant(String pName, EnumerationFormulaType pTyp public EnumerationFormula makeVariable(String pVar, EnumerationFormulaType pType) { return logger.logDef( "mgr.getEnumerationFormulaManager()", - String.format("makeVariable(\"%s\", %s)", pVar, logger.toVariable(pType)), + String.format("makeVariable(%s, %s)", logger.printString(pVar), logger.toVariable(pType)), () -> delegate.makeVariable(pVar, pType)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index e78d3dc0c8..cc02dc0152 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -165,7 +165,8 @@ exponent, mantissa, printSign(sign), logger.printFormulaType(type)), public FloatingPointFormula makeVariable(String pVar, FloatingPointType type) { return logger.logDef( "mgr.getFloatingPointFormulaManager()", - String.format("makeVariable(\"%s\", %s)", pVar, logger.printFormulaType(type)), + String.format( + "makeVariable(%s, %s)", logger.printString(pVar), logger.printFormulaType(type)), () -> delegate.makeVariable(pVar, type)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index fa47e45fd3..5f89d176ab 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -140,8 +140,8 @@ public Formula visitFreeVariable(Formula f, String name) { logger.logDef( "mgr", String.format( - "makeVariable(%s, \"%s\")", - logger.printFormulaType(delegate.getFormulaType(f)), name), + "makeVariable(%s, %s)", + logger.printFormulaType(delegate.getFormulaType(f)), logger.printString(name)), () -> delegate.makeVariable(delegate.getFormulaType(f), name)); Preconditions.checkArgument(g.equals(f)); } @@ -274,7 +274,9 @@ public T makeVariable(FormulaType formulaType, String nam String var = logger.newVariable(); logger.appendDef( var, - String.format("mgr.makeVariable(%s, \"%s\")", logger.printFormulaType(formulaType), name)); + String.format( + "mgr.makeVariable(%s, %s)", + logger.printFormulaType(formulaType), logger.printString(name))); T f = delegate.makeVariable(formulaType, name); if (logger.isTracked(f)) { logger.undoLast(); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 8079f8d2b0..96c3ae75c8 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -216,8 +216,19 @@ public void logStmtDiscard(String prefix, String method, CheckedRunnable closure } /** - * Takes a {@link org.sosy_lab.java_smt.api.FormulaType} and returns a Java expression to - * construct this type. + * Print a String for the trace. + * + *

Adds quotes around the literal and escapes special characters. + */ + public String printString(String pString) { + // TODO Do we need more escape sequences? + return String.format("\"%s\"", pString.replace("\"", "\\\"").replace("\n", "\\\n")); + } + + /** + * Print a {@link org.sosy_lab.java_smt.api.FormulaType} for the trace. + * + *

Returns a Java expression that will construct the type. */ public String printFormulaType(FormulaType pType) { if (pType.isBooleanType()) { diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index 0361b9cfa9..3b44cb7c0a 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -55,7 +55,7 @@ public ResultFormulaType makeNumber(BigInteger number) { public ResultFormulaType makeVariable(String pVar) { return logger.logDef( getPrefix(), - String.format("makeVariable(\"%s\")", pVar), + String.format("makeVariable(%s)", logger.printString(pVar)), () -> delegate.makeVariable(pVar)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java index 6881e35914..835988eec9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java @@ -31,7 +31,7 @@ public class TraceStringFormulaManager implements StringFormulaManager { public StringFormula makeString(String value) { return logger.logDef( "mgr.getStringFormulaManager()", - String.format("makeString(\"%s\")", value), + String.format("makeString(%s)", logger.printString(value)), () -> delegate.makeString(value)); } @@ -39,7 +39,7 @@ public StringFormula makeString(String value) { public StringFormula makeVariable(String pVar) { return logger.logDef( "mgr.getStringFormulaManager()", - String.format("makeVariable(\"%s\")", pVar), + String.format("makeVariable(%s)", logger.printString(pVar)), () -> delegate.makeVariable(pVar)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index d4e067c341..96eb5704f9 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -40,8 +40,8 @@ public FunctionDeclaration declareUF( logger.appendDef( var, String.format( - "mgr.getUFManager().declareUF(\"%s\", %s, %s)", - name, + "mgr.getUFManager().declareUF(%s, %s, %s)", + logger.printString(name), logger.printFormulaType(returnType), FluentIterable.from(args).transform(logger::printFormulaType).join(Joiner.on(", ")))); FunctionDeclaration f = delegate.declareUF(name, returnType, args); From af6981af5b5b54e11fa7b2da1f683f96d5bdaa13 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:33:41 +0100 Subject: [PATCH 160/233] Trace: Fix two typos in the log --- .../java_smt/delegate/trace/TraceRationalFormulaManager.java | 2 +- src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java index cf03d5f5f2..1d72dd9ba4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java @@ -32,7 +32,7 @@ public class TraceRationalFormulaManager public RationalFormula makeNumber(double number) { return logger.logDef( "mgr.getRationalFormulaManager()", - String.format("makeNumber(%s))", number), + String.format("makeNumber(%s)", number), () -> delegate.makeNumber(number)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 96eb5704f9..3d6dfc6371 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -58,7 +58,7 @@ public T callUF( FunctionDeclaration funcType, List args) { if (funcType.getKind().equals(FunctionDeclarationKind.UF)) { return logger.logDef( - "mgr.getUFManager", + "mgr.getUFManager()", String.format("callUF(%s, %s)", logger.toVariable(funcType), logger.toVariables(args)), () -> delegate.callUF(funcType, args)); } else { From 1a78dbc6dc84d9d175805f7441b1d9d584412b94 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:35:09 +0100 Subject: [PATCH 161/233] Trace: Don't keep log entries for mgr.substitute --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 5f89d176ab..6ca0da29f3 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -1177,7 +1177,7 @@ public ImmutableMap extractVariablesAndUFs(Formula f) { @Override public T substitute( T f, Map fromToMapping) { - return logger.logDef( + return logger.logDefDiscard( "mgr", String.format( "substitute(%s, ImmutableMap.ofEntries(%s))", From 0c289f3c87a3a915201bad58d0f2d849bc094ca9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 16:35:40 +0100 Subject: [PATCH 162/233] Trace: Don't keep log entries for Model.evaluate and Model.eval --- .../java_smt/delegate/trace/TraceModel.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java index 09a234625d..69a5d19bdb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java @@ -64,7 +64,7 @@ public ImmutableList asList() { @Override public @Nullable T eval(T formula) { - return logger.logDef( + return logger.logDefDiscard( logger.toVariable(this), String.format("eval(%s)", logger.toVariable(formula)), () -> delegate.eval(formula)); @@ -72,7 +72,7 @@ public ImmutableList asList() { @Override public @Nullable Object evaluate(Formula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -80,7 +80,7 @@ public ImmutableList asList() { @Override public @Nullable BigInteger evaluate(IntegerFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -88,7 +88,7 @@ public ImmutableList asList() { @Override public @Nullable Rational evaluate(RationalFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -96,7 +96,7 @@ public ImmutableList asList() { @Override public @Nullable Boolean evaluate(BooleanFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -104,7 +104,7 @@ public ImmutableList asList() { @Override public @Nullable BigInteger evaluate(BitvectorFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -112,7 +112,7 @@ public ImmutableList asList() { @Override public @Nullable String evaluate(StringFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -120,7 +120,7 @@ public ImmutableList asList() { @Override public @Nullable String evaluate(EnumerationFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); @@ -128,7 +128,7 @@ public ImmutableList asList() { @Override public @Nullable FloatingPointNumber evaluate(FloatingPointFormula formula) { - return logger.logDefKeep( + return logger.logDefDiscard( logger.toVariable(this), String.format("evaluate(%s)", logger.toVariable(formula)), () -> delegate.evaluate(formula)); From 4ba4f19def68695fa778233855be0341b5096637 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 17:23:48 +0100 Subject: [PATCH 163/233] Trace: Fix prefix for several methods in TraceBooleanFormulaManager --- .../delegate/trace/TraceBooleanFormulaManager.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 99c104d47e..2d30db4927 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -152,7 +152,7 @@ public BooleanFormula xor(BooleanFormula bits1, BooleanFormula bits2) { @Override public R visit(BooleanFormula pFormula, BooleanFormulaVisitor visitor) { return logger.logDefDiscard( - "mgr", + "mgr.getBooleanFormulaManager()", String.format( "visit(%s, new DefaultBooleanFormulaVisitor<>() {" + "protected Formula visitDefault(Formula f) {" @@ -166,7 +166,7 @@ public R visit(BooleanFormula pFormula, BooleanFormulaVisitor visitor) { public void visitRecursively( BooleanFormula f, BooleanFormulaVisitor rFormulaVisitor) { logger.logStmtDiscard( - "mgr", + "mgr.getBooleanFormulaManager()", String.format( "visitRecursively(%s, new DefaultBooleanFormulaVisitor<>() {" + "protected TraversalProcess visitDefault(Formula f) {" @@ -180,7 +180,7 @@ public void visitRecursively( public BooleanFormula transformRecursively( BooleanFormula f, BooleanFormulaTransformationVisitor pVisitor) { return logger.logDefDiscard( - "mgr", + "mgr.getBooleanFormulaManager()", String.format( "transformRecursively(%s, new BooleanFormulaTransformationVisitor(%s) {})", logger.toVariable(f), "mgr"), @@ -190,7 +190,9 @@ public BooleanFormula transformRecursively( @Override public Set toConjunctionArgs(BooleanFormula f, boolean flatten) { logger.appendStmt( - String.format("mgr.toConjunctionArgs(%s, %s)", logger.toVariable(f), flatten)); + String.format( + "mgr.getBooleanFormulaManager().toConjunctionArgs(%s, %s)", + logger.toVariable(f), flatten)); Set set = delegate.toConjunctionArgs(f, flatten); logger.undoLast(); return mgr.rebuildAll(set); @@ -199,7 +201,9 @@ public Set toConjunctionArgs(BooleanFormula f, boolean flatten) @Override public Set toDisjunctionArgs(BooleanFormula f, boolean flatten) { logger.appendStmt( - String.format("mgr.toDisjunctionArgs(%s, %s)", logger.toVariable(f), flatten)); + String.format( + "mgr.getBooleanFormulaManager().toDisjunctionArgs(%s, %s)", + logger.toVariable(f), flatten)); Set set = delegate.toDisjunctionArgs(f, flatten); logger.undoLast(); return mgr.rebuildAll(set); From 58fd3fa6a9b8e7da19570364a6e6ea03e49c8933 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 22:12:04 +0100 Subject: [PATCH 164/233] Revert "Trace: Use varargs instead of ImmutableList.of() in the trace" Wrapping the arguments in a list allows us to more easily handle the case when there are no arguments This reverts commit c549ce04 --- .../sosy_lab/java_smt/delegate/trace/TraceUFManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index 3d6dfc6371..dc996afd81 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -40,7 +40,7 @@ public FunctionDeclaration declareUF( logger.appendDef( var, String.format( - "mgr.getUFManager().declareUF(%s, %s, %s)", + "mgr.getUFManager().declareUF(%s, %s, ImmutableList.of(%s))", logger.printString(name), logger.printFormulaType(returnType), FluentIterable.from(args).transform(logger::printFormulaType).join(Joiner.on(", ")))); @@ -59,7 +59,9 @@ public T callUF( if (funcType.getKind().equals(FunctionDeclarationKind.UF)) { return logger.logDef( "mgr.getUFManager()", - String.format("callUF(%s, %s)", logger.toVariable(funcType), logger.toVariables(args)), + String.format( + "callUF(%s, ImmutableList.of(%s))", + logger.toVariable(funcType), logger.toVariables(args)), () -> delegate.callUF(funcType, args)); } else { return mgr.makeApplication(funcType, args); From a09c9f4705ff1f1e4f323adfa5ad44094e0d346f Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 22:23:35 +0100 Subject: [PATCH 165/233] Trace: Escape more String literals --- .../java_smt/delegate/trace/TraceArrayFormulaManager.java | 6 ++++-- .../java_smt/delegate/trace/TraceFormulaManager.java | 6 +++--- .../java_smt/delegate/trace/TraceStringFormulaManager.java | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java index 7a1da852dc..d5d5714203 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceArrayFormulaManager.java @@ -56,8 +56,10 @@ ArrayFormula makeArray(String pName, FTI pIndexType, FTE pElementType) { return logger.logDef( "mgr.getArrayFormulaManager()", String.format( - "makeArray(\"%s\", %s, %s)", - pName, logger.printFormulaType(pIndexType), logger.printFormulaType(pElementType)), + "makeArray(%s, %s, %s)", + logger.printString(pName), + logger.printFormulaType(pIndexType), + logger.printFormulaType(pElementType)), () -> delegate.makeArray(pName, pIndexType, pElementType)); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 6ca0da29f3..7b2b33eb3c 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -207,7 +207,7 @@ public Formula visitConstant(Formula f, Object value) { var g = logger.logDef( "mgr.getStringFormulaManager()", - String.format("makeString(%s)", value), + String.format("makeString(%s)", logger.printString((String) value)), () -> delegate.getStringFormulaManager().makeString((String) value)); Preconditions.checkArgument(g.equals(f)); } else { @@ -1081,7 +1081,7 @@ public FormulaType getFormulaType(T formula) { @Override public BooleanFormula parse(String s) throws IllegalArgumentException { String var = logger.newVariable(); - logger.appendDef(var, String.format("mgr.parse(\"%s\")", s)); + logger.appendDef(var, String.format("mgr.parse(%s)", logger.printString(s))); BooleanFormula f = delegate.parse(s); logger.undoLast(); return rebuild(f); @@ -1115,7 +1115,7 @@ public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) @Override public T simplify(T input) throws InterruptedException { - return logger.logDef( + return logger.logDefDiscard( "mgr", String.format("simplify(%s)", logger.toVariable(input)), () -> delegate.simplify(input)); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java index 835988eec9..a8212da2c2 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceStringFormulaManager.java @@ -187,7 +187,7 @@ public BooleanFormula in(StringFormula str, RegexFormula regex) { public RegexFormula makeRegex(String value) { return logger.logDef( "mgr.getStringFormulaManager()", - String.format("makeRegex(\"%s\")", value), + String.format("makeRegex(%s)", logger.printString(value)), () -> delegate.makeRegex(value)); } From a2cbdfd688b9ee4f8019cc5085e28886ccca7dcf Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 22:41:17 +0100 Subject: [PATCH 166/233] Trace: Improve the escaping algorithm --- scripts/traceToSmtlib.py | 14 +++++++--- .../java_smt/delegate/trace/TraceLogger.java | 27 +++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 57c6afa3a2..d7c563ea5f 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -208,11 +208,19 @@ def test_number(): # String constants -litString = regex(r'"(\\"|[^"])*"').map(lambda str: str.replace(r'\"', '"').replace(r'\n', '\n')) - +@generate +def litString(): + yield string('"') + lit = yield regex(r'(\\"|\\\'|\\n|\\\\|[^"])*') + yield string('"') + return lit.replace('\\"', '"').replace('\\\'', '\'').replace('\\n', '\n').replace('\\\\', '\\') def test_string(): - assert litString.parse('"str"') == "str" + assert litString.parse('"str"') == 'str' + assert litString.parse('"\\""') == '"' + assert litString.parse('"\\\\"') == '\\' + assert litString.parse('"\\\'"') == '\'' + assert litString.parse('"\\n"') == '\n' class RoundingMode(Enum): diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 96c3ae75c8..6b606940db 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -221,8 +221,31 @@ public void logStmtDiscard(String prefix, String method, CheckedRunnable closure *

Adds quotes around the literal and escapes special characters. */ public String printString(String pString) { - // TODO Do we need more escape sequences? - return String.format("\"%s\"", pString.replace("\"", "\\\"").replace("\n", "\\\n")); + StringBuilder builder = new StringBuilder(); + builder.append("\""); + for (var c : pString.codePoints().toArray()) { + switch (c) { + case '\'': + builder.append("\\'"); + break; + case '"': + builder.append("\\\""); + break; + case '\\': + builder.append("\\\\"); + break; + case '\n': + builder.append("\\n"); + break; + case '\t': + builder.append("\\t"); + break; + default: + builder.appendCodePoint(c); + } + } + builder.append("\""); + return builder.toString(); } /** From 654e738e8a878e60b43a52f039d6c0297d9f5c5d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 23:00:08 +0100 Subject: [PATCH 167/233] Trace: Don't keep log entries for mgr.applyTactics --- .../delegate/trace/TraceFormulaManager.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 7b2b33eb3c..97fcdd9699 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -1098,19 +1098,10 @@ public Appender dumpFormula(BooleanFormula pT) { @Override public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) throws InterruptedException, SolverException { - String var = logger.newVariable(); - logger.appendDef( - var, - String.format( - "mgr.applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name())); - BooleanFormula f = delegate.applyTactic(input, tactic); - if (logger.isTracked(f)) { - logger.undoLast(); - return f; - } else { - logger.mapVariable(var, f); - return rebuild(f); - } + return logger.logDefDiscard( + "mgr", + String.format("applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name()), + () -> delegate.applyTactic(input, tactic)); } @Override From ac74e6d2f61d1fe5ffa70c661e28147f3d156fca Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 23:45:21 +0100 Subject: [PATCH 168/233] traceToSmtlib: Use varargs in uf.callUF and uf.declareUF --- scripts/traceToSmtlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index d7c563ea5f..7affaa6de6 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1223,7 +1223,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[:-1] == ["mgr", "getUFManager"]: if stmt.getCalls()[-1] == "callUF": arg0 = stmt.value[-1].args[0] - args = stmt.value[-1].args[1:] + args = stmt.value[-1].args[1] name = nameMap[arg0] sortMap[stmt.variable] = sortMap[arg0].value output.append( @@ -1232,7 +1232,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "declareUF": arg0 = stmt.value[-1].args[0] arg1 = stmt.value[-1].args[1] - args = stmt.value[-1].args[2:] + args = stmt.value[-1].args[2] sortMap[stmt.variable] = FunctionType(args, arg1) nameMap[stmt.variable] = arg0 output.append( From 5a2d9822825005ba23422770797140b467abcc61 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Tue, 9 Dec 2025 23:46:11 +0100 Subject: [PATCH 169/233] traceToSmtlib: Use list arguments in numeral.distinct and numeral.sum --- scripts/traceToSmtlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 7affaa6de6..72f799a146 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -811,7 +811,7 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {arg1} {arg2}))') elif stmt.getCalls()[-1] == "distinct": - args = stmt.value[-1].args[0] + args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') @@ -950,7 +950,7 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {arg1} {arg2}))') elif stmt.getCalls()[-1] == "sum": - args = stmt.value[-1].args[0] + args = stmt.value[-1].args sortMap[stmt.variable] = IntegerType() output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(args)}))') From 862c91d2a8a7412ba1e598bc0c7c75808296cfb8 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 05:33:17 +0100 Subject: [PATCH 170/233] traceToSmtlib: Add missing fp functions --- scripts/traceToSmtlib.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 72f799a146..5452b219db 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -215,6 +215,7 @@ def litString(): yield string('"') return lit.replace('\\"', '"').replace('\\\'', '\'').replace('\\n', '\n').replace('\\\\', '\\') + def test_string(): assert litString.parse('"str"') == 'str' assert litString.parse('"\\""') == '"' @@ -1059,6 +1060,42 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.gt {arg1} {arg2}))') + elif stmt.getCalls()[-1] == "isInfinity": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isInfinite {arg1}))') + + elif stmt.getCalls()[-1] == "isNaN": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isNaN {arg1}))') + + elif stmt.getCalls()[-1] == "isNegative": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isNegative {arg1}))') + + elif stmt.getCalls()[-1] == "isNormal": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isNormal {arg1}))') + + elif stmt.getCalls()[-1] == "isSubnormal": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isSubnormal {arg1}))') + + elif stmt.getCalls()[-1] == "isZero": + arg1 = stmt.value[-1].args[0] + sortMap[stmt.variable] = BooleanType() + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isZero {arg1}))') + elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] @@ -1109,6 +1146,9 @@ def translate(prog: List[Definition]): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ +oo {arg1.exponent} {arg1.significand}))') + elif stmt.getCalls()[-1] == "makeRoundingMode": + pass + elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name arg2 = stmt.value[-1].args[1] From d4a4b5649aaa8dacfa9bd9c654c2c50bea078edb Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 05:33:43 +0100 Subject: [PATCH 171/233] traceToSmtlib: Add support for more argument types in fp.makeNumber --- scripts/traceToSmtlib.py | 43 +++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 5452b219db..074351bb42 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1123,22 +1123,33 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ NaN {arg1.exponent} {arg1.significand}))') elif stmt.getCalls()[-1] == "makeNumber": - if len(stmt.value[-1].args) < 4: - raise Exception(f'Expected 4 arguments to fp.makeNumber, got {len(stmt.value)}') - arg1 = stmt.value[-1].args[0] # exponent - arg2 = stmt.value[-1].args[1] # significand - arg3 = stmt.value[-1].args[2] # sign - arg4 = stmt.value[-1].args[3] # type - if not (isinstance(arg1, int) and - isinstance(arg2, int) and - isinstance(arg3, Sign) and - isinstance(arg4, FloatType)): - # TODO Support more value constructors - raise Exception( - "We currently only support fp.makeNumber when sign, exponent and mantissa are given explicitly") - sortMap[stmt.variable] = arg4 - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp {'#1' if arg3 == Sign.NEGATIVE else '#0'} {printBitvector(arg4.exponent, arg1)} {printBitvector(arg4.significand, arg2)}))') + args = stmt.value[-1].args + if (len(args) == 3 + and (isinstance(args[0], float) or isinstance(args[0], int) or isinstance(args[0], str)) + and isinstance(args[1], Type) + and isinstance(args[2], RoundingMode)): + rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] + sortMap[stmt.variable] = args[1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm} {args[0]}))') + elif (len(args) == 3 + and isinstance(args[0], Fraction) + and isinstance(args[1], Type) + and isinstance(args[2], RoundingMode)): + rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] + sortMap[stmt.variable] = args[1] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm} (/ {args[0].numerator} {args[0].denominator})))') + elif (len(args) == 4 + and isinstance(args[0], int) + and isinstance(args[1], int) + and isinstance(args[2], Sign) + and isinstance(args[3], FloatType)): + sortMap[stmt.variable] = args[3] + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp {'#1' if args[2] == Sign.NEGATIVE else '#0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand, args[1])}))') + else: + raise Exception(f'Unsupported call: {stmt.getCalls()} ({type(args[0])} {args})') elif stmt.getCalls()[-1] == "makePlusInfinity": arg1 = stmt.value[-1].args[0] From afd1544a57be09050fc3ef90f339d84b5a68ade6 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 10:39:27 +0100 Subject: [PATCH 172/233] Trace: Include rounding mode in the trace for all fp calls --- .../TraceFloatingPointFormulaManager.java | 66 ++++--------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index cc02dc0152..4fd1d5e114 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -67,10 +67,7 @@ public FloatingPointRoundingMode fromRoundingModeFormula( @Override public FloatingPointFormula makeNumber(double n, FloatingPointType type) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("makeNumber(%s, %s)", toString(n), logger.printFormulaType(type)), - () -> delegate.makeNumber(n, type)); + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -88,10 +85,7 @@ public FloatingPointFormula makeNumber( @Override public FloatingPointFormula makeNumber(BigDecimal n, FloatingPointType type) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("makeNumber(new BigDecimal(\"%s\"), %s)", n, logger.printFormulaType(type)), - () -> delegate.makeNumber(n, type)); + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -107,10 +101,7 @@ public FloatingPointFormula makeNumber( @Override public FloatingPointFormula makeNumber(String n, FloatingPointType type) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("makeNumber(\"%s\", %s)", n, logger.printFormulaType(type)), - () -> delegate.makeNumber(n, type)); + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -126,10 +117,7 @@ public FloatingPointFormula makeNumber( @Override public FloatingPointFormula makeNumber(Rational n, FloatingPointType type) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("makeNumber(Rational.of(\"%s\"), %s)", n, logger.printFormulaType(type)), - () -> delegate.makeNumber(n, type)); + return makeNumber(n, type, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -138,11 +126,8 @@ public FloatingPointFormula makeNumber( return logger.logDef( "mgr.getFloatingPointFormulaManager()", String.format( - "makeNumber(Rational.of(%s, %s), %s, %s)", - n.getNum(), - n.getDen(), - logger.printFormulaType(type), - printRoundingMode(pFloatingPointRoundingMode)), + "makeNumber(Rational.of(\"%s\"), %s, %s)", + n, logger.printFormulaType(type), printRoundingMode(pFloatingPointRoundingMode)), () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); } @@ -197,12 +182,7 @@ public FloatingPointFormula makeNaN(FloatingPointType type) { @Override public T castTo( FloatingPointFormula source, boolean signed, FormulaType targetType) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format( - "castTo(%s, %s, %s)", - logger.toVariable(source), signed, logger.printFormulaType(targetType)), - () -> delegate.castTo(source, signed, targetType)); + return castTo(source, signed, targetType, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -225,12 +205,7 @@ public T castTo( @Override public FloatingPointFormula castFrom( Formula source, boolean signed, FloatingPointType targetType) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format( - "castFrom(%s, %s, %s)", - logger.toVariable(source), signed, logger.printFormulaType(targetType)), - () -> delegate.castFrom(source, signed, targetType)); + return castFrom(source, signed, targetType, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -312,10 +287,7 @@ public FloatingPointFormula min(FloatingPointFormula number1, FloatingPointFormu @Override public FloatingPointFormula sqrt(FloatingPointFormula number) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("sqrt(%s)", logger.toVariable(number)), - () -> delegate.sqrt(number)); + return sqrt(number, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -329,10 +301,7 @@ public FloatingPointFormula sqrt( @Override public FloatingPointFormula add(FloatingPointFormula number1, FloatingPointFormula number2) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("add(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.add(number1, number2)); + return add(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -352,10 +321,7 @@ public FloatingPointFormula add( @Override public FloatingPointFormula subtract(FloatingPointFormula number1, FloatingPointFormula number2) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("subtract(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.subtract(number1, number2)); + return subtract(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -375,10 +341,7 @@ public FloatingPointFormula subtract( @Override public FloatingPointFormula divide(FloatingPointFormula number1, FloatingPointFormula number2) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("divide(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.divide(number1, number2)); + return divide(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override @@ -398,10 +361,7 @@ public FloatingPointFormula divide( @Override public FloatingPointFormula multiply(FloatingPointFormula number1, FloatingPointFormula number2) { - return logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format("multiply(%s, %s)", logger.toVariable(number1), logger.toVariable(number2)), - () -> delegate.multiply(number1, number2)); + return multiply(number1, number2, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); } @Override From 62adb194ee43590dadcfabfe02861d74e57eb779 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 10:40:25 +0100 Subject: [PATCH 173/233] traceToSmtlib: Set logic in the trace --- scripts/traceToSmtlib.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 074351bb42..ca4ff50649 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -530,7 +530,9 @@ def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" sortMap = {} nameMap = {} # Stores UF names for function declarations - output = ["(set-option :produce-models true)", + output = ["(set-logic ALL)", + "(set-option :interactive-mode true)" + "(set-option :produce-models true)", "(set-option :global-declarations true)"] for stmt in prog[5:]: if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: From f42b77c7bea316c63e5078375bc702e18b8f9155 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 10:44:45 +0100 Subject: [PATCH 174/233] traceToSmtlib: Print rounding mode in Smtlib format --- scripts/traceToSmtlib.py | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index ca4ff50649..ac9a4f5c1b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -231,6 +231,20 @@ class RoundingMode(Enum): TOWARD_NEGATIVE = "FloatingPointRoundingMode.TOWARD_NEGATIVE" TOWARD_ZERO = "FloatingPointRoundingMode.TOWARD_ZERO" + def toSmtlib(self): + if self == RoundingMode.NEAREST_TIES_TO_EVEN: + return "RNE" + elif self == RoundingMode.NEAREST_TIES_AWAY: + return "RNA" + elif self == RoundingMode.TOWARD_POSITIVE: + return "RTP" + elif self == RoundingMode.TOWARD_NEGATIVE: + return "RTN" + elif self == RoundingMode.TOWARD_ZERO: + return "RTZ" + else: + raise Exception("Unknown rounding mode") + litRoundingMode = from_enum(RoundingMode) @@ -974,7 +988,7 @@ def translate(prog: List[Definition]): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.add {arg3} {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.add {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "assignment": arg1 = stmt.value[-1].args[0] @@ -992,7 +1006,7 @@ def translate(prog: List[Definition]): sortMap[stmt.variable] = arg3 if isinstance(arg3, FloatType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1})') elif isinstance(arg3, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(arg3, RationalType): @@ -1014,15 +1028,15 @@ def translate(prog: List[Definition]): sourceType = sortMap[arg1] if isinstance(sourceType, FloatType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1})') elif isinstance(sourceType, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(sourceType, RationalType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1})') elif isinstance(sourceType, BitvectorType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent}) {arg3.significand}) {arg3} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent}) {arg3.significand}) {arg4.toSmtlib()} {arg1})') else: raise Exception(f"Illegal cast from {sourceType} to float") @@ -1032,7 +1046,7 @@ def translate(prog: List[Definition]): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.div {arg3} {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.div {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "equalWithFPSemantics": arg1 = stmt.value[-1].args[0] @@ -1133,7 +1147,7 @@ def translate(prog: List[Definition]): rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] sortMap[stmt.variable] = args[1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm} {args[0]}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm.toSmtlib()} {args[0]}))') elif (len(args) == 3 and isinstance(args[0], Fraction) and isinstance(args[1], Type) @@ -1141,7 +1155,7 @@ def translate(prog: List[Definition]): rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] sortMap[stmt.variable] = args[1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm} (/ {args[0].numerator} {args[0].denominator})))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm.toSmtlib()} (/ {args[0].numerator} {args[0].denominator})))') elif (len(args) == 4 and isinstance(args[0], int) and isinstance(args[1], int) @@ -1189,7 +1203,7 @@ def translate(prog: List[Definition]): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.mul {arg3} {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.mul {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] @@ -1209,14 +1223,14 @@ def translate(prog: List[Definition]): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.roundToIntegral {arg2} {arg1}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.roundToIntegral {arg2.toSmtlib()} {arg1}))') elif stmt.getCalls()[-1] == "sqrt": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sqrt {arg2} {arg1}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sqrt {arg2.toSmtlib()} {arg1}))') elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] @@ -1224,7 +1238,7 @@ def translate(prog: List[Definition]): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3} {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "toIeeBitvector": raise Exception("Recasting from float to bitvector is not supported in SMTLIB") From 71a9cce1fa58129249a6b83738d062b3e210cf9d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 10:45:46 +0100 Subject: [PATCH 175/233] traceToSmtlib: Fix formula type for fp.eq --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index ac9a4f5c1b..3dee2fb61b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1051,7 +1051,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "equalWithFPSemantics": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = sortMap[arg1] + sortMap[stmt.variable] = BooleanType() output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.eq {arg1} {arg2}))') From 803ba6266b0b8f9052b61670cf03cf7b7302cc14 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 11:21:46 +0100 Subject: [PATCH 176/233] traceToSmtlib: Fix smtlib output for creating constant fp values --- scripts/traceToSmtlib.py | 70 +++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 3dee2fb61b..6a79983668 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 - +import math # This file is part of JavaSMT, # an API wrapper for a collection of SMT solvers: # https://github.com/sosy-lab/java-smt @@ -511,6 +511,62 @@ def test_printBitvector(): assert printBitvector(8, -5) == "#b11111011" +def parseNumber(repr): + "Parse a String as a number" + value = None + try: + value = int(repr) + except Exception: + pass + if value is not None: + return value + try: + value = Fraction(repr) + except Exception: + pass + if value is not None: + return value + try: + value = float(repr) + except Exception: + pass + if value is not None: + return value + else: + raise Exception(f'Could not parse "{repr}"') + + +def toRealSmtlib(value): + "Print real value as smtlib" + if isinstance(value, str): + return toRealSmtlib(parseNumber(value)) + if isinstance(value, int): + return toRealSmtlib(Fraction(value)) + elif isinstance(value, Fraction): + if value < 0: + return f'(/ (- {-value.numerator}) {value.denominator})' + else: + return f'(/ {value.numerator} {value.denominator})' + else: + raise Exception(f'Can\'t convert "{value}" to Real') + + +def toFpSmtlib(rm, fpType, value): + "Print float value as smtlib" + if isinstance(value, str): + return toFpSmtlib(rm, fpType, parseNumber(value)) + elif value == float('-inf'): + return f'(_ -oo {fpType.exponent} {fpType.significand})' + elif value == float('+inf'): + return f'(_ +oo {fpType.exponent} {fpType.significand})' + elif isinstance(value, float) and math.isnan(value): + return f'(_ NaN {fpType.exponent} {fpType.significand})' + elif isinstance(value, float): + return toFpSmtlib(rm, fpType, Fraction.from_float(value)) + else: + return f'((_ to_fp {fpType.exponent} {fpType.significand}) {rm.toSmtlib()} {toRealSmtlib(value)})' + + def flattenProvers(prog: List[Definition]): "Push all assertions onto the same global prover" # We assume that the provers are not used "in parallel" @@ -1141,21 +1197,13 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "makeNumber": args = stmt.value[-1].args if (len(args) == 3 - and (isinstance(args[0], float) or isinstance(args[0], int) or isinstance(args[0], str)) + and (isinstance(args[0], float | int | Fraction | str)) and isinstance(args[1], Type) and isinstance(args[2], RoundingMode)): rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] sortMap[stmt.variable] = args[1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm.toSmtlib()} {args[0]}))') - elif (len(args) == 3 - and isinstance(args[0], Fraction) - and isinstance(args[1], Type) - and isinstance(args[2], RoundingMode)): - rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] - sortMap[stmt.variable] = args[1] - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {args[1].exponent} {args[1].significand}) {rm.toSmtlib()} (/ {args[0].numerator} {args[0].denominator})))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toFpSmtlib(rm, args[1], args[0])})') elif (len(args) == 4 and isinstance(args[0], int) and isinstance(args[1], int) From 74c9affab6f8ff826f8677ba814216348d77e4f5 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 11:37:54 +0100 Subject: [PATCH 177/233] traceToSmtlib: Fix smtlib output for fp to bv conversions --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 6a79983668..ba02738134 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1070,7 +1070,7 @@ def translate(prog: List[Definition]): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1})') elif isinstance(arg3, BitvectorType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4.toSmtlib()} {arg1}))') else: raise Exception(f"Illegal cast from float to {arg3}") From 30287b659c5598c8845381f2e6a79acc350ba491 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 12:14:57 +0100 Subject: [PATCH 178/233] traceToSmtlib: Fix smtlib output for creating constant integer and real values --- scripts/traceToSmtlib.py | 44 +++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index ba02738134..a9091f4eb9 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -536,6 +536,23 @@ def parseNumber(repr): raise Exception(f'Could not parse "{repr}"') +def toIntSmtlib(value): + "Print integer value as smtlib" + if isinstance(value, str): + return toIntSmtlib(parseNumber(value)) + if isinstance(value, float) and not math.isnan(value) and not math.isinf(value): + return toIntSmtlib(Fraction(value)) + if isinstance(value, int): + return f'(- {-value})' if value < 0 else str(value) + if isinstance(value, Fraction): + if value < 0: + return f'(div (- {-value.numerator}) {value.denominator})' + else: + return f'(div {value.numerator} {value.denominator})' + else: + raise Exception(f'Can\'t convert "{value}" to Integer') + + def toRealSmtlib(value): "Print real value as smtlib" if isinstance(value, str): @@ -953,33 +970,14 @@ def translate(prog: List[Definition]): elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "makeNumber"]: arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = IntegerType() - if isinstance(arg1, int): - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1 if arg1 >= 0 else f'(- {abs(arg1)})'})') - elif isinstance(arg1, Fraction): - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (div {arg1.numerator} {arg1.denominator}))') - elif isinstance(arg1, float): - # FIXME We need to use euclidean division here. Converting with int() will (probably?) truncate - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {int(arg1)})') - else: - raise Exception("makeNumber is only supported for constant integer arguments") + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toIntSmtlib(arg1)})') elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "makeNumber"]: arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = RationalType() - if isinstance(arg1, int): - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') - elif isinstance(arg1, Fraction): - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (/ {arg1.numerator} {arg1.denominator}))') - elif isinstance(arg1, float): - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') - else: - raise Exception("makeNumber is only supported for constant integer arguments") + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toRealSmtlib(arg1)})') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name From 25ec4a967a2e6507aafb7bed0b146b52282c0e44 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 12:15:24 +0100 Subject: [PATCH 179/233] traceToSmtlib: Fix closing parentheses --- scripts/traceToSmtlib.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index a9091f4eb9..f617e2b67e 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1060,12 +1060,12 @@ def translate(prog: List[Definition]): sortMap[stmt.variable] = arg3 if isinstance(arg3, FloatType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') elif isinstance(arg3, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(arg3, RationalType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1}))') elif isinstance(arg3, BitvectorType): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4.toSmtlib()} {arg1}))') @@ -1082,15 +1082,15 @@ def translate(prog: List[Definition]): sourceType = sortMap[arg1] if isinstance(sourceType, FloatType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') elif isinstance(sourceType, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(sourceType, RationalType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') elif isinstance(sourceType, BitvectorType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent}) {arg3.significand}) {arg4.toSmtlib()} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') else: raise Exception(f"Illegal cast from {sourceType} to float") From 08096170b4c47542925285b3db5ea3368506eccc Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 12:52:30 +0100 Subject: [PATCH 180/233] traceToSmtlib: Fix smtlib type for fromIeeeBitvector --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index f617e2b67e..886f848076 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1112,7 +1112,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "fromIeeeBitvector": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = sortMap[arg1] + sortMap[stmt.variable] = arg2 output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg2.exponent} {arg2.significand}) {arg1}))') From 2349e3ce535c49df331d15e3713682182fcd4603 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 12:53:15 +0100 Subject: [PATCH 181/233] traceToSmtlib: Include hidden bit in the size of the significand --- scripts/traceToSmtlib.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 886f848076..89860cb055 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -279,7 +279,7 @@ def litFloatType(): yield whitespace.optional() << string(",") << whitespace.optional() significand = yield regex(r'[0-9]+').map(int) yield whitespace.optional() << string(")") - return FloatType(exponent, significand) + return FloatType(exponent, 1 + significand) @generate @@ -1182,13 +1182,13 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "makeMinusInfinity": arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = FloatType(arg1.exponent, arg1.significand) + sortMap[stmt.variable] = arg1 output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ -oo {arg1.exponent} {arg1.significand}))') elif stmt.getCalls()[-1] == "makeNaN": arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = FloatType(arg1.exponent, arg1.significand) + sortMap[stmt.variable] = arg1 output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ NaN {arg1.exponent} {arg1.significand}))') @@ -1209,13 +1209,13 @@ def translate(prog: List[Definition]): and isinstance(args[3], FloatType)): sortMap[stmt.variable] = args[3] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp {'#1' if args[2] == Sign.NEGATIVE else '#0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand, args[1])}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp '#1' if args[2] == Sign.NEGATIVE else '#0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand-1, args[1])}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()} ({type(args[0])} {args})') elif stmt.getCalls()[-1] == "makePlusInfinity": arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = FloatType(arg1.exponent, arg1.significand) + sortMap[stmt.variable] = arg1 output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ +oo {arg1.exponent} {arg1.significand}))') From 6a486b674c5d66a40d37186d2440a37dddf47ae9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 13:00:55 +0100 Subject: [PATCH 182/233] traceToSmtlib: Add missing #b prefix when printing the sign bit --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 89860cb055..69e5cefa7a 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1209,7 +1209,7 @@ def translate(prog: List[Definition]): and isinstance(args[3], FloatType)): sortMap[stmt.variable] = args[3] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp '#1' if args[2] == Sign.NEGATIVE else '#0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand-1, args[1])}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp #b{'1' if args[2] == Sign.NEGATIVE else '0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand-1, args[1])}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()} ({type(args[0])} {args})') From dba635f3688809ea31ea541380ccbfbf21d33c23 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 13:29:52 +0100 Subject: [PATCH 183/233] traceToSmtlib: Allow float values in toRealSmtlib --- scripts/traceToSmtlib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 69e5cefa7a..ebd5c7367b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -557,8 +557,10 @@ def toRealSmtlib(value): "Print real value as smtlib" if isinstance(value, str): return toRealSmtlib(parseNumber(value)) - if isinstance(value, int): + elif isinstance(value, int): return toRealSmtlib(Fraction(value)) + elif isinstance(value, float): + return toRealSmtlib(Fraction.from_float(value)) elif isinstance(value, Fraction): if value < 0: return f'(/ (- {-value.numerator}) {value.denominator})' @@ -578,8 +580,6 @@ def toFpSmtlib(rm, fpType, value): return f'(_ +oo {fpType.exponent} {fpType.significand})' elif isinstance(value, float) and math.isnan(value): return f'(_ NaN {fpType.exponent} {fpType.significand})' - elif isinstance(value, float): - return toFpSmtlib(rm, fpType, Fraction.from_float(value)) else: return f'((_ to_fp {fpType.exponent} {fpType.significand}) {rm.toSmtlib()} {toRealSmtlib(value)})' From 56f5e1a974e38a8136bd94bdeabe1a29e98dea13 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 13:44:23 +0100 Subject: [PATCH 184/233] traceToSmtlib: Fix typo in model.evaluate --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index ebd5c7367b..a54fff7cc4 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1366,7 +1366,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "evaluate": arg1 = stmt.value[-1].args[0] - output.append(f'(get-values ({arg1}))') + output.append(f'(get-value ({arg1}))') elif stmt.getCalls()[-1] == "getModel": output.append(f'(get-model)') From eb991d74ddfefd789021543ab1e62eeb982b32ba Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 13:53:40 +0100 Subject: [PATCH 185/233] traceToSmtlib: Add missing line break --- scripts/traceToSmtlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index a54fff7cc4..b34ab77068 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -618,7 +618,7 @@ def translate(prog: List[Definition]): sortMap = {} nameMap = {} # Stores UF names for function declarations output = ["(set-logic ALL)", - "(set-option :interactive-mode true)" + "(set-option :interactive-mode true)", "(set-option :produce-models true)", "(set-option :global-declarations true)"] for stmt in prog[5:]: @@ -1209,7 +1209,7 @@ def translate(prog: List[Definition]): and isinstance(args[3], FloatType)): sortMap[stmt.variable] = args[3] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp #b{'1' if args[2] == Sign.NEGATIVE else '0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand-1, args[1])}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp #b{'1' if args[2] == Sign.NEGATIVE else '0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand - 1, args[1])}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()} ({type(args[0])} {args})') From 7c10dbb32a7fb2ab797b3a447f9ceed5e7517a0a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 14:07:28 +0100 Subject: [PATCH 186/233] traceToSmtlib: Fix smtlib for bool.makeBoolean --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index b34ab77068..a02c07044f 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -863,7 +863,7 @@ def translate(prog: List[Definition]): arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {'true' if arg1 else 'false'})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {'true' if arg1 else 'false'})') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name From 8fea4043dfb0e942c6cd00ebe3a2b1e69ed23857 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 15:38:19 +0100 Subject: [PATCH 187/233] traceToSmtlib: Fix parsing of Bool type --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index a02c07044f..535b068724 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -258,7 +258,7 @@ class Sign(Enum): litType = forward_declaration() -litBoolType = string("FormulaType.BooleanType").map(lambda str: IntegerType()) +litBoolType = string("FormulaType.BooleanType").map(lambda str: BooleanType()) litIntegerType = string("FormulaType.IntegerType").map(lambda str: IntegerType()) litRationalType = string("FormulaType.RationalType").map(lambda str: RationalType()) litStringType = string("FormulaType.StringType").map(lambda str: StringType()) From def70696655921cc5a1262332b0816c97d9c5926 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 15:51:07 +0100 Subject: [PATCH 188/233] Trace: Always wrap bv types --- scripts/traceToSmtlib.py | 2 +- .../delegate/trace/TraceBitvectorFormulaManager.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 535b068724..fb0c2b0565 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -720,7 +720,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] # We ignore the actual variable name - sortMap[stmt.variable] = BitvectorType(arg1) + sortMap[stmt.variable] = arg1 output.append(f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') elif stmt.getCalls()[-1] == "multiply": diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java index ac4623af31..4db78c5804 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBitvectorFormulaManager.java @@ -15,6 +15,7 @@ import org.sosy_lab.java_smt.api.BitvectorFormula; import org.sosy_lab.java_smt.api.BitvectorFormulaManager; import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; @@ -61,10 +62,7 @@ public IntegerFormula toIntegerFormula(BitvectorFormula pI, boolean signed) { @Override public BitvectorFormula makeVariable(int length, String pVar) { - return logger.logDef( - "mgr.getBitvectorFormulaManager()", - String.format("makeVariable(%s, %s)", length, logger.printString(pVar)), - () -> delegate.makeVariable(length, pVar)); + return makeVariable(FormulaType.getBitvectorTypeWithSize(length), pVar); } @Override From 2eb45147d187f92721cdd3885160fb58d81e20d6 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 16:05:14 +0100 Subject: [PATCH 189/233] traceToSmtlib: Fix bv comparisons --- scripts/traceToSmtlib.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index fb0c2b0565..dffdddbd8b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -683,26 +683,30 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (>= {arg1} {arg2}))') + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsge' if arg3 else 'bvuge'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (> {arg1} {arg2}))') + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsgt' if arg3 else 'bvugt'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (<= {arg1} {arg2}))') + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsle' if arg3 else 'bvule'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] + arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {arg1} {arg2}))') + output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvslt' if arg3 else 'bvult'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "makeBitvector": arg1 = stmt.value[-1].args[0] From 4e6c028f98eb5a321d488296f715bb25d3e21512 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 16:05:49 +0100 Subject: [PATCH 190/233] traceToSmtlib: Escape uf symbols --- scripts/traceToSmtlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index dffdddbd8b..2a2ce1da91 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1351,9 +1351,9 @@ def translate(prog: List[Definition]): arg1 = stmt.value[-1].args[1] args = stmt.value[-1].args[2] sortMap[stmt.variable] = FunctionType(args, arg1) - nameMap[stmt.variable] = arg0 + nameMap[stmt.variable] = arg0 if arg0[0] == '|' and arg0[-1] == '|' else f'|{arg0}|' output.append( - f'(declare-fun {arg0} {sortMap[stmt.variable].toSmtlib()})') + f'(declare-fun {nameMap[stmt.variable]} {sortMap[stmt.variable].toSmtlib()})') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') From b2826bcc99138670f1edecb1323e8aea75cbe08e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 16:08:46 +0100 Subject: [PATCH 191/233] traceToSmtlib: Fix bv comparisons --- scripts/traceToSmtlib.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 2a2ce1da91..9744faf20d 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -685,28 +685,32 @@ def translate(prog: List[Definition]): arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsge' if arg3 else 'bvuge'} {arg1} {arg2}))') + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsge' if arg3 else 'bvuge'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsgt' if arg3 else 'bvugt'} {arg1} {arg2}))') + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsgt' if arg3 else 'bvugt'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsle' if arg3 else 'bvule'} {arg1} {arg2}))') + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsle' if arg3 else 'bvule'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvslt' if arg3 else 'bvult'} {arg1} {arg2}))') + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvslt' if arg3 else 'bvult'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "makeBitvector": arg1 = stmt.value[-1].args[0] From 9722b9ba2c22bbfcaf2d881d991dfbec676f8f79 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 16:09:53 +0100 Subject: [PATCH 192/233] traceToSmtlib: Throw an exception for unsupported formula managers --- scripts/traceToSmtlib.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 9744faf20d..1d7c172ea2 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1341,6 +1341,22 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') + elif stmt.getCalls()[:-1] == ["mgr", "getQuantifiedFormulaManager"]: + # TODOThro + raise Exception(f'Quantifiers are not supported yet') + + elif stmt.getCalls()[:-1] == ["mgr", "getStringFormulaManager"]: + # TODO + raise Exception(f'Strings are not supported yet') + + elif stmt.getCalls()[:-1] == ["mgr", "getEnumerationFormulaManager"]: + # TODO + raise Exception(f'Enumerations are not supported yet') + + elif stmt.getCalls()[:-1] == ["mgr", "getSLFormulaManager"]: + # TODO + raise Exception(f'Separation logic is not supported yet') + elif stmt.getCalls()[:-1] == ["mgr", "getUFManager"]: if stmt.getCalls()[-1] == "callUF": arg0 = stmt.value[-1].args[0] From e6fe5bcc51d1a8039e0299431a7b03f5ec755b96 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 17:35:45 +0100 Subject: [PATCH 193/233] traceToSmtlib: Add a command line option to store the output in a file --- scripts/traceToSmtlib.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 1d7c172ea2..d6fefcec66 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import argparse import math # This file is part of JavaSMT, # an API wrapper for a collection of SMT solvers: @@ -1422,19 +1423,30 @@ def translate(prog: List[Definition]): else: raise Exception(f'Unsupported call: {stmt.getCalls()}') + output.append("") return '\n'.join(output) if __name__ == '__main__': - arg = sys.argv - if not len(sys.argv) == 2: - print('Expecting a path to a JavaSMT trace as argument') - exit(-1) + options = argparse.ArgumentParser(description='Convert JavaSMT traces to SMTLIB files') + + options.add_argument('file', type=Path, help='Input file') + options.add_argument('--save', action='store_true', + help='Save the output in a *.smt2 file. The path to the file is the same as for the input, but with a different extension') + + args = options.parse_args() - path = Path(sys.argv[1]) - if not (path.is_file()): - print(f'Could not find file "{path}"') + if not args.file.is_file(): + print(f'Could not find input file "{args.file}"') exit(-1) # Translate the trace - print(translate(flattenProvers(program.parse(open(path).read())))) + try: + output = translate(flattenProvers(program.parse(open(args.file).read()))) + except Exception as exception: + print(f'In {args.file}: {exception}') + exit(-1) + + out = open(args.file.with_suffix('.smt2'), 'w') if args.save else sys.stdout + out.write(output) + out.close() From 547719b1474d611abb57a7226fca59d962acee4d Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 17:56:57 +0100 Subject: [PATCH 194/233] traceToSmtlib: Fix smtlib type for rational.makeVariable --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index d6fefcec66..cb798d2a89 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -990,7 +990,7 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name - sortMap[stmt.variable] = IntegerType() + sortMap[stmt.variable] = IntegerType() if 'Integer' in stmt.getCalls()[1] else RationalType() output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') From 37187dca85a442ffaa5ec6764161189a8033c2ba Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Wed, 10 Dec 2025 19:32:53 +0100 Subject: [PATCH 195/233] traceToSmtlib: Cast argument for mixed real-integer theories --- scripts/traceToSmtlib.py | 87 +++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index cb798d2a89..67a3f4eacd 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -623,6 +623,15 @@ def translate(prog: List[Definition]): "(set-option :produce-models true)", "(set-option :global-declarations true)"] for stmt in prog[5:]: + def matchType(param, arg): + "Convert argument to match the given type" + if param == IntegerType() and sortMap[arg] == RationalType(): + return f'(to_int {arg})' + elif param == RationalType() and sortMap[arg] == IntegerType(): + return f'(to_real {arg})' + else: + return arg + if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: if stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] @@ -902,95 +911,82 @@ def translate(prog: List[Definition]): raise Exception(f'Unsupported call: {stmt.getCalls()}') elif stmt.getCalls()[1] == "getIntegerFormulaManager" or stmt.getCalls()[1] == "getRationalFormulaManager": + theoryType = IntegerType() if "Integer" in stmt.getCalls()[1] else RationalType() + + def conv(arg): + "Convert argument to match the type of the parameter" + return matchType(theoryType, arg) + if stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = IntegerType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(map(conv, args))}))') - elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "divide"]: - arg1 = stmt.value[-1].args[0] - arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (div {arg1} {arg2}))') - - elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "divide"]: + elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = RationalType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (/ {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'div' if theoryType == IntegerType() else '/'} {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') - - elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "floor"]: - arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {arg1})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {conv(arg1)} {conv(arg2)}))') - elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "floor"]: + elif stmt.getCalls()[-1] == "floor": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = IntegerType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (to_int {arg1}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {matchType(IntegerType(), arg1)})') elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (>= {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (>= {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (> {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (> {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (<= {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (<= {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {conv(arg1)} {conv(arg2)}))') - elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "makeNumber"]: - arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toIntSmtlib(arg1)})') - - elif stmt.getCalls() == ["mgr", "getRationalFormulaManager", "makeNumber"]: + elif stmt.getCalls()[-1] == "makeNumber": arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = RationalType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toRealSmtlib(arg1)})') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toIntSmtlib(arg1) if theoryType == IntegerType() else toRealSmtlib(arg1)})') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name - sortMap[stmt.variable] = IntegerType() if 'Integer' in stmt.getCalls()[1] else RationalType() + sortMap[stmt.variable] = theoryType output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') @@ -1012,28 +1008,28 @@ def translate(prog: List[Definition]): elif stmt.getCalls()[-1] == "multiply": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = IntegerType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (* {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (* {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] - sortMap[stmt.variable] = IntegerType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {arg1}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)}))') elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] - sortMap[stmt.variable] = IntegerType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {arg1} {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "sum": args = stmt.value[-1].args - sortMap[stmt.variable] = IntegerType() + sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(args)}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(map(conv, args))}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -1363,9 +1359,10 @@ def translate(prog: List[Definition]): arg0 = stmt.value[-1].args[0] args = stmt.value[-1].args[1] name = nameMap[arg0] + values = [matchType(param, arg) for param, arg in zip(sortMap[arg0].arguments, args)] sortMap[stmt.variable] = sortMap[arg0].value output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(args)}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(values)}))') elif stmt.getCalls()[-1] == "declareUF": arg0 = stmt.value[-1].args[0] From 7fa3525a7dbb4eead06c619c515565d67b77e575 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 12:12:42 +0100 Subject: [PATCH 196/233] traceToSmtlib: Add special case for unary sums We use (+ var) to convert integers to reals. However, in SMTLIb + is defined to take at least two arguments. Instead, we have to use to_real for the conversion --- scripts/traceToSmtlib.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 67a3f4eacd..a8278b6994 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1028,8 +1028,12 @@ def conv(arg): elif stmt.getCalls()[-1] == "sum": args = stmt.value[-1].args sortMap[stmt.variable] = theoryType - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(map(conv, args))}))') + if len(args) == 1: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {conv(args[0])})') + else: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(map(conv, args))}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') From 7179ba03ad5e542ae590d8bf20a99d979c69c88c Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 14:13:21 +0100 Subject: [PATCH 197/233] Trace: Add support for interpolation sequences --- .../trace/TraceInterpolatingProverEnvironment.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java index 16e793fbb4..685db6e37d 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java @@ -10,6 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.collect.FluentIterable; import java.util.Collection; import java.util.List; import org.sosy_lab.java_smt.api.BooleanFormula; @@ -35,7 +36,16 @@ public class TraceInterpolatingProverEnvironment extends TraceBasicProverEnvi @Override public List getSeqInterpolants(List> partitionedFormulas) throws SolverException, InterruptedException { - throw new UnsupportedOperationException(); + logger.appendStmt( + String.format( + "%s.getSeqInterpolant(ImmutableList.of(%s))", + logger.toVariable(this), + FluentIterable.from(partitionedFormulas) + .transform( + p -> String.format("ImmutableList" + ".of(%s)", logger.toVariables(p))))); + List seq = delegate.getSeqInterpolants(partitionedFormulas); + logger.undoLast(); + return mgr.rebuildAll(seq); } @Override From 52551d5913dcd2f16c972889189ff29c39986e95 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 15:26:19 +0100 Subject: [PATCH 198/233] Trace: Rebuild formulas in mgr.applyTactic, mgr.simplify and mgr.subdstitute to add the new terms to the cache Trace: Rebuild formulas in mgr.applyTactic and mgr.simplify to add the terms to the cache --- .../delegate/trace/TraceFormulaManager.java | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 97fcdd9699..4846c22cde 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -1098,18 +1098,21 @@ public Appender dumpFormula(BooleanFormula pT) { @Override public BooleanFormula applyTactic(BooleanFormula input, Tactic tactic) throws InterruptedException, SolverException { - return logger.logDefDiscard( - "mgr", - String.format("applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name()), - () -> delegate.applyTactic(input, tactic)); + return rebuild( + logger.logDefDiscard( + "mgr", + String.format( + "applyTactic(%s, %s)", logger.toVariable(input), "Tactic." + tactic.name()), + () -> delegate.applyTactic(input, tactic))); } @Override public T simplify(T input) throws InterruptedException { - return logger.logDefDiscard( - "mgr", - String.format("simplify(%s)", logger.toVariable(input)), - () -> delegate.simplify(input)); + return rebuild( + logger.logDefDiscard( + "mgr", + String.format("simplify(%s)", logger.toVariable(input)), + () -> delegate.simplify(input))); } @Override @@ -1168,19 +1171,21 @@ public ImmutableMap extractVariablesAndUFs(Formula f) { @Override public T substitute( T f, Map fromToMapping) { - return logger.logDefDiscard( - "mgr", - String.format( - "substitute(%s, ImmutableMap.ofEntries(%s))", - logger.toVariable(f), - FluentIterable.from(fromToMapping.entrySet()) - .transform( - entry -> - String.format( - "Map.entry(%s, %s)", - logger.toVariable(entry.getKey()), logger.toVariable(entry.getValue()))) - .join(Joiner.on(", "))), - () -> delegate.substitute(f, fromToMapping)); + return rebuild( + logger.logDefDiscard( + "mgr", + String.format( + "substitute(%s, ImmutableMap.ofEntries(%s))", + logger.toVariable(f), + FluentIterable.from(fromToMapping.entrySet()) + .transform( + entry -> + String.format( + "Map.entry(%s, %s)", + logger.toVariable(entry.getKey()), + logger.toVariable(entry.getValue()))) + .join(Joiner.on(", "))), + () -> delegate.substitute(f, fromToMapping))); } @Override From 819442cd5b8830d68f4dd3c1997a48d077bab85e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 15:41:04 +0100 Subject: [PATCH 199/233] CVC5: Add support for term simplification --- .../sosy_lab/java_smt/solvers/cvc5/CVC5FormulaManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaManager.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaManager.java index e77d109188..ff5618f730 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaManager.java @@ -109,6 +109,11 @@ assert getFormulaCreator().getFormulaType(f) == FormulaType.BooleanType return out.toString(); } + @Override + protected Term simplify(Term f) throws InterruptedException { + return creator.getSolver().simplify(f); + } + @Override public T substitute( final T f, final Map fromToMapping) { From 0b5075110f0fdbf7e3789b7f01ae86b28c2920cb Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 15:41:54 +0100 Subject: [PATCH 200/233] CVC5: Simplify interpolants --- .../java_smt/solvers/cvc5/CVC5InterpolatingProver.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5InterpolatingProver.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5InterpolatingProver.java index f39e004ff7..a322f1f7ca 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5InterpolatingProver.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5InterpolatingProver.java @@ -180,7 +180,8 @@ private Term getCVC5Interpolation(Collection formulasA, Collection f Term interpolant; try { itpSolver.assertFormula(phiPlus); - interpolant = itpSolver.getInterpolant(termManager.mkTerm(Kind.NOT, phiMinus)); + interpolant = + itpSolver.simplify(itpSolver.getInterpolant(termManager.mkTerm(Kind.NOT, phiMinus))); } finally { itpSolver.deletePointer(); } From 7b1fa6824c1e63b25b4a0a84bd13a8f96d57caed Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 16:29:44 +0100 Subject: [PATCH 201/233] traceToSmtlib: Add special cases for several more functions with variable arguments --- scripts/traceToSmtlib.py | 43 +++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index a8278b6994..7d4ed57d88 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -657,8 +657,12 @@ def matchType(param, arg): elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') + if len(args) < 2: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + else: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] @@ -842,8 +846,15 @@ def matchType(param, arg): if stmt.getCalls()[-1] == "and": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (and {' '.join(args)}))') + if len(args) == 0: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + elif len(args) == 1: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {args[0]})') + else: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (and {' '.join(args)}))') elif stmt.getCalls()[-1] == "equivalence": arg1 = stmt.value[-1].args[0] @@ -897,8 +908,15 @@ def matchType(param, arg): elif stmt.getCalls()[-1] == "or": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (or {' '.join(args)}))') + if len(args) == 0: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} false)') + elif len(args) == 1: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {args[0]})') + else: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (or {' '.join(args)}))') elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] @@ -927,8 +945,12 @@ def conv(arg): elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(map(conv, args))}))') + if len(args) < 2: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + else: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(map(conv, args))}))') elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] @@ -1028,7 +1050,10 @@ def conv(arg): elif stmt.getCalls()[-1] == "sum": args = stmt.value[-1].args sortMap[stmt.variable] = theoryType - if len(args) == 1: + if len(args) == 0: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {"0" if theoryType == IntegerType() else "0.0"})') + elif len(args) == 1: output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {conv(args[0])})') else: From 1c16448e0109cb83d5ee539b5a6ab3d6511d43b9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 16:40:19 +0100 Subject: [PATCH 202/233] traceToSmtlib: Rewrite uf with 0 arguments as variables --- scripts/traceToSmtlib.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 7d4ed57d88..18128a2c01 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1390,8 +1390,12 @@ def conv(arg): name = nameMap[arg0] values = [matchType(param, arg) for param, arg in zip(sortMap[arg0].arguments, args)] sortMap[stmt.variable] = sortMap[arg0].value - output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(values)}))') + if args == []: + output.append( + f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + else: + output.append( + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(values)}))') elif stmt.getCalls()[-1] == "declareUF": arg0 = stmt.value[-1].args[0] @@ -1399,8 +1403,9 @@ def conv(arg): args = stmt.value[-1].args[2] sortMap[stmt.variable] = FunctionType(args, arg1) nameMap[stmt.variable] = arg0 if arg0[0] == '|' and arg0[-1] == '|' else f'|{arg0}|' - output.append( - f'(declare-fun {nameMap[stmt.variable]} {sortMap[stmt.variable].toSmtlib()})') + if args != []: + output.append( + f'(declare-fun {nameMap[stmt.variable]} {sortMap[stmt.variable].toSmtlib()})') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') From d97ea3ad7e8b9c3dfe34ce1d8c90cc78a8802f88 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 16:59:13 +0100 Subject: [PATCH 203/233] Trace: Fix log message for prover.getSeqInterpolants --- .../delegate/trace/TraceInterpolatingProverEnvironment.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java index 685db6e37d..d716aab88f 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java @@ -10,6 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; +import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; import java.util.Collection; import java.util.List; @@ -41,8 +42,8 @@ public List getSeqInterpolants(List> par "%s.getSeqInterpolant(ImmutableList.of(%s))", logger.toVariable(this), FluentIterable.from(partitionedFormulas) - .transform( - p -> String.format("ImmutableList" + ".of(%s)", logger.toVariables(p))))); + .transform(p -> String.format("ImmutableList.of(%s)", logger.toVariables(p))) + .join(Joiner.on(", ")))); List seq = delegate.getSeqInterpolants(partitionedFormulas); logger.undoLast(); return mgr.rebuildAll(seq); From 57b127574811107305358be553ffe44e3b6bc2ec Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 17:32:37 +0100 Subject: [PATCH 204/233] Trace: Fix undo points --- .../trace/TraceBasicProverEnvironment.java | 4 ++++ .../delegate/trace/TraceFormulaManager.java | 2 ++ .../java_smt/delegate/trace/TraceLogger.java | 19 +++++++++++++++++-- .../delegate/trace/TraceUFManager.java | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index 6930c3d9e7..98558ce288 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -47,6 +47,7 @@ public void pop() { String.format( "%s.addConstraint(%s)", logger.toVariable(this), logger.toVariable(constraint))); T f = delegate.addConstraint(constraint); + logger.keepLast(); logger.mapVariable(var, f); return f; } @@ -66,6 +67,7 @@ public boolean isUnsat() throws SolverException, InterruptedException { String var = logger.newVariable(); logger.appendDef(var, String.format("%s.isUnsat()", logger.toVariable(this))); boolean unsat = delegate.isUnsat(); + logger.keepLast(); logger.mapVariable(var, unsat); return unsat; } @@ -80,6 +82,7 @@ public boolean isUnsatWithAssumptions(Collection assumptions) "%s.isUnsatWithAssumptions(ImmutableList.of(%s))", logger.toVariable(this), logger.toVariables(assumptions))); boolean unsat = delegate.isUnsatWithAssumptions(assumptions); + logger.keepLast(); logger.mapVariable(var, unsat); return unsat; } @@ -90,6 +93,7 @@ public Model getModel() throws SolverException { String var = logger.newVariable(); logger.appendDef(var, String.format("%s.getModel()", logger.toVariable(this))); Model model = new TraceModel(delegate.getModel(), mgr, logger); + logger.keepLast(); logger.mapVariable(var, model); return model; } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 4846c22cde..e8dcd25425 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -281,6 +281,7 @@ public T makeVariable(FormulaType formulaType, String nam if (logger.isTracked(f)) { logger.undoLast(); } else { + logger.keepLast(); logger.mapVariable(var, f); } return f; @@ -1083,6 +1084,7 @@ public BooleanFormula parse(String s) throws IllegalArgumentException { String var = logger.newVariable(); logger.appendDef(var, String.format("mgr.parse(%s)", logger.printString(s))); BooleanFormula f = delegate.parse(s); + logger.keepLast(); logger.undoLast(); return rebuild(f); } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 6b606940db..0bab23a0a4 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -37,6 +37,10 @@ class TraceLogger { private final Map valueMap = new HashMap<>(); private final RandomAccessFile output; + /** + * Contains lines that were recently added to the log. Entries on this list are preliminary and + * can still be removed from the final trace + */ private final Deque lastLines = new ArrayDeque<>(); TraceLogger(TraceFormulaManager pMgr, File pFile) { @@ -106,8 +110,10 @@ public void appendStmt(String pStmt) { } } + /** Undo the last line and remove it from the trace. */ public void undoLast() { - Preconditions.checkArgument(!lastLines.isEmpty(), "Cannot undo last trace"); + Preconditions.checkArgument( + !lastLines.isEmpty(), "Cannot undo last trace, no undo points found"); try { var start = lastLines.pop(); output.seek(start); @@ -129,6 +135,13 @@ public void undoLast() { } } + /** Remove an undo point and permanently commit the line to the trace. */ + public void keepLast() { + Preconditions.checkArgument( + !lastLines.isEmpty(), "Cannot remove undo point, list is already empty"); + lastLines.pop(); + } + /** Log an API call with return value. */ public R logDef(String prefix, String method, Callable closure) { String var = newVariable(); @@ -139,8 +152,8 @@ public R logDef(String prefix, String method, Callable cl undoLast(); return f; } else { + keepLast(); mapVariable(var, f); - lastLines.pop(); return mgr.rebuild(f); } } catch (Exception e) { @@ -159,6 +172,7 @@ public R logDefKeep(String prefix, String method, Callable closure) { try { appendDef(var, prefix + "." + method); R f = closure.call(); + keepLast(); mapVariable(var, f); return f; } catch (Exception e) { @@ -194,6 +208,7 @@ public void logStmt(String prefix, String method, CheckedRunnable closure) { try { appendStmt(prefix + "." + method); closure.run(); + keepLast(); } catch (Exception e) { Throwables.throwIfUnchecked(e); throw new RuntimeException(e); diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java index dc996afd81..8e295b87eb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceUFManager.java @@ -48,6 +48,7 @@ public FunctionDeclaration declareUF( if (logger.isTracked(f)) { logger.undoLast(); } else { + logger.keepLast(); logger.mapVariable(var, f); } return f; From 0828f4ad26dad514c8c0f0cc89b68ede67603868 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 18:10:43 +0100 Subject: [PATCH 205/233] traceToSmtlib: Print a better error message --- scripts/traceToSmtlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 18128a2c01..1acab549d6 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -534,7 +534,7 @@ def parseNumber(repr): if value is not None: return value else: - raise Exception(f'Could not parse "{repr}"') + raise Exception(f'Could not parse "{repr}" as a number') def toIntSmtlib(value): @@ -1368,7 +1368,7 @@ def conv(arg): raise Exception(f'Unsupported call: {stmt.getCalls()}') elif stmt.getCalls()[:-1] == ["mgr", "getQuantifiedFormulaManager"]: - # TODOThro + # TODO raise Exception(f'Quantifiers are not supported yet') elif stmt.getCalls()[:-1] == ["mgr", "getStringFormulaManager"]: From fdc5151dfdfff8126947e47d2d3bc23a2471e39a Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Thu, 11 Dec 2025 18:42:44 +0100 Subject: [PATCH 206/233] traceToSmtlib: Skip illegal uf symbols in the trace JavaSMT throws an exception only after these declarations were already added to the trace. We simply ignore these symbols as they are never used --- scripts/traceToSmtlib.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 1acab549d6..fbaeecd82c 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -742,6 +742,8 @@ def matchType(param, arg): elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + if '|' in arg2: + continue sortMap[stmt.variable] = arg1 output.append(f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') @@ -896,6 +898,8 @@ def matchType(param, arg): elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + if '|' in arg1: + continue sortMap[stmt.variable] = BooleanType() output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') @@ -1008,6 +1012,8 @@ def conv(arg): elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + if '|' in arg1: + continue sortMap[stmt.variable] = theoryType output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') @@ -1259,6 +1265,8 @@ def conv(arg): elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name arg2 = stmt.value[-1].args[1] + if '|' in arg1: + continue sortMap[stmt.variable] = arg2 output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') @@ -1401,8 +1409,10 @@ def conv(arg): arg0 = stmt.value[-1].args[0] arg1 = stmt.value[-1].args[1] args = stmt.value[-1].args[2] + if '|' in arg0: + continue sortMap[stmt.variable] = FunctionType(args, arg1) - nameMap[stmt.variable] = arg0 if arg0[0] == '|' and arg0[-1] == '|' else f'|{arg0}|' + nameMap[stmt.variable] = f'|{arg0}|' if args != []: output.append( f'(declare-fun {nameMap[stmt.variable]} {sortMap[stmt.variable].toSmtlib()})') @@ -1433,6 +1443,8 @@ def conv(arg): elif stmt.getCalls() == ["mgr", "makeVariable"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + if '|' in arg2: + continue sortMap[stmt.variable] = arg1 output.append( f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') From 309b589a58f82c01469e5537603b0b51e31ecdb6 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 12:23:28 +0100 Subject: [PATCH 207/233] traceToSmtlib: Fix parsing test for sorts --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index fbaeecd82c..4dcb1a8c6e 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -299,7 +299,7 @@ def litArrayType(): def test_sort(): - assert litType.parse("FormulaType.BooleanType") == IntegerType() + assert litType.parse("FormulaType.BooleanType") == BooleanType() assert litType.parse("FormulaType.IntegerType") == IntegerType() assert litType.parse("FormulaType.getBitvectorTypeWithSize(8)") == BitvectorType(8) assert (litType.parse("FormulaType.getArrayType(FormulaType.IntegerType, FormulaType.IntegerType)") From 7318024c1fafd94b054f8b93365ef40ce976af8f Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 14:23:43 +0100 Subject: [PATCH 208/233] Trace: Add a script to help with debugging The script will translate all traces from the JavaSMT tests and then passes them to the solver How to use: ant tests cd scripts ./tracingTest.sh cvc5 --incremental --fp-exp --- .gitignore | 1 + scripts/tracingTest.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100755 scripts/tracingTest.sh diff --git a/.gitignore b/.gitignore index 59f442f20d..b8294fa20b 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ solvers_maven_conf/*.asc /Javadoc-z3 /gh-pages /traces +/scripts/solver.log .idea/ diff --git a/scripts/tracingTest.sh b/scripts/tracingTest.sh new file mode 100755 index 0000000000..c2a725a863 --- /dev/null +++ b/scripts/tracingTest.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# This file is part of JavaSMT, +# an API wrapper for a collection of SMT solvers: +# https://github.com/sosy-lab/java-smt +# +# SPDX-FileCopyrightText: 2025 Dirk Beyer +# +# SPDX-License-Identifier: Apache-2.0 + +set -e + +if [[ $# -eq 0 ]]; then + echo "No command line for the solver" + echo "Usage: ./tracingTest.sh " + echo "Where is the full command for the solver, including any options that need to be passed" >&2 + exit 1 +fi + +cmd=$* + +echo "Initializing venv" +python3 -m venv .venv +source .venv/bin/activate + +pip install -r requirements.txt + +echo -e "\nConverting JavaTraces to Smtlib" +find ../traces -name *.java -exec ./traceToSmtlib.py --save {} ';' + +echo -e "\nRunning the solver on the generated Smtlib files" +find ../traces -name *.smt2 -exec echo "path: {}" ';' -exec timeout 20s $* {} ';' > solver.log + +grep -E "error|path" solver.log + +echo -e "\n(See solver.log for the entire solver output)" + +deactivate From 89393c5acba3abd678800bf4784c2a83589b15cb Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 15:00:16 +0100 Subject: [PATCH 209/233] Trace: Fix a mistake in 57b127574811107305358be553ffe44e3b6bc2ec --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index e8dcd25425..f2898c84eb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -1084,7 +1084,6 @@ public BooleanFormula parse(String s) throws IllegalArgumentException { String var = logger.newVariable(); logger.appendDef(var, String.format("mgr.parse(%s)", logger.printString(s))); BooleanFormula f = delegate.parse(s); - logger.keepLast(); logger.undoLast(); return rebuild(f); } From 537a6b20df900957826de1ab8358c0ed3e1b8852 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 15:13:06 +0100 Subject: [PATCH 210/233] traceToSmtlib: Use to_bv for MathSAT Since Smtlib 2.7 the standard says the name should be int_to_bv, but this is not recognized by the MathSAT parser --- scripts/traceToSmtlib.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 4dcb1a8c6e..3cfa299540 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -622,6 +622,7 @@ def translate(prog: List[Definition]): "(set-option :interactive-mode true)", "(set-option :produce-models true)", "(set-option :global-declarations true)"] + solver = prog[3].value[1].args[3] # Get solver name from createSolverContext call in the preamble for stmt in prog[5:]: def matchType(param, arg): "Convert argument to match the given type" @@ -736,8 +737,9 @@ def matchType(param, arg): f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') else: # Convert integer formula to bv formula + operation = "to_bv" if solver == Solvers.MATHSAT5 else "int_to_bv" output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ int_to_bv {arg1}) {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {arg2}))') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] From ddaca58a663eb2bf01c0b4393feb298b9881cd0c Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 15:16:45 +0100 Subject: [PATCH 211/233] traceToSmtlib: Make line numbers in parsing errors start at 1 --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 3cfa299540..3d49f3824a 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1487,7 +1487,7 @@ def conv(arg): # Translate the trace try: - output = translate(flattenProvers(program.parse(open(args.file).read()))) + output = translate(flattenProvers(program.parse("\n" + open(args.file).read()))) except Exception as exception: print(f'In {args.file}: {exception}') exit(-1) From ed9828fe4a708c675b0b937e2c910d29b3054b59 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 15:42:41 +0100 Subject: [PATCH 212/233] Trace: Move makeNumber implementations to NumeralFormulaManager --- .../trace/TraceIntegerFormulaManager.java | 34 ------------------- .../trace/TraceNumeralFormulaManager.java | 26 ++++++++++++++ .../trace/TraceRationalFormulaManager.java | 28 --------------- 3 files changed, 26 insertions(+), 62 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java index 6d512f7dd9..f7cf7b93bb 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceIntegerFormulaManager.java @@ -10,9 +10,7 @@ package org.sosy_lab.java_smt.delegate.trace; -import java.math.BigDecimal; import java.math.BigInteger; -import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.IntegerFormulaManager; import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula; @@ -29,38 +27,6 @@ public class TraceIntegerFormulaManager logger = pLogger; } - @Override - public IntegerFormula makeNumber(double number) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(%s)", number), - () -> delegate.makeNumber(number)); - } - - @Override - public IntegerFormula makeNumber(BigDecimal number) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(new BigDecimal(\"%s\"))", number), - () -> delegate.makeNumber(number)); - } - - @Override - public IntegerFormula makeNumber(String pI) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(\"%s\")", pI), - () -> delegate.makeNumber(pI)); - } - - @Override - public IntegerFormula makeNumber(Rational pRational) { - return logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(Rational.of(\"%s\"))", pRational), - () -> delegate.makeNumber(pRational)); - } - @Override public BooleanFormula modularCongruence( IntegerFormula number1, IntegerFormula number2, BigInteger n) { diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index 3b44cb7c0a..6b5ca12644 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -10,8 +10,10 @@ package org.sosy_lab.java_smt.delegate.trace; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; +import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.NumeralFormula; @@ -51,6 +53,30 @@ public ResultFormulaType makeNumber(BigInteger number) { () -> delegate.makeNumber(number)); } + @Override + public ResultFormulaType makeNumber(double number) { + return logger.logDef( + getPrefix(), String.format("makeNumber(%s)", number), () -> delegate.makeNumber(number)); + } + + @Override + public ResultFormulaType makeNumber(BigDecimal number) { + return makeNumber(Rational.ofBigDecimal(number)); + } + + @Override + public ResultFormulaType makeNumber(String pI) { + return makeNumber(new BigDecimal(pI)); + } + + @Override + public ResultFormulaType makeNumber(Rational pRational) { + return logger.logDef( + getPrefix(), + String.format("makeNumber(Rational.of(\"%s\"))", pRational), + () -> delegate.makeNumber(pRational)); + } + @Override public ResultFormulaType makeVariable(String pVar) { return logger.logDef( diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java index 1d72dd9ba4..5883f2fb45 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceRationalFormulaManager.java @@ -10,8 +10,6 @@ package org.sosy_lab.java_smt.delegate.trace; -import java.math.BigDecimal; -import org.sosy_lab.common.rationals.Rational; import org.sosy_lab.java_smt.api.NumeralFormula; import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula; import org.sosy_lab.java_smt.api.RationalFormulaManager; @@ -27,30 +25,4 @@ public class TraceRationalFormulaManager delegate = pDelegate; logger = pLogger; } - - @Override - public RationalFormula makeNumber(double number) { - return logger.logDef( - "mgr.getRationalFormulaManager()", - String.format("makeNumber(%s)", number), - () -> delegate.makeNumber(number)); - } - - @Override - public RationalFormula makeNumber(BigDecimal number) { - return makeNumber(Rational.ofBigDecimal(number)); - } - - @Override - public RationalFormula makeNumber(String pI) { - return makeNumber(new BigDecimal(pI)); - } - - @Override - public RationalFormula makeNumber(Rational pRational) { - return logger.logDef( - "mgr.getRationalFormulaManager()", - String.format("makeNumber(Rational.of(\"%s\"))", pRational), - () -> delegate.makeNumber(pRational)); - } } From 90259b0386ab416a45739778dfbfc016d787cfb4 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 15:47:03 +0100 Subject: [PATCH 213/233] Trace: Fix printing of rationals in the visitor --- .../sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index f2898c84eb..26b9f0d0da 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -187,7 +187,7 @@ public Formula visitConstant(Formula f, Object value) { var g = logger.logDef( "mgr.getRationalFormulaManager()", - String.format("makeNumber(%s)", value), + String.format("makeNumber(Rational.of(\"%s\"))", value), () -> delegate.getRationalFormulaManager().makeNumber((Rational) value)); Preconditions.checkArgument(g.equals(f)); } else if (f instanceof FloatingPointRoundingModeFormula From 865bf1c2217b20784a6026502556c4ad1eb35b60 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Fri, 12 Dec 2025 16:18:27 +0100 Subject: [PATCH 214/233] traceToSmtlib: Fix printing of bv constants that are converted from integer --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 3d49f3824a..33db145602 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -739,7 +739,7 @@ def matchType(param, arg): # Convert integer formula to bv formula operation = "to_bv" if solver == Solvers.MATHSAT5 else "int_to_bv" output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {arg2}))') + f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {toIntSmtlib(arg2)}))') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] From a188addc3fdc86dcf5d45eb2c1ec5528d63b61d4 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 13 Dec 2025 13:28:25 +0100 Subject: [PATCH 215/233] Trace: Avoid rewrites when logging numeral.makenumber --- .../delegate/trace/TraceNumeralFormulaManager.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java index 6b5ca12644..7f85da6839 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceNumeralFormulaManager.java @@ -61,12 +61,16 @@ public ResultFormulaType makeNumber(double number) { @Override public ResultFormulaType makeNumber(BigDecimal number) { - return makeNumber(Rational.ofBigDecimal(number)); + return logger.logDef( + getPrefix(), + String.format("makeNumber(new BigInteger(\"%s\"))", number), + () -> delegate.makeNumber(number)); } @Override public ResultFormulaType makeNumber(String pI) { - return makeNumber(new BigDecimal(pI)); + return logger.logDef( + getPrefix(), String.format("makeNumber(\"%s\")", pI), () -> delegate.makeNumber(pI)); } @Override From 81f578aad3b8d5670222afb3bc54f37c9530c1d2 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 13 Dec 2025 22:29:27 +0100 Subject: [PATCH 216/233] Trace: Simplify tracing code --- .../trace/TraceBasicProverEnvironment.java | 104 ++++++++---------- .../trace/TraceBooleanFormulaManager.java | 24 ++-- .../TraceFloatingPointFormulaManager.java | 17 +-- .../delegate/trace/TraceFormulaManager.java | 90 ++++----------- .../TraceInterpolatingProverEnvironment.java | 29 +++-- .../java_smt/delegate/trace/TraceModel.java | 9 +- .../delegate/trace/TraceSolverContext.java | 2 +- 7 files changed, 105 insertions(+), 170 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java index 98558ce288..71983d6ce3 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBasicProverEnvironment.java @@ -41,15 +41,10 @@ public void pop() { @Override public @Nullable T addConstraint(BooleanFormula constraint) throws InterruptedException { - String var = logger.newVariable(); - logger.appendDef( - var, - String.format( - "%s.addConstraint(%s)", logger.toVariable(this), logger.toVariable(constraint))); - T f = delegate.addConstraint(constraint); - logger.keepLast(); - logger.mapVariable(var, f); - return f; + return logger.logDefKeep( + logger.toVariable(this), + String.format("addConstraint(%s)", logger.toVariable(constraint)), + () -> delegate.addConstraint(constraint)); } @Override @@ -64,58 +59,45 @@ public int size() { @Override public boolean isUnsat() throws SolverException, InterruptedException { - String var = logger.newVariable(); - logger.appendDef(var, String.format("%s.isUnsat()", logger.toVariable(this))); - boolean unsat = delegate.isUnsat(); - logger.keepLast(); - logger.mapVariable(var, unsat); - return unsat; + return logger.logDefKeep(logger.toVariable(this), "isUnsat()", delegate::isUnsat); } @Override public boolean isUnsatWithAssumptions(Collection assumptions) throws SolverException, InterruptedException { - String var = logger.newVariable(); - logger.appendDef( - var, + return logger.logDefKeep( + logger.toVariable(this), String.format( - "%s.isUnsatWithAssumptions(ImmutableList.of(%s))", - logger.toVariable(this), logger.toVariables(assumptions))); - boolean unsat = delegate.isUnsatWithAssumptions(assumptions); - logger.keepLast(); - logger.mapVariable(var, unsat); - return unsat; + "isUnsatWithAssumptions(ImmutableList.of(%s))", logger.toVariables(assumptions)), + () -> delegate.isUnsatWithAssumptions(assumptions)); } @SuppressWarnings("resource") @Override public Model getModel() throws SolverException { - String var = logger.newVariable(); - logger.appendDef(var, String.format("%s.getModel()", logger.toVariable(this))); - Model model = new TraceModel(delegate.getModel(), mgr, logger); - logger.keepLast(); - logger.mapVariable(var, model); - return model; + return logger.logDefKeep( + logger.toVariable(this), + "getModel()", + () -> new TraceModel(delegate.getModel(), mgr, logger)); } @Override public List getUnsatCore() { - logger.appendStmt(String.format("%s.getUnsatCore()", logger.toVariable(this))); - List core = delegate.getUnsatCore(); - logger.undoLast(); - return mgr.rebuildAll(core); + return mgr.rebuildAll( + logger.logDefDiscard(logger.toVariable(this), "getUnsatCore()", delegate::getUnsatCore)); } @Override public Optional> unsatCoreOverAssumptions( Collection assumptions) throws SolverException, InterruptedException { - logger.appendStmt( - String.format( - "%s.getUnsatCoreOverAssumptions(ImmutableList.of(%s))", - logger.toVariable(this), logger.toVariables(assumptions))); - Optional> maybeCore = delegate.unsatCoreOverAssumptions(assumptions); - logger.undoLast(); - return maybeCore.map(mgr::rebuildAll); + return logger + .logDefKeep( + logger.toVariable(this), + String.format( + "getUnsatCoreOverAssumptions(ImmutableList.of(%s))", + logger.toVariables(assumptions)), + () -> delegate.unsatCoreOverAssumptions(assumptions)) + .map(mgr::rebuildAll); } @Override @@ -126,22 +108,28 @@ public void close() { @Override public R allSat(AllSatCallback callback, List important) throws InterruptedException, SolverException { - // We don't log the call to allSat as it is hard to remove it later on. This is fine as long - // as the crash is not (immediately) caused by this call - // TODO Redesign the logger and add the call to the log - return delegate.allSat( - new AllSatCallback() { - @Override - public void apply(List model) { - var newModel = mgr.rebuildAll(model); - callback.apply(newModel); - } - - @Override - public R getResult() throws InterruptedException { - return callback.getResult(); - } - }, - important); + return logger.logDefDiscard( + logger.toVariable(this), + String.format( + "delegate.allSat(new AllSatCallback<>() {" + + " public void apply(List model) {}" + + " public R getResult() { throw new UnsupportedOperationException(); }" + + "}, ImmutableList.of(%s));", + logger.toVariables(important)), + () -> + delegate.allSat( + new AllSatCallback() { + @Override + public void apply(List model) { + var newModel = mgr.rebuildAll(model); + callback.apply(newModel); + } + + @Override + public R getResult() throws InterruptedException { + return callback.getResult(); + } + }, + important)); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java index 2d30db4927..5d31d2e5c7 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceBooleanFormulaManager.java @@ -189,23 +189,19 @@ public BooleanFormula transformRecursively( @Override public Set toConjunctionArgs(BooleanFormula f, boolean flatten) { - logger.appendStmt( - String.format( - "mgr.getBooleanFormulaManager().toConjunctionArgs(%s, %s)", - logger.toVariable(f), flatten)); - Set set = delegate.toConjunctionArgs(f, flatten); - logger.undoLast(); - return mgr.rebuildAll(set); + return mgr.rebuildAll( + logger.logDefDiscard( + "mgr.getBooleanFormulaManager()", + String.format("toConjunctionArgs(%s, %s)", logger.toVariable(f), flatten), + () -> delegate.toConjunctionArgs(f, flatten))); } @Override public Set toDisjunctionArgs(BooleanFormula f, boolean flatten) { - logger.appendStmt( - String.format( - "mgr.getBooleanFormulaManager().toDisjunctionArgs(%s, %s)", - logger.toVariable(f), flatten)); - Set set = delegate.toDisjunctionArgs(f, flatten); - logger.undoLast(); - return mgr.rebuildAll(set); + return mgr.rebuildAll( + logger.logDefDiscard( + "mgr.getBooleanFormulaManager()", + String.format("toDisjunctionArgs(%s, %s)", logger.toVariable(f), flatten), + () -> delegate.toDisjunctionArgs(f, flatten))); } } diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java index 4fd1d5e114..1c65a2cded 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFloatingPointFormulaManager.java @@ -37,7 +37,11 @@ private String printRoundingMode(FloatingPointRoundingMode pRoundingMode) { return "FloatingPointRoundingMode." + pRoundingMode.name(); } - private String toString(double number) { + private String printSign(Sign pSign) { + return "FloatingPointNumber.Sign." + pSign.name(); + } + + private String printDouble(double number) { if (Double.isNaN(number)) { return "Double.NaN"; } else if (Double.isInfinite(number)) { @@ -62,7 +66,10 @@ public FloatingPointRoundingModeFormula makeRoundingMode( @Override public FloatingPointRoundingMode fromRoundingModeFormula( FloatingPointRoundingModeFormula pRoundingModeFormula) { - return delegate.fromRoundingModeFormula(pRoundingModeFormula); + return logger.logDefDiscard( + "mgr.getFloatingPointFormulaManager()", + String.format("fromRoundingModeFormula(%s)", logger.toVariable(pRoundingModeFormula)), + () -> delegate.fromRoundingModeFormula(pRoundingModeFormula)); } @Override @@ -77,7 +84,7 @@ public FloatingPointFormula makeNumber( "mgr.getFloatingPointFormulaManager()", String.format( "makeNumber(%s, %s, %s)", - toString(n), + printDouble(n), logger.printFormulaType(type), printRoundingMode(pFloatingPointRoundingMode)), () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); @@ -131,10 +138,6 @@ public FloatingPointFormula makeNumber( () -> delegate.makeNumber(n, type, pFloatingPointRoundingMode)); } - private String printSign(Sign pSign) { - return "FloatingPointNumber.Sign." + pSign.name(); - } - @Override public FloatingPointFormula makeNumber( BigInteger exponent, BigInteger mantissa, Sign sign, FloatingPointType type) { diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 26b9f0d0da..00f2932032 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -151,71 +151,32 @@ public Formula visitFreeVariable(Formula f, String name) { @Override public Formula visitConstant(Formula f, Object value) { if (!logger.isTracked(f)) { + Formula g; if (f instanceof BooleanFormula && value instanceof Boolean) { - var g = - logger.logDef( - "mgr.getBooleanFormulaManager()", - String.format("makeBoolean(%s)", value), - () -> delegate.getBooleanFormulaManager().makeBoolean((Boolean) value)); - Preconditions.checkArgument(g.equals(f)); + g = getBooleanFormulaManager().makeBoolean((Boolean) value); } else if (f instanceof BitvectorFormula && value instanceof BigInteger) { var bvSize = delegate.getBitvectorFormulaManager().getLength((BitvectorFormula) f); - var g = - logger.logDef( - "mgr.getBitvectorFormulaManager()", - String.format("makeBitvector(%s, %s)", bvSize, value), - () -> - delegate - .getBitvectorFormulaManager() - .makeBitvector(bvSize, (BigInteger) value)); - Preconditions.checkArgument(g.equals(f)); + g = getBitvectorFormulaManager().makeBitvector(bvSize, (BigInteger) value); } else if (f instanceof IntegerFormula && value instanceof BigInteger) { - var g = - logger.logDef( - "mgr.getIntegerFormulaManager()", - String.format("makeNumber(%s)", value), - () -> delegate.getIntegerFormulaManager().makeNumber((BigInteger) value)); - Preconditions.checkArgument(g.equals(f)); + g = getIntegerFormulaManager().makeNumber((BigInteger) value); } else if (f instanceof RationalFormula && value instanceof BigInteger) { - var g = - logger.logDef( - "mgr.getRationalFormulaManager()", - String.format("makeNumber(%s)", value), - () -> delegate.getRationalFormulaManager().makeNumber((BigInteger) value)); + g = getRationalFormulaManager().makeNumber((BigInteger) value); Preconditions.checkArgument(g.equals(f)); } else if (f instanceof RationalFormula && value instanceof Rational) { - var g = - logger.logDef( - "mgr.getRationalFormulaManager()", - String.format("makeNumber(Rational.of(\"%s\"))", value), - () -> delegate.getRationalFormulaManager().makeNumber((Rational) value)); + g = getRationalFormulaManager().makeNumber((Rational) value); Preconditions.checkArgument(g.equals(f)); } else if (f instanceof FloatingPointRoundingModeFormula && value instanceof FloatingPointRoundingMode) { - @SuppressWarnings("unused") - var g = - logger.logDef( - "mgr.getFloatingPointFormulaManager()", - String.format( - "makeRoundingMode(%s)", - "FloatingPointRoundingMode." + ((FloatingPointRoundingMode) value).name()), - () -> - delegate - .getFloatingPointFormulaManager() - .makeRoundingMode((FloatingPointRoundingMode) value)); + g = getFloatingPointFormulaManager().makeRoundingMode((FloatingPointRoundingMode) value); } else if (f instanceof StringFormula && value instanceof String) { - var g = - logger.logDef( - "mgr.getStringFormulaManager()", - String.format("makeString(%s)", logger.printString((String) value)), - () -> delegate.getStringFormulaManager().makeString((String) value)); - Preconditions.checkArgument(g.equals(f)); + g = getStringFormulaManager().makeString((String) value); } else { throw new IllegalArgumentException( String.format( "Unsupported value: Formula=%s, Value=%s", delegate.getFormulaType(f), value.getClass().getName())); } + Preconditions.checkArgument(g.equals(f)); } return f; } @@ -271,20 +232,11 @@ public Set rebuildAll(Set formulas) { @Override public T makeVariable(FormulaType formulaType, String name) { - String var = logger.newVariable(); - logger.appendDef( - var, + return logger.logDef( + "mgr", String.format( - "mgr.makeVariable(%s, %s)", - logger.printFormulaType(formulaType), logger.printString(name))); - T f = delegate.makeVariable(formulaType, name); - if (logger.isTracked(f)) { - logger.undoLast(); - } else { - logger.keepLast(); - logger.mapVariable(var, f); - } - return f; + "makeVariable(%s, %s)", logger.printFormulaType(formulaType), logger.printString(name)), + () -> delegate.makeVariable(formulaType, name)); } private int getArity(FunctionDeclaration pDeclaration) { @@ -1081,19 +1033,17 @@ public FormulaType getFormulaType(T formula) { @Override public BooleanFormula parse(String s) throws IllegalArgumentException { - String var = logger.newVariable(); - logger.appendDef(var, String.format("mgr.parse(%s)", logger.printString(s))); - BooleanFormula f = delegate.parse(s); - logger.undoLast(); - return rebuild(f); + return rebuild( + logger.logDefDiscard( + "mgr", String.format("parse(%s)", logger.printString(s)), () -> delegate.parse(s))); } @Override public Appender dumpFormula(BooleanFormula pT) { - logger.appendStmt(String.format("mgr.dumpFormula(%s)", logger.toVariable(pT))); - Appender str = delegate.dumpFormula(pT); - logger.undoLast(); - return str; + return logger.logDefDiscard( + "mgr", + String.format("dumpFormula(%s)", logger.toVariable(pT)), + () -> delegate.dumpFormula(pT)); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java index d716aab88f..f4d0694c70 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java @@ -37,28 +37,25 @@ public class TraceInterpolatingProverEnvironment extends TraceBasicProverEnvi @Override public List getSeqInterpolants(List> partitionedFormulas) throws SolverException, InterruptedException { - logger.appendStmt( - String.format( - "%s.getSeqInterpolant(ImmutableList.of(%s))", + return mgr.rebuildAll( + logger.logDefDiscard( logger.toVariable(this), - FluentIterable.from(partitionedFormulas) - .transform(p -> String.format("ImmutableList.of(%s)", logger.toVariables(p))) - .join(Joiner.on(", ")))); - List seq = delegate.getSeqInterpolants(partitionedFormulas); - logger.undoLast(); - return mgr.rebuildAll(seq); + String.format( + "getSeqInterpolant(ImmutableList.of(%s))", + FluentIterable.from(partitionedFormulas) + .transform(p -> String.format("ImmutableList.of(%s)", logger.toVariables(p))) + .join(Joiner.on(", "))), + () -> delegate.getSeqInterpolants(partitionedFormulas))); } @Override public BooleanFormula getInterpolant(Collection formulasOfA) throws SolverException, InterruptedException { - logger.appendStmt( - String.format( - "%s.getInterpolant(ImmutableList.of(%s))", - logger.toVariable(this), logger.toVariables(formulasOfA))); - BooleanFormula itp = delegate.getInterpolant(formulasOfA); - logger.undoLast(); - return mgr.rebuild(itp); + return mgr.rebuild( + logger.logDefDiscard( + logger.toVariable(this), + String.format("getInterpolant(ImmutableList.of(%s))", logger.toVariables(formulasOfA)), + () -> delegate.getInterpolant(formulasOfA))); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java index 69a5d19bdb..f373625958 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceModel.java @@ -64,10 +64,11 @@ public ImmutableList asList() { @Override public @Nullable T eval(T formula) { - return logger.logDefDiscard( - logger.toVariable(this), - String.format("eval(%s)", logger.toVariable(formula)), - () -> delegate.eval(formula)); + return mgr.rebuild( + logger.logDefDiscard( + logger.toVariable(this), + String.format("eval(%s)", logger.toVariable(formula)), + () -> delegate.eval(formula))); } @Override diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java index 2e8cb618fb..c86c614088 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceSolverContext.java @@ -143,7 +143,7 @@ public OptimizationProverEnvironment newOptimizationProverEnvironment(ProverOpti @Override public String getVersion() { - return delegate.getVersion(); + return logger.logDefDiscard("context", "getVersion()", delegate::getVersion); } @Override From 182cdf36922981e92c681b395796a2acc31a9829 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sat, 13 Dec 2025 22:31:31 +0100 Subject: [PATCH 217/233] Trace: Use sneaky throw to work around checked exceptions --- .../java_smt/delegate/trace/TraceLogger.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java index 0bab23a0a4..ce6a3d3f42 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceLogger.java @@ -12,7 +12,6 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; -import com.google.common.base.Throwables; import com.google.common.collect.FluentIterable; import java.io.File; import java.io.IOException; @@ -142,6 +141,11 @@ public void keepLast() { lastLines.pop(); } + @SuppressWarnings("unchecked") + public static void sneakyThrow(Throwable e) throws E { + throw (E) e; + } + /** Log an API call with return value. */ public R logDef(String prefix, String method, Callable closure) { String var = newVariable(); @@ -157,7 +161,7 @@ public R logDef(String prefix, String method, Callable cl return mgr.rebuild(f); } } catch (Exception e) { - Throwables.throwIfUnchecked(e); + sneakyThrow(e); throw new RuntimeException(e); } } @@ -176,7 +180,7 @@ public R logDefKeep(String prefix, String method, Callable closure) { mapVariable(var, f); return f; } catch (Exception e) { - Throwables.throwIfUnchecked(e); + sneakyThrow(e); throw new RuntimeException(e); } } @@ -193,7 +197,7 @@ public R logDefDiscard(String prefix, String method, Callable closure) { undoLast(); return f; } catch (Exception e) { - Throwables.throwIfUnchecked(e); + sneakyThrow(e); throw new RuntimeException(e); } } @@ -210,8 +214,7 @@ public void logStmt(String prefix, String method, CheckedRunnable closure) { closure.run(); keepLast(); } catch (Exception e) { - Throwables.throwIfUnchecked(e); - throw new RuntimeException(e); + sneakyThrow(e); } } @@ -225,8 +228,7 @@ public void logStmtDiscard(String prefix, String method, CheckedRunnable closure closure.run(); undoLast(); } catch (Exception e) { - Throwables.throwIfUnchecked(e); - throw new RuntimeException(e); + sneakyThrow(e); } } From b51f502b4f76b320ead0e0fecfcb503482304057 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 10:52:14 +0100 Subject: [PATCH 218/233] traceToSmtlib: Move imports --- scripts/traceToSmtlib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 33db145602..bbc14806e1 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import argparse -import math + # This file is part of JavaSMT, # an API wrapper for a collection of SMT solvers: # https://github.com/sosy-lab/java-smt @@ -9,8 +8,9 @@ # # SPDX-License-Identifier: Apache-2.0 +import argparse +import math import sys - from dataclasses import dataclass from enum import Enum from fractions import Fraction From 27d6145e97000ceb1b84466d1567cd68bcaea1c5 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 11:59:26 +0100 Subject: [PATCH 219/233] Trace: Enable preconditions while rebuilding --- .../delegate/trace/TraceFormulaManager.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 00f2932032..45f00dd772 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -143,7 +143,7 @@ public Formula visitFreeVariable(Formula f, String name) { "makeVariable(%s, %s)", logger.printFormulaType(delegate.getFormulaType(f)), logger.printString(name)), () -> delegate.makeVariable(delegate.getFormulaType(f), name)); - Preconditions.checkArgument(g.equals(f)); + Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); } return f; } @@ -161,10 +161,8 @@ public Formula visitConstant(Formula f, Object value) { g = getIntegerFormulaManager().makeNumber((BigInteger) value); } else if (f instanceof RationalFormula && value instanceof BigInteger) { g = getRationalFormulaManager().makeNumber((BigInteger) value); - Preconditions.checkArgument(g.equals(f)); } else if (f instanceof RationalFormula && value instanceof Rational) { g = getRationalFormulaManager().makeNumber((Rational) value); - Preconditions.checkArgument(g.equals(f)); } else if (f instanceof FloatingPointRoundingModeFormula && value instanceof FloatingPointRoundingMode) { g = getFloatingPointFormulaManager().makeRoundingMode((FloatingPointRoundingMode) value); @@ -186,11 +184,8 @@ public Formula visitConstant(Formula f, Object value) { public Formula visitFunction( Formula f, List args, FunctionDeclaration functionDeclaration) { if (!logger.isTracked(f)) { - // Formula g = - //noinspection ResultOfMethodCallIgnored - makeApplication(functionDeclaration, args); - // precondition is not helpful, as some solvers restructure their formulas. - // Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); + Formula g = makeApplication(functionDeclaration, args); + Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); } return f; } @@ -203,16 +198,13 @@ public BooleanFormula visitQuantifier( List boundVariables, BooleanFormula body) { if (!logger.isTracked(f)) { - // final Formula g; + final Formula g; if (quantifier == Quantifier.EXISTS) { - // g = - getQuantifiedFormulaManager().exists(boundVariables, body); + g = getQuantifiedFormulaManager().exists(boundVariables, body); } else { - // g = - getQuantifiedFormulaManager().forall(boundVariables, body); + g = getQuantifiedFormulaManager().forall(boundVariables, body); } - // precondition is not helpful, as some solvers restructure their formulas. - // Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); + Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); } return f; } From 418605f10561c9e81cbb4ce572cdba23e20efd54 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 13:33:21 +0100 Subject: [PATCH 220/233] Trace: Fix quantifier weight for Z3 --- .../java_smt/solvers/z3/Z3QuantifiedFormulaManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/solvers/z3/Z3QuantifiedFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/z3/Z3QuantifiedFormulaManager.java index 424f6bef9d..f6a9b043c3 100644 --- a/src/org/sosy_lab/java_smt/solvers/z3/Z3QuantifiedFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/z3/Z3QuantifiedFormulaManager.java @@ -38,11 +38,11 @@ public Long mkQuantifier(Quantifier q, List pVariables, Long pBody) { return Native.mkQuantifierConst( z3context, q == Quantifier.FORALL, - 0, + 1, pVariables.size(), Longs.toArray(pVariables), 0, - new long[0], + null, pBody); } From 1754d220b0d88dbc7c4e0b9fd3c17e5031176e90 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 13:50:35 +0100 Subject: [PATCH 221/233] Trace: Visit bound variables while rebuilding Needed if the variable does not occur in the body of the quanified formula --- .../java_smt/delegate/trace/TraceFormulaManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index 45f00dd772..b954d295f8 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -198,11 +198,12 @@ public BooleanFormula visitQuantifier( List boundVariables, BooleanFormula body) { if (!logger.isTracked(f)) { + var bound = rebuildAll(boundVariables); final Formula g; if (quantifier == Quantifier.EXISTS) { - g = getQuantifiedFormulaManager().exists(boundVariables, body); + g = getQuantifiedFormulaManager().exists(bound, body); } else { - g = getQuantifiedFormulaManager().forall(boundVariables, body); + g = getQuantifiedFormulaManager().forall(bound, body); } Preconditions.checkArgument(g.equals(f), "%s (should be: %s)", g, f); } From 20c43230cbc5db66d865319c77525ebea3b3a87e Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 14:21:01 +0100 Subject: [PATCH 222/233] Trace: Use unary minus in Z3 --- .../sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java index 218e50a8e1..2c380b8848 100644 --- a/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/z3/Z3NumeralFormulaManager.java @@ -60,9 +60,7 @@ protected Long makeVariableImpl(String varName) { @Override protected Long negate(Long pNumber) { - long sort = Native.getSort(z3context, pNumber); - long minusOne = Native.mkInt(z3context, -1, sort); - return Native.mkMul(z3context, 2, new long[] {minusOne, pNumber}); + return Native.mkUnaryMinus(z3context, pNumber); } @Override From 22f2e32a66da185772a45fe1d55b8fd43ec1894b Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 14:33:24 +0100 Subject: [PATCH 223/233] Trace: Add support for `distinct` --- .../delegate/trace/TraceFormulaManager.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java index b954d295f8..d921f10191 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceFormulaManager.java @@ -421,8 +421,19 @@ public T makeApplication( return (T) getBooleanFormulaManager() .implication((BooleanFormula) args.get(0), (BooleanFormula) args.get(1)); - // TODO We only have 'distinct' for some theories - // case DISTINCT: + case DISTINCT: + if (declaration.getType().isIntegerType()) { + return (T) getIntegerFormulaManager().distinct((List) args); + } else if (declaration.getType().isRationalType()) { + return (T) getRationalFormulaManager().distinct((List) args); + } else if (declaration.getType().isBitvectorType()) { + return (T) getBitvectorFormulaManager().distinct((List) args); + } else { + // FIXME JavaSMT only supports 'distinct' for some of its theories + throw new UnsupportedOperationException( + String.format( + "Operator 'distinct' not " + "supported for %ss", declaration.getType())); + } case STORE: return (T) getArrayFormulaManager().store((ArrayFormula) args.get(0), args.get(1), args.get(2)); From 415ca39a9b7da561d8ed435b2ac1eb6824cd9610 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 18:22:16 +0100 Subject: [PATCH 224/233] traceToSmtlib: Fix typo in Solvers enum --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index bbc14806e1..035a587e01 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -316,7 +316,7 @@ class Solvers(Enum): CVC4 = "SolverContextFactory.Solvers.CVC4" CVC5 = "SolverContextFactory.Solvers.CVC5" YICES2 = "SolverContextFactory.Solvers.OPENSMT" - BITWUZLA = "SolverContextFactory.Solvers.OPENSMT" + BITWUZLA = "SolverContextFactory.Solvers.BITWUZLA" litSolvers = from_enum(Solvers) From 2e9c7c7dfac1c120dafdd8fea6d74cf82e89ffa3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 18:34:23 +0100 Subject: [PATCH 225/233] traceToSmtlib: Fix typo in method name --- scripts/traceToSmtlib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 035a587e01..0183c9a64b 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -1330,8 +1330,8 @@ def conv(arg): output.append( f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3.toSmtlib()} {arg1} {arg2}))') - elif stmt.getCalls()[-1] == "toIeeBitvector": - raise Exception("Recasting from float to bitvector is not supported in SMTLIB") + elif stmt.getCalls()[-1] == "toIeeeBitvector": + raise Exception("Extracting the bits of a floating-point value is not supported in SMTLIB") else: raise Exception(f'Unsupported call: {stmt.getCalls()}') From e22c14dd4a40d4d94cca488bcca29436d0ddf263 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 18:48:50 +0100 Subject: [PATCH 226/233] traceToSmtlib: Redirect stderr to the output --- scripts/tracingTest.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/tracingTest.sh b/scripts/tracingTest.sh index c2a725a863..9348993f3f 100755 --- a/scripts/tracingTest.sh +++ b/scripts/tracingTest.sh @@ -29,9 +29,7 @@ echo -e "\nConverting JavaTraces to Smtlib" find ../traces -name *.java -exec ./traceToSmtlib.py --save {} ';' echo -e "\nRunning the solver on the generated Smtlib files" -find ../traces -name *.smt2 -exec echo "path: {}" ';' -exec timeout 20s $* {} ';' > solver.log - -grep -E "error|path" solver.log +find ../traces -name *.smt2 -exec echo "path: {}" ';' -exec timeout 20s $* {} ';' 2>&1 | tee solver.log | grep -E "error|path" echo -e "\n(See solver.log for the entire solver output)" From 223bd704598ea6a0f568d9476493eeafec4932ec Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 19:06:12 +0100 Subject: [PATCH 227/233] traceToSmtlib: Replace define-const with define-fun to work around an issue in the Bitwuzla parser See https://github.com/bitwuzla/bitwuzla/issues/37 --- scripts/traceToSmtlib.py | 202 +++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index 0183c9a64b..e6673109e6 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -639,31 +639,31 @@ def matchType(param, arg): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvadd {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvadd {arg1} {arg2}))') elif stmt.getCalls()[-1] == "and": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvand {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvand {arg1} {arg2}))') elif stmt.getCalls()[-1] == "concat": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BitvectorType(sortMap[arg1].width + sortMap[arg2].width) output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (concat {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (concat {arg1} {arg2}))') elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() if len(args) < 2: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') else: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] @@ -671,13 +671,13 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvsdiv" if arg3 else "bvudiv"} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"bvsdiv" if arg3 else "bvudiv"} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + output.append(f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') elif stmt.getCalls()[-1] == "extend": arg1 = stmt.value[-1].args[0] @@ -685,7 +685,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BitvectorType(sortMap[arg1].width + arg2) output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {"sign_extend" if arg3 else "zero_extend"} {arg2}) {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {"sign_extend" if arg3 else "zero_extend"} {arg2}) {arg1}))') elif stmt.getCalls()[-1] == "extract": arg1 = stmt.value[-1].args[0] @@ -693,7 +693,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BitvectorType(arg2 - arg3 + 1) output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ extract {arg2} {arg3}) {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ extract {arg2} {arg3}) {arg1}))') elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] @@ -701,7 +701,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsge' if arg3 else 'bvuge'} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvsge' if arg3 else 'bvuge'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] @@ -709,7 +709,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsgt' if arg3 else 'bvugt'} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvsgt' if arg3 else 'bvugt'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] @@ -717,7 +717,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvsle' if arg3 else 'bvule'} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvsle' if arg3 else 'bvule'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] @@ -725,7 +725,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'bvslt' if arg3 else 'bvult'} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvslt' if arg3 else 'bvult'} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "makeBitvector": arg1 = stmt.value[-1].args[0] @@ -734,12 +734,12 @@ def matchType(param, arg): if arg2 is int: # Create bv constant output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') else: # Convert integer formula to bv formula operation = "to_bv" if solver == Solvers.MATHSAT5 else "int_to_bv" output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {toIntSmtlib(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {toIntSmtlib(arg2)}))') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] @@ -754,25 +754,25 @@ def matchType(param, arg): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvmul {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvmul {arg1} {arg2}))') elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvneg {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvneg {arg1}))') elif stmt.getCalls()[-1] == "not": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvnot {arg1}))') + output.append(f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvnot {arg1}))') elif stmt.getCalls()[-1] == "or": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvor {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvor {arg1} {arg2}))') elif stmt.getCalls()[-1] == "remainder": arg1 = stmt.value[-1].args[0] @@ -780,7 +780,7 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvsrem" if arg3 else "bvurem"} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"bvsrem" if arg3 else "bvurem"} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "rotateLeft": arg1 = stmt.value[-1].args[0] @@ -789,7 +789,7 @@ def matchType(param, arg): raise Exception("rotateLeft is only supported for constant rotations") sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ rotate_left {arg2}) {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ rotate_left {arg2}) {arg1}))') elif stmt.getCalls()[-1] == "rotateRight": arg1 = stmt.value[-1].args[0] @@ -798,14 +798,14 @@ def matchType(param, arg): raise Exception("rotateRight is only supported for constant rotations") sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ rotate_right {arg2}) {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ rotate_right {arg2}) {arg1}))') elif stmt.getCalls()[-1] == "shiftLeft": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvshl {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvshl {arg1} {arg2}))') elif stmt.getCalls()[-1] == "shiftRight": arg1 = stmt.value[-1].args[0] @@ -813,35 +813,35 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"bvashr" if arg3 else "bvlshr"} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"bvashr" if arg3 else "bvlshr"} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "smodulo": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvsmod {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvsmod {arg1} {arg2}))') elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvsub {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvsub {arg1} {arg2}))') elif stmt.getCalls()[-1] == "toIntegerFormula": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = IntegerType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({"sbv_to_int" if arg2 else "ubv_to_int"} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"sbv_to_int" if arg2 else "ubv_to_int"} {arg1}))') elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (bvxor {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvxor {arg1} {arg2}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -852,20 +852,20 @@ def matchType(param, arg): sortMap[stmt.variable] = BooleanType() if len(args) == 0: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') elif len(args) == 1: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {args[0]})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {args[0]})') else: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (and {' '.join(args)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (and {' '.join(args)}))') elif stmt.getCalls()[-1] == "equivalence": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') elif stmt.getCalls()[-1] == "ifThenElse": arg1 = stmt.value[-1].args[0] @@ -873,30 +873,30 @@ def matchType(param, arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg2] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (ite {arg1} {arg2} {arg3}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (ite {arg1} {arg2} {arg3}))') elif stmt.getCalls()[-1] == "implication": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (=> {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (=> {arg1} {arg2}))') elif stmt.getCalls()[-1] == "makeFalse": sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} false)') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} false)') elif stmt.getCalls()[-1] == "makeTrue": sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') elif stmt.getCalls()[-1] == "makeBoolean": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {'true' if arg1 else 'false'})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {'true' if arg1 else 'false'})') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name @@ -909,27 +909,27 @@ def matchType(param, arg): elif stmt.getCalls()[-1] == "not": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append(f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (not {arg1}))') + output.append(f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (not {arg1}))') elif stmt.getCalls()[-1] == "or": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() if len(args) == 0: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} false)') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} false)') elif len(args) == 1: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {args[0]})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {args[0]})') else: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (or {' '.join(args)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (or {' '.join(args)}))') elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (xor {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (xor {arg1} {arg2}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -946,71 +946,71 @@ def conv(arg): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (+ {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() if len(args) < 2: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} true)') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') else: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(map(conv, args))}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(map(conv, args))}))') elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({'div' if theoryType == IntegerType() else '/'} {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'div' if theoryType == IntegerType() else '/'} {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "floor": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = IntegerType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {matchType(IntegerType(), arg1)})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {matchType(IntegerType(), arg1)})') elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (>= {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (>= {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (> {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (> {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (<= {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (<= {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (< {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (< {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "makeNumber": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toIntSmtlib(arg1) if theoryType == IntegerType() else toRealSmtlib(arg1)})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {toIntSmtlib(arg1) if theoryType == IntegerType() else toRealSmtlib(arg1)})') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] # We ignore the actual variable name @@ -1026,47 +1026,47 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= (mod (- {arg1} {arg2}) {arg3}) 0))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= (mod (- {arg1} {arg2}) {arg3}) 0))') elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "modulo"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = IntegerType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (mod {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (mod {arg1} {arg2}))') elif stmt.getCalls()[-1] == "multiply": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (* {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (* {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)}))') elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)} {conv(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)} {conv(arg2)}))') elif stmt.getCalls()[-1] == "sum": args = stmt.value[-1].args sortMap[stmt.variable] = theoryType if len(args) == 0: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {"0" if theoryType == IntegerType() else "0.0"})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {"0" if theoryType == IntegerType() else "0.0"})') elif len(args) == 1: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {conv(args[0])})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {conv(args[0])})') else: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(map(conv, args))}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(map(conv, args))}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -1076,7 +1076,7 @@ def conv(arg): arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.abs {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.abs {arg1}))') elif stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] @@ -1084,14 +1084,14 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.add {arg3.toSmtlib()} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.add {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "assignment": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') elif stmt.getCalls()[-1] == "castTo": # Converts from float to bv/int, or convert between different fp precisions @@ -1102,15 +1102,15 @@ def conv(arg): sortMap[stmt.variable] = arg3 if isinstance(arg3, FloatType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') elif isinstance(arg3, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(arg3, RationalType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1}))') elif isinstance(arg3, BitvectorType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4.toSmtlib()} {arg1}))') else: raise Exception(f"Illegal cast from float to {arg3}") @@ -1124,15 +1124,15 @@ def conv(arg): sourceType = sortMap[arg1] if isinstance(sourceType, FloatType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') elif isinstance(sourceType, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(sourceType, RationalType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') elif isinstance(sourceType, BitvectorType): output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') else: raise Exception(f"Illegal cast from {sourceType} to float") @@ -1142,97 +1142,97 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.div {arg3.toSmtlib()} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.div {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "equalWithFPSemantics": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.eq {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.eq {arg1} {arg2}))') elif stmt.getCalls()[-1] == "fromIeeeBitvector": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = arg2 output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg2.exponent} {arg2.significand}) {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg2.exponent} {arg2.significand}) {arg1}))') elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.geq {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.geq {arg1} {arg2}))') elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.gt {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.gt {arg1} {arg2}))') elif stmt.getCalls()[-1] == "isInfinity": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isInfinite {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isInfinite {arg1}))') elif stmt.getCalls()[-1] == "isNaN": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isNaN {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isNaN {arg1}))') elif stmt.getCalls()[-1] == "isNegative": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isNegative {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isNegative {arg1}))') elif stmt.getCalls()[-1] == "isNormal": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isNormal {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isNormal {arg1}))') elif stmt.getCalls()[-1] == "isSubnormal": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isSubnormal {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isSubnormal {arg1}))') elif stmt.getCalls()[-1] == "isZero": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.isZero {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isZero {arg1}))') elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.leq {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.leq {arg1} {arg2}))') elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.lt {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.lt {arg1} {arg2}))') elif stmt.getCalls()[-1] == "makeMinusInfinity": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = arg1 output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ -oo {arg1.exponent} {arg1.significand}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (_ -oo {arg1.exponent} {arg1.significand}))') elif stmt.getCalls()[-1] == "makeNaN": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = arg1 output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ NaN {arg1.exponent} {arg1.significand}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (_ NaN {arg1.exponent} {arg1.significand}))') elif stmt.getCalls()[-1] == "makeNumber": args = stmt.value[-1].args @@ -1243,7 +1243,7 @@ def conv(arg): rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] sortMap[stmt.variable] = args[1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} {toFpSmtlib(rm, args[1], args[0])})') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {toFpSmtlib(rm, args[1], args[0])})') elif (len(args) == 4 and isinstance(args[0], int) and isinstance(args[1], int) @@ -1251,7 +1251,7 @@ def conv(arg): and isinstance(args[3], FloatType)): sortMap[stmt.variable] = args[3] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp #b{'1' if args[2] == Sign.NEGATIVE else '0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand - 1, args[1])}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp #b{'1' if args[2] == Sign.NEGATIVE else '0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand - 1, args[1])}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()} ({type(args[0])} {args})') @@ -1259,7 +1259,7 @@ def conv(arg): arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = arg1 output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (_ +oo {arg1.exponent} {arg1.significand}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (_ +oo {arg1.exponent} {arg1.significand}))') elif stmt.getCalls()[-1] == "makeRoundingMode": pass @@ -1278,14 +1278,14 @@ def conv(arg): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.max {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.max {arg1} {arg2}))') elif stmt.getCalls()[-1] == "min": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.min {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.min {arg1} {arg2}))') elif stmt.getCalls()[-1] == "multiply": arg1 = stmt.value[-1].args[0] @@ -1293,34 +1293,34 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.mul {arg3.toSmtlib()} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.mul {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.neg {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.neg {arg1}))') elif stmt.getCalls()[-1] == "remainder": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.rem {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.rem {arg1} {arg2}))') elif stmt.getCalls()[-1] == "round": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.roundToIntegral {arg2.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.roundToIntegral {arg2.toSmtlib()} {arg1}))') elif stmt.getCalls()[-1] == "sqrt": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sqrt {arg2.toSmtlib()} {arg1}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.sqrt {arg2.toSmtlib()} {arg1}))') elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] @@ -1328,7 +1328,7 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3.toSmtlib()} {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3.toSmtlib()} {arg1} {arg2}))') elif stmt.getCalls()[-1] == "toIeeeBitvector": raise Exception("Extracting the bits of a floating-point value is not supported in SMTLIB") @@ -1342,7 +1342,7 @@ def conv(arg): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') elif stmt.getCalls()[-1] == "makeArray": arg1 = stmt.value[-1].args[0] @@ -1352,7 +1352,7 @@ def conv(arg): # Build a const array sortMap[stmt.variable] = ArrayType(arg1, arg2) output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ((as const {sortMap[stmt.variable].toSmtlib()}) {arg3}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((as const {sortMap[stmt.variable].toSmtlib()}) {arg3}))') else: # Declare a new variable sortMap[stmt.variable] = ArrayType(arg2, arg3) @@ -1364,7 +1364,7 @@ def conv(arg): arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1].element output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (select {arg1} {arg2}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (select {arg1} {arg2}))') elif stmt.getCalls()[-1] == "store": arg1 = stmt.value[-1].args[0] @@ -1372,7 +1372,7 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} (store {arg1} {arg2} {arg3}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (store {arg1} {arg2} {arg3}))') else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -1405,7 +1405,7 @@ def conv(arg): f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') else: output.append( - f'(define-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(values)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(values)}))') elif stmt.getCalls()[-1] == "declareUF": arg0 = stmt.value[-1].args[0] From 5de8ba3be6541d2a5bca0c05f1513346b4aaa447 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 19:56:20 +0100 Subject: [PATCH 228/233] Trace: Simplify str.range in CVC5 --- .../solvers/cvc5/CVC5StringFormulaManager.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5StringFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5StringFormulaManager.java index 6bb7c0f618..3f112c6296 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5StringFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5StringFormulaManager.java @@ -140,17 +140,7 @@ protected Term allCharImpl() { @Override protected Term range(Term start, Term end) { - // Precondition: Both bounds must be single character Strings - // CVC5 already checks that the lower bound is smaller than the upper bound and returns the - // empty language otherwise. - Term one = termManager.mkInteger(1); - Term cond = - termManager.mkTerm( - Kind.AND, - termManager.mkTerm(Kind.EQUAL, length(start), one), - termManager.mkTerm(Kind.EQUAL, length(end), one)); - return termManager.mkTerm( - Kind.ITE, cond, termManager.mkTerm(Kind.REGEXP_RANGE, start, end), noneImpl()); + return termManager.mkTerm(Kind.REGEXP_RANGE, start, end); } @Override From 5f57874f5c39ab7071c1b5707bad4ad7252644e3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 21:39:01 +0100 Subject: [PATCH 229/233] traceToSmtlib: Fix integer to bv conversion --- scripts/traceToSmtlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index e6673109e6..b7f5974ff7 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -739,7 +739,7 @@ def matchType(param, arg): # Convert integer formula to bv formula operation = "to_bv" if solver == Solvers.MATHSAT5 else "int_to_bv" output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {toIntSmtlib(arg2)}))') + f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {arg2}))') elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] From 74a18a314eb4dee10327212e0f8d791b7f1c34f9 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 22:24:38 +0100 Subject: [PATCH 230/233] Trace: Add support for tree interpolation --- .../TraceInterpolatingProverEnvironment.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java index f4d0694c70..e825aab60b 100644 --- a/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java +++ b/src/org/sosy_lab/java_smt/delegate/trace/TraceInterpolatingProverEnvironment.java @@ -12,8 +12,10 @@ import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; import org.sosy_lab.java_smt.api.SolverException; @@ -62,6 +64,17 @@ public BooleanFormula getInterpolant(Collection formulasOfA) public List getTreeInterpolants( List> partitionedFormulas, int[] startOfSubTree) throws SolverException, InterruptedException { - throw new UnsupportedOperationException(); + return mgr.rebuildAll( + logger.logDefDiscard( + logger.toVariable(this), + String.format( + "getTreeInterpolant(ImmutableList.of(%s), new int[]{%s})", + FluentIterable.from(partitionedFormulas) + .transform(p -> String.format("ImmutableList.of(%s)", logger.toVariables(p))) + .join(Joiner.on(", ")), + FluentIterable.from(Arrays.stream(startOfSubTree).boxed().toArray()) + .transform(Objects::toString) + .join(Joiner.on(", "))), + () -> delegate.getTreeInterpolants(partitionedFormulas, startOfSubTree))); } } From c3cd25978f5ab1589c6c72240f22a224674a4dc1 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 22:43:41 +0100 Subject: [PATCH 231/233] Trace: Implement numeral.sum for Smtinterpol --- .../smtinterpol/SmtInterpolNumeralFormulaManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/org/sosy_lab/java_smt/solvers/smtinterpol/SmtInterpolNumeralFormulaManager.java b/src/org/sosy_lab/java_smt/solvers/smtinterpol/SmtInterpolNumeralFormulaManager.java index 7c7657d1d1..09bd150d6d 100644 --- a/src/org/sosy_lab/java_smt/solvers/smtinterpol/SmtInterpolNumeralFormulaManager.java +++ b/src/org/sosy_lab/java_smt/solvers/smtinterpol/SmtInterpolNumeralFormulaManager.java @@ -174,4 +174,9 @@ public Term lessThan(Term pNumber1, Term pNumber2) { public Term lessOrEquals(Term pNumber1, Term pNumber2) { return env.term("<=", pNumber1, pNumber2); } + + @Override + protected Term sumImpl(List operands) { + return env.term("+", operands.toArray(new Term[0])); + } } From 48972fb8fd9ffb3abeba028544d196e51ee554d3 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Sun, 14 Dec 2025 23:34:11 +0100 Subject: [PATCH 232/233] traceToSmtlib: Don't write help message to stderr --- scripts/tracingTest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tracingTest.sh b/scripts/tracingTest.sh index 9348993f3f..175a438d0c 100755 --- a/scripts/tracingTest.sh +++ b/scripts/tracingTest.sh @@ -13,7 +13,7 @@ set -e if [[ $# -eq 0 ]]; then echo "No command line for the solver" echo "Usage: ./tracingTest.sh " - echo "Where is the full command for the solver, including any options that need to be passed" >&2 + echo "Where is the full command for the solver, including any options that need to be passed" exit 1 fi From bd303b81bbd05c0e32a03ba822d77c88998aa5f1 Mon Sep 17 00:00:00 2001 From: Daniel Raffler Date: Mon, 15 Dec 2025 17:21:40 +0100 Subject: [PATCH 233/233] traceToSmtlib: Translate to an intermediate representation, rather than printing Smtlib directly --- scripts/traceToSmtlib.py | 549 ++++++++++++++++++++------------------- 1 file changed, 285 insertions(+), 264 deletions(-) diff --git a/scripts/traceToSmtlib.py b/scripts/traceToSmtlib.py index b7f5974ff7..a2b79dfb65 100755 --- a/scripts/traceToSmtlib.py +++ b/scripts/traceToSmtlib.py @@ -537,6 +537,75 @@ def parseNumber(repr): raise Exception(f'Could not parse "{repr}" as a number') +def flattenProvers(prog: List[Definition]): + "Push all assertions onto the same global prover" + # We assume that the provers are not used "in parallel" + # FIXME Reorder the instructions to avoid overlapping prover instances + active = "" + levels = 0 + trace = [] + for stmt in prog: + if (stmt.getCalls()[-1] == "newProverEnvironment" + or stmt.getCalls()[-1] == "newProverEnvironmentWithInterpolation"): + if levels > 0: + raise Exception("Can't open new prover before closing the last instance") + active = stmt.variable + levels = 1 + trace.append(Definition(None, [Call(active), Call("push", [])])) + elif stmt.getCalls()[-1] == "push": + levels += 1 + trace.append(stmt) + elif stmt.getCalls()[-1] == "pop": + levels -= 1 + trace.append(stmt) + elif stmt.getCalls() == [active, "close"]: + trace.extend([Definition(None, [Call(active), Call("pop", [])])] * levels) + levels = 0 + else: + trace.append(stmt) + return trace + + +@dataclass +class Expr: + fn: str + args: Optional[List] + + def toSmtlib(self): + if self.args == None or self.args == []: + return self.fn + else: + return f'({self.fn} {' '.join([arg.toSmtlib() for arg in self.args])})' + + +@dataclass +class Def: + symbol: str + sort: Type + value: Optional[Expr] + + def toSmtlib(self): + if self.value == None: + if isinstance(self.sort, FunctionType): + return f'(declare-fun {self.symbol} {self.sort.toSmtlib()})' + else: + return f'(declare-const {self.symbol} {self.sort.toSmtlib()})' + else: + return f'(define-fun {self.symbol} () {self.sort.toSmtlib()} {self.value.toSmtlib()})' + + +def const(value): + return Expr(value, []) + + +def var(name): + return Expr(str(name), None) + + +def app(fn, *args): + return Expr(fn, [p if isinstance(p, Expr) else var(p) for p in args]) + + def toIntSmtlib(value): "Print integer value as smtlib" if isinstance(value, str): @@ -544,12 +613,12 @@ def toIntSmtlib(value): if isinstance(value, float) and not math.isnan(value) and not math.isinf(value): return toIntSmtlib(Fraction(value)) if isinstance(value, int): - return f'(- {-value})' if value < 0 else str(value) - if isinstance(value, Fraction): if value < 0: - return f'(div (- {-value.numerator}) {value.denominator})' + return app('-', toIntSmtlib(-value)) else: - return f'(div {value.numerator} {value.denominator})' + return const(str(value)) + if isinstance(value, Fraction): + return app('div', toIntSmtlib(value.numerator), toIntSmtlib(value.numerator)) else: raise Exception(f'Can\'t convert "{value}" to Integer') @@ -563,10 +632,7 @@ def toRealSmtlib(value): elif isinstance(value, float): return toRealSmtlib(Fraction.from_float(value)) elif isinstance(value, Fraction): - if value < 0: - return f'(/ (- {-value.numerator}) {value.denominator})' - else: - return f'(/ {value.numerator} {value.denominator})' + return app('/', toIntSmtlib(value.numerator), toIntSmtlib(value.denominator)) else: raise Exception(f'Can\'t convert "{value}" to Real') @@ -576,156 +642,137 @@ def toFpSmtlib(rm, fpType, value): if isinstance(value, str): return toFpSmtlib(rm, fpType, parseNumber(value)) elif value == float('-inf'): - return f'(_ -oo {fpType.exponent} {fpType.significand})' + return const(f'(_ -oo {fpType.exponent} {fpType.significand})') elif value == float('+inf'): - return f'(_ +oo {fpType.exponent} {fpType.significand})' + return const(f'(_ +oo {fpType.exponent} {fpType.significand})') elif isinstance(value, float) and math.isnan(value): - return f'(_ NaN {fpType.exponent} {fpType.significand})' + return const(f'(_ NaN {fpType.exponent} {fpType.significand})') else: - return f'((_ to_fp {fpType.exponent} {fpType.significand}) {rm.toSmtlib()} {toRealSmtlib(value)})' - - -def flattenProvers(prog: List[Definition]): - "Push all assertions onto the same global prover" - # We assume that the provers are not used "in parallel" - # FIXME Reorder the instructions to avoid overlapping prover instances - active = "" - levels = 0 - trace = [] - for stmt in prog: - if (stmt.getCalls()[-1] == "newProverEnvironment" - or stmt.getCalls()[-1] == "newProverEnvironmentWithInterpolation"): - if levels > 0: - raise Exception("Can't open new prover before closing the last instance") - active = stmt.variable - levels = 1 - trace.append(Definition(None, [Call(active), Call("push", [])])) - elif stmt.getCalls()[-1] == "push": - levels += 1 - trace.append(stmt) - elif stmt.getCalls()[-1] == "pop": - levels -= 1 - trace.append(stmt) - elif stmt.getCalls() == [active, "close"]: - trace.extend([Definition(None, [Call(active), Call("pop", [])])] * levels) - levels = 0 - else: - trace.append(stmt) - return trace + return app(f'(_ to_fp {fpType.exponent} {fpType.significand})', const(rm.toSmtlib()), toRealSmtlib(value)) def translate(prog: List[Definition]): "Convert a JavaSMT trace to a SMTLIB2 script" + # TODO Print error location + # TODO Use actual variable names in declarations sortMap = {} nameMap = {} # Stores UF names for function declarations - output = ["(set-logic ALL)", - "(set-option :interactive-mode true)", - "(set-option :produce-models true)", - "(set-option :global-declarations true)"] + output: List[Def | Expr] = \ + [app('set-logic', const('ALL')), + app('set-option', const(':interactive-mode'), const('true')), + app('set-option', const(':produce-models'), const('true')), + app('set-option', const(':global-declarations'), const('true')) + ] solver = prog[3].value[1].args[3] # Get solver name from createSolverContext call in the preamble for stmt in prog[5:]: def matchType(param, arg): "Convert argument to match the given type" if param == IntegerType() and sortMap[arg] == RationalType(): - return f'(to_int {arg})' + return app('to_int', arg) elif param == RationalType() and sortMap[arg] == IntegerType(): - return f'(to_real {arg})' + return app('to_real', arg) else: - return arg + return var(arg) if stmt.getCalls()[:-1] == ["mgr", "getBitvectorFormulaManager"]: if stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvadd {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvadd', arg1, arg2))) elif stmt.getCalls()[-1] == "and": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvand {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvand', arg1, arg2))) elif stmt.getCalls()[-1] == "concat": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BitvectorType(sortMap[arg1].width + sortMap[arg2].width) - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (concat {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('concat', arg1, arg2))) elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() if len(args) < 2: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') + output.append(Def(stmt.variable, sortMap[stmt.variable], const('true'))) else: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(args)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('distinct', *args))) elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"bvsdiv" if arg3 else "bvudiv"} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsdiv', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvudiv', arg1, arg2))) elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append(f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('=', arg1, arg2))) elif stmt.getCalls()[-1] == "extend": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BitvectorType(sortMap[arg1].width + arg2) - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {"sign_extend" if arg3 else "zero_extend"} {arg2}) {arg1}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app(f'(_ sign_extend {arg2})', arg1))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app(f'(_ zero_extend {arg2})', arg1))) elif stmt.getCalls()[-1] == "extract": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BitvectorType(arg2 - arg3 + 1) - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ extract {arg2} {arg3}) {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app(f'(_ extract {arg2} {arg3})', arg1))) elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvsge' if arg3 else 'bvuge'} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsge', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvuge', arg1, arg2))) elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvsgt' if arg3 else 'bvugt'} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsgt', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvugt', arg1, arg2))) elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvsle' if arg3 else 'bvule'} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsle', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvule', arg1, arg2))) elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'bvslt' if arg3 else 'bvult'} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvslt', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvult', arg1, arg2))) elif stmt.getCalls()[-1] == "makeBitvector": arg1 = stmt.value[-1].args[0] @@ -733,54 +780,51 @@ def matchType(param, arg): sortMap[stmt.variable] = BitvectorType(arg1) if arg2 is int: # Create bv constant - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {printBitvector(arg1, arg2)})') + output.append(Def(stmt.variable, sortMap[stmt.variable], const(printBitvector(arg1, arg2)))) else: # Convert integer formula to bv formula operation = "to_bv" if solver == Solvers.MATHSAT5 else "int_to_bv" - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {operation} {arg1}) {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app(f'(_ {operation} {arg1})', arg2))) elif stmt.getCalls()[-1] == "makeVariable": arg1 = stmt.value[-1].args[0] - arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + arg2 = stmt.value[-1].args[1] if '|' in arg2: - continue + continue # Skip illegal names sortMap[stmt.variable] = arg1 - output.append(f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) elif stmt.getCalls()[-1] == "multiply": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvmul {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvmul', arg1, arg2))) elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvneg {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvneg', arg1))) elif stmt.getCalls()[-1] == "not": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append(f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvnot {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvnot', arg1))) elif stmt.getCalls()[-1] == "or": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvor {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvor', arg1, arg2))) elif stmt.getCalls()[-1] == "remainder": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"bvsrem" if arg3 else "bvurem"} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsrem', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvurem', arg1, arg2))) elif stmt.getCalls()[-1] == "rotateLeft": arg1 = stmt.value[-1].args[0] @@ -788,8 +832,7 @@ def matchType(param, arg): if not isinstance(arg2, int): raise Exception("rotateLeft is only supported for constant rotations") sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ rotate_left {arg2}) {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app(f'(_ rotate_left {arg2})', arg1))) elif stmt.getCalls()[-1] == "rotateRight": arg1 = stmt.value[-1].args[0] @@ -797,51 +840,50 @@ def matchType(param, arg): if not isinstance(arg2, int): raise Exception("rotateRight is only supported for constant rotations") sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ rotate_right {arg2}) {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app(f'(_ rotate_right {arg2})', arg1))) elif stmt.getCalls()[-1] == "shiftLeft": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvshl {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvshl', arg1, arg2))) elif stmt.getCalls()[-1] == "shiftRight": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"bvashr" if arg3 else "bvlshr"} {arg1} {arg2}))') + if arg3: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvashr', arg1, arg2))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvlshr', arg1, arg2))) elif stmt.getCalls()[-1] == "smodulo": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvsmod {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsmod', arg1, arg2))) elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvsub {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvsub', arg1, arg2))) elif stmt.getCalls()[-1] == "toIntegerFormula": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({"sbv_to_int" if arg2 else "ubv_to_int"} {arg1}))') + if arg2: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('sbv_to_int', arg1))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('ubv_to_int', arg1))) elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (bvxor {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('bvxor', arg1, arg2))) else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -851,85 +893,74 @@ def matchType(param, arg): args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() if len(args) == 0: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') + output.append(Def(stmt.variable, sortMap[stmt.variable], const('true'))) elif len(args) == 1: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {args[0]})') + output.append(Def(stmt.variable, sortMap[stmt.variable], var(args[0]))) else: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (and {' '.join(args)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('and', *args))) elif stmt.getCalls()[-1] == "equivalence": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('=', arg1, arg2))) elif stmt.getCalls()[-1] == "ifThenElse": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg2] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (ite {arg1} {arg2} {arg3}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('ite', arg1, arg2, arg3))) elif stmt.getCalls()[-1] == "implication": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (=> {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('=>', arg1, arg2))) elif stmt.getCalls()[-1] == "makeFalse": sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} false)') + output.append(Def(stmt.variable, sortMap[stmt.variable], const('false'))) elif stmt.getCalls()[-1] == "makeTrue": sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') + output.append(Def(stmt.variable, sortMap[stmt.variable], const('true'))) elif stmt.getCalls()[-1] == "makeBoolean": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {'true' if arg1 else 'false'})') + if arg1: + output.append(Def(stmt.variable, sortMap[stmt.variable], const('true'))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], const('false'))) elif stmt.getCalls()[-1] == "makeVariable": - arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + arg1 = stmt.value[-1].args[0] if '|' in arg1: - continue + continue # Skip illegal names sortMap[stmt.variable] = BooleanType() - output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) elif stmt.getCalls()[-1] == "not": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append(f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (not {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('not', arg1))) elif stmt.getCalls()[-1] == "or": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() if len(args) == 0: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} false)') + output.append(Def(stmt.variable, sortMap[stmt.variable], const('false'))) elif len(args) == 1: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {args[0]})') + output.append(Def(stmt.variable, sortMap[stmt.variable], var(args[0]))) else: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (or {' '.join(args)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('or', *args))) elif stmt.getCalls()[-1] == "xor": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (xor {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('xor', arg1, arg2))) else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -945,128 +976,117 @@ def conv(arg): arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (+ {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('+', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "distinct": args = stmt.value[-1].args sortMap[stmt.variable] = BooleanType() if len(args) < 2: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} true)') + output.append(Def(stmt.variable, sortMap[stmt.variable], const('true'))) else: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (distinct {' '.join(map(conv, args))}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('distinct', *[conv(p) for p in args]))) elif stmt.getCalls()[-1] == "divide": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({'div' if theoryType == IntegerType() else '/'} {conv(arg1)} {conv(arg2)}))') + if theoryType == IntegerType(): + output.append(Def(stmt.variable, sortMap[stmt.variable], app('div', conv(arg1), conv(arg2)))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], app('/', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "equal": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('=', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "floor": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {matchType(IntegerType(), arg1)})') + output.append(Def(stmt.variable, sortMap[stmt.variable], matchType(IntegerType(), arg1))) elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (>= {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('>=', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (> {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('>', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (<= {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('<=', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (< {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('<', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "makeNumber": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = theoryType - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {toIntSmtlib(arg1) if theoryType == IntegerType() else toRealSmtlib(arg1)})') + if theoryType == IntegerType(): + output.append(Def(stmt.variable, sortMap[stmt.variable], toIntSmtlib(arg1))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], toRealSmtlib(arg1))) elif stmt.getCalls()[-1] == "makeVariable": - arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + arg1 = stmt.value[-1].args[0] if '|' in arg1: - continue + continue # Skip illegal names sortMap[stmt.variable] = theoryType - output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "modularCongruence"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= (mod (- {arg1} {arg2}) {arg3}) 0))') + output.append(Def(stmt.variable, sortMap[stmt.variable], + app('=', app('mod', app('-', arg1, arg2), toIntSmtlib(arg3)), + toIntSmtlib(0)))) elif stmt.getCalls() == ["mgr", "getIntegerFormulaManager", "modulo"]: arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = IntegerType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (mod {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('mod', arg1, arg2))) elif stmt.getCalls()[-1] == "multiply": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (* {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('*', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = theoryType - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('-', conv(arg1)))) elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = theoryType - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (- {conv(arg1)} {conv(arg2)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('-', conv(arg1), conv(arg2)))) elif stmt.getCalls()[-1] == "sum": args = stmt.value[-1].args sortMap[stmt.variable] = theoryType if len(args) == 0: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {"0" if theoryType == IntegerType() else "0.0"})') + output.append(Def(stmt.variable, sortMap[stmt.variable], + const('0') if theoryType == IntegerType() else const('0.0'))) elif len(args) == 1: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {conv(args[0])})') + output.append(Def(stmt.variable, sortMap[stmt.variable], conv(args[0]))) else: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (+ {' '.join(map(conv, args))}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('+', *[conv(p) for p in args]))) else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -1075,8 +1095,7 @@ def conv(arg): if stmt.getCalls()[-1] == "abs": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.abs {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.abs', arg1))) elif stmt.getCalls()[-1] == "add": arg1 = stmt.value[-1].args[0] @@ -1084,14 +1103,13 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.add {arg3.toSmtlib()} {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.add', const(arg3.toSmtlib()), arg1, arg2))) elif stmt.getCalls()[-1] == "assignment": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('=', arg1, arg2))) elif stmt.getCalls()[-1] == "castTo": # Converts from float to bv/int, or convert between different fp precisions @@ -1101,16 +1119,20 @@ def conv(arg): arg4 = stmt.value[-1].args[3] # rounding mode sortMap[stmt.variable] = arg3 if isinstance(arg3, FloatType): - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ to_fp {arg3.exponent} {arg3.significand})', const(arg4.toSmtlib()), + arg1))) elif isinstance(arg3, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(arg3, RationalType): - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.to_real {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.to_real', arg1))) elif isinstance(arg3, BitvectorType): - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {'fp.to_sbv' if arg2 else 'fp.to_ubv'} {arg3.width}) {arg4.toSmtlib()} {arg1}))') + if arg2: + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ fp.to_sbv {arg3.width})', const(arg4.toSmtlib()), arg1))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ fp.to_ubv {arg3.width})', const(arg4.toSmtlib()), arg1))) else: raise Exception(f"Illegal cast from float to {arg3}") @@ -1123,16 +1145,25 @@ def conv(arg): sortMap[stmt.variable] = arg3 sourceType = sortMap[arg1] if isinstance(sourceType, FloatType): - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ to_fp {arg3.exponent} {arg3.significand})', const(arg4.toSmtlib()), + arg1))) elif isinstance(sourceType, IntegerType): raise Exception("Converting from float to integer is not supported in SMTLIB") elif isinstance(sourceType, RationalType): - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ to_fp {arg3.exponent} {arg3.significand})', const(arg4.toSmtlib()), + arg1))) elif isinstance(sourceType, BitvectorType): - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ {'to_fp' if arg2 else 'to_fp_unsigned'} {arg3.exponent} {arg3.significand}) {arg4.toSmtlib()} {arg1}))') + if arg2: + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ to_fp {arg3.exponent} {arg3.significand})', const(arg4.toSmtlib()), + arg1))) + else: + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ to_fp_unsigned {arg3.exponent} {arg3.significand})', + const(arg4.toSmtlib()), + arg1))) else: raise Exception(f"Illegal cast from {sourceType} to float") @@ -1142,97 +1173,96 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.div {arg3.toSmtlib()} {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.div', const(arg3.toSmtlib()), arg1, arg2))) elif stmt.getCalls()[-1] == "equalWithFPSemantics": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.eq {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.eq', arg1, arg2))) elif stmt.getCalls()[-1] == "fromIeeeBitvector": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = arg2 output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((_ to_fp {arg2.exponent} {arg2.significand}) {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], + app(f'(_ to_fp {arg2.exponent} {arg2.significand})', arg1))) elif stmt.getCalls()[-1] == "greaterOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.geq {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.geq', arg1, arg2))) elif stmt.getCalls()[-1] == "greaterThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.gt {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.gt', arg1, arg2))) elif stmt.getCalls()[-1] == "isInfinity": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isInfinite {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.isInfinite', arg1))) elif stmt.getCalls()[-1] == "isNaN": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isNaN {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.isNaN', arg1))) elif stmt.getCalls()[-1] == "isNegative": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isNegative {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.isNegative', arg1))) elif stmt.getCalls()[-1] == "isNormal": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isNormal {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.isNormal', arg1))) elif stmt.getCalls()[-1] == "isSubnormal": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isSubnormal {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.isSubnormal', arg1))) elif stmt.getCalls()[-1] == "isZero": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = BooleanType() output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.isZero {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.isZero', arg1))) elif stmt.getCalls()[-1] == "lessOrEquals": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.leq {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.leq', arg1, arg2))) elif stmt.getCalls()[-1] == "lessThan": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.lt {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.lt', arg1, arg2))) elif stmt.getCalls()[-1] == "makeMinusInfinity": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = arg1 output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (_ -oo {arg1.exponent} {arg1.significand}))') + Def(stmt.variable, sortMap[stmt.variable], const(f'(_ -oo {arg1.exponent} {arg1.significand})'))) elif stmt.getCalls()[-1] == "makeNaN": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = arg1 output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (_ NaN {arg1.exponent} {arg1.significand}))') + Def(stmt.variable, sortMap[stmt.variable], const(f'(_ NaN {arg1.exponent} {arg1.significand})'))) elif stmt.getCalls()[-1] == "makeNumber": args = stmt.value[-1].args @@ -1242,16 +1272,17 @@ def conv(arg): and isinstance(args[2], RoundingMode)): rm = RoundingMode.NEAREST_TIES_TO_EVEN if len(args) == 2 else args[2] sortMap[stmt.variable] = args[1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} {toFpSmtlib(rm, args[1], args[0])})') + output.append(Def(stmt.variable, sortMap[stmt.variable], toFpSmtlib(rm, args[1], args[0]))) elif (len(args) == 4 and isinstance(args[0], int) and isinstance(args[1], int) and isinstance(args[2], Sign) and isinstance(args[3], FloatType)): sortMap[stmt.variable] = args[3] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp #b{'1' if args[2] == Sign.NEGATIVE else '0'} {printBitvector(args[3].exponent, args[0])} {printBitvector(args[3].significand - 1, args[1])}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], + app('fp', '#b1' if args[2] == Sign.NEGATIVE else '#b0', + printBitvector(args[3].exponent, args[0]), + printBitvector(args[3].significand - 1, args[1])))) else: raise Exception(f'Unsupported call: {stmt.getCalls()} ({type(args[0])} {args})') @@ -1259,33 +1290,30 @@ def conv(arg): arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = arg1 output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (_ +oo {arg1.exponent} {arg1.significand}))') + Def(stmt.variable, sortMap[stmt.variable], const(f'(_ +oo {arg1.exponent} {arg1.significand})'))) elif stmt.getCalls()[-1] == "makeRoundingMode": pass elif stmt.getCalls()[-1] == "makeVariable": - arg1 = stmt.value[-1].args[0] # We ignore the actual variable name + arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] if '|' in arg1: - continue + continue # Skip illegal names sortMap[stmt.variable] = arg2 - output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) elif stmt.getCalls()[-1] == "max": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.max {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.max', arg1, arg2))) elif stmt.getCalls()[-1] == "min": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.min {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.min', arg1, arg2))) elif stmt.getCalls()[-1] == "multiply": arg1 = stmt.value[-1].args[0] @@ -1293,34 +1321,31 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.mul {arg3.toSmtlib()} {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.mul', const(arg3.toSmtlib()), arg1, arg2))) elif stmt.getCalls()[-1] == "negate": arg1 = stmt.value[-1].args[0] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.neg {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.neg', arg1))) elif stmt.getCalls()[-1] == "remainder": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.rem {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.rem', arg1, arg2))) elif stmt.getCalls()[-1] == "round": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.roundToIntegral {arg2.toSmtlib()} {arg1}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.roundToIntegral', const(arg2.toSmtlib()), arg1))) elif stmt.getCalls()[-1] == "sqrt": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.sqrt {arg2.toSmtlib()} {arg1}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('fp.sqrt', const(arg2.toSmtlib()), arg1))) elif stmt.getCalls()[-1] == "subtract": arg1 = stmt.value[-1].args[0] @@ -1328,7 +1353,7 @@ def conv(arg): arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (fp.sub {arg3.toSmtlib()} {arg1} {arg2}))') + Def(stmt.variable, sortMap[stmt.variable], app('fp.sub', const(arg3.toSmtlib()), arg1, arg2))) elif stmt.getCalls()[-1] == "toIeeeBitvector": raise Exception("Extracting the bits of a floating-point value is not supported in SMTLIB") @@ -1341,8 +1366,7 @@ def conv(arg): arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = BooleanType() - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (= {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('=', arg1, arg2))) elif stmt.getCalls()[-1] == "makeArray": arg1 = stmt.value[-1].args[0] @@ -1351,28 +1375,25 @@ def conv(arg): if isinstance(arg1, Type) and isinstance(arg2, Type): # Build a const array sortMap[stmt.variable] = ArrayType(arg1, arg2) - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ((as const {sortMap[stmt.variable].toSmtlib()}) {arg3}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], + app(f'(as const {sortMap[stmt.variable].toSmtlib()})', arg3))) else: # Declare a new variable sortMap[stmt.variable] = ArrayType(arg2, arg3) - output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) elif stmt.getCalls()[-1] == "select": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] sortMap[stmt.variable] = sortMap[arg1].element - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (select {arg1} {arg2}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('select', arg1, arg2))) elif stmt.getCalls()[-1] == "store": arg1 = stmt.value[-1].args[0] arg2 = stmt.value[-1].args[1] arg3 = stmt.value[-1].args[2] sortMap[stmt.variable] = sortMap[arg1] - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} (store {arg1} {arg2} {arg3}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app('store', arg1, arg2, arg3))) else: raise Exception(f'Unsupported call: {stmt.getCalls()}') @@ -1401,30 +1422,27 @@ def conv(arg): values = [matchType(param, arg) for param, arg in zip(sortMap[arg0].arguments, args)] sortMap[stmt.variable] = sortMap[arg0].value if args == []: - output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) else: - output.append( - f'(define-fun {stmt.variable} () {sortMap[stmt.variable].toSmtlib()} ({name} {' '.join(values)}))') + output.append(Def(stmt.variable, sortMap[stmt.variable], app(name, *values))) elif stmt.getCalls()[-1] == "declareUF": arg0 = stmt.value[-1].args[0] arg1 = stmt.value[-1].args[1] args = stmt.value[-1].args[2] if '|' in arg0: - continue + continue # Skip illegal names sortMap[stmt.variable] = FunctionType(args, arg1) nameMap[stmt.variable] = f'|{arg0}|' if args != []: - output.append( - f'(declare-fun {nameMap[stmt.variable]} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(nameMap[stmt.variable], sortMap[stmt.variable], None)) else: raise Exception(f'Unsupported call: {stmt.getCalls()}') elif stmt.getCalls()[-1] == "addConstraint": arg1 = stmt.value[-1].args[0] - output.append(f'(assert {arg1})') + output.append(app('assert', arg1)) elif stmt.getCalls()[-1] == "asList": pass @@ -1434,22 +1452,21 @@ def conv(arg): elif stmt.getCalls()[-1] == "evaluate": arg1 = stmt.value[-1].args[0] - output.append(f'(get-value ({arg1}))') + output.append(app('get-value', app('', arg1))) elif stmt.getCalls()[-1] == "getModel": - output.append(f'(get-model)') + output.append(const('(get-model)')) elif stmt.getCalls()[-1] == "isUnsat": - output.append(f'(check-sat)') + output.append(const('(check-sat)')) elif stmt.getCalls() == ["mgr", "makeVariable"]: arg1 = stmt.value[-1].args[0] - arg2 = stmt.value[-1].args[1] # We ignore the actual variable name + arg2 = stmt.value[-1].args[1] if '|' in arg2: - continue + continue # Skip illegal names sortMap[stmt.variable] = arg1 - output.append( - f'(declare-const {stmt.variable} {sortMap[stmt.variable].toSmtlib()})') + output.append(Def(stmt.variable, sortMap[stmt.variable], None)) elif stmt.getCalls()[-1] == "newProverEnvironment": # TODO Apply options at the top of the file @@ -1460,16 +1477,20 @@ def conv(arg): pass elif stmt.getCalls()[-1] == "pop": - output.append(f'(pop 1)') + output.append(app('pop', const('1'))) elif stmt.getCalls()[-1] == "push": - output.append(f'(push 1)') + output.append(app('push', const('1'))) else: raise Exception(f'Unsupported call: {stmt.getCalls()}') - output.append("") - return '\n'.join(output) + return output + + +def printSmtlib(program): + "Convert intermediate representation to String" + return '\n'.join([line.toSmtlib() for line in program]) + '\n' if __name__ == '__main__': @@ -1487,7 +1508,7 @@ def conv(arg): # Translate the trace try: - output = translate(flattenProvers(program.parse("\n" + open(args.file).read()))) + output = printSmtlib(translate(flattenProvers(program.parse("\n" + open(args.file).read())))) except Exception as exception: print(f'In {args.file}: {exception}') exit(-1)