|
Boost : |
From: John Maddock (john_at_[hidden])
Date: 2007-06-12 05:37:38
Following the successful review of the math-toolkit of special functions and
statistical distributions the main feature request was for a better way of
customising the library: both for choosing between precision vs speed
tradeoffs, and for determining how errors are best handled. I've been
experimenting with various policy-based interfaced based on Boost.Parameter,
and I think I now have something useable, so I'd like to know what people
think:
Policy Defaults
~~~~~~~~~~~~~~~
The library will use a sensible set of defaults (throw on domain errors and
internal evaluation errors, favour accuracy over speed etc), which can be
changed via the usual macro mechanism, so adding:
#define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error
#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignor_error
to a user-config header would do what they say to the default policies.
Add Hock Changes:
~~~~~~~~~~~~~~~~~
We can create an ad-hock policy change at the call site by using the
make_policy function, for example:
using namespace boost::math::policy;
using namespace boost::math;
quantile(
poisson(100),
0.05,
make_policy(
// 5 dicimal digits precision only
digits10<10>(),
// don't internally promote double->long double for extra precision:
promote_double<false>(),
// return integer result, immediately below the "real" value:
discrete_quantile<integer_below>()
));
Which returns the lower 95% quantile (ie critical value) of a poisson
distribution with rate parameter of 100 event's per unit time. The result
is calculated using only 10 decimal digits internal precision, truncated to
the largest integer that gives a CDF less than 0.05.
Predefined Policies
~~~~~~~~~~~~~~~~~~~
Although ad-hock policies are useful for testing, I imagine most sites would
want a few carefully controlled (and tested) policies. To achieve that you
define a typedef of the policy class:
using namespace boost::math::policy;
typedef policy<
// Set error handling:
domain_error<throw_on_error>,
pole_error<throw_on_error>,
overflow_error<throw_on_error>,
evaluation_error<throw_on_error>,
denorm_error<ignor_error>,
underflow_error<ignor_error>,
// calculate to 8 decimal digits internally
digits10<8>,
// don't promote double->long double for accuracy
promote_double<false>,
// Integer quantiles return the "outside edge":
// below the real value for lower critical values,
// above it for upper critical values, so that the
// area inside contains *at least* the requested coverage:
discrete_quantile<integer_outside_edge>
> fast_quantile_policy;
static fast_quantile_policy fast_quantile;
Then we can just use:
quantile(
poisson(100),
0.05,
fast_quantile);
In our actual code.
Currently this policy interface is vapourware: I have enough of a prototype
implemented to know that it's possible to achieve this syntax (this is
revision #3 already !), but there's a lot of hairy meta-programming to
convert that into something that the library's internals can make use of...
so I'd like to know what folks think before I invest too much time messing
about with MPL :-)
The main disadvantage I've noticed at present, is that the mangled names of
the policy class - and therefore all the special functions etc - are *very*
long. This has an impact on error messages: in particular we currently use
BOOST_CURRENT_FUNCTION to get a nice formatted name of a function that's
about to throw, but with function names a couple of pages long I don't think
that will be possible with this interface any more :-(
Thanks in advance, John Maddock.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk