1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.analysis.solvers;
18
19 import org.apache.commons.math4.legacy.exception.NoBracketingException;
20 import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
21 import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException;
22 import org.apache.commons.math4.core.jdkmath.JdkMath;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class MullerSolver extends AbstractUnivariateSolver {
50
51
52 private static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6;
53
54
55
56
57 public MullerSolver() {
58 this(DEFAULT_ABSOLUTE_ACCURACY);
59 }
60
61
62
63
64
65 public MullerSolver(double absoluteAccuracy) {
66 super(absoluteAccuracy);
67 }
68
69
70
71
72
73
74 public MullerSolver(double relativeAccuracy,
75 double absoluteAccuracy) {
76 super(relativeAccuracy, absoluteAccuracy);
77 }
78
79
80
81
82 @Override
83 protected double doSolve()
84 throws TooManyEvaluationsException,
85 NumberIsTooLargeException,
86 NoBracketingException {
87 final double min = getMin();
88 final double max = getMax();
89 final double initial = getStartValue();
90
91 final double functionValueAccuracy = getFunctionValueAccuracy();
92
93 verifySequence(min, initial, max);
94
95
96 final double fMin = computeObjectiveValue(min);
97 if (JdkMath.abs(fMin) < functionValueAccuracy) {
98 return min;
99 }
100 final double fMax = computeObjectiveValue(max);
101 if (JdkMath.abs(fMax) < functionValueAccuracy) {
102 return max;
103 }
104 final double fInitial = computeObjectiveValue(initial);
105 if (JdkMath.abs(fInitial) < functionValueAccuracy) {
106 return initial;
107 }
108
109 verifyBracketing(min, max);
110
111 if (isBracketing(min, initial)) {
112 return solve(min, initial, fMin, fInitial);
113 } else {
114 return solve(initial, max, fInitial, fMax);
115 }
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129 private double solve(double min, double max,
130 double fMin, double fMax)
131 throws TooManyEvaluationsException {
132 final double relativeAccuracy = getRelativeAccuracy();
133 final double absoluteAccuracy = getAbsoluteAccuracy();
134 final double functionValueAccuracy = getFunctionValueAccuracy();
135
136
137
138
139
140
141 double x0 = min;
142 double y0 = fMin;
143 double x2 = max;
144 double y2 = fMax;
145 double x1 = 0.5 * (x0 + x2);
146 double y1 = computeObjectiveValue(x1);
147
148 double oldx = Double.POSITIVE_INFINITY;
149 while (true) {
150
151
152
153
154 final double d01 = (y1 - y0) / (x1 - x0);
155 final double d12 = (y2 - y1) / (x2 - x1);
156 final double d012 = (d12 - d01) / (x2 - x0);
157 final double c1 = d01 + (x1 - x0) * d012;
158 final double delta = c1 * c1 - 4 * y1 * d012;
159 final double xplus = x1 + (-2.0 * y1) / (c1 + JdkMath.sqrt(delta));
160 final double xminus = x1 + (-2.0 * y1) / (c1 - JdkMath.sqrt(delta));
161
162
163 final double x = isSequence(x0, xplus, x2) ? xplus : xminus;
164 final double y = computeObjectiveValue(x);
165
166
167 final double tolerance = JdkMath.max(relativeAccuracy * JdkMath.abs(x), absoluteAccuracy);
168 if (JdkMath.abs(x - oldx) <= tolerance ||
169 JdkMath.abs(y) <= functionValueAccuracy) {
170 return x;
171 }
172
173
174
175
176
177 boolean bisect = (x < x1 && (x1 - x0) > 0.95 * (x2 - x0)) ||
178 (x > x1 && (x2 - x1) > 0.95 * (x2 - x0)) ||
179 (x == x1);
180
181 if (!bisect) {
182 x0 = x < x1 ? x0 : x1;
183 y0 = x < x1 ? y0 : y1;
184 x2 = x > x1 ? x2 : x1;
185 y2 = x > x1 ? y2 : y1;
186 x1 = x; y1 = y;
187 oldx = x;
188 } else {
189 double xm = 0.5 * (x0 + x2);
190 double ym = computeObjectiveValue(xm);
191 if (JdkMath.signum(y0) + JdkMath.signum(ym) == 0.0) {
192 x2 = xm; y2 = ym;
193 } else {
194 x0 = xm; y0 = ym;
195 }
196 x1 = 0.5 * (x0 + x2);
197 y1 = computeObjectiveValue(x1);
198 oldx = Double.POSITIVE_INFINITY;
199 }
200 }
201 }
202 }