{-# LANGUAGE RankNTypes #-}

-- |
-- Module      :  Mcmc.Proposal.Slide
-- Description :  Additive proposals
-- Copyright   :  2021 Dominik Schrempf
-- License     :  GPL-3.0-or-later
--
-- Maintainer  :  dominik.schrempf@gmail.com
-- Stability   :  unstable
-- Portability :  portable
--
-- Creation date: Wed May  6 10:59:13 2020.
module Mcmc.Proposal.Slide
  ( slide,
    slideSymmetric,
    slideUniformSymmetric,
    slideContrarily,
  )
where

import Mcmc.Proposal
import Mcmc.Proposal.Generic
import Mcmc.Statistics.Types
import Statistics.Distribution.Normal
import Statistics.Distribution.Uniform

-- The actual proposal with tuning parameter.
slidePFunction :: Mean Double -> StandardDeviation Double -> TuningParameter -> PFunction Double
slidePFunction :: Mean Double
-> Mean Double -> Mean Double -> PFunction (Mean Double)
slidePFunction Mean Double
m Mean Double
s Mean Double
t =
  NormalDistribution
-> (Mean Double -> Mean Double -> Mean Double)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (Mean Double -> Mean Double -> Jacobian)
-> PFunction (Mean Double)
forall d a.
(ContDistr d, ContGen d) =>
d
-> (a -> Mean Double -> a)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (a -> Mean Double -> Jacobian)
-> PFunction a
genericContinuous (Mean Double -> Mean Double -> NormalDistribution
normalDistr Mean Double
m (Mean Double
s Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
* Mean Double
t)) Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
(+) ((Mean Double -> Mean Double) -> Maybe (Mean Double -> Mean Double)
forall a. a -> Maybe a
Just Mean Double -> Mean Double
forall a. Num a => a -> a
negate) Maybe (Mean Double -> Mean Double -> Jacobian)
forall a. Maybe a
Nothing

-- | Additive proposal.
--
-- A normal distribution is used to sample the addend.
slide ::
  Mean Double ->
  StandardDeviation Double ->
  PName ->
  PWeight ->
  Tune ->
  Proposal Double
slide :: Mean Double
-> Mean Double
-> PName
-> PWeight
-> Tune
-> Proposal (Mean Double)
slide Mean Double
m Mean Double
s = PDescription
-> (Mean Double -> PFunction (Mean Double))
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal (Mean Double)
forall a.
PDescription
-> (Mean Double -> PFunction a)
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal a
createProposal PDescription
description (Mean Double
-> Mean Double -> Mean Double -> PFunction (Mean Double)
slidePFunction Mean Double
m Mean Double
s) PSpeed
PFast (Int -> PDimension
PDimension Int
1)
  where
    description :: PDescription
description = String -> PDescription
PDescription (String -> PDescription) -> String -> PDescription
forall a b. (a -> b) -> a -> b
$ String
"Slide; mean: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Mean Double -> String
forall a. Show a => a -> String
show Mean Double
m String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", sd: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Mean Double -> String
forall a. Show a => a -> String
show Mean Double
s

-- The actual proposal with tuning parameter.
slideSymmetricPFunction :: StandardDeviation Double -> TuningParameter -> PFunction Double
slideSymmetricPFunction :: Mean Double -> Mean Double -> PFunction (Mean Double)
slideSymmetricPFunction Mean Double
s Mean Double
t =
  NormalDistribution
-> (Mean Double -> Mean Double -> Mean Double)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (Mean Double -> Mean Double -> Jacobian)
-> PFunction (Mean Double)
forall d a.
(ContDistr d, ContGen d) =>
d
-> (a -> Mean Double -> a)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (a -> Mean Double -> Jacobian)
-> PFunction a
genericContinuous (Mean Double -> Mean Double -> NormalDistribution
normalDistr Mean Double
0.0 (Mean Double
s Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
* Mean Double
t)) Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
(+) Maybe (Mean Double -> Mean Double)
forall a. Maybe a
Nothing Maybe (Mean Double -> Mean Double -> Jacobian)
forall a. Maybe a
Nothing

-- | See 'slide'.
--
-- Use a normal distribution with mean zero. This proposal is fast, because the
-- Metropolis-Hastings-Green ratio does not include calculation of the forwards
-- and backwards kernels.
slideSymmetric ::
  StandardDeviation Double ->
  PName ->
  PWeight ->
  Tune ->
  Proposal Double
slideSymmetric :: Mean Double -> PName -> PWeight -> Tune -> Proposal (Mean Double)
slideSymmetric Mean Double
s = PDescription
-> (Mean Double -> PFunction (Mean Double))
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal (Mean Double)
forall a.
PDescription
-> (Mean Double -> PFunction a)
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal a
createProposal PDescription
description (Mean Double -> Mean Double -> PFunction (Mean Double)
slideSymmetricPFunction Mean Double
s) PSpeed
PFast (Int -> PDimension
PDimension Int
1)
  where
    description :: PDescription
description = String -> PDescription
PDescription (String -> PDescription) -> String -> PDescription
forall a b. (a -> b) -> a -> b
$ String
"Slide symmetric; sd: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Mean Double -> String
forall a. Show a => a -> String
show Mean Double
s

-- The actual proposal with tuning parameter.
slideUniformPFunction :: Size -> TuningParameter -> PFunction Double
slideUniformPFunction :: Mean Double -> Mean Double -> PFunction (Mean Double)
slideUniformPFunction Mean Double
d Mean Double
t =
  UniformDistribution
-> (Mean Double -> Mean Double -> Mean Double)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (Mean Double -> Mean Double -> Jacobian)
-> PFunction (Mean Double)
forall d a.
(ContDistr d, ContGen d) =>
d
-> (a -> Mean Double -> a)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (a -> Mean Double -> Jacobian)
-> PFunction a
genericContinuous (Mean Double -> Mean Double -> UniformDistribution
uniformDistr (-Mean Double
t Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
* Mean Double
d) (Mean Double
t Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
* Mean Double
d)) Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
(+) Maybe (Mean Double -> Mean Double)
forall a. Maybe a
Nothing Maybe (Mean Double -> Mean Double -> Jacobian)
forall a. Maybe a
Nothing

-- | See 'slide'.
--
-- Use a uniformly distributed kernel with mean zero. This proposal is fast,
-- because the Metropolis-Hastings-Green ratio does not include calculation of
-- the forwards and backwards kernels.
slideUniformSymmetric ::
  Size ->
  PName ->
  PWeight ->
  Tune ->
  Proposal Double
slideUniformSymmetric :: Mean Double -> PName -> PWeight -> Tune -> Proposal (Mean Double)
slideUniformSymmetric Mean Double
d = PDescription
-> (Mean Double -> PFunction (Mean Double))
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal (Mean Double)
forall a.
PDescription
-> (Mean Double -> PFunction a)
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal a
createProposal PDescription
description (Mean Double -> Mean Double -> PFunction (Mean Double)
slideUniformPFunction Mean Double
d) PSpeed
PFast (Int -> PDimension
PDimension Int
1)
  where
    description :: PDescription
description = String -> PDescription
PDescription (String -> PDescription) -> String -> PDescription
forall a b. (a -> b) -> a -> b
$ String
"Slide uniform symmetric; delta: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Mean Double -> String
forall a. Show a => a -> String
show Mean Double
d

contra :: (Double, Double) -> Double -> (Double, Double)
contra :: (Mean Double, Mean Double)
-> Mean Double -> (Mean Double, Mean Double)
contra (Mean Double
x, Mean Double
y) Mean Double
u = (Mean Double
x Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
+ Mean Double
u, Mean Double
y Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
- Mean Double
u)

slideContrarilyPFunction ::
  Mean Double ->
  StandardDeviation Double ->
  TuningParameter ->
  PFunction (Double, Double)
slideContrarilyPFunction :: Mean Double
-> Mean Double
-> Mean Double
-> PFunction (Mean Double, Mean Double)
slideContrarilyPFunction Mean Double
m Mean Double
s Mean Double
t =
  NormalDistribution
-> ((Mean Double, Mean Double)
    -> Mean Double -> (Mean Double, Mean Double))
-> Maybe (Mean Double -> Mean Double)
-> Maybe ((Mean Double, Mean Double) -> Mean Double -> Jacobian)
-> PFunction (Mean Double, Mean Double)
forall d a.
(ContDistr d, ContGen d) =>
d
-> (a -> Mean Double -> a)
-> Maybe (Mean Double -> Mean Double)
-> Maybe (a -> Mean Double -> Jacobian)
-> PFunction a
genericContinuous (Mean Double -> Mean Double -> NormalDistribution
normalDistr Mean Double
m (Mean Double
s Mean Double -> Mean Double -> Mean Double
forall a. Num a => a -> a -> a
* Mean Double
t)) (Mean Double, Mean Double)
-> Mean Double -> (Mean Double, Mean Double)
contra ((Mean Double -> Mean Double) -> Maybe (Mean Double -> Mean Double)
forall a. a -> Maybe a
Just Mean Double -> Mean Double
forall a. Num a => a -> a
negate) Maybe ((Mean Double, Mean Double) -> Mean Double -> Jacobian)
forall a. Maybe a
Nothing

-- | See 'slide'.
--
-- Use a normally distributed kernel.
--
-- The two values are slid contrarily so that their sum stays constant. Contrary
-- proposals are useful when parameters are confounded.
slideContrarily ::
  Mean Double ->
  StandardDeviation Double ->
  PName ->
  PWeight ->
  Tune ->
  Proposal (Double, Double)
slideContrarily :: Mean Double
-> Mean Double
-> PName
-> PWeight
-> Tune
-> Proposal (Mean Double, Mean Double)
slideContrarily Mean Double
m Mean Double
s = PDescription
-> (Mean Double -> PFunction (Mean Double, Mean Double))
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal (Mean Double, Mean Double)
forall a.
PDescription
-> (Mean Double -> PFunction a)
-> PSpeed
-> PDimension
-> PName
-> PWeight
-> Tune
-> Proposal a
createProposal PDescription
description (Mean Double
-> Mean Double
-> Mean Double
-> PFunction (Mean Double, Mean Double)
slideContrarilyPFunction Mean Double
m Mean Double
s) PSpeed
PFast (Int -> PDimension
PDimension Int
2)
  where
    description :: PDescription
description = String -> PDescription
PDescription (String -> PDescription) -> String -> PDescription
forall a b. (a -> b) -> a -> b
$ String
"Slide contrarily; mean: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Mean Double -> String
forall a. Show a => a -> String
show Mean Double
m String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", sd: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Mean Double -> String
forall a. Show a => a -> String
show Mean Double
s