1 Directory Structure of PDMPFlux.jl/src
1.1 Composites.jl
composites / constructs such as BoundBox
, PDMPState
, PDMPHistory
are defined.
BoundBox
is basically a grid, together with the values on it, to perform thinning.PDMPState
is used to keep the position of the sampler. The wholeSamplingLoop.jl
Section 1.3 is implemented as functions that modify thePDMPState
in place. In addition to the \((x,v,t)\) tuple, the fields includestate.rate
andstate.rate_vect
are the rate function and its vectorized version. These slots are determined after checking the fieldpdmp.signed_bound
ininit_state()
inAbstractPDMP.jl
Section 2.1.state.upper_bound_func()
is a function that takes \((x,v,t)\) and returns theBoundBox
object. Basically,state.upper_bound_func()
is the only field that differs among samplers.- boolean flags to indicate whether Poisson thinning proposal is accepted or not, which is used within
ac_step_with_proxy()
in theSamplingLoop.jl
Section 1.3. - proposed jump time
tp
and time already spentts
. They are using inSamplingLoop.jl
Section 1.3 to conduct poisson thinning, wheretp
is the proposed jump time, and is added tots
when rejected. - statistics to diagnose the sampler dynamic.
1.2 sample.jl
sample.jl
contains functions, called by users, to start MCMC sampling. The ProgressBar
package is used to be friendly to users.
sample.jl
contains 2 functions, and sample()
that calls them in sequel.
sample_skeleton() -> PDMPHistory
initializes the progress bar andPDMPState
&PDMPHistory
objects, usinginit_state()
andPDMPHistory()
constructor respectively. Then callget_event_state()
inSamplingLoop.jl
Section 1.3 foriter::Int
times.sample_from_skeleton() -> Matrix{Float64}
is a function that generates samples, which might subsequently be called by the plotting functions inplot.jl
.
1.3 SamplingLoop.jl
This module contains 10 functions. Some of them are summarized in the following figure:
The main loop for sampling is implemented here.
get_event_state() -> PDMPState
is the entering point fromsample.jl
.There is only one thing in
get_event_state()
, i.e., calllingone_step_of_thinning()
untilstate.accept
becomestrue
.get_event_state()
returns aPDMPState
object with the field \((x,v,t)\) indicating where an accepted event happens, which is pushed toPDMPHistory
back insample_skeleton()
insample.jl
Section 1.2.
one_step_of_thinning()
returns where simulation has completed up to, withstate.accept = false
if any proposal isnot accepted yet.Firstly, it proposes the next jump event, by simulating
exp_rv
and callingnext_event(upper_bound, exp_rv) -> (tp, lambda_bar)
.upper_bound
is theBoundBox
object, which is calculated bystate.upper_bound_func()
and the current state(x,v,t)
.tp
is the proposed jump time.lambda_bar
is a upper bound, with error, for the rate function \(\lambda\).
Secondly, it checks whether
tp <= state.horizon
.- If not, it calls
move_to_horizon()
and continues the loopone_step_of_thinning()
insideget_event_state()
. - If yes, it proceeds to
moves_until_horizon()
, where another loop, callingac_step()
, is performed until one of the following 2 happens- when
state.accept
becomestrue
, it gets out of the both loops. - when
tp > state.horizon
, it callsmove_to_horizon2()
to get out ofac_step()
loop, and continues the loopone_step_of_thinning()
insideget_event_state()
.
- when
- If not, it calls
ac_step()
, standing for acceptance-rejection step, is the core of Poisson thinning.calculating the acceptance rate
ar
, which might exceed \(1.0\).In that case,
erroneous_acceptance_rate()
is called to shrink thehorizon
by half, and then continues theac_step()
loop inmoves_until_horizon()
function. Shrinkinghorizon
leads to a finer grid, sincen_grid
is fixed.Otherwise, it performs the Poisson thinning using the proxy rate
lambda_bar
, inac_step_with_proxy()
call.- Within
ac_step_with_proxy()
, eitherif_accept()
orif_reject()
is called depending on the result of Poisson thinning, followed bymove_to_horizon2()
if accepted. Whether accepted or not is informed bystate.accept
flag, which will lead you out of all the loops. - In
if_accept()
, the flags are updated asstate.accept = true
&state.accept = true
, getting out of bothac_step()
loop andone_step_of_thinning()
loop, with the correct \((x,v,t)\) stored in appropriatestate
’s fields, which is pushed toPDMPHistory
back insample_skeleton()
insample.jl
Section 1.2. if_reject()
being called, we are still in theac_step()
loop inmoves_until_horizon()
, until acceptance ortp > state.horizon
.
- Within
1.4 UpperBound.jl
This module contains 2 functions, upper_bound_constant()
and upper_bound_adaptive()
.
upper_bound_constant()
computes the constant upper bound using the Brent’s algorithm.upper_bound_adaptive()
computes the adaptive upper bound using the Brent’s algorithm.
1.5 plot.jl
This file contains functions to plot the samples generated by sample.jl
.
2 Implementation of the Samplers
2.1 Samplers/AbstractPDMP.jl
This module contains one line
and one function
init_state(pdmp::AbstractPDMP, xinit::Array{Float64}, vinit::Array{Float64}, seed::Int) -> PDMPState
init_state()
is basically a constructor for PDMPState
. This is defined in AbstractPDMP.jl
, because the composite PDMPState
must have different field values depending on the type of the samplers.
init_state()
mainly does two things
- Check the field
pdmp.signed_bound
and initialize the 3 fieldsrate
,rate_vect
,refresh_rate
accordingly. - Check the field
pdmp.grid_size
&pdmp.vectorized_bound
and initialize the fieldupper_bound_func
as one of the functions in theUpperBound.jl
Section 1.4 module accordingly.
2.2 Samplers/StickyZigZagSamplers.jl
This module implements the Sticky Zig-Zag sampler, a variant of the Zig-Zag sampler that allows for sticky behavior at boundaries or other specified conditions.
- The sampler modifies the velocity component of the state when certain conditions are met.
- It is particularly useful for models with reflective or sticky boundaries.