001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.nabla;
018    
019    import org.apache.commons.nabla.core.DifferentialPair;
020    
021    /** <code>StrictMath</code>-like utility class computing differentials.
022     * <p>This class provides mathematical functions similar to the functions
023     * provided by the standard <code>java.lang.StrictMath</code> class but
024     * using {@link org.apache.commons.nabla.core.DifferentialPair DifferentialPair}
025     * instances instead of doubles.</p>
026     */
027    public class NablaStrictMath {
028    
029        /** Hidden constructor.
030         * <p>Since this class is a utility class, it cannot be instantiated.</p>
031         */
032        private NablaStrictMath() {
033        }
034    
035        ///////////////////////////
036        // exponential functions //
037        ///////////////////////////
038    
039        /** Exponential function.
040         * @param a function input value
041         * @return e<sup>a</sup>
042         */
043        public static DifferentialPair exp(final DifferentialPair a) {
044            final double e = StrictMath.exp(a.getValue());
045            return new DifferentialPair(e, a.getFirstDerivative() * e);
046        }
047    
048        /** Exponential minus 1 function.
049         * @param a function input value
050         * @return e<sup>a</sup>-1
051         */
052        public static DifferentialPair expm1(final DifferentialPair a) {
053            final double e = StrictMath.expm1(a.getValue());
054            return new DifferentialPair(e, a.getFirstDerivative() * (e + 1));
055        }
056    
057        /** Natural logarithm function.
058         * @param a function input value
059         * @return log(a)
060         */
061        public static DifferentialPair log(final DifferentialPair a) {
062            final double a0 = a.getValue();
063            return new DifferentialPair(StrictMath.log(a0), a.getFirstDerivative() / a0);
064        }
065    
066        /** Shifted natural logarithm function.
067         * @param a function input value
068         * @return log(1+a)
069         */
070        public static DifferentialPair log1p(final DifferentialPair a) {
071            final double a0 = a.getValue();
072            return new DifferentialPair(StrictMath.log1p(a0), a.getFirstDerivative() / (1 + a0));
073        }
074    
075        /** Base 10 logarithm function.
076         * @param a function input value
077         * @return log<sub>10</sub>(a)
078         */
079        public static DifferentialPair log10(final DifferentialPair a) {
080            final double a0 = a.getValue();
081            return new DifferentialPair(StrictMath.log10(a0), a.getFirstDerivative() / (a0 * StrictMath.log(10)));
082        }
083    
084    
085        ////////////////////////
086        // circular functions //
087        ////////////////////////
088    
089        /** Cosine function.
090         * @param a function input value
091         * @return cos(a)
092         */
093        public static DifferentialPair cos(final DifferentialPair a) {
094            final double a0 = a.getValue();
095            return new DifferentialPair(StrictMath.cos(a0), -a.getFirstDerivative() * StrictMath.sin(a0));
096        }
097    
098        /** Sine function.
099         * @param a function input value
100         * @return sin(a)
101         */
102        public static DifferentialPair sin(final DifferentialPair a) {
103            final double a0 = a.getValue();
104            return new DifferentialPair(StrictMath.sin(a0), a.getFirstDerivative() * StrictMath.cos(a0));
105        }
106    
107        /** Tangent function.
108         * @param a function input value
109         * @return tan(a)
110         */
111        public static DifferentialPair tan(final DifferentialPair a) {
112            final double t = StrictMath.tan(a.getValue());
113            return new DifferentialPair(t, a.getFirstDerivative() * (1 + t * t));
114        }
115    
116        /** Inverse cosine function.
117         * @param a function input value
118         * @return acos(a)
119         */
120        public static DifferentialPair acos(final DifferentialPair a) {
121            final double a0 = a.getValue();
122            return new DifferentialPair(StrictMath.acos(a0), -a.getFirstDerivative() / StrictMath.sqrt(1 - a0 * a0));
123        }
124    
125        /** Inverse sine function.
126         * @param a function input value
127         * @return asin(a)
128         */
129        public static DifferentialPair asin(final DifferentialPair a) {
130            final double a0 = a.getValue();
131            return new DifferentialPair(StrictMath.asin(a0), a.getFirstDerivative() / StrictMath.sqrt(1 - a0 * a0));
132        }
133    
134        /** Inverse tangent function.
135         * @param a function input value
136         * @return atan(a)
137         */
138        public static DifferentialPair atan(final DifferentialPair a) {
139            final double a0 = a.getValue();
140            return new DifferentialPair(StrictMath.atan(a0), a.getFirstDerivative() / (1 + a0 * a0));
141        }
142    
143    
144        /////////////////////////////////
145        // cartesian/polar conversions //
146        ////////////////////////////////
147    
148        /** Cartesian to polar conversion function.
149         * @param y cartesian ordinate of the point
150         * @param x cartesian abscissa of the point
151         * @return angular part of the polar coordinates of the point
152         */
153        public static DifferentialPair atan2(final DifferentialPair y, final double x) {
154            final double y0 = y.getValue();
155            return new DifferentialPair(StrictMath.atan2(y0, x),
156                                        x * y.getFirstDerivative() / (x * x + y0 * y0));
157        }
158    
159        /** Cartesian to polar conversion function.
160         * @param y cartesian ordinate of the point
161         * @param x cartesian abscissa of the point
162         * @return angular part of the polar coordinates of the point
163         */
164        public static DifferentialPair atan2(final double y, final DifferentialPair x) {
165            final double x0 = x.getValue();
166            return new DifferentialPair(StrictMath.atan2(y, x0),
167                                        -y * x.getFirstDerivative() / (x0 * x0 + y * y));
168        }
169    
170        /** Cartesian to polar conversion function.
171         * @param y cartesian ordinate of the point
172         * @param x cartesian abscissa of the point
173         * @return angular part of the polar coordinates of the point
174         */
175        public static DifferentialPair atan2(final DifferentialPair y, final DifferentialPair x) {
176            final double y0 = y.getValue();
177            final double x0 = x.getValue();
178            return new DifferentialPair(StrictMath.atan2(y0, x0),
179                                        (x0 * y.getFirstDerivative() - y0 * x.getFirstDerivative()) / (x0 * x0 + y0 * y0));
180        }
181    
182        /** Cartesian to polar conversion function.
183         * @param x cartesian abscissa of the point
184         * @param y cartesian ordinate of the point
185         * @return radius part of the polar coordinates of the point
186         */
187        public static DifferentialPair hypot(final DifferentialPair x, final double y) {
188            final double x0 = x.getValue();
189            final double h = StrictMath.hypot(x0, y);
190            return new DifferentialPair(h, x0 * x.getFirstDerivative() / h);
191        }
192    
193        /** Cartesian to polar conversion function.
194         * @param x cartesian abscissa of the point
195         * @param y cartesian ordinate of the point
196         * @return radius part of the polar coordinates of the point
197         */
198        public static DifferentialPair hypot(final double x, final DifferentialPair y) {
199            final double y0 = y.getValue();
200            final double h = StrictMath.hypot(x, y0);
201            return new DifferentialPair(h, y0 * y.getFirstDerivative() / h);
202        }
203    
204        /** Cartesian to polar conversion function.
205         * @param x cartesian abscissa of the point
206         * @param y cartesian ordinate of the point
207         * @return radius part of the polar coordinates of the point
208         */
209        public static DifferentialPair hypot(final DifferentialPair x, final DifferentialPair y) {
210            final double x0 = x.getValue();
211            final double y0 = y.getValue();
212            final double h = StrictMath.hypot(x0, y0);
213            return new DifferentialPair(h, (x0 * x.getFirstDerivative() + y0 * y.getFirstDerivative()) / h);
214        }
215    
216    
217        //////////////////////////
218        // hyperbolic functions //
219        //////////////////////////
220    
221        /** Hyperbolic cosine function.
222         * @param a function input value
223         * @return cosh(a)
224         */
225        public static DifferentialPair cosh(final DifferentialPair a) {
226            final double a0 = a.getValue();
227            return new DifferentialPair(StrictMath.cosh(a0), a.getFirstDerivative() * StrictMath.sinh(a0));
228        }
229    
230        /** Hyperbolic sine function.
231         * @param a function input value
232         * @return sinh(a)
233         */
234        public static DifferentialPair sinh(final DifferentialPair a) {
235            final double a0 = a.getValue();
236            return new DifferentialPair(StrictMath.sinh(a0), a.getFirstDerivative() * StrictMath.cosh(a0));
237        }
238    
239        /** Hyperbolic tangent function.
240         * @param a function input value
241         * @return tanh(a)
242         */
243        public static DifferentialPair tanh(final DifferentialPair a) {
244            final double t = StrictMath.tanh(a.getValue());
245            return new DifferentialPair(t, a.getFirstDerivative() * (1 - t * t));
246        }
247    
248        /** Inverse hyperbolic cosine function.
249         * @param a function input value
250         * @return acosh(a)
251         */
252        public static DifferentialPair acosh(final DifferentialPair a) {
253            // the acosh function is not provided by java.lang.StrictMath as of Java6
254            final double a0 = a.getValue();
255            final double root = StrictMath.sqrt(a0 - 1) * StrictMath.sqrt(a0 + 1);
256            return new DifferentialPair(StrictMath.log(a0 + root), a.getFirstDerivative() / root);
257        }
258    
259        /** Inverse hyperbolic sine function.
260         * @param a function input value
261         * @return asinh(a)
262         */
263        public static DifferentialPair asinh(final DifferentialPair a) {
264            // the asinh function is not provided by java.lang.StrictMath as of Java6
265            final double a0 = a.getValue();
266            final double root = StrictMath.sqrt(a0 * a0 + 1);
267            return new DifferentialPair(StrictMath.log(a0 + root), a.getFirstDerivative() / root);
268        }
269    
270        /** Inverse hyperbolic tangent function.
271         * @param a function input value
272         * @return atanh(a)
273         */
274        public static DifferentialPair atanh(final DifferentialPair a) {
275            // the atanh function is not provided by java.lang.StrictMath as of Java6
276            final double a0 = a.getValue();
277            final double ath = (StrictMath.log1p(a0) - StrictMath.log1p(-a0)) / 2;
278            return new DifferentialPair(ath, a.getFirstDerivative() / (1 - a0 * a0));
279        }
280    
281        /////////////////////
282        // power functions //
283        /////////////////////
284    
285        /** Square root function.
286         * @param a function input value
287         * @return &sqrt;a
288         */
289        public static DifferentialPair sqrt(final DifferentialPair a) {
290            final double root = StrictMath.sqrt(a.getValue());
291            return new DifferentialPair(root, a.getFirstDerivative() / (2 * root));
292        }
293    
294        /** Cubic root function.
295         * @param a function input value
296         * @return cbrt(a)
297         */
298        public static DifferentialPair cbrt(final DifferentialPair a) {
299            final double root = StrictMath.cbrt(a.getValue());
300            return new DifferentialPair(root, a.getFirstDerivative() / (3 * root * root));
301        }
302    
303        /** Power function.
304         * @param a base value
305         * @param b exponent value
306         * @return a<sup>b</sup>
307         */
308        public static DifferentialPair pow(final DifferentialPair a, final double b) {
309            final double a0 = a.getValue();
310            final double p = StrictMath.pow(a0, b);
311            return new DifferentialPair(p, a.getFirstDerivative() * b * p / a0);
312        }
313    
314        /** Power function.
315         * @param a base value
316         * @param b exponent value
317         * @return a<sup>b</sup>
318         */
319        public static DifferentialPair pow(final double a, final DifferentialPair b) {
320            final double p = StrictMath.pow(a, b.getValue());
321            return new DifferentialPair(p, b.getFirstDerivative() * StrictMath.log(a) * p);
322        }
323    
324        /** Power function.
325         * @param a base value
326         * @param b exponent value
327         * @return a<sup>b</sup>
328         */
329        public static DifferentialPair pow(final DifferentialPair a, final DifferentialPair b) {
330            final double a0 = a.getValue();
331            final double b0 = b.getValue();
332            final double p = StrictMath.pow(a0, b0);
333            return new DifferentialPair(p, (a.getFirstDerivative() * b0 / a0 + b.getFirstDerivative() * StrictMath.log(a0)) * p);
334        }
335    
336    
337        ////////////////////////////
338        // sign related functions //
339        ////////////////////////////
340    
341        /** Absolute value function.
342         * @param a function input value
343         * @return |a|
344         */
345        public static DifferentialPair abs(final DifferentialPair a) {
346            return (a.getValue() >= 0) ? a : DifferentialPair.negate(a);
347        }
348    
349        /** Sign function.
350         * @param a function input value
351         * @return -1, 0 or +1 according to the sign of a
352         */
353        public static DifferentialPair signum(final DifferentialPair a) {
354            return DifferentialPair.newConstant(StrictMath.signum(a.getValue()));
355        }
356    
357        /** Sign copy function.
358         * @param magnitude function input value
359         * @param sign sign reference
360         * @return either magnitude or -magnitude to match sign
361         */
362        public static DifferentialPair copySign(final DifferentialPair magnitude,
363                                                final double sign) {
364            final long mBits = Double.doubleToLongBits(magnitude.getValue());
365            final long sBits = Double.doubleToLongBits(sign);
366            return (((mBits ^ sBits) & 0x8000000000000000L) == 0) ?
367                    magnitude : DifferentialPair.negate(magnitude);
368        }
369    
370        /** Sign copy function.
371         * @param magnitude function input value
372         * @param sign sign reference
373         * @return either magnitude or -magnitude to match sign
374         */
375        public static DifferentialPair copySign(final double magnitude,
376                                                final DifferentialPair sign) {
377            final long mBits = Double.doubleToLongBits(magnitude);
378            final long sBits = Double.doubleToLongBits(sign.getValue());
379            return (((mBits ^ sBits) & 0x8000000000000000L) == 0) ?
380                   DifferentialPair.newConstant(magnitude) :
381                   DifferentialPair.newConstant(-magnitude);
382        }
383    
384        /** Sign copy function.
385         * @param magnitude function input value
386         * @param sign sign reference
387         * @return either magnitude or -magnitude to match sign
388         */
389        public static DifferentialPair copySign(final DifferentialPair magnitude,
390                                                final DifferentialPair sign) {
391            final long mBits = Double.doubleToLongBits(magnitude.getValue());
392            final long sBits = Double.doubleToLongBits(sign.getValue());
393            return (((mBits ^ sBits) & 0x8000000000000000L) == 0) ?
394                    magnitude : DifferentialPair.negate(magnitude);
395        }
396    
397    
398        ////////////////////////////
399        // neighborhood functions //
400        ////////////////////////////
401    
402        /** Floor function.
403         * @param a function input value
404         * @return largest integer value smaller than a or equal to a
405         */
406        public static DifferentialPair floor(final DifferentialPair a) {
407            return DifferentialPair.newConstant(StrictMath.floor(a.getValue()));
408        }
409    
410        /** Rounding function.
411         * @param a function input value
412         * @return closest integer value to a
413         */
414        public static DifferentialPair rint(final DifferentialPair a) {
415            return DifferentialPair.newConstant(StrictMath.rint(a.getValue()));
416        }
417    
418        /** Ceil function.
419         * @param a function input value
420         * @return smallest integer value greater than a or equal to a
421         */
422        public static DifferentialPair ceil(final DifferentialPair a) {
423            return DifferentialPair.newConstant(StrictMath.ceil(a.getValue()));
424        }
425    
426        /** Neighbor function.
427         * @param a function input value
428         * @return smallest representable double value ly greater than a
429         */
430        public static DifferentialPair nextUp(final DifferentialPair a) {
431            return new DifferentialPair(StrictMath.nextUp(a.getValue()), a.getFirstDerivative());
432        }
433    
434        /** Neighbor function.
435         * @param start function input value
436         * @param direction direction of neighboring (relative to a)
437         * @return closest double value different than a in given direction
438         */
439        public static DifferentialPair nextAfter(final DifferentialPair start,
440                                                 final double direction) {
441            return new DifferentialPair(StrictMath.nextAfter(start.getValue(), direction),
442                                        start.getFirstDerivative());
443        }
444    
445        /** Neighbor function.
446         * @param start function input value
447         * @param direction direction of neighboring (relative to a)
448         * @return closest double value different than a in given direction
449         */
450        public static DifferentialPair nextAfter(final double start,
451                                                 final DifferentialPair direction) {
452            return DifferentialPair.newConstant(StrictMath.nextAfter(start, direction.getValue()));
453        }
454    
455        /** Neighbor function.
456         * @param start function input value
457         * @param direction direction of neighboring (relative to a)
458         * @return closest double value different than a in given direction
459         */
460        public static DifferentialPair nextAfter(final DifferentialPair start,
461                                                 final DifferentialPair direction) {
462            return new DifferentialPair(StrictMath.nextAfter(start.getValue(), direction.getValue()), start.getFirstDerivative());
463        }
464    
465    
466        ////////////////////////
467        // encoding functions //
468        ////////////////////////
469    
470        /** Unit in Last Position function.
471         * @param a function input value
472         * @return value of the least significant bit of a
473         */
474        public static DifferentialPair ulp(final DifferentialPair a) {
475            return DifferentialPair.newConstant(StrictMath.ulp(a.getValue()));
476        }
477    
478        /** Binary rescaling function.
479         * @param a function input value
480         * @param scale exponent part of the 2<sup>scale</sup> multiplication factor
481         * @return a &times; 2<sup>scale</sup>
482         */
483        public static DifferentialPair scalb(final DifferentialPair a,
484                                             final int scale) {
485            return new DifferentialPair(StrictMath.scalb(a.getValue(), scale),
486                                        StrictMath.scalb(a.getFirstDerivative(), scale));
487        }
488    
489        /** Remainder function.
490         * @param f1 dividend
491         * @param f2 divisor
492         * @return remainder of f1/f2, following IEEE754 conventions
493         */
494        public static DifferentialPair IEEEremainder(final DifferentialPair f1,
495                                                     final double f2) {
496            final double r = StrictMath.IEEEremainder(f1.getValue(), f2);
497            return new DifferentialPair(r, f1.getFirstDerivative());
498        }
499    
500        /** Remainder function.
501         * @param f1 dividend
502         * @param f2 divisor
503         * @return remainder of f1/f2, following IEEE754 conventions
504         */
505        public static DifferentialPair IEEEremainder(final double f1,
506                                                     final DifferentialPair f2) {
507            final double f20 = f2.getValue();
508            final double r = StrictMath.IEEEremainder(f1, f20);
509            final int n = (int) ((r - f1) / f20);
510            return new DifferentialPair(r, n * f2.getFirstDerivative());
511        }
512    
513        /** Remainder function.
514         * @param f1 dividend
515         * @param f2 divisor
516         * @return remainder of f1/f2, following IEEE754 conventions
517         */
518        public static DifferentialPair IEEEremainder(final DifferentialPair f1,
519                                                     final DifferentialPair f2) {
520            final double f10 = f1.getValue();
521            final double f20 = f2.getValue();
522            final double r = StrictMath.IEEEremainder(f10, f20);
523            final int n = (int) ((r - f10) / f20);
524            return new DifferentialPair(r, f1.getFirstDerivative() + n * f2.getFirstDerivative());
525        }
526    
527    
528        //////////////////////////
529        // conversion functions //
530        //////////////////////////
531    
532        /** Angular conversion function.
533         * @param a angle in radians
534         * @return angle converted to degrees
535         */
536        public static DifferentialPair toDegrees(final DifferentialPair a) {
537            return new DifferentialPair(StrictMath.toDegrees(a.getValue()), StrictMath.toDegrees(a.getFirstDerivative()));
538        }
539    
540        /** Angular conversion function.
541         * @param a angle in degrees
542         * @return angle converted to radians
543         */
544        public static DifferentialPair toRadians(final DifferentialPair a) {
545            return new DifferentialPair(StrictMath.toRadians(a.getValue()), StrictMath.toRadians(a.getFirstDerivative()));
546        }
547    
548    
549        //////////////////////////
550        // comparison functions //
551        //////////////////////////
552    
553        /** Max function.
554         * @param a first function input value
555         * @param b second function input value
556         * @return maximal value from the (a, b) pair
557         */
558        public static DifferentialPair max(final DifferentialPair a,
559                                           final double b) {
560            return (a.getValue() >= b) ? a : DifferentialPair.newConstant(b);
561        }
562    
563        /** Max function.
564         * @param a first function input value
565         * @param b second function input value
566         * @return maximal value from the (a, b) pair
567         */
568        public static DifferentialPair max(final double a,
569                                           final DifferentialPair b) {
570            return (b.getValue() >= a) ? b : DifferentialPair.newConstant(a);
571        }
572    
573        /** Max function.
574         * @param a first function input value
575         * @param b second function input value
576         * @return maximal value from the (a, b) pair
577         */
578        public static DifferentialPair max(final DifferentialPair a,
579                                           final DifferentialPair b) {
580            return (a.getValue() >= b.getValue()) ? a : b;
581        }
582    
583        /** Min function.
584         * @param a first function input value
585         * @param b second function input value
586         * @return minimal value from the (a, b) pair
587         */
588        public static DifferentialPair min(final DifferentialPair a,
589                                           final double b) {
590            return (a.getValue() <= b) ? a : DifferentialPair.newConstant(b);
591        }
592    
593        /** Min function.
594         * @param a first function input value
595         * @param b second function input value
596         * @return minimal value from the (a, b) pair
597         */
598        public static DifferentialPair min(final double a,
599                                           final DifferentialPair b) {
600            return (b.getValue() <= a) ? b : DifferentialPair.newConstant(a);
601        }
602    
603        /** Min function.
604         * @param a first function input value
605         * @param b second function input value
606         * @return minimal value from the (a, b) pair
607         */
608        public static DifferentialPair min(final DifferentialPair a,
609                                           final DifferentialPair b) {
610            return (a.getValue() <= b.getValue()) ? a : b;
611        }
612    
613    }