1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.numerical.polynomials.estimators;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.numerical.LockedException;
20 import com.irurueta.numerical.NotReadyException;
21 import com.irurueta.numerical.polynomials.Polynomial;
22
23 import java.util.Arrays;
24 import java.util.List;
25
26
27
28
29
30 @SuppressWarnings("Duplicates")
31 public abstract class PolynomialEstimator {
32
33
34
35
36 public static final int MIN_DEGREE = 1;
37
38
39
40
41 public static final PolynomialEstimatorType DEFAULT_ESTIMATOR_TYPE =
42 PolynomialEstimatorType.LMSE_POLYNOMIAL_ESTIMATOR;
43
44
45
46
47 protected int degree;
48
49
50
51
52
53 protected List<PolynomialEvaluation> evaluations;
54
55
56
57
58 protected boolean locked;
59
60
61
62
63
64 protected PolynomialEstimatorListener listener;
65
66
67
68
69 protected PolynomialEstimator() {
70 degree = MIN_DEGREE;
71 }
72
73
74
75
76
77
78
79 protected PolynomialEstimator(final int degree) {
80 internalSetDegree(degree);
81 }
82
83
84
85
86
87
88 protected PolynomialEstimator(final List<PolynomialEvaluation> evaluations) {
89 this();
90 this.evaluations = evaluations;
91 }
92
93
94
95
96
97
98 protected PolynomialEstimator(final PolynomialEstimatorListener listener) {
99 this();
100 this.listener = listener;
101 }
102
103
104
105
106
107
108
109
110 protected PolynomialEstimator(final int degree, final List<PolynomialEvaluation> evaluations) {
111 this(degree);
112 this.evaluations = evaluations;
113 }
114
115
116
117
118
119
120
121
122 protected PolynomialEstimator(final int degree, final PolynomialEstimatorListener listener) {
123 this(degree);
124 this.listener = listener;
125 }
126
127
128
129
130
131
132
133 protected PolynomialEstimator(
134 final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener) {
135 this(evaluations);
136 this.listener = listener;
137 }
138
139
140
141
142
143
144
145
146
147 protected PolynomialEstimator(
148 final int degree, final List<PolynomialEvaluation> evaluations,
149 final PolynomialEstimatorListener listener) {
150 this(degree, evaluations);
151 this.listener = listener;
152 }
153
154
155
156
157
158
159 public int getDegree() {
160 return degree;
161 }
162
163
164
165
166
167
168
169
170 public void setDegree(final int degree) throws LockedException {
171 if (isLocked()) {
172 throw new LockedException();
173 }
174
175 internalSetDegree(degree);
176 }
177
178
179
180
181
182
183
184 public List<PolynomialEvaluation> getEvaluations() {
185 return evaluations;
186 }
187
188
189
190
191
192
193
194
195 public void setEvaluations(final List<PolynomialEvaluation> evaluations) throws LockedException {
196 if (isLocked()) {
197 throw new LockedException();
198 }
199
200 this.evaluations = evaluations;
201 }
202
203
204
205
206
207
208
209
210
211
212
213 public void setDegreeAndEvaluations(
214 final int degree, final List<PolynomialEvaluation> evaluations) throws LockedException {
215 setDegree(degree);
216 setEvaluations(evaluations);
217 }
218
219
220
221
222
223
224
225 public boolean isReady() {
226
227 final var nParams = degree + 1;
228 if (evaluations == null || evaluations.size() < nParams) {
229 return false;
230 }
231
232
233 var count = 0;
234 for (final var eval : evaluations) {
235 if (eval.getType() == PolynomialEvaluationType.DIRECT_EVALUATION
236 || eval.getType() == PolynomialEvaluationType.INTEGRAL_EVALUATION
237 || eval.getType() == PolynomialEvaluationType.INTEGRAL_INTERVAL) {
238 count++;
239 }
240 }
241
242 return count >= 1 && evaluations.size() >= nParams;
243 }
244
245
246
247
248
249
250
251
252
253 public static int getMinNumberOfEvaluations(final int degree) {
254 if (degree < MIN_DEGREE) {
255 throw new IllegalArgumentException();
256 }
257
258 return degree + 1;
259 }
260
261
262
263
264
265
266
267 public int getMinNumberOfEvaluations() {
268 return getMinNumberOfEvaluations(degree);
269 }
270
271
272
273
274
275
276
277 public boolean isLocked() {
278 return locked;
279 }
280
281
282
283
284
285
286
287 public PolynomialEstimatorListener getListener() {
288 return listener;
289 }
290
291
292
293
294
295
296
297
298 public void setListener(final PolynomialEstimatorListener listener) throws LockedException {
299 if (isLocked()) {
300 throw new LockedException();
301 }
302
303 this.listener = listener;
304 }
305
306
307
308
309
310
311
312
313
314 public abstract Polynomial estimate() throws LockedException, NotReadyException, PolynomialEstimationException;
315
316
317
318
319
320
321 public abstract PolynomialEstimatorType getType();
322
323
324
325
326
327
328
329 public static PolynomialEstimator create() {
330 return create(DEFAULT_ESTIMATOR_TYPE);
331 }
332
333
334
335
336
337
338
339
340
341 public static PolynomialEstimator create(final int degree) {
342 return create(degree, DEFAULT_ESTIMATOR_TYPE);
343 }
344
345
346
347
348
349
350
351
352 public static PolynomialEstimator create(final List<PolynomialEvaluation> evaluations) {
353 return create(evaluations, DEFAULT_ESTIMATOR_TYPE);
354 }
355
356
357
358
359
360
361
362
363 public static PolynomialEstimator create(final PolynomialEstimatorListener listener) {
364 return create(listener, DEFAULT_ESTIMATOR_TYPE);
365 }
366
367
368
369
370
371
372
373
374
375
376 public static PolynomialEstimator create(final int degree, final List<PolynomialEvaluation> evaluations) {
377 return create(degree, evaluations, DEFAULT_ESTIMATOR_TYPE);
378 }
379
380
381
382
383
384
385
386
387
388
389 public static PolynomialEstimator create(final int degree, final PolynomialEstimatorListener listener) {
390 return create(degree, listener, DEFAULT_ESTIMATOR_TYPE);
391 }
392
393
394
395
396
397
398
399
400
401 public static PolynomialEstimator create(
402 final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener) {
403 return create(evaluations, listener, DEFAULT_ESTIMATOR_TYPE);
404 }
405
406
407
408
409
410
411
412
413
414
415
416 public static PolynomialEstimator create(
417 final int degree, final List<PolynomialEvaluation> evaluations,
418 final PolynomialEstimatorListener listener) {
419 return create(degree, evaluations, listener, DEFAULT_ESTIMATOR_TYPE);
420 }
421
422
423
424
425
426
427
428
429 public static PolynomialEstimator create(final PolynomialEstimatorType type) {
430 if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
431 return new WeightedPolynomialEstimator();
432 } else {
433 return new LMSEPolynomialEstimator();
434 }
435 }
436
437
438
439
440
441
442
443
444
445
446 public static PolynomialEstimator create(final int degree, final PolynomialEstimatorType type) {
447 if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
448 return new WeightedPolynomialEstimator(degree);
449 } else {
450 return new LMSEPolynomialEstimator(degree);
451 }
452 }
453
454
455
456
457
458
459
460
461
462 public static PolynomialEstimator create(
463 final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorType type) {
464 switch (type) {
465 case WEIGHTED_POLYNOMIAL_ESTIMATOR:
466 final var weights = new double[evaluations.size()];
467 Arrays.fill(weights, 1.0);
468 return new WeightedPolynomialEstimator(evaluations, weights);
469 case LMSE_POLYNOMIAL_ESTIMATOR:
470 default:
471 return new LMSEPolynomialEstimator(evaluations);
472 }
473 }
474
475
476
477
478
479
480
481
482
483 public static PolynomialEstimator create(
484 final PolynomialEstimatorListener listener, final PolynomialEstimatorType type) {
485 if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
486 return new WeightedPolynomialEstimator(listener);
487 } else {
488 return new LMSEPolynomialEstimator(listener);
489 }
490 }
491
492
493
494
495
496
497
498
499
500
501
502 public static PolynomialEstimator create(
503 final int degree, final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorType type) {
504 switch (type) {
505 case WEIGHTED_POLYNOMIAL_ESTIMATOR:
506 final var weights = new double[evaluations.size()];
507 Arrays.fill(weights, 1.0);
508 return new WeightedPolynomialEstimator(degree, evaluations, weights);
509 case LMSE_POLYNOMIAL_ESTIMATOR:
510 default:
511 return new LMSEPolynomialEstimator(degree, evaluations);
512 }
513 }
514
515
516
517
518
519
520
521
522
523
524
525 public static PolynomialEstimator create(
526 final int degree, final PolynomialEstimatorListener listener, final PolynomialEstimatorType type) {
527 if (type == PolynomialEstimatorType.WEIGHTED_POLYNOMIAL_ESTIMATOR) {
528 return new WeightedPolynomialEstimator(degree, listener);
529 } else {
530 return new LMSEPolynomialEstimator(degree, listener);
531 }
532 }
533
534
535
536
537
538
539
540
541
542
543 public static PolynomialEstimator create(
544 final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener,
545 final PolynomialEstimatorType type) {
546 switch (type) {
547 case WEIGHTED_POLYNOMIAL_ESTIMATOR:
548 final var weights = new double[evaluations.size()];
549 Arrays.fill(weights, 1.0);
550 return new WeightedPolynomialEstimator(evaluations, weights, listener);
551 case LMSE_POLYNOMIAL_ESTIMATOR:
552 default:
553 return new LMSEPolynomialEstimator(evaluations, listener);
554 }
555 }
556
557
558
559
560
561
562
563
564
565
566
567
568 public static PolynomialEstimator create(
569 final int degree, final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener,
570 final PolynomialEstimatorType type) {
571 switch (type) {
572 case WEIGHTED_POLYNOMIAL_ESTIMATOR:
573 final var weights = new double[evaluations.size()];
574 Arrays.fill(weights, 1.0);
575 return new WeightedPolynomialEstimator(degree, evaluations, weights, listener);
576 case LMSE_POLYNOMIAL_ESTIMATOR:
577 default:
578 return new LMSEPolynomialEstimator(degree, evaluations, listener);
579 }
580 }
581
582
583
584
585
586
587
588
589
590 protected void fillDirectEvaluation(
591 final DirectPolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row) {
592
593 var powX = 1.0;
594 final var x = evaluation.getX();
595 for (var i = 0; i < a.getColumns(); i++) {
596 a.setElementAt(row, i, powX);
597 powX *= x;
598 }
599
600 b.setElementAtIndex(row, evaluation.getEvaluation());
601 }
602
603
604
605
606
607
608
609
610
611 protected void fillDerivativeEvaluation(
612 final DerivativePolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row) {
613
614 final var order = evaluation.getDerivativeOrder();
615
616 for (var i = 0; i < order; i++) {
617 a.setElementAt(row, i, 0.0);
618 }
619
620 var powX = 1.0;
621 final var x = evaluation.getX();
622 for (var i = order; i < a.getColumns(); i++) {
623 var param = i;
624 for (var j = 1; j < order; j++) {
625 param *= i - j;
626 }
627 a.setElementAt(row, i, param * powX);
628 powX *= x;
629 }
630
631 b.setElementAtIndex(row, evaluation.getEvaluation());
632 }
633
634
635
636
637
638
639
640
641
642
643
644 protected void fillIntegralEvaluation(
645 final IntegralPolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row)
646 throws PolynomialEstimationException {
647
648 final var order = evaluation.getIntegralOrder();
649 final var constants = evaluation.getConstants();
650 if (constants != null && constants.length != order) {
651 throw new PolynomialEstimationException();
652 }
653
654 var accum = 0.0;
655 var powX = 1.0;
656 final var x = evaluation.getX();
657 for (var i = 0; i < order; i++) {
658 if (constants != null) {
659 var param = 1;
660 for (var k = 1; k <= i; k++) {
661 param *= k;
662 }
663 accum += constants[i] / param * powX;
664 }
665 powX *= x;
666 }
667
668 for (int i = 0, j = order; i < a.getColumns(); i++, j++) {
669 var param = j;
670 for (var k = 1; k < order; k++) {
671 param *= j - k;
672 }
673 a.setElementAt(row, i, powX / param);
674 powX *= x;
675 }
676
677 b.setElementAtIndex(row, evaluation.getEvaluation() - accum);
678 }
679
680
681
682
683
684
685
686
687
688
689
690
691 protected void fillIntegralIntervalEvaluation(
692 final IntegralIntervalPolynomialEvaluation evaluation, final Matrix a, final Matrix b, final int row)
693 throws PolynomialEstimationException {
694
695 final var order = evaluation.getIntegralOrder();
696 final var constants = evaluation.getConstants();
697 if (constants != null && constants.length != order) {
698 throw new PolynomialEstimationException();
699 }
700
701 var accum = 0.0;
702 var powStartX = 1.0;
703 var powEndX = 1.0;
704 final var startX = evaluation.getStartX();
705 final var endX = evaluation.getEndX();
706 for (var i = 0; i < order; i++) {
707 if (constants != null) {
708 var param = 1;
709 for (var k = 1; k <= i; k++) {
710 param *= k;
711 }
712 accum += constants[i] / param * (powEndX - powStartX);
713 }
714 powStartX *= startX;
715 powEndX *= endX;
716 }
717
718 for (int i = 0, j = order; i < a.getColumns(); i++, j++) {
719 var param = j;
720 for (var k = 1; k < order; k++) {
721 param *= j - k;
722 }
723 a.setElementAt(row, i, (powEndX - powStartX) / param);
724 powStartX *= startX;
725 powEndX *= endX;
726 }
727
728 b.setElementAtIndex(row, evaluation.getEvaluation() - accum);
729 }
730
731
732
733
734
735
736
737
738
739 protected void normalize(final Matrix a, final Matrix b, final int row) {
740 var sqrNorm = 0.0;
741 for (var i = 0; i < a.getColumns(); i++) {
742 sqrNorm += Math.pow(a.getElementAt(row, i), 2.0);
743 }
744 sqrNorm += Math.pow(b.getElementAtIndex(row), 2.0);
745
746 final var norm = Math.sqrt(sqrNorm);
747
748 for (var i = 0; i < a.getColumns(); i++) {
749 a.setElementAt(row, i, a.getElementAt(row, i) / norm);
750 }
751 b.setElementAtIndex(row, b.getElementAtIndex(row) / norm);
752 }
753
754
755
756
757
758
759
760 private void internalSetDegree(final int degree) {
761 if (degree < MIN_DEGREE) {
762 throw new IllegalArgumentException("degree must be at least 1");
763 }
764 this.degree = degree;
765 }
766 }