1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.hipparchus.special.elliptic.jacobi;
18
19 import java.util.function.DoubleFunction;
20 import java.util.function.Function;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.Field;
24 import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
25 import org.hipparchus.dfp.Dfp;
26 import org.hipparchus.dfp.DfpField;
27 import org.hipparchus.util.Binary64Field;
28 import org.hipparchus.util.FastMath;
29 import org.junit.Assert;
30 import org.junit.Test;
31
32 public class FieldJacobiEllipticTest {
33
34 @Test
35 public void testCircular() {
36 doTestCircular(Binary64Field.getInstance());
37 }
38
39 @Test
40 public void testHyperbolic() {
41 doTestHyperbolic(Binary64Field.getInstance());
42 }
43
44 @Test
45 public void testNoConvergence() {
46 doTestNoConvergence(Binary64Field.getInstance());
47 }
48
49 @Test
50 public void testNegativeParameter() {
51 doTestNegativeParameter(Binary64Field.getInstance());
52 }
53
54 @Test
55 public void testAbramowitzStegunExample1() {
56 doTestAbramowitzStegunExample1(Binary64Field.getInstance());
57 }
58
59 @Test
60 public void testAbramowitzStegunExample2() {
61 doTestAbramowitzStegunExample2(Binary64Field.getInstance());
62 }
63
64 @Test
65 public void testAbramowitzStegunExample3() {
66 doTestAbramowitzStegunExample3(Binary64Field.getInstance());
67 }
68
69 @Test
70 public void testAbramowitzStegunExample4() {
71 doTestAbramowitzStegunExample4(Binary64Field.getInstance());
72 }
73
74 @Test
75 public void testAbramowitzStegunExample5() {
76 doTestAbramowitzStegunExample5(Binary64Field.getInstance());
77 }
78
79 @Test
80 public void testAbramowitzStegunExample7() {
81 doTestAbramowitzStegunExample7(Binary64Field.getInstance());
82 }
83
84 @Test
85 public void testAbramowitzStegunExample8() {
86 doTestAbramowitzStegunExample8(Binary64Field.getInstance());
87 }
88
89 @Test
90 public void testAbramowitzStegunExample9() {
91 doTestAbramowitzStegunExample9(Binary64Field.getInstance());
92 }
93
94 @Test
95 public void testAllFunctions() {
96 doTestAllFunctions(Binary64Field.getInstance());
97 }
98
99 @Test
100 public void testHighAccuracy() {
101 final DfpField field = new DfpField(60);
102 FieldJacobiElliptic<Dfp> je = JacobiEllipticBuilder.build(field.newDfp("0.75"));
103 Dfp sn = je.valuesN(field.newDfp("1.3")).sn();
104
105 Dfp reference = field.newDfp("0.8929235150418389265984488063926925504375953835259703680383");
106 Assert.assertTrue(sn.subtract(reference).abs().getReal() < 5.0e-58);
107 }
108
109 @Test
110 public void testInverseCopolarN() {
111 doTestInverseCopolarN(Binary64Field.getInstance());
112 }
113
114 @Test
115 public void testInverseCopolarS() {
116 doTestInverseCopolarS(Binary64Field.getInstance());
117 }
118
119 @Test
120 public void testInverseCopolarC() {
121 doTestInverseCopolarC(Binary64Field.getInstance());
122 }
123
124 @Test
125 public void testInverseCopolarD() {
126 doTestInverseCopolarD(Binary64Field.getInstance());
127 }
128
129 @Test
130 public void testDerivatives() {
131
132 final double m = 0.75;
133 final double m1 = 1 - m;
134 final double u = 1.3;
135
136 JacobiElliptic jeD = JacobiEllipticBuilder.build(m);
137 CopolarN valuesND = jeD.valuesN(u);
138 CopolarC valuesCD = jeD.valuesC(u);
139 CopolarS valuesSD = jeD.valuesS(u);
140 CopolarD valuesDD = jeD.valuesD(u);
141
142 FieldJacobiElliptic<UnivariateDerivative1> jeU = JacobiEllipticBuilder.build(new UnivariateDerivative1(m, 0.0));
143 FieldCopolarN<UnivariateDerivative1> valuesNU = jeU.valuesN(new UnivariateDerivative1(u, 1.0));
144 FieldCopolarC<UnivariateDerivative1> valuesCU = jeU.valuesC(new UnivariateDerivative1(u, 1.0));
145 FieldCopolarS<UnivariateDerivative1> valuesSU = jeU.valuesS(new UnivariateDerivative1(u, 1.0));
146 FieldCopolarD<UnivariateDerivative1> valuesDU = jeU.valuesD(new UnivariateDerivative1(u, 1.0));
147
148
149 Assert.assertEquals( valuesND.cn() * valuesND.dn(), valuesNU.sn().getFirstDerivative(), 2.0e-15);
150 Assert.assertEquals(-1 * valuesND.sn() * valuesND.dn(), valuesNU.cn().getFirstDerivative(), 2.0e-15);
151 Assert.assertEquals(-m * valuesND.sn() * valuesND.cn(), valuesNU.dn().getFirstDerivative(), 2.0e-15);
152
153 Assert.assertEquals(-m1 * valuesDD.sd() * valuesDD.nd(), valuesDU.cd().getFirstDerivative(), 2.0e-15);
154 Assert.assertEquals( valuesDD.cd() * valuesDD.nd(), valuesDU.sd().getFirstDerivative(), 2.0e-15);
155 Assert.assertEquals( m * valuesDD.sd() * valuesDD.cd(), valuesDU.nd().getFirstDerivative(), 2.0e-15);
156
157 Assert.assertEquals( m1 * valuesCD.sc() * valuesCD.nc(), valuesCU.dc().getFirstDerivative(), 2.0e-15);
158 Assert.assertEquals( valuesCD.sc() * valuesCD.dc(), valuesCU.nc().getFirstDerivative(), 2.0e-15);
159 Assert.assertEquals( valuesCD.dc() * valuesCD.nc(), valuesCU.sc().getFirstDerivative(), 2.0e-15);
160
161 Assert.assertEquals(-1 * valuesSD.ds() * valuesSD.cs(), valuesSU.ns().getFirstDerivative(), 2.0e-15);
162 Assert.assertEquals(-1 * valuesSD.cs() * valuesSD.ns(), valuesSU.ds().getFirstDerivative(), 2.0e-15);
163 Assert.assertEquals(-1 * valuesSD.ns() * valuesSD.ds(), valuesSU.cs().getFirstDerivative(), 2.0e-15);
164
165 }
166
167 private <T extends CalculusFieldElement<T>> void doTestCircular(final Field<T> field) {
168 for (double m : new double[] { -1.0e-10, 0.0, 1.0e-10 }) {
169 final double eps = 3 * FastMath.max(1.0e-14, FastMath.abs(m));
170 final FieldJacobiElliptic<T> je = build(field, m);
171 for (double t = -10; t < 10; t += 0.01) {
172 final FieldCopolarN<T> n = je.valuesN(t);
173 Assert.assertEquals(FastMath.sin(t), n.sn().getReal(), eps);
174 Assert.assertEquals(FastMath.cos(t), n.cn().getReal(), eps);
175 Assert.assertEquals(1.0, n.dn().getReal(), eps);
176 }
177 }
178 }
179
180 private <T extends CalculusFieldElement<T>> void doTestHyperbolic(final Field<T> field) {
181 for (double m1 : new double[] { -1.0e-12, 0.0, 1.0e-12 }) {
182 final double eps = 3 * FastMath.max(1.0e-14, FastMath.abs(m1));
183 final FieldJacobiElliptic<T> je = build(field, 1.0 - m1);
184 for (double t = -3; t < 3; t += 0.01) {
185 final FieldCopolarN<T> n = je.valuesN(t);
186 Assert.assertEquals(FastMath.tanh(t), n.sn().getReal(), eps);
187 Assert.assertEquals(1.0 / FastMath.cosh(t), n.cn().getReal(), eps);
188 Assert.assertEquals(1.0 / FastMath.cosh(t), n.dn().getReal(), eps);
189 }
190 }
191 }
192
193 private <T extends CalculusFieldElement<T>> void doTestNoConvergence(final Field<T> field) {
194 Assert.assertTrue(build(field, Double.NaN).valuesS(0.0).cs().isNaN());
195 }
196
197 private <T extends CalculusFieldElement<T>> void doTestNegativeParameter(final Field<T> field) {
198 Assert.assertEquals(0.49781366219021166315, build(field, -4.5).valuesN(8.3).sn().getReal(), 1.5e-10);
199 Assert.assertEquals(0.86728401215332559984, build(field, -4.5).valuesN(8.3).cn().getReal(), 1.5e-10);
200 Assert.assertEquals(1.45436686918553524215, build(field, -4.5).valuesN(8.3).dn().getReal(), 1.5e-10);
201 }
202
203 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample1(final Field<T> field) {
204
205 Assert.assertEquals(-1392.11114434139393839735, build(field, 0.64).valuesC(1.99650).nc().getReal(), 2.8e-10);
206 }
207
208 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample2(final Field<T> field) {
209 Assert.assertEquals(0.996253, build(field, 0.19).valuesN(0.20).dn().getReal(), 1.0e-6);
210 }
211
212 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample3(final Field<T> field) {
213 Assert.assertEquals(0.984056, build(field, 0.81).valuesN(0.20).dn().getReal(), 1.0e-6);
214 }
215
216 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample4(final Field<T> field) {
217 Assert.assertEquals(0.980278, build(field, 0.81).valuesN(0.20).cn().getReal(), 1.0e-6);
218 }
219
220 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample5(final Field<T> field) {
221 Assert.assertEquals(0.60952, build(field, 0.36).valuesN(0.672).sn().getReal(), 1.0e-5);
222 Assert.assertEquals(1.1740, build(field, 0.36).valuesC(0.672).dc().getReal(), 1.0e-4);
223 }
224
225 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample7(final Field<T> field) {
226 Assert.assertEquals(1.6918083, build(field, 0.09).valuesS(0.5360162).cs().getReal(), 1.0e-7);
227 }
228
229 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample8(final Field<T> field) {
230 Assert.assertEquals(0.56458, build(field, 0.5).valuesN(0.61802).sn().getReal(), 1.0e-5);
231 }
232
233 private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample9(final Field<T> field) {
234 Assert.assertEquals(0.68402, build(field, 0.5).valuesC(0.61802).sc().getReal(), 1.0e-5);
235 }
236
237 private <T extends CalculusFieldElement<T>> void doTestAllFunctions(final Field<T> field) {
238
239
240
241
242 final double u = 1.4;
243 final double m = 0.7;
244 final double[] reference = {
245 0.92516138673582827365, 0.37957398289798418747, 0.63312991237590996850,
246 0.41027866958131945027, 0.68434537093007175683, 1.08089249544689572795,
247 1.66800134071905681841, 2.63453251554589286796, 2.43736775548306830513,
248 1.57945467502452678756, 1.46125047743207819361, 0.59951990180590090343
249 };
250 final FieldJacobiElliptic<T> je = build(field, m);
251 Assert.assertEquals(reference[ 0], je.valuesN(u).sn().getReal(), 4 * FastMath.ulp(reference[ 0]));
252 Assert.assertEquals(reference[ 1], je.valuesN(u).cn().getReal(), 4 * FastMath.ulp(reference[ 1]));
253 Assert.assertEquals(reference[ 2], je.valuesN(u).dn().getReal(), 4 * FastMath.ulp(reference[ 2]));
254 Assert.assertEquals(reference[ 3], je.valuesS(u).cs().getReal(), 4 * FastMath.ulp(reference[ 3]));
255 Assert.assertEquals(reference[ 4], je.valuesS(u).ds().getReal(), 4 * FastMath.ulp(reference[ 4]));
256 Assert.assertEquals(reference[ 5], je.valuesS(u).ns().getReal(), 4 * FastMath.ulp(reference[ 5]));
257 Assert.assertEquals(reference[ 6], je.valuesC(u).dc().getReal(), 4 * FastMath.ulp(reference[ 6]));
258 Assert.assertEquals(reference[ 7], je.valuesC(u).nc().getReal(), 4 * FastMath.ulp(reference[ 7]));
259 Assert.assertEquals(reference[ 8], je.valuesC(u).sc().getReal(), 4 * FastMath.ulp(reference[ 8]));
260 Assert.assertEquals(reference[ 9], je.valuesD(u).nd().getReal(), 4 * FastMath.ulp(reference[ 9]));
261 Assert.assertEquals(reference[10], je.valuesD(u).sd().getReal(), 4 * FastMath.ulp(reference[10]));
262 Assert.assertEquals(reference[11], je.valuesD(u).cd().getReal(), 4 * FastMath.ulp(reference[11]));
263 }
264
265 private <T extends CalculusFieldElement<T>> FieldJacobiElliptic<T> build(final Field<T> field, final double m) {
266 return JacobiEllipticBuilder.build(field.getZero().newInstance(m));
267 }
268
269 private <T extends CalculusFieldElement<T>> void doTestInverseCopolarN(final Field<T> field) {
270 final double m = 0.7;
271 final FieldJacobiElliptic<T> je = build(field, m);
272 doTestInverse(-0.80, 0.80, 100, field, u -> je.valuesN(u).sn(), x -> je.arcsn(x), x -> je.arcsn(x), 1.0e-14);
273 doTestInverse(-1.00, 1.00, 100, field, u -> je.valuesN(u).cn(), x -> je.arccn(x), x -> je.arccn(x), 1.0e-14);
274 doTestInverse( 0.55, 1.00, 100, field, u -> je.valuesN(u).dn(), x -> je.arcdn(x), x -> je.arcdn(x), 1.0e-14);
275 }
276
277 private <T extends CalculusFieldElement<T>> void doTestInverseCopolarS(final Field<T> field) {
278 final double m = 0.7;
279 final FieldJacobiElliptic<T> je = build(field, m);
280 doTestInverse(-2.00, 2.00, 100, field, u -> je.valuesS(u).cs(), x -> je.arccs(x), x -> je.arccs(x), 1.0e-14);
281 doTestInverse( 0.55, 2.00, 100, field, u -> je.valuesS(u).ds(), x -> je.arcds(x), x -> je.arcds(x), 1.0e-14);
282 doTestInverse(-2.00, -0.55, 100, field, u -> je.valuesS(u).ds(), x -> je.arcds(x), x -> je.arcds(x), 1.0e-14);
283 doTestInverse( 1.00, 2.00, 100, field, u -> je.valuesS(u).ns(), x -> je.arcns(x), x -> je.arcns(x), 1.0e-11);
284 doTestInverse(-2.00, -1.00, 100, field, u -> je.valuesS(u).ns(), x -> je.arcns(x), x -> je.arcns(x), 1.0e-11);
285 }
286
287 private <T extends CalculusFieldElement<T>> void doTestInverseCopolarC(final Field<T> field) {
288 final double m = 0.7;
289 final FieldJacobiElliptic<T> je = build(field, m);
290 doTestInverse( 1.00, 2.00, 100, field, u -> je.valuesC(u).dc(), x -> je.arcdc(x), x -> je.arcdc(x), 1.0e-14);
291 doTestInverse(-2.00, -1.00, 100, field, u -> je.valuesC(u).dc(), x -> je.arcdc(x), x -> je.arcdc(x), 1.0e-14);
292 doTestInverse( 1.00, 2.00, 100, field, u -> je.valuesC(u).nc(), x -> je.arcnc(x), x -> je.arcnc(x), 1.0e-14);
293 doTestInverse(-2.00, -1.00, 100, field, u -> je.valuesC(u).nc(), x -> je.arcnc(x), x -> je.arcnc(x), 1.0e-14);
294 doTestInverse(-2.00, 2.00, 100, field, u -> je.valuesC(u).sc(), x -> je.arcsc(x), x -> je.arcsc(x), 1.0e-14);
295 }
296
297 private <T extends CalculusFieldElement<T>> void doTestInverseCopolarD(final Field<T> field) {
298 final double m = 0.7;
299 final FieldJacobiElliptic<T> je = build(field, m);
300 doTestInverse( 1.00, 1.80, 100, field, u -> je.valuesD(u).nd(), x -> je.arcnd(x), x -> je.arcnd(x), 1.0e-14);
301 doTestInverse(-1.80, 1.80, 100, field, u -> je.valuesD(u).sd(), x -> je.arcsd(x), x -> je.arcsd(x), 1.0e-14);
302 doTestInverse(-1.00, 1.00, 100, field, u -> je.valuesD(u).cd(), x -> je.arccd(x), x -> je.arccd(x), 1.0e-14);
303 }
304
305 private <T extends CalculusFieldElement<T>> void doTestInverse(final double xMin, final double xMax, final int n,
306 final Field<T> field,
307 final Function<T, T> direct,
308 final Function<T, T> inverseField,
309 final DoubleFunction<T> inverseDouble,
310 final double tolerance) {
311 for (int i = 0; i < n; ++i) {
312 final T x = field.getZero().newInstance(xMin + i * (xMax - xMin) / (n - 1));
313 final T xFieldRebuilt = direct.apply(inverseField.apply(x));
314 Assert.assertEquals(x.getReal(), xFieldRebuilt.getReal(), tolerance);
315 final T xDoubleRebuilt = direct.apply(inverseDouble.apply(x.getReal()));
316 Assert.assertEquals(x.getReal(), xDoubleRebuilt.getReal(), tolerance);
317 }
318 }
319
320 }