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 }