The ersatz package

[Tags:bsd3, library, test]

A monad for expressing SAT or QSAT problems using observable sharing.

For example, we can express a full-adder with:

 full_adder :: Bit -> Bit -> Bit -> (Bit, Bit)
 full_adder a b cin = (s2, c1 || c2)
   where (s1,c1) = half_adder a b
         (s2,c2) = half_adder s1 cin
 half_adder :: Bit -> Bit -> (Bit, Bit)
 half_adder a b = (a `xor` b, a && b)

[Skip to Readme]


Versions 0.1,,, 0.2,, 0.2.4, 0.2.5,, 0.2.6,, 0.3, 0.3.1
Change log
Dependencies array (>=0.2 && <0.5), base (>=4.5 && <6), containers (>=, data-default (==0.5.*), ghc-prim, mtl (>=1.1 && <2.2), process (==1.1.*), temporary (==1.1.*), transformers (==0.3.*), unordered-containers (==0.2.*) [details]
License BSD3
Copyright (c) 2010-2013 Edward Kmett, (c) 2013 Johan Kiviniemi
Author Edward A. Kmett, Johan Kiviniemi
Maintainer Edward A. Kmett <>
Category Logic, Algorithms
Home page
Uploaded Sat Mar 9 09:11:11 UTC 2013 by EdwardKmett
Updated Sat Jul 11 22:46:08 UTC 2015 by EdwardKmett to revision 1
Distributions LTSHaskell:0.3.1, NixOS:0.3.1, Stackage:0.3.1, Tumbleweed:0.3.1
Downloads 2560 total (23 in the last 30 days)
1 []
Status Docs uploaded by user
Build status unknown [no reports yet]




Maintainer's Corner

For package maintainers and hackage trustees

Readme for ersatz

Readme for ersatz-0.1


Build Status

Ersatz is a library for generating QSAT (CNF/QBF) problems using a monad. It takes care of generating the normal form, encoding your problem, marshaling the data to an external solver, and parsing and interpreting the result into Haskell types.

What differentiates Ersatz is the use of observable sharing in the API.

For instance to define a full adder:

full_adder :: Bit -> Bit -> Bit -> (Bit, Bit)
full_adder a b cin = (s2, c1 || c2)
  where (s1,c1) = half_adder a b
        (s2,c2) = half_adder s1 cin

half_adder :: Bit -> Bit -> (Bit, Bit)
half_adder a b = (a `xor` b, a && b)

as opposed to the following code in satchmo:

full_adder :: Boolean -> Boolean -> Boolean
           -> SAT ( Boolean, Boolean )
full_adder a b c = do
  let s x y z = sum $ map fromEnum [x,y,z]
  r <- fun3 ( \ x y z -> odd $ s x y z ) a b c
  d <- fun3 ( \ x y z -> 1   < s x y z ) a b c
  return ( r, d )

half_adder :: Boolean -> Boolean
           -> SAT ( Boolean, Boolean )
half_adder a b = do
  let s x y = sum $ map fromEnum [x,y]
  r <- fun2 ( \ x y -> odd $ s x y ) a b
  d <- fun2 ( \ x y -> 1   < s x y ) a b
  return ( r, d )

This enables you to use the a much richer subset of Haskell than the purely monadic meta-language, and it becomes much easier to see that the resulting encoding is correct.

To allocate fresh existentially or universally quantified variables or to assert that a Bit is true and add the attendant circuit with sharing to the current problem you use the SAT monad.

verify_currying :: SAT m ()
verify_currying = do
  (x::Bit, y::Bit, z::Bit) <- forall
  assert $ ((x && y) ==> z) === (x ==> y ==> z)

We can then hand that off to a SAT solver, and get back an answer:

main = solveWith minisat verify_currying >>= print

Support is offered for decoding various Haskell datatypes from the solution provided by the SAT solver.

Contact Information

Contributions and bug reports are welcome!

Please feel free to contact me through github or on the #haskell IRC channel on

-Edward Kmett