The OpenD Programming Language

1 /++
2 Hermite Polynomial Coefficients
3 
4 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0)
5 Authors: John Hall
6 
7 +/
8 
9 module mir.math.func.hermite;
10 
11 /++
12 Normalized (probabilist's) Hermite polynomial coefficients
13 
14 Params:
15     N = Degree of polynomial
16 
17 See_also:
18     $(LINK2 https://en.wikipedia.org/wiki/Hermite_polynomials, Hermite polynomials)
19 +/
20 @safe pure nothrow
21 long[] hermiteCoefficientsNorm(size_t N)
22 {
23     if (N == 0) {
24       return [1];  
25     } else {
26         typeof(return) output = [0, 1];
27         if (N > 1) {
28             output.length = N + 1;
29             int K;
30             typeof(return) h_N_minus_1 = hermiteCoefficientsNorm(0); // to be copied to h_N_minus_2 in loop
31             h_N_minus_1.length = N;
32             typeof(return) h_N_minus_2; //value replaced later
33             h_N_minus_2.length = N - 1;
34 
35             foreach (size_t j; 2..(N + 1)) {
36                 h_N_minus_2[0..(j - 1)] = h_N_minus_1[0..(j - 1)];
37                 h_N_minus_1[0..j] = output[0..j];
38                 K = -(cast(int) j - 1);
39                 output[0] = K * h_N_minus_2[0];
40                 foreach (size_t i; 1..(j - 1)) {
41                     output[i] = h_N_minus_1[i - 1] + K * h_N_minus_2[i];
42                 }
43                 foreach (size_t i; (j - 1)..(j + 1)) {
44                     output[i] = h_N_minus_1[i - 1];
45                 }
46             }
47         }
48         return output;
49     }
50 }
51 
52 ///
53 version(mir_test)
54 @safe pure nothrow
55 unittest
56 {
57     import mir.polynomial: polynomial;
58     import mir.rc.array: rcarray;
59     import mir.test: should;
60 
61     auto h0 = hermiteCoefficientsNorm(0).rcarray!(const double).polynomial;
62     auto h1 = hermiteCoefficientsNorm(1).rcarray!(const double).polynomial;
63     auto h2 = hermiteCoefficientsNorm(2).rcarray!(const double).polynomial;
64     auto h3 = hermiteCoefficientsNorm(3).rcarray!(const double).polynomial;
65     auto h4 = hermiteCoefficientsNorm(4).rcarray!(const double).polynomial;
66     auto h5 = hermiteCoefficientsNorm(5).rcarray!(const double).polynomial;
67     auto h6 = hermiteCoefficientsNorm(6).rcarray!(const double).polynomial;
68     auto h7 = hermiteCoefficientsNorm(7).rcarray!(const double).polynomial;
69     auto h8 = hermiteCoefficientsNorm(8).rcarray!(const double).polynomial;
70     auto h9 = hermiteCoefficientsNorm(9).rcarray!(const double).polynomial;
71     auto h10 = hermiteCoefficientsNorm(10).rcarray!(const double).polynomial;
72 
73     h0(3).should == 1;
74     h1(3).should == 3;
75     h2(3).should == 8;
76     h3(3).should == 18;
77     h4(3).should == 30;
78     h5(3).should == 18;
79     h6(3).should == -96;
80     h7(3).should == -396;
81     h8(3).should == -516;
82     h9(3).should == 1_620;
83     h10(3).should == 9_504;
84 }
85 
86 /// Also works with @nogc CTFE
87 version(mir_test)
88 @safe pure nothrow @nogc
89 unittest
90 {
91     import mir.ndslice.slice: sliced;
92     import mir.test: should;
93 
94     static immutable result = [-1, 0, 1];
95 
96     static immutable hc2 = hermiteCoefficientsNorm(2);
97     hc2.sliced.should == result;
98 }
99 
100 /++
101 Physicist's Hermite polynomial coefficients
102 
103 Params:
104     N = Degree of polynomial
105 
106 See_also:
107     $(LINK2 https://en.wikipedia.org/wiki/Hermite_polynomials, Hermite polynomials)
108 +/
109 @safe pure nothrow
110 long[] hermiteCoefficients(size_t N)
111 {
112     if (N == 0) {
113       return [1];  
114     } else {
115         typeof(return) output = [0, 2];
116         if (N > 1) {
117             output.length = N + 1;
118             typeof(return) h_N_minus_1 = hermiteCoefficients(0);
119             h_N_minus_1.length = N;
120 
121             foreach (size_t j; 2..(N + 1)) {
122                 h_N_minus_1[0..j] = output[0..j];
123                 output[0] = -h_N_minus_1[1];
124                 foreach (size_t i; 1..(j - 1)) {
125                     output[i] = 2 * h_N_minus_1[i - 1] - (cast(int) i + 1) * h_N_minus_1[i + 1];
126                 }
127                 foreach (size_t i; (j - 1)..(j + 1)) {
128                     output[i] = 2 * h_N_minus_1[i - 1];
129                 }
130             }
131         }
132         return output;
133     }
134 }
135 
136 ///
137 version(mir_test)
138 @safe pure nothrow
139 unittest
140 {
141     import mir.polynomial: polynomial;
142     import mir.rc.array: rcarray;
143     import mir.test: should;
144 
145     auto h0 = hermiteCoefficients(0).rcarray!(const double).polynomial;
146     auto h1 = hermiteCoefficients(1).rcarray!(const double).polynomial;
147     auto h2 = hermiteCoefficients(2).rcarray!(const double).polynomial;
148     auto h3 = hermiteCoefficients(3).rcarray!(const double).polynomial;
149     auto h4 = hermiteCoefficients(4).rcarray!(const double).polynomial;
150     auto h5 = hermiteCoefficients(5).rcarray!(const double).polynomial;
151     auto h6 = hermiteCoefficients(6).rcarray!(const double).polynomial;
152     auto h7 = hermiteCoefficients(7).rcarray!(const double).polynomial;
153     auto h8 = hermiteCoefficients(8).rcarray!(const double).polynomial;
154     auto h9 = hermiteCoefficients(9).rcarray!(const double).polynomial;
155     auto h10 = hermiteCoefficients(10).rcarray!(const double).polynomial;
156 
157     h0(3).should == 1;
158     h1(3).should == 6;
159     h2(3).should == 34;
160     h3(3).should == 180;
161     h4(3).should == 876;
162     h5(3).should == 3_816;
163     h6(3).should == 14_136;
164     h7(3).should == 39_024;
165     h8(3).should == 36_240;
166     h9(3).should == -406_944;
167     h10(3).should == -3_093_984;
168 }
169 
170 /// Also works with @nogc CTFE
171 version(mir_test)
172 @safe pure nothrow @nogc
173 unittest
174 {
175     import mir.ndslice.slice: sliced;
176     import mir.test: should;
177 
178     static immutable result = [-2, 0, 4];
179 
180     static immutable hc2 = hermiteCoefficients(2);
181     hc2.sliced.should == result;
182 }