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>Math</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.Math</code> class but
024 * using {@link org.apache.commons.nabla.core.DifferentialPair DifferentialPair}
025 * instances instead of doubles.</p>
026 */
027 public class NablaMath {
028
029 /** Hidden constructor.
030 * <p>Since this class is a utility class, it cannot be instantiated.</p>
031 */
032 private NablaMath() {
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 = Math.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 = Math.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(Math.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(Math.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(Math.log10(a0), a.getFirstDerivative() / (a0 * Math.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(Math.cos(a0), -a.getFirstDerivative() * Math.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(Math.sin(a0), a.getFirstDerivative() * Math.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 = Math.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(Math.acos(a0), -a.getFirstDerivative() / Math.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(Math.asin(a0), a.getFirstDerivative() / Math.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(Math.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(Math.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(Math.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(Math.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 = Math.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 = Math.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 = Math.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(Math.cosh(a0), a.getFirstDerivative() * Math.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(Math.sinh(a0), a.getFirstDerivative() * Math.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 = Math.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.Math as of Java6
254 final double a0 = a.getValue();
255 final double root = Math.sqrt(a0 - 1) * Math.sqrt(a0 + 1);
256 return new DifferentialPair(Math.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.Math as of Java6
265 final double a0 = a.getValue();
266 final double root = Math.sqrt(a0 * a0 + 1);
267 return new DifferentialPair(Math.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.Math as of Java6
276 final double a0 = a.getValue();
277 final double ath = (Math.log1p(a0) - Math.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 = Math.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 = Math.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 = Math.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 = Math.pow(a, b.getValue());
321 return new DifferentialPair(p, b.getFirstDerivative() * Math.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 = Math.pow(a0, b0);
333 return new DifferentialPair(p, (a.getFirstDerivative() * b0 / a0 + b.getFirstDerivative() * Math.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(Math.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(Math.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(Math.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(Math.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(Math.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(Math.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(Math.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(Math.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(Math.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 × 2<sup>scale</sup>
482 */
483 public static DifferentialPair scalb(final DifferentialPair a,
484 final int scale) {
485 return new DifferentialPair(Math.scalb(a.getValue(), scale),
486 Math.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 = Math.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 = Math.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 = Math.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(Math.toDegrees(a.getValue()), Math.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(Math.toRadians(a.getValue()), Math.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 }