-- Language extensions {{{
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE ViewPatterns #-}
-- }}}
-- Imports {{{
import Prelude hiding (catch)
import Control.Concurrent (threadDelay)
import Control.Exception (SomeException,catch)
import Control.Monad (forever,replicateM_,void)
import Control.Monad.IO.Class (liftIO)
import Data.Functor ((<$>))
import Data.IORef (modifyIORef,newIORef,readIORef)
import Data.Monoid ((<>),Sum(..),mempty)
import Data.Serialize (Serialize(..))
import System.Environment (getArgs)
import System.Log.Logger (Priority(..),updateGlobalLogger,rootLoggerName,setLevel)
import qualified System.Log.Logger as Logger -- needed for deriveLoggers
import System.Log.Logger.TH (deriveLoggers)
import System.IO (stdin,stdout)
import System.Random (randomRIO)
import Test.Framework
import Test.Framework.Providers.HUnit
import Test.HUnit
import qualified LogicGrowsOnTrees as V
import LogicGrowsOnTrees.Checkpoint
import LogicGrowsOnTrees.Examples.Queens
import LogicGrowsOnTrees.Parallel.Adapter.Processes
import LogicGrowsOnTrees.Parallel.ExplorationMode (ExplorationMode(AllMode))
import LogicGrowsOnTrees.Parallel.Main
import LogicGrowsOnTrees.Parallel.Purity (Purity(Pure))
-- }}}
-- Logging Functions {{{
deriveLoggers "Logger" [ERROR]
-- }}}
-- Helper functions {{{
remdups :: (Eq a) => [a] -> [a] -- {{{
remdups [] = []
remdups (x : []) = [x]
remdups (x : xx : xs)
| x == xx = remdups (x : xs)
| otherwise = x : remdups (xx : xs)
-- }}}
-- }}}
-- Instances {{{
instance Serialize (Sum Int) where -- {{{
put = put . getSum
get = fmap Sum get
-- }}}
-- }}}
main = do
-- updateGlobalLogger rootLoggerName (setLevel DEBUG)
args ← getArgs
case args of
["nqueens",read → n] →
runWorkerUsingHandles
AllMode
Pure
(nqueensCount n)
stdin
stdout
`catch`
(\(e::SomeException) → errorM $ "Worker process failed: " ++ show e)
_ → defaultMain tests
tests = -- {{{
[testCase "one process" . runTest $ do
setNumberOfWorkers 0
setNumberOfWorkers 1
,testCase "two processes" . runTest . void $
changeNumberOfWorkers (3-)
,testCase "many processes" . runTest . void $ liftIO (randomRIO (0,1::Int)) >>= \i → case i of
0 → changeNumberOfWorkers (\i → if i > 1 then i-1 else i)
1 → changeNumberOfWorkers (+1)
]
where
runTest generateNoise = do
let n = 15
tree = nqueensCount n
progresses_ref ← newIORef []
filepath ← getProgFilepath
RunOutcome _ termination_reason ←
runSupervisor
AllMode
filepath
["nqueens",show n]
(const $ return ())
mempty
(do setNumberOfWorkers 1
forever $ do
liftIO $ threadDelay 10000
requestProgressUpdate >>= liftIO . modifyIORef progresses_ref . (:)
generateNoise
)
result ← case termination_reason of
Aborted _ → error "prematurely aborted"
Completed result → return result
Failure _ message → error message
let correct_result = V.exploreTree tree
result @?= correct_result
progresses ← remdups <$> readIORef progresses_ref
replicateM_ 4 $ randomRIO (0,length progresses-1) >>= \i → do
let Progress checkpoint result = progresses !! i
result @=? exploreTreeStartingFromCheckpoint (invertCheckpoint checkpoint) tree
correct_result @=? result <> (exploreTreeStartingFromCheckpoint checkpoint tree)
-- }}}