A generic "ziggurat algorithm" implementation. Fairly rough right now.
There is a lot of room for improvement in findBin0
especially.
It needs a fair amount of cleanup and elimination of redundant
calculation, as well as either a justification for using the simple
findMinFrom
or a proper root-finding algorithm.
It would also be nice to add (preferably by pulling in an external package) support for numerical integration and differentiation, so that tables can be derived from only a PDF (if the end user is willing to take the performance and accuracy hit for the convenience).
- data Ziggurat v t = Ziggurat {}
- mkZigguratRec :: (RealFloat t, Vector v t, Distribution Uniform t) => Bool -> (t -> t) -> (t -> t) -> (t -> t) -> t -> Int -> RVar (Int, t) -> Ziggurat v t
- mkZiggurat :: (RealFloat t, Vector v t, Distribution Uniform t) => Bool -> (t -> t) -> (t -> t) -> (t -> t) -> t -> Int -> RVar (Int, t) -> (t -> RVar t) -> Ziggurat v t
- mkZiggurat_ :: (RealFloat t, Vector v t, Distribution Uniform t) => Bool -> (t -> t) -> (t -> t) -> Int -> t -> t -> RVar (Int, t) -> RVar t -> Ziggurat v t
- findBin0 :: RealFloat b => Int -> (b -> b) -> (b -> b) -> (b -> b) -> b -> (b, b)
- runZiggurat :: (Num a, Ord a, Vector v a) => Ziggurat v a -> RVar a
Documentation
A data structure containing all the data that is needed to implement Marsaglia & Tang's "ziggurat" algorithm for sampling certain kinds of random distributions.
The documentation here is probably not sufficient to tell a user exactly
how to build one of these from scratch, but it is not really intended to
be. There are several helper functions that will build Ziggurat
s.
The pathologically curious may wish to read the runZiggurat
source.
That is the ultimate specification of the semantics of all these fields.
Ziggurat | |
|
(Num t, Ord t, Vector v t) => Distribution (Ziggurat v) t |
mkZigguratRec :: (RealFloat t, Vector v t, Distribution Uniform t) => Bool -> (t -> t) -> (t -> t) -> (t -> t) -> t -> Int -> RVar (Int, t) -> Ziggurat v tSource
Build a lazy recursive ziggurat. Uses a lazily-constructed ziggurat as its tail distribution (with another as its tail, ad nauseum).
Arguments:
- flag indicating whether to mirror the distribution
- the (one-sided antitone) PDF, not necessarily normalized
- the inverse of the PDF
- the integral of the PDF (definite, from 0)
- the estimated volume under the PDF (from 0 to +infinity)
- the chunk size (number of bins in each layer). 64 seems to perform well in practice.
- an RVar providing the
zGetIU
random tuple
mkZiggurat :: (RealFloat t, Vector v t, Distribution Uniform t) => Bool -> (t -> t) -> (t -> t) -> (t -> t) -> t -> Int -> RVar (Int, t) -> (t -> RVar t) -> Ziggurat v tSource
Build the tables to implement the "ziggurat algorithm" devised by Marsaglia & Tang, attempting to automatically compute the R and V values.
Arguments are the same as for mkZigguratRec
, with an additional
argument for the tail distribution as a function of the selected
R value.
mkZiggurat_ :: (RealFloat t, Vector v t, Distribution Uniform t) => Bool -> (t -> t) -> (t -> t) -> Int -> t -> t -> RVar (Int, t) -> RVar t -> Ziggurat v tSource
Build the tables to implement the "ziggurat algorithm" devised by Marsaglia & Tang, attempting to automatically compute the R and V values.
Arguments:
- flag indicating whether to mirror the distribution
- the (one-sided antitone) PDF, not necessarily normalized
- the inverse of the PDF
- the number of bins
- R, the x value of the first bin
- V, the volume of each bin
- an RVar providing the
zGetIU
random tuple - an RVar sampling from the tail (the region where x > R)
findBin0 :: RealFloat b => Int -> (b -> b) -> (b -> b) -> (b -> b) -> b -> (b, b)Source
I suspect this isn't completely right, but it works well so far. Search the distribution for an appropriate R and V.
Arguments:
- Number of bins
- target function (one-sided antitone PDF, not necessarily normalized)
- function inverse
- function definite integral (from 0 to _)
- estimate of total volume under function (integral from 0 to infinity)
Result: (R,V)