1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.fitting;
23
24 import org.hipparchus.UnitTestUtils;
25 import org.hipparchus.analysis.polynomials.PolynomialFunction;
26 import org.hipparchus.exception.MathIllegalStateException;
27 import org.hipparchus.random.RandomDataGenerator;
28 import org.hipparchus.util.FastMath;
29 import org.junit.jupiter.api.Test;
30
31 import java.util.Random;
32
33 import static org.junit.jupiter.api.Assertions.assertEquals;
34 import static org.junit.jupiter.api.Assertions.assertTrue;
35
36
37
38
39 class PolynomialCurveFitterTest {
40 @Test
41 void testFit() {
42 final RandomDataGenerator randomDataGenerator = new RandomDataGenerator(64925784252L);
43
44 final double[] coeff = { 12.9, -3.4, 2.1 };
45 final PolynomialFunction f = new PolynomialFunction(coeff);
46
47
48 final WeightedObservedPoints obs = new WeightedObservedPoints();
49 for (int i = 0; i < 100; i++) {
50 final double x = randomDataGenerator.nextUniform(-100, 100);
51 obs.add(x, f.value(x));
52 }
53
54
55 final PolynomialCurveFitter fitter
56 = PolynomialCurveFitter.create(0).withStartPoint(new double[] { -1e-20, 3e15, -5e25 });
57 final double[] best = fitter.fit(obs.toList());
58
59 UnitTestUtils.customAssertEquals("best != coeff", coeff, best, 1e-12);
60 }
61
62 @Test
63 void testNoError() {
64 final Random randomizer = new Random(64925784252l);
65 for (int degree = 1; degree < 10; ++degree) {
66 final PolynomialFunction p = buildRandomPolynomial(degree, randomizer);
67 final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(degree);
68
69 final WeightedObservedPoints obs = new WeightedObservedPoints();
70 for (int i = 0; i <= degree; ++i) {
71 obs.add(1.0, i, p.value(i));
72 }
73
74 final PolynomialFunction fitted = new PolynomialFunction(fitter.fit(obs.toList()));
75
76 for (double x = -1.0; x < 1.0; x += 0.01) {
77 final double error = FastMath.abs(p.value(x) - fitted.value(x)) /
78 (1.0 + FastMath.abs(p.value(x)));
79 assertEquals(0.0, error, 1.0e-6);
80 }
81 }
82 }
83
84 @Test
85 void testSmallError() {
86 final Random randomizer = new Random(53882150042l);
87 double maxError = 0;
88 for (int degree = 0; degree < 10; ++degree) {
89 final PolynomialFunction p = buildRandomPolynomial(degree, randomizer);
90 final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(degree);
91
92 final WeightedObservedPoints obs = new WeightedObservedPoints();
93 for (double x = -1.0; x < 1.0; x += 0.01) {
94 obs.add(1.0, x, p.value(x) + 0.1 * randomizer.nextGaussian());
95 }
96
97 final PolynomialFunction fitted = new PolynomialFunction(fitter.fit(obs.toList()));
98
99 for (double x = -1.0; x < 1.0; x += 0.01) {
100 final double error = FastMath.abs(p.value(x) - fitted.value(x)) /
101 (1.0 + FastMath.abs(p.value(x)));
102 maxError = FastMath.max(maxError, error);
103 assertTrue(FastMath.abs(error) < 0.1);
104 }
105 }
106 assertTrue(maxError > 0.01);
107 }
108
109 @Test
110 void testRedundantSolvable() {
111
112 checkUnsolvableProblem(true);
113 }
114
115 @Test
116 void testLargeSample() {
117 final Random randomizer = new Random(0x5551480dca5b369bl);
118 double maxError = 0;
119 for (int degree = 0; degree < 10; ++degree) {
120 final PolynomialFunction p = buildRandomPolynomial(degree, randomizer);
121 final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(degree);
122
123 final WeightedObservedPoints obs = new WeightedObservedPoints();
124 for (int i = 0; i < 40000; ++i) {
125 final double x = -1.0 + i / 20000.0;
126 obs.add(1.0, x, p.value(x) + 0.1 * randomizer.nextGaussian());
127 }
128
129 final PolynomialFunction fitted = new PolynomialFunction(fitter.fit(obs.toList()));
130 for (double x = -1.0; x < 1.0; x += 0.01) {
131 final double error = FastMath.abs(p.value(x) - fitted.value(x)) /
132 (1.0 + FastMath.abs(p.value(x)));
133 maxError = FastMath.max(maxError, error);
134 assertTrue(FastMath.abs(error) < 0.01);
135 }
136 }
137 assertTrue(maxError > 0.001);
138 }
139
140 private void checkUnsolvableProblem(boolean solvable) {
141 final Random randomizer = new Random(1248788532l);
142
143 for (int degree = 0; degree < 10; ++degree) {
144 final PolynomialFunction p = buildRandomPolynomial(degree, randomizer);
145 final PolynomialCurveFitter fitter = PolynomialCurveFitter.create(degree);
146 final WeightedObservedPoints obs = new WeightedObservedPoints();
147
148
149
150
151 for (double x = -1.0; x < 1.0; x += 0.01) {
152 obs.add(1.0, 0.0, p.value(0.0));
153 }
154
155 try {
156 fitter.fit(obs.toList());
157 assertTrue(solvable || (degree == 0));
158 } catch(MathIllegalStateException e) {
159 assertTrue((! solvable) && (degree > 0));
160 }
161 }
162 }
163
164 private PolynomialFunction buildRandomPolynomial(int degree, Random randomizer) {
165 final double[] coefficients = new double[degree + 1];
166 for (int i = 0; i <= degree; ++i) {
167 coefficients[i] = randomizer.nextGaussian();
168 }
169 return new PolynomialFunction(coefficients);
170 }
171 }