boltzmann-brain-1.6: Data/Boltzmann/System/Tuner/Algebraic.hs
{-|
Module : Data.Boltzmann.System.Tuner.Algebraic
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.Algebraic
( writeSpecification
, paramSystem
, toPSpec
) where
import Control.Monad
import System.IO
import qualified Data.Map.Strict as M
import Numeric.LinearAlgebra hiding (size)
import Data.MultiSet (MultiSet)
import qualified Data.MultiSet as B
import qualified Data.Set as S
import Data.Maybe
import Data.Boltzmann.System
import Data.Boltzmann.Internal.Utils
import Data.Boltzmann.Internal.Tuner
-- | Writes the system specification into the given
-- file handle. In paricular, to Paganini's standard
-- input handle.
writeSpecification :: System Int -> Handle -> IO ()
writeSpecification sys hout = do
let freqs = frequencies sys
let seqs = seqTypes sys
let spec = toPSpec sys
-- # of equations and frequencies
writeListLn hout [numTypes spec + numSeqTypes spec, length freqs]
-- vector of frequencies
writeListLn hout freqs
-- type specifications
let find' x = x `S.findIndex` M.keysSet (defs sys)
foldM_ (typeSpecification hout find' spec) 0 (M.elems $ defs sys)
-- sequence specifications
mapM_ (seqSpecification hout find' spec) seqs
frequencies :: System Int -> [Double]
frequencies sys = concatMap (mapMaybe frequency)
((M.elems . defs) sys)
toPSpec :: System Int -> PSpec
toPSpec sys = PSpec { numFreqs = d
, numTypes = ts
, numSeqTypes = ss
}
where ts = size sys
d = length $ frequencies sys
ss = length $ seqTypes sys
typeSpecification :: Handle -> (String -> Int) -> PSpec
-> Int -> [Cons Int] -> IO Int
typeSpecification hout find' spec idx cons = do
let n = length cons
hPrint hout n -- # of constructors
foldM (consSpecification hout find' spec) idx cons
consSpecification :: Handle -> (String -> Int) -> PSpec
-> Int -> Cons Int -> IO Int
consSpecification hout find' spec idx cons = do
let (vec, idx') = sparseConsVec find' spec idx cons
writeListLn hout vec -- constructor specification
return idx'
occurrences :: Cons a -> (MultiSet String, MultiSet String)
occurrences cons = occurrences' (B.empty,B.empty) $ args cons
occurrences' :: (MultiSet String, MultiSet String)
-> [Arg] -> (MultiSet String, MultiSet String)
occurrences' (ts,sts) [] = (ts,sts)
occurrences' (ts,sts) (Type s : xs) = occurrences' (s `B.insert` ts,sts) xs
occurrences' (ts,sts) (List s : xs) = occurrences' (ts, s `B.insert` sts) xs
-- | Prepends a pair to a list if its
-- first component is positive.
sparsePrepend :: (Num a, Ord a)
=> (a, b) -> [(a, b)] -> [(a, b)]
sparsePrepend x xs
| fst x > 0 = x : xs
| otherwise = xs
prependWeight :: (Num a, Ord a, Num b)
=> Cons a -> [(a, b)] -> [(a, b)]
prependWeight cons =
sparsePrepend (weight cons, 0)
prependFreq :: (Num a, Ord a, Num b)
=> Cons a -> b -> [(a, b)] -> [(a, b)]
prependFreq cons idx xs
| isJust (frequency cons) =
sparsePrepend (weight cons, 1 + idx) xs -- note: offset for z
| otherwise = xs
sparseTypeVec :: Num a => (b -> a) -> a -> [(b, c)] -> [(c, a)]
sparseTypeVec _ _ [] = []
sparseTypeVec find' offset ((t,n) : xs) =
(n, offset + find' t) : sparseTypeVec find' offset xs
sparseConsVec :: (String -> Int) -> PSpec
-> Int -> Cons Int -> ([(Int,Int)], Int)
sparseConsVec find' spec idx cons =
let (tocc, socc) = occurrences cons
us = numFreqs spec
-- sparse type representation
tv = sparseTypeVec find' (1 + us) (B.toOccurList tocc)
ts = numTypes spec
-- sparse sequence representation
sv = sparseTypeVec find' (1 + us + ts) (B.toOccurList socc)
-- prepend weight and frequency
xs = prependWeight cons (prependFreq cons idx $ tv ++ sv)
in case frequency cons of
Just _ -> (xs, idx + 1)
Nothing -> (xs, idx)
seqSpecification :: Handle -> (String -> Int) -> PSpec
-> String -> IO ()
seqSpecification hout find' spec st = do
hPrint hout (2 :: Int) -- # of constructors
writeListLn hout ([] :: [Int]) -- empty sequence constructor
let offset = 1 + numFreqs spec
writeListLn hout [(1, offset + find' st) :: (Int,Int)
,(1, offset + numTypes spec + find' st)] -- cons constructor
evalExp :: System Int -> Double -> Vector Double
-> [Double] -> Cons Int -> (Double, [Double])
evalExp sys rho ts us exp' =
let w = weight exp'
xs = args exp'
exp'' = (rho ^^ w) * product (map (evalA sys ts) xs)
in case frequency exp' of
Nothing -> (exp'', us)
Just _ -> (head us ^^ w * exp'', tail us)
computeExp :: System Int
-> Double -> Vector Double
-> [Double] -> Double -> Double -> [Cons Int]
-> ([Cons Double], [Double])
computeExp _ _ _ us _ _ [] = ([], us)
computeExp sys rho ts us tw _ (e:es) = (e { weight = w' / tw } : es', us'')
where (es', us'') = computeExp sys rho ts us' tw 0 es
(w', us') = evalExp sys rho ts us e
computeProb :: System Int
-> Double -> Vector Double
-> [Double] -> [(String, [Cons Int])]
-> [(String, [Cons Double])]
computeProb _ _ _ _ [] = []
computeProb sys rho ts us ((t,cons):tys) = (t,cons') : tys'
where (cons', us') = computeExp sys rho ts us (value t sys ts) 0 cons
tys' = computeProb sys rho ts us' tys
paramSystem :: System Int
-> Double -> Vector Double
-> [Double] -> PSystem Double
paramSystem sys rho ts us = sys'
where types' = computeProb sys rho ts us (M.toList $ defs sys)
sys' = PSystem { system = sys { defs = M.fromList types' }
, values = ts
, param = rho
, weights = sys
}