packages feed

lazyppl-1.1.0: test/TestLogPdf.hs

module Main where

import LazyPPL.Distributions
import System.Exit (exitFailure, exitSuccess)

approxEq :: String -> Double -> Double -> Double -> IO Bool
approxEq name expected actual tol = do
  let ok = expected == actual || abs (expected - actual) < tol
  if ok
    then putStrLn $ "  PASS: " ++ name
    else putStrLn $ "  FAIL: " ++ name ++ " expected=" ++ show expected ++ " actual=" ++ show actual
  return ok

main :: IO ()
main = do
  putStrLn "Testing log-PDF/PMF functions..."
  results <- sequence
    [ approxEq "normalLogPdf 0 1 0" (-0.9189385) (normalLogPdf 0 1 0) 1e-4
    , approxEq "normalLogPdf 0 1 1" (-1.4189385) (normalLogPdf 0 1 1) 1e-4
    , approxEq "exponentialLogPdf 1 1" (-1.0) (exponentialLogPdf 1 1) 1e-6
    , approxEq "exponentialLogPdf 2 0.5" (log 2 - 1.0) (exponentialLogPdf 2 0.5) 1e-6
      -- (k-1)*log(1) - 1/1 - 2*log(1) - logGamma(2) = -1
    , approxEq "gammaLogPdf 2 1 1" (-1.0) (gammaLogPdf 2 1 1) 1e-6
    , approxEq "betaLogPdf 1 1 0.5" 0.0 (betaLogPdf 1 1 0.5) 1e-6
      -- B(2,2) = 1/6, pdf at 0.5 = 6*0.25 = 1.5
    , approxEq "betaLogPdf 2 2 0.5" (log 1.5) (betaLogPdf 2 2 0.5) 1e-6
    , approxEq "bernoulliLogPmf 0.3 True" (log 0.3) (bernoulliLogPmf 0.3 True) 1e-6
    , approxEq "bernoulliLogPmf 0.3 False" (log 0.7) (bernoulliLogPmf 0.3 False) 1e-6
    , approxEq "categoricalLogPmf [0.2,0.3,0.5] 2" (log 0.5) (categoricalLogPmf [0.2, 0.3, 0.5] 2) 1e-6
    , approxEq "categoricalLogPmf OOB" (-1/0) (categoricalLogPmf [0.5, 0.5] 3) 1e-6 -- Outside the support: probability 0, log 0 = -Infinity.
    , approxEq "uniformBoundedLogPdf 0 10 5" (-log 10) (uniformBoundedLogPdf 0 10 5) 1e-6
    , approxEq "uniformBoundedLogPdf OOB" (-1/0) (uniformBoundedLogPdf 0 1 2) 1e-6 -- Outside the support: probability 0, log 0 = -Infinity.
      -- Dirichlet(1,1,1) normalizer = Gamma(3)/(Gamma(1)^3) = 2
    , approxEq "dirichletLogPdf [1,1,1] uniform" (log 2) (dirichletLogPdf [1,1,1] [1/3, 1/3, 1/3]) 1e-4
    , approxEq "logNormalLogPdf 0 1 1" (-0.9189385) (logNormalLogPdf 0 1 1) 1e-4
    , approxEq "logNormalLogPdf negative" (-1/0) (logNormalLogPdf 0 1 (-1)) 1e-6 -- Outside the support: probability 0, log 0 = -Infinity.
      -- C(10,5) = 252
    , approxEq "binomialLogPmf 10 0.5 5" (log 252 - 10 * log 2) (binomialLogPmf 10 0.5 5) 1e-4
    , approxEq "binomialLogPmf OOB" (-1/0) (binomialLogPmf 5 0.3 6) 1e-6 -- Outside the support: probability 0, log 0 = -Infinity.
    , approxEq "poissonLogPmf 3 2" (2 * log 3 - 3 - log 2) (poissonLogPmf 3 2) 1e-6
    ]
  let nPass  = length (filter id results)
      nTotal = length results
  putStrLn $ show nPass ++ "/" ++ show nTotal ++ " tests passed."
  if nPass == nTotal then exitSuccess else exitFailure