25 #if !defined(LSST_AFW_MATH_INTEGRATE_H)
26 #define LSST_AFW_MATH_INTEGRATE_H 1
178 #define integ_dbg1 if (false) (*_dbgout)
179 #define integ_dbg2 if (false) (*(reg.getDbgout()))
180 #define integ_dbg3 if (false) (*(tempreg.getDbgout()))
182 #define integ_dbg1 if (_dbgout) (*_dbgout)
183 #define integ_dbg2 if (reg.getDbgout()) (*(reg.getDbgout()))
184 #define integ_dbg3 if (tempreg.getDbgout()) (*(tempreg.getDbgout()))
191 template <
class T>
inline T
norm(
const T&
x) {
return x*
x; }
193 template <
class T>
inline T
real(
const T&
x) {
return x; }
208 bool operator<(IntRegion<T>
const &r2)
const {
return _error < r2._error; }
212 assert(children->size() == 0);
220 std::cerr <<
"a, b = " <<
_a <<
', ' <<
_b << std::endl;
221 std::cerr <<
"_splitpoints = ";
225 std::cerr << std::endl;
266 inline T
Epsilon() {
return std::numeric_limits<T>::epsilon(); }
268 inline T
MinRep() {
return std::numeric_limits<T>::min(); }
273 inline Quad Epsilon<Quad>() {
return 3.08148791094e-33; }
275 inline Quad MinRep<Quad>() {
return 2.2250738585072014e-308; }
281 if (resasc != 0.0 && err != 0.0) {
282 T
const scale = (200.0 * err / resasc);
284 err = resasc * scale * sqrt(scale);
290 if (resabs > MinRep<T>() / (50.0 * Epsilon<T>())) {
291 T
const min_err = 50.0 * Epsilon<T>() * resabs;
318 typename UF::result_type
const epsabs,
319 typename UF::result_type
const epsrel,
320 std::map<typename UF::result_type, typename UF::result_type>* fxmap = 0) {
322 typedef typename UF::result_type UfResult;
323 UfResult
const a = reg.
Left();
324 UfResult
const b = reg.
Right();
326 UfResult
const halfLength = 0.5 * (b - a);
327 UfResult
const absHalfLength = fabs (halfLength);
328 UfResult
const center = 0.5 * (b + a);
329 UfResult
const fCenter = func(center);
334 assert(gkp_wb<UfResult>(0).size() == gkp_x<UfResult>(0).size() + 1);
335 UfResult area1 = gkp_wb<UfResult>(0).back() * fCenter;
336 std::vector<UfResult> fv1, fv2;
337 fv1.reserve(2*gkp_x<UfResult>(0).size() + 1);
338 fv2.reserve(2*gkp_x<UfResult>(0).size() + 1);
339 for (
size_t k = 0; k<gkp_x<UfResult>(0).size(); k++) {
340 UfResult
const abscissa = halfLength * gkp_x<UfResult>(0)[k];
341 UfResult
const fval1 = func(center - abscissa);
342 UfResult
const fval2 = func(center + abscissa);
343 area1 += gkp_wb<UfResult>(0)[k] * (fval1 + fval2);
344 fv1.push_back(fval1);
345 fv2.push_back(fval2);
347 (*fxmap)[center - abscissa] = fval1;
348 (*fxmap)[center + abscissa] = fval2;
352 nfeval += gkp_x<UfResult>(0).size()*2;
355 integ_dbg2 <<
"level 0 rule: area = " << area1 << std::endl;
358 bool calcabsasc =
true;
359 UfResult resabs = 0.0, resasc = 0.0;
360 for (
int level = 1; level < NGKPLEVELS; level++) {
361 assert(gkp_wa<UfResult>(level).size() == fv1.size());
362 assert(gkp_wa<UfResult>(level).size() == fv2.size());
363 assert(gkp_wb<UfResult>(level).size() == gkp_x<UfResult>(level).size() + 1);
364 UfResult area2 = gkp_wb<UfResult>(level).back() * fCenter;
367 resabs = fabs(area2);
369 for (
size_t k = 0; k < fv1.size(); k++) {
370 area2 += gkp_wa<UfResult>(level)[k] * (fv1[k] + fv2[k]);
372 resabs += gkp_wa<UfResult>(level)[k] * (fabs(fv1[k]) + fabs(fv2[k]));
375 for (
size_t k = 0; k < gkp_x<UfResult>(level).size(); k++) {
376 UfResult
const abscissa = halfLength * gkp_x<UfResult>(level)[k];
377 UfResult
const fval1 = func(center - abscissa);
378 UfResult
const fval2 = func(center + abscissa);
379 UfResult
const fval = fval1 + fval2;
380 area2 += gkp_wb<UfResult>(level)[k] * fval;
382 resabs += gkp_wb<UfResult>(level)[k] * (fabs(fval1) + fabs(fval2));
384 fv1.push_back(fval1);
385 fv2.push_back(fval2);
387 (*fxmap)[center - abscissa] = fval1;
388 (*fxmap)[center + abscissa] = fval2;
392 nfeval += gkp_x<UfResult>(level).size()*2;
395 UfResult
const mean = area1*UfResult(0.5);
397 resasc = gkp_wb<UfResult>(level).back() * fabs(fCenter - mean);
398 for (
size_t k = 0; k<gkp_wa<UfResult>(level).size(); k++) {
399 resasc += gkp_wa<UfResult>(level)[k] * (fabs(fv1[k] - mean) + fabs(fv2[k] - mean));
401 for (
size_t k = 0; k<gkp_x<UfResult>(level).size(); k++) {
402 resasc += gkp_wb<UfResult>(level)[k] * (fabs(fv1[k] - mean) + fabs(fv2[k] - mean));
404 resasc *= absHalfLength;
405 resabs *= absHalfLength;
413 integ_dbg2 <<
"at level " << level <<
" area2 = " << area2;
417 if (err < epsabs || err < epsrel * fabs (area2)) {
427 integ_dbg2 <<
"Failed to reach tolerance with highest-order GKP rule";
452 typename UF::result_type
const epsabs,
453 typename UF::result_type
const epsrel,
454 std::map<typename UF::result_type, typename UF::result_type>* fxmap = 0) {
456 typedef typename UF::result_type UfResult;
459 assert(epsabs >= 0.0);
460 assert(epsrel > 0.0);
463 bool done =
intGKPNA(func, reg, epsabs, epsrel, fxmap);
466 integ_dbg2 <<
"In adaptive GKP, failed first pass... subdividing\n";
469 int roundoffType1 = 0, errorType = 0;
470 UfResult roundoffType2 = 0;
471 size_t iteration = 1;
473 std::priority_queue<IntRegion<UfResult>, std::vector<IntRegion<UfResult> > > allregions;
474 allregions.push(reg);
475 UfResult finalarea = reg.
Area();
476 UfResult finalerr = reg.
Err();
477 UfResult tolerance = std::max(epsabs, epsrel * fabs(finalarea));
478 assert(finalerr > tolerance);
480 while (!errorType && finalerr > tolerance) {
482 integ_dbg2 <<
"Current answer = " << finalarea <<
" +- " << finalerr;
483 integ_dbg2 <<
" (tol = " << tolerance <<
")\n";
486 integ_dbg2 <<
"Subdividing largest error region ";
490 std::vector<IntRegion<UfResult> > children;
496 UfResult factor = 3*children.size()*finalerr/tolerance;
497 UfResult newepsabs = fabs(parent.
Err()/factor);
498 UfResult newepsrel = newepsabs/fabs(parent.
Area());
499 integ_dbg2 <<
"New epsabs, rel = " << newepsabs <<
", " << newepsrel;
500 integ_dbg2 <<
" (" << children.size() <<
" children)\n";
502 UfResult newarea = UfResult(0.0);
503 UfResult newerror = 0.0;
504 for (
size_t i = 0; i<children.size(); i++) {
509 hasConverged =
intGKPNA(func, child, newepsabs, newepsrel);
510 integ_dbg2 <<
"child (" << i + 1 <<
'/' << children.size() <<
") ";
518 newarea += child.
Area();
519 newerror += child.
Err();
521 integ_dbg2 <<
"Compare: newerr = " << newerror;
522 integ_dbg2 <<
" to parent err = " << parent.
Err() << std::endl;
524 finalerr += (newerror - parent.
Err());
525 finalarea += newarea - parent.
Area();
527 UfResult delta = parent.
Area() - newarea;
528 if (newerror <= parent.
Err() && fabs (delta) <= parent.
Err()
529 && newerror >= 0.99 * parent.
Err()) {
530 integ_dbg2 <<
"roundoff type 1: delta/newarea = ";
532 integ_dbg2 <<
", newerror/error = " << newerror/parent.
Err() << std::endl;
535 if (iteration >= 10 && newerror > parent.
Err() &&
536 fabs(delta) <= newerror - parent.
Err()) {
537 integ_dbg2 <<
"roundoff type 2: newerror/error = ";
539 roundoffType2 += std::min(newerror/parent.
Err() - 1.0, UfResult(1.0));
542 tolerance = std::max(epsabs, epsrel * fabs(finalarea));
543 if (finalerr > tolerance) {
544 if (roundoffType1 >= 200) {
548 if (roundoffType2 >= 200.0) {
553 < Epsilon<double>()) {
558 for (
size_t i = 0; i<children.size(); i++) {
559 allregions.push(children[i]);
567 while (!allregions.empty()) {
569 finalarea += r.
Area();
573 reg.
SetArea(finalarea, finalerr);
575 if (errorType == 1) {
576 std::ostringstream s;
577 s <<
"Type 1 roundoff's = " << roundoffType1;
578 s <<
", Type 2 = " << roundoffType2 << std::endl;
579 s <<
"Roundoff error 1 prevents tolerance from being achieved ";
581 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, s.str());
582 }
else if (errorType == 2) {
583 std::ostringstream s;
584 s <<
"Type 1 roundoff's = " << roundoffType1;
585 s <<
", Type 2 = " << roundoffType2 << std::endl;
586 s <<
"Roundoff error 2 prevents tolerance from being achieved ";
588 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, s.str());
589 }
else if (errorType == 3) {
590 std::ostringstream s;
591 s <<
"Bad integrand behavior found in the integration interval ";
593 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, s.str());
604 public std::unary_function<typename UF::argument_type, typename UF::result_type> {
607 typename UF::result_type
operator()(
typename UF::argument_type
x)
const {
608 return _f(1.0/x - 1.0)/(x*
x);
625 public std::unary_function<typename UF::argument_type, typename UF::result_type> {
628 typename UF::result_type
operator()(
typename UF::argument_type
x)
const {
629 return _f(1.0/x + 1.0)/(x*
x);
658 struct ConstantReg2 :
public std::binary_function<T, T, IntRegion<T> > {
669 :
public std::unary_function<typename BF::second_argument_type,
670 typename BF::result_type> {
673 typename BF::first_argument_type
val)
675 typename BF::result_type
684 template <
class BF,
class Tp>
686 typedef typename BF::first_argument_type Arg;
691 template <
class BF,
class YREG>
692 class Int2DAuxType :
public std::unary_function<typename BF::first_argument_type, typename BF::result_type> {
695 typename BF::result_type
const &abserr,
696 typename BF::result_type
const &relerr) :
699 typename BF::result_type
operator()(
typename BF::first_argument_type
x)
const {
700 typename YREG::result_type tempreg =
_yreg(x);
701 typename BF::result_type result =
704 integ_dbg3 <<
": f = " << result <<
" +- " << tempreg.Err() << std::endl;
718 :
public std::binary_function<typename TF::secondof3_argument_type,
719 typename TF::thirdof3_argument_type,
720 typename TF::result_type> {
723 typename TF::firstof3_argument_type
val)
725 typename TF::result_type
727 typename TF::thirdof3_argument_type
const &x2)
const {
732 typename TF::firstof3_argument_type
_value;
735 template <
class TF,
class Tp>
738 typedef typename TF::firstof3_argument_type Arg;
743 template <
class TF,
class YREG,
class ZREG>
745 public std::unary_function<typename TF::firstof3_argument_type, typename TF::result_type> {
748 const typename TF::result_type& abserr,
749 const typename TF::result_type& relerr) :
752 typename TF::result_type
operator()(
typename TF::firstof3_argument_type
x)
const {
753 typename YREG::result_type tempreg =
_yreg(x);
754 typename TF::result_type result =
757 integ_dbg3 <<
": f = " << result <<
" +- " << tempreg.Err() << std::endl;
776 inline typename UF::result_type
int1d(
779 typename UF::result_type
const &abserr =
DEFABSERR,
780 typename UF::result_type
const &relerr =
DEFRELERR) {
782 typedef typename UF::result_type UfResult;
783 using namespace details;
792 std::vector<IntRegion<UfResult> > children;
794 integ_dbg2 <<
"Subdivided into " << children.size() <<
" children\n";
795 UfResult answer = UfResult();
797 for (
size_t i = 0; i<children.size(); i++) {
801 answer +=
int1d(func, child, abserr, relerr);
810 integ_dbg2 <<
"left = -infinity, right = " << reg.
Right() << std::endl;
811 assert(reg.
Right() <= 0.0);
813 intGKP(Aux2<UF>(func), modreg, abserr, relerr);
814 reg.
SetArea(modreg.Area(), modreg.Err());
817 assert(reg.
Left() >= 0.0);
819 intGKP(Aux1<UF>(func), modreg, abserr, relerr);
820 reg.
SetArea(modreg.Area(), modreg.Err());
824 intGKP(func, reg, abserr, relerr);
836 template <
class BF,
class YREG>
837 inline typename BF::result_type
int2d(
841 typename BF::result_type
const &abserr =
DEFABSERR,
842 typename BF::result_type
const &relerr =
DEFRELERR) {
844 using namespace details;
847 Int2DAuxType<BF, YREG> faux(func, yreg, abserr*1.0e-3, relerr*1.0e-3);
848 typename BF::result_type answer =
int1d(faux, reg, abserr, relerr);
849 integ_dbg2 <<
"done int2d answer = " << answer <<
" +- " << reg.
Err() << std::endl;
856 template <
class TF,
class YREG,
class ZREG>
857 inline typename TF::result_type
int3d(
862 typename TF::result_type
const &abserr =
DEFABSERR,
863 typename TF::result_type
const &relerr =
DEFRELERR) {
865 using namespace details;
868 Int3DAuxType<TF, YREG, ZREG> faux(func, yreg, zreg, abserr*1.e-3, relerr*1.e-3);
869 typename TF::result_type answer =
int1d(faux, reg, abserr, relerr);
870 integ_dbg2 <<
"done int3d answer = " << answer <<
" +- " << reg.
Err() << std::endl;
878 inline typename BF::result_type
int2d(
882 typename BF::result_type
const &abserr =
DEFABSERR,
883 typename BF::result_type
const &relerr =
DEFRELERR) {
884 using namespace details;
885 return int2d(func, reg, ConstantReg1<typename BF::result_type>(yreg), abserr, relerr);
892 inline typename TF::result_type
int3d(
897 typename TF::result_type
const &abserr =
DEFABSERR,
898 typename TF::result_type
const &relerr =
DEFRELERR) {
899 using namespace details;
900 return int3d(func, reg, ConstantReg1<typename TF::result_type>(yreg),
901 ConstantReg2<typename TF::result_type>(zreg), abserr, relerr);
916 template<
typename UnaryFunctionT>
917 typename UnaryFunctionT::result_type
integrate(UnaryFunctionT func,
918 typename UnaryFunctionT::argument_type
const a,
919 typename UnaryFunctionT::argument_type
const b,
920 double eps = 1.0e-6) {
922 typedef typename UnaryFunctionT::argument_type Arg;
945 template<
typename BinaryFunctionT>
947 public std::unary_function<typename BinaryFunctionT::second_argument_type,
948 typename BinaryFunctionT::result_type> {
951 typename BinaryFunctionT::first_argument_type
const x1,
952 typename BinaryFunctionT::first_argument_type
const x2,
953 double const eps = 1.0e-6) :
956 BinaryFunctionT::second_argument_type
const y)
const {
961 typename BinaryFunctionT::first_argument_type
_x1,
_x2;
976 template<
typename BinaryFunctionT>
977 typename BinaryFunctionT::result_type
integrate2d(BinaryFunctionT func,
978 typename BinaryFunctionT::first_argument_type
const x1,
979 typename BinaryFunctionT::first_argument_type
const x2,
980 typename BinaryFunctionT::second_argument_type
const y1,
981 typename BinaryFunctionT::second_argument_type
const y2,
982 double eps = 1.0e-6) {
983 using namespace details;
986 FunctionWrapper<BinaryFunctionT> fwrap(func, x1, x2, eps);
UF::result_type operator()(typename UF::argument_type x) const
BF::result_type int2d(BF const &func, IntRegion< typename BF::result_type > ®, YREG const &yreg, typename BF::result_type const &abserr=DEFABSERR, typename BF::result_type const &relerr=DEFRELERR)
Front end for the 2d integrator.
FunctionWrapper(BinaryFunctionT func, typename BinaryFunctionT::first_argument_type const x1, typename BinaryFunctionT::first_argument_type const x2, double const eps=1.0e-6)
BF::result_type operator()(typename BF::first_argument_type x) const
IntRegion< T > operator()(T) const
Include files required for standard LSST Exception handling.
binder2_1< BF > bind21(const BF &oper, const Tp &x)
BinaryFunctionT::result_type integrate2d(BinaryFunctionT func, typename BinaryFunctionT::first_argument_type const x1, typename BinaryFunctionT::first_argument_type const x2, typename BinaryFunctionT::second_argument_type const y1, typename BinaryFunctionT::second_argument_type const y2, double eps=1.0e-6)
The 2D integrator.
void SetArea(const T &a, const T &e)
void SubDivide(std::vector< IntRegion< T > > *children)
AuxFunc1< UF > Aux1(UF uf)
Auxiliary function 1.
ConstantReg2(IntRegion< T > const &r)
TF::result_type operator()(typename TF::firstof3_argument_type x) const
UF::result_type int1d(UF const &func, IntRegion< typename UF::result_type > ®, typename UF::result_type const &abserr=DEFABSERR, typename UF::result_type const &relerr=DEFRELERR)
Front end for the 1d integrator.
bool operator>(IntRegion< T > const &r2) const
ConstantReg1(IntRegion< T > const &r)
AuxFunc2< UF > Aux2(UF uf)
Auxiliary function 2.
Int3DAuxType(const TF &func, const YREG &yreg, const ZREG &zreg, const typename TF::result_type &abserr, const typename TF::result_type &relerr)
binder3_1< TF > bind31(const TF &oper, const Tp &x)
BinaryFunctionT::result_type operator()(typename BinaryFunctionT::second_argument_type const y) const
TF::firstof3_argument_type _value
BF::first_argument_type _value
Int2DAuxType(BF const &func, YREG const &yreg, typename BF::result_type const &abserr, typename BF::result_type const &relerr)
binder3_1(const TF &oper, typename TF::firstof3_argument_type val)
#define LSST_EXCEPT(type,...)
UF::result_type operator()(typename UF::argument_type x) const
TF::result_type operator()(typename TF::secondof3_argument_type const &x1, typename TF::thirdof3_argument_type const &x2) const
std::ostream * getDbgout()
BinaryFunctionT::first_argument_type _x1
bool intGKPNA(UF const &func, IntRegion< typename UF::result_type > ®, typename UF::result_type const epsabs, typename UF::result_type const epsrel, std::map< typename UF::result_type, typename UF::result_type > *fxmap=0)
Non-adaptive integration of the function f over the region 'reg'.
afw::table::Key< double > b
std::vector< T > _splitpoints
BinaryFunctionT::first_argument_type _x2
TF::result_type int3d(TF const &func, IntRegion< typename TF::result_type > ®, YREG const &yreg, ZREG const &zreg, typename TF::result_type const &abserr=DEFABSERR, typename TF::result_type const &relerr=DEFRELERR)
Front end for the 3d integrator.
binder2_1(const BF &oper, typename BF::first_argument_type val)
T rescale_error(T err, T const &resabs, T const &resasc)
IntRegion(T const a, T const b, std::ostream *dbgout=0)
BF::result_type operator()(const typename BF::second_argument_type &x) const
IntRegion< T > operator()(T x, T y) const
void intGKP(UF const &func, IntRegion< typename UF::result_type > ®, typename UF::result_type const epsabs, typename UF::result_type const epsrel, std::map< typename UF::result_type, typename UF::result_type > *fxmap=0)
An adaptive integration algorithm which computes the integral of f over the region reg...
std::ostream *const dbgout
Wrap an integrand in a call to a 1D integrator: romberg()
UnaryFunctionT::result_type integrate(UnaryFunctionT func, typename UnaryFunctionT::argument_type const a, typename UnaryFunctionT::argument_type const b, double eps=1.0e-6)
The 1D integrator.
Helpers for constant regions for int2d, int3d: