boltzmann-brain-1.6: Data/Boltzmann/System/Tuner.hs
{-|
Module : Data.Boltzmann.System.Tuner
Description : Interface utilities with the Paganini tuner.
Copyright : (c) Maciej Bendkowski, 2017-2019
License : BSD3
Maintainer : maciej.bendkowski@tcs.uj.edu.pl
Stability : experimental
General utilities managing the IO interface between Boltzmann Brain
and the Paganini tuner script.
-}
module Data.Boltzmann.System.Tuner
( readPaganini
, runPaganini
) where
import Control.Exception
import Data.Void
import qualified Data.Map.Strict as M
import Numeric.LinearAlgebra hiding (size,double)
import System.IO
import System.Process hiding (system)
import Text.Megaparsec
import Data.Boltzmann.Internal.Logging
import Data.Boltzmann.Internal.Parser
import Data.Boltzmann.Internal.Tuner
import Data.Boltzmann.Internal.Utils
import Data.Boltzmann.System
import qualified Data.Boltzmann.System.Tuner.Algebraic as A
import qualified Data.Boltzmann.System.Tuner.Rational as R
type Parser = Parsec Void String
-- | Catch IO exceptions.
try' :: IO a -> IO (Either IOException a)
try' = Control.Exception.try
-- | Communicates with Paganini and collects the respective
-- tuning vector for the given system. If communication is not possible,
-- for instance due to the missing Paganini script, the current process
-- is terminated with an error message on the standard error output.
runPaganini :: Format
-> System Int
-> Parametrisation
-> Maybe PArg
-> IO (Either (ParseErrorBundle String Void) (PSystem Double))
runPaganini sysFormat sys paramT arg = do
info "Running paganini..."
let arg' = getArgs sys arg
info (printer (++) $ "Arguments: " : toArgs arg')
-- Execute the paganini tuning script.
pp <- try' $ createProcess
(proc "medulla" (toArgs arg'))
{ std_out = CreatePipe, std_in = CreatePipe }
case pp of
Left _ -> fail' "Could not locate the medulla tuner. Is is available in the PATH?"
Right (Just hin, Just hout, _, _) -> do
-- write to paganini's stdout
info "Writing system specification..."
case sysFormat of
RationalF -> R.writeSpecification sys hin
AlgebraicF -> A.writeSpecification sys hin
-- read output parameters
let spec = case sysFormat of
RationalF -> R.toPSpec sys
AlgebraicF -> A.toPSpec sys
s <- hGetContents hout
let pag = parse (paganiniStmt spec) "" s
case pag of
Left err -> return $ Left err
Right (rho, us, ts) -> do
info "Parsing paganini output..."
let ts' = fromList ts
let sys' = parametrise sysFormat sys paramT rho ts' us
return $ Right sys'
_ -> fail' "Could not establish inter-process communication with medulla."
-- | Parses the given input string as a Paganini tuning vector.
readPaganini :: Format -> System Int -> Parametrisation -> String
-> IO (Either (ParseErrorBundle String Void)
(PSystem Double))
readPaganini sysFormat sys paramT f = do
let spec = case sysFormat of
RationalF -> R.toPSpec sys
AlgebraicF -> A.toPSpec sys
pag <- parsePaganini spec f
case pag of
Left err -> return $ Left err
Right (rho, us, ts) -> do
let ts' = fromList ts
return (Right $ parametrise sysFormat sys paramT rho ts' us)
paganiniStmt :: PSpec -> Parser (Double, [Double], [Double])
paganiniStmt spec = do
rho <- double
us <- parseN double $ numFreqs spec
ts <- parseN double $ numTypes spec
return (rho, us, ts)
-- | Parses the given Paganini specification.
parsePaganini :: PSpec -> String
-> IO (Either (ParseErrorBundle String Void)
(Double, [Double], [Double]))
parsePaganini spec = parseFromFile (paganiniStmt spec)
accumulateCons :: Double -> [Cons Double] -> [Cons Double]
accumulateCons _ [] = []
accumulateCons acc (con : xs) =
con' : accumulateCons acc' xs
where con' = con { weight = w + acc }
acc' = acc + w
w = weight con
accumulateType :: (String, [Cons Double]) -> (String, [Cons Double])
accumulateType (t, cons) =
(t, accumulateCons 0 cons)
accumulate :: PSystem Double -> PSystem Double
accumulate psys = psys { system = sys { defs = M.fromList types' } }
where sys = system psys
typs = M.toList (defs sys)
types' = map accumulateType typs
-- | Compute the numerical branching probabilities for the given system.
parametrise :: Format
-> System Int
-> Parametrisation
-> Double -> Vector Double
-> [Double] -> PSystem Double
parametrise sysFormat sys paramT rho ts us =
let sys' = paramFun sys rho ts us
paramFun = case sysFormat of
RationalF -> R.paramSystem
AlgebraicF -> A.paramSystem
in case paramT of
Regular -> sys'
Cummulative -> accumulate sys'