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.pow;
42
43
44
45
46
47
48
49
50
51 public class BellCurveSwitch implements UnivariateSwitchingFunction {
52 private final double midpoint;
53 private final double halfWidth;
54 private final double invWidth;
55 private final UnivariateSwitchingFunction switchingFunction;
56 private final UnivariateSwitchingFunction secondSwitchingFunction;
57
58
59 public BellCurveSwitch() {
60 this(0.5);
61 }
62
63
64
65
66
67
68 public BellCurveSwitch(double midpoint) {
69 this(midpoint, 1.0);
70 }
71
72
73
74
75
76
77
78 public BellCurveSwitch(double midpoint, double width) {
79 this.midpoint = midpoint;
80 invWidth = 1.0 / width;
81
82 halfWidth = 0.5 * width;
83 switchingFunction = new MultiplicativeSwitch(midpoint, midpoint - halfWidth);
84 secondSwitchingFunction = new MultiplicativeSwitch(midpoint, midpoint + halfWidth);
85 }
86
87
88 @Override
89 public boolean constantOutsideBounds() {
90 return switchingFunction.constantOutsideBounds()
91 && secondSwitchingFunction.constantOutsideBounds();
92 }
93
94
95 @Override
96 public double firstDerivative(double x) {
97 if (x > midpoint) {
98 return invWidth * secondSwitchingFunction.firstDerivative(x);
99 } else {
100 return invWidth * switchingFunction.firstDerivative(x);
101 }
102 }
103
104
105 @Override
106 public int getHighestOrderZeroDerivative() {
107 return Math.min(
108 switchingFunction.getHighestOrderZeroDerivative(),
109 secondSwitchingFunction.getHighestOrderZeroDerivative());
110 }
111
112
113 @Override
114 public double getOneBound() {
115 return midpoint + halfWidth;
116 }
117
118
119 @Override
120 public double getZeroBound() {
121 return midpoint - halfWidth;
122 }
123
124
125 @Override
126 public double nthDerivative(double x, int order) throws IllegalArgumentException {
127 double mult = pow(invWidth, order);
128 if (x > midpoint) {
129 return mult * secondSwitchingFunction.nthDerivative(x, order);
130 } else {
131 return mult * switchingFunction.nthDerivative(x, order);
132 }
133 }
134
135
136 @Override
137 public double secondDerivative(double x) {
138 if (x > midpoint) {
139 return invWidth * invWidth * secondSwitchingFunction.secondDerivative(x);
140 } else {
141 return invWidth * invWidth * switchingFunction.secondDerivative(x);
142 }
143 }
144
145
146 @Override
147 public boolean symmetricToUnity() {
148 return switchingFunction.symmetricToUnity() && secondSwitchingFunction.symmetricToUnity();
149 }
150
151 @Override
152 public String toString() {
153 return format(
154 " Spliced 5'th order Hermite splines with midpoint " + "%11.5g, width %11.5g",
155 midpoint, 2.0 * halfWidth);
156 }
157
158
159 @Override
160 public boolean validOutsideBounds() {
161 return switchingFunction.validOutsideBounds() && secondSwitchingFunction.validOutsideBounds();
162 }
163
164
165 @Override
166 public double valueAt(double x) throws IllegalArgumentException {
167 if (x > midpoint) {
168 return secondSwitchingFunction.valueAt(x);
169 } else {
170 return switchingFunction.valueAt(x);
171 }
172 }
173 }