-
Couldn't load subscription status.
- Fork 54
Develop a common proof format and export proofs #458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 102 commits
9f449e7
b2bc9eb
766e665
9c07f08
ca725ba
955c1af
375937d
af4f670
c2139ad
e05451c
e69d1e0
a6a3efd
2015b46
a4bbe62
5962139
e7940f1
f988d6a
fcdf44f
1d9ab98
2fec458
7c20761
3d89810
d88ecb2
e87f469
018d857
818fe70
87159e8
c1eef9f
746d653
aca4b7c
34c9a7e
5aeb644
f7c5682
4b35856
7dce948
4af588c
1440715
c64814a
c5ea9bb
e2268ba
e0d116d
23e79a8
99f682e
f0d19ac
3debfe2
85f8e11
44e6ce8
f7da393
dc6d5b3
12e4ccb
9bc37ca
78e5431
9617048
95ee755
036a563
fd2230a
7fcd878
4dbc7ec
2aa8f25
07e5866
912e315
e942121
a888646
2dce339
9fc4a22
a268761
fd5ae78
4e9bd18
7d9ab91
a677bbb
1131456
f9e4209
f81f2e3
6fa3a60
7fa1304
50ecf10
15f4bc7
9166aee
6c0fc0a
c379e89
f81fbe8
f9fd81e
f0e702c
35732ed
fce8053
1fbc3cc
2007795
066de33
16c9aa8
e4f52c2
5cef715
fa3cfb4
5375cf4
24f4ddf
59bcd5e
1f805df
4b89e38
3119873
e814fa2
e59a15f
d26157d
136f1fe
9303114
ca7e1eb
a761fca
28390a2
5096139
85d89a1
ea1735a
6bbb92d
81780c6
e751e16
640c6f7
303713b
84f1a16
86c01cd
24991fe
331f7ac
48534bd
dd460aa
a687265
0bbaa73
0739661
16c6c9b
bcad354
e86e7e2
7aa247c
cec06cf
c8009f0
25f67f7
4200112
b6a786c
27e4bb3
14e4991
08f8038
d056b4e
6171224
78f891c
5383562
c2b67a9
cf73814
1ee6997
9a8b123
fa23eca
c32b3e8
df37825
b6dadc9
fd549ba
c663d0a
ea5166e
6394abe
b867817
6766089
95f0b36
d297ba3
9118e3a
1255d6e
42eac03
7ec483e
268af0c
bfdf2d8
3ca6540
4e90d2c
c4fa3c3
910a101
82140a0
cbe6804
a09b10f
ab9d118
7cff403
71b042a
5e075e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| /* | ||
| * This file is part of JavaSMT, | ||
| * an API wrapper for a collection of SMT solvers: | ||
| * https://github.com/sosy-lab/java-smt | ||
| * | ||
| * SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org> | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.sosy_lab.java_smt; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
| import org.sosy_lab.java_smt.api.proofs.ProofRule; | ||
|
|
||
| /** | ||
| * A proof rule in the proof DAG of the proof format RESOLUTE used by SMTInterpol. See: <a | ||
| * href="https://ultimate.informatik.uni-freiburg.de/smtinterpol/proof-format.html">...</a> | ||
| * | ||
| * <p>The conversion from other formats to RESOLUTE appears to be simple and as such, it is a good | ||
| * candidate for a common proof format. | ||
| * | ||
| * @author Gabriel Carpio | ||
| */ | ||
| public final class ResProofRule { | ||
|
|
||
| private static final Map<String, ResAxiom> RULE_MAP = new HashMap<>(); | ||
|
|
||
| private ResProofRule() { | ||
| // prevent instantiation | ||
| } | ||
|
|
||
| static { | ||
| for (ResAxiom rule : ResAxiom.values()) { | ||
| RULE_MAP.put(rule.getName().toLowerCase(Locale.ROOT), rule); | ||
| } | ||
| } | ||
|
|
||
| /** Any operation that proves a term. */ | ||
| public enum ResAxiom implements ProofRule { | ||
| // Resolution Rule | ||
| RESOLUTION("res", "(res t proof1 proof2)"), | ||
| ASSUME("assume", "(assume t)"), | ||
| // Logical operators | ||
| TRUE_POSITIVE("true+", "(+ true)"), | ||
| FALSE_NEGATIVE("false-", "(- false)"), | ||
| NOT_POSITIVE("not+", "(+ (not p0) + p0)"), | ||
| NOT_NEGATIVE("not-", "(- (not p0) - p0)"), | ||
| AND_POSITIVE("and+", "(+ (and p0 … pn) - p0 … - pn)"), | ||
| AND_NEGATIVE("and-", "(- (and p0 … pn) + pi)"), | ||
| OR_POSITIVE("or+", "(+ (or p0 … pn) - pi)"), | ||
| OR_NEGATIVE("or-", "(- (or p0 … pn) + p0 … + pn)"), | ||
| IMPLIES_POSITIVE("=>+", "(+ (=> p0 … pn) +/- pi)"), | ||
| IMPLIES_NEGATIVE("=>-", "(- (=> p0 … pn) - p0 … + pn)"), | ||
| EQUAL_POSITIVE1("=+1", "(+ (= p0 p1) + p0 + p1)"), | ||
| EQUAL_NEGATIVE1("=-1", "(- (= p0 p1) + p0 - p1)"), | ||
| EQUAL_POSITIVE2("=+2", "(+ (= p0 p1) - p0 - p1)"), | ||
| EQUAL_NEGATIVE2("=-2", "(- (= p0 p1) - p0 + p1)"), | ||
| XOR_POSITIVE("xor+", "(+(xor l1) +(xor l2) -(xor l3))"), | ||
| XOR_NEGATIVE("xor-", "(-(xor l1) -(xor l2) -(xor l3))"), | ||
|
|
||
| // Quantifiers | ||
| FORALL_POSITIVE("forall+", "(+ (forall x (F x)) - (F (choose x (F x))))"), | ||
| FORALL_NEGATIVE("forall-", "(- (forall x (F x)) + (F t))"), | ||
| EXISTS_POSITIVE("exists+", "(+ (exists x (F x)) - (F t))"), | ||
| EXISTS_NEGATIVE("exists-", "(- (exists x (F x)) + (F (choose x (F x))))"), | ||
|
|
||
| // Equality axioms | ||
| REFLEXIVITY("refl", "(+ (= t t))"), | ||
| SYMMETRY("symm", "(+(= t0 t1) -(= t1 t0))"), | ||
| TRANSITIVITY("trans", "(+(= t0 tn) -(= t0 t1) … -(= tn-1 tn))"), | ||
| CONGRUENCE("cong", "(+(= (f t0 … tn) (f t0' … tn')) -(= t0 t0') … -(= tn tn'))"), | ||
| EQUALITY_POSITIVE("=+", "(+ (= t0 … tn) -(= t0 t1) … -(= tn-1 tn))"), | ||
| EQUALITY_NEGATIVE("=-", "(- (= t0 … tn) +(= ti tj))"), | ||
| DISTINCT_POSITIVE("distinct+", "(+ (distinct t0 … tn) +(= t0 t1) … +(= t0 tn) … +(= tn-1 tn))"), | ||
| DISTINCT_NEGATIVE("distinct-", "(- (distinct t0 … tn) -(= ti tj))"), | ||
|
|
||
| // ITE, define-fun, annotations | ||
| ITE1("ite1", "(+(= (ite t0 t1 t2) t1) - t0)"), | ||
| ITE2("ite2", "(+(= (ite t0 t1 t2) t2) + t0)"), | ||
| DEL("del!", "(+(= (! t :annotation…) t))"), | ||
| EXPAND("expand", "(+(= (f t0 … tn) (let ((x0 t0)…(xn tn)) d)))"), | ||
|
|
||
| // Array Theory | ||
| SELECTSTORE1("selectstore1", "(+ (= (select (store a i v) i) v))"), | ||
| SELECTSTORE2("selectstore2", "(+ (= (select (store a i v) j) (select a j)) (= i j))"), | ||
| EXTDIFF("extdiff", "(+ (= a b) (- (= (select a (@diff a b)) (select b (@diff a b)))))"), | ||
| CONST("const", "(+ (= (select (@const v) i) v))"), | ||
|
|
||
| // Linear Arithmetic | ||
| POLY_ADD("poly+", "(+ (= (+ a1 ... an) a))"), | ||
| POLY_MUL("poly*", "(+ (= (* a1 ... an) a))"), | ||
| TO_REAL("to_real", "(+ (= (to_real a) a'))"), | ||
| FARKAS("farkas", "(- (<=? a1 b1) ... - (<=? an bn))"), | ||
| TRICHOTOMY("trichotomy", "(+ (< a b) (= a b) (< b a))"), | ||
| TOTAL("total", "(+ (<= a b) (< b a))"), | ||
| GT_DEF("gt_def", "(+ (= (> a b) (< b a)))"), | ||
| GE_DEF("ge_def", "(+ (= (>= a b) (<= b a)))"), | ||
| DIV_DEF("div_def", "(+ (= a (* b1 ... bn (/ a b1 ... bn))) (= b1 0) ... (= bn 0))"), | ||
| NEG_DEF("neg_def", "(+ (= (- a) (* (- 1) a)))"), | ||
| NEG_DEF2("neg_def2", "(+ (= (- a b1 ... bn) (+ a (* (- 1) b1)) ... (* (- 1) bn)))"), | ||
| ABS_DEF("abs_def", "(+ (= (abs x) (ite (< x 0) (- x) x)))"), | ||
| TOTAL_INT("total_int", "(+ (<= a c) (<= (c+1) a))"), | ||
| TO_INT_LOW("to_int_low", "(+ (<= (to_real (to_int x)) x))"), | ||
| TO_INT_HIGH("to_int_high", "(+ (< x (+ (to_real (to_int x)) 1.0)))"), | ||
| DIV_LOW("div_low", "(+ (<= (* d (div x d)) x) (= d 0))"), | ||
| DIV_HIGH("div_high", "(+ (< x (+ (* d (div x d)) (abs d))) (= d 0))"), | ||
| MOD_DEF("mod_def", "(+ (= (mod x d) (- x (* d (div x d)))) (= d 0))"), | ||
| DIVISIBLE_DEF("divisible_def", "(+ (= ((_ divisible c) x) (= x (* c (div x c)))))"), | ||
| EXPAND_IS_INT("expand_is_int", "(+ (= (is_int x) (= x (to_real (to_int x)))))"), | ||
|
|
||
| // Data Types | ||
| DT_PROJECT("dt_project", "(= (seli (cons a1 ... an)) ai)"), | ||
| DT_CONS("dt_cons", "(~ ((_ is cons) x), (= (cons (sel1 x) ... (seln x)) x))"), | ||
| DT_TEST_CONS("dt_test_cons", "((_ is cons) (cons a1 ... an))"), | ||
| DT_TEST_CONS_PRIME("dt_test_cons_prime", "(~ ((_ is cons') (cons a1 ... an)))"), | ||
| DT_EXHAUST("dt_exhaust", "((_ is cons1) x), ..., ((_ is consn) x)"), | ||
| DT_ACYCLIC("dt_acyclic", "(~ (= (cons ... x ...) x))"), | ||
| DT_MATCH( | ||
| "dt_match", | ||
| "(= (match t ((p1 x1) c1) ...) (ite ((_ is p1) t) (let (x1 (sel1 t)) c1) ...))"); | ||
|
|
||
| private final String name; | ||
| private final String formula; | ||
|
|
||
| ResAxiom(String pName, String pFormula) { | ||
| name = pName; | ||
| formula = pFormula; | ||
| } | ||
|
|
||
| @Override | ||
| public String getName() { | ||
| return name; | ||
| } | ||
|
|
||
| @Override | ||
| public String getFormula() { | ||
| return formula; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves a ProofRule by its name. | ||
| * | ||
| * @param name The name of the proof rule. | ||
| * @return The matching ProofRule. | ||
| * @throws NullPointerException if the name is null. | ||
| * @throws IllegalArgumentException if the name does not match any rule. | ||
| */ | ||
| public static ResAxiom getFromName(String name) { | ||
|
|
||
| ResAxiom rule = RULE_MAP.get(name.toLowerCase(Locale.ROOT)); | ||
| if (rule == null) { | ||
|
||
| throw new IllegalArgumentException("Rule not found or not specified: " + name); | ||
| } | ||
|
|
||
| return rule; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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: 2024 Dirk Beyer <https://www.sosy-lab.org> | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.sosy_lab.java_smt; | ||
|
|
||
| import java.util.Objects; | ||
| import org.sosy_lab.java_smt.ResProofRule.ResAxiom; | ||
| import org.sosy_lab.java_smt.api.Formula; | ||
| import org.sosy_lab.java_smt.api.proofs.ProofNode; | ||
| import org.sosy_lab.java_smt.api.proofs.ProofRule; | ||
| import org.sosy_lab.java_smt.basicimpl.AbstractProofDAG; | ||
|
|
||
| /** | ||
| * This class represents a resolution proof DAG. Its nodes might be of the type {@link | ||
| * AxiomProofNode} or {@link ResolutionProofNode}. It is used to represent proofs based on the | ||
| * RESOLUTE proof format from SMTInterpol. | ||
| * | ||
| * @see ResProofRule | ||
| */ | ||
| @SuppressWarnings("all") | ||
|
||
| public class ResolutionProofDAG extends AbstractProofDAG { | ||
| // Work in progress. The functionality of producing just nodes should be provided first. | ||
| // The idea is to provide extended functionality (by providng a set of edges for example). | ||
|
|
||
| public static class ResolutionProofNode extends AbstractProofNode implements ProofNode { | ||
|
|
||
| private final Formula pivot; | ||
|
|
||
| public ResolutionProofNode(Formula formula, Formula pivot) { | ||
| super(ResAxiom.RESOLUTION, Objects.requireNonNull(formula, "Formula must not be null")); | ||
| this.pivot = Objects.requireNonNull(pivot, "Pivot must not be null"); | ||
|
||
| } | ||
|
|
||
| public Formula getPivot() { | ||
| return pivot; | ||
| } | ||
|
|
||
| @Override | ||
| public ProofRule getRule() { | ||
| return super.getRule(); | ||
| } | ||
| } | ||
|
|
||
| public static class AxiomProofNode extends AbstractProofNode implements ProofNode { | ||
|
|
||
| public AxiomProofNode(ResAxiom rule, Formula formula) { | ||
| super( | ||
| Objects.requireNonNull(rule, "Rule must not be null"), | ||
| Objects.requireNonNull(formula, "Formula must not be null")); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -282,7 +282,8 @@ private SolverContext generateContext0(Solvers solverToCreate) | |
| case Z3: | ||
| return Z3SolverContext.create( | ||
| logger, | ||
| config, | ||
| Configuration.builder().copyFrom(config) | ||
|
||
| .setOption("solver.z3.requireProofs", "true").build(), | ||
| shutdownNotifier, | ||
| logfile, | ||
| randomSeed, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,6 +52,9 @@ enum ProverOptions { | |
| */ | ||
| GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS, | ||
|
|
||
| /** Whether the solver should generate proofs for unsatisfiable formulas. */ | ||
|
||
| GENERATE_PROOFS, | ||
|
|
||
| /** Whether the solver should enable support for formulae build in SL theory. */ | ||
| ENABLE_SEPARATION_LOGIC | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| /* | ||
| * This file is part of JavaSMT, | ||
| * an API wrapper for a collection of SMT solvers: | ||
| * https://github.com/sosy-lab/java-smt | ||
| * | ||
| * SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org> | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.sosy_lab.java_smt.api.proofs; | ||
|
|
||
| import java.util.Collection; | ||
| import org.sosy_lab.java_smt.api.proofs.visitors.ProofVisitor; | ||
|
|
||
| /** | ||
| * A DAG representing a proof. Each node in the DAG is a {@link ProofNode} and each edge is a | ||
| * directed edge from a parent node to a child node. | ||
| */ | ||
| public interface ProofDAG { | ||
|
|
||
| /** | ||
| * Add a node to the DAG. | ||
| * | ||
| * @param node The node to be added to the DAG. | ||
| */ | ||
| void addNode(ProofNode node); | ||
|
|
||
| /** | ||
| * Get a node from the DAG. | ||
| * | ||
| * @param nodeId The ID of the node. | ||
| * @return A {@link ProofNode} based on its ID. | ||
| */ | ||
| ProofNode getNode(int nodeId); | ||
|
|
||
| /** | ||
| * Add an edge to the DAG. | ||
| * | ||
| * @param parentNodeId Predecessor | ||
| * @param childNodeId Successor | ||
| */ | ||
| void addEdge(int parentNodeId, int childNodeId); | ||
|
|
||
| /** Get all nodes in the DAG. */ | ||
| Collection<ProofNode> getNodes(); | ||
|
|
||
| void accept(ProofVisitor visitor); // To allow traversal of the entire DAG | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* | ||
| * This file is part of JavaSMT, | ||
| * an API wrapper for a collection of SMT solvers: | ||
| * https://github.com/sosy-lab/java-smt | ||
| * | ||
| * SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org> | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.sosy_lab.java_smt.api.proofs; | ||
|
|
||
| import org.sosy_lab.java_smt.ResProofRule.ResAxiom; | ||
| import org.sosy_lab.java_smt.ResolutionProofDAG.AxiomProofNode; | ||
| import org.sosy_lab.java_smt.ResolutionProofDAG.ResolutionProofNode; | ||
| import org.sosy_lab.java_smt.api.Formula; | ||
| import org.sosy_lab.java_smt.api.ProverEnvironment; | ||
| import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5ProofNode; | ||
|
|
||
| /** | ||
| * A factory for creating proof nodes. The methods of this class are to be used in the ProofNode | ||
| * implementations of each solver to be able to convert the proof object given back by the solver to | ||
| * a proof in JavaSMT. | ||
| * | ||
| * @param <T> The type of the proof object. | ||
| */ | ||
| public class ProofFactory<T> { | ||
|
|
||
| // private final FormulaCreator<?, ?, ?, ?> formulaCreator; | ||
| private final ProverEnvironment prover; | ||
| private final Solvers solver; | ||
|
|
||
| enum Solvers { | ||
|
||
| OPENSMT, | ||
| MATHSAT5, | ||
| SMTINTERPOL, | ||
| Z3, | ||
| PRINCESS, | ||
| BOOLECTOR, | ||
| CVC4, | ||
| CVC5, | ||
| YICES2, | ||
| BITWUZLA | ||
| } | ||
|
|
||
| protected ProofFactory(ProverEnvironment pProver, String pSolver) { | ||
| if (pProver == null) { | ||
|
||
| throw new NullPointerException("ProverEnvironment must not be null"); | ||
| } | ||
| if (pSolver == null) { | ||
| throw new NullPointerException("Solver name must not be null"); | ||
| } | ||
| prover = pProver; | ||
| solver = Solvers.valueOf(pSolver); | ||
| } | ||
|
|
||
| protected ProofNode createProofNode(T proof) { | ||
| return createProofNode0(proof); | ||
| } | ||
|
|
||
| protected ProofNode createProofNode0(T proof) { | ||
|
|
||
| switch (solver) { | ||
| case MATHSAT5: | ||
| return Mathsat5ProofNode.fromMsatProof(prover, (long) proof); | ||
| case CVC5: | ||
| return null; | ||
|
||
| default: | ||
| throw new UnsupportedOperationException("Unsupported solver: " + solver); | ||
| } | ||
| } | ||
|
|
||
| protected static ProofNode createSourceNode(ResAxiom rule, Formula formula) { | ||
| return new AxiomProofNode(rule, formula); | ||
| } | ||
|
|
||
| protected static ProofNode createResolutionNode(Formula formula, Formula pivot) { | ||
| return new ResolutionProofNode(formula, pivot); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use this to write out all axiom cases and then add the data structure statically. That way we as devs can actually read the cases.
This static block could be added as a unit-test (new native API test class) for SMTInterpol that checks that the data-structure is correct and is not missing a case.
Also, plain
toLowerCase()without arguments is fine, alternatively a static language (ENGLISH). We don't want this to break based on the language of the root system.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something was complaining about the toLowerCase() without arguments in the CI. I will change the parameter to ENGLISH