1 /*
2 * Copyright (C) 2016 Alberto Irurueta Carro (alberto@irurueta.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package com.irurueta.numerical.polynomials.estimators;
17
18 import com.irurueta.algebra.AlgebraException;
19 import com.irurueta.algebra.Matrix;
20 import com.irurueta.algebra.Utils;
21 import com.irurueta.numerical.LockedException;
22 import com.irurueta.numerical.NotReadyException;
23 import com.irurueta.numerical.polynomials.Polynomial;
24
25 import java.util.List;
26
27 /**
28 * This class defines an LMSE (Least Mean Square Error) estimator of a
29 * polynomial of a given degree using points where polynomials (or its
30 * derivatives or integrals) are evaluated.
31 */
32 public class LMSEPolynomialEstimator extends PolynomialEstimator {
33
34 /**
35 * Indicates if by default an LMSE (Least Mean Square Error) solution is
36 * allowed if more evaluations than the required minimum are provided.
37 */
38 public static final boolean DEFAULT_ALLOW_LMSE_SOLUTION = false;
39
40 /**
41 * Indicates if an LMSE (Least Mean Square Error) solution is allowed if
42 * more evaluations than the required minimum are provided. If false, the
43 * exceeding evaluations are ignored, and only the first minimum required
44 * are used.
45 */
46 private boolean allowLMSESolution;
47
48 /**
49 * Constructor.
50 */
51 public LMSEPolynomialEstimator() {
52 super();
53 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
54 }
55
56 /**
57 * Constructor.
58 *
59 * @param degree degree of polynomial to be estimated.
60 * @throws IllegalArgumentException if provided degree is less than 1.
61 */
62 public LMSEPolynomialEstimator(final int degree) {
63 super(degree);
64 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
65 }
66
67 /**
68 * Constructor.
69 *
70 * @param evaluations collection of polynomial evaluations.
71 */
72 public LMSEPolynomialEstimator(final List<PolynomialEvaluation> evaluations) {
73 super(evaluations);
74 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
75 }
76
77 /**
78 * Constructor.
79 *
80 * @param listener listener to be notified of events.
81 */
82 public LMSEPolynomialEstimator(final PolynomialEstimatorListener listener) {
83 super(listener);
84 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
85 }
86
87 /**
88 * Constructor.
89 *
90 * @param degree degree of polynomial to be estimated.
91 * @param evaluations collection of polynomial evaluations.
92 * @throws IllegalArgumentException if provided degree is less than 1.
93 */
94 public LMSEPolynomialEstimator(final int degree, final List<PolynomialEvaluation> evaluations) {
95 super(degree, evaluations);
96 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
97 }
98
99 /**
100 * Constructor.
101 *
102 * @param degree degree of polynomial to be estimated.
103 * @param listener listener to be notified of events.
104 * @throws IllegalArgumentException if provided degree is less than 1.
105 */
106 public LMSEPolynomialEstimator(final int degree, final PolynomialEstimatorListener listener) {
107 super(degree, listener);
108 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
109 }
110
111 /**
112 * Constructor.
113 *
114 * @param evaluations collection of polynomial evaluations.
115 * @param listener listener to be notified of events.
116 */
117 public LMSEPolynomialEstimator(
118 final List<PolynomialEvaluation> evaluations, final PolynomialEstimatorListener listener) {
119 super(evaluations, listener);
120 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
121 }
122
123 /**
124 * Constructor.
125 *
126 * @param degree degree of polynomial to be estimated.
127 * @param evaluations collection of polynomial evaluations.
128 * @param listener listener to be notified of events.
129 * @throws IllegalArgumentException if provided degree is less than 1.
130 */
131 public LMSEPolynomialEstimator(
132 final int degree, final List<PolynomialEvaluation> evaluations,
133 final PolynomialEstimatorListener listener) {
134 super(degree, evaluations, listener);
135 allowLMSESolution = DEFAULT_ALLOW_LMSE_SOLUTION;
136 }
137
138 /**
139 * Indicates if an LMSE (Least Mean Square Error) solution is allowed if
140 * more evaluations than the required minimum are provided. If false, the
141 * exceeding evaluations are ignored, and only the first minimum required
142 * are used.
143 *
144 * @return true if LMSE solution is allowed, false otherwise.
145 */
146 public boolean isLMSESolutionAllowed() {
147 return allowLMSESolution;
148 }
149
150 /**
151 * Specified if an LMSE (Least Mean Square Error) solution is allowed if
152 * more evaluations than the required minimum are provided. If false, the
153 * exceeding evaluations are ignored, and only the first minimum required
154 * are used.
155 *
156 * @param allowed true if LMSE solution is allowed, false otherwise.
157 * @throws LockedException if estimator is locked.
158 */
159 public void setLMSESolutionAllowed(final boolean allowed) throws LockedException {
160 if (isLocked()) {
161 throw new LockedException();
162 }
163 allowLMSESolution = allowed;
164 }
165
166 /**
167 * Estimates a polynomial based on provided evaluations.
168 *
169 * @return estimated polynomial.
170 * @throws LockedException if estimator is locked.
171 * @throws NotReadyException if estimator is not ready.
172 * @throws PolynomialEstimationException if polynomial estimation fails.
173 */
174 @SuppressWarnings("DuplicatedCode")
175 @Override
176 public Polynomial estimate() throws LockedException, NotReadyException, PolynomialEstimationException {
177 if (isLocked()) {
178 throw new LockedException();
179 }
180 if (!isReady()) {
181 throw new NotReadyException();
182 }
183
184 try {
185 locked = true;
186 if (listener != null) {
187 listener.onEstimateStart(this);
188 }
189
190 final var minNumberOfEvaluations = getMinNumberOfEvaluations();
191
192 final var a = new Matrix(evaluations.size(), degree + 1);
193 final var b = new Matrix(evaluations.size(), 1);
194
195 var counter = 0;
196 for (var evaluation : evaluations) {
197 switch (evaluation.getType()) {
198 case DIRECT_EVALUATION:
199 fillDirectEvaluation((DirectPolynomialEvaluation) evaluation, a, b, counter);
200 break;
201 case DERIVATIVE_EVALUATION:
202 fillDerivativeEvaluation((DerivativePolynomialEvaluation) evaluation, a, b, counter);
203 break;
204 case INTEGRAL_EVALUATION:
205 fillIntegralEvaluation((IntegralPolynomialEvaluation) evaluation, a, b, counter);
206 break;
207 case INTEGRAL_INTERVAL:
208 fillIntegralIntervalEvaluation((IntegralIntervalPolynomialEvaluation) evaluation, a, b,
209 counter);
210 break;
211 default:
212 continue;
213 }
214
215 normalize(a, b, counter);
216 counter++;
217
218 if (!isLMSESolutionAllowed() && counter >= minNumberOfEvaluations) {
219 break;
220 }
221 }
222
223 final var params = Utils.solve(a, b);
224
225 final var result = new Polynomial(params.toArray());
226
227 if (listener != null) {
228 listener.onEstimateEnd(this);
229 }
230
231 return result;
232 } catch (final AlgebraException e) {
233 throw new PolynomialEstimationException(e);
234 } finally {
235 locked = false;
236 }
237 }
238
239 /**
240 * Returns type of polynomial estimator.
241 *
242 * @return type of polynomial estimator.
243 */
244 @Override
245 public PolynomialEstimatorType getType() {
246 return PolynomialEstimatorType.LMSE_POLYNOMIAL_ESTIMATOR;
247 }
248 }