1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.analysis.polynomials;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.commons.numbers.fraction.BigFraction;
25 import org.apache.commons.numbers.combinatorics.BinomialCoefficient;
26 import org.apache.commons.math4.core.jdkmath.JdkMath;
27
28
29
30
31
32
33 public final class PolynomialsUtils {
34
35 private static final BigFraction BF_MINUS_ONE = BigFraction.of(-1);
36
37 private static final BigFraction BF_TWO = BigFraction.of(2);
38
39
40 private static final List<BigFraction> CHEBYSHEV_COEFFICIENTS;
41
42
43 private static final List<BigFraction> HERMITE_COEFFICIENTS;
44
45
46 private static final List<BigFraction> LAGUERRE_COEFFICIENTS;
47
48
49 private static final List<BigFraction> LEGENDRE_COEFFICIENTS;
50
51
52 private static final Map<JacobiKey, List<BigFraction>> JACOBI_COEFFICIENTS;
53
54 static {
55
56
57
58 CHEBYSHEV_COEFFICIENTS = new ArrayList<>();
59 CHEBYSHEV_COEFFICIENTS.add(BigFraction.ONE);
60 CHEBYSHEV_COEFFICIENTS.add(BigFraction.ZERO);
61 CHEBYSHEV_COEFFICIENTS.add(BigFraction.ONE);
62
63
64
65 HERMITE_COEFFICIENTS = new ArrayList<>();
66 HERMITE_COEFFICIENTS.add(BigFraction.ONE);
67 HERMITE_COEFFICIENTS.add(BigFraction.ZERO);
68 HERMITE_COEFFICIENTS.add(BF_TWO);
69
70
71
72 LAGUERRE_COEFFICIENTS = new ArrayList<>();
73 LAGUERRE_COEFFICIENTS.add(BigFraction.ONE);
74 LAGUERRE_COEFFICIENTS.add(BigFraction.ONE);
75 LAGUERRE_COEFFICIENTS.add(BF_MINUS_ONE);
76
77
78
79 LEGENDRE_COEFFICIENTS = new ArrayList<>();
80 LEGENDRE_COEFFICIENTS.add(BigFraction.ONE);
81 LEGENDRE_COEFFICIENTS.add(BigFraction.ZERO);
82 LEGENDRE_COEFFICIENTS.add(BigFraction.ONE);
83
84
85 JACOBI_COEFFICIENTS = new HashMap<>();
86 }
87
88
89
90
91 private PolynomialsUtils() {
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public static PolynomialFunction createChebyshevPolynomial(final int degree) {
109 return buildPolynomial(degree, CHEBYSHEV_COEFFICIENTS,
110 new RecurrenceCoefficientsGenerator() {
111
112 private final BigFraction[] coeffs = { BigFraction.ZERO, BF_TWO, BigFraction.ONE };
113
114 @Override
115 public BigFraction[] generate(int k) {
116 return coeffs;
117 }
118 });
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 public static PolynomialFunction createHermitePolynomial(final int degree) {
137 return buildPolynomial(degree, HERMITE_COEFFICIENTS,
138 new RecurrenceCoefficientsGenerator() {
139
140 @Override
141 public BigFraction[] generate(int k) {
142 return new BigFraction[] {
143 BigFraction.ZERO,
144 BF_TWO,
145 BigFraction.of(2 * k)};
146 }
147 });
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 public static PolynomialFunction createLaguerrePolynomial(final int degree) {
165 return buildPolynomial(degree, LAGUERRE_COEFFICIENTS,
166 new RecurrenceCoefficientsGenerator() {
167
168 @Override
169 public BigFraction[] generate(int k) {
170 final int kP1 = k + 1;
171 return new BigFraction[] {
172 BigFraction.of(2 * k + 1, kP1),
173 BigFraction.of(-1, kP1),
174 BigFraction.of(k, kP1)};
175 }
176 });
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 public static PolynomialFunction createLegendrePolynomial(final int degree) {
194 return buildPolynomial(degree, LEGENDRE_COEFFICIENTS,
195 new RecurrenceCoefficientsGenerator() {
196
197 @Override
198 public BigFraction[] generate(int k) {
199 final int kP1 = k + 1;
200 return new BigFraction[] {
201 BigFraction.ZERO,
202 BigFraction.of(k + kP1, kP1),
203 BigFraction.of(k, kP1)};
204 }
205 });
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226 public static PolynomialFunction createJacobiPolynomial(final int degree, final int v, final int w) {
227
228
229 final JacobiKey key = new JacobiKey(v, w);
230
231 if (!JACOBI_COEFFICIENTS.containsKey(key)) {
232
233
234 final List<BigFraction> list = new ArrayList<>();
235 JACOBI_COEFFICIENTS.put(key, list);
236
237
238 list.add(BigFraction.ONE);
239
240
241 list.add(BigFraction.of(v - w, 2));
242 list.add(BigFraction.of(2 + v + w, 2));
243 }
244
245 return buildPolynomial(degree, JACOBI_COEFFICIENTS.get(key),
246 new RecurrenceCoefficientsGenerator() {
247
248 @Override
249 public BigFraction[] generate(int k) {
250 k++;
251 final int kvw = k + v + w;
252 final int twoKvw = kvw + k;
253 final int twoKvwM1 = twoKvw - 1;
254 final int twoKvwM2 = twoKvw - 2;
255 final int den = 2 * k * kvw * twoKvwM2;
256
257 return new BigFraction[] {
258 BigFraction.of(twoKvwM1 * (v * v - w * w), den),
259 BigFraction.of(twoKvwM1 * twoKvw * twoKvwM2, den),
260 BigFraction.of(2 * (k + v - 1) * (k + w - 1) * twoKvw, den)
261 };
262 }
263 });
264 }
265
266
267 private static final class JacobiKey {
268
269
270 private final int v;
271
272
273 private final int w;
274
275
276
277
278
279 JacobiKey(final int v, final int w) {
280 this.v = v;
281 this.w = w;
282 }
283
284
285
286
287 @Override
288 public int hashCode() {
289 return (v << 16) ^ w;
290 }
291
292
293
294
295
296 @Override
297 public boolean equals(final Object key) {
298
299 if (!(key instanceof JacobiKey)) {
300 return false;
301 }
302
303 final JacobiKey otherK = (JacobiKey) key;
304 return v == otherK.v && w == otherK.w;
305 }
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 public static double[] shift(final double[] coefficients,
326 final double shift) {
327 final int dp1 = coefficients.length;
328 final double[] newCoefficients = new double[dp1];
329
330
331 final int[][] coeff = new int[dp1][dp1];
332 for (int i = 0; i < dp1; i++){
333 for(int j = 0; j <= i; j++){
334 coeff[i][j] = (int) BinomialCoefficient.value(i, j);
335 }
336 }
337
338
339 for (int i = 0; i < dp1; i++){
340 newCoefficients[0] += coefficients[i] * JdkMath.pow(shift, i);
341 }
342
343
344 final int d = dp1 - 1;
345 for (int i = 0; i < d; i++) {
346 for (int j = i; j < d; j++){
347 newCoefficients[i + 1] += coeff[j + 1][j - i] *
348 coefficients[j + 1] * JdkMath.pow(shift, j - i);
349 }
350 }
351
352 return newCoefficients;
353 }
354
355
356
357
358
359
360
361
362 private static PolynomialFunction buildPolynomial(final int degree,
363 final List<BigFraction> coefficients,
364 final RecurrenceCoefficientsGenerator generator) {
365
366
367
368 synchronized (coefficients) {
369 final int maxDegree = (int) JdkMath.floor(JdkMath.sqrt(2.0 * coefficients.size())) - 1;
370 if (degree > maxDegree) {
371 computeUpToDegree(degree, maxDegree, generator, coefficients);
372 }
373 }
374
375
376
377
378
379
380
381
382
383 final int start = degree * (degree + 1) / 2;
384
385 final double[] a = new double[degree + 1];
386 for (int i = 0; i <= degree; ++i) {
387 a[i] = coefficients.get(start + i).doubleValue();
388 }
389
390
391 return new PolynomialFunction(a);
392 }
393
394
395
396
397
398
399
400 private static void computeUpToDegree(final int degree, final int maxDegree,
401 final RecurrenceCoefficientsGenerator generator,
402 final List<BigFraction> coefficients) {
403
404 int startK = (maxDegree - 1) * maxDegree / 2;
405 for (int k = maxDegree; k < degree; ++k) {
406
407
408 int startKm1 = startK;
409 startK += k;
410
411
412 BigFraction[] ai = generator.generate(k);
413
414 BigFraction ck = coefficients.get(startK);
415 BigFraction ckm1 = coefficients.get(startKm1);
416
417
418 coefficients.add(ck.multiply(ai[0]).subtract(ckm1.multiply(ai[2])));
419
420
421 for (int i = 1; i < k; ++i) {
422 final BigFraction ckPrev = ck;
423 ck = coefficients.get(startK + i);
424 ckm1 = coefficients.get(startKm1 + i);
425 coefficients.add(ck.multiply(ai[0]).add(ckPrev.multiply(ai[1])).subtract(ckm1.multiply(ai[2])));
426 }
427
428
429 final BigFraction ckPrev = ck;
430 ck = coefficients.get(startK + k);
431 coefficients.add(ck.multiply(ai[0]).add(ckPrev.multiply(ai[1])));
432
433
434 coefficients.add(ck.multiply(ai[1]));
435 }
436 }
437
438
439 private interface RecurrenceCoefficientsGenerator {
440
441
442
443
444
445
446 BigFraction[] generate(int k);
447 }
448 }