UnivariateDerivative1.java

  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 Hipparchus project 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.differentiation;

  18. import org.hipparchus.exception.LocalizedCoreFormats;
  19. import org.hipparchus.exception.MathIllegalArgumentException;
  20. import org.hipparchus.util.FastMath;
  21. import org.hipparchus.util.MathArrays;
  22. import org.hipparchus.util.MathUtils;

  23. /** Class representing both the value and the differentials of a function.
  24.  * <p>This class is a stripped-down version of {@link DerivativeStructure}
  25.  * with only one {@link DerivativeStructure#getFreeParameters() free parameter}
  26.  * and {@link DerivativeStructure#getOrder() derivation order} also limited to one.
  27.  * It should have less overhead than {@link DerivativeStructure} in its domain.</p>
  28.  * <p>This class is an implementation of Rall's numbers. Rall's numbers are an
  29.  * extension to the real numbers used throughout mathematical expressions; they hold
  30.  * the derivative together with the value of a function.</p>
  31.  * <p>{@link UnivariateDerivative1} instances can be used directly thanks to
  32.  * the arithmetic operators to the mathematical functions provided as
  33.  * methods by this class (+, -, *, /, %, sin, cos ...).</p>
  34.  * <p>Implementing complex expressions by hand using {@link Derivative}-based
  35.  * classes (or in fact any {@link org.hipparchus.CalculusFieldElement} class) is
  36.  * a tedious and error-prone task but has the advantage of not requiring users
  37.  * to compute the derivatives by themselves and allowing to switch for one
  38.  * derivative implementation to another as they all share the same filed API.</p>
  39.  * <p>Instances of this class are guaranteed to be immutable.</p>
  40.  * @see DerivativeStructure
  41.  * @see UnivariateDerivative2
  42.  * @see Gradient
  43.  * @see FieldDerivativeStructure
  44.  * @see FieldUnivariateDerivative1
  45.  * @see FieldUnivariateDerivative2
  46.  * @see FieldGradient
  47.  * @since 1.7
  48.  */
  49. public class UnivariateDerivative1 extends UnivariateDerivative<UnivariateDerivative1>
  50.         implements Derivative1<UnivariateDerivative1> {

  51.     /** The constant value of π as a {@code UnivariateDerivative1}.
  52.      * @since 2.0
  53.      */
  54.     public static final UnivariateDerivative1 PI = new UnivariateDerivative1(FastMath.PI, 0.0);

  55.     /** Serializable UID. */
  56.     private static final long serialVersionUID = 20200519L;

  57.     /** Value of the function. */
  58.     private final double f0;

  59.     /** First derivative of the function. */
  60.     private final double f1;

  61.     /** Build an instance with values and derivative.
  62.      * @param f0 value of the function
  63.      * @param f1 first derivative of the function
  64.      */
  65.     public UnivariateDerivative1(final double f0, final double f1) {
  66.         this.f0 = f0;
  67.         this.f1 = f1;
  68.     }

  69.     /** Build an instance from a {@link DerivativeStructure}.
  70.      * @param ds derivative structure
  71.      * @exception MathIllegalArgumentException if either {@code ds} parameters
  72.      * is not 1 or {@code ds} order is not 1
  73.      */
  74.     public UnivariateDerivative1(final DerivativeStructure ds) throws MathIllegalArgumentException {
  75.         MathUtils.checkDimension(ds.getFreeParameters(), 1);
  76.         MathUtils.checkDimension(ds.getOrder(), 1);
  77.         this.f0 = ds.getValue();
  78.         this.f1 = ds.getPartialDerivative(1);
  79.     }

  80.     /** {@inheritDoc} */
  81.     @Override
  82.     public UnivariateDerivative1 newInstance(final double value) {
  83.         return new UnivariateDerivative1(value, 0.0);
  84.     }

  85.     /** {@inheritDoc} */
  86.     @Override
  87.     public UnivariateDerivative1 withValue(final double value) {
  88.         return new UnivariateDerivative1(value, f1);
  89.     }

  90.     /** {@inheritDoc} */
  91.     @Override
  92.     public UnivariateDerivative1 getAddendum() {
  93.         return new UnivariateDerivative1(0, f1);
  94.     }

  95.     /** {@inheritDoc} */
  96.     @Override
  97.     public double getValue() {
  98.         return f0;
  99.     }

  100.     /** {@inheritDoc} */
  101.     @Override
  102.     public double getDerivative(final int n) {
  103.         switch (n) {
  104.             case 0 :
  105.                 return f0;
  106.             case 1 :
  107.                 return f1;
  108.             default :
  109.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
  110.         }
  111.     }

  112.     /** Get the first derivative.
  113.      * @return first derivative
  114.      * @see #getValue()
  115.      */
  116.     public double getFirstDerivative() {
  117.         return f1;
  118.     }

  119.     /** {@inheritDoc} */
  120.     @Override
  121.     public DerivativeStructure toDerivativeStructure() {
  122.         return getField().getConversionFactory().build(f0, f1);
  123.     }

  124.     /** {@inheritDoc} */
  125.     @Override
  126.     public UnivariateDerivative1 add(final UnivariateDerivative1 a) {
  127.         return new UnivariateDerivative1(f0 + a.f0, f1 + a.f1);
  128.     }

  129.     /** {@inheritDoc} */
  130.     @Override
  131.     public UnivariateDerivative1 subtract(final UnivariateDerivative1 a) {
  132.         return new UnivariateDerivative1(f0 - a.f0, f1 - a.f1);
  133.     }

  134.     /** {@inheritDoc} */
  135.     @Override
  136.     public UnivariateDerivative1 multiply(final int n) {
  137.         return new UnivariateDerivative1(f0 * n, f1 * n);
  138.     }

  139.     /** {@inheritDoc} */
  140.     @Override
  141.     public UnivariateDerivative1 multiply(final double a) {
  142.         return new UnivariateDerivative1(f0 * a, f1 * a);
  143.     }

  144.     /** {@inheritDoc} */
  145.     @Override
  146.     public UnivariateDerivative1 multiply(final UnivariateDerivative1 a) {
  147.         return new UnivariateDerivative1(f0 * a.f0,
  148.                                          MathArrays.linearCombination(f1, a.f0, f0, a.f1));
  149.     }

  150.     /** {@inheritDoc} */
  151.     @Override
  152.     public UnivariateDerivative1 divide(final double a) {
  153.         final double inv1 = 1.0 / a;
  154.         return new UnivariateDerivative1(f0 * inv1, f1 * inv1);
  155.     }

  156.     /** {@inheritDoc} */
  157.     @Override
  158.     public UnivariateDerivative1 divide(final UnivariateDerivative1 a) {
  159.         final double inv1 = 1.0 / a.f0;
  160.         final double inv2 = inv1 * inv1;
  161.         return new UnivariateDerivative1(f0 * inv1,
  162.                                          MathArrays.linearCombination(f1, a.f0, -f0, a.f1) * inv2);
  163.     }

  164.     /** {@inheritDoc} */
  165.     @Override
  166.     public UnivariateDerivative1 remainder(final UnivariateDerivative1 a) {

  167.         // compute k such that lhs % rhs = lhs - k rhs
  168.         final double rem = FastMath.IEEEremainder(f0, a.f0);
  169.         final double k   = FastMath.rint((f0 - rem) / a.f0);

  170.         return new UnivariateDerivative1(rem, f1 - k * a.f1);

  171.     }

  172.     /** {@inheritDoc} */
  173.     @Override
  174.     public UnivariateDerivative1 negate() {
  175.         return new UnivariateDerivative1(-f0, -f1);
  176.     }

  177.     /** {@inheritDoc} */
  178.     @Override
  179.     public UnivariateDerivative1 abs() {
  180.         if (Double.doubleToLongBits(f0) < 0) {
  181.             // we use the bits representation to also handle -0.0
  182.             return negate();
  183.         } else {
  184.             return this;
  185.         }
  186.     }

  187.     /** {@inheritDoc} */
  188.     @Override
  189.     public UnivariateDerivative1 copySign(final UnivariateDerivative1 sign) {
  190.         long m = Double.doubleToLongBits(f0);
  191.         long s = Double.doubleToLongBits(sign.f0);
  192.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  193.             return this;
  194.         }
  195.         return negate(); // flip sign
  196.     }

  197.     /** {@inheritDoc} */
  198.     @Override
  199.     public UnivariateDerivative1 copySign(final double sign) {
  200.         long m = Double.doubleToLongBits(f0);
  201.         long s = Double.doubleToLongBits(sign);
  202.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  203.             return this;
  204.         }
  205.         return negate(); // flip sign
  206.     }

  207.     /** {@inheritDoc} */
  208.     @Override
  209.     public UnivariateDerivative1 scalb(final int n) {
  210.         return new UnivariateDerivative1(FastMath.scalb(f0, n), FastMath.scalb(f1, n));
  211.     }

  212.     /** {@inheritDoc} */
  213.     @Override
  214.     public UnivariateDerivative1 hypot(final UnivariateDerivative1 y) {

  215.         if (Double.isInfinite(f0) || Double.isInfinite(y.f0)) {
  216.             return new UnivariateDerivative1(Double.POSITIVE_INFINITY, 0.0);
  217.         } else if (Double.isNaN(f0) || Double.isNaN(y.f0)) {
  218.             return new UnivariateDerivative1(Double.NaN, 0.0);
  219.         } else {

  220.             final int expX = getExponent();
  221.             final int expY = y.getExponent();
  222.             if (expX > expY + 27) {
  223.                 // y is negligible with respect to x
  224.                 return abs();
  225.             } else if (expY > expX + 27) {
  226.                 // x is negligible with respect to y
  227.                 return y.abs();
  228.             } else {

  229.                 // find an intermediate scale to avoid both overflow and underflow
  230.                 final int middleExp = (expX + expY) / 2;

  231.                 // scale parameters without losing precision
  232.                 final UnivariateDerivative1 scaledX = scalb(-middleExp);
  233.                 final UnivariateDerivative1 scaledY = y.scalb(-middleExp);

  234.                 // compute scaled hypotenuse
  235.                 final UnivariateDerivative1 scaledH =
  236.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  237.                 // remove scaling
  238.                 return scaledH.scalb(middleExp);

  239.             }

  240.         }
  241.     }

  242.     /** {@inheritDoc} */
  243.     @Override
  244.     public UnivariateDerivative1 compose(final double... f) {
  245.         MathUtils.checkDimension(f.length, getOrder() + 1);
  246.         return compose(f[0], f[1]);
  247.     }

  248.     /** {@inheritDoc} */
  249.     @Override
  250.     public UnivariateDerivative1 compose(final double ff0, final double ff1) {
  251.         return new UnivariateDerivative1(ff0, this.f1 * ff1);
  252.     }

  253.     /** {@inheritDoc} */
  254.     @Override
  255.     public UnivariateDerivative1Field getField() {
  256.         return UnivariateDerivative1Field.getInstance();
  257.     }

  258.     /** Compute a<sup>x</sup> where a is a double and x a {@link UnivariateDerivative1}
  259.      * @param a number to exponentiate
  260.      * @param x power to apply
  261.      * @return a<sup>x</sup>
  262.      */
  263.     public static UnivariateDerivative1 pow(final double a, final UnivariateDerivative1 x) {
  264.         if (a == 0) {
  265.             return x.getField().getZero();
  266.         } else {
  267.             final double aX = FastMath.pow(a, x.f0);
  268.             return new UnivariateDerivative1(aX, FastMath.log(a) * aX * x.f1);
  269.         }
  270.     }

  271.     /** {@inheritDoc} */
  272.     @Override
  273.     public UnivariateDerivative1 pow(final double p) {
  274.         if (p == 0) {
  275.             return getField().getOne();
  276.         } else {
  277.             final double f0Pm1 = FastMath.pow(f0, p - 1);
  278.             return compose(f0Pm1 * f0, p * f0Pm1);
  279.         }
  280.     }

  281.     /** {@inheritDoc} */
  282.     @Override
  283.     public UnivariateDerivative1 pow(final int n) {
  284.         if (n == 0) {
  285.             return getField().getOne();
  286.         } else {
  287.             final double f0Nm1 = FastMath.pow(f0, n - 1);
  288.             return compose(f0Nm1 * f0, n * f0Nm1);
  289.         }
  290.     }

  291.     /** {@inheritDoc} */
  292.     @Override
  293.     public UnivariateDerivative1 atan2(final UnivariateDerivative1 x) {
  294.         final double inv = 1.0 / (f0 * f0 + x.f0 * x.f0);
  295.         return new UnivariateDerivative1(FastMath.atan2(f0, x.f0),
  296.                                          MathArrays.linearCombination(x.f0, f1, -x.f1, f0) * inv);
  297.     }

  298.     /** {@inheritDoc} */
  299.     @Override
  300.     public UnivariateDerivative1 toDegrees() {
  301.         return new UnivariateDerivative1(FastMath.toDegrees(f0), FastMath.toDegrees(f1));
  302.     }

  303.     /** {@inheritDoc} */
  304.     @Override
  305.     public UnivariateDerivative1 toRadians() {
  306.         return new UnivariateDerivative1(FastMath.toRadians(f0), FastMath.toRadians(f1));
  307.     }

  308.     /** Evaluate Taylor expansion a univariate derivative.
  309.      * @param delta parameter offset Δx
  310.      * @return value of the Taylor expansion at x + Δx
  311.      */
  312.     public double taylor(final double delta) {
  313.         return f0 + delta * f1;
  314.     }

  315.     /** {@inheritDoc} */
  316.     @Override
  317.     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1[] a, final UnivariateDerivative1[] b) {

  318.         // extract values and first derivatives
  319.         final int      n  = a.length;
  320.         final double[] a0 = new double[n];
  321.         final double[] b0 = new double[n];
  322.         final double[] a1 = new double[2 * n];
  323.         final double[] b1 = new double[2 * n];
  324.         for (int i = 0; i < n; ++i) {
  325.             final UnivariateDerivative1 ai = a[i];
  326.             final UnivariateDerivative1 bi = b[i];
  327.             a0[i]         = ai.f0;
  328.             b0[i]         = bi.f0;
  329.             a1[2 * i]     = ai.f0;
  330.             a1[2 * i + 1] = ai.f1;
  331.             b1[2 * i]     = bi.f1;
  332.             b1[2 * i + 1] = bi.f0;
  333.         }

  334.         return new UnivariateDerivative1(MathArrays.linearCombination(a0, b0),
  335.                                          MathArrays.linearCombination(a1, b1));

  336.     }

  337.     /** {@inheritDoc} */
  338.     @Override
  339.     public UnivariateDerivative1 linearCombination(final double[] a, final UnivariateDerivative1[] b) {

  340.         // extract values and first derivatives
  341.         final int      n  = b.length;
  342.         final double[] b0 = new double[n];
  343.         final double[] b1 = new double[n];
  344.         for (int i = 0; i < n; ++i) {
  345.             b0[i] = b[i].f0;
  346.             b1[i] = b[i].f1;
  347.         }

  348.         return new UnivariateDerivative1(MathArrays.linearCombination(a, b0),
  349.                                          MathArrays.linearCombination(a, b1));

  350.     }

  351.     /** {@inheritDoc} */
  352.     @Override
  353.     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1 a1, final UnivariateDerivative1 b1,
  354.                                                    final UnivariateDerivative1 a2, final UnivariateDerivative1 b2) {
  355.         return new UnivariateDerivative1(MathArrays.linearCombination(a1.f0, b1.f0,
  356.                                                                       a2.f0, b2.f0),
  357.                                          MathArrays.linearCombination(a1.f0, b1.f1,
  358.                                                                       a1.f1, b1.f0,
  359.                                                                       a2.f0, b2.f1,
  360.                                                                       a2.f1, b2.f0));
  361.     }

  362.     /** {@inheritDoc} */
  363.     @Override
  364.     public UnivariateDerivative1 linearCombination(final double a1, final UnivariateDerivative1 b1,
  365.                                                    final double a2, final UnivariateDerivative1 b2) {
  366.         return new UnivariateDerivative1(MathArrays.linearCombination(a1, b1.f0,
  367.                                                                       a2, b2.f0),
  368.                                          MathArrays.linearCombination(a1, b1.f1,
  369.                                                                       a2, b2.f1));
  370.     }

  371.     /** {@inheritDoc} */
  372.     @Override
  373.     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1 a1, final UnivariateDerivative1 b1,
  374.                                                    final UnivariateDerivative1 a2, final UnivariateDerivative1 b2,
  375.                                                    final UnivariateDerivative1 a3, final UnivariateDerivative1 b3) {
  376.         return new UnivariateDerivative1(MathArrays.linearCombination(a1.f0, b1.f0,
  377.                                                                       a2.f0, b2.f0,
  378.                                                                       a3.f0, b3.f0),
  379.                                          MathArrays.linearCombination(new double[] {
  380.                                                                           a1.f0, a1.f1,
  381.                                                                           a2.f0, a2.f1,
  382.                                                                           a3.f0, a3.f1
  383.                                                                       }, new double[] {
  384.                                                                           b1.f1, b1.f0,
  385.                                                                           b2.f1, b2.f0,
  386.                                                                           b3.f1, b3.f0
  387.                                                                       }));
  388.     }

  389.     /** {@inheritDoc} */
  390.     @Override
  391.     public UnivariateDerivative1 linearCombination(final double a1, final UnivariateDerivative1 b1,
  392.                                                    final double a2, final UnivariateDerivative1 b2,
  393.                                                    final double a3, final UnivariateDerivative1 b3) {
  394.         return new UnivariateDerivative1(MathArrays.linearCombination(a1, b1.f0,
  395.                                                                       a2, b2.f0,
  396.                                                                       a3, b3.f0),
  397.                                          MathArrays.linearCombination(a1, b1.f1,
  398.                                                                       a2, b2.f1,
  399.                                                                       a3, b3.f1));
  400.     }

  401.     /** {@inheritDoc} */
  402.     @Override
  403.     public UnivariateDerivative1 linearCombination(final UnivariateDerivative1 a1, final UnivariateDerivative1 b1,
  404.                                                    final UnivariateDerivative1 a2, final UnivariateDerivative1 b2,
  405.                                                    final UnivariateDerivative1 a3, final UnivariateDerivative1 b3,
  406.                                                    final UnivariateDerivative1 a4, final UnivariateDerivative1 b4) {
  407.         return new UnivariateDerivative1(MathArrays.linearCombination(a1.f0, b1.f0,
  408.                                                                       a2.f0, b2.f0,
  409.                                                                       a3.f0, b3.f0,
  410.                                                                       a4.f0, b4.f0),
  411.                                          MathArrays.linearCombination(new double[] {
  412.                                                                           a1.f0, a1.f1,
  413.                                                                           a2.f0, a2.f1,
  414.                                                                           a3.f0, a3.f1,
  415.                                                                           a4.f0, a4.f1
  416.                                                                       }, new double[] {
  417.                                                                           b1.f1, b1.f0,
  418.                                                                           b2.f1, b2.f0,
  419.                                                                           b3.f1, b3.f0,
  420.                                                                           b4.f1, b4.f0
  421.                                                                       }));
  422.     }

  423.     /** {@inheritDoc} */
  424.     @Override
  425.     public UnivariateDerivative1 linearCombination(final double a1, final UnivariateDerivative1 b1,
  426.                                                    final double a2, final UnivariateDerivative1 b2,
  427.                                                    final double a3, final UnivariateDerivative1 b3,
  428.                                                    final double a4, final UnivariateDerivative1 b4) {
  429.         return new UnivariateDerivative1(MathArrays.linearCombination(a1, b1.f0,
  430.                                                                       a2, b2.f0,
  431.                                                                       a3, b3.f0,
  432.                                                                       a4, b4.f0),
  433.                                          MathArrays.linearCombination(a1, b1.f1,
  434.                                                                       a2, b2.f1,
  435.                                                                       a3, b3.f1,
  436.                                                                       a4, b4.f1));
  437.     }

  438.     /** {@inheritDoc} */
  439.     @Override
  440.     public UnivariateDerivative1 getPi() {
  441.         return PI;
  442.     }

  443.     /** Test for the equality of two univariate derivatives.
  444.      * <p>
  445.      * univariate derivatives are considered equal if they have the same derivatives.
  446.      * </p>
  447.      * @param other Object to test for equality to this
  448.      * @return true if two univariate derivatives are equal
  449.      */
  450.     @Override
  451.     public boolean equals(Object other) {

  452.         if (this == other) {
  453.             return true;
  454.         }

  455.         if (other instanceof UnivariateDerivative1) {
  456.             final UnivariateDerivative1 rhs = (UnivariateDerivative1) other;
  457.             return f0 == rhs.f0 && f1 == rhs.f1;
  458.         }

  459.         return false;

  460.     }

  461.     /** Get a hashCode for the univariate derivative.
  462.      * @return a hash code value for this object
  463.      */
  464.     @Override
  465.     public int hashCode() {
  466.         return 453 - 19 * Double.hashCode(f0) + 37 * Double.hashCode(f1);
  467.     }

  468.     /** {@inheritDoc}
  469.      * <p>
  470.      * Comparison performed considering that derivatives are intrinsically linked to monomials in the corresponding
  471.      * Taylor expansion and that the higher the degree, the smaller the term.
  472.      * </p>
  473.      * @since 3.0
  474.      */
  475.     @Override
  476.     public int compareTo(final UnivariateDerivative1 o) {
  477.         final int cF0 = Double.compare(f0, o.getReal());
  478.         if (cF0 == 0) {
  479.             return Double.compare(f1, o.getFirstDerivative());
  480.         } else {
  481.             return cF0;
  482.         }
  483.     }

  484. }