1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.numerics.switching;
39
40 import static java.lang.String.format;
41 import static org.apache.commons.math3.util.FastMath.max;
42 import static org.apache.commons.math3.util.FastMath.min;
43 import static org.apache.commons.math3.util.FastMath.pow;
44
45
46
47
48
49
50
51
52 public class MultiplicativeSwitch implements UnivariateSwitchingFunction {
53
54 private final double b;
55 private final double a;
56 private final double c0;
57 private final double c1;
58 private final double c2;
59 private final double c3;
60 private final double c4;
61 private final double c5;
62 private final double twoC2;
63 private final double threeC3;
64 private final double fourC4;
65 private final double fiveC5;
66
67
68
69
70
71
72 public MultiplicativeSwitch() {
73 this(0.0, 1.0);
74 }
75
76
77
78
79
80
81
82
83
84 public MultiplicativeSwitch(double a, double b) {
85
86
87 this.a = a;
88
89 this.b = b;
90
91 double a2 = a * a;
92 double b2 = b * b;
93
94 double denominator = pow(b - a, 5.0);
95 c0 = b * b2 * (b2 - 5.0 * a * b + 10.0 * a2) / denominator;
96 c1 = -30.0 * a2 * b2 / denominator;
97 c2 = 30.0 * b * a * (b + a) / denominator;
98 c3 = -10.0 * (a2 + 4.0 * a * b + b2) / denominator;
99 c4 = 15.0 * (a + b) / denominator;
100 c5 = -6.0 / denominator;
101 twoC2 = 2.0 * c2;
102 threeC3 = 3.0 * c3;
103 fourC4 = 4.0 * c4;
104 fiveC5 = 5.0 * c5;
105 }
106
107
108 @Override
109 public boolean constantOutsideBounds() {
110 return false;
111 }
112
113
114
115
116
117
118
119
120
121
122 public double dtaper(double r, double r2, double r3, double r4) {
123 return fiveC5 * r4 + fourC4 * r3 + threeC3 * r2 + twoC2 * r + c1;
124 }
125
126
127
128
129
130
131
132 public double dtaper(double r) {
133
134 double r2 = r * r;
135 return dtaper(r, r2, r2 * r, r2 * r2);
136 }
137
138
139 @Override
140 public double firstDerivative(double x) {
141 return dtaper(x);
142 }
143
144
145 @Override
146 public int getHighestOrderZeroDerivative() {
147 return 2;
148 }
149
150
151 @Override
152 public double getOneBound() {
153 return max(a, b);
154 }
155
156
157
158
159
160
161 public double getSwitchEnd() {
162 return b;
163 }
164
165
166
167
168
169
170 public double getSwitchStart() {
171 return a;
172 }
173
174
175 @Override
176 public double getZeroBound() {
177 return min(b, a);
178 }
179
180
181 @Override
182 public double nthDerivative(double x, int order) throws IllegalArgumentException {
183 if (order < 1) {
184 throw new IllegalArgumentException("Order must be >= 1");
185 }
186 switch (order) {
187 case 1:
188 return dtaper(x);
189 case 2:
190 return secondDerivative(x);
191 case 3:
192 double val = 60.0 * c5 * x * x;
193 val += 24.0 * c4 * x;
194 val += 6.0 * c3;
195 return val;
196 case 4:
197 val = 120.0 * c5 * x;
198 val += 24.0 * c4;
199 return val;
200 case 5:
201 return 120.0 * c5;
202 default:
203 return 0;
204 }
205 }
206
207
208 @Override
209 public double secondDerivative(double x) {
210 double x2 = x * x;
211 double val = 20.0 * c5 * x2 * x;
212 val += 12.0 * c4 * x2;
213 val += 6.0 * c3 * x;
214 val += 2.0 * c2;
215 return val;
216 }
217
218
219 @Override
220 public boolean symmetricToUnity() {
221 return true;
222 }
223
224
225
226
227
228
229
230
231
232
233
234 public double taper(double r, double r2, double r3, double r4, double r5) {
235 return c5 * r5 + c4 * r4 + c3 * r3 + c2 * r2 + c1 * r + c0;
236 }
237
238
239
240
241
242
243
244 public double taper(double r) {
245
246 double r2 = r * r;
247 double r3 = r2 * r;
248 return taper(r, r2, r3, r2 * r2, r3 * r2);
249 }
250
251
252 @Override
253 public String toString() {
254 return format(
255 "Multiplicative switch of form f(x) = %8.4g*x^5 + "
256 + "%8.4g*x^4 + %8.4g*x^3 + %8.4g*x^2 + %8.4g*x + %8.4g",
257 c5, c4, c3, c2, c1, c0);
258 }
259
260
261 @Override
262 public boolean validOutsideBounds() {
263 return false;
264 }
265
266
267 @Override
268 public double valueAt(double x) throws IllegalArgumentException {
269 return taper(x);
270 }
271 }