{-# LANGUAGE OverloadedStrings #-}

-- |
-- Module      :  Mcmc.Mcmc
-- Description :  Framework for running Markov chain Monte Carlo samplers
-- Copyright   :  2021 Dominik Schrempf
-- License     :  GPL-3.0-or-later
--
-- Maintainer  :  dominik.schrempf@gmail.com
-- Stability   :  unstable
-- Portability :  portable
--
-- Creation date: Fri May 29 10:19:45 2020.
--
-- This module provides the general framework for running MCMC samplers. By
-- design choice this module is agnostic about the details of the used
-- 'Algorithm'.
module Mcmc.Mcmc
  ( mcmc,
    mcmcContinue,
  )
where

import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader
import Mcmc.Algorithm
import Mcmc.Cycle
import Mcmc.Environment
import Mcmc.Logger
import Mcmc.Proposal (TuningType (LastTuningStep, NormalTuningStep))
import Mcmc.Settings
import System.Exit
import System.IO
import Prelude hiding (cycle)

-- The MCMC algorithm has read access to an environment and uses an algorithm
-- transforming the state @a@.
type MCMC = ReaderT (Environment Settings) IO

mcmcExecute :: Algorithm a => a -> MCMC a
mcmcExecute :: a -> MCMC a
mcmcExecute a
a = do
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Executing MCMC run."
  Settings
s <- (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO Settings
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader Environment Settings -> Settings
forall s. Environment s -> s
settings
  a
a' <- case Settings -> ExecutionMode
sExecutionMode Settings
s of
    ExecutionMode
Fail -> a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcNewRun a
a
    ExecutionMode
Overwrite -> a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcNewRun a
a
    ExecutionMode
Continue -> a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcContinueRun a
a
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Executed MCMC run."
  a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a'

mcmcResetAcceptance :: Algorithm a => a -> MCMC a
mcmcResetAcceptance :: a -> MCMC a
mcmcResetAcceptance a
a = do
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Reset acceptance rates."
  a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> MCMC a) -> a -> MCMC a
forall a b. (a -> b) -> a -> b
$ a -> a
forall a. Algorithm a => a -> a
aResetAcceptance a
a

mcmcExceptionHandler :: Algorithm a => Environment Settings -> a -> AsyncException -> IO b
mcmcExceptionHandler :: Environment Settings -> a -> AsyncException -> IO b
mcmcExceptionHandler Environment Settings
e a
a AsyncException
err = do
  String -> IO ()
putStrLn String
""
  String -> IO ()
putStrLn String
"INTERRUPT!"
  String -> IO ()
putStrLn String
"Try to terminate gracefully and save chain for continuation."
  String -> IO ()
putStrLn String
"Press CTRL-C (again) to terminate now."
  String -> IO ()
putStrLn String
"Closing output files."
  a
_ <- a -> IO a
forall a. Algorithm a => a -> IO a
aCloseMonitors a
a
  Environment Settings -> IO ()
forall s. Environment s -> IO ()
closeEnvironment Environment Settings
e
  String -> IO ()
putStrLn String
"Saving settings."
  let s :: Settings
s = Environment Settings -> Settings
forall s. Environment s -> s
settings Environment Settings
e
  Settings -> IO ()
settingsSave Settings
s
  String -> IO ()
putStrLn String
"Saving compressed MCMC analysis."
  String -> IO ()
putStrLn String
"For long traces, or complex objects, this may take a while."
  let nm :: AnalysisName
nm = Settings -> AnalysisName
sAnalysisName Settings
s
  AnalysisName -> a -> IO ()
forall a. Algorithm a => AnalysisName -> a -> IO ()
aSave AnalysisName
nm a
a
  String -> IO ()
putStrLn String
"Markov chain saved. Analysis can be continued."
  String -> IO ()
putStrLn String
"Graceful termination successful."
  String -> IO ()
putStrLn String
"Rethrowing error."
  AsyncException -> IO b
forall a e. Exception e => e -> a
throw AsyncException
err

-- XXX: Exception handling. Is it enough to mask execution of monitors and catch
-- UserInterrupt during iterations?

mcmcExecuteMonitors :: Algorithm a => a -> MCMC ()
mcmcExecuteMonitors :: a -> Logger (Environment Settings) ()
mcmcExecuteMonitors a
a = do
  Environment Settings
e <- ReaderT (Environment Settings) IO (Environment Settings)
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
  let s :: Settings
s = Environment Settings -> Settings
forall s. Environment s -> s
settings Environment Settings
e
      vb :: Verbosity
vb = Settings -> Verbosity
sVerbosity Settings
s
      t0 :: UTCTime
t0 = Environment Settings -> UTCTime
forall s. Environment s -> UTCTime
startingTime Environment Settings
e
      iTotal :: Int
iTotal = BurnInSettings -> Int
burnInIterations (Settings -> BurnInSettings
sBurnIn Settings
s) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Iterations -> Int
fromIterations (Settings -> Iterations
sIterations Settings
s)
  -- NOTE: Mask asynchronous exceptions when writing monitor files.
  Maybe ByteString
mStdLog <- IO (Maybe ByteString)
-> ReaderT (Environment Settings) IO (Maybe ByteString)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe ByteString)
 -> ReaderT (Environment Settings) IO (Maybe ByteString))
