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 MullerSolver2 extends AbstractUnivariateSolver {
50
51
52 private static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6;
53
54
55
56
57 public MullerSolver2() {
58 this(DEFAULT_ABSOLUTE_ACCURACY);
59 }
60
61
62
63
64
65 public MullerSolver2(double absoluteAccuracy) {
66 super(absoluteAccuracy);
67 }
68
69
70
71
72
73
74 public MullerSolver2(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
90 verifyInterval(min, max);
91
92 final double relativeAccuracy = getRelativeAccuracy();
93 final double absoluteAccuracy = getAbsoluteAccuracy();
94 final double functionValueAccuracy = getFunctionValueAccuracy();
95
96
97
98
99
100 double x0 = min;
101 double y0 = computeObjectiveValue(x0);
102 if (JdkMath.abs(y0) < functionValueAccuracy) {
103 return x0;
104 }
105 double x1 = max;
106 double y1 = computeObjectiveValue(x1);
107 if (JdkMath.abs(y1) < functionValueAccuracy) {
108 return x1;
109 }
110
111 if(y0 * y1 > 0) {
112 throw new NoBracketingException(x0, x1, y0, y1);
113 }
114
115 double x2 = 0.5 * (x0 + x1);
116 double y2 = computeObjectiveValue(x2);
117
118 double oldx = Double.POSITIVE_INFINITY;
119 while (true) {
120
121 final double q = (x2 - x1) / (x1 - x0);
122 final double a = q * (y2 - (1 + q) * y1 + q * y0);
123 final double b = (2 * q + 1) * y2 - (1 + q) * (1 + q) * y1 + q * q * y0;
124 final double c = (1 + q) * y2;
125 final double delta = b * b - 4 * a * c;
126 double x;
127 final double denominator;
128 if (delta >= 0.0) {
129
130 double dplus = b + JdkMath.sqrt(delta);
131 double dminus = b - JdkMath.sqrt(delta);
132 denominator = JdkMath.abs(dplus) > JdkMath.abs(dminus) ? dplus : dminus;
133 } else {
134
135 denominator = JdkMath.sqrt(b * b - delta);
136 }
137 if (denominator != 0) {
138 x = x2 - 2.0 * c * (x2 - x1) / denominator;
139
140
141 while (x == x1 || x == x2) {
142 x += absoluteAccuracy;
143 }
144 } else {
145
146 x = min + JdkMath.random() * (max - min);
147 oldx = Double.POSITIVE_INFINITY;
148 }
149 final double y = computeObjectiveValue(x);
150
151
152 final double tolerance = JdkMath.max(relativeAccuracy * JdkMath.abs(x), absoluteAccuracy);
153 if (JdkMath.abs(x - oldx) <= tolerance ||
154 JdkMath.abs(y) <= functionValueAccuracy) {
155 return x;
156 }
157
158
159 x0 = x1;
160 y0 = y1;
161 x1 = x2;
162 y1 = y2;
163 x2 = x;
164 y2 = y;
165 oldx = x;
166 }
167 }
168 }