Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d7f226a
Added interfaces for handling general proofs of unsatisfiability: `Pr…
gcarpio21 Dec 20, 2025
9647cd5
Added abstract class implementing the proof interface `AbstractProof`.
gcarpio21 Dec 20, 2025
570eb5c
Added the implementation of method `getProof` for retrieving `Proof` …
gcarpio21 Dec 20, 2025
0fd0070
Added the implementation of method `getProof` for retrieving `Proof` …
gcarpio21 Dec 20, 2025
6272b50
Added the abstract class `ProofFrame` for transformation of native pr…
gcarpio21 Dec 20, 2025
0f8c032
Added `GENERATE_PROOFS` to `ProverOptions` in `SolverContext`.
gcarpio21 Dec 20, 2025
b9dc850
Implemented method `getProof` in `CVC5AbstractProver` for retrieving …
gcarpio21 Dec 20, 2025
d3e69b1
Added enum `CVC5ProofRule` for the different proof rules used by CVC5.
gcarpio21 Dec 20, 2025
1b79e82
Added class `CV5Proof` which extends `AbstractProof`. `generateProofI…
gcarpio21 Dec 20, 2025
9f2ac63
Added method `requireProofGeneration` to `SolverBasedTest0`.
gcarpio21 Dec 20, 2025
dcc728a
In `ProverEnvironmentTest` added multiple methods for testing retriev…
gcarpio21 Dec 20, 2025
f849437
In `ProverEnvironmentTest` fixed "MissingFail" and "UnusedVariable" w…
gcarpio21 Jan 10, 2026
7abe581
Added file `package-info.java` to package `proofs`.
gcarpio21 Jan 10, 2026
f1fa31a
Added missing documentation in interface `Proof`.
gcarpio21 Jan 10, 2026
f5e3376
Fixed multiple checkstyle warnings.
gcarpio21 Jan 10, 2026
27847d8
Formatting changes
gcarpio21 Jan 10, 2026
8213c7a
Added `CVC5ProofRule` `CHAIN_M_RESOLUTION`.
gcarpio21 Jan 10, 2026
6a133f6
Implemented refaster suggestion.
gcarpio21 Jan 10, 2026
72c9697
Fixed "unused" warning in `ProverEnvironmentTest`.
gcarpio21 Jan 10, 2026
50a9b16
Removed unnecessary method from the `ProofRule` interface.
gcarpio21 Jan 16, 2026
32da899
Merge branch 'master' into 558-add-general-proof-api
gcarpio21 Jan 19, 2026
ed64164
Proofs: Changed `children` in `AbstractProof` to type `ImmutableSet`.…
gcarpio21 Jan 20, 2026
f037077
Proofs: Fixed year in copyright header.
gcarpio21 Jan 20, 2026
77d77a8
Fixed formatting
gcarpio21 Jan 20, 2026
c2cdbae
Proofs: fixed documentation for proof retrieval code.
gcarpio21 Jan 20, 2026
ab4e485
Proofs: added `Z3_WITH_INTERPOLATION` to the solvers to exclude durin…
gcarpio21 Jan 20, 2026
d1a18f9
Revert "Proofs: Changed `children` in `AbstractProof` to type `Immuta…
gcarpio21 Jan 20, 2026
98daf50
Proofs: Fixed header year, deleted unneeded comments.
gcarpio21 Jan 20, 2026
71fbd4b
Proofs: Field `children` of `AbstractProof` now is an `ImmutableSet`.
gcarpio21 Jan 21, 2026
0cdc9b0
Proofs: Moved `ProofFrame` inside `AbstractProof`. Changed return typ…
gcarpio21 Jan 22, 2026
230924a
Proofs: changed modifier of `CVC5Proof` constructor to private.
gcarpio21 Jan 22, 2026
47922a9
Proofs: return type of `getChildren` from the general proof API chang…
gcarpio21 Jan 22, 2026
7f94d1b
Proofs: renamed parameters, changed signatures and types in `Abstract…
gcarpio21 Jan 22, 2026
127a0af
Proofs: renamed parameters and changed types in `CVC5Proof` to comply…
gcarpio21 Jan 22, 2026
e969884
Proofs: renamed parameters in `ProverEnvironmentTest` to comply with …
gcarpio21 Jan 22, 2026
1e01011
Proofs: made `CVC5` `final`.
gcarpio21 Jan 26, 2026
c59874b
Proofs: removed unused import in `ProverEnvironmentTest`.
gcarpio21 Jan 26, 2026
1684258
Merge branch 'master' into 558-add-general-proof-api
gcarpio21 Jan 27, 2026
f750ce1
Proofs: renamed helper function for testing in `ProverEnvironmentTest`.
gcarpio21 Jan 28, 2026
be6ae14
Proofs: added more documentation to the `ProofRule` interface.
gcarpio21 Jan 28, 2026
58cf62c
Proofs: added more documentation in `ProverEnvironmentTest`.
gcarpio21 Jan 28, 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
8 changes: 8 additions & 0 deletions src/org/sosy_lab/java_smt/api/BasicProverEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.Optional;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
import org.sosy_lab.java_smt.api.proofs.Proof;

/**
* Super interface for {@link ProverEnvironment} and {@link InterpolatingProverEnvironment} that
Expand Down Expand Up @@ -160,6 +161,13 @@ default ImmutableMap<String, String> getStatistics() {
return ImmutableMap.of();
}

/**
* Get proof of unsatisfiability of the conjuction of the current satck of all formulas. This
* method should be called only immediately after an {@link #isUnsat()} call that returned <code>
* true</code>.
*/
Proof getProof() throws SolverException, InterruptedException;

/**
* Closes the prover environment. The object should be discarded, and should not be used after
* closing. The first call of this method will close the prover instance, further calls are
Expand Down
3 changes: 3 additions & 0 deletions src/org/sosy_lab/java_smt/api/SolverContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ enum ProverOptions {
*/
GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS,

/** Whether the solver should generate proofs for unsatisfiable formulas. */
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add a note about Z3 here please? The Z3 proof situation might be confusing for users.

Copy link
Member Author

Choose a reason for hiding this comment

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

You mean about it needing proof generation enabled on the context object?

I was thinking to leave that out for this, as the only solver with proof generation should be CVC5 for now. Once it is turn for Z3 then I would add the corresponding note.

GENERATE_PROOFS,

/** Whether the solver should enable support for formulae build in SL theory. */
ENABLE_SEPARATION_LOGIC
}
Expand Down
43 changes: 43 additions & 0 deletions src/org/sosy_lab/java_smt/api/proofs/Proof.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of JavaSMT,
* an API wrapper for a collection of SMT solvers:
* https://github.com/sosy-lab/java-smt
*
* SPDX-FileCopyrightText: 2026 Dirk Beyer <https://www.sosy-lab.org>
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.sosy_lab.java_smt.api.proofs;

import com.google.common.collect.ImmutableSet;
import java.util.Optional;
import org.sosy_lab.java_smt.api.Formula;

/** A proof node in the proof DAG of a proof. */
public interface Proof {
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like the name of this class should be ProofNode.

Copy link
Contributor

Choose a reason for hiding this comment

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

Note: this was named ProofNode in the past and was changed due to me requesting it.

In general: the Proof interface/object should hold all proofs themselves, and provide API to access them (similar to the model). The problem with this being called Proof can be seen in the API, e.g. ImmutableSet<Proof> getChildren();. If getChildren() returns a Proof, it is clear that there is a problem, as the Proof should only exist as one central element. Hence i was wrong in wanting to rename this interface to Proof, and it should be called ProofNode as @gcarpio21 named it correctly initially!

We should then add a new interface Proof, that has the API to return the root (and only ever the root) of the proof DAG (and potentially more in the future).


/** Get the children of the proof node. */
ImmutableSet<Proof> getChildren();

/**
* Check if the proof node is a leaf.
*
* @return True if the proof node is a leaf, false otherwise.
*/
boolean isLeaf();

/**
* Get the formula of the proof node.
*
* @return The formula of the proof node.
*/
Optional<Formula> getFormula();

/**
* Get the rule of the proof node.
*
* @return The rule of the proof node.
*/
ProofRule getRule();
}
31 changes: 31 additions & 0 deletions src/org/sosy_lab/java_smt/api/proofs/ProofRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* This file is part of JavaSMT,
* an API wrapper for a collection of SMT solvers:
* https://github.com/sosy-lab/java-smt
*
* SPDX-FileCopyrightText: 2026 Dirk Beyer <https://www.sosy-lab.org>
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.sosy_lab.java_smt.api.proofs;

/**
* A proof rule from a given proof format. E.g.:
*
* <p>CVC5 currently uses many rules in its calculus for proving unsatisfiability. Through its API
* one can retrieve a rule in form of an enum. See: <a
* href="https://cvc5.github.io/docs/cvc5-1.3.2/api/java/io/github/cvc5/ProofRule.html">...</a>
* Note: Other solvers may return just a String, the name of the rule applied.
*
* <p>We can look at RESOLUTION: Given two nodes viewed as clauses C_1 and C_2, as well as the pivot
* which is a literal occurring in C_1 and C_2 (positively and negatively or the other way around)
* and its polarity, it produces C which "is a clause resulting from collecting all the literals in
* C_1, minus the first occurrence of the pivot or its negation, and C_2, minus the first occurrence
* of the pivot or its negation, according to the policy above". See the link given earlier.
*/
public interface ProofRule {

/** Get the name of the proof rule. */
Copy link
Contributor

Choose a reason for hiding this comment

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

An example would be helpful for users to understand. Especially since distinct solvers can return distinct rules.

String getName();
}
14 changes: 14 additions & 0 deletions src/org/sosy_lab/java_smt/api/proofs/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* This file is part of JavaSMT,
* an API wrapper for a collection of SMT solvers:
* https://github.com/sosy-lab/java-smt
*
* SPDX-FileCopyrightText: 2026 Dirk Beyer <https://www.sosy-lab.org>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* This package is meant to provide abstract classes and interfaces that are inherited and used all
* over to process proofs from the solvers.
*/
package org.sosy_lab.java_smt.api.proofs;
132 changes: 132 additions & 0 deletions src/org/sosy_lab/java_smt/basicimpl/AbstractProof.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* This file is part of JavaSMT,
* an API wrapper for a collection of SMT solvers:
* https://github.com/sosy-lab/java-smt
*
* SPDX-FileCopyrightText: 2026 Dirk Beyer <https://www.sosy-lab.org>
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.sosy_lab.java_smt.basicimpl;

import com.google.common.collect.ImmutableSet;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.proofs.Proof;
import org.sosy_lab.java_smt.api.proofs.ProofRule;

/**
* A proof DAG of a proof.
*
* @author Gabriel Carpio
*/
public abstract class AbstractProof implements Proof {

private ImmutableSet<Proof> children = ImmutableSet.of();
private ProofRule rule;
protected Optional<Formula> formula = Optional.empty();

protected AbstractProof(ProofRule pRule, @Nullable Formula pFormula) {
this.rule = pRule;
this.formula = Optional.ofNullable(pFormula);
}

@Override
public Optional<Formula> getFormula() {
return this.formula;
}

@Override
public ImmutableSet<Proof> getChildren() {
return this.children;
}

protected void addChild(Proof pChild) {
Set<Proof> tempChildren = new LinkedHashSet<>(this.children);
tempChildren.add(pChild);
this.children = ImmutableSet.copyOf(tempChildren);
}

@Override
public ProofRule getRule() {
return rule;
}

@Override
public boolean isLeaf() {
return getChildren().isEmpty();
}

/**
* This method gibes the proof back as a formatted string. It is meant to have a readable proof
* for debugging purposes.
*/
public String proofAsString() {
return proofAsString(0);
}

protected String proofAsString(int pIndentLevel) {
StringBuilder sb = new StringBuilder();
String indent = " ".repeat(pIndentLevel);

String sFormula = getFormula().map(Object::toString).orElse("null");

sb.append(indent).append("Formula: ").append(sFormula).append("\n");
sb.append(indent).append("Rule: ").append(getRule().getName()).append("\n");
sb.append(indent)
.append("No. Children: ")
.append(this.isLeaf() ? 0 : getChildren().size())
.append("\n");
sb.append(indent).append("leaf: ").append(isLeaf()).append("\n");

int i = 0;
if (!isLeaf()) {
for (Proof child : getChildren()) {
sb.append(indent).append("Child ").append(++i).append(":\n");
sb.append(((AbstractProof) child).proofAsString(pIndentLevel + 1));
}
}

return sb.toString();
}

protected abstract static class ProofFrame<T> {
final T proof;
int numArgs = 0;
boolean visited;

protected ProofFrame(T pProof) {
this.proof = pProof;
this.visited = false;
}

/** Get the proof object. */
public T getProof() {
return proof;
}

/** Get the number of arguments the proof object has. */
public int getNumArgs() {
return numArgs;
}

/** Check if the frame has been visited. */
public boolean isVisited() {
return visited;
}

/** Set the frame as visited. */
public void setAsVisited() {
this.visited = true;
}

/** Set the number of arguments the proof object has. */
public void setNumArgs(int pNumArgs) {
this.numArgs = pNumArgs;
}
}
}
16 changes: 16 additions & 0 deletions src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.sosy_lab.java_smt.api.OptimizationProverEnvironment.OptStatus;
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
import org.sosy_lab.java_smt.api.SolverException;
import org.sosy_lab.java_smt.api.proofs.Proof;

public abstract class AbstractProver<T> implements BasicProverEnvironment<T> {

Expand All @@ -40,6 +41,7 @@ public abstract class AbstractProver<T> implements BasicProverEnvironment<T> {
protected final boolean generateAllSat;
protected final boolean generateUnsatCores;
private final boolean generateUnsatCoresOverAssumptions;
protected final boolean generateProofs;
protected final boolean enableSL;

// flags for status
Expand All @@ -64,6 +66,7 @@ protected AbstractProver(Set<ProverOptions> pOptions) {
generateUnsatCores = pOptions.contains(ProverOptions.GENERATE_UNSAT_CORE);
generateUnsatCoresOverAssumptions =
pOptions.contains(ProverOptions.GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS);
generateProofs = pOptions.contains(ProverOptions.GENERATE_PROOFS);
enableSL = pOptions.contains(ProverOptions.ENABLE_SEPARATION_LOGIC);

assertedFormulas.add(LinkedHashMultimap.create());
Expand Down Expand Up @@ -97,6 +100,13 @@ protected final void checkGenerateUnsatCoresOverAssumptions() {
Preconditions.checkState(!wasLastSatCheckSatisfiable);
}

protected final void checkGenerateProofs() {
Preconditions.checkState(generateProofs, TEMPLATE, ProverOptions.GENERATE_PROOFS);
Preconditions.checkState(!closed);
Preconditions.checkState(!changedSinceLastSatQuery);
Preconditions.checkState(!wasLastSatCheckSatisfiable);
}

protected final void checkGenerateInterpolants() {
Preconditions.checkState(!closed);
Preconditions.checkState(
Expand Down Expand Up @@ -276,4 +286,10 @@ public void close() {
closeAllEvaluators();
closed = true;
}

@Override
public Proof getProof() throws InterruptedException, SolverException {
throw new UnsupportedOperationException(
"Proof generation is not available for the current solver.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.SolverException;
import org.sosy_lab.java_smt.api.proofs.Proof;

public class BasicProverWithAssumptionsWrapper<T, P extends BasicProverEnvironment<T>>
implements BasicProverEnvironment<T> {
Expand Down Expand Up @@ -128,4 +129,9 @@ public <R> R allSat(AllSatCallback<R> pCallback, List<BooleanFormula> pImportant
clearAssumptions();
return delegate.allSat(pCallback, pImportant);
}

@Override
public Proof getProof() throws SolverException, InterruptedException {
return delegate.getProof();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.SolverException;
import org.sosy_lab.java_smt.api.proofs.Proof;

class DebuggingBasicProverEnvironment<T> implements BasicProverEnvironment<T> {
private final BasicProverEnvironment<T> delegate;
Expand Down Expand Up @@ -93,6 +94,11 @@ public Optional<List<BooleanFormula>> unsatCoreOverAssumptions(
return delegate.unsatCoreOverAssumptions(assumptions);
}

@Override
public Proof getProof() throws SolverException, InterruptedException {
return delegate.getProof();
}

@Override
public void close() {
debugging.assertThreadLocal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.Model.ValueAssignment;
import org.sosy_lab.java_smt.api.SolverException;
import org.sosy_lab.java_smt.api.proofs.Proof;

/** Wraps a basic prover environment with a logging object. */
class LoggingBasicProverEnvironment<T> implements BasicProverEnvironment<T> {
Expand Down Expand Up @@ -120,6 +121,12 @@ public ImmutableMap<String, String> getStatistics() {
return wrapped.getStatistics();
}

@Override
public Proof getProof() throws SolverException, InterruptedException {
Proof p = wrapped.getProof();
return p;
}

@Override
public void close() {
wrapped.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.SolverException;
import org.sosy_lab.java_smt.api.proofs.Proof;
import org.sosy_lab.java_smt.delegate.statistics.TimerPool.TimerWrapper;

class StatisticsBasicProverEnvironment<T> implements BasicProverEnvironment<T> {
Expand Down Expand Up @@ -99,6 +100,11 @@ public Optional<List<BooleanFormula>> unsatCoreOverAssumptions(
return delegate.unsatCoreOverAssumptions(pAssumptions);
}

@Override
public Proof getProof() throws SolverException, InterruptedException {
return delegate.getProof();
}

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