-> IO (Maybe ByteString)
-> ReaderT (Environment Settings) IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ IO (Maybe ByteString) -> IO (Maybe ByteString)
forall a. IO a -> IO a
mask_ (IO (Maybe ByteString) -> IO (Maybe ByteString))
-> IO (Maybe ByteString) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ Verbosity -> UTCTime -> Int -> a -> IO (Maybe ByteString)
forall a.
Algorithm a =>
Verbosity -> UTCTime -> Int -> a -> IO (Maybe ByteString)
aExecuteMonitors Verbosity
vb UTCTime
t0 Int
iTotal a
a
  Maybe ByteString
-> (ByteString -> Logger (Environment Settings) ())
-> Logger (Environment Settings) ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ Maybe ByteString
mStdLog (ByteString -> ByteString -> Logger (Environment Settings) ()
forall e.
(HasLogHandles e, HasLock e) =>
ByteString -> ByteString -> Logger e ()
logOutB ByteString
"   ")

mcmcIterate :: Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate :: IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
m Int
n a
a
  | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> MCMC a
forall a. HasCallStack => String -> a
error String
"mcmcIterate: Number of iterations is negative."
  | Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
  | Bool
otherwise = do
      Environment Settings
e <- ReaderT (Environment Settings) IO (Environment Settings)
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
      ParallelizationMode
p <- Settings -> ParallelizationMode
sParallelizationMode (Settings -> ParallelizationMode)
-> (Environment Settings -> Settings)
-> Environment Settings
-> ParallelizationMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Environment Settings -> Settings
forall s. Environment s -> s
settings (Environment Settings -> ParallelizationMode)
-> ReaderT (Environment Settings) IO (Environment Settings)
-> ReaderT (Environment Settings) IO ParallelizationMode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT (Environment Settings) IO (Environment Settings)
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
      -- NOTE: User interrupt is handled during iterations.
      a
a' <- IO a -> MCMC a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> MCMC a) -> IO a -> MCMC a
forall a b. (a -> b) -> a -> b
$ IO a -> (AsyncException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (IterationMode -> ParallelizationMode -> a -> IO a
forall a.
Algorithm a =>
IterationMode -> ParallelizationMode -> a -> IO a
aIterate IterationMode
m ParallelizationMode
p a
a) (Environment Settings -> a -> AsyncException -> IO a
forall a b.
Algorithm a =>
Environment Settings -> a -> AsyncException -> IO b
mcmcExceptionHandler Environment Settings
e a
a)
      a -> Logger (Environment Settings) ()
forall a. Algorithm a => a -> Logger (Environment Settings) ()
mcmcExecuteMonitors a
a'
      IterationMode -> Int -> a -> MCMC a
forall a. Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
m (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) a
a'

mcmcNewRun :: Algorithm a => a -> MCMC a
mcmcNewRun :: a -> MCMC a
mcmcNewRun a
a = do
  Settings
s <- (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO Settings
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader Environment Settings -> Settings
forall s. Environment s -> s
settings
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Start new MCMC sampler."
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Initial state."
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a
  a -> Logger (Environment Settings) ()
forall a. Algorithm a => a -> Logger (Environment Settings) ()
mcmcExecuteMonitors a
a
  Bool
-> Logger (Environment Settings) ()
-> Logger (Environment Settings) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (a -> Bool
forall a. Algorithm a => a -> Bool
aIsInValidState a
a) (ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logWarnB ByteString
"The initial state is invalid!")
  a
a' <- a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcBurnIn a
a
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Clean chain after burn in."
  let tl :: TraceLength
tl = Settings -> TraceLength
sTraceLength Settings
s
  a
a'' <- IO a -> MCMC a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> MCMC a) -> IO a -> MCMC a
forall a b. (a -> b) -> a -> b
$ TraceLength -> a -> IO a
forall a. Algorithm a => TraceLength -> a -> IO a
aCleanAfterBurnIn TraceLength
tl a
a'
  let i :: Int
i = Iterations -> Int
fromIterations (Iterations -> Int) -> Iterations -> Int
forall a b. (a -> b) -> a -> b
$ Settings -> Iterations
sIterations Settings
s
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Run chain for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" iterations."
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a''
  IterationMode -> Int -> a -> MCMC a
forall a. Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
AllProposals Int
i a
a''

mcmcContinueRun :: Algorithm a => a -> MCMC a
mcmcContinueRun :: a -> MCMC a
mcmcContinueRun a
a = do
  Settings
s <- (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO Settings
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader Environment Settings -> Settings
forall s. Environment s -> s
settings
  let iBurnIn :: Int
iBurnIn = BurnInSettings -> Int
burnInIterations (Settings -> BurnInSettings
sBurnIn Settings
s)
      iNormal :: Int
iNormal = Iterations -> Int
fromIterations (Settings -> Iterations
sIterations Settings
s)
      iTotal :: Int
iTotal = Int
iBurnIn Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
iNormal
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Continuation of MCMC sampler."
  let iCurrent :: Int
iCurrent = a -> Int
forall a. Algorithm a => a -> Int
aIteration a
a
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Burn in iterations: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
iBurnIn String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Normal iterations: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
iNormal String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Total iterations: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
iTotal String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Current iteration: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
iCurrent String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
  Bool
-> Logger (Environment Settings) ()
-> Logger (Environment Settings) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
iCurrent Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
iBurnIn) (Logger (Environment Settings) ()
 -> Logger (Environment Settings) ())
-> Logger (Environment Settings) ()
-> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String -> Logger (Environment Settings) ()
forall a. HasCallStack => String -> a
error String
"mcmcContinueRun: Can not continue burn in."
  let di :: Int
di = Int
iTotal Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
iCurrent
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Run chain for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
di String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" iterations."
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a
  IterationMode -> Int -> a -> MCMC a
forall a. Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
AllProposals Int
di a
a

mcmcBurnIn :: Algorithm a => a -> MCMC a
mcmcBurnIn :: a -> MCMC a
mcmcBurnIn a
a = do
  Settings
s <- (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO Settings
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader Environment Settings -> Settings
forall s. Environment s -> s
settings
  case Settings -> BurnInSettings
sBurnIn Settings
s of
    BurnInSettings
NoBurnIn -> do
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS String
"No burn in."
      a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a
    BurnInWithoutAutoTuning Int
n -> do
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Burn in for " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" iterations."
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS String
"Auto tuning is disabled."
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a
      a
a' <- IterationMode -> Int -> a -> MCMC a
forall a. Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
AllProposals Int
n a
a
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a'
      a
a'' <- a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcResetAcceptance a
a'
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Burn in finished."
      a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a''
    BurnInWithAutoTuning Int
n Int
t -> do
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Burn in for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" iterations."
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Auto tuning is enabled with a period of " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a
      let (Int
m, Int
r) = Int
n Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
t
          -- Don't add another auto tune period if r == 0, because then we auto
          -- tune without acceptance counts and get NaNs.
          xs :: [Int]
xs = Int -> Int -> [Int]
forall a. Int -> a -> [a]
replicate Int
m Int
t [Int] -> [Int] -> [Int]
forall a. Semigroup a => a -> a -> a
<> [Int
r | Int
r Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0]
      a
a' <- IterationMode -> [Int] -> a -> MCMC a
forall a. Algorithm a => IterationMode -> [Int] -> a -> MCMC a
mcmcBurnInWithAutoTuning IterationMode
AllProposals [Int]
xs a
a
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Burn in finished."
      a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a'
    BurnInWithCustomAutoTuning [Int]
xs [Int]
ys -> do
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Burn in for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ([Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int]
xs Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Int]
ys) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" iterations."
      a
a' <-
        if [Int] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Int]
xs
          then do
            ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a
            a -> MCMC a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
          else do
            ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
FastProposals a
a
            String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Fast custom auto tuning with periods " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Int] -> String
forall a. Show a => a -> String
show [Int]
xs String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
            ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a
            IterationMode -> [Int] -> a -> MCMC a
forall a. Algorithm a => IterationMode -> [Int] -> a -> MCMC a
mcmcBurnInWithAutoTuning IterationMode
FastProposals [Int]
xs a
a
      String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Full custom auto tuning with periods " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Int] -> String
forall a. Show a => a -> String
show [Int]
ys String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a
      a
a'' <- IterationMode -> [Int] -> a -> MCMC a
forall a. Algorithm a => IterationMode -> [Int] -> a -> MCMC a
mcmcBurnInWithAutoTuning IterationMode
AllProposals [Int]
ys a
a'
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Burn in finished."
      a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a''

-- Auto tune the proposals.
mcmcAutotune :: Algorithm a => TuningType -> Int -> a -> MCMC a
mcmcAutotune :: TuningType -> Int -> a -> MCMC a
mcmcAutotune TuningType
NormalTuningStep Int
n a
a = do
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Auto tune."
  IO a -> MCMC a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> MCMC a) -> IO a -> MCMC a
forall a b. (a -> b) -> a -> b
$ TuningType -> Int -> a -> IO a
forall a. Algorithm a => TuningType -> Int -> a -> IO a
aAutoTune TuningType
NormalTuningStep Int
n a
a
mcmcAutotune TuningType
LastTuningStep Int
n a
a = do
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Last auto tune."
  IO a -> MCMC a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> MCMC a) -> IO a -> MCMC a
forall a b. (a -> b) -> a -> b
$ TuningType -> Int -> a -> IO a
forall a. Algorithm a => TuningType -> Int -> a -> IO a
aAutoTune TuningType
LastTuningStep Int
n a
a

mcmcBurnInWithAutoTuning :: Algorithm a => IterationMode -> [Int] -> a -> MCMC a
mcmcBurnInWithAutoTuning :: IterationMode -> [Int] -> a -> MCMC a
mcmcBurnInWithAutoTuning IterationMode
_ [] a
_ = String -> MCMC a
forall a. HasCallStack => String -> a
error String
"mcmcBurnInWithAutoTuning: Empty list."
mcmcBurnInWithAutoTuning IterationMode
m [Int
x] a
a = do
  -- Last round.
  a
a' <- IterationMode -> Int -> a -> MCMC a
forall a. Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
m Int
x a
a
  a
a'' <- TuningType -> Int -> a -> MCMC a
forall a. Algorithm a => TuningType -> Int -> a -> MCMC a
mcmcAutotune TuningType
LastTuningStep Int
x a
a'
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
m a
a''
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Acceptance rates calculated over the last " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
x String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" iterations."
  a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcResetAcceptance a
a''
mcmcBurnInWithAutoTuning IterationMode
m (Int
x : [Int]
xs) a
a = do
  a
a' <- IterationMode -> Int -> a -> MCMC a
forall a. Algorithm a => IterationMode -> Int -> a -> MCMC a
mcmcIterate IterationMode
m Int
x a
a
  a
a'' <- TuningType -> Int -> a -> MCMC a
forall a. Algorithm a => TuningType -> Int -> a -> MCMC a
mcmcAutotune TuningType
NormalTuningStep Int
x a
a'
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
m a
a''
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logDebugS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ String
"Acceptance rates calculated over the last " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
x String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" iterations."
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> ByteString
forall a. Algorithm a => a -> ByteString
aStdMonitorHeader a
a''
  a
a''' <- a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcResetAcceptance a
a''
  IterationMode -> [Int] -> a -> MCMC a
forall a. Algorithm a => IterationMode -> [Int] -> a -> MCMC a
mcmcBurnInWithAutoTuning IterationMode
m [Int]
xs a
a'''

mcmcInitialize :: Algorithm a => a -> MCMC a
mcmcInitialize :: a -> MCMC a
mcmcInitialize a
a = do
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> String
forall a. Algorithm a => a -> String
aName a
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" algorithm."
  Settings
s <- Environment Settings -> Settings
forall s. Environment s -> s
settings (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO (Environment Settings)
-> ReaderT (Environment Settings) IO Settings
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT (Environment Settings) IO (Environment Settings)
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Opening monitors."
  a
a' <- IO a -> MCMC a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> MCMC a) -> IO a -> MCMC a
forall a b. (a -> b) -> a -> b
$ AnalysisName -> ExecutionMode -> a -> IO a
forall a. Algorithm a => AnalysisName -> ExecutionMode -> a -> IO a
aOpenMonitors (Settings -> AnalysisName
sAnalysisName Settings
s) (Settings -> ExecutionMode
sExecutionMode Settings
s) a
a
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Monitors opened."
  a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a'

-- Save the MCMC run.
mcmcSave :: Algorithm a => a -> MCMC ()
mcmcSave :: a -> Logger (Environment Settings) ()
mcmcSave a
a = do
  Settings
s <- (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO Settings
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader Environment Settings -> Settings
forall s. Environment s -> s
settings
  case Settings -> SaveMode
sSaveMode Settings
s of
    SaveMode
NoSave -> ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Do not save the MCMC analysis."
    SaveMode
Save -> do
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Save settings."
      IO () -> Logger (Environment Settings) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Logger (Environment Settings) ())
-> IO () -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ Settings -> IO ()
settingsSave Settings
s
      let nm :: AnalysisName
nm = Settings -> AnalysisName
sAnalysisName Settings
s
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Save compressed MCMC analysis."
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"For long traces, or complex objects, this may take a while."
      IO () -> Logger (Environment Settings) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Logger (Environment Settings) ())
-> IO () -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ AnalysisName -> a -> IO ()
forall a. Algorithm a => AnalysisName -> a -> IO ()
aSave AnalysisName
nm a
a
      ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB ByteString
"Markov chain saved."

-- Report and finish up.
mcmcClose :: Algorithm a => a -> MCMC a
mcmcClose :: a -> MCMC a
mcmcClose a
a = do
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB ByteString
"Closing MCMC run."
  ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> ByteString -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ IterationMode -> a -> ByteString
forall a. Algorithm a => IterationMode -> a -> ByteString
aSummarizeCycle IterationMode
AllProposals a
a
  String -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger (Environment Settings) ())
-> String -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ a -> String
forall a. Algorithm a => a -> String
aName a
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" algorithm finished."
  a -> Logger (Environment Settings) ()
forall a. Algorithm a => a -> Logger (Environment Settings) ()
mcmcSave a
a
  Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasStartingTime e, HasVerbosity e) =>
Logger e ()
logInfoEndTime
  a
a' <- IO a -> MCMC a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> MCMC a) -> IO a -> MCMC a
forall a b. (a -> b) -> a -> b
$ a -> IO a
forall a. Algorithm a => a -> IO a
aCloseMonitors a
a
  Environment Settings
e <- ReaderT (Environment Settings) IO (Environment Settings)
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
  IO () -> Logger (Environment Settings) ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Logger (Environment Settings) ())
-> IO () -> Logger (Environment Settings) ()
forall a b. (a -> b) -> a -> b
$ Environment Settings -> IO ()
forall s. Environment s -> IO ()
closeEnvironment Environment Settings
e
  a -> MCMC a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a'

-- Initialize the run, execute the run, and close the run.
mcmcRun :: Algorithm a => a -> MCMC a
mcmcRun :: a -> MCMC a
mcmcRun a
a = do
  -- Header.
  Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
Logger e ()
logInfoHeader
  (Environment Settings -> Settings)
-> ReaderT (Environment Settings) IO Settings
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader Environment Settings -> Settings
forall s. Environment s -> s
settings ReaderT (Environment Settings) IO Settings
-> (Settings -> Logger (Environment Settings) ())
-> Logger (Environment Settings) ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString -> Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger (Environment Settings) ())
-> (Settings -> ByteString)
-> Settings
-> Logger (Environment Settings) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Settings -> ByteString
settingsPrettyPrint

  -- Initialize.
  a
a' <- a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcInitialize a
a
  Logger (Environment Settings) ()
forall e.
(HasLock e, HasLogHandles e, HasStartingTime e, HasVerbosity e) =>
Logger e ()
logInfoStartingTime

  -- Execute.
  a
a'' <- a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcExecute a
a'

  -- Close.
  a -> MCMC a
forall a. Algorithm a => a -> MCMC a
mcmcClose a
a''

-- | Run an MCMC algorithm with given settings.
mcmc :: Algorithm a => Settings -> a -> IO a
mcmc :: Settings -> a -> IO a
mcmc Settings
s a
a = do
  Settings -> Int -> IO ()
settingsCheck Settings
s (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ a -> Int
forall a. Algorithm a => a -> Int
aIteration a
a
  Environment Settings
e <- Settings -> IO (Environment Settings)
forall s.
(HasAnalysisName s, HasExecutionMode s, HasLogMode s,
 HasVerbosity s) =>
s -> IO (Environment s)
initializeEnvironment Settings
s
  ReaderT (Environment Settings) IO a -> Environment Settings -> IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (a -> ReaderT (Environment Settings) IO a
forall a. Algorithm a => a -> MCMC a
mcmcRun a
a) Environment Settings
e

-- | Continue an MCMC algorithm for the given number of iterations.
--
-- Currently, it is only possible to continue MCMC algorithms that have
-- completed successfully. This restriction is necessary, because for parallel
-- chains, it is hardly possible to ensure all chains are synchronized when the
-- process is killed or fails.
--
-- See:
--
-- - 'Mcmc.Algorithm.MHG.mhgLoad'
--
-- - 'Mcmc.Algorithm.MC3.mc3Load'
mcmcContinue :: Algorithm a => Iterations -> Settings -> a -> IO a
mcmcContinue :: Iterations -> Settings -> a -> IO a
mcmcContinue Iterations
dn Settings
s = Settings -> a -> IO a
forall a. Algorithm a => Settings -> a -> IO a
mcmc Settings
s'
  where
    n' :: Iterations
n' = Int -> Iterations
Iterations (Int -> Iterations) -> Int -> Iterations
forall a b. (a -> b) -> a -> b
$ Iterations -> Int
fromIterations (Settings -> Iterations
sIterations Settings
s) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Iterations -> Int
fromIterations Iterations
dn
    s' :: Settings
s' = Settings
s {sIterations :: Iterations
sIterations = Iterations
n', sExecutionMode :: ExecutionMode
sExecutionMode = ExecutionMode
Continue}