Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c794274
Add common API in AbstractProver to check inheritors for closed status
baierd Jun 9, 2026
4a2e807
Add new OptimizationProverDelegate that handled common checks of Opti…
baierd Jun 9, 2026
d3c7a74
Remove common checks from Optimization Provers of Z3 and Mathsat
baierd Jun 9, 2026
0886c38
Add implementations for getModel() and getEvaluator() in AbstractProv…
baierd Jun 9, 2026
8232a8d
Add default implementation of getUnsatCore() in AbstractProver that p…
baierd Jun 9, 2026
811e75b
Add default implementation of unsatCoreOverAssumptions() in AbstractP…
baierd Jun 9, 2026
bfb7f23
Reduce visibility of getModelImpl() and getEvaluatorImpl() as they sh…
baierd Jun 9, 2026
1075a97
Remove another redundant usage of checkGenerateModels() from MathSAT
baierd Jun 9, 2026
58f602a
Reduce visibility of getModelImpl() and getEvaluatorImpl() as they sh…
baierd Jun 9, 2026
837cbd0
Remove another redundant usage of checkGenerateModels() from MathSAT
baierd Jun 9, 2026
a11a593
Add AllSat default impl in AbstractProver that calls the new method A…
baierd Jun 9, 2026
dc58778
Add JavaDoc for allsat impls
baierd Jun 10, 2026
5e65df3
Improve impl spec JavaDoc for AbstractProver#allSatImpl
baierd Jun 10, 2026
de07dc2
Add default impl for AbstractProver#getStatistics to perform common c…
baierd Jun 10, 2026
7ecd782
Move ShutdownNotifier from AbstractProverWithAllSat to AbstractProver…
baierd Jun 10, 2026
276faa9
Extend optimization API with InterruptedExceptions and checks for sol…
baierd Jun 10, 2026
3ceaaf0
Add shutdownIfNecessary() check to all common checks that did not yet…
baierd Jun 10, 2026
abb95d8
Add comment to size() in AbstractProver
baierd Jun 10, 2026
1bff9da
Add API for shouldShutdown() in AbstractProver, handling whether a Sh…
baierd Jun 10, 2026
b9b32ad
Rename most ShutdownNotifier to reflect that they are context bound
baierd Jun 10, 2026
b488699
Switch Boolector and Bitwuzla to using common shouldShutdown API from…
baierd Jun 10, 2026
3928243
Add type check for delegate in OptimizationProverDelegate
baierd Jun 12, 2026
faeb24f
Add type check for delegate in InterpolatingProverDelegate
baierd Jun 12, 2026
7527299
Merge branch 'master' into add_common_optimizationProver_delegate2
baierd Jun 12, 2026
181128a
Merge branch 'add_common_optimizationProver_delegate2' into handle_mo…
baierd Jun 12, 2026
8d914f9
Merge branch 'handle_model_generation_api_through_impl_delegates' int…
baierd Jun 12, 2026
07333ac
Merge branch 'add_common_impl_for_unsatCore_allSat' into add_solver_a…
baierd Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/org/sosy_lab/java_smt/api/BasicProverEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ default T push(BooleanFormula f) throws InterruptedException {
* Remove one backtracking point/level from the current stack. This removes the latest level
* including all of its formulas, i.e., all formulas that were added for this backtracking point.
*/
void pop();
void pop() throws InterruptedException;

/** Add a constraint to the latest backtracking point. */
@Nullable
Expand Down Expand Up @@ -100,15 +100,15 @@ boolean isUnsatWithAssumptions(Collection<BooleanFormula> assumptions)
* model might contain additional symbols with their evaluation, if a solver uses its own
* temporary symbols.
*/
Model getModel() throws SolverException;
Model getModel() throws SolverException, InterruptedException;

/**
* Get a temporary view on the current satisfying assignment. This should be called only
* immediately after an {@link #isUnsat()} call that returned <code>false</code>. The evaluator
* should no longer be used as soon as any constraints are added to, pushed, or popped from the
* prover stack.
*/
default Evaluator getEvaluator() throws SolverException {
default Evaluator getEvaluator() throws SolverException, InterruptedException {
return getModel();
}

Expand All @@ -120,7 +120,8 @@ default Evaluator getEvaluator() throws SolverException {
* <p>Note that if you need to iterate multiple times over the model it may be more efficient to
* use this method instead of {@link #getModel()} (depending on the solver).
*/
default ImmutableList<Model.ValueAssignment> getModelAssignments() throws SolverException {
default ImmutableList<Model.ValueAssignment> getModelAssignments()
throws SolverException, InterruptedException {
try (Model model = getModel()) {
return model.asList();
}
Expand All @@ -132,7 +133,7 @@ default ImmutableList<Model.ValueAssignment> getModelAssignments() throws Solver
* <p>This should be called only immediately after an {@link #isUnsat()} call that returned <code>
* false</code>. Requires the {@link ProverOptions#GENERATE_UNSAT_CORE} option to work.
*/
List<BooleanFormula> getUnsatCore();
List<BooleanFormula> getUnsatCore() throws InterruptedException;

/**
* Returns an UNSAT core (if it exists, otherwise {@code Optional.empty()}), over the chosen
Expand Down Expand Up @@ -166,9 +167,7 @@ Optional<List<BooleanFormula>> unsatCoreOverAssumptions(Collection<BooleanFormul
*
* @see SolverContext#getStatistics()
*/
default ImmutableMap<String, String> getStatistics() {
return ImmutableMap.of();
}
ImmutableMap<String, String> getStatistics() throws InterruptedException;

/**
* Closes the prover environment. The object should be discarded, and should not be used after
Expand Down
10 changes: 5 additions & 5 deletions src/org/sosy_lab/java_smt/api/OptimizationProverEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface OptimizationProverEnvironment extends BasicProverEnvironment<Vo
*
* @return Objective handle, to be used for retrieving the value.
*/
int maximize(Formula objective);
int maximize(Formula objective) throws InterruptedException;

/**
* Add minimization <code>objective</code>.
Expand All @@ -30,7 +30,7 @@ public interface OptimizationProverEnvironment extends BasicProverEnvironment<Vo
*
* @return Objective handle, to be used for retrieving the value.
*/
int minimize(Formula objective);
int minimize(Formula objective) throws InterruptedException;

/**
* Optimize the objective function subject to the previously imposed constraints.
Expand All @@ -44,14 +44,14 @@ public interface OptimizationProverEnvironment extends BasicProverEnvironment<Vo
* @return Upper approximation of the optimized value, or absent optional if the objective is
* unbounded.
*/
Optional<Rational> upper(int handle, Rational epsilon);
Optional<Rational> upper(int handle, Rational epsilon) throws InterruptedException;

/**
* @param epsilon Value to substitute for the {@code epsilon}.
* @return Lower approximation of the optimized value, or absent optional if the objective is
* unbounded.
*/
Optional<Rational> lower(int handle, Rational epsilon);
Optional<Rational> lower(int handle, Rational epsilon) throws InterruptedException;

/**
* {@inheritDoc}
Expand All @@ -68,7 +68,7 @@ public interface OptimizationProverEnvironment extends BasicProverEnvironment<Vo
* (epsilon is irrelevant here and can be zero). The model returns the optimal assignment x=9.
*/
@Override
Model getModel() throws SolverException;
Model getModel() throws SolverException, InterruptedException;

/** Status of the optimization problem. */
enum OptStatus {
Expand Down
138 changes: 128 additions & 10 deletions src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.java_smt.api.BasicProverEnvironment;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Evaluator;
import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment;
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.OptimizationProverEnvironment;
import org.sosy_lab.java_smt.api.OptimizationProverEnvironment.OptStatus;
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
Expand All @@ -52,6 +55,8 @@ public abstract class AbstractProver<T> implements BasicProverEnvironment<T> {

private final Set<Evaluator> evaluators = new LinkedHashSet<>();

protected final ShutdownNotifier contextShutdownNotifier;

/**
* This data-structure tracks all formulas that were asserted on different levels. We can assert a
* formula multiple times on the same or also distinct levels and return a new ID for each
Expand All @@ -61,7 +66,7 @@ public abstract class AbstractProver<T> implements BasicProverEnvironment<T> {

private static final String TEMPLATE = "Please set the prover option %s.";

protected AbstractProver(Set<ProverOptions> pOptions) {
protected AbstractProver(Set<ProverOptions> pOptions, ShutdownNotifier pContextShutdownNotifier) {
generateModels = pOptions.contains(ProverOptions.GENERATE_MODELS);
generateAllSat = pOptions.contains(ProverOptions.GENERATE_ALL_SAT);
generateUnsatCores = pOptions.contains(ProverOptions.GENERATE_UNSAT_CORE);
Expand All @@ -70,37 +75,66 @@ protected AbstractProver(Set<ProverOptions> pOptions) {
enableSL = pOptions.contains(ProverOptions.ENABLE_SEPARATION_LOGIC);

assertedFormulas.add(LinkedHashMultimap.create());
contextShutdownNotifier = pContextShutdownNotifier;
}

protected final void checkGenerateModels() {
protected final void checkGenerateModels() throws InterruptedException {
Preconditions.checkState(generateModels, TEMPLATE, ProverOptions.GENERATE_MODELS);
Preconditions.checkState(!closed);
shutdownIfNecessary();
Preconditions.checkState(!changedSinceLastSatQuery);
Preconditions.checkState(wasLastSatCheckSatisfiable, NO_MODEL_HELP);
}

protected final void checkGenerateAllSat() {
protected final void checkGenerateAllSat() throws InterruptedException {
// TODO: should this close all evaluators as well?
Preconditions.checkState(!closed);
shutdownIfNecessary();
Preconditions.checkState(generateAllSat, TEMPLATE, ProverOptions.GENERATE_ALL_SAT);
}

protected final void checkGenerateUnsatCores() {
protected final void checkGenerateUnsatCores() throws InterruptedException {
// TODO: should this close all evaluators as well?
Preconditions.checkState(generateUnsatCores, TEMPLATE, ProverOptions.GENERATE_UNSAT_CORE);
Preconditions.checkState(!closed);
shutdownIfNecessary();
Preconditions.checkState(!changedSinceLastSatQuery);
Preconditions.checkState(!wasLastSatCheckSatisfiable);
}

protected final void checkGenerateUnsatCoresOverAssumptions() {
protected final void checkGenerateUnsatCoresOverAssumptions(
Collection<BooleanFormula> assumptions) throws InterruptedException {
// TODO: should this close all evaluators as well?
Preconditions.checkState(!closed);
shutdownIfNecessary();
Preconditions.checkNotNull(assumptions);
Preconditions.checkState(
generateUnsatCoresOverAssumptions,
TEMPLATE,
ProverOptions.GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS);
// TODO: why is there no check for changedSinceLastSatQuery or wasLastSatCheckSatisfiable?
}

/**
* Checks whether the prover has been closed already. Only to be used if this is the only check
* performed in a call.
*/
protected void checkClosed() {
Preconditions.checkState(!closed);
}

private void checkGenerateInterpolants() {
protected final void shutdownIfNecessary() throws InterruptedException {
contextShutdownNotifier.shutdownIfNecessary();
}

protected final boolean shouldShutdown() {
return contextShutdownNotifier.shouldShutdown();
}

private void checkGenerateInterpolants() throws InterruptedException {
// TODO: should this close all evaluators as well?
Preconditions.checkState(!closed);
shutdownIfNecessary();
Preconditions.checkState(
!changedSinceLastSatQuery,
"Interpolants can only be calculated right after a call to isUnsat()");
Expand All @@ -110,15 +144,16 @@ private void checkGenerateInterpolants() {
+ "unsatisfiable.");
}

protected final void checkGenerateInterpolants(Collection<T> formulasOfA) {
protected final void checkGenerateInterpolants(Collection<T> formulasOfA)
throws InterruptedException {
checkGenerateInterpolants();
checkArgument(
getAssertedConstraintIds().containsAll(formulasOfA),
"interpolation can only be done over previously asserted formulas.");
}

protected final void checkGenerateSeqInterpolants(
List<? extends Collection<T>> partitionedFormulas) {
List<? extends Collection<T>> partitionedFormulas) throws InterruptedException {
checkGenerateInterpolants();
Preconditions.checkArgument(
!partitionedFormulas.isEmpty(), "at least one partition should be available.");
Expand All @@ -129,7 +164,8 @@ protected final void checkGenerateSeqInterpolants(
}

protected final void checkGenerateTreeInterpolants(
List<? extends Collection<T>> partitionedFormulas, int[] startOfSubTree) {
List<? extends Collection<T>> partitionedFormulas, int[] startOfSubTree)
throws InterruptedException {
checkGenerateSeqInterpolants(partitionedFormulas);
assert InterpolatingProverEnvironment.checkTreeStructure(
partitionedFormulas.size(), startOfSubTree);
Expand All @@ -155,12 +191,14 @@ private void setChanged() {
@Override
public int size() {
checkState(!closed);
// TODO: can the solver calls used in the implementations cause interrupts?
return assertedFormulas.size() - 1;
}

@Override
public final void push() throws InterruptedException {
checkState(!closed);
shutdownIfNecessary();
pushImpl();
setChanged();
assertedFormulas.add(LinkedHashMultimap.create());
Expand All @@ -169,8 +207,9 @@ public final void push() throws InterruptedException {
protected abstract void pushImpl() throws InterruptedException;

@Override
public final void pop() {
public final void pop() throws InterruptedException {
checkState(!closed);
shutdownIfNecessary();
checkState(assertedFormulas.size() > 1, "initial level must remain until close");
assertedFormulas.remove(assertedFormulas.size() - 1); // remove last
popImpl();
Expand All @@ -183,6 +222,7 @@ public final void pop() {
@CanIgnoreReturnValue
public final @Nullable T addConstraint(BooleanFormula constraint) throws InterruptedException {
checkState(!closed);
shutdownIfNecessary();
T t = addConstraintImpl(constraint);
setChanged();
Iterables.getLast(assertedFormulas).put(constraint, t);
Expand All @@ -196,6 +236,7 @@ public final void pop() {
@Override
public final boolean isUnsat() throws SolverException, InterruptedException {
checkState(!closed);
shutdownIfNecessary();
changedSinceLastSatQuery = false;
wasLastSatCheckSatisfiable = false;
final boolean isUnsat = isUnsatImpl();
Expand Down Expand Up @@ -223,6 +264,7 @@ public final boolean isUnsat() throws SolverException, InterruptedException {
*/
public final OptStatus check() throws InterruptedException, SolverException {
checkState(!closed);
shutdownIfNecessary();
wasLastSatCheckSatisfiable = false;
changedSinceLastSatQuery = false;
final OptStatus status = checkImpl();
Expand Down Expand Up @@ -279,6 +321,24 @@ protected ImmutableMap<T, BooleanFormula> getAssertedFormulasById() {
return builder.buildOrThrow();
}

@Override
public final Model getModel() throws SolverException, InterruptedException {
checkGenerateModels();
return getModelImpl();
}

protected abstract Model getModelImpl() throws SolverException;

@Override
public final Evaluator getEvaluator() throws SolverException, InterruptedException {
checkGenerateModels();
return getEvaluatorImpl();
}

protected Evaluator getEvaluatorImpl() throws SolverException, InterruptedException {
return getModel();
}

/**
* This method registers the Evaluator to be cleaned up before the next change on the prover
* stack.
Expand All @@ -297,6 +357,64 @@ protected void closeAllEvaluators() {
evaluators.clear();
}

@Override
public final List<BooleanFormula> getUnsatCore() throws InterruptedException {
checkGenerateUnsatCores();
return getUnsatCoreImpl();
}

/**
* @implSpec override and implement if a solver supports UNSAT-CORE generation.
*/
protected List<BooleanFormula> getUnsatCoreImpl() {
throw new UnsupportedOperationException(UNSAT_CORE_NOT_SUPPORTED);
}

@Override
public final Optional<List<BooleanFormula>> unsatCoreOverAssumptions(
Collection<BooleanFormula> assumptions) throws SolverException, InterruptedException {
checkGenerateUnsatCoresOverAssumptions(assumptions);
return unsatCoreOverAssumptionsImpl(assumptions);
}

/**
* TODO: once javac does not complain if we use a default impl here, add one.
*
* @implSpec override and implement if a solver supports the generation of UNSAT-COREs over
* assumptions. Else, override and throw a {@link UnsupportedOperationException} with {@link
* BasicProverEnvironment#UNSAT_CORE_WITH_ASSUMPTIONS_NOT_SUPPORTED}
*/
protected abstract Optional<List<BooleanFormula>> unsatCoreOverAssumptionsImpl(
Collection<BooleanFormula> assumptions) throws SolverException, InterruptedException;

@Override
public final <R> R allSat(AllSatCallback<R> callback, List<BooleanFormula> important)
throws InterruptedException, SolverException {
checkGenerateAllSat();
return allSatImpl(callback, important);
}

/**
* @implSpec only override and implement if a solver offers its own AllSAT procedure, otherwise
* inherit {@link AbstractProverWithAllSat} instead of this class.
*/
protected abstract <R> R allSatImpl(AllSatCallback<R> callback, List<BooleanFormula> important)
throws InterruptedException, SolverException;

@Override
public final ImmutableMap<String, String> getStatistics() throws InterruptedException {
Preconditions.checkState(!closed);
shutdownIfNecessary();
return getStatisticsImpl();
}

/**
* @implSpec override and implement for solvers that provide statistics.
*/
protected ImmutableMap<String, String> getStatisticsImpl() {
return ImmutableMap.of();
}

@Override
public void close() {
assertedFormulas.clear();
Expand Down
Loading
Loading