View Javadoc
1   /*
2    * Licensed to the Hipparchus project under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.hipparchus.analysis.function;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.analysis.UnivariateFunction;
21  import org.hipparchus.analysis.differentiation.DSFactory;
22  import org.hipparchus.analysis.differentiation.DerivativeStructure;
23  import org.hipparchus.analysis.differentiation.Gradient;
24  import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction;
25  import org.hipparchus.util.FastMath;
26  import org.junit.jupiter.api.Test;
27  
28  import java.lang.reflect.InvocationTargetException;
29  import java.lang.reflect.Method;
30  
31  import static org.junit.jupiter.api.Assertions.assertEquals;
32  import static org.junit.jupiter.api.Assertions.assertTrue;
33  import static org.junit.jupiter.api.Assertions.fail;
34  
35  class FunctionsWithFastMathVersionTest {
36  
37      @Test
38      void testAcos() {
39          doTestF0(new Acos(), -1.25, -0.25, 0.0, 0.25, 1.25);
40          doTestFn(new Acos(), -1.25, -0.25, 0.0, 0.25, 1.25);
41          doTestF1(new Acos(), -1.25, -0.25, 0.0, 0.25, 1.25);
42      }
43  
44      @Test
45      void testAcosH() {
46          doTestF0(new Acosh(), -10.0, -5.0, -0.5, 0.5, 5.0, 10.0);
47          doTestFn(new Acosh(), -10.0, -5.0, -0.5, 0.5, 5.0, 10.0);
48          doTestF1(new Acosh(), -10.0, -5.0, -0.5, 0.5, 5.0, 10.0);
49      }
50  
51      @Test
52      void testAsin() {
53          doTestF0(new Asin(), -1.25, -0.25, 0.0, 0.25, 1.25);
54          doTestFn(new Asin(), -1.25, -0.25, 0.0, 0.25, 1.25);
55          doTestF1(new Asin(), -1.25, -0.25, 0.0, 0.25, 1.25);
56      }
57  
58      @Test
59      void testAsinh() {
60          doTestF0(new Asinh(), -10.0, -1.25, 0.0, 1.25, 10.0);
61          doTestFn(new Asinh(), -10.0, -1.25, 0.0, 1.25, 10.0);
62          doTestF1(new Asinh(), -10.0, -1.25, 0.0, 1.25, 10.0);
63      }
64  
65      @Test
66      void testAtan() {
67          doTestF0(new Atan(), -10.0, -1.25, 0.0, 1.25, 10.0);
68          doTestFn(new Atan(), -10.0, -1.25, 0.0, 1.25, 10.0);
69          doTestF1(new Atan(), -10.0, -1.25, 0.0, 1.25, 10.0);
70      }
71  
72      @Test
73      void testAtanh() {
74          doTestF0(new Atanh(), -10.0, -1.25, 0.0, 1.25, 10.0);
75          doTestFn(new Atanh(), -10.0, -1.25, 0.0, 1.25, 10.0);
76          doTestF1(new Atanh(), -10.0, -1.25, 0.0, 1.25, 10.0);
77      }
78  
79      @Test
80      void testCbrt() {
81          doTestF0(new Cbrt(), -10.0, -1.25, 0.0, 1.25, 10.0);
82          doTestFn(new Cbrt(), -10.0, -1.25, 0.0, 1.25, 10.0);
83          doTestF1(new Cbrt(), -10.0, -1.25, 0.0, 1.25, 10.0);
84      }
85  
86      @Test
87      void testCeil() {
88          doTestF0(new Ceil(), -10.0, -1.25, 0.0, 1.25, 10.0);
89          doTestFn(new Ceil(), -10.0, -1.25, 0.0, 1.25, 10.0);
90          doTestF1(new Ceil(), -10.0, -1.25, 0.0, 1.25, 10.0);
91      }
92  
93      @Test
94      void testCos() {
95          doTestF0(new Cos(), -10.0, -1.25, 0.0, 1.25, 10.0);
96          doTestFn(new Cos(), -10.0, -1.25, 0.0, 1.25, 10.0);
97          doTestF1(new Cos(), -10.0, -1.25, 0.0, 1.25, 10.0);
98      }
99  
100     @Test
101     void testCosh() {
102         doTestF0(new Cosh(), -10.0, -1.25, -0.5, 0.0, 0.5, 1.25, 10.0);
103         doTestFn(new Cosh(), -10.0, -1.25, -0.5, 0.0, 0.5, 1.25, 10.0);
104         doTestF1(new Cosh(), -10.0, -1.25, -0.5, 0.0, 0.5, 1.25, 10.0);
105     }
106 
107     @Test
108     void testExp() {
109         doTestF0(new Exp(), -10.0, -1.25, 0.0, 1.25, 10.0);
110         doTestFn(new Exp(), -10.0, -1.25, 0.0, 1.25, 10.0);
111         doTestF1(new Exp(), -10.0, -1.25, 0.0, 1.25, 10.0);
112     }
113 
114     @Test
115     void testExpm1() {
116         doTestF0(new Expm1(), -10.0, -1.25, 0.0, 1.25, 10.0);
117         doTestFn(new Expm1(), -10.0, -1.25, 0.0, 1.25, 10.0);
118         doTestF1(new Expm1(), -10.0, -1.25, 0.0, 1.25, 10.0);
119     }
120 
121     @Test
122     void testFloor() {
123         doTestF0(new Floor(), -10.0, -1.25, 0.0, 1.25, 10.0);
124         doTestFn(new Floor(), -10.0, -1.25, 0.0, 1.25, 10.0);
125         doTestF1(new Floor(), -10.0, -1.25, 0.0, 1.25, 10.0);
126     }
127 
128     @Test
129     void testLog() {
130         doTestF0(new Log(), -10.0, -1.25, 0.0, 1.25, 10.0);
131         doTestFn(new Log(), -10.0, -1.25, 0.0, 1.25, 10.0);
132         doTestF1(new Log(), -10.0, -1.25, 0.0, 1.25, 10.0);
133     }
134 
135     @Test
136     void testLog10() {
137         doTestF0(new Log10(), -10.0, -1.25, 0.0, 1.25, 10.0);
138         doTestFn(new Log10(), -10.0, -1.25, 0.0, 1.25, 10.0);
139         doTestF1(new Log10(), -10.0, -1.25, 0.0, 1.25, 10.0);
140     }
141 
142     @Test
143     void testLog1p() {
144         doTestF0(new Log1p(), -10.0, -1.25, 0.0, 1.25, 10.0);
145         doTestFn(new Log1p(), -10.0, -1.25, 0.0, 1.25, 10.0);
146         doTestF1(new Log1p(), -10.0, -1.25, 0.0, 1.25, 10.0);
147     }
148 
149     @Test
150     void testRint() {
151         doTestF0(new Rint(), -10.0, -1.25, 0.0, 1.25, 10.0);
152         doTestFn(new Rint(), -10.0, -1.25, 0.0, 1.25, 10.0);
153         doTestF1(new Rint(), -10.0, -1.25, 0.0, 1.25, 10.0);
154     }
155 
156     @Test
157     void testSin() {
158         doTestF0(new Sin(), -10.0, -1.25, 0.0, 1.25, 10.0);
159         doTestFn(new Sin(), -10.0, -1.25, 0.0, 1.25, 10.0);
160         doTestF1(new Sin(), -10.0, -1.25, 0.0, 1.25, 10.0);
161     }
162 
163     @Test
164     void testSinh() {
165         doTestF0(new Sinh(), -10.0, -1.25, 0.0, 1.25, 10.0);
166         doTestFn(new Sinh(), -10.0, -1.25, 0.0, 1.25, 10.0);
167         doTestF1(new Sinh(), -10.0, -1.25, 0.0, 1.25, 10.0);
168     }
169 
170     @Test
171     void testSqrt() {
172         doTestF0(new Sqrt(), -10.0, -1.25, 0.0, 1.25, 10.0);
173         doTestFn(new Sqrt(), -10.0, -1.25, 0.0, 1.25, 10.0);
174         doTestF1(new Sqrt(), -10.0, -1.25, 0.0, 1.25, 10.0);
175     }
176 
177     @Test
178     void testTan() {
179         doTestF0(new Tan(), -10.0, -1.25, 0.0, 1.25, 10.0);
180         doTestFn(new Tan(), -10.0, -1.25, 0.0, 1.25, 10.0);
181         doTestF1(new Tan(), -10.0, -1.25, 0.0, 1.25, 10.0);
182     }
183 
184     @Test
185     void testTanh() {
186         doTestF0(new Tanh(), -10.0, -1.25, 0.0, 1.25, 10.0);
187         doTestFn(new Tanh(), -10.0, -1.25, 0.0, 1.25, 10.0);
188         doTestF1(new Tanh(), -10.0, -1.25, 0.0, 1.25, 10.0);
189     }
190 
191     @Test
192     void testUlp() {
193         doTestF0(new Ulp(), -10.0, -1.25, 0.0, 1.25, 10.0);
194     }
195 
196     @Test
197     void testAtan2() {
198         final double[] d = { Double.NEGATIVE_INFINITY, -13.4, -0.4, 0.0, 0.4, 13.4, Double.POSITIVE_INFINITY, Double.NaN};
199         for (double x : d) {
200             for (double y : d) {
201                 double aRef = FastMath.atan2(y, x);
202                 double a    = new Atan2().value(y, x);
203                 if (Double.isNaN(aRef)) {
204                     assertTrue(Double.isNaN(a));
205                 } else if (Double.isInfinite(aRef)) {
206                     assertTrue(Double.isInfinite(a));
207                     assertTrue(a * aRef > 0.0);
208                 } else {
209                     assertEquals(aRef, a, FastMath.ulp(aRef));
210                 }
211             }
212         }
213     }
214 
215     private void doTestF0(final UnivariateFunction f, double... x) {
216         try {
217             final Method fastMathVersion = FastMath.class.getMethod(f.getClass().getSimpleName().toLowerCase(), Double.TYPE);
218             for (double xi : x) {
219                 checkF0Equality(f, fastMathVersion, xi);
220             }
221             checkF0Equality(f, fastMathVersion, Double.NEGATIVE_INFINITY);
222             checkF0Equality(f, fastMathVersion, Double.POSITIVE_INFINITY);
223             checkF0Equality(f, fastMathVersion, Double.NaN);
224         } catch (NoSuchMethodException e) {
225             fail(e.getLocalizedMessage());
226         }
227     }
228 
229     private void checkF0Equality(final UnivariateFunction f, final Method ref, final double x) {
230         try {
231             double yRef = ((Double) ref.invoke(null, x)).doubleValue();
232             double y    = f.value(x);
233             if (Double.isNaN(yRef)) {
234                 assertTrue(Double.isNaN(y));
235             } else if (Double.isInfinite(yRef)) {
236                 assertTrue(Double.isInfinite(y));
237                 assertTrue(y * yRef > 0.0);
238             } else {
239                 assertEquals(yRef, y, FastMath.ulp(yRef));
240             }
241         } catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
242             fail(e.getLocalizedMessage());
243         }
244     }
245 
246     private void doTestFn(final UnivariateDifferentiableFunction f, double... x) {
247         try {
248             final Method fastMathVersion = FastMath.class.getMethod(f.getClass().getSimpleName().toLowerCase(),
249                                                                     CalculusFieldElement.class);
250             for (double xi : x) {
251                 checkFnEqualities(f, fastMathVersion, xi);
252             }
253             checkFnEqualities(f, fastMathVersion, Double.NEGATIVE_INFINITY);
254             checkFnEqualities(f, fastMathVersion, Double.POSITIVE_INFINITY);
255             checkFnEqualities(f, fastMathVersion, Double.NaN);
256         } catch (NoSuchMethodException e) {
257             fail(e.getLocalizedMessage());
258         }
259     }
260 
261     private void checkFnEqualities(final UnivariateDifferentiableFunction f, final Method ref, final double x) {
262         try {
263             DSFactory           factory = new DSFactory(1, 5);
264             DerivativeStructure xDS     = factory.variable(0, x);
265             DerivativeStructure yRef    = (DerivativeStructure) ref.invoke(null, xDS);
266             DerivativeStructure y       = f.value(xDS);
267             for (int order = 0; order < factory.getCompiler().getOrder(); ++order) {
268                 if (Double.isNaN(yRef.getPartialDerivative(order))) {
269                     assertTrue(Double.isNaN(y.getPartialDerivative(order)));
270                 } else if (Double.isInfinite(yRef.getPartialDerivative(order))) {
271                     assertTrue(Double.isInfinite(y.getPartialDerivative(order)));
272                     assertTrue(y.getPartialDerivative(order) * yRef.getPartialDerivative(order) > 0.0);
273                 } else {
274                     assertEquals(yRef.getPartialDerivative(order), y.getPartialDerivative(order), FastMath.ulp(yRef.getPartialDerivative(order)));
275                 }
276             }
277         } catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
278             fail(e.getLocalizedMessage());
279         }
280     }
281 
282     private void doTestF1(final UnivariateDifferentiableFunction f, double... x) {
283         try {
284             final Method fastMathVersion = FastMath.class.getMethod(f.getClass().getSimpleName().toLowerCase(),
285                                                                     CalculusFieldElement.class);
286             for (double xi : x) {
287                 checkF1Equalities(f, fastMathVersion, xi);
288             }
289             checkF1Equalities(f, fastMathVersion, Double.NEGATIVE_INFINITY);
290             checkF1Equalities(f, fastMathVersion, Double.POSITIVE_INFINITY);
291             checkF1Equalities(f, fastMathVersion, Double.NaN);
292         } catch (NoSuchMethodException e) {
293             fail(e.getLocalizedMessage());
294         }
295     }
296 
297     private void checkF1Equalities(final UnivariateDifferentiableFunction f, final Method ref, final double x) {
298         try {
299             Gradient xDS     = Gradient.variable(1, 0, x);
300             Gradient yRef    = (Gradient) ref.invoke(null, xDS);
301             Gradient y       = f.value(xDS);
302             if (Double.isNaN(yRef.getPartialDerivative(0))) {
303                 assertTrue(Double.isNaN(y.getPartialDerivative(0)));
304             } else if (Double.isInfinite(yRef.getPartialDerivative(0))) {
305                 assertTrue(Double.isInfinite(y.getPartialDerivative(0)));
306                 assertTrue(y.getPartialDerivative(0) * yRef.getPartialDerivative(0) > 0.0);
307             } else {
308                 assertEquals(yRef.getPartialDerivative(0), y.getPartialDerivative(0), FastMath.ulp(yRef.getPartialDerivative(0)));
309             }
310         } catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
311             fail(e.getLocalizedMessage());
312         }
313     }
314 
315 }