Satisfiability.jl is a package for representing satisfiability modulo theories (SMT) problems in Julia.
SMT is used in formal verification and synthesis. You can use it to find satisfying assignments for logical statements (finding a set of values that make the statement true), or to prove that no satisfying assignment exists. More practically, you can verify software correctness (some good examples are in Chapter 5 of “SAT/SMT by Example”), find a set of inputs for which a system crashes, or prove your Amazon EC2 instance is secure (Amazon’s IAM access analyzer uses SMT).
Satisfiability.jl is not a theorem prover. It is a simple interface to existing provers (Z3, cvc5, etc) using the SMT-LIB language. Currently, the theories of propositional logic, Integers, Reals and fixed-size BitVectors are supported. We plan to add support for the remaining SMT-LIB standard theories: IEEE floating points, Arrays, and Strings.
If you’re familiar with PySMT, Satisfiability.jl seeks to fill the same niche in the Julia ecosystem. Our inspirations for the package interface are JuMP and Convex.jl
What Satisfiability.jl does
- Provides a high-level interface to specify single-valued or vector-valued SMT expressions using Julia’s built-in capabilities.
- Generates files in the SMT-LIB specification language.
- Interacts with any solver that follows the SMT-LIB standard.
Examples
These are from the package documentation, linked in the respository!
Proving a bitwise version of de Morgan’s law.
Verify there is NO possible value of x and y such that de Morgan’s bitwise law doesn’t hold.
@satvariable(x, BitVector, 64)
@satvariable(y, BitVector, 64)
expr = not((~x & ~y) == ~(x | y))
status = sat!(expr, solver=Z3())
println(status) # if status is UNSAT we proved it.
Investigating rounding of real numbers
We want to find out if there exists a constant a
and two real numbers xR
and yR
such that round(xR) + round(yR) > a
while xR + yR < a
.
@satvariable(xR, Real)
@satvariable(yR, Real)
@satvariable(x, Int) # x represents a rounded version of xR
@satvariable(y, Int) # y represents a rounded version of yR
@satvariable(a, Int)
exprs = [xR + yR < a,
x + y > a,
or(x == xR, ((x < xR) ∧ (xR < x+1)), ((x-1 < xR) ∧ (xR < x))),
or(y == yR, ((y < yR) ∧ (yR < y+1)), ((y-1 < yR) ∧ (yR < y))),
]
status = sat!(exprs)
println("status = $status, xR=$(value(xR)), yR=$(value(yR)), a = $(value(a))")
There are! We get status = SAT, xR=0.666, yR=-0.834, a = 0
.
Previous work in Julia SMT
- Z3.jl provides bindings of the Z3 C++ API
- PicoSAT.jl provides bindings to the PicoSAT solver (using CNF format).
- SatisfiabilityInterface.jl was presented at JuliaCon 2021. It’s for “modelling discrete constraint satisfaction problems and encoding them to Boolean satisfiability (SAT) problems.”
Try it out!
I haven’t registered the package yet, so you can install it with using Pkg; Pkg.add(url="https://github.com/elsoroka/Satisfiability.jl/")
You’ll also need a back-end solver. Both Z3 and cvc5 are available for free; the package documentation has instructions to install them.
If you do try it I’d love to hear feedback, ideas, or any issues you encountered!