How can I get a random propositional formula in haskell? Preferably I need the formula in CNF, but I would
I want to use the formulas for performance testing that also involves SAT solvers. Please note that my goal is not to test the performance of SAT solvers! I am also not interested in very difficult formulas, so the difficulty should be random or otherwise only include easy formulas.
I know that my real world data leads to propositional formulas that are not difficult for SAT solvers.
At the moment I use the hatt and SBV libraries as data structures to work with propositional formulas. I also looked at the hGen library, perhaps it can be used to generate the random formulas. However there is no documentation and I didn’t get far by looking at the source code of hGen.
My goal is to chose n
and get back a formula that includes n
boolean variables.
If you want to generate something randomly, I suggest a nondeterminism monad, of which MonadRandom is a popular choice.
I would suggest two inputs to this procedure: vars
, the number of variables, and clauses
the number of clauses. Of course you could always generate the number of clauses at random as well, using this same idea. Here's a sketch:
import Control.Monad.Random (Rand, StdGen, uniform)
import Control.Applicative ((<$>))
import Control.Monad (replicateM)
type Cloud = Rand StdGen -- for "probability cloud"
newtype Var = Var Int
data Atom = Positive Var -- X
| Negative Var -- not X
type CNF = [[Atom]] -- conjunction of disjunctions
genCNF :: Int -> Int -> Cloud CNF
genCNF vars clauses = replicateM clauses genClause
where
genClause :: Could [Atom]
genClause = replicateM 3 genAtom -- for CNF-3
genAtom :: Cloud Atom
genAtom = do
f <- uniform [Positive, Negative]
v <- Var <$> uniform [0..vars-1]
return (f v)
I included the optional type signatures in the where
clause to make it easier to follow the structure.
Essentially, follow the "grammar" of what you are trying to generate; with each nonterminal associate with a gen*
function.
I don't know how to judge whether a CNF expression is easy or hard.
Using the types in hatt
:
import Data.Logic.Propositional
import System.Random
import Control.Monad.State
import Data.Maybe
import Data.SBV
type Rand = State StdGen
rand :: Random a => (a, a) -> Rand a
rand = state . randomR
runRand :: Rand a -> IO a
runRand r = randomIO >>= return . fst . runState r . mkStdGen
randFormula :: Rand Expr
randFormula = rand (3, 10) >>= randFormulaN 50
randFormulaN :: Int -> Int -> Rand Expr
randFormulaN negC n = replicateM n clause >>= return . foldl1 Conjunction
where vars = take n (map (Variable . Var) ['a'..])
clause = rand (1, n) >>= mapM f . flip take vars >>= return . foldl1 Disjunction
f v = rand (0,100) >>= \neg -> return (if neg <= negC then Negation v else v)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With