1 /** Functions for numerical integration (quadrature) and differentiation.
2 
3     It is recommended to read the following introduction before using
4     any of the functions in this module, as it discusses features and
5     issues that are common to several of them.
6 
7     Integration:
8 
9     This module contains several different integration methods, suitable
10     for a wide range of problems.  The choice of which method to use
11     depends on several things, such as whether the integration
12     interval is finite or infinite, whether the integrand oscillates, or
13     whether it exhibits other difficult behaviour such as singularities or
14     discontinuities in the integration interval.  Choosing the right method
15     can both speed up the calculation and make it more accurate.
16     Therefore, each method below has a short description of which types of
17     integral it is suitable for.
18 
19     When you just want to "get things done" without any fuss,
20     use the general-purpose $(D integrate()) function.  It tries to select
21     the method which is most likely to succeed for the given interval.
22 
23     All the integration functions have a set of input parameters in common:
24     The function to integrate, the limits of the integral, and some accuracy
25     requirements.  All of these are described in the documentation for
26     $(D integrate()).
27 
28     Most of the quadrature routines in SciD are ported from from
29     $(LINK2 http://www.netlib.org/quadpack,QUADPACK)
30     which is a well-known FORTRAN package for numerical evaluation of
31     integrals using
32     $(LINK2 http://en.wikipedia.org/wiki/Gaussian_quadrature,Gaussian quadrature).
33     Gaussian quadrature is
34     $(LINK2 http://mathworld.wolfram.com/NumericalIntegration.html,considered)
35     to be the most accurate method available for numerical integration of
36     smooth functions.  The QUADPACK integrators are named $(D integrateQ*()) below.
37 
38     In addition, SciD has support for
39     $(LINK2 http://mathworld.wolfram.com/DoubleExponentialIntegration.html,double exponential integration).
40     The DE algorithms are ported from Takuya Ooura's
41     $(LINK2 http://www.kurims.kyoto-u.ac.jp/~ooura/intde.html,DE-Quadrature package),
42     and are available in this module through the $(D integrateDE*()) functions.
43 
44     Differentiation:
45 
46     The simplest, but fastest, form of numerical differentiation is using
47     finite differences. The functions in this module use three different
48     finite-difference formulas: Forward differences,
49     ---
50     df   f(x+h) - f(x)
51     -- = -------------
52     dx         h
53     ---
54     backward differences,
55     ---
56     df   f(x) - f(x-h)
57     -- = -------------
58     dx         h
59     ---
60     and central differences,
61     ---
62     df   f(x+h) - f(x-h)
63     -- = ---------------
64     dx         2 h
65     ---
66     Of these three, the latter is the most accurate, but in the cases where
67     $(D f(x)) is already known it requires one more function evaluation compared
68     to the forward-/backward-difference formulas. This is of particular
69     importance when one needs to evaluate several derivatives, as is the
70     case with e.g. gradients and Jacobians.
71 
72     Some functions in this module, like $(D diff()), use another method by Ridders,
73     which extrapolates the results of finite-difference formulas like the
74     above to make the approximation more accurate – usually a lot more so.
75     This requires several function evaluations and is therefore also a lot
76     slower than simple finite differences.
77 
78     All the differentiation methods in this module take an optional
79     $(D scale) parameter. This is a "characteristic scale" for the function,
80     i.e. a scale over which the function changes significantly. It is
81     worth experimenting a bit with this parameter, as it can have a
82     drastic impact on accuracy. (For an extreme example, see the "Example"
83     section for the $(D diff()) function below.) For practical reasons, $(D 1.0) is
84     chosen as the default scale in this module. Another, probably more
85     common, choice that sometimes works well is to set $(D scale = x), where
86     $(D x) is the point at which the derivative is taken.
87 
88 
89     Authors:    Lars Tandle Kyllingstad
90     Copyright:  Copyright (c) 2009-2010, Lars T. Kyllingstad. All rights reserved.
91     License:    Boost License 1.0
92     Macros:
93         D = <b><code>$0</code></b>
94         INFTY = &infin;
95         SUP = <sup>$0</sup>
96 */
97 module scid.calculus;
98 
99 
100 import std.algorithm;
101 import std.conv;
102 import std.math;
103 import std.traits;
104 
105 import scid.core.fortran;
106 import scid.core.memory;
107 import scid.core.traits;
108 import scid.internal.calculus.integrate_qng;
109 import scid.ports.intde.intde1;
110 import scid.ports.quadpack.qage;
111 import scid.ports.quadpack.qagie;
112 import scid.ports.quadpack.qagpe;
113 import scid.ports.quadpack.qagse;
114 import scid.ports.quadpack.qawce;
115 import scid.ports.quadpack.qawfe;
116 import scid.ports.quadpack.qawoe;
117 import scid.ports.quadpack.qawse;
118 import scid.matrix;
119 import scid.types;
120 import scid.util;
121 
122 version(unittest)
123 {
124     import std.range;
125     import scid.core.testing;
126 }
127 
128 
129 
130 
131 /** Integrate a function from $(D a) to $(D b).
132 
133     This module contains a lot of different integration routines, and
134     $(D _integrate()) aims to be a simple interface to some of
135     these. Currently, it only calls the $(D integrateQAGS()) and
136     $(D integrateQAGI()) routines, but this may change in the future.
137     In particular, it should take into account whether a function
138     is oscillatory, if it has discontinuities and singularities in
139     the integration interval, and so on.
140 
141     Params:
142         f       = The function to _integrate.  This can be given as a
143                     function pointer, a delegate, or a struct/class
144                     which defines $(D opCall()).
145         a       = The lower limit of integration.
146         b       = The upper limit of integration.
147         epsRel  = (optional) The requested relative accuracy.
148         epsAbs  = (optional) The requested absolute accuracy.
149 
150     Note:
151     This function is different from the other $(D integrateXXX()) routines
152     in this module in that it allows $(D a) and $(D b) to take on the special
153     values $(D Real.infinity) and $(D -Real.infinity), where $(D Real) is the
154     floating-point type being used.
155 
156     Example:
157     ---
158     // Let's integrate the function
159     //
160     //              log(x)
161     //     f(x) = ----------
162     //                     2
163     //            1 + 100 x
164     //
165     // from x=0 to x=infinity.
166 
167     real f(real x)  { return log(x)/(1 + 100*x*x); }
168     auto result = integrate(&f, 0.0L, real.infinity, 0.001L);
169 
170     real exact = -PI * log(10.0)/20.0;
171     assert (abs(result.value - exact) < result.error);
172     ---
173 */
174 Result!Real integrate (Func, Real)(scope Func f, Real a, Real b,
175     Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
176 {
177     if (isFinite(a))
178     {
179         if (isFinite(b))
180             return integrateQAGS(f, a, b, epsRel, epsAbs);
181 
182         else if (b == Real.infinity)
183             return integrateQAGI(f, a, Infinite.upper, epsRel, epsAbs);
184 
185         else if (b == -Real.infinity)
186             return -integrateQAGI(f, a, Infinite.lower, epsRel, epsAbs);
187     }
188     else if (a == -Real.infinity)
189     {
190         if (isFinite(b))
191             return integrateQAGI(f, b, Infinite.lower, epsRel, epsAbs);
192 
193         else if (b == Real.infinity)
194             return integrateQAGI(f, epsRel, epsAbs);
195 
196         else if (b == -Real.infinity)
197             return Result!Real(0.0, 0.0);
198     }
199     else if (a == Real.infinity)
200     {
201         if (isFinite(b))
202             return -integrateQAGI(f, b, Infinite.upper, epsRel, epsAbs);
203 
204         else if (b == -Real.infinity)
205             return -integrateQAGI(f, epsRel, epsAbs);
206 
207         else if (b == Real.infinity)
208             return Result!Real(0.0, 0.0);
209     }
210 
211     // a or b is NaN.
212     return Result!Real(Real.nan, Real.nan);
213 }
214 
215 
216 unittest
217 {
218     // Tests for when both limits are finite.
219     real logsqrt(real x) { return (x <= 0.0 ? 0.0 : log(x)/sqrt(x)); }
220     auto logsqrtResult = integrate(&logsqrt, 0.0L, 1.0L, 0.0L, 1e-10L);
221     assert (approxEqual(logsqrtResult.value, -4.0L, 0.0L, logsqrtResult.error));
222     assert (logsqrtResult.error < abs(logsqrtResult.value*1e-10L));
223 
224 
225     // Tests for when both limits are infinite.
226     real gauss(real x)
227     {
228         return exp(-x*x);
229     }
230 
231     auto gaussResult1 =
232         integrate(&gauss, -real.infinity, real.infinity, 1e-10L);
233     assert (approxEqual(gaussResult1.value, sqrt(PI), 0.0L, gaussResult1.error));
234     assert (gaussResult1.error < abs(gaussResult1.value*1e-10));
235 
236     auto gaussResult2 =
237         integrate(&gauss, real.infinity, -real.infinity, 1e-10L);
238     assert (approxEqual(gaussResult2.value,-sqrt(PI), 0.0L, gaussResult2.error));
239 
240     auto gaussResult3 =
241         integrate(&gauss, -real.infinity, -real.infinity, 1e-10L);
242     assert (gaussResult3.value == 0.0);
243 
244     auto gaussResult4 =
245         integrate(&gauss, real.infinity, real.infinity, 1e-10L);
246     assert (gaussResult4.value == 0.0);
247 
248 
249     // Tests for when one limit is infinite.
250     real u(real x)  { return log( x)/(1 + 100*x*x); }
251     real l(real x)  { return log(-x)/(1 + 100*x*x); }
252 
253     real ulExact = -PI * log(10.0)/20.0;
254     auto uResult = integrate(&u, 0.0L, real.infinity, 0.001L);
255     auto muResult = integrate(&u, real.infinity, 0.0L, 0.001L);
256     auto lResult = integrate(&l, -real.infinity, 0.0L, 0.001L);
257     auto mlResult = integrate(&l, 0.0L, -real.infinity, 0.001L);
258 
259     assert (approxEqual(uResult.value, ulExact, 0.0L, uResult.error));
260     assert (approxEqual(lResult.value, ulExact, 0.0L, lResult.error));
261     assert (uResult.value == -muResult.value);
262     assert (lResult.value == -mlResult.value);
263 }
264 
265 
266 
267 
268 /** Calculate the integral of $(D f(x)) over the finite interval ($(D a),$(D b))
269     using a simple
270     non-adaptive automatic integrator, based on a sequence of rules with
271     increasing degree of algebraic precision.
272 
273     This method should only be used for well-behaved integrands, or when
274     speed is a lot more important than accuracy.
275 
276     Example:
277     ---
278     // Despite the statement above, integrateQNG() can handle some
279     // difficulties, such as the endpoint singularity in the following
280     // example:
281     double f(double x) { return x^^2 * log(1/x); }
282     auto i = integrateQNG(&f, 0.0, 1.0);
283     ---
284 */
285 Result!Real integrateQNG(Func, Real)(scope Func f, Real a, Real b,
286     Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
287     in
288     {
289         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
290             "Requested accuracy is too small.");
291     }
292     body
293 {
294     return scid.internal.calculus.integrate_qng.qng(f, a, b, epsRel, epsAbs);
295 }
296 
297 
298 unittest
299 {
300     double f(double x) { return x^^2 * log(1/x); }
301     auto result = integrateQNG(&f, 0.0, 1.0);
302     assert (abs(result.value - 1.0/9) <= result.error);
303 }
304 
305 
306 
307 
308 // Integration rules for integrateQAG()
309 enum GaussKronrod { rule15 = 1, rule21, rule31, rule41, rule51, rule61 }
310 
311 
312 
313 
314 /** Calculate the integral of $(D f(x)) over the finite interval
315     ($(D a),$(D b)) using a simple globally adaptive integrator.
316 
317     This method is suitable for functions without singularities
318     or discontinuities which are too difficult for $(D integrateQNG()),
319     and, in particular, for functions with oscillating behaviour of a
320     non-specific type.
321 
322     It is possible to choose between 6 pairs of
323     $(LINK2 http://en.wikipedia.org/wiki/Gauss–Kronrod_quadrature_formula,
324     Gauss–Kronrod quadrature formulae)
325     for the rule evaluation component.  The pairs of high
326     degree of precision are suitable for handling integration
327     difficulties due to a strongly oscillating integrand, whereas
328     the lower-order rules are more efficient for well-behaved integrands.
329     The $(D rule) parameter may take on the following values, corresponding to
330     15-, 21-, 31-, 41-, 51-, and 61-point Gauss–Kronrod rules:
331     ---
332     enum GaussKronrod { rule15, rule21, rule31, rule41, rule51, rule61 }
333     ---
334 
335     Example:
336     ---
337     // Strongly oscillating integrand, better use highest-order rule.
338     double f(double x) { return cos(100 * sin(x)); }
339     auto i = integrateQAG(&f, 0.0, cast(double) PI, GaussKronrod.rule61);
340     ---
341 */
342 Result!Real integrateQAG(Func, Real)
343     (scope Func f, Real a, Real b, GaussKronrod rule = GaussKronrod.rule31,
344      Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
345     in
346     {
347         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
348             "Requested accuracy is too small.");
349     }
350     body
351 {
352     Real result, abserr;
353     int neval, ier, last;
354 
355     enum int limit = 500;
356     Real[limit] alist, blist, rlist, elist;
357     int[limit] iord;
358 
359     qage(f, a, b, epsAbs, epsRel, rule, limit, result, abserr,
360         neval, ier, alist.ptr, blist.ptr, rlist.ptr, elist.ptr,
361         iord.ptr, last);
362     checkQuadpackStatus(ier, result, abserr);
363 
364     return typeof(return)(result, abserr);
365 }
366 
367 
368 unittest
369 {
370     double f(double x) { return cos(100 * sin(x)); }
371     auto i = integrateQAG(&f, 0.0, cast(double) PI, GaussKronrod.rule61);
372     assert (isAccurate(i.value, i.error, 0.062787400491492695655, 1e-6));
373 }
374 
375 
376 
377 
378 /** Calculate the integral of $(D f(x)) over the finite interval
379     ($(D a),$(D b)) using a general-purpose integration algorithm.
380 
381     $(D _integrateQAGS()) is an integrator based on globally adaptive interval
382     subdivision in connection with extrapolation by the Epsilon
383     algorithm, which eliminates the effects of integrand singularities
384     of several types.
385 
386     This is the most "intelligent" of the general-purpose finite-interval
387     integration methods, and the one that best handles bad integrand
388     behaviour.  It is fairly expensive in terms of processing time, though,
389     so if that is an issue you may want to investigate the integrand
390     in more detail and try one or a combination of the more specialised
391     integration methods.
392 
393     Example:
394     ---
395     // This function has an internal singularity at x = 1/3.
396     double f(double x) { return 1/sqrt(abs(x-1.0/3)); }
397     auto i = integrateQAGS(&f, 0.0, 1.0);
398     ---
399 */
400 Result!Real integrateQAGS(Func, Real)(scope Func f, Real a, Real b,
401     Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
402     in
403     {
404         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
405             "Requested accuracy is too small.");
406     }
407     body
408 {
409     Real result, abserr;
410     int neval, ier;
411     int last;
412 
413     enum int limit = 500;
414     Real[limit] alist, blist, rlist, elist;
415     int[limit] iord;
416 
417     qagse(f, a, b, epsAbs, epsRel, limit, result, abserr, neval, ier,
418         alist.ptr, blist.ptr, rlist.ptr, elist.ptr, iord.ptr, last);
419     checkQuadpackStatus(ier, result, abserr);
420 
421     return typeof(return)(result, abserr);
422 }
423 
424 
425 unittest
426 {
427     double f(double x) { return 1/sqrt(abs(x-1.0/3)); }
428     auto i = integrateQAGS(&f, 0.0, 1.0);
429     double expected = 2 * (sqrt(2.0/3) + sqrt(1.0/3));
430     assert (isAccurate(i, expected, 1e-8));
431 }
432 
433 
434 
435 
436 /** Calculate the integral of $(D f(x)) over the finite interval ($(D a),$(D b)),
437     taking into account known points of special difficulty
438     inside the interval.
439 
440     This routine uses the same integration method as $(D integrateQAGS()),
441     but allows you to specify an array of points where the
442     integrand has internal singularities, discontinuities or
443     other types of bad behaviour.
444 */
445 Result!Real integrateQAGP(Func, Real)(scope Func f, Real a, Real b,
446     Real[] trouble, Real epsRel = cast(Real) 1e-6,
447     Real epsAbs = cast(Real) 0)
448     in
449     {
450         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
451             "Requested accuracy is too small.");
452     }
453     body
454 {
455     if (trouble.length == 0)  return integrateQAGS(f, a, b, epsRel, epsAbs);
456 
457     mixin(newFrame);
458 
459     Real result, abserr;
460     int neval, ier;
461     int last;
462 
463     enum int limit = 500;
464     Real[limit] alist, blist, rlist, elist;
465     int[limit] iord, level;
466 
467     // The array passed to qagp must have two unused slots.
468     // Unfortunately, this will sometimes cause an allocation.
469     int npts2 = toInt(trouble.length) + 2;
470     trouble.length = npts2;
471     auto pts = newStack!Real(npts2);
472     auto ndin = newStack!int(npts2);
473 
474     qagpe(f, a, b, npts2, trouble.ptr, epsAbs, epsRel, limit,
475         result, abserr, neval, ier,
476         alist.ptr, blist.ptr, rlist.ptr, elist.ptr, pts.ptr,
477         iord.ptr, level.ptr, ndin.ptr, last);
478     checkQuadpackStatus(ier, result, abserr);
479 
480     return typeof(return)(result, abserr);
481 }
482 
483 
484 unittest
485 {
486     real f(real x) { return abs(x - PI/4)^^(-0.4L); }
487     auto i = integrateQAGP(&f, 0.0L, 1.0L, [PI/4], 1e-8L);
488     auto expect = ((1-PI/4)^^0.6L + (PI/4)^^0.6L)/0.6L;
489     assert (isAccurate(i, expect, 1e-8L));
490 }
491 
492 
493 
494 
495 // Integration ranges for integrateQAGI()
496 enum Infinite { upper = 1, lower = -1 }
497 
498 
499 
500 
501 /** Calculate the integral of $(D f(x)) over an infinite interval.
502 
503     The infinite range is mapped onto a finite interval and subsequently
504     the same strategy as in $(D integrateQAGS()) is applied.
505 
506     To integrate $(D f(x)) over the interval (-$(INFTY),$(INFTY)), use the
507     first form.  To integrate $(D f(x)) over the interval (-$(INFTY),$(D a)) or
508     ($(D a),$(INFTY)) use the second form with $(D inf=Infinite.lower) or
509     $(D inf=Infinite.upper), respectively.
510 
511     Example:
512     ---
513     // Slowly convergent integral over infinite interval,
514     // integrand with endpoint singularity.
515     double f(double x) { return (1 + 10*x)^^(-2) / sqrt(x); }
516     auto i = integrateQAGI(&f, 0.0, Infinite.upper, 1e-8);
517     ---
518 */
519 Result!Real integrateQAGI(Func, Real)
520     (scope Func f, Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
521 {
522     return integrateQAGI(f, Real.init, cast(Infinite) 2, epsRel, epsAbs);
523 }
524 
525 
526 /// ditto
527 Result!Real integrateQAGI(Func, Real)(scope Func f, Real a, Infinite inf,
528     Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
529     in
530     {
531         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
532             "Requested accuracy is too small.");
533     }
534     body
535 {
536     Real result, abserr;
537     int neval, ier, last;
538 
539     enum int limit = 500;
540     Real[limit] alist, blist, rlist, elist;
541     int[limit] iord;
542 
543     qagie(f, a, inf, epsAbs, epsRel, limit, result, abserr, neval, ier,
544         alist.ptr, blist.ptr, rlist.ptr, elist.ptr, iord.ptr, last);
545     checkQuadpackStatus(ier, result, abserr);
546 
547     return typeof(return)(result, abserr);
548 }
549 
550 
551 unittest
552 {
553     double f(double x) { return (1 + 10*x)^^(-2) / sqrt(x); }
554     auto i = integrateQAGI(&f, 0.0, Infinite.upper);
555     double expected = PI / (2 * sin(PI/2)) / sqrt(10.0);
556     assert (isAccurate(i.value, i.error, expected, 1e-6));
557 }
558 
559 
560 
561 
562 /** Calculate the integral of an oscillatory function over the
563     finite interval ($(D a),$(D b)).
564 
565     Use this to calculate the integral of $(D f(x)*cos(omega*x))
566     or $(D f(x)*sin(omega*x))
567     where $(D f(x)) is the (possibly singular) user-specified function
568     and $(D omega) is a known constant.  The weight function is specified
569     by setting $(D weight) to $(D Oscillation.cos) or $(D Oscillation.sin).
570 
571     The rule evaluation component is based on the modified
572     $(LINK2 http://en.wikipedia.org/wiki/Clenshaw%E2%80%93Curtis_quadrature,
573     Clenshaw–Curtis technique).
574     An adaptive subdivision scheme is used in connection with
575     an extrapolation procedure, which is a modification of that in
576     $(D integrateQAGS()) and allows the algorithm to deal with
577     singularities in $(D f(x)).
578 
579     See_Also:
580     $(D integrateQAWF()), for similar integrals over an infinite interval.
581 
582     Example:
583     ---
584     // Integrate exp(20*(x-1))*sin(256*x) over the interval (0,1)
585     real f(real x) { return exp(20*(x-1)); }
586     auto i = integrateQAWO(&f, 0.0L, 1.0L, 256.0L, Oscillation.sin, 1e-15L);
587     ---
588 */
589 Result!Real integrateQAWO(Func, Real)(scope Func f, Real a, Real b, Real omega,
590     Oscillation weight, Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
591     in
592     {
593         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
594             "Requested accuracy is too small.");
595     }
596     body
597 {
598     Real result, abserr;
599     int neval, ier, last, momcom;
600 
601     enum limit = 500;
602     enum icall = 1;
603     enum maxp1 = 21;
604     Real[limit] alist, blist, rlist, elist;
605     int[limit] iord, nnlog;
606     Real[maxp1*25] chebmo;
607 
608     qawoe!(Real, Func)(f, a, b, omega, weight, epsAbs, epsRel, limit,
609         icall, maxp1, result, abserr, neval, ier, last,
610         alist.ptr, blist.ptr, rlist.ptr, elist.ptr, iord.ptr, nnlog.ptr,
611         momcom, chebmo.ptr);
612     checkQuadpackStatus(ier, result, abserr);
613 
614     return typeof(return)(result, abserr);
615 }
616 
617 
618 enum Oscillation { cos = 1, sin = 2 }
619 
620 
621 unittest
622 {
623     enum eps = 1e-15L;
624     real f(real x) { return exp(20*(x-1)); }
625     auto i = integrateQAWO(&f, 0.0L, 1.0L, 256.0L, Oscillation.sin, eps);
626     real expect = (20*sin(256.0L) - 256*cos(256.0L) + 256*exp(-20.0L))/(400+65536);
627     assert (isAccurate(i, expect, eps));
628 }
629 
630 
631 
632 
633 /** Calculates a Fourier transform integral.
634 
635     Use this to calculate the integral of $(D f(x)*cos(omega*x))
636     or $(D f(x)*sin(omega*x))
637     on the interval ($(D a),$(INFTY)).  The weight function is specified
638     by setting $(D weight) to $(D Oscillation.cos) or $(D Oscillation.sin).
639 
640     The procedure of $(D integrateQAWO()) is applied on successive finite
641     intervals, and convergence acceleration by means of the Epsilon
642     algorithm is applied to the series of integral approximations.
643 
644     Note:
645     This function is unique among the QUADPACK integrators in that
646     you must specify an absolute accuracy, not a relative one.
647 
648     See_Also:
649     $(D integrateQAWO()), for similar integrals over a finite interval.
650 
651     Example:
652     ---
653     // Calculate the integral of cos(x)*exp(-x/64)/sqrt(x) over
654     // the interval (0, infinity).
655     real f(real x) { return x <= 0 ? 0 : exp(-x/64) / sqrt(x); }
656     auto i = integrateQAWF(&f, 0.0L, 1.0L, Oscillation.cos, 1e-15L);
657     ---
658 */
659 Result!Real integrateQAWF(Func, Real)(scope Func f, Real a, Real omega,
660     Oscillation weight, Real epsAbs)
661 in
662 {
663     assert (epsAbs > 0, "Requested accuracy is too small.");
664 }
665 body
666 {
667     Real result, abserr;
668     int neval, ier, lst;
669 
670     enum limit = 500;
671     enum limlst = 50;
672     enum maxp1 = 21;
673     Real[limit] alist, blist, rlist, elist;
674     Real[limlst] rslst, erlst;
675     int[limit] iord, nnlog;
676     int[limlst] ierlst;
677     Real[maxp1*25] chebmo;
678 
679     qawfe!(Real, Func)(f, a, omega, weight, epsAbs, limlst, limit,
680         maxp1, result, abserr, neval, ier, rslst.ptr, erlst.ptr, ierlst.ptr,
681         lst, alist.ptr, blist.ptr, rlist.ptr, elist.ptr, iord.ptr, nnlog.ptr,
682         chebmo.ptr);
683 
684     // QAWF has slightly different error codes, so we can't
685     // use checkQuadpackStatus()
686     string msg, extra;
687     switch(ier)
688     {
689         case 0:
690             return typeof(return)(result, abserr);
691         case 1:
692             msg = "The maximum number of cycles allowed has been reached";
693             break;
694         case 4:
695             msg = "Convergence acceleration algorithm failed to reach the "
696                 ~"desired accuracy";
697             break;
698         case 6:
699             msg = "Invalid input";
700             extra = "If you get this error message, it is a bug in SciD.  "
701                 ~ "Please report.";
702             break;
703         case 7:
704             msg = "Bad integrand behaviour within one or more of the cycles.";
705             break;
706         default:
707             msg = "Invalid QUADPACK error code";
708             extra = "If you get this error message, it is a bug in SciD.  "
709                 ~ "Please report.";
710     }
711     if (extra.length == 0)
712     {
713         extra = "There may be local integration difficulties "
714             ~"(singularities, discontinuities, etc.).  If the position "
715             ~"of such a difficulty can be determined, try to split "
716             ~"up the interval at this point and call the appropriate "
717             ~"integrators on the subintervals.";
718     }
719     throw new IntegrationException(msg, extra, result, abserr);
720 }
721 
722 
723 unittest
724 {
725     enum eps = 1e-14L;
726     real f(real x) { return x <= 0 ? 0 : exp(-x/64) / sqrt(x); }
727     auto i = integrateQAWF(&f, 0.0L, 1.0L, Oscillation.cos, eps);
728     real expect = sqrt(PI) * (1 + 1.0L/4096)^^(-0.25L) * cos(atan(64.0L)/2);
729     assert (isAccurate(i, expect, 0.0L, eps));
730 }
731 
732 
733 
734 
735 // Weight functions for integrateQAWS()
736 enum Weight { unity = 1, logxa = 2, logbx = 3, logab = 4 }
737 
738 
739 /** Calculate an integral over the finite interval ($(D a),$(D b)),
740     where the integrand has algebraic and/or logarithmic endpoint
741     singularities of a known type.
742 
743     The integrand is taken to be on the form
744     ---
745                 alpha        beta
746     f(x) (x - a)      (b - x)     w(x)
747     ---
748     where $(D f(x)) is the given function and $(D w(x)) is
749     specified by setting the $(D weight) parameter to one of the following:
750     ---
751     Weight.unity:  w(x) = 1
752     Weight.logxa:  w(x) = log(x-a)
753     Weight.logbx:  w(x) = log(b-x)
754     Weight.logab:  w(x) = log(x-a) log(b-x)
755     ---
756 
757     A globally adaptive subdivision strategy is applied,
758     with modified
759     $(LINK2 http://en.wikipedia.org/wiki/Clenshaw%E2%80%93Curtis_quadrature,
760     Clenshaw–Curtis integration) on those subintervals
761     which contain $(D a) or $(D b).
762 
763     Example:
764     ---
765     // Calculate the integral of 1/(sqrt(1-x^^2) * (x+1.5)).
766     // Another way to write this integrand is
767     //     (x-(-1))^^(-0.5) * (1-x)^^0.5 / (x+1.5),
768     // so we set alpha = beta = -0.5.
769     real f(real x) { return 1/(x + 1.5L); }
770     auto i = integrateQAWS(&f, -1.0L, 1.0L, -0.5L, -0.5L, Weight.unity, 1e-15L);
771     ---
772 */
773 Result!Real integrateQAWS(Func, Real)(scope Func f, Real a, Real b,
774     Real alpha, Real beta, Weight weight,
775     Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
776     in
777     {
778         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
779             "Requested accuracy is too small.");
780     }
781     body
782 {
783     Real result, abserr;
784     int neval, ier, last;
785 
786     enum int limit = 500;
787     Real[limit] alist, blist, rlist, elist;
788     int[limit] iord;
789 
790     int sign = 1;
791     if (b <= a)
792     {
793         if (b == a) return typeof(return)(0, 0);
794         swap(a, b);
795         sign = -1;
796     }
797 
798     qawse(f, a, b, alpha, beta, weight, epsAbs, epsRel, limit,
799         result, abserr, neval, ier,
800         alist.ptr, blist.ptr, rlist.ptr, elist.ptr, iord.ptr, last);
801     checkQuadpackStatus(ier, result, abserr);
802 
803     return typeof(return)(sign*result, abserr);
804 }
805 
806 
807 unittest
808 {
809     enum eps = 1e-15L;
810     real f(real x) { return 1/(x + 1.5L); }
811     auto i = integrateQAWS(&f, 1.0L, -1.0L, -0.5L, -0.5L, Weight.unity, eps);
812     auto expected = -PI / sqrt(1.5L^^2 - 1);
813     assert (isAccurate(i, expected, eps));
814 }
815 
816 
817 
818 
819 /** Calculate a Cauchy principal value integral.
820 
821     Use this to calculate the integral of $(D f(x)/(x-c)) over the finite
822     interval ($(D a),$(D b)), where $(D f(x)) is smooth on the entire
823     interval and $(D c) is not one of the endpoints.
824 
825     The strategy is globally adaptive.  Modified
826     $(LINK2 http://en.wikipedia.org/wiki/Clenshaw%E2%80%93Curtis_quadrature,
827     Clenshaw–Curtis integration) is used on those intervals containing the point
828     $(D x = c).
829 
830     Example:
831     ---
832     // Integrate cos(x-1)/(x-1) over the interval (0,3)
833     real f(real x) { return cos(x-1); }
834     auto i = integrateQAWC(&f, 0.0L, 3.0L, 1.0L, 1e-15L);
835     ---
836 */
837 Result!Real integrateQAWC(Func, Real)(scope Func f, Real a, Real b, Real c,
838     Real epsRel = cast(Real) 1e-6, Real epsAbs = cast(Real) 0)
839     in
840     {
841         assert (epsAbs > 0 || epsRel >= 50*Real.epsilon,
842             "Requested accuracy is too small.");
843         assert (c != a && c != b, "Singularity at interval endpoint.");
844     }
845     body
846 {
847     Real result, abserr;
848     int neval, ier, last;
849 
850     enum limit = 500;
851     Real[limit] alist, blist, rlist, elist;
852     int[limit] iord;
853 
854     qawce!(Real, Func)(f, a, b, c, epsAbs, epsRel, limit, result, abserr,
855         neval, ier, alist.ptr, blist.ptr, rlist.ptr, elist.ptr, iord.ptr,
856         last);
857     checkQuadpackStatus(ier, result, abserr);
858 
859     return typeof(return)(result, abserr);
860 }
861 
862 
863 unittest
864 {
865     // This is just a simple test of basic functionality.
866     // More thorough unittests are in the scid.ports.quadpack.qawc module.
867     enum eps = 1e-15L;
868     enum expect = 0.085576905873896861036L;
869     static real f(real x) { return cos(x-1); }
870     auto i = integrateQAWC(&f, 0.0L, 3.0L, 1.0L, eps);
871     assert (abs(i.value-expect) < eps*expect && i.error <= eps);
872 }
873 
874 
875 
876 
877 /** Calculate the integral of $(D f(x)) over the finite interval
878     ($(D a),$(D b)) using double exponential integration.
879 
880     Example:
881     ---
882     double f(double x) { return x^^2 * log(1/x); }
883     auto i = integrateDE(&f, 0.0, 1.0);
884     ---
885 */
886 Result!Real integrateDE(Func, Real)(scope Func f, Real a, Real b,
887     Real epsRel = cast(Real) 1e-6)
888 {
889     Real result, error;
890     intde(f, a, b, epsRel, &result, &error);
891     if (error < 0) throw new IntegrationException(
892         "Integration failed",
893         "The integrand may have discontinuities, singularities or "
894         ~"oscillatory behaviour in the integration interval.",
895         result,
896         real.nan);
897     return typeof(return)(result, error);
898 }
899 
900 
901 unittest
902 {
903     double f(double x) { return x^^2 * log(1/x); }
904     auto result = integrateDE(&f, 0.0, 1.0, 1e-7);
905     assert (isAccurate(result.value, result.error, 1.0/9, 1e-6));
906 }
907 
908 
909 
910 
911 /** Calculate the integral of $(D f(x)) over the infinite interval
912     ($(D a),$(INFTY)) using double exponential integration.
913 
914     Example:
915     ---
916     double f(double x) { return (1 + 10*x)^^(-2) / sqrt(x); }
917     auto i = integrateDEI(&f, 0.0);
918     ---
919 */
920 Result!Real integrateDEI(Func, Real)(scope Func f, Real a,
921     Real epsRel = cast(Real) 1e-6)
922 {
923     Real result, error;
924     intdei!Real(f, a, epsRel, &result, &error);
925     if (error < 0) throw new IntegrationException(
926         "Integration failed",
927         "The integrand may have discontinuities, singularities or "
928         ~"oscillatory behaviour in the integration interval.",
929         result,
930         real.nan);
931     return typeof(return)(result, error);
932 }
933 
934 
935 unittest
936 {
937     double f(double x) { return (1 + 10*x)^^(-2) / sqrt(x); }
938     auto result = integrateDEI(&f, 0.0);
939     double expected = PI / (2 * sin(PI/2)) / sqrt(10.0);
940     assert (matchDigits(result.value, expected, 6));
941 }
942 
943 
944 
945 
946 /** Calculate the integral of an oscillating function $(D f(x))
947     over the infinite interval ($(D a),$(INFTY)) using double exponential
948     integration.
949 
950     $(D f(x)) is assumed to take the form
951     ---
952     f(x) = g(x) * sin(omega * x + theta)
953     ---
954     as $(D x) goes to infinity ($(D theta) is not specified).
955 
956     Example:
957     ---
958     real f(real x) { return x <= 0 ? 0 : cos(x) * exp(-x/64) / sqrt(x); }
959     auto i = integrateDEO(&f, 0.0L, 1.0L, 1e-18L);
960     ---
961 */
962 Result!Real integrateDEO(Func, Real)(scope Func f, Real a,
963     Real omega, Real epsRel = cast(Real) 1e-6)
964 {
965     Real result, error;
966     intdeo(f, a, omega, epsRel, &result, &error);
967     if (error < 0) throw new IntegrationException(
968         "Integration failed",
969         "The integrand may have discontinuities, singularities or "
970         ~"oscillatory behaviour in the integration interval.",
971         result,
972         real.nan);
973     return typeof(return)(result, error);
974 }
975 
976 
977 unittest
978 {
979     real f(real x) { return x <= 0 ? 0 : cos(x) * exp(-x/64) / sqrt(x); }
980     auto i = integrateDEO(&f, 0.0L, 1.0L, 1e-18L);
981     real expect = sqrt(PI) * (1 + 1.0L/4096)^^(-0.25L) * cos(atan(64.0L)/2);
982     assert (matchDigits(i.value, expect, 18));
983 }
984 
985 
986 
987 
988 /** Exception thrown when an integration routine fails. */
989 class IntegrationException : Exception
990 {
991     /** The current estimates of the integration result and
992         absolute error.
993 
994         Depending on the type of error, these may or may not be
995         close to the correct values.  They are, however, very often
996         useful for figuring out what has gone wrong.
997     */
998     immutable real resultEstimate;
999     immutable real errorEstimate;       /// ditto
1000 
1001 
1002     /** This value will sometimes contain more detailed information
1003         about the error.
1004     */
1005     immutable string extra;
1006 
1007 
1008     this(string msg, real resultEstimate, real errorEstimate,
1009         string file = __FILE__, size_t line = __LINE__)
1010     {
1011         this(msg, null, resultEstimate, errorEstimate, file, line);
1012     }
1013 
1014 
1015     this(string msg, string extra, real resultEstimate, real errorEstimate,
1016         string file = __FILE__, size_t line = __LINE__)
1017     {
1018         super (msg, file, line);
1019 
1020         this.extra = extra;
1021         this.resultEstimate = resultEstimate;
1022         this.errorEstimate = errorEstimate;
1023     }
1024 
1025 
1026     override string toString()
1027     {
1028         return super.toString()
1029             ~ (extra.length > 0 ? "\n"~extra : "")
1030             ~ text("\nCurrent estimate: ", resultEstimate, " ± ", errorEstimate);
1031     }
1032 }
1033 
1034 
1035 /*  Verify the value of 'ier' returned by QUADPACK routines, and
1036     throw an appropriate exception if it is not zero.
1037 */
1038 void checkQuadpackStatus(Real)(int ier, Real result, Real abserr,
1039     string file = __FILE__, size_t line = __LINE__)
1040 {
1041     string msg, extra;
1042     switch(ier)
1043     {
1044         case 0: return;
1045         case 1:
1046             msg = "Reached the maximum number of iterations or subdivisions";
1047             extra = "If possible, try using a more special-purpose integrator.";
1048             break;
1049         case 2:
1050             msg = "Roundoff error detected";
1051             extra = "The occurrence of roundoff error is detected, which "
1052                 ~ "prevents the requested tolerance from being achieved.  "
1053                 ~ "The error may be under-estimated.";
1054             break;
1055         case 3:
1056             msg = "Bad integrand behaviour";
1057             extra = "Extremely bad integrand behaviour occurs at at some "
1058                 ~ "points of the integration interval.";
1059             break;
1060         case 4:
1061             msg = "Roundoff error detected.";
1062             extra = "The algorithm does not converge.  Roundoff error is "
1063                 ~ "detected in the extrapolation table.  It is assumed that "
1064                 ~ "the requested tolerance cannot be achieved, and that the "
1065                 ~ "returned result is the best that can be obtained.";
1066             break;
1067         case 5:
1068             msg = "Integral is divergent or converges too slowly";
1069             break;
1070         case 6:
1071             msg = "Invalid input";
1072             extra = "If you get this error message, it is a bug in SciD.  "
1073                 ~ "Please report.";
1074             break;
1075         default:
1076             msg = "Invalid QUADPACK error code";
1077             extra = "If you get this error message, it is a bug in SciD.  "
1078                 ~ "Please report.";
1079     }
1080     throw new IntegrationException(msg, extra, result, abserr, file, line);
1081 }
1082 
1083 
1084 
1085 
1086 /** Calculate the derivative of a function.
1087 
1088     This function uses Ridders' method of extrapolating the results
1089     of finite difference formulas for consecutively smaller step sizes,
1090     with an improved stopping criterion described in the Numerical Recipes
1091     books by Press et al.
1092 
1093     This method gives a much higher degree of accuracy in the answer
1094     compared to a single finite difference calculation, but requires
1095     more function evaluations; typically 6 to 12. The maximum number
1096     of function evaluations is $(D 2*tableauSize).
1097 
1098     Params:
1099         f = The function of which to take the derivative.
1100         x = The point at which to take the derivative.
1101         scale = A "characteristic scale" over which the function
1102             changes. (optional)
1103         tableauSize = The values of the consecutive approximations
1104             are stored in a $(D tableauSize)-by-$(D tableauSize) triangular
1105             matrix. Sometimes this number can be reduced to limit
1106             the possible number of function evaluations (see above)
1107             and thus greater speed, and sometimes it can be increased
1108             to allow for higher accuracy. (optional)
1109 
1110     Example:
1111     This example is from Ridders' paper:
1112     ---
1113     // Let's take the derivative of
1114     //                 x
1115     //                e
1116     //     f(x) = ----------
1117     //                     2
1118     //            sin x - x
1119     // at x=1.
1120     real f(real x) { return exp(x)/(sin(x)-x*x); }
1121     real dfdxAt1 = 140.73773557129660339;
1122 
1123     // scale=0.01 is appropriate for this function.
1124     auto r = diff(&f, 1.0, 0.01);
1125     assert (abs(r.value - dfdxAt1) <= r.error);
1126 
1127     // Note that if we use the default scale, it won't work:
1128     auto s = diff(&f, 1.0);
1129     writeln(s.error);           // prints "inf"
1130     ---
1131 
1132     References:
1133     $(UL
1134         $(LI
1135             C. J. F. Ridders,
1136             $(I Accurate computation of F'(x) and F'(x)F''(x)).
1137             Advances in Engineering Software, vol. 4 (1982), issue 2, p. 75.)
1138         $(LI
1139             W. H. Press, S. A. Teukolsky, W. T. Vetterling, and B. P. Flannery,
1140             $(I Numerical Recipes in C++) (2nd ed.).
1141             Cambridge University Press, 2003.)
1142     )
1143 */
1144 Result!real diff (Func)
1145     (scope Func f, real x, real scale = 1.0, size_t tableauSize = 10)
1146 in
1147 {
1148     assert (tableauSize > 0);
1149 }
1150 body
1151 {
1152     mixin(newFrame);
1153 
1154     static assert (__traits(compiles, { real y; Func g; real z = g(y); }),
1155         "diff: Invalid function type: "~Func.stringof);
1156 
1157     // Set up Romberg tableau.
1158     auto workspace = newStack!real((tableauSize*(tableauSize+1))/2);
1159     auto tab =
1160         MatrixView!(real, Storage.Triangular)(workspace, tableauSize);
1161 
1162     // Let's keep the notation in order.
1163     real h = scale == 0.0 ? 1.0 : abs(scale);
1164 
1165     // Divide h by the factor FAC for each finite-difference
1166     // approximation. Ridders uses FAC=2.0 in his paper, but
1167     // the NR book uses FAC=1.4.
1168     // TODO: Experiment and see which value is best.
1169     enum real FAC = 2.0;
1170     enum real FACSQ = FAC*FAC;
1171     enum real INVFAC = 1.0/FAC;
1172 
1173     // From the NR book: Stop when the difference between consecutive
1174     // approximations is bigger than SAFE*error, where error is an
1175     // estimate of the absolute error in the current (best) approximation.
1176     enum int SAFE = 2;
1177 
1178     // First approximation: A_0
1179     tab[0,0] = (f(x+h) - f(x-h))/(2.0*h);
1180 
1181     real result, error = real.infinity;
1182     for (size_t n=1; n<tableauSize; n++)
1183     {
1184         // Decrease h.
1185         h *= INVFAC;
1186 
1187         // Compute A_n
1188         tab[0,n] = (f(x+h) - f(x-h))/(2.0*h);
1189 
1190         real facm = 1.0;
1191         for (size_t m=1; m<=n; m++)
1192         {
1193             facm *= FACSQ;
1194 
1195             // Compute B_(n-1), C_(n-2), ...
1196             real upLeft  = tab[m-1, n-1];
1197             real up      = tab[m-1, n];
1198             real current = (facm*up - upLeft)/(facm-1);
1199             tab[m,n] = current;
1200 
1201             // Calculate and check error.
1202             real currentError = max(abs(current - upLeft), abs(current - up));
1203             if (currentError <= error)
1204             {
1205                 result = current;
1206                 error = currentError;
1207             }
1208         }
1209 
1210         if (abs(tab[n,n]-tab[n-1,n-1]) >= SAFE*error)  break;
1211     }
1212 
1213     return Result!real(result, error);
1214 }
1215 
1216 unittest
1217 {
1218     alias diff!(float function(float)) diff_float;
1219     alias diff!(double function(double)) diff_double;
1220     alias diff!(real function(real)) diff_real;
1221 
1222     real f(real x) { return exp(x)/(sin(x)-x*x); }
1223     auto r = diff(&f, 1.0, 0.01, 5);
1224     assert (approxEqual(r.value, 140.73773557129660339L,
1225         0.0L, min(r.error, sqrt(real.epsilon))));
1226 }
1227 
1228 
1229 
1230 
1231 /** Calculate the derivative of a function using a two-point
1232     formula, i.e. a forward- or backward-difference formula.
1233 
1234     This method only evaluates the function once (in addition
1235     to the function value provided by the user), and is therefore
1236     the fastest way to compute a derivative.  However, it is also
1237     the least accurate method, and should only be used if the
1238     function is very expensive to compute $(I and) you have
1239     already calculated $(D f(x)).
1240 
1241     Params:
1242         f = The function to differentiate.
1243         x = The point at which to take the derivative.
1244         fx = The function value at $(D x), i.e. $(D f(x))
1245         scale = A characteristic scale for $(D f).  When this
1246             is positive, the forward-difference formula
1247             is used, and when it is negative, the
1248             backward-difference formula is used.
1249 
1250     Returns:
1251         An approximation to the derivative of $(D f) at the point
1252         $(D x).  The relative error in the result is $(I at best)
1253         on the order of $(D sqrt(real.epsilon)).
1254         Usually it is much higher.
1255 */
1256 real diff2(Func)(scope Func f, real x, real fx, real scale = 1.0)
1257 in { assert (scale != 0); }
1258 body
1259 {
1260     enum sqrtEpsilon = sqrt(real.epsilon);
1261     immutable xph = x + sqrtEpsilon*scale;
1262     immutable h = xph - x;
1263     return (f(xph) - fx) / (xph - x);
1264 }
1265 
1266 unittest
1267 {
1268     real f(real x) { return sin(x) * log(x); }
1269     real df(real x) { return cos(x) * log(x) + sin(x) / x; }
1270 
1271     foreach (x; iota(0.1, 1.0, 0.1))
1272     {
1273         assert (matchDigits(diff2(&f, x, f(x)), df(x), 8));
1274     }
1275 }
1276 
1277 
1278 
1279 
1280 /** Calculate the derivative of a function using a three-point
1281     formula, a.k.a. a central difference formula.
1282 
1283     The function is evaluated twice, at points just below and
1284     just above $(D x).
1285 
1286     Params:
1287         f = The function to differentiate.
1288         x = The point at which to take the derivative.
1289         scale = A characteristic scale for $(D f).
1290 
1291     Returns:
1292         An approximation to the derivative of $(D f) at the point
1293         $(D x).  The relative error in the result is at best
1294         on the order of $(D (real.epsilon)^(2/3)), roughly three
1295         orders of magnitude more accurate than $(D diff2()).
1296 */
1297 real diff3(Func)(scope Func f, real x, real scale = 1.0)
1298 in { assert (scale != 0); }
1299 body
1300 {
1301     immutable h = cbrt(real.epsilon) * scale;
1302     immutable xmh = x - h;
1303     immutable xph = x + h;
1304     return (f(xph) - f(xmh))/(xph - xmh);
1305 }
1306 
1307 unittest
1308 {
1309     real f(real x) { return sin(x) * log(x); }
1310     real df(real x) { return cos(x) * log(x) + sin(x) / x; }
1311 
1312     foreach (x; iota(0.1, 1.0, 0.1))
1313     {
1314         assert (matchDigits(diff3(&f, x), df(x), 11));
1315     }
1316 }
1317 
1318 
1319 
1320 
1321 /** Calculate the Jacobian matrix associated with a set of $(I m) functions
1322     in $(I n) variables using a central-difference approximation to the
1323     Jacobian.
1324 
1325     This method requires 2$(I n) function evaluations, but is more
1326     accurate than the faster $(D jacobian2()) function. The relative
1327     accuracy in the result is, at best, on the order of
1328     $(D (real.epsilon)^(2/3)).
1329 
1330     Params:
1331         f = The set of functions. This is typically a function or delegate
1332             which takes a vector as input and returns a vector. If the
1333             function takes a second vector parameter, this is assumed to
1334             be a buffer for the return value, and will be used as such.
1335 
1336         m = The number of functions in $(D f).
1337 
1338         x = The point at which to take the derivative.
1339 
1340         scale = A "characteristic scale" over which the function changes.
1341             (optional)
1342 
1343         buffer = A buffer of length at least $(I m)*$(I n), for storing the calculated
1344             Jacobian matrix. (optional)
1345 
1346     Examples:
1347     ---
1348     // Let's say we want to find the Jacobian of the function
1349     //      f(x,y) = (xy, x-y)
1350     // at the point p = (1, 2).
1351     real[] p = [ 1.0, 2.0 ];
1352 
1353     // This is the simplest way to do it:
1354     real[] f(real[] a)
1355     {
1356         auto r = new real[2];
1357         r[0] = a[0] * a[1];
1358         r[1] = a[0] - a[1];
1359         return r;
1360     }
1361 
1362     auto j = jacobian(&f, 2, p);
1363 
1364     // However, if we need to perform this operation many times,
1365     // we may want to speed things up a bit. To avoid unnecessary
1366     // repeated allocations, we can add a buffer parameter to the
1367     // function:
1368     real[] g(real[] a, real[] r)
1369     {
1370         r[0] = a[0] * a[1];
1371         r[1] = a[0] - a[1];
1372         return r[0 .. 2];
1373     }
1374 
1375     auto jFaster = jacobian(&g, 2, p);
1376     ---
1377 
1378     See_also:
1379     $(UL $(LI Wikipedia:
1380         $(LINK2 http://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant,Jacobian matrix and determinant).
1381     ))
1382 */
1383 MatrixView!Real jacobian (Real, Func) (scope Func f, int m, Real[] x,
1384     real scale=1.0, Real[] buffer=null)
1385 {
1386     mixin (newFrame);
1387 
1388     static assert (isFloatingPoint!Real,
1389         "jacobian: Not a floating-point type: "~Real.stringof);
1390     static assert (isVectorField!(Func, Real),
1391         "jacobian: Invalid function type ("~Func.stringof~"), or "
1392        ~"function type doesn't match parameter type ("~Real.stringof~")");
1393     assert (m > 0);
1394 
1395     immutable size_t n = x.length;
1396     buffer.length = m*n;
1397     auto jaco = MatrixView!Real(buffer, m, n);
1398 
1399     // Allocate workspace.
1400     auto workspace = newStack!Real(2*m);
1401     auto fxph = workspace[0 .. m];
1402     auto fxmh = workspace[m .. $];
1403 
1404     // Determine step length.
1405     scale = scale == 0.0 ? 1.0 : abs(scale);
1406     immutable real CBRT_EPSILON = cbrt(real.epsilon); // TODO: make enum
1407     real h = CBRT_EPSILON * scale;
1408 
1409     foreach (j; 0 .. n)
1410     {
1411         // We don't want to change x.
1412         real save = x[j];
1413 
1414         // Ensure 2h is exactly (x+h)-(x-h)
1415         real xph = save + h;
1416         real xmh = save - h;
1417         real twh = xph - xmh;
1418 
1419         // Evaluate function at both points, provide buffer if possible.
1420         x[j] = xph;
1421         static if (isBufferVectorField!(Func,Real))  fxph = f(x, fxph);
1422         else  fxph = f(x);
1423 
1424         x[j] = xmh;
1425         static if (isBufferVectorField!(Func,Real))  fxmh = f(x, fxmh);
1426         else  fxmh = f(x);
1427 
1428         // Restore x.
1429         x[j] = save;
1430 
1431         // Calculate one column of the Jacobian.
1432         foreach (i; 0 .. m)
1433             jaco[i, j] = (fxph[i] - fxmh[i])/twh;
1434     }
1435 
1436     return jaco;
1437 }
1438 
1439 unittest
1440 {
1441     alias jacobian!(float, float[] function(float[])) jacobian_float;
1442     alias jacobian!(double, double[] function(double[])) jacobian_double;
1443     alias jacobian!(real, real[] function(real[])) jacobian_real;
1444 
1445     // Note: This is the example from the doc comment.
1446     // There are more unittests for jacobian() below jacobian2().
1447     double[] f(double[] a, double[] r=null)
1448     {
1449         if (r.length < 2)  r = new double[2];
1450         auto x = a[0], y = a[1];
1451 
1452         r[0] = x*y;
1453         r[1] = x-y;
1454         return r[0 .. 2];
1455     }
1456 
1457     double[] x = [ 1.0, 2.0 ];
1458     double[4] buffer;
1459     auto j1 = jacobian(&f, 2, x);
1460     auto j2 = jacobian(&f, 2, x, 1.0, buffer);
1461 
1462     double e = 1e-6;
1463     assert (approxEqual(j1[0,0], 2.0, e) && approxEqual(j1[0,1],  1.0, e)
1464       &&  approxEqual(j1[1,0], 1.0, e) && approxEqual(j1[1,1], -1.0, e));
1465 
1466     assert (approxEqual(j2[0,0], 2.0, e) && approxEqual(j2[0,1],  1.0, e)
1467       &&  approxEqual(j2[1,0], 1.0, e) && approxEqual(j2[1,1], -1.0, e));
1468 }
1469 
1470 
1471 
1472 
1473 /** Calculate the Jacobian using forward-/backward-difference
1474     methods, also known as 2-point formulas.
1475 
1476     This is less accurate than the central-difference method
1477     used in the $(D jacobian()) function, but requires only half
1478     as many function evaluations. The relative accuracy is,
1479     at best, on the order of $(D sqrt(real.epsilon)).
1480 
1481     Params:
1482         f = The set of functions. This is typically a function or delegate
1483             which takes a vector as input and returns a vector. If the
1484             function takes a second vector parameter, this is assumed to
1485             be a buffer for the return value, and will be used as such.
1486 
1487         m = The number of functions in $(D f).
1488 
1489         x = The point at which to take the derivative.
1490 
1491         scale = $(D abs(scale)) is the characteristic scale of the
1492             function, and the sign of scale determines which
1493             differentiation method is used. If $(D scale) is
1494             negative, the backward difference method is used, and
1495             if it is positive, forward differences are used.
1496             (optional)
1497 
1498         fx = The result of evaluating the function at the point $(D x).
1499             Providing this saves one function evaluation if you
1500             for some reason have already calculated the value. (optional)
1501 
1502         buffer = A buffer of length at least $(I m)*$(I n), for storing the calculated
1503             Jacobian matrix. (optional)
1504 
1505     Examples:
1506     ---
1507     // Continuing with the example for the jacobian() function,
1508     // we make it even faster by using a 2-point formula.
1509     auto gp = g(p);
1510     auto jFastest = jacobian2(&g, p, 1.0, gp, buffer, workspace);
1511     ---
1512 */
1513 MatrixView!Real jacobian2 (Real, Func) (scope Func f, int m, Real[] x,
1514     real scale=1.0, Real[] fx=null, Real[] buffer=null)
1515 {
1516     mixin (newFrame);
1517 
1518     static assert (isFloatingPoint!Real,
1519         "jacobian2: Not a floating-point type: "~Real.stringof);
1520     static assert (isVectorField!(Func, Real),
1521         "jacobian2: Invalid function type ("~Func.stringof~"), or "
1522        ~"function type doesn't match parameter type ("~Real.stringof~")");
1523     assert (m > 0);
1524 
1525     immutable size_t n = x.length;
1526     buffer.length = m*n;
1527     auto jaco = MatrixView!Real(buffer, m, n);
1528 
1529     // Allocate workspace.
1530     auto fxph = newStack!Real(m);
1531 
1532     // Calculate f(x) if it's not provided.
1533     if (fx.length == 0)
1534     {
1535         static if (isBufferVectorField!(Func, Real))
1536         {
1537             fx = newStack!Real(m);
1538             fx = f(x, fx);
1539         }
1540         else fx = f(x);
1541     }
1542     else assert (fx.length == m);
1543 
1544     // Determine step length.
1545     scale = scale == 0.0 ? 1.0 : abs(scale);
1546     real h = sqrt(real.epsilon) * scale;
1547 
1548     for (int j=0; j<n; j++)
1549     {
1550         // We don't want to change x.
1551         real save = x[j];
1552 
1553         // Ensure h is exactly (x+h)-x
1554         real xph = save + h;
1555         real hExact = xph - save;
1556 
1557         // Evaluate function at x+h, provide buffer if possible.
1558         x[j] = xph;
1559         static if (isBufferVectorField!(Func,Real))  fxph = f(x, fxph);
1560         else  fxph = f(x);
1561 
1562         // Restore x.
1563         x[j] = save;
1564 
1565         // Calculate one column of the Jacobian.
1566         for (int i=0; i<m; i++)
1567             jaco[i, j] = (fxph[i] - fx[i])/hExact;
1568     }
1569 
1570     return jaco;
1571 }
1572 
1573 unittest
1574 {
1575     alias jacobian2!(float, float[] function(float[])) jacobian2_float;
1576     alias jacobian2!(double, double[] function(double[])) jacobian2_double;
1577     alias jacobian2!(real, real[] function(real[])) jacobian2_real;
1578 
1579     real[] f(real[] x, real[] buf=null)
1580     {
1581         if (buf.length < 4)  buf = new real[4];
1582         real x1 = x[0], x2 = x[1], x3 = x[2];
1583 
1584         buf[0] = x1;
1585         buf[1] = 5*x3;
1586         buf[2] = 4*x2*x2 - 2*x3;
1587         buf[3] = x3*sin(x1);
1588 
1589         return buf[0 .. 4];
1590     }
1591 
1592     real[] p = [0.0L, 1, 2];
1593     real[] answer = [1.0L, 0,      0, p[2]*cos(p[0]),
1594                         0, 0, 8*p[1],              0,
1595                         0, 5,     -2,      sin(p[0])];
1596     real[12] buffer;
1597 
1598 
1599     // Central difference
1600     real e = 1e-10;
1601     auto j = jacobian(&f, 4, p);
1602     assert (approxEqual(j.array, answer, e, e));
1603 
1604     j = jacobian(&f, 4, p, 1.0, buffer);
1605     assert (approxEqual(j.array, answer, e, e));
1606 
1607 
1608     // The next ones are less accurate.
1609     e = 1e-6;
1610 
1611     // Forward difference
1612     j = jacobian2(&f, 4, p);
1613     assert (approxEqual(j.array, answer, e, e));
1614 
1615     // Backward difference
1616     j = jacobian2(&f, 4, p, -1.0, f(p), buffer);
1617     assert (approxEqual(j.array, answer, e, e));
1618 }
1619 
1620 
1621 
1622 
1623 /** Calculate the _gradient of a function of several variables.
1624 
1625     This function calculates a central-difference approximation to
1626     the _gradient of a function $(D f). The error in the result is, at best,
1627     on the order of $(D sqrt(real.epsilon)). The function $(D f) is evaluated
1628     2$(I n) times, where $(I n) is the length of the vector $(D x).
1629 
1630     Params:
1631         f = The function of which to find the _gradient.
1632         x = The point at which to find the _gradient.
1633         scale = A "characteristic scale" over which the function
1634             changes significantly. (optional)
1635         buffer = A buffer of the same length as $(D x), for the returned
1636             _gradient vector. (optional)
1637 
1638     Example:
1639     ---
1640     // Let's find the gradient of f(x,y) = x exp(y) at
1641     // the point p = (2,1).
1642     real f(real[] x)  { return x[0] * exp(x[1]); }
1643     real[] p = [2.0L, 1.0L];
1644 
1645     auto g = gradient(&f, p);
1646     ---
1647 
1648     See_also:
1649     $(UL $(LI Wikipedia:
1650         $(LINK2 http://en.wikipedia.org/wiki/Gradient,Gradient).
1651     ))
1652 */
1653 Real[] gradient (Real, Func)
1654     (scope Func f, Real[] x, real scale=1.0, Real[] buffer=null)
1655 {
1656     static assert (isFloatingPoint!Real,
1657         "gradient: Not a floating-point type: "~Real.stringof);
1658     static assert (__traits(compiles, { Real[] u; Func g; Real v = g(u); }),
1659         "gradient: Invalid function type ("~Func.stringof~"), or "
1660        ~"function type doesn't match parameter type ("~Real.stringof~")");
1661 
1662     immutable size_t n = x.length;
1663     buffer.length = n;
1664 
1665     // Determine step length.
1666     scale = scale == 0.0 ? 1.0 : abs(scale);
1667     real h = cbrt(real.epsilon) * scale;
1668 
1669     foreach (i; 0 .. n)
1670     {
1671         // We don't want to modify the vector x.
1672         real save = x[i];
1673 
1674         // Ensure the difference between x+h and x-h is exactly 2h.
1675         real xph = save + h;
1676         real xmh = save - h;
1677         real twh = xph - xmh;
1678 
1679         // Calculate central difference and divide by 2h.
1680         x[i] = xph;
1681         real sum = f(x);
1682         x[i] = xmh;
1683         sum -= f(x);
1684         buffer[i] = sum/twh;
1685 
1686         // Restore vector.
1687         x[i] = save;
1688     }
1689 
1690     return buffer[0 .. n];
1691 }
1692 
1693 unittest
1694 {
1695     alias gradient!(float, float function(float[])) gradient_float;
1696     alias gradient!(double, double function(double[])) gradient_double;
1697     alias gradient!(real, real function(real[])) gradient_real;
1698 
1699     real f(real[] x)  { return x[0] * exp(x[1]); }
1700     real[] p = [2.0L, 1.0L];
1701 
1702     auto g = gradient(&f, p);
1703 
1704     real[] fgrad(real[] x) { return [exp(x[1]), x[0]*exp(x[1])]; }
1705     auto gtest = fgrad(p);
1706     assert (approxEqual(g, gtest, 1e-10, 1e-10));
1707 }
1708 
1709 
1710 
1711 /** Calculate the gradient of a function of several variables
1712     using Ridders' method.
1713 
1714     This function uses $(D diff()) to calculate the derivative
1715     in each direction. It is therefore more accurate, but slower, than
1716     the $(D gradient()) function. The function $(D f) is typically evaluated
1717     between 6$(I n) and 12$(I n) times, where $(I n) is the length of $(D x).
1718     See the documentation for $(D diff()) for more information on this method.
1719 
1720     This function is used in the same way as $(D gradient()).
1721 */
1722 Real[] gradientR (Real, Func)
1723     (scope Func f, Real[] x, real scale=1.0, Real[] buffer=null)
1724 {
1725     static assert (isFloatingPoint!Real,
1726         "gradientR: Not a floating-point type: "~Real.stringof);
1727     static assert (__traits(compiles, { Real[] u; Func g; Real v = g(u); }),
1728         "gradientR: Invalid function type ("~Func.stringof~"), or "
1729        ~"function type doesn't match parameter type ("~Real.stringof~")");
1730 
1731     immutable size_t n = x.length;
1732     buffer.length = n;
1733 
1734     // Calculate the derivative in each direction using Ridders' method.
1735     foreach (i; 0 .. n)
1736     {
1737         real save = x[i];
1738 
1739         // Provide a real->real proxy function.
1740         real g(real y)
1741         {
1742             x[i] = y;
1743             return f(x);
1744         }
1745 
1746         // Use Ridders' method to differentiate.
1747         buffer[i] = diff(&g, save, scale, 10);
1748         x[i] = save;
1749     }
1750 
1751     return buffer;
1752 }
1753 
1754 unittest
1755 {
1756     alias gradientR!(float, float function(float[])) gradientR_float;
1757     alias gradientR!(double, double function(double[])) gradientR_double;
1758     alias gradientR!(real, real function(real[])) gradientR_real;
1759 
1760     real f(real[] v)
1761     {
1762         real x = v[0], y = v[1], z = v[2];
1763         return exp(x) + log(y) + z*z;
1764     }
1765 
1766     real[] df(real[] v)
1767     {
1768         real x = v[0], y = v[1], z = v[2];
1769         real[] g = new real[3];
1770         g[0] = exp(x);
1771         g[1] = 1/y;
1772         g[2] = 2*z;
1773         return g;
1774     }
1775 
1776     real[] p = [ 0.0L, 2.0, 4.0 ];
1777     real[] ans = df(p);
1778     auto g = gradient(&f, p);
1779 
1780     assert (approxEqual(g, ans, sqrt(real.epsilon)));
1781 }
1782 
1783 
1784 
1785 
1786 /** Calculate the Hessian matrix of a function of several variables
1787     using a central-difference approximation.
1788 
1789     This function stores its results in an $(I n)-by-$(I n) symmetric matrix,
1790     where $(I n) is the number of variables (i.e. the length of $(D x)).
1791     The function $(D f) is evaluated 1+2$(I n)$(SUP 2) times.
1792 
1793     Params:
1794         f = The function of which to calculate the Hessian.
1795         x = The point at which to calculate the Hessian.
1796         scale = A "characteristic scale" over which the function
1797             changes significantly. (optional)
1798         buffer = A buffer of size at least $(I n)($(I n)+1)/2, for storing
1799             the Hessian matrix. (optional)
1800 
1801     Example:
1802     ---
1803     // Above, we found the gradient of f(x,y) at the point p.
1804     // Finding the Hessian matrix is just as simple:
1805     auto h = hessian(&f, p);
1806     ---
1807 
1808     See_also:
1809     $(UL $(LI Wikipedia:
1810         $(LINK2 http://en.wikipedia.org/wiki/Hessian_matrix,Hessian matrix).
1811     ))
1812 */
1813 MatrixView!(Real, Storage.Symmetric) hessian(Real, Func)
1814     (scope Func f, Real[] x, real scale=1.0, Real[] buffer=null)
1815 {
1816     static assert (isFloatingPoint!Real,
1817         "hessian: Not a floating-point type: "~Real.stringof);
1818     static assert (__traits(compiles, { Real[] u; Func g; Real v = g(u); }),
1819         "hessian: Invalid function type ("~Func.stringof~"), or "
1820        ~"function type doesn't match parameter type ("~Real.stringof~")");
1821 
1822     immutable size_t n = x.length;
1823 
1824     buffer.length = (n*n + n)/2;
1825     auto hess = MatrixView!(Real, Storage.Symmetric)(buffer, n, n);
1826 
1827     // Determine step length.
1828     enum real SQRT_EPSILON = sqrt(real.epsilon);
1829     enum real QDRT_EPSILON = sqrt(SQRT_EPSILON);
1830     scale = scale == 0.0 ? 1.0 : abs(scale);
1831     real hOffdiag = QDRT_EPSILON*scale;
1832     real hDiag = cbrt(real.epsilon*(scale^^4));
1833 
1834     // We need the function at x for the diagonal elements.
1835     real m2fx = -2.0*f(x);
1836 
1837     // Loop over columns.
1838     foreach (j; 0 .. n)
1839     {
1840         // Loop over rows, calculate offdiagonal elements.
1841         foreach (i; 0 .. j)
1842         {
1843             // Don't want to change x.
1844             real savex = x[i];
1845             real savey = x[j];
1846 
1847             // Make hx and hy exactly representable numbers.
1848             real xph = savex + hOffdiag;
1849             real xmh = savex - hOffdiag;
1850             real twhx = xph - xmh;
1851 
1852             real yph = savey + hOffdiag;
1853             real ymh = savey - hOffdiag;
1854             real twhy = yph - ymh;
1855 
1856             // Sum function value at all four points.
1857             x[i] = xph;
1858             x[j] = yph;
1859             real sum = f(x);
1860 
1861             x[j] = ymh;
1862             sum -= f(x);
1863 
1864             x[i] = xmh;
1865             sum += f(x);
1866 
1867             x[j] = yph;
1868             sum -= f(x);
1869 
1870             // Restore x and save one element of the Hessian.
1871             x[i] = savex;
1872             x[j] = savey;
1873             hess[i, j] = sum/(twhx*twhy);
1874         }
1875 
1876         // Calculate the diagonal element.
1877         {
1878             // Don't want to change x.
1879             real save = x[j];
1880 
1881             // Make h an exactly representable number.
1882             real xph = save + hDiag;
1883             real h = xph - save;
1884 
1885             // We have already calculated -2f(x).
1886             real sum = m2fx;
1887 
1888             x[j] = xph;
1889             sum += f(x);
1890 
1891             x[j] = save - hDiag;
1892             sum += f(x);
1893 
1894             // Reset x and calculate diagonal element.
1895             x[j] = save;
1896             hess[j, j] = sum/(h*h);
1897         }
1898     }
1899 
1900     return hess;
1901 }
1902 
1903 unittest
1904 {
1905     alias hessian!(float, float function(float[])) hessian_float;
1906     alias hessian!(double, double function(double[])) hessian_double;
1907     alias hessian!(real, real function(real[])) hessian_real;
1908 
1909     real f(real[] x) { return cos(x[0]+x[1]) + sin(x[0]*x[1]); }
1910     real fxx(real[] x) { return -cos(x[0]+x[1]) - x[1]*x[1]*sin(x[0]*x[1]); }
1911     real fxy(real[] x) { return -cos(x[0]+x[1]) - x[0]*x[1]*sin(x[0]*x[1])
1912         + cos(x[0]*x[1]); }
1913     real fyx(real[] x) { return fxy(x); }
1914     real fyy(real[] x) { return -cos(x[0]+x[1]) - x[0]*x[0]*sin(x[0]*x[1]); }
1915 
1916     real[] x = [ 10., 100.0 ];
1917     real[3] buffer;
1918 
1919     auto h = hessian(&f, x, PI*0.25, buffer);
1920 
1921     assert (approxEqual(h[0,0], fxx(x), 1e-6L));
1922     assert (approxEqual(h[0,1], fxy(x), 1e-6L));
1923     assert (approxEqual(h[1,0], fyx(x), 1e-6L));
1924     assert (approxEqual(h[1,1], fyy(x), 1e-6L));
1925 }