25 #if !defined(LSST_AFW_MATH_INTEGRATE_H)
26 #define LSST_AFW_MATH_INTEGRATE_H 1
175 if (false) (*_dbgout)
177 if (false) (*(reg.getDbgout()))
179 if (false) (*(tempreg.getDbgout()))
182 if (_dbgout) (*_dbgout)
184 if (reg.getDbgout()) (*(reg.getDbgout()))
186 if (tempreg.getDbgout()) (*(tempreg.getDbgout()))
212 : _a(
a), _b(
b), _error(0.0), _area(0), _dbgout(dbgout) {}
224 assert(children->size() == 0);
225 if (_splitpoints.size() == 0) {
228 if (_splitpoints.size() > 1) {
229 std::sort(_splitpoints.begin(), _splitpoints.end());
233 if (_a > _splitpoints[0] || _b < _splitpoints.back()) {
236 for (
size_t i = 0; i<_splitpoints.size(); i++) {
242 assert(_splitpoints[0] >= _a);
243 assert(_splitpoints.back() <= _b);
244 children->push_back(
IntRegion<T>(_a, _splitpoints[0], _dbgout));
245 for (
size_t i = 1; i < _splitpoints.size(); i++) {
246 children->push_back(
IntRegion<T>(_splitpoints[i - 1], _splitpoints[i], _dbgout));
248 children->push_back(
IntRegion<T>(_splitpoints.back(), _b, _dbgout));
251 void Bisect() { _splitpoints.push_back((_a + _b) / 2.0); }
253 size_t NSplit()
const {
return _splitpoints.size(); }
255 T
const &
Left()
const {
return _a; }
256 T
const &
Right()
const {
return _b; }
257 T
const &
Err()
const {
return _error; }
258 T
const &
Area()
const {
return _area; }
267 T _a, _b, _error, _area;
288 inline Quad Epsilon<Quad>() {
289 return 3.08148791094e-33;
292 inline Quad MinRep<Quad>() {
293 return 2.2250738585072014e-308;
299 if (resasc != 0.0 && err != 0.0) {
300 T
const scale = (200.0 * err / resasc);
307 if (resabs > MinRep<T>() / (50.0 * Epsilon<T>())) {
308 T
const min_err = 50.0 * Epsilon<T>() * resabs;
334 typename UF::result_type
const epsabs,
typename UF::result_type
const epsrel,
336 typedef typename UF::result_type UfResult;
337 UfResult
const a = reg.
Left();
338 UfResult
const b = reg.
Right();
340 UfResult
const halfLength = 0.5 * (
b -
a);
341 UfResult
const absHalfLength = fabs(halfLength);
342 UfResult
const center = 0.5 * (
b +
a);
343 UfResult
const fCenter = func(center);
348 assert(gkp_wb<UfResult>(0).size() == gkp_x<UfResult>(0).size() + 1);
349 UfResult area1 = gkp_wb<UfResult>(0).back() * fCenter;
351 fv1.
reserve(2 * gkp_x<UfResult>(0).size() + 1);
352 fv2.
reserve(2 * gkp_x<UfResult>(0).size() + 1);
353 for (
size_t k = 0; k < gkp_x<UfResult>(0).size(); k++) {
354 UfResult
const abscissa = halfLength * gkp_x<UfResult>(0)[k];
355 UfResult
const fval1 = func(center - abscissa);
356 UfResult
const fval2 = func(center + abscissa);
357 area1 += gkp_wb<UfResult>(0)[k] * (fval1 + fval2);
361 (*fxmap)[center - abscissa] = fval1;
362 (*fxmap)[center + abscissa] = fval2;
366 nfeval += gkp_x<UfResult>(0).size() * 2;
372 bool calcabsasc =
true;
373 UfResult resabs = 0.0, resasc = 0.0;
374 for (
int level = 1; level < NGKPLEVELS; level++) {
375 assert(gkp_wa<UfResult>(level).size() == fv1.
size());
376 assert(gkp_wa<UfResult>(level).size() == fv2.
size());
377 assert(gkp_wb<UfResult>(level).size() == gkp_x<UfResult>(level).size() + 1);
378 UfResult area2 = gkp_wb<UfResult>(level).back() * fCenter;
381 resabs = fabs(area2);
383 for (
size_t k = 0; k < fv1.
size(); k++) {
384 area2 += gkp_wa<UfResult>(level)[k] * (fv1[k] + fv2[k]);
386 resabs += gkp_wa<UfResult>(level)[k] * (fabs(fv1[k]) + fabs(fv2[k]));
389 for (
size_t k = 0; k < gkp_x<UfResult>(level).size(); k++) {
390 UfResult
const abscissa = halfLength * gkp_x<UfResult>(level)[k];
391 UfResult
const fval1 = func(center - abscissa);
392 UfResult
const fval2 = func(center + abscissa);
393 UfResult
const fval = fval1 + fval2;
394 area2 += gkp_wb<UfResult>(level)[k] * fval;
396 resabs += gkp_wb<UfResult>(level)[k] * (fabs(fval1) + fabs(fval2));
401 (*fxmap)[center - abscissa] = fval1;
402 (*fxmap)[center + abscissa] = fval2;
406 nfeval += gkp_x<UfResult>(level).size() * 2;
409 UfResult
const mean = area1 * UfResult(0.5);
411 resasc = gkp_wb<UfResult>(level).back() * fabs(fCenter - mean);
412 for (
size_t k = 0; k < gkp_wa<UfResult>(level).size(); k++) {
413 resasc += gkp_wa<UfResult>(level)[k] * (fabs(fv1[k] - mean) + fabs(fv2[k] - mean));
415 for (
size_t k = 0; k < gkp_x<UfResult>(level).size(); k++) {
416 resasc += gkp_wb<UfResult>(level)[k] * (fabs(fv1[k] - mean) + fabs(fv2[k] - mean));
418 resasc *= absHalfLength;
419 resabs *= absHalfLength;
427 integ_dbg2 <<
"at level " << level <<
" area2 = " << area2;
431 if (err < epsabs || err < epsrel * fabs(area2)) {
441 integ_dbg2 <<
"Failed to reach tolerance with highest-order GKP rule";
464 typename UF::result_type
const epsabs,
typename UF::result_type
const epsrel,
466 typedef typename UF::result_type UfResult;
469 assert(epsabs >= 0.0);
470 assert(epsrel > 0.0);
473 bool done =
intGKPNA(func, reg, epsabs, epsrel, fxmap);
476 integ_dbg2 <<
"In adaptive GKP, failed first pass... subdividing\n";
479 int roundoffType1 = 0, errorType = 0;
480 UfResult roundoffType2 = 0;
481 size_t iteration = 1;
484 allregions.
push(reg);
485 UfResult finalarea = reg.
Area();
486 UfResult finalerr = reg.
Err();
487 UfResult tolerance =
std::max(epsabs, epsrel * fabs(finalarea));
488 assert(finalerr > tolerance);
490 while (!errorType && finalerr > tolerance) {
492 integ_dbg2 <<
"Current answer = " << finalarea <<
" +- " << finalerr;
493 integ_dbg2 <<
" (tol = " << tolerance <<
")\n";
496 integ_dbg2 <<
"Subdividing largest error region ";
506 UfResult factor = 3 * children.
size() * finalerr / tolerance;
507 UfResult newepsabs = fabs(parent.
Err() / factor);
508 UfResult newepsrel = newepsabs / fabs(parent.
Area());
509 integ_dbg2 <<
"New epsabs, rel = " << newepsabs <<
", " << newepsrel;
512 UfResult newarea = UfResult(0.0);
513 UfResult newerror = 0.0;
514 for (
size_t i = 0; i < children.
size(); i++) {
519 hasConverged =
intGKPNA(func, child, newepsabs, newepsrel);
520 integ_dbg2 <<
"child (" << i + 1 <<
'/' << children.
size() <<
") ";
528 newarea += child.
Area();
529 newerror += child.
Err();
531 integ_dbg2 <<
"Compare: newerr = " << newerror;
534 finalerr += (newerror - parent.
Err());
535 finalarea += newarea - parent.
Area();
537 UfResult delta = parent.
Area() - newarea;
538 if (newerror <= parent.
Err() && fabs(delta) <= parent.
Err() && newerror >= 0.99 * parent.
Err()) {
539 integ_dbg2 <<
"roundoff type 1: delta/newarea = ";
544 if (iteration >= 10 && newerror > parent.
Err() && fabs(delta) <= newerror - parent.
Err()) {
545 integ_dbg2 <<
"roundoff type 2: newerror/error = ";
547 roundoffType2 +=
std::min(newerror / parent.
Err() - 1.0, UfResult(1.0));
550 tolerance =
std::max(epsabs, epsrel * fabs(finalarea));
551 if (finalerr > tolerance) {
552 if (roundoffType1 >= 200) {
556 if (roundoffType2 >= 200.0) {
560 if (fabs((parent.
Right() - parent.
Left()) / (reg.
Right() - reg.
Left())) < Epsilon<double>()) {
565 for (
size_t i = 0; i < children.
size(); i++) {
566 allregions.
push(children[i]);
574 while (!allregions.
empty()) {
576 finalarea += r.
Area();
580 reg.
SetArea(finalarea, finalerr);
582 if (errorType == 1) {
584 s <<
"Type 1 roundoff's = " << roundoffType1;
585 s <<
", Type 2 = " << roundoffType2 <<
std::endl;
586 s <<
"Roundoff error 1 prevents tolerance from being achieved ";
589 }
else if (errorType == 2) {
591 s <<
"Type 1 roundoff's = " << roundoffType1;
592 s <<
", Type 2 = " << roundoffType2 <<
std::endl;
593 s <<
"Roundoff error 2 prevents tolerance from being achieved ";
596 }
else if (errorType == 3) {
598 s <<
"Bad integrand behavior found in the integration interval ";
613 typename UF::result_type
operator()(
typename UF::argument_type
x)
const {
614 return _f(1.0 /
x - 1.0) / (
x *
x);
635 typename UF::result_type
operator()(
typename UF::argument_type
x)
const {
636 return _f(1.0 /
x + 1.0) / (
x *
x);
677 typename BF::result_type
operator()(
const typename BF::second_argument_type &
x)
const {
686 template <
class BF,
class Tp>
688 typedef typename BF::first_argument_type Arg;
692 template <
class BF,
class YREG>
695 Int2DAuxType(BF
const &func, YREG
const &yreg,
typename BF::result_type
const &abserr,
696 typename BF::result_type
const &relerr)
697 : _func(func), _yreg(yreg), _abserr(abserr), _relerr(relerr) {}
699 typename BF::result_type
operator()(
typename BF::first_argument_type
x)
const {
700 typename YREG::result_type tempreg = _yreg(
x);
710 typename BF::result_type _abserr, _relerr;
716 typename TF::thirdof3_argument_type, typename TF::result_type> {
719 typename TF::result_type
operator()(
typename TF::secondof3_argument_type
const &x1,
720 typename TF::thirdof3_argument_type
const &x2)
const {
726 typename TF::firstof3_argument_type
_value;
729 template <
class TF,
class Tp>
731 typedef typename TF::firstof3_argument_type Arg;
735 template <
class TF,
class YREG,
class ZREG>
737 :
public std::unary_function<typename TF::firstof3_argument_type, typename TF::result_type> {
739 Int3DAuxType(
const TF &func,
const YREG &yreg,
const ZREG &zreg,
const typename TF::result_type &abserr,
740 const typename TF::result_type &relerr)
741 : _func(func), _yreg(yreg), _zreg(zreg), _abserr(abserr), _relerr(relerr) {}
743 typename TF::result_type
operator()(
typename TF::firstof3_argument_type
x)
const {
744 typename YREG::result_type tempreg = _yreg(
x);
745 typename TF::result_type
result =
756 typename TF::result_type _abserr, _relerr;
766 typename UF::result_type
const &abserr =
DEFABSERR,
767 typename UF::result_type
const &relerr =
DEFRELERR) {
768 typedef typename UF::result_type UfResult;
780 integ_dbg2 <<
"Subdivided into " << children.
size() <<
" children\n";
781 UfResult answer = UfResult();
783 for (
size_t i = 0; i < children.
size(); i++) {
787 answer +=
int1d(func, child, abserr, relerr);
797 assert(reg.
Right() <= 0.0);
799 intGKP(Aux2<UF>(func), modreg, abserr, relerr);
803 assert(reg.
Left() >= 0.0);
805 intGKP(Aux1<UF>(func), modreg, abserr, relerr);
810 intGKP(func, reg, abserr, relerr);
821 template <
class BF,
class YREG>
823 YREG
const &yreg,
typename BF::result_type
const &abserr =
DEFABSERR,
824 typename BF::result_type
const &relerr =
DEFRELERR) {
828 Int2DAuxType<BF, YREG> faux(func, yreg, abserr * 1.0e-3, relerr * 1.0e-3);
829 typename BF::result_type answer =
int1d(faux, reg, abserr, relerr);
837 template <
class TF,
class YREG,
class ZREG>
839 YREG
const &yreg, ZREG
const &zreg,
840 typename TF::result_type
const &abserr =
DEFABSERR,
841 typename TF::result_type
const &relerr =
DEFRELERR) {
845 Int3DAuxType<TF, YREG, ZREG> faux(func, yreg, zreg, abserr * 1.e-3, relerr * 1.e-3);
846 typename TF::result_type answer =
int1d(faux, reg, abserr, relerr);
857 typename BF::result_type
const &abserr =
DEFABSERR,
858 typename BF::result_type
const &relerr =
DEFRELERR) {
860 return int2d(func, reg, ConstantReg1<typename BF::result_type>(yreg), abserr, relerr);
870 typename TF::result_type
const &abserr =
DEFABSERR,
871 typename TF::result_type
const &relerr =
DEFRELERR) {
873 return int3d(func, reg, ConstantReg1<typename TF::result_type>(yreg),
874 ConstantReg2<typename TF::result_type>(zreg), abserr, relerr);
885 template <
typename UnaryFunctionT>
886 typename UnaryFunctionT::result_type
integrate(UnaryFunctionT func,
887 typename UnaryFunctionT::argument_type
const a,
888 typename UnaryFunctionT::argument_type
const b,
889 double eps = 1.0e-6) {
890 typedef typename UnaryFunctionT::argument_type Arg;
907 template <
typename BinaryFunctionT>
909 typename BinaryFunctionT::result_type> {
911 FunctionWrapper(BinaryFunctionT func,
typename BinaryFunctionT::first_argument_type
const x1,
912 typename BinaryFunctionT::first_argument_type
const x2,
double const eps = 1.0e-6)
913 : _func(func), _x1(x1), _x2(x2), _eps(eps) {}
915 typename BinaryFunctionT::second_argument_type
const y)
const {
916 return integrate(std::bind2nd(_func,
y), _x1, _x2, _eps);
920 BinaryFunctionT _func;
921 typename BinaryFunctionT::first_argument_type _x1, _x2;
934 template <
typename BinaryFunctionT>
935 typename BinaryFunctionT::result_type
integrate2d(BinaryFunctionT func,
936 typename BinaryFunctionT::first_argument_type
const x1,
937 typename BinaryFunctionT::first_argument_type
const x2,
938 typename BinaryFunctionT::second_argument_type
const y1,
939 typename BinaryFunctionT::second_argument_type
const y2,
940 double eps = 1.0e-6) {
944 FunctionWrapper<BinaryFunctionT> fwrap(func, x1, x2, eps);
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Wrap an integrand in a call to a 1D integrator: romberg()
FunctionWrapper(BinaryFunctionT func, typename BinaryFunctionT::first_argument_type const x1, typename BinaryFunctionT::first_argument_type const x2, double const eps=1.0e-6)
BinaryFunctionT::result_type operator()(typename BinaryFunctionT::second_argument_type const y) const
Int2DAuxType(BF const &func, YREG const &yreg, typename BF::result_type const &abserr, typename BF::result_type const &relerr)
BF::result_type operator()(typename BF::first_argument_type x) const
Int3DAuxType(const TF &func, const YREG &yreg, const ZREG &zreg, const typename TF::result_type &abserr, const typename TF::result_type &relerr)
TF::result_type operator()(typename TF::firstof3_argument_type x) const
BF::first_argument_type _value
BF::result_type operator()(const typename BF::second_argument_type &x) const
binder2_1(const BF &oper, typename BF::first_argument_type val)
TF::firstof3_argument_type _value
binder3_1(const TF &oper, typename TF::firstof3_argument_type val)
TF::result_type operator()(typename TF::secondof3_argument_type const &x1, typename TF::thirdof3_argument_type const &x2) const
Reports errors that are due to events beyond the control of the program.
def scale(algorithm, min, max=None, frame=None)
class[[deprecated("Removed with no replacement (but see lsst::afw::image::TransmissionCurve). Will be " "removed after v22.")]] FilterProperty final
Describe the properties of a Filter (e.g.
AuxFunc2< UF > Aux2(UF uf)
Auxiliary function 2.
AuxFunc1< UF > Aux1(UF uf)
Auxiliary function 1.
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.
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'.
T rescale_error(T err, T const &resabs, T const &resasc)
binder2_1< BF > bind21(const BF &oper, const Tp &x)
binder3_1< TF > bind31(const TF &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.
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.
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.
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.
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.
A base class for image defects.
void SetArea(const T &a, const T &e)
IntRegion(IntRegion &&)=default
bool operator>(IntRegion< T > const &r2) const
IntRegion(T const a, T const b, std::ostream *dbgout=0)
std::ostream * getDbgout()
IntRegion(IntRegion const &)=default
void SubDivide(std::vector< IntRegion< T > > *children)
bool operator<(IntRegion< T > const &r2) const
IntRegion & operator=(IntRegion const &)=default
IntRegion & operator=(IntRegion &&)=default
UF::result_type operator()(typename UF::argument_type x) const
UF::result_type operator()(typename UF::argument_type x) const
Helpers for constant regions for int2d, int3d:
IntRegion< T > operator()(T) const
ConstantReg1(IntRegion< T > const &r)
ConstantReg2(IntRegion< T > const &r)
IntRegion< T > operator()(T x, T y) const