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.analysis.solvers;
23
24 import org.hipparchus.analysis.polynomials.PolynomialFunction;
25 import org.hipparchus.complex.Complex;
26 import org.hipparchus.complex.ComplexUtils;
27 import org.hipparchus.exception.LocalizedCoreFormats;
28 import org.hipparchus.exception.MathIllegalArgumentException;
29 import org.hipparchus.exception.MathIllegalStateException;
30 import org.hipparchus.exception.NullArgumentException;
31 import org.hipparchus.util.FastMath;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class LaguerreSolver extends AbstractPolynomialSolver {
47
48 private static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6;
49
50 private final ComplexSolver complexSolver = new ComplexSolver();
51
52
53
54
55 public LaguerreSolver() {
56 this(DEFAULT_ABSOLUTE_ACCURACY);
57 }
58
59
60
61
62
63 public LaguerreSolver(double absoluteAccuracy) {
64 super(absoluteAccuracy);
65 }
66
67
68
69
70
71
72 public LaguerreSolver(double relativeAccuracy,
73 double absoluteAccuracy) {
74 super(relativeAccuracy, absoluteAccuracy);
75 }
76
77
78
79
80
81
82
83 public LaguerreSolver(double relativeAccuracy,
84 double absoluteAccuracy,
85 double functionValueAccuracy) {
86 super(relativeAccuracy, absoluteAccuracy, functionValueAccuracy);
87 }
88
89
90
91
92 @Override
93 public double doSolve()
94 throws MathIllegalArgumentException, MathIllegalStateException {
95 final double min = getMin();
96 final double max = getMax();
97 final double initial = getStartValue();
98 final double functionValueAccuracy = getFunctionValueAccuracy();
99
100 verifySequence(min, initial, max);
101
102
103 final double yInitial = computeObjectiveValue(initial);
104 if (FastMath.abs(yInitial) <= functionValueAccuracy) {
105 return initial;
106 }
107
108
109 final double yMin = computeObjectiveValue(min);
110 if (FastMath.abs(yMin) <= functionValueAccuracy) {
111 return min;
112 }
113
114
115 if (yInitial * yMin < 0) {
116 return laguerre(min, initial);
117 }
118
119
120 final double yMax = computeObjectiveValue(max);
121 if (FastMath.abs(yMax) <= functionValueAccuracy) {
122 return max;
123 }
124
125
126 if (yInitial * yMax < 0) {
127 return laguerre(initial, max);
128 }
129
130 throw new MathIllegalArgumentException(LocalizedCoreFormats.NOT_BRACKETING_INTERVAL,
131 min, max, yMin, yMax);
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150 private double laguerre(double lo, double hi) {
151 final Complex[] c = ComplexUtils.convertToComplex(getCoefficients());
152
153 final Complex initial = new Complex(0.5 * (lo + hi), 0);
154 final Complex z = complexSolver.solve(c, initial);
155 if (complexSolver.isRoot(lo, hi, z)) {
156 return z.getReal();
157 } else {
158 double r = Double.NaN;
159
160 Complex[] root = complexSolver.solveAll(c, initial);
161 for (int i = 0; i < root.length; i++) {
162 if (complexSolver.isRoot(lo, hi, root[i])) {
163 r = root[i].getReal();
164 break;
165 }
166 }
167 return r;
168 }
169 }
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 public Complex[] solveAllComplex(double[] coefficients,
187 double initial)
188 throws MathIllegalArgumentException, NullArgumentException,
189 MathIllegalStateException {
190 return solveAllComplex(coefficients, 100_000, initial);
191 }
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 public Complex[] solveAllComplex(double[] coefficients,
210 int maxEval,
211 double initial)
212 throws MathIllegalArgumentException, NullArgumentException,
213 MathIllegalStateException {
214 setup(maxEval,
215 new PolynomialFunction(coefficients),
216 Double.NEGATIVE_INFINITY,
217 Double.POSITIVE_INFINITY,
218 initial);
219 return complexSolver.solveAll(ComplexUtils.convertToComplex(coefficients),
220 new Complex(initial, 0d));
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 public Complex solveComplex(double[] coefficients,
239 double initial)
240 throws MathIllegalArgumentException, NullArgumentException,
241 MathIllegalStateException {
242 setup(Integer.MAX_VALUE,
243 new PolynomialFunction(coefficients),
244 Double.NEGATIVE_INFINITY,
245 Double.POSITIVE_INFINITY,
246 initial);
247 return complexSolver.solve(ComplexUtils.convertToComplex(coefficients),
248 new Complex(initial, 0d));
249 }
250
251
252
253
254 private class ComplexSolver {
255
256
257
258
259
260
261
262
263
264 public boolean isRoot(double min, double max, Complex z) {
265 if (isSequence(min, z.getReal(), max)) {
266 final double zAbs = z.norm();
267 double tolerance = FastMath.max(getRelativeAccuracy() * zAbs, getAbsoluteAccuracy());
268 return (FastMath.abs(z.getImaginary()) <= tolerance) ||
269 (zAbs <= getFunctionValueAccuracy());
270 }
271 return false;
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287 public Complex[] solveAll(Complex[] coefficients, Complex initial)
288 throws MathIllegalArgumentException, NullArgumentException,
289 MathIllegalStateException {
290 if (coefficients == null) {
291 throw new NullArgumentException();
292 }
293 final int n = coefficients.length - 1;
294 if (n == 0) {
295 throw new MathIllegalArgumentException(LocalizedCoreFormats.POLYNOMIAL);
296 }
297
298 final Complex[] c = new Complex[n + 1];
299 for (int i = 0; i <= n; i++) {
300 c[i] = coefficients[i];
301 }
302
303
304 final Complex[] root = new Complex[n];
305 for (int i = 0; i < n; i++) {
306 final Complex[] subarray = new Complex[n - i + 1];
307 System.arraycopy(c, 0, subarray, 0, subarray.length);
308 root[i] = solve(subarray, initial);
309
310 Complex newc = c[n - i];
311 Complex oldc;
312 for (int j = n - i - 1; j >= 0; j--) {
313 oldc = c[j];
314 c[j] = newc;
315 newc = oldc.add(newc.multiply(root[i]));
316 }
317 }
318
319 return root;
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 public Complex solve(Complex[] coefficients, Complex initial)
336 throws MathIllegalArgumentException, NullArgumentException,
337 MathIllegalStateException {
338 if (coefficients == null) {
339 throw new NullArgumentException();
340 }
341
342 final int n = coefficients.length - 1;
343 if (n == 0) {
344 throw new MathIllegalArgumentException(LocalizedCoreFormats.POLYNOMIAL);
345 }
346
347 final double absoluteAccuracy = getAbsoluteAccuracy();
348 final double relativeAccuracy = getRelativeAccuracy();
349 final double functionValueAccuracy = getFunctionValueAccuracy();
350
351 final Complex nC = new Complex(n, 0);
352 final Complex n1C = new Complex(n - 1, 0);
353
354 Complex z = initial;
355 Complex oldz = new Complex(Double.POSITIVE_INFINITY,
356 Double.POSITIVE_INFINITY);
357 while (true) {
358
359
360 Complex pv = coefficients[n];
361 Complex dv = Complex.ZERO;
362 Complex d2v = Complex.ZERO;
363 for (int j = n-1; j >= 0; j--) {
364 d2v = dv.add(z.multiply(d2v));
365 dv = pv.add(z.multiply(dv));
366 pv = coefficients[j].add(z.multiply(pv));
367 }
368 d2v = d2v.multiply(new Complex(2.0, 0.0));
369
370
371 final double tolerance = FastMath.max(relativeAccuracy * z.norm(),
372 absoluteAccuracy);
373 if ((z.subtract(oldz)).norm() <= tolerance) {
374 return z;
375 }
376 if (pv.norm() <= functionValueAccuracy) {
377 return z;
378 }
379
380
381 final Complex G = dv.divide(pv);
382 final Complex G2 = G.multiply(G);
383 final Complex H = G2.subtract(d2v.divide(pv));
384 final Complex delta = n1C.multiply((nC.multiply(H)).subtract(G2));
385
386 final Complex deltaSqrt = delta.sqrt();
387 final Complex dplus = G.add(deltaSqrt);
388 final Complex dminus = G.subtract(deltaSqrt);
389 final Complex denominator = dplus.norm() > dminus.norm() ? dplus : dminus;
390
391
392 if (denominator.isZero()) {
393 z = z.add(new Complex(absoluteAccuracy, absoluteAccuracy));
394 oldz = new Complex(Double.POSITIVE_INFINITY,
395 Double.POSITIVE_INFINITY);
396 } else {
397 oldz = z;
398 z = z.subtract(nC.divide(denominator));
399 }
400 incrementEvaluationCount();
401 }
402 }
403 }
404 }