content: module TestSequential (twoSync, finishedTwoSync, checkTwoSync, checkPreserve, pFinished, isFinished, checkSync) where
  
  import Control.Monad.Bayes.Class
    ( MonadDistribution (uniformD),
      MonadMeasure,
      factor,
    )
  import Control.Monad.Bayes.Enumerator as Dist (enumerator, mass)
  import Control.Monad.Bayes.Sequential.Coroutine (advance, finish, finished)
  import Data.AEq (AEq ((~==)))
  import Sprinkler (soft)
  
  twoSync :: (MonadMeasure m) => m Int
  twoSync = do
    x <- uniformD [0, 1]
    factor (fromIntegral x)
    y <- uniformD [0, 1]
    factor (fromIntegral y)
    return (x + y)
  
  finishedTwoSync :: (MonadMeasure m) => Int -> m Bool
  finishedTwoSync n = finished (run n twoSync)
    where
      run 0 d = d
      run k d = run (k - 1) (advance d)
  
  checkTwoSync :: Int -> Bool
  checkTwoSync 0 = mass (finishedTwoSync 0) False ~== 1
  checkTwoSync 1 = mass (finishedTwoSync 1) False ~== 1
  checkTwoSync 2 = mass (finishedTwoSync 2) True ~== 1
  checkTwoSync _ = error "Unexpected argument"
  
  sprinkler :: (MonadMeasure m) => m Bool
  sprinkler = Sprinkler.soft
  
  checkPreserve :: Bool
  checkPreserve = enumerator (finish sprinkler) ~== enumerator sprinkler
  
  pFinished :: Int -> Double
  pFinished 0 = 0.8267716535433071
  pFinished 1 = 0.9988062077198566
  pFinished 2 = 1
  pFinished _ = error "Unexpected argument"
  
  isFinished :: (MonadMeasure m) => Int -> m Bool
  isFinished n = finished (run n sprinkler)
    where
      run 0 d = d
      run k d = run (k - 1) (advance d)
  
  checkSync :: Int -> Bool
  checkSync n = mass (isFinished n) True ~== pFinished n
  