packages feed

boltzmann-brain-1.6: Data/Boltzmann/System/Tuner/Rational.hs

{-|
 Module      : Data.Boltzmann.System.Tuner.Rational
 Description : Interface utilities with the Paganini tuner.
 Copyright   : (c) Maciej Bendkowski, 2017-2019

 License     : BSD3
 Maintainer  : maciej.bendkowski@tcs.uj.edu.pl
 Stability   : experimental
 -}
module Data.Boltzmann.System.Tuner.Rational
    ( writeSpecification
    , paramSystem
    , toPSpec
    ) where

import System.IO

import Data.Maybe

import Data.Set (Set)
import qualified Data.Set as S
import qualified Data.Map.Strict as M

import Numeric.LinearAlgebra hiding (size)

import Data.Boltzmann.System

import Data.Boltzmann.Internal.Utils
import Data.Boltzmann.Internal.Tuner

toPSpec :: System Int -> PSpec
toPSpec sys = PSpec { numFreqs    = s
                    , numTypes    = t
                    , numSeqTypes = 0
                    }

   where t     = size sys
         alph  = alphabet sys
         s     = S.size (tunedLetters alph)

frequencies :: Set Letter -> [Double]
frequencies alph = mapMaybe freq (S.toList alph)

tunedLetters :: Set Letter -> Set Letter
tunedLetters = S.filter (isJust . freq)

writeSpecification :: System Int -> Handle -> IO ()
writeSpecification sys hout = do
    let spec = toPSpec sys

    -- # of equations and tuned symbols.
    writeListLn hout [numTypes spec, numFreqs spec]

    -- # requested letter frequencies.
    writeListLn hout (frequencies $ alphabet sys)

    -- type specifications
    let types' = types sys
    let alph   = tunedLetters $ alphabet sys
    mapM_ (typeSpecification hout alph types') (M.elems $ defs sys)

typeSpecification :: Handle -> Set Letter -> Set String -> [Cons Int] -> IO ()
typeSpecification hout alph types' cons = do
    let n = length cons
    hPrint hout n -- # of constructors
    mapM_ (consSpecification hout alph types') cons

sparsePrepend :: (Num a, Ord a)
              => (a, b) -> [(a, b)]
sparsePrepend x
  | fst x > 0 = [x]
  | otherwise = []

consSpecification :: Handle -> Set Letter -> Set String -> Cons Int -> IO ()
consSpecification hout alph types' con = do
    let z  = weight con
    let us = sparseMarkLetter alph z (func con) -- note: func con is the transition letter.
    let offset = 1 + S.size alph
    let ts = if isAtomic con then [] -- note: epsilon transition.
                             else sparseMarkType offset types' (head $ args con)

    writeListLn hout (sparsePrepend (z,0) ++ us ++ ts)

sparseMarkLetter :: Set Letter -> Int -> String -> [(Int,Int)]
sparseMarkLetter _ _ "_" = []
sparseMarkLetter alph w u =
    case letter `S.lookupIndex` alph of
      Nothing  -> []
      Just idx -> sparsePrepend (w, 1 + idx) -- note: offset for z
    where
        letter = Letter { symb = u, freq = Nothing, weightL = 0 }

sparseMarkType :: Int -> Set String -> Arg -> [(Int,Int)]
sparseMarkType offset types' (Type typ) = [(1, offset + idx)]
    where idx = typ `S.findIndex` types'

sparseMarkType _ _ _ = error "I wasn't expecting the Spanish inquisition!"

freqL :: Cons Int -> [Double] -> Alphabet -> Double
freqL con us alph =
    let f = func con -- note: func con is in fact the letter name.
        idx = Letter { symb = f, freq = Nothing, weightL = 0 } `S.findIndex` tunedLetters alph
        in case f `letterFreq` alph of
            Just _  -> us !! idx ^^ weight con
            Nothing -> 1

paramCons :: System Int -> Double -> Vector Double
          -> [Double] -> Double -> Cons Int -> Cons Double

paramCons sys rho ts us typW con
    | isAtomic con = con { weight = recip typW } -- note: epsilon transition
    | otherwise =
        let z    = rho ^^ weight con
            u    = freqL con us (alphabet sys)
            w    = z * u * value (argName $ head $ args con) sys ts
            in con { weight = w / typW }

paramType :: System Int -> Double -> Vector Double
          -> [Double] -> (String, [Cons Int]) -> (String, [Cons Double])

paramType sys rho ts us (t, cons) =
    (t, map (paramCons sys rho ts us typW) cons)
    where typW = value t sys ts

paramSystem :: System Int -> Double -> Vector Double
            -> [Double] -> PSystem Double

paramSystem sys rho ts us = sys'
    where typs   = M.toList (defs sys)
          types' = map (paramType sys rho ts us) typs
          sys'   = PSystem { system  = sys { defs = M.fromList types' }
                           , values  = ts
                           , param   = rho
                           , weights = sys
                           }