mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-09 04:35:35 -05:00
188 lines
4.7 KiB
Markdown
188 lines
4.7 KiB
Markdown
# MSAT [](https://travis-ci.org/Gbury/mSAT)
|
|
|
|
MSAT is an OCaml library that features a modular SAT-solver and some
|
|
extensions (including SMT), derived from [Alt-Ergo Zero](http://cubicle.lri.fr/alt-ergo-zero).
|
|
|
|
It was presented at [ICFP 2017](https://icfp17.sigplan.org/event/ocaml-2017-papers-msat-an-ocaml-sat-solver),
|
|
using a [poster](https://github.com/Gbury/mSAT/blob/master/articles/icfp_2017.pdf)
|
|
|
|
|
|
## COPYRIGHT
|
|
|
|
This program is distributed under the Apache Software License version
|
|
2.0. See the enclosed file `LICENSE`.
|
|
|
|
## Documentation
|
|
|
|
See https://gbury.github.io/mSAT/
|
|
|
|
## INSTALLATION
|
|
|
|
### Via opam
|
|
|
|
Once the package is on [opam](http://opam.ocaml.org), just `opam install msat`.
|
|
For the development version, use:
|
|
|
|
```
|
|
opam pin add msat https://github.com/Gbury/mSAT.git
|
|
```
|
|
|
|
### Manual installation
|
|
|
|
You will need `dune` and `iter`. The command is:
|
|
|
|
```
|
|
$ make install
|
|
```
|
|
|
|
## USAGE
|
|
|
|
### Generic SAT/SMT Solver
|
|
|
|
A modular implementation of the SMT algorithm can be found in the `Msat.Solver` module,
|
|
as a functor which takes two modules :
|
|
|
|
- A representation of formulas (which implements the `Formula_intf.S` signature)
|
|
|
|
- A theory (which implements the `Theory_intf.S` signature) to check consistence of assertions.
|
|
|
|
- A dummy empty module to ensure generativity of the solver (solver modules heavily relies on
|
|
side effects to their internal state)
|
|
|
|
### Sat Solver
|
|
|
|
A ready-to-use SAT solver is available in the `Msat_sat` module
|
|
using the `msat.sat` library. It can be loaded
|
|
as shown in the following code :
|
|
|
|
```ocaml
|
|
# #require "msat";;
|
|
# #require "msat.sat";;
|
|
# #print_depth 0;; (* do not print details *)
|
|
```
|
|
|
|
Then we can create a solver and create some boolean variables:
|
|
|
|
```ocaml
|
|
module Sat = Msat_sat
|
|
module E = Sat.Int_lit (* expressions *)
|
|
|
|
let solver = Sat.create()
|
|
|
|
(* We create here two distinct atoms *)
|
|
let a = E.fresh () (* A 'new_atom' is always distinct from any other atom *)
|
|
let b = E.make 1 (* Atoms can be created from integers *)
|
|
```
|
|
|
|
We can try and check the satisfiability of some clauses — here, the clause `a or b`.
|
|
`Sat.assume` adds a list of clauses to the solver. Calling `Sat.solve`
|
|
will check the satisfiability of the current set of clauses, here "Sat".
|
|
|
|
```ocaml
|
|
# a <> b;;
|
|
- : bool = true
|
|
# Sat.assume solver [[a; b]] ();;
|
|
- : unit = ()
|
|
# let res = Sat.solve solver;;
|
|
val res : Sat.res = Sat.Sat ...
|
|
```
|
|
|
|
The Sat solver has an incremental mutable state, so we still have
|
|
the clause `a or b` in our assumptions.
|
|
We add `not a` and `not b` to the state, and get "Unsat".
|
|
|
|
```ocaml
|
|
# Sat.assume solver [[E.neg a]; [E.neg b]] () ;;
|
|
- : unit = ()
|
|
# let res = Sat.solve solver ;;
|
|
val res : Sat.res = Sat.Unsat ...
|
|
```
|
|
|
|
#### Formulas API
|
|
|
|
Writing clauses by hand can be tedious and error-prone.
|
|
The functor `Msat_tseitin.Make` in the library `msat.tseitin`
|
|
proposes a formula AST (parametrized by
|
|
atoms) and a function to convert these formulas into clauses:
|
|
|
|
```ocaml
|
|
# #require "msat.tseitin";;
|
|
```
|
|
|
|
```ocaml
|
|
(* Module initialization *)
|
|
module F = Msat_tseitin.Make(E)
|
|
|
|
let solver = Sat.create ()
|
|
|
|
(* We create here two distinct atoms *)
|
|
let a = E.fresh () (* A fresh atom is always distinct from any other atom *)
|
|
let b = E.make 1 (* Atoms can be created from integers *)
|
|
|
|
(* Let's create some formulas *)
|
|
let p = F.make_atom a
|
|
let q = F.make_atom b
|
|
let r = F.make_and [p; q]
|
|
let s = F.make_or [F.make_not p; F.make_not q]
|
|
```
|
|
|
|
We can try and check the satisfiability of the given formulas, by turning
|
|
it into clauses using `make_cnf`:
|
|
|
|
```ocaml
|
|
# Sat.assume solver (F.make_cnf r) ();;
|
|
- : unit = ()
|
|
# Sat.solve solver;;
|
|
- : Sat.res = Sat.Sat ...
|
|
```
|
|
|
|
```ocaml
|
|
# Sat.assume solver (F.make_cnf s) ();;
|
|
- : unit = ()
|
|
# Sat.solve solver ;;
|
|
- : Sat.res = Sat.Unsat ...
|
|
```
|
|
|
|
### CDCL(T): a Sudoku solver as an example
|
|
|
|
The directory `src/sudoku/` contains a simple Sudoku solver that
|
|
uses the interface `Msat.Make_cdcl_t`.
|
|
In essence, it implements the logical theory `CDCL(Sudoku)`.
|
|
The script `sudoku_solve.sh` compiles and runs the solver,
|
|
as does `dune exec src/sudoku/sudoku_solve.exe`.
|
|
|
|
It's able to parse sudoku grids denoted as 81 integers
|
|
(see `tests/sudoku/sudoku.txt` for example).
|
|
|
|
Here is a sample grid and the output from the solver (in roughly .5s):
|
|
|
|
```sh non-deterministic=command
|
|
$ echo '..............3.85..1.2.......5.7.....4...1...9.......5......73..2.1........4...9' > sudoku.txt
|
|
$ dune exec src/sudoku/sudoku_solve.exe -- sudoku.txt
|
|
...
|
|
#########################
|
|
solve grid:
|
|
.........
|
|
.....3.85
|
|
..1.2....
|
|
...5.7...
|
|
..4...1..
|
|
.9.......
|
|
5......73
|
|
..2.1....
|
|
....4...9
|
|
|
|
...
|
|
987654321
|
|
246173985
|
|
351928746
|
|
128537694
|
|
634892157
|
|
795461832
|
|
519286473
|
|
472319568
|
|
863745219
|
|
|
|
###################
|
|
...
|
|
```
|