Skip to content

Commit ce691f4

Browse files
authored
Solver configuration api (#34)
* KModel toString/equals/hashCode * Solver configuration api * Fix example and documentation * Solver configuration docs * Update version * Fix Fp custom sized decl * Skip bad test case * Handle failed worker initialization * Fix test data cache * Cache downloaded testData * Cache on all os * Handle hard timeout in check-sat as Unknown
1 parent 929a249 commit ce691f4

File tree

32 files changed

+668
-107
lines changed

32 files changed

+668
-107
lines changed

.github/workflows/release.yml

+1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ jobs:
3131
ksmt-core/build/release/**/ksmt-core-*.jar
3232
ksmt-z3/build/release/**/ksmt-z3-*.jar
3333
ksmt-bitwuzla/build/release/**/ksmt-bitwuzla-*.jar
34+
ksmt-runner/build/release/**/ksmt-runner-*.jar
3435

.github/workflows/run-long-tests.yml

+58-13
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ on:
2020
type: number
2121
default: 170000
2222

23+
env:
24+
TEST_DATA_REVISION: 0.2.1
25+
2326
jobs:
2427
setup:
2528
runs-on: ubuntu-latest
@@ -58,53 +61,95 @@ jobs:
5861
TEST_ARRAY+="]"
5962
echo "tests=$TEST_ARRAY" >> $GITHUB_OUTPUT
6063
61-
run_tests:
62-
needs: setup
63-
continue-on-error: true
64+
prepare_test_data:
6465
strategy:
6566
matrix:
6667
os: [ ubuntu-latest, windows-latest ]
67-
test: ${{ fromJSON(needs.setup.outputs.matrix-tests) }}
68-
chunk: ${{ fromJSON(needs.setup.outputs.matrix-chunks) }}
69-
70-
name: Run ${{ matrix.test }}[${{ matrix.chunk }}] on ${{ matrix.os }}
7168

7269
runs-on: ${{ matrix.os }}
7370

7471
steps:
7572
- uses: actions/checkout@v3
7673

74+
- name: Prepare test data (cache)
75+
id: test-data-cache
76+
uses: actions/cache@v3
77+
env:
78+
cache-name: cache-test-data
79+
with:
80+
key: test-data-${{ env.TEST_DATA_REVISION }}-${{ matrix.os }}
81+
path: ksmt-test/testData/testData.zip
82+
7783
- name: Set up JDK 1.8
84+
if: steps.test-data-cache.outputs.cache-hit != 'true'
7885
uses: actions/setup-java@v3
7986
with:
8087
java-version: 8
8188
distribution: 'zulu'
8289
cache: gradle
8390

84-
- name: Build project
91+
- name: Prepare test data (download)
92+
if: steps.test-data-cache.outputs.cache-hit != 'true'
8593
uses: gradle/gradle-build-action@v2
8694
with:
8795
arguments: |
88-
build
96+
:ksmt-test:downloadPreparedSmtLibBenchmarkTestData
8997
--no-daemon
98+
-PtestDataRevision=${{ env.TEST_DATA_REVISION }}
99+
100+
run_tests:
101+
needs: [setup, prepare_test_data]
102+
continue-on-error: true
103+
strategy:
104+
matrix:
105+
os: [ ubuntu-latest, windows-latest ]
106+
test: ${{ fromJSON(needs.setup.outputs.matrix-tests) }}
107+
chunk: ${{ fromJSON(needs.setup.outputs.matrix-chunks) }}
108+
109+
name: Run ${{ matrix.test }}[${{ matrix.chunk }}] on ${{ matrix.os }}
110+
111+
runs-on: ${{ matrix.os }}
112+
113+
steps:
114+
- uses: actions/checkout@v3
90115

91116
- name: Prepare test data (cache)
92117
id: test-data-cache
93118
uses: actions/cache@v3
94119
env:
95120
cache-name: cache-test-data
96121
with:
97-
key: test-data-0.2.1-${{ matrix.os }}
98-
path: ksmt-test/testData
122+
key: test-data-${{ env.TEST_DATA_REVISION }}-${{ matrix.os }}
123+
path: ksmt-test/testData/testData.zip
99124

100-
- name: Prepare test data (download)
125+
- name: Check test data downloaded
101126
if: steps.test-data-cache.outputs.cache-hit != 'true'
127+
run: |
128+
echo "Test data is not available"
129+
exit 1
130+
131+
- name: Set up JDK 1.8
132+
uses: actions/setup-java@v3
133+
with:
134+
java-version: 8
135+
distribution: 'zulu'
136+
cache: gradle
137+
138+
# Since ksmt-test/testData/testData.zip exists task will not download it again
139+
- name: Prepare test data (unpack)
102140
uses: gradle/gradle-build-action@v2
103141
with:
104142
arguments: |
105143
:ksmt-test:downloadPreparedSmtLibBenchmarkTestData
106144
--no-daemon
107-
-PtestDataRevision=0.2.1
145+
-PtestDataRevision=${{ env.TEST_DATA_REVISION }}
146+
147+
- name: Build project
148+
uses: gradle/gradle-build-action@v2
149+
with:
150+
arguments: |
151+
build
152+
--no-daemon
108153
109154
- name: Run ${{ matrix.test }}
110155
uses: gradle/gradle-build-action@v2

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ repositories {
1414
}
1515

1616
// core
17-
implementation("com.github.UnitTestBot.ksmt:ksmt-core:0.2.1")
17+
implementation("com.github.UnitTestBot.ksmt:ksmt-core:0.3.0")
1818
// z3 solver
19-
implementation("com.github.UnitTestBot.ksmt:ksmt-z3:0.2.1")
19+
implementation("com.github.UnitTestBot.ksmt:ksmt-z3:0.3.0")
2020
```
2121

2222
## Usage
@@ -52,8 +52,8 @@ val array by mkArraySort(intSort, intSort)
5252
val index by intSort
5353
val value by intSort
5454

55-
val expr = (array.select(index - 1.intExpr) lt value) and
56-
(array.select(index + 1.intExpr) gt value)
55+
val expr = (array.select(index - 1.expr) lt value) and
56+
(array.select(index + 1.expr) gt value)
5757
```
5858
Check out our [example project](examples) for more complicated examples.
5959

Requirements.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
| [CVC5 solver support](#cvc5-solver-support) | TODO |
1414
| [External process runner](#external-process-runner) | Done |
1515
| [Portfolio solver](#portfolio-solver) | TODO |
16-
| [Solver configuration API](#solver-configuration-api) | In progress |
16+
| [Solver configuration API](#solver-configuration-api) | Done |
1717
| [Deployment](#deployment) | Done partially |
1818
| [Expression simplification / evaluation](#expression-simplification--evaluation) | Done partially |
1919
| [Performance tests](#performance-tests) | TODO |

buildSrc/src/main/kotlin/SmtLibBenchmarkUtil.kt

+2-5
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,16 @@ fun Project.usePreparedSmtLibBenchmarkTestData(path: File) = tasks.register("smt
5454
}
5555
}
5656

57-
fun Project.downloadPreparedSmtLibBenchmarkTestData(path: File, version: String) =
57+
fun Project.downloadPreparedSmtLibBenchmarkTestData(downloadPath: File, testDataPath: File, version: String) =
5858
tasks.register("downloadPreparedSmtLibBenchmarkTestData") {
5959
doLast {
60-
path.mkdir()
61-
6260
val benchmarksUrl = "https://github.com/UnitTestBot/ksmt/releases/download/$version/benchmarks.zip"
63-
val downloadPath = buildDir.resolve("benchmarks.zip")
6461

6562
download(benchmarksUrl, downloadPath)
6663

6764
copy {
6865
from(zipTree(downloadPath))
69-
into(path)
66+
into(testDataPath)
7067
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
7168
}
7269
}

buildSrc/src/main/kotlin/org.ksmt.ksmt-base.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ plugins {
99
}
1010

1111
group = "org.ksmt"
12-
version = "0.2.1"
12+
version = "0.3.0"
1313

1414
repositories {
1515
mavenCentral()

docs/getting-started.md

+35-12
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ repositories {
1818
```kotlin
1919
dependencies {
2020
// core
21-
implementation("com.github.UnitTestBot.ksmt:ksmt-core:0.2.1")
21+
implementation("com.github.UnitTestBot.ksmt:ksmt-core:0.3.0")
2222
}
2323
```
2424

2525
#### 3. Add one or more SMT solver dependencies:
2626
```kotlin
2727
dependencies {
2828
// z3
29-
implementation("com.github.UnitTestBot.ksmt:ksmt-z3:0.2.1")
29+
implementation("com.github.UnitTestBot.ksmt:ksmt-z3:0.3.0")
3030
// bitwuzla
31-
implementation("com.github.UnitTestBot.ksmt:ksmt-bitwuzla:0.2.1")
31+
implementation("com.github.UnitTestBot.ksmt:ksmt-bitwuzla:0.3.0")
3232
}
3333
```
3434
SMT solver specific packages are provided with solver native binaries.
@@ -51,19 +51,24 @@ In this example, we want to create an expression
5151
over Boolean variable `a` and integer variables `b` and `c`.
5252

5353
```kotlin
54+
import org.ksmt.utils.getValue
55+
5456
with(ctx) {
5557
// create symbolic variables
5658
val a by boolSort
5759
val b by intSort
5860
val c by intSort
5961

6062
// create expression
61-
val constraint = a and (b ge c + 3.intExpr)
63+
val constraint = a and (b ge c + 3.expr)
6264
}
6365
```
6466
All KSMT expressions are typed and incorrect terms (e.g. `and` with integer arguments)
6567
result in a compile-time error.
6668

69+
Note the use of `import getValue`, which is required for the `by` syntax.
70+
Alternatively, `mkConst(name, sort)` can be used.
71+
6772
### Working with SMT solvers
6873

6974
To check SMT formula satisfiability we need to instantiate an SMT solver.
@@ -112,10 +117,10 @@ with(ctx) {
112117
// create symbolic variables
113118
val cond1 by boolSort
114119
val cond2 by boolSort
115-
val a by mkBv32Sort()
116-
val b by mkBv32Sort()
117-
val c by mkBv32Sort()
118-
val goal by mkBv32Sort()
120+
val a by bv32Sort
121+
val b by bv32Sort
122+
val c by bv32Sort
123+
val goal by bv32Sort
119124

120125
KZ3Solver(this).use { solver ->
121126
// a == 0
@@ -212,10 +217,10 @@ with(ctx) {
212217
// create symbolic variables
213218
val cond1 by boolSort
214219
val cond2 by boolSort
215-
val a by mkBv32Sort()
216-
val b by mkBv32Sort()
217-
val c by mkBv32Sort()
218-
val goal by mkBv32Sort()
220+
val a by bv32Sort
221+
val b by bv32Sort
222+
val c by bv32Sort
223+
val goal by bv32Sort
219224

220225
KZ3Solver(this).use { solver ->
221226
// a == 0
@@ -357,3 +362,21 @@ with(ctx) {
357362
val assertions = KZ3SMTLibParser().parse(formula)
358363
}
359364
```
365+
366+
### Solver configuration
367+
368+
KSMT provides an API for modifying solver-specific parameters.
369+
Since the parameters and their correct values are solver-specific
370+
KSMT does not perform any checks.
371+
See the corresponding solver documentation for a list of available options.
372+
373+
```kotlin
374+
with(ctx) {
375+
KZ3Solver(this).use { solver ->
376+
solver.configure {
377+
// set Z3 solver parameter random_seed to 42
378+
setZ3Option("random_seed", 42)
379+
}
380+
}
381+
}
382+
```

examples/build.gradle.kts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
plugins {
22
kotlin("jvm") version "1.7.20"
3-
`java-library`
3+
java
44
}
55

66
repositories {
@@ -10,9 +10,9 @@ repositories {
1010

1111
dependencies {
1212
// core
13-
implementation("com.github.UnitTestBot.ksmt:ksmt-core:0.2.1")
13+
implementation("com.github.UnitTestBot.ksmt:ksmt-core:0.3.0")
1414
// z3 solver
15-
implementation("com.github.UnitTestBot.ksmt:ksmt-z3:0.2.1")
15+
implementation("com.github.UnitTestBot.ksmt:ksmt-z3:0.3.0")
1616
}
1717

1818
java {

examples/src/main/java/Sudoku.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static void main(String[] args) {
5353
final List<KExpr<KBoolSort>> symbolAssignments = assignSymbols(ctx, symbols, initialGrid);
5454

5555
// Create Z3 SMT solver instance.
56-
try (final KSolver solver = new KZ3Solver(ctx)) {
56+
try (final KSolver<?> solver = new KZ3Solver(ctx)) {
5757
// Assert all constraints.
5858
rules.forEach(solver::assertExpr);
5959
symbolAssignments.forEach(solver::assertExpr);
@@ -79,7 +79,7 @@ private static List<List<KExpr<KIntSort>>> createSymbolicGrid(final KContext ctx
7979
for (int row = 0; row < SIZE; row++) {
8080
final List<KExpr<KIntSort>> gridRow = new ArrayList<>();
8181
for (int col = 0; col < SIZE; col++) {
82-
gridRow.add(ctx.mkConst(ctx.getIntSort(), "x_" + row + "_" + col));
82+
gridRow.add(ctx.mkConst("x_" + row + "_" + col, ctx.getIntSort()));
8383
}
8484
grid.add(gridRow);
8585
}
@@ -93,8 +93,8 @@ private static List<KExpr<KBoolSort>> sudokuRules(final KContext ctx,
9393
final Stream<KExpr<KBoolSort>> symbolConstraints = symbols
9494
.stream().flatMap(Collection::stream)
9595
.map(cell -> ctx.and(
96-
ctx.ge(cell, ctx.getIntExpr(1)),
97-
ctx.le(cell, ctx.getIntExpr(9))));
96+
ctx.ge(cell, ctx.getExpr(1)),
97+
ctx.le(cell, ctx.getExpr(9))));
9898

9999
// Each row contains distinct numbers.
100100
final Stream<KExpr<KBoolSort>> rowDistinctConstraints = symbols.stream()
@@ -138,7 +138,7 @@ private static List<KExpr<KBoolSort>> assignSymbols(final KContext ctx,
138138
for (int col = 0; col < SIZE; col++) {
139139
int cell = grid.get(row).get(col);
140140
if (cell != EMPTY_CELL_VALUE) {
141-
assignments.add(ctx.eq(symbols.get(row).get(col), ctx.getIntExpr(cell)));
141+
assignments.add(ctx.eq(symbols.get(row).get(col), ctx.getExpr(cell)));
142142
}
143143
}
144144
}

examples/src/main/kotlin/GettingStartedExample.kt

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import org.ksmt.KContext
22
import org.ksmt.solver.z3.KZ3Solver
3+
import org.ksmt.utils.getValue
34
import kotlin.time.Duration.Companion.seconds
45

56
fun main() {
@@ -22,7 +23,7 @@ private fun basicSolverUsageExample(ctx: KContext) =
2223
val c by intSort
2324

2425
// create expression
25-
val constraint = a and (b ge c + 3.intExpr)
26+
val constraint = a and (b ge c + 3.expr)
2627

2728
KZ3Solver(this).use { solver -> // create s Z3 Smt solver instance
2829
// assert expression
@@ -46,10 +47,10 @@ private fun pushPopIncrementalExample(ctx: KContext) =
4647
// create symbolic variables
4748
val cond1 by boolSort
4849
val cond2 by boolSort
49-
val a by mkBv32Sort()
50-
val b by mkBv32Sort()
51-
val c by mkBv32Sort()
52-
val goal by mkBv32Sort()
50+
val a by bv32Sort
51+
val b by bv32Sort
52+
val c by bv32Sort
53+
val goal by bv32Sort
5354

5455
KZ3Solver(this).use { solver ->
5556
// a == 0
@@ -138,10 +139,10 @@ private fun assumptionsIncrementalExample(ctx: KContext) =
138139
// create symbolic variables
139140
val cond1 by boolSort
140141
val cond2 by boolSort
141-
val a by mkBv32Sort()
142-
val b by mkBv32Sort()
143-
val c by mkBv32Sort()
144-
val goal by mkBv32Sort()
142+
val a by bv32Sort
143+
val b by bv32Sort
144+
val c by bv32Sort
145+
val goal by bv32Sort
145146

146147
KZ3Solver(this).use { solver ->
147148
// a == 0

0 commit comments

Comments
 (0)