boltzmann-brain-1.3.1.3: Data/Boltzmann/System/Oracle.hs
{-|
Module : Data.Boltzmann.System.Oracle
Description : Numeric Newton oracle utilities.
Copyright : (c) Maciej Bendkowski, 2017
License : BSD3
Maintainer : maciej.bendkowski@tcs.uj.edu.pl
Stability : experimental
Numerical Newton oracles meant for combinatorial systems
without additional tuning parameters. Note that, alternatively,
convex optimisation methods are also available.
-}
module Data.Boltzmann.System.Oracle
( singularity
, parametrise
) where
import qualified Data.Map as M
import Numeric.LinearAlgebra hiding (size)
import Data.Boltzmann.System
import Data.Boltzmann.System.Jacobian
computeProb :: System Int -> Double -> Vector Double -> System Double
computeProb sys z ys = sys { defs = M.mapWithKey computeProb' (defs sys) }
where computeProb' t = computeExp (value t sys ys) 0.0
computeExp _ _ [] = []
computeExp tw w (e:es) = e { weight = x / tw } : computeExp tw x es
where w' = evalC sys z ys e
x = w' + w
-- | Compute the numerical Boltzmann probabilities for the given system.
parametrise :: System Int -> Double -> Double -> PSystem Double
parametrise sys rho eps = parametrise' initState state sys rho eps
where initState = size sys |> [0..]
state = newton sys initState rho
parametrise' :: Vector Double -> Vector Double
-> System Int -> Double -> Double -> PSystem Double
parametrise' state' state sys rho eps
| not $ halt eps state' state =
let newState = newton sys state rho
in parametrise' state newState sys rho eps
| otherwise = PSystem { system = computeProb sys rho state
, values = state
, param = rho
, weights = sys
}
-- | Newton iteration for combinatorial systems.
newton :: System Int -> Vector Double -> Double -> Vector Double
newton sys state rho = state + (inv (ide - m) #> (h - state))
where h = eval sys state rho
m = jacobian sys rho state
ide = ident $ size sys
-- | Finds a numerical approximation of the system's dominating singularity.
singularity :: System Int -> Double -> Double
singularity sys eps = singularity' 0 1.0
where singularity' lb ub
| abs (ub - lb) < eps = lb
| otherwise = if divergent sys eps z then singularity' lb z
else singularity' z ub
where z = (ub + lb) / 2
divergent :: System Int -> Double -> Double -> Bool
divergent sys eps z = divergent' 0 state initState
where initState = size sys |> [0..]
state = newton sys initState z
divergent' :: Int -> Vector Double -> Vector Double -> Bool
divergent' iter v v'
| negative v || iter >= 25 = True
| halt eps v v' = False
| otherwise = divergent' (iter+1) (newton sys v z) v
negative :: Vector Double -> Bool
negative v = any (< 0) $ toList v
-- | Decide whether the system diverges or not.
halt :: Double -> Vector Double -> Vector Double -> Bool
halt eps v w = all (< eps) $ toList $ cmap abs (v - w)