-
Notifications
You must be signed in to change notification settings - Fork 56
Add logic, engine and further options for Z3 #626
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
Open
baierd
wants to merge
42
commits into
master
Choose a base branch
from
613-feature-request-setting-solver-logic-via-javasmt
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
57cfd21
Allow setting custom options in tests with automatic re-initializatio…
baierd e8abb4e
Add ability to access most Z3 options and their types and description…
baierd f9a680b
Add Z3 options for logic, engine and "further options" with arbitrary…
baierd 072c528
Add ability to Z3 provers to switch to HORN solving with spacer
baierd 74b3ea7
Add todo about option types in Z3SolverContext
baierd dc19034
Add prototype for SolverNativeOptionsTest
baierd fe195a9
Simplify Z3 options resolving by adding the only cases in which the o…
baierd 333d6be
Remove done TODO and rename method that transforms "further" options …
baierd cc399c6
Add Z3 tactic options (info) getter and remove done TODO
baierd 3612918
Add more option constants and block them for users, and add the optio…
baierd 6045d93
Remove options info getter in Z3FormulaManager to declutter the manager
baierd 4ac91fd
Use solver with logic in all cases in Z3 that are not "all" and add c…
baierd b73d0ad
Rework and add more tests to SolverNativeOptionsTest
baierd 55bd6e1
Unify setting additional options in SolverBasedTest0 and add more ver…
baierd 1f468eb
Add explicit Z3 Prover constructor arguments for engine and logic (as…
baierd 2bfd8fe
Refactor logic, engine and additional option resolving in Z3SolverCon…
baierd a96051e
Add Z3 specific logic tests that show that setting a logic can be ben…
baierd 5613c8f
Add smt2 file provided by Thomas Haar (Dartagnan) for tests
baierd c91e7d0
Add Z3 native API tests for engine spacer and options
baierd 62dcd1e
Merge branch 'master' into 613-feature-request-setting-solver-logic-v…
baierd c66319e
Add doc for (Z3) native tests and remove test that exists twice + add…
baierd 42c797f
Add another smt2 file and a test that shows that Z3 solves much faste…
baierd 4cfc98e
Modify SMTLIB2 file for tests so that the current parser accepts it
baierd de46233
Use formater of checkArgument to make message gen lazy in Z3SolverCon…
baierd dbaba17
Rename Z3_ENGINE into ENGINE (as it is only used in Z3 and checkstyle…
baierd a7dd394
Simplify method for creating new test environments with set configura…
baierd 4cbac9f
Increase allowed amount of arguments in constructors in checkstyle to…
baierd 97af0da
Fix naming of vars and JavaDoc in Z3NativeApiTest
baierd 374aec8
Add timeouts to tests that change the default solving time to actuall…
baierd 9d9551b
Switch assertion to hasSize() in SolverNativeOptionsTest
baierd cb48958
Allow Z3NativeApiTest to fail loading the libraries and not fail the …
baierd fa9ad2d
Apply refaster suggestions to Z3NativeApiTest
baierd c61c093
Merge branch 'master' into 613-feature-request-setting-solver-logic-v…
baierd 7dd2127
Use new """ type string block for HORN SMT2 problem in SolverNativeOp…
baierd 395da31
Add license files for 2 SMT2 files provided by Thomas Haas via Dartagnan
baierd ce0b38f
Improve license files for 2 SMT2 files provided by Thomas Haas via Da…
baierd e7b9e09
Add CC-BY-4.0 license to reuse LICENSE folder
baierd 2836687
Improve string composition in SolverNativeOptionsTest test
baierd 51c3aee
Merge branch 'master' into 613-feature-request-setting-solver-logic-v…
baierd 1619e68
Update smt2 files and licenses donated by ThomasHaas (Dartagnan) with…
baierd 4273dfa
Remove set-info based license in 2 smt2 files as discussed in https:/…
baierd 3ca8c0b
Increase timeout by 1.5s in a test in SolverNativeOptionsTest as the …
baierd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
196 changes: 196 additions & 0 deletions
196
src/org/sosy_lab/java_smt/solvers/z3/Z3NativeApiTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| /* | ||
| * 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.solvers.z3; | ||
|
|
||
| import static com.google.common.truth.Truth.assertThat; | ||
| import static org.sosy_lab.java_smt.solvers.z3.Z3SolverContext.doubleOptions; | ||
|
|
||
| import com.google.common.base.Splitter; | ||
| import com.google.common.collect.ImmutableList; | ||
| import com.google.common.collect.ImmutableSet; | ||
| import com.google.common.collect.Sets; | ||
| import com.microsoft.z3.BoolSort; | ||
| import com.microsoft.z3.Context; | ||
| import com.microsoft.z3.Expr; | ||
| import com.microsoft.z3.FuncDecl; | ||
| import com.microsoft.z3.Global; | ||
| import com.microsoft.z3.IntSort; | ||
| import com.microsoft.z3.Model; | ||
| import com.microsoft.z3.Params; | ||
| import com.microsoft.z3.Solver; | ||
| import com.microsoft.z3.Sort; | ||
| import com.microsoft.z3.Status; | ||
| import java.util.ArrayDeque; | ||
| import java.util.Deque; | ||
| import java.util.HashSet; | ||
| import java.util.List; | ||
| import java.util.Set; | ||
| import java.util.stream.Stream; | ||
| import org.junit.AssumptionViolatedException; | ||
| import org.junit.BeforeClass; | ||
| import org.junit.Test; | ||
| import org.sosy_lab.common.NativeLibraries; | ||
|
|
||
| public class Z3NativeApiTest { | ||
|
|
||
| @BeforeClass | ||
| public static void loadLibraries() { | ||
| try { | ||
| NativeLibraries.loadLibrary("z3"); | ||
| NativeLibraries.loadLibrary("z3java"); | ||
| } catch (UnsatisfiedLinkError e) { | ||
| throw new AssumptionViolatedException("Z3 is not available", e); | ||
| } | ||
|
|
||
| System.setProperty("z3.skipLibraryLoad", "true"); | ||
| } | ||
|
|
||
| @Test | ||
| public void interpolationTest() { | ||
| // Translation of an example by Arie Gurfinkel for calculating interpolants with spacer in Z3 | ||
| // See https://github.com/agurfinkel/spacer-on-jupyter/blob/master/Dagstuhl2019.ipynb for the | ||
| // original Python code | ||
|
|
||
| try (Context env = new Context()) { | ||
| Global.setParameter("smt.random_seed", "42"); | ||
| Global.setParameter("model.compact", "false"); | ||
|
|
||
| Expr<IntSort> a = env.mkIntConst("a"); | ||
| Expr<IntSort> b = env.mkIntConst("b"); | ||
| Expr<IntSort> x = env.mkIntConst("x"); | ||
|
|
||
| Expr<BoolSort> formulasA = env.mkAnd(env.mkLt(a, x), env.mkLt(x, b)); | ||
| Expr<BoolSort> formulasB = env.mkLt(b, a); | ||
|
|
||
| Expr<BoolSort> interpolant = interpolate(env, formulasA, formulasB); | ||
|
|
||
| assertThat(validate(env, formulasA, formulasB, interpolant)).isTrue(); | ||
| } | ||
| } | ||
|
|
||
| // Test that we correctly discern between int and double for options set in Z3, even after | ||
| // updates! This is very much a white-box test that utilizes internal info about the | ||
| // Z3SolverContext implementation. | ||
| // If this fails: update the doubleOptions set with the missing option! | ||
| @Test | ||
| public void z3OptionsTypeTest() { | ||
| try (Context env = new Context()) { | ||
| String options = env.mkSolver().getHelp(); | ||
| options += env.mkSimplifier("propagate-values").getHelp(); | ||
| options += env.mkTactic("simplify").getHelp(); | ||
| options += env.mkFixedpoint().getHelp(); | ||
| options += env.mkOptimize().getHelp(); | ||
|
|
||
| Set<String> optionsByLine = ImmutableSet.copyOf(Splitter.on('\n').splitToList(options)); | ||
| ImmutableSet.Builder<String> doubleOptionsExtracted = ImmutableSet.builder(); | ||
| for (String line : optionsByLine) { | ||
| // Z3 options encode the type always following the option name, e.g.: option.name (type) | ||
| if (line.contains("(double)")) { | ||
| List<String> optionAndSuffix = Splitter.on(" (double)").splitToList(line); | ||
| // Make sure there is only one (double) type declaration in the line | ||
| assertThat(optionAndSuffix).hasSize(2); | ||
| doubleOptionsExtracted.add(optionAndSuffix.get(0)); | ||
| } | ||
| } | ||
|
|
||
| assertThat(doubleOptions).containsExactlyElementsIn(doubleOptionsExtracted.build()); | ||
| } | ||
| } | ||
|
|
||
| private Set<Expr<?>> getFreeVars(Expr<?> expr) { | ||
| Deque<Expr<?>> worklist = new ArrayDeque<>(); | ||
| worklist.push(expr); | ||
|
|
||
| Set<Expr<?>> vars = new HashSet<>(); | ||
|
|
||
| while (!worklist.isEmpty()) { | ||
| Expr<?> f = worklist.removeFirst(); | ||
| if (f.isConst()) { | ||
| vars.add(f); | ||
| } | ||
| for (Expr<?> c : f.getArgs()) { | ||
| worklist.addLast(c); | ||
| } | ||
| } | ||
| return vars; | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| private Model solveHornClauses(Context env, List<Expr<BoolSort>> chc) { | ||
| Params opts = env.mkParams(); | ||
| opts.add("engine", "spacer"); | ||
| opts.add("spacer.order_children", 2); | ||
| opts.add("xform.inline_eager", false); | ||
| opts.add("xform.inline_linear", false); | ||
| opts.add("xform.slice", false); | ||
| opts.add("spacer.max_level", 10); | ||
|
|
||
| Solver solver = env.mkSolver("HORN"); | ||
| solver.setParameters(opts); | ||
|
|
||
| for (Expr<BoolSort> c : chc) { | ||
| solver.add(c); | ||
| } | ||
| Status status = solver.check(); | ||
|
|
||
| assertThat(status).isEqualTo(Status.SATISFIABLE); | ||
|
|
||
| return solver.getModel(); | ||
| } | ||
|
|
||
| private Expr<BoolSort> interpolate( | ||
| Context env, Expr<BoolSort> formulasA, Expr<BoolSort> formulasB) { | ||
| Set<Expr<?>> varsA = getFreeVars(formulasA); | ||
| Set<Expr<?>> varsB = getFreeVars(formulasB); | ||
|
|
||
| Expr<?>[] shared = Sets.intersection(varsA, varsB).toArray(new Expr<?>[0]); | ||
|
|
||
| FuncDecl<BoolSort> symbolItp = | ||
| env.mkFuncDecl( | ||
| "Itp", Stream.of(shared).map(Expr::getSort).toArray(Sort[]::new), env.mkBoolSort()); | ||
| Expr<BoolSort> constant = symbolItp.apply(shared); | ||
|
|
||
| Expr<BoolSort> left = | ||
| env.mkForall( | ||
| varsA.toArray(new Expr<?>[0]), | ||
| env.mkImplies(formulasA, constant), | ||
| 1, | ||
| null, | ||
| null, | ||
| null, | ||
| null); | ||
|
|
||
| Expr<BoolSort> right = | ||
| env.mkForall( | ||
| varsB.toArray(new Expr<?>[0]), | ||
| env.mkImplies(constant, env.mkNot(formulasB)), | ||
| 1, | ||
| null, | ||
| null, | ||
| null, | ||
| null); | ||
|
|
||
| Model model = solveHornClauses(env, ImmutableList.of(left, right)); | ||
| return model.eval(constant, false); | ||
| } | ||
|
|
||
| /** Validate that itp is an interpolant for formula(s) A and formula(s) B. */ | ||
| private boolean validate( | ||
| Context env, Expr<BoolSort> formulasA, Expr<BoolSort> formulasB, Expr<BoolSort> itp) { | ||
| Solver solver = env.mkSolver("QF_LIA"); | ||
| return solver.check(env.mkNot(env.mkImplies(formulasA, itp))).equals(Status.UNSATISFIABLE) | ||
| && solver | ||
| .check(env.mkNot(env.mkImplies(itp, env.mkNot(formulasB)))) | ||
| .equals(Status.UNSATISFIABLE) | ||
| && Sets.intersection(getFreeVars(formulasA), getFreeVars(formulasB)) | ||
| .containsAll(getFreeVars(itp)); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Is this still used? Or has it been replaced by
Z3SolverContext.getAllZ3Options()?