1 /*
2 * Copyright (C) 2012 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.roots;
17
18 import com.irurueta.algebra.Complex;
19 import com.irurueta.numerical.LockedException;
20 import com.irurueta.numerical.NotAvailableException;
21 import com.irurueta.numerical.NotReadyException;
22
23 /**
24 * Class to estimate the root of a first degree polynomial along with other
25 * polynomial properties.
26 * A first degree polynomial is defined by its parameters as p(x) = a * x + b,
27 * hence the polynomial can be simply be defined by an array of length 2 [b, a].
28 */
29 @SuppressWarnings("DuplicatedCode")
30 public class FirstDegreePolynomialRootsEstimator extends PolynomialRootsEstimator {
31
32 /**
33 * Constant defining machine precision.
34 */
35 public static final double EPS = 1e-10;
36
37 /**
38 * Number of parameters valid for a first degree polynomial.
39 */
40 public static final int VALID_POLY_PARAMS_LENGTH = 2;
41
42 /**
43 * Array containing parameters of a first degree polynomial.
44 */
45 private double[] realPolyParams;
46
47 /**
48 * Empty constructor.
49 */
50 public FirstDegreePolynomialRootsEstimator() {
51 super();
52 realPolyParams = null;
53 }
54
55 /**
56 * Constructor.
57 *
58 * @param polyParams Array containing polynomial parameters.
59 * @throws IllegalArgumentException Raised if the length of the provided
60 * array is not valid.
61 */
62 public FirstDegreePolynomialRootsEstimator(final double[] polyParams) {
63 super();
64 internalSetPolynomialParameters(polyParams);
65 }
66
67 /**
68 * Set array of first degree polynomial parameters.
69 * A first degree polynomial is defined by p(x) = a * x + b, and the array
70 * must be provided as [b, a].
71 * Note: This class only supports real polynomial parameters.
72 *
73 * @param polyParams Array containing polynomial parameters.
74 * @throws LockedException Raised if this instance is locked.
75 * @throws IllegalArgumentException Raised if the length of the provided
76 * array is not valid.
77 */
78 public void setPolynomialParameters(final double[] polyParams) throws LockedException {
79 if (isLocked()) {
80 throw new LockedException();
81 }
82 internalSetPolynomialParameters(polyParams);
83 }
84
85 /**
86 * Internal method to set array of first degree polynomial parameters.
87 * A first degree polynomial is defined by p(x) = a * x + b, and the array
88 * must be provided as [b, a].
89 * Note: This class only supports real polynomial parameters.
90 * This method does not check if this instance is locked.
91 *
92 * @param polyParams Array containing polynomial parameters.
93 * @throws IllegalArgumentException Raised if the length of the provided
94 * array is not valid.
95 */
96 private void internalSetPolynomialParameters(final double[] polyParams) {
97 if (polyParams.length < VALID_POLY_PARAMS_LENGTH) {
98 throw new IllegalArgumentException();
99 }
100 if (!isFirstDegree(polyParams)) {
101 throw new IllegalArgumentException();
102 }
103
104 this.realPolyParams = polyParams;
105 }
106
107 /**
108 * Returns array of first degree polynomial parameters.
109 * A first degree polynomial is defined by p(x) = a * x + b, and the array
110 * is returned as [b, a].
111 * Note: This class only supports real polynomial parameters.
112 *
113 * @return Array of first degree polynomial parameters.
114 * @throws NotAvailableException if parameters are not available for retrieval.
115 */
116 public double[] getRealPolynomialParameters() throws NotAvailableException {
117 if (!arePolynomialParametersAvailable()) {
118 throw new NotAvailableException();
119 }
120 return realPolyParams;
121 }
122
123 /**
124 * Returns boolean indicating whether REAL polynomial parameters have been
125 * provided and is available for retrieval.
126 * Note: This class only supports real polynomial parameters.
127 *
128 * @return True if available, false otherwise.
129 */
130 @Override
131 public boolean arePolynomialParametersAvailable() {
132 return realPolyParams != null;
133 }
134
135 /**
136 * This method will always raise a NotAvailableException because this class
137 * only supports REAL polynomial parameters.
138 *
139 * @return throws NotAvailableException.
140 * @throws NotAvailableException always throws this exception.
141 */
142 @Override
143 public Complex[] getPolynomialParameters() throws NotAvailableException {
144 throw new NotAvailableException();
145 }
146
147
148 /**
149 * This method will always raise an IllegalArgumentException because this
150 * class only supports REAL polynomial parameters.
151 */
152 @Override
153 protected void internalSetPolynomialParameters(final Complex[] polyParams) {
154 // complex values are not supported
155 throw new IllegalArgumentException();
156 }
157
158 /**
159 * Estimates the root of provided polynomial.
160 *
161 * @throws LockedException Raised if this instance is locked estimating a
162 * root.
163 * @throws NotReadyException Raised if this instance is not ready because
164 * polynomial parameters have not been provided.
165 */
166 @Override
167 public void estimate() throws LockedException, NotReadyException {
168
169 if (isLocked()) {
170 throw new LockedException();
171 }
172 if (!isReady()) {
173 throw new NotReadyException();
174 }
175
176 locked = true;
177
178 roots = new Complex[VALID_POLY_PARAMS_LENGTH - 1];
179
180 final var b = realPolyParams[0];
181 final var a = realPolyParams[1];
182
183 final var x = solveLinear(a, b);
184
185 roots[0] = new Complex(x, 0.0);
186
187 locked = false;
188 }
189
190 /**
191 * Returns boolean indicating whether provided array of polynomial
192 * parameters correspond to a valid first degree polynomial.
193 * A first degree polynomial is defined by p(x) = a * x + b, and the array
194 * is returned as [b, a].
195 * Note: This class only supports real polynomial parameters
196 *
197 * @param polyParams Array containing polynomial parameters
198 * @return True if is a first degree polynomial, false otherwise
199 */
200 public static boolean isFirstDegree(final double[] polyParams) {
201 final var length = polyParams.length;
202 if (length >= VALID_POLY_PARAMS_LENGTH && Math.abs(polyParams[VALID_POLY_PARAMS_LENGTH - 1]) > EPS) {
203 for (var i = VALID_POLY_PARAMS_LENGTH; i < length; i++) {
204 if (Math.abs(polyParams[i]) > EPS) {
205 return false;
206 }
207 }
208 return true;
209 }
210 return false;
211 }
212
213 /**
214 * Returns boolean indicating whether polynomial parameters provided to this
215 * instance correspond to a valid first degree polynomial.
216 * A first degree polynomial is defined by p(x) = a * x + b, and the array
217 * is returned as [b, a].
218 * Note: This class only supports real polynomial parameters.
219 *
220 * @return True if is a first degree polynomial, false otherwise.
221 * @throws NotReadyException Raised if this instance is not ready because
222 * an array of polynomial parameters has not yet been provided.
223 */
224 public boolean isFirstDegree() throws NotReadyException {
225 if (!isReady()) {
226 throw new NotReadyException();
227 }
228 return isFirstDegree(realPolyParams);
229 }
230
231 /**
232 * Returns boolean indicating whether estimated root is real.
233 * Because this class only accepts real polynomial parameters, then the
234 * estimated root will always be real, and consequently this method always
235 * returns true.
236 *
237 * @return True if estimated root is real, false otherwise.
238 */
239 public boolean isRealSolution() {
240 return true;
241 }
242
243 /**
244 * Internal method to estimate a root on a first degree polynomial.
245 *
246 * @param a A parameter.
247 * @param b B parameter.
248 * @return Root.
249 */
250 private double solveLinear(final double a, final double b) {
251 //a * x + b = 0
252 return -b / a;
253 }
254 }