packages feed

picosat-0.1.4: test/Rand.hs

import Picosat
import RandomCNF (randomLiteral, randomCNF)
import System.CPUTime.Rdtsc
import Data.Word (Word64)
import Control.Monad.IO.Class (liftIO, MonadIO)

-- | Wrap any 'IO' computation so that it returns execution
-- time in CPU cycles as well as the real value.
measureCycles :: (MonadIO m) => m a -> m (Word64, a)
measureCycles ioa = do
  start <- liftIO $ rdtsc
  a <- ioa
  a `seq` return ()
  end <- liftIO $ rdtsc
  return (end-start, a)


-- | Test program demonstrating effectiveness of using Picosat's
-- solve-with-assumptions interface. One Picosat instance is kept
-- across many calls. It is able to use the kept state for good
-- improvements in run time.
-- 
-- Random CNF's are generated and then solved multiple times,
-- each time assuming another additional random literal.
-- On my computer the resulting times look like this:
-- @
-- -- 100 variables
-- ("num clauses",408)
-- ("unshared times:",[517,662,389,390,644,534,710,588,1808,
--     486,587,526,937,692,750,882,671,545,649,531,445])
-- ("shared times:",[460,185,25,23,21,20,19,20,22,153,203,25,
--     30,23,41,24,23,22,37,25,22])
-- -- ...
-- ("num clauses",418)
-- ("unshared times:",[1135,1384,913,1646,1753,2276,1277,1744,
--     1385,1552,1725,1909,1783,1463,715,1561,1802,1816,1660,1970,2145])
-- ("shared times:",[997,642,231,428,283,154,65,52,1,33,0,0,0,
--     0,0,0,0,0,0,0,0])
-- @
-- Unshared times are close to constant. This is not surprising. Each
-- time the same CNF plus an additional literal is solved again and
-- again from cold.  The shared times show how good Picosat runtimes
-- benefit from keeping one Picosat instance in memory.

testNumSolutions num_vars negp clause_size num_rands num_clauses =
  do cnf <- randomCNF num_vars negp clause_size num_clauses
     someLiterals <-
       mapM (\_->randomLiteral num_vars negp) [0..num_rands]
     print ("num clauses", num_clauses)
     let solveUnsharedWith r = do
           solution <- solve $ cnf ++ [[r]]
           case solution of
             Unsatisfiable -> return 0
             Solution _ -> return 1
     re <- mapM (\r-> do
                    (c, _) <- measureCycles (solveUnsharedWith r)
                    return $ c `div` 3000)
           someLiterals
     print ("unshared times:", re)

     let solveSharedWith lit = do
           (cyc, _) <- measureCycles $
                       scopedSolutionWithAssumptions [lit]
           return $ cyc `div` 3000
     ts <- evalScopedPicosat $ do
       addBaseClauses cnf
       mapM solveSharedWith someLiterals
     print ("shared times:", ts)


main = do
  mapM_ (testNumSolutions 100 0.5 3 20) [300,302..500]