1 module deint.utils;
2 
3 
4 import std.math;
5 import std.traits;
6 import std.typecons;
7 
8 import deint.deint;
9 
10 
11 /** This function create a instance of NumInt from original another and weight function.
12  * This function is useful when we know integrands has same weight.
13  */
14 auto withWeight(Int, Fn)(auto ref Int integ, Fn weightFn)
15 {
16     alias X = Unqual!(typeof(integ.xs[0]));
17     alias W = Unqual!(typeof( integ.ws[0] * weightFn(X.init) ));
18 
19     auto xs = integ.xs;
20     auto ws = integ.ws;
21     // return IntWithWeight!(X, W)(integ.xs, integ.ws, weightFn);
22     immutable(W)[] newws;
23     if (!__ctfe)
24         newws.reserve(xs.length);
25     foreach(i, x; xs)
26         newws ~= weightFn(x) * ws[i];
27 
28     return NumInt!(X, W)(xs, newws);
29 }
30 
31 ///
32 unittest
33 {
34     // integration on [0, inf] by DE formula
35     auto deint = makeDEInt!real(0, real.infinity, Yes.isExpDecay);
36 
37     // integration on [0, inf] by DE formula with a weight exp(-x).
38     auto weighted = deint.withWeight((real x) => exp(-x));
39 
40     assert(deint.integrate((real x) => 1.0/(2*sqrt(x)) * exp(-x) )
41         .approxEqual(weighted.integrate((real x) => 1.0/(2*sqrt(x)) )));
42 }
43 
44 
45 /** This function creates a instance of NumInt for integration by the trapezoidal rule.
46  *
47  * Reference:
48  * $(HTTP en.wikipedia.org/wiki/Trapezoidal_rule)
49  */
50 NumInt!(F, F) makeTrapInt(F)(F xa, F xb, size_t N, Flag!"isPeriodic" isPeriodic = No.isPeriodic)
51 {
52     immutable(F)[] xs;
53     immutable(F)[] ws;
54     if (!__ctfe)
55     {
56         xs.reserve(N);
57         ws.reserve(N);
58     }
59 
60     if(!isPeriodic) {
61         F h = (xb - xa) / (N-1);
62         foreach(i; 0 .. N) {
63             xs ~= h*i + xa;
64             ws ~= h * (i == 0 || i == N-1 ? 0.5 : 1);
65         }
66     } else {
67         F h = (xb - xa) / N;
68         foreach(i; 0 .. N) {
69             xs ~= h*i + xa;
70             ws ~= h;
71         }
72     }
73 
74     return NumInt!(F, F)(xs, ws);
75 }
76 
77 ///
78 unittest
79 {
80     auto trap = makeTrapInt!real(0, 5, 100);
81     assert(trap.integrate((real x) => exp(-x^^2))
82         .approxEqual(sqrt(PI)/2));
83 }