Skip to content

Commit 7df2cbb

Browse files
authored
Reviewed Readme and /docs (#111)
* Reviewed Readme and /docs
1 parent 71d3378 commit 7df2cbb

4 files changed

Lines changed: 252 additions & 178 deletions

File tree

README.md

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
# KSMT
2-
Kotlin/Java API for various SMT solvers.
32

4-
[![KSMT: build](https://github.com/UnitTestBot/ksmt/actions/workflows/build-and-run-tests.yml/badge.svg)](https://github.com/UnitTestBot/ksmt/workflows/build-and-run-tests.yml)
5-
![Maven Central](https://img.shields.io/maven-central/v/io.ksmt/ksmt-core)
6-
[![javadoc](https://javadoc.io/badge2/io.ksmt/ksmt-core/javadoc.svg)](https://javadoc.io/doc/io.ksmt/ksmt-core)
3+
Meet the unified Kotlin/Java API for various SMT solvers.
4+
5+
Get the most out of SMT solving with KSMT features:
6+
* Supporting more [solvers and theories](#supported-solvers-and-theories) — for all popular operating systems
7+
* [Solver-agnostic formula representation](#solver-agnostic-formula-representation) and easy-to-use [DSL](#kotlin-based-dsl-for-smt-formulas)
8+
* Utilities to [simplify and transform](#utilities-to-simplify-and-transform-expressions) your expressions
9+
* Switching between solvers and support for [portfolio mode](#using-multiple-solvers--portfolio-mode-)
10+
* Running solvers in a [separate process](#running-solvers-in-separate-processes) to reduce timeout-related crashes
11+
* Streamlined [solver delivery](#ksmt-distribution) with no need for building a solver or implementing JVM bindings
712

8-
# Overview
13+
[![KSMT: build](https://github.com/UnitTestBot/ksmt/actions/workflows/build-and-run-tests.yml/badge.svg)](https://github.com/UnitTestBot/ksmt/actions/workflows/build-and-run-tests.yml)
14+
[![Maven Central](https://img.shields.io/maven-central/v/io.ksmt/ksmt-core)](https://central.sonatype.com/artifact/io.ksmt/ksmt-core/0.5.3)
15+
[![javadoc](https://javadoc.io/badge2/io.ksmt/ksmt-core/javadoc.svg)](https://javadoc.io/doc/io.ksmt/ksmt-core)
916

10-
`KSMT` provides a simple and unified way to work with SMT:
11-
* Define formulas in a simple and solver-independent way
12-
* Simplify and transform formulas without involving the SMT solver
13-
* Solve SMT formulas using various SMT solvers through a unified API
17+
## Get started
1418

15-
# Getting started
16-
Install via [Gradle](https://gradle.org/).
19+
To start using KSMT, install it via [Gradle](https://gradle.org/):
1720

1821
```kotlin
1922
// core
@@ -22,21 +25,32 @@ implementation("io.ksmt:ksmt-core:0.5.3")
2225
implementation("io.ksmt:ksmt-z3:0.5.3")
2326
```
2427

25-
## Usage
26-
Check out our [Getting started guide](docs/getting-started.md) and the [example project](examples).
27-
Also, check out the [Java examples](examples/src/main/java).
28+
Find basic instructions in the [Getting started](docs/getting-started.md) guide and try it out with the
29+
[Kotlin](examples/src/main/kotlin) or [Java](examples/src/main/java) examples.
30+
31+
To go beyond the basic scenarios, proceed to the [Advanced usage](docs/advanced-usage.md) guide and try the [advanced
32+
example](/examples/src/main/kotlin/AdvancedExamples.kt).
33+
34+
To get guided experience in KSMT, step through the detailed scenario for creating
35+
[custom expressions](docs/custom-expressions.md).
36+
37+
## Find more on KSMT features
2838

29-
# Features
30-
Currently, KSMT supports the following SMT solvers:
39+
Check the [Roadmap](https://github.com/UnitTestBot/ksmt/blob/main/Requirements.md) to know more about current
40+
feature support and plans for the nearest future.
3141

32-
| SMT Solver | Linux-x64 | Windows-x64 | MacOS-aarch64 | MacOS-x64 |
42+
### Supported solvers and theories
43+
44+
KSMT provides support for various solvers:
45+
46+
| SMT solver | Linux-x64 | Windows-x64 | macOS-aarch64 | macOS-x64 |
3347
|--------------------------------------------------|:------------------:|:------------------:|:------------------:|:------------------:|
3448
| [Z3](https://github.com/Z3Prover/z3) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
3549
| [Bitwuzla](https://github.com/bitwuzla/bitwuzla) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
3650
| [Yices2](https://github.com/SRI-CSL/yices2) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
3751
| [cvc5](https://github.com/cvc5/cvc5) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
3852

39-
KSMT can express formulas in the following theories:
53+
You can also use SMT solvers across multiple theories:
4054

4155
| Theory | Z3 | Bitwuzla | Yices2 | cvc5 |
4256
|-------------------------|:------------------:|:------------------:|:------------------:|:------------------:|
@@ -46,12 +60,24 @@ KSMT can express formulas in the following theories:
4660
| Uninterpreted Functions | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
4761
| Arithmetic | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark: |
4862

49-
Check out our [roadmap](Requirements.md) for detailed description of features and future plans.
63+
### Solver-agnostic formula representation
64+
65+
Various scenarios are available for using SMT solvers: you can use a single solver to determine whether a formula is
66+
satisfiable, or you can apply several solvers to the same expression successively. In the latter case, you need a _solver-agnostic formula representation_.
67+
68+
We implemented it in KSMT, so you can
69+
* transform expressions from the solver native representation to KSMT representation and vice versa,
70+
* use _formula introspection_,
71+
* manipulate expressions without involving a solver,
72+
* use expressions even if the solver is freed.
73+
74+
Expression interning (hash consing) affords faster expression comparison: we do not need to compare the expression
75+
trees. Expressions are deduplicated, so we avoid redundant memory allocation.
5076

51-
# Why KSMT?
77+
### Kotlin-based DSL for SMT formulas
78+
79+
KSMT provides you with a unified DSL for SMT expressions:
5280

53-
### Kotlin based DSL for SMT formulas
54-
KSMT provides simple and concise DSL for expressions.
5581
```kotlin
5682
val array by mkArraySort(intSort, intSort)
5783
val index by intSort
@@ -60,22 +86,43 @@ val value by intSort
6086
val expr = (array.select(index - 1.expr) lt value) and
6187
(array.select(index + 1.expr) gt value)
6288
```
63-
Check out our [example project](examples) for more complicated examples.
6489

65-
### Solver agnostic SMT formula representation
66-
KSMT provides a solver-independent formula representation
67-
with back and forth transformations to the solver's native representation.
68-
Such representation allows introspection of formulas and transformation of formulas
69-
independent of the solver.
90+
### Utilities to simplify and transform expressions
91+
92+
KSMT provides a simplification engine applicable to all supported expressions for all supported theories:
93+
94+
* reduce expression size and complexity
95+
* evaluate expressions (including those with free variables) — reduce your expression to a constant
96+
* perform formula transformations
97+
* substitute expressions
98+
99+
KSMT simplification engine implements more than 200 rules.
100+
By default, it attempts to apply simplifications when you create the expressions, but you can turn this
101+
feature off, if necessary. You can also simplify an arbitrary expression manually.
102+
103+
### Using multiple solvers (portfolio mode)
104+
105+
SMT solvers may differ in performance across different formulas:
106+
see the [International Satisfiability Modulo Theories Competition](https://smt-comp.github.io/2022/).
107+
108+
With KSMT portfolio solving, you can run multiple solvers in parallel on the same formula — until you get the first
109+
(the fastest) result.
110+
111+
For detailed instructions on running multiple solvers, see [Advanced usage](docs/advanced-usage.md).
112+
113+
### Running solvers in separate processes
114+
115+
Most of the SMT solvers are research projects — they are implemented via native libraries and are sometimes not
116+
production ready:
117+
* they may ignore timeouts — they sometimes hang in a long-running operation, and you cannot interrupt it;
118+
* they may suddenly crash interrupting the entire process — because of a pointer issue, for example.
119+
120+
KSMT runs each solver in a separate process, which adds to stability of your application and provides support for
121+
portfolio mode.
70122

71-
### Process based solver runner
72-
KSMT provides a high-performant API for running SMT solvers in separate processes.
73-
This feature is important for implementing hard timeouts and
74-
solving using multiple solvers in portfolio mode.
123+
### KSMT distribution
75124

76-
### Formula simplification and manipulation utils
77-
KSMT provides a simplification engine that can simplify and especially evaluate all supported expressions in all
78-
supported theories.
79-
Also, KSMT provides utilities for performing formula transformation, visiting and expression substitution.
125+
Many solvers do not have prebuilt binaries, or binaries are for Linux only.
80126

81-
Check out our [advanced features tutorial](docs/advanced-usage.md) for the examples.
127+
KSMT is distributed as JVM library with solver binaries provided. The library has been tested against the SMT-LIB
128+
benchmarks. Documentation and examples are also available.

docs/advanced-usage.md

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
# Advanced usage
22

3-
Advanced features usage tutorial.
4-
If you are new to KSMT, please check out our [getting started guide](/docs/getting-started.md) first.
5-
6-
For complete code examples, see our [example project](/examples) and
7-
particularly [`AdvancedExamples.kt`](/examples/src/main/kotlin/AdvancedExamples.kt)
3+
For basic KSMT usage, please refer to [Getting started](/docs/getting-started.md) guide.
4+
5+
Having tried the essential scenarios, find the [advanced example](/examples/src/main/kotlin/AdvancedExamples.kt) and proceed to advanced usage:
6+
7+
<!-- TOC -->
8+
* [Working with SMT formulas](#working-with-smt-formulas)
9+
* [Parsing formulas in SMT-LIB2 format](#parsing-formulas-in-smt-lib2-format)
10+
* [Default simplification](#default-simplification)
11+
* [Manual simplification](#manual-simplification)
12+
* [Expression substitution](#expression-substitution)
13+
* [Working with SMT solvers](#working-with-smt-solvers)
14+
* [Solver configuration](#solver-configuration)
15+
* [Solver-independent models](#solver-independent-models)
16+
* [Solver runner](#solver-runner)
17+
* [Using custom solvers in a runner](#using-custom-solvers-in-a-runner)
18+
* [Solver portfolio](#solver-portfolio)
19+
<!-- TOC -->
820

921
## Working with SMT formulas
1022

23+
Learn how to parse, simplify, and substitute expressions.
24+
1125
### Parsing formulas in SMT-LIB2 format
1226

1327
KSMT provides an API for parsing formulas in the SMT-LIB2 format.
14-
Currently, KSMT provides a parser implemented on top of the Z3 solver API
15-
and therefore `ksmt-z3` module is required for parsing.
28+
Currently, KSMT provides a parser implemented on top of the Z3 solver API, and therefore `ksmt-z3` module is
29+
required for parsing.
1630

1731
```kotlin
1832
val formula = """
@@ -26,10 +40,10 @@ with(ctx) {
2640
}
2741
```
2842

29-
### Simplification during expressions creation
43+
### Default simplification
3044

31-
By default, `KContext` will attempt to apply lightweight simplifications during expression creation. If simplifications
32-
are not suitable for your use cases you can disable them using the `KContext.simplificationMode` parameter.
45+
By default, `KContext` attempts to apply lightweight simplifications when you create an expression. If you do not
46+
need simplifications, disable them using the `KContext.simplificationMode` parameter.
3347

3448
```kotlin
3549
// Simplification is enabled by default
@@ -52,12 +66,12 @@ println(nonSimplifiedExpr) // (not (and a false))
5266
println(simplifiedExpr) // true
5367
```
5468

55-
### Manual expression simplification
69+
### Manual simplification
5670

57-
KSMT provides a `KExprSimplifier` which allows you to manually perform simplification of an arbitrary expression.
71+
KSMT provides `KExprSimplifier`, so you can manually simplify an arbitrary expression.
5872

5973
```kotlin
60-
// Context do not simplify expressions during creation
74+
// Context does not simplify expressions during creation
6175
val ctx = KContext(simplificationMode = KContext.SimplificationMode.NO_SIMPLIFY)
6276

6377
with(ctx) {
@@ -74,7 +88,7 @@ with(ctx) {
7488

7589
### Expression substitution
7690

77-
KSMT provides a `KExprSubstitutor` which allows you to replace all occurrences of one expression with another
91+
KSMT provides `KExprSubstitutor`, so you can replace all the expression occurrences with another
7892
expression.
7993

8094
```kotlin
@@ -95,30 +109,32 @@ println(exprAfterSubstitution) // true
95109

96110
## Working with SMT solvers
97111

112+
Learn how to configure and run solvers, get models, and switch to portfolio mode.
113+
98114
### Solver configuration
99115

100116
KSMT provides an API for modifying solver-specific parameters.
101-
Since the parameters and their correct values are solver-specific
117+
Since the parameters and their correct values are solver-specific,
102118
KSMT does not perform any checks.
103-
See the corresponding solver documentation for a list of available options.
119+
See corresponding solver documentation for a list of available options.
104120

105121
```kotlin
106122
with(ctx) {
107123
KZ3Solver(this).use { solver ->
108124
solver.configure {
109-
// set Z3 solver parameter random_seed to 42
125+
// set Z3 solver `random_seed` parameter to 42
110126
setZ3Option("random_seed", 42)
111127
}
112128
}
113129
}
114130
```
115131

116-
### Solver independent models
132+
### Solver-independent models
117133

118-
By default, SMT solver models lazily initialized.
119-
The values of the declared variables are loaded from the underlying solver's native model on demand.
120-
Therefore, models become invalid after solver close. Also, solvers like `Bitwuzla` invalidate their models every
121-
time `check-sat` is called.
134+
By default, SMT solver models are lazily initialized.
135+
The values of the declared variables are loaded from the underlying solver native model on demand.
136+
Therefore, models become invalid as soon as the solver closes. Moreover, solvers like Bitwuzla invalidate their models
137+
each time `check-sat` is called.
122138
To overcome these problems, KSMT provides the `KModel.detach` function that allows you to make the model independent of
123139
the underlying native representation.
124140

@@ -147,19 +163,12 @@ try {
147163
println(detachedModel.eval(expr)) // true
148164
```
149165

150-
Note: it is usually a good idea to use `KModel.detach` when you need to keep model e.g. in a `List`.
166+
Note: it is recommended to use `KModel.detach` when you need to keep the model in a `List`, for example.
151167

152168
### Solver runner
153169

154-
SMT solvers are implemented via native libraries and usually have the following issues:
155-
156-
1. Timeout ignore. SMT solver may hang in a long-running operation before reaching a checkpoint.
157-
Since solver is a native library, there is no way to interrupt it.
158-
2. Solvers are usually research projects with a bunch of bugs, e.g. pointer issues. Such
159-
errors lead to the interruption of the entire process, including the user's app.
160-
161-
To overcome these problems KSMT provides a solver runner that runs solvers in separate processes to preserve your
162-
application stability.
170+
SMT solvers may ignore timeouts, or they suddenly crash, thus interrupting the entire application process.
171+
KSMT provides a process-based solver runner: it runs each solver in a separate process.
163172

164173
```kotlin
165174
// Create a long-lived solver manager that manages a pool of solver workers
@@ -182,13 +191,12 @@ KSolverRunnerManager().use { solverManager ->
182191

183192
### Using custom solvers in a runner
184193

185-
Solver runner also supports user defined solvers. Custom solvers must be registered before being used in the runner
186-
using `registerSolver`.
194+
Solver runner also supports user-defined solvers. Custom solvers must be registered via `registerSolver` before being used in the runner.
187195

188196
```kotlin
189197
// Create a long-lived solver manager that manages a pool of solver workers
190198
KSolverRunnerManager().use { solverManager ->
191-
// Register user-defined solver in a current manager
199+
// Register the user-defined solver in a current manager
192200
solverManager.registerSolver(CustomZ3BasedSolver::class, KZ3SolverUniversalConfiguration::class)
193201

194202
// Use solver API as usual
@@ -208,19 +216,16 @@ KSolverRunnerManager().use { solverManager ->
208216

209217
### Solver portfolio
210218

211-
Various SMT solvers usually show different performance on a same SMT formula.
212-
[Portfolio solving](https://arxiv.org/abs/1505.03340) is a simple idea of
213-
running different solvers on the same formula simultaneously and waiting only
214-
for the first result.
215-
The portfolio solver workflow in KSMT is similar to the solver runner.
219+
To run solvers in portfolio mode, i.e., to run them in parallel until you get the first result, try the following
220+
workflow, which is similar to using the solver runner:
216221

217222
```kotlin
218223
// Create a long-lived portfolio solver manager that manages a pool of solver workers
219224
KPortfolioSolverManager(
220225
// Solvers to include in portfolio
221226
listOf(KZ3Solver::class, CustomZ3BasedSolver::class)
222227
).use { solverManager ->
223-
// Since we use user-defined solver in our portfolio we must register it in the current manager
228+
// Since we use the user-defined solver in our portfolio, we must register it in the current manager
224229
solverManager.registerSolver(CustomZ3BasedSolver::class, KZ3SolverUniversalConfiguration::class)
225230

226231
// Use solver API as usual

0 commit comments

Comments
 (0)