sidekick/README.md
2019-12-16 16:43:49 -06:00

188 lines
4.7 KiB
Markdown

# MSAT [![Build Status](https://travis-ci.org/Gbury/mSAT.svg?branch=master)](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
###################
...
```