1 module des.math.method.calculus.diff;
2 
3 import des.math.linear;
4 import std.traits;
5 
6 import des.util.testsuite;
7 
8 version(unittest) import std.math;
9 
10 ///
11 auto df(size_t N, size_t M, T, E=T)
12     ( Vector!(M,T) delegate( in Vector!(N,T) ) f, in Vector!(N,T) p, E step=E.epsilon*10 )
13     if( isFloatingPoint!T && isFloatingPoint!E )
14 {
15     Matrix!(M,N,T) ret;
16 
17     T dstep = 2.0 * step;
18     foreach( i; 0 .. N )
19     {
20         Vector!(N,T) p1 = p;
21         p1[i] -= step;
22         Vector!(N,T) p2 = p;
23         p2[i] += step;
24 
25         auto r1 = f(p1);
26         auto r2 = f(p2);
27 
28         ret.setCol( i, (r2-r1) / dstep );
29     }
30 
31     return ret;
32 }
33 
34 ///
35 unittest
36 {
37     auto func( in dvec2 p ) { return dvec3( p.x^^2, sqrt(p.y) * p.x, 3 ); }
38 
39     auto res = df( &func, dvec2(18,9), 1e-5 );
40     auto must = Matrix!(3,2,double)( 36, 0, 3, 3, 0, 0 );
41 
42     assert( eq_approx( res.asArray, must.asArray, 1e-5 ) );
43 }
44 
45 ///
46 auto df_scalar(T,K,E=T)( T delegate(T) f, K p, E step=E.epsilon*2 )
47     if( isFloatingPoint!T && isFloatingPoint!E && is( K : T ) )
48 {
49     Vector!(1,T) f_vec( in Vector!(1,T) p_vec )
50     { return Vector!(1,T)( f( p_vec[0] ) ); }
51     return df( &f_vec, Vector!(1,T)(p), step )[0][0];
52 }
53 
54 ///
55 unittest
56 {
57     auto pow2( double x ){ return x^^2; }
58     auto res1 = df_scalar( &pow2, 1 );
59     auto res2 = df_scalar( &pow2, 3 );
60     auto res3 = df_scalar( &pow2, -2 );
61     assert( abs(res1 - 2.0) < 2e-6 );
62     assert( abs(res2 - 6.0) < 2e-6 );
63     assert( abs(res3 + 4.0) < 2e-6 );
64 }