function [samples,seed] = ars1d(fun, dims, opts) % ARS1D 1-D derivative-free adaptive rejection sampler % % [samples,seed] = ars1d(fun, dims, opts) % % Efficient 1-D sampler for log-convex density functions. While sampling % , computes and refines a piecewise-exponential approximation to the % density function. Note that this MEX interface does not save this % approximation between calls; it's best to sample as many variates as you % think you'll need up front. % % The fun argument is the density function you wish to sample. It should be % be log concave and non-negative everywhere (unless it returns the log of the % density; see below). % % The dims argument is optional; if blank, the sampler returns one sample. % Otherwise, the argument works the same as the argument in single-argument % calls to MATLAB's rand function. % % The optional opts argument is a struct containing arguments for the sampler. % If opts is not specified, default options are used. Calling this function % with no arguments returns the default opts struct. Fields in opts include: % % x_min (default: -inf) % % Specifies the left bound of support for the density function. % May be infinite. % % x_max (default: inf) % % Specifies the right bound of support for the density function. % May be infinite. % % function_returns_log (default: false) % % Some distributions may be more numerically stable when expressed as the % log of the density function instead of the function itself. Set % this field to true iff fun returns the log of the density function. % % seed (optional) % % The sampler uses a different random number generator than MATLAB's--- % one provided by the Boost C++ library. Each call to the sampler must % seed this separate generator. If this field is missing from the opts % struct, a random seed value is generated from MATLAB's random number % generator. This way, to ensure identical samples, it's only necessary % to control MATLAB's random seed. If you wish to set the sampler's random % seed manually, however, specify a floating point number here in [0,1]. % % hint1, hint2, hint3 (default for all: -inf) % % Though pains have been taken to avoid it, this code may encounter % numerical contingencies that prevent it from sampling the density % function. If this happens, the samples result will contain a single NaN % value. Sometimes these difficulties can be overcome with more helpful % hints; other times, as in the case of betapdf(x,1.000001,2), the % resolution of doubles is insufficient for the sampler to locate points % around the mode of the density function. % % The extra return value "seed" will contain the random seed used to % initialize the sampler's random generator. % % The ars1d.m file is a wrapper for a MEX function, and it performs all of % the error checking for the routine. If you're sure your arguments are OK, % you can call mex_ars1d directly. With mex_ars1d, all of the optional % arguments and parameters for ars1d are mandatory, including the seed field % in opts. % If no arguments, return the default options struct if nargin == 0 samples = struct; samples.x_min = -inf; samples.x_max = inf; samples.function_returns_log = false; samples.hint1 = -inf; samples.hint2 = -inf; samples.hint3 = -inf; return; end % If no options, use the default options struct. Otherwise, sanity check % the options. if nargin < 3 opts = ars1d; else assert(opts.x_min < opts.x_max, 'x_min must be less than x_max in opts'); assert(isfield(opts,'function_returns_log'), ... 'opts missing required field "function_returns_log"'); assert(islogical(opts.function_returns_log), ... 'opts.function_returns_log must be a logical value'); assert(isfield(opts,'hint1'), 'opts missing required field "hint1"'); assert(isfield(opts,'hint2'), 'opts missing required field "hint2"'); assert(isfield(opts,'hint3'), 'opts missing required field "hint3"'); end % If no random seed, create a random seed if ~isfield(opts,'seed') opts.seed = rand; end % If no dimensions, we just want one sample. if nargin < 2 dims = 1; end % Furnish the random seed we used if nargout > 1 seed = opts.seed; end % Call the sampler samples = mex_ars1d(fun, dims, opts);