UnivariateDerivative2.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.FieldSinCos;
  22. import org.hipparchus.util.FieldSinhCosh;
  23. import org.hipparchus.util.MathArrays;
  24. import org.hipparchus.util.MathUtils;
  25. import org.hipparchus.util.SinCos;
  26. import org.hipparchus.util.SinhCosh;

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

  54.     /** The constant value of π as a {@code UnivariateDerivative2}.
  55.      * @since 2.0
  56.      */
  57.     public static final UnivariateDerivative2 PI = new UnivariateDerivative2(FastMath.PI, 0.0, 0.0);

  58.     /** Serializable UID. */
  59.     private static final long serialVersionUID = 20200520L;

  60.     /** Value of the function. */
  61.     private final double f0;

  62.     /** First derivative of the function. */
  63.     private final double f1;

  64.     /** Second derivative of the function. */
  65.     private final double f2;

  66.     /** Build an instance with values and derivative.
  67.      * @param f0 value of the function
  68.      * @param f1 first derivative of the function
  69.      * @param f2 second derivative of the function
  70.      */
  71.     public UnivariateDerivative2(final double f0, final double f1, final double f2) {
  72.         this.f0 = f0;
  73.         this.f1 = f1;
  74.         this.f2 = f2;
  75.     }

  76.     /** Build an instance from a {@link DerivativeStructure}.
  77.      * @param ds derivative structure
  78.      * @exception MathIllegalArgumentException if either {@code ds} parameters
  79.      * is not 1 or {@code ds} order is not 2
  80.      */
  81.     public UnivariateDerivative2(final DerivativeStructure ds) throws MathIllegalArgumentException {
  82.         MathUtils.checkDimension(ds.getFreeParameters(), 1);
  83.         MathUtils.checkDimension(ds.getOrder(), 2);
  84.         this.f0 = ds.getValue();
  85.         this.f1 = ds.getPartialDerivative(1);
  86.         this.f2 = ds.getPartialDerivative(2);
  87.     }

  88.     /** {@inheritDoc} */
  89.     @Override
  90.     public UnivariateDerivative2 newInstance(final double value) {
  91.         return new UnivariateDerivative2(value, 0.0, 0.0);
  92.     }

  93.     @Override
  94.     public UnivariateDerivative2 withValue(final double value) {
  95.         return new UnivariateDerivative2(value, f1, f2);
  96.     }

  97.     /** {@inheritDoc} */
  98.     @Override
  99.     public UnivariateDerivative2 getAddendum() {
  100.         return new UnivariateDerivative2(0, f1, f2);
  101.     }

  102.     /** {@inheritDoc} */
  103.     @Override
  104.     public double getValue() {
  105.         return f0;
  106.     }

  107.     /** {@inheritDoc} */
  108.     @Override
  109.     public double getDerivative(final int n) {
  110.         switch (n) {
  111.             case 0 :
  112.                 return f0;
  113.             case 1 :
  114.                 return f1;
  115.             case 2 :
  116.                 return f2;
  117.             default :
  118.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
  119.         }
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public int getOrder() {
  124.         return 2;
  125.     }

  126.     /** Get the first derivative.
  127.      * @return first derivative
  128.      * @see #getValue()
  129.      * @see #getSecondDerivative()
  130.      */
  131.     public double getFirstDerivative() {
  132.         return f1;
  133.     }

  134.     /** Get the second derivative.
  135.      * @return second derivative
  136.      * @see #getValue()
  137.      * @see #getFirstDerivative()
  138.      */
  139.     public double getSecondDerivative() {
  140.         return f2;
  141.     }

  142.     /** {@inheritDoc} */
  143.     @Override
  144.     public DerivativeStructure toDerivativeStructure() {
  145.         return getField().getConversionFactory().build(f0, f1, f2);
  146.     }

  147.     /** {@inheritDoc} */
  148.     @Override
  149.     public UnivariateDerivative2 add(final UnivariateDerivative2 a) {
  150.         return new UnivariateDerivative2(f0 + a.f0, f1 + a.f1, f2 + a.f2);
  151.     }

  152.     /** {@inheritDoc} */
  153.     @Override
  154.     public UnivariateDerivative2 subtract(final UnivariateDerivative2 a) {
  155.         return new UnivariateDerivative2(f0 - a.f0, f1 - a.f1, f2 - a.f2);
  156.     }

  157.     /** {@inheritDoc} */
  158.     @Override
  159.     public UnivariateDerivative2 multiply(final int n) {
  160.         return new UnivariateDerivative2(f0 * n, f1 * n, f2 * n);
  161.     }

  162.     /** {@inheritDoc} */
  163.     @Override
  164.     public UnivariateDerivative2 multiply(final double a) {
  165.         return new UnivariateDerivative2(f0 * a, f1 * a, f2 * a);
  166.     }

  167.     /** {@inheritDoc} */
  168.     @Override
  169.     public UnivariateDerivative2 multiply(final UnivariateDerivative2 a) {
  170.         return new UnivariateDerivative2(f0 * a.f0,
  171.                                          MathArrays.linearCombination(f1, a.f0, f0, a.f1),
  172.                                          MathArrays.linearCombination(f2, a.f0, 2 * f1, a.f1, f0, a.f2));
  173.     }

  174.     /** {@inheritDoc} */
  175.     @Override
  176.     public UnivariateDerivative2 square() {
  177.         return new UnivariateDerivative2(f0 * f0, 2 * f0 * f1, 2 * (f0 * f2 + f1 * f1));
  178.     }

  179.     /** {@inheritDoc} */
  180.     @Override
  181.     public UnivariateDerivative2 divide(final double a) {
  182.         final double inv1 = 1.0 / a;
  183.         return new UnivariateDerivative2(f0 * inv1, f1 * inv1, f2 * inv1);
  184.     }

  185.     /** {@inheritDoc} */
  186.     @Override
  187.     public UnivariateDerivative2 divide(final UnivariateDerivative2 a) {
  188.         final double inv1 = 1.0 / a.f0;
  189.         final double inv2 = inv1 * inv1;
  190.         final double inv3 = inv1 * inv2;
  191.         return new UnivariateDerivative2(f0 * inv1,
  192.                                          MathArrays.linearCombination(f1, a.f0, -f0, a.f1) * inv2,
  193.                                          MathArrays.linearCombination(f2, a.f0 * a.f0,
  194.                                                                       -2 * f1, a.f0 * a.f1,
  195.                                                                        2 * f0, a.f1 * a.f1,
  196.                                                                        -f0, a.f0 * a.f2) * inv3);
  197.     }

  198.     /** {@inheritDoc} */
  199.     @Override
  200.     public UnivariateDerivative2 remainder(final UnivariateDerivative2 a) {

  201.         // compute k such that lhs % rhs = lhs - k rhs
  202.         final double rem = FastMath.IEEEremainder(f0, a.f0);
  203.         final double k   = FastMath.rint((f0 - rem) / a.f0);

  204.         return new UnivariateDerivative2(rem, f1 - k * a.f1, f2 - k * a.f2);

  205.     }

  206.     /** {@inheritDoc} */
  207.     @Override
  208.     public UnivariateDerivative2 negate() {
  209.         return new UnivariateDerivative2(-f0, -f1, -f2);
  210.     }

  211.     /** {@inheritDoc} */
  212.     @Override
  213.     public UnivariateDerivative2 abs() {
  214.         if (Double.doubleToLongBits(f0) < 0) {
  215.             // we use the bits representation to also handle -0.0
  216.             return negate();
  217.         } else {
  218.             return this;
  219.         }
  220.     }

  221.     /** {@inheritDoc} */
  222.     @Override
  223.     public UnivariateDerivative2 copySign(final UnivariateDerivative2 sign) {
  224.         long m = Double.doubleToLongBits(f0);
  225.         long s = Double.doubleToLongBits(sign.f0);
  226.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  227.             return this;
  228.         }
  229.         return negate(); // flip sign
  230.     }

  231.     /** {@inheritDoc} */
  232.     @Override
  233.     public UnivariateDerivative2 copySign(final double sign) {
  234.         long m = Double.doubleToLongBits(f0);
  235.         long s = Double.doubleToLongBits(sign);
  236.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  237.             return this;
  238.         }
  239.         return negate(); // flip sign
  240.     }

  241.     /** {@inheritDoc} */
  242.     @Override
  243.     public UnivariateDerivative2 scalb(final int n) {
  244.         return new UnivariateDerivative2(FastMath.scalb(f0, n), FastMath.scalb(f1, n), FastMath.scalb(f2, n));
  245.     }

  246.     /** {@inheritDoc} */
  247.     @Override
  248.     public UnivariateDerivative2 hypot(final UnivariateDerivative2 y) {

  249.         if (Double.isInfinite(f0) || Double.isInfinite(y.f0)) {
  250.             return new UnivariateDerivative2(Double.POSITIVE_INFINITY, 0.0, 0.0);
  251.         } else if (Double.isNaN(f0) || Double.isNaN(y.f0)) {
  252.             return new UnivariateDerivative2(Double.NaN, 0.0, 0.0);
  253.         } else {

  254.             final int expX = getExponent();
  255.             final int expY = y.getExponent();
  256.             if (expX > expY + 27) {
  257.                 // y is negligible with respect to x
  258.                 return abs();
  259.             } else if (expY > expX + 27) {
  260.                 // x is negligible with respect to y
  261.                 return y.abs();
  262.             } else {

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

  265.                 // scale parameters without losing precision
  266.                 final UnivariateDerivative2 scaledX = scalb(-middleExp);
  267.                 final UnivariateDerivative2 scaledY = y.scalb(-middleExp);

  268.                 // compute scaled hypotenuse
  269.                 final UnivariateDerivative2 scaledH =
  270.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  271.                 // remove scaling
  272.                 return scaledH.scalb(middleExp);

  273.             }

  274.         }
  275.     }

  276.     /** {@inheritDoc} */
  277.     @Override
  278.     public UnivariateDerivative2 reciprocal() {
  279.         final double inv1 = 1.0 / f0;
  280.         final double inv2 = inv1 * inv1;
  281.         final double inv3 = inv1 * inv2;
  282.         return new UnivariateDerivative2(inv1, -f1 * inv2, MathArrays.linearCombination(2 * f1, f1, -f0, f2) * inv3);
  283.     }

  284.     /** {@inheritDoc} */
  285.     @Override
  286.     public UnivariateDerivative2 compose(final double... f) {
  287.         MathUtils.checkDimension(f.length, getOrder() + 1);
  288.         return new UnivariateDerivative2(f[0],
  289.                                          f[1] * f1,
  290.                                          MathArrays.linearCombination(f[1], f2, f[2], f1 * f1));
  291.     }

  292.     /** {@inheritDoc} */
  293.     @Override
  294.     public UnivariateDerivative2 sqrt() {
  295.         final double s0 = FastMath.sqrt(f0);
  296.         final double s0twice = 2. * s0;
  297.         final double s1 = f1 / s0twice;
  298.         final double s2 = (f2 - 2. * s1 * s1) / s0twice;
  299.         return new UnivariateDerivative2(s0, s1, s2);
  300.     }

  301.     /** {@inheritDoc} */
  302.     @Override
  303.     public UnivariateDerivative2 cbrt() {
  304.         final double c  = FastMath.cbrt(f0);
  305.         final double c2 = c * c;
  306.         return compose(c, 1 / (3 * c2), -1 / (4.5 * c2 * f0));
  307.     }

  308.     /** {@inheritDoc} */
  309.     @Override
  310.     public UnivariateDerivative2 rootN(final int n) {
  311.         if (n == 2) {
  312.             return sqrt();
  313.         } else if (n == 3) {
  314.             return cbrt();
  315.         } else {
  316.             final double r = FastMath.pow(f0, 1.0 / n);
  317.             final double z = n * FastMath.pow(r, n - 1);
  318.             return compose(r, 1 / z, (1 - n) / (z * z * r));
  319.         }
  320.     }

  321.     /** {@inheritDoc} */
  322.     @Override
  323.     public UnivariateDerivative2Field getField() {
  324.         return UnivariateDerivative2Field.getInstance();
  325.     }

  326.     /** Compute a<sup>x</sup> where a is a double and x a {@link UnivariateDerivative2}
  327.      * @param a number to exponentiate
  328.      * @param x power to apply
  329.      * @return a<sup>x</sup>
  330.      */
  331.     public static UnivariateDerivative2 pow(final double a, final UnivariateDerivative2 x) {
  332.         if (a == 0) {
  333.             return x.getField().getZero();
  334.         } else {
  335.             final double aX    = FastMath.pow(a, x.f0);
  336.             final double lnA   = FastMath.log(a);
  337.             final double aXlnA = aX * lnA;
  338.             return new UnivariateDerivative2(aX, aXlnA * x.f1, aXlnA * (x.f1 * x.f1 * lnA + x.f2));
  339.         }
  340.     }

  341.     /** {@inheritDoc} */
  342.     @Override
  343.     public UnivariateDerivative2 pow(final double p) {
  344.         if (p == 0) {
  345.             return getField().getOne();
  346.         } else {
  347.             final double f0Pm2 = FastMath.pow(f0, p - 2);
  348.             final double f0Pm1 = f0Pm2 * f0;
  349.             final double f0P   = f0Pm1 * f0;
  350.             return compose(f0P, p * f0Pm1, p * (p - 1) * f0Pm2);
  351.         }
  352.     }

  353.     /** {@inheritDoc} */
  354.     @Override
  355.     public UnivariateDerivative2 pow(final int n) {
  356.         if (n == 0) {
  357.             return getField().getOne();
  358.         } else {
  359.             final double f0Nm2 = FastMath.pow(f0, n - 2);
  360.             final double f0Nm1 = f0Nm2 * f0;
  361.             final double f0N   = f0Nm1 * f0;
  362.             return compose(f0N, n * f0Nm1, n * (n - 1) * f0Nm2);
  363.         }
  364.     }

  365.     /** {@inheritDoc} */
  366.     @Override
  367.     public UnivariateDerivative2 exp() {
  368.         final double exp = FastMath.exp(f0);
  369.         return compose(exp, exp, exp);
  370.     }

  371.     /** {@inheritDoc} */
  372.     @Override
  373.     public UnivariateDerivative2 expm1() {
  374.         final double exp   = FastMath.exp(f0);
  375.         final double expM1 = FastMath.expm1(f0);
  376.         return compose(expM1, exp, exp);
  377.     }

  378.     /** {@inheritDoc} */
  379.     @Override
  380.     public UnivariateDerivative2 log() {
  381.         final double inv = 1 / f0;
  382.         return compose(FastMath.log(f0), inv, -inv * inv);
  383.     }

  384.     /** {@inheritDoc} */
  385.     @Override
  386.     public UnivariateDerivative2 log1p() {
  387.         final double inv = 1 / (1 + f0);
  388.         return compose(FastMath.log1p(f0), inv, -inv * inv);
  389.     }

  390.     /** {@inheritDoc} */
  391.     @Override
  392.     public UnivariateDerivative2 log10() {
  393.         final double invF0 = 1 / f0;
  394.         final double inv = invF0 / FastMath.log(10.0);
  395.         return compose(FastMath.log10(f0), inv, -inv * invF0);
  396.     }

  397.     /** {@inheritDoc} */
  398.     @Override
  399.     public UnivariateDerivative2 cos() {
  400.         final SinCos sinCos = FastMath.sinCos(f0);
  401.         return compose(sinCos.cos(), -sinCos.sin(), -sinCos.cos());
  402.     }

  403.     /** {@inheritDoc} */
  404.     @Override
  405.     public UnivariateDerivative2 sin() {
  406.         final SinCos sinCos = FastMath.sinCos(f0);
  407.         return compose(sinCos.sin(), sinCos.cos(), -sinCos.sin());
  408.     }

  409.     /** {@inheritDoc} */
  410.     @Override
  411.     public FieldSinCos<UnivariateDerivative2> sinCos() {
  412.         final SinCos sinCos = FastMath.sinCos(f0);
  413.         return new FieldSinCos<>(compose(sinCos.sin(),  sinCos.cos(), -sinCos.sin()),
  414.                                  compose(sinCos.cos(), -sinCos.sin(), -sinCos.cos()));
  415.     }

  416.     /** {@inheritDoc} */
  417.     @Override
  418.     public UnivariateDerivative2 tan() {
  419.         final double tan  = FastMath.tan(f0);
  420.         final double sec2 = 1 + tan * tan;
  421.         return compose(tan, sec2, 2 * sec2 * tan);
  422.     }

  423.     /** {@inheritDoc} */
  424.     @Override
  425.     public UnivariateDerivative2 acos() {
  426.         final double inv = 1.0 / (1 - f0 * f0);
  427.         final double mS  = -FastMath.sqrt(inv);
  428.         return compose(FastMath.acos(f0), mS, mS * f0 * inv);
  429.     }

  430.     /** {@inheritDoc} */
  431.     @Override
  432.     public UnivariateDerivative2 asin() {
  433.         final double inv = 1.0 / (1 - f0 * f0);
  434.         final double s   = FastMath.sqrt(inv);
  435.         return compose(FastMath.asin(f0), s, s * f0 * inv);
  436.     }

  437.     /** {@inheritDoc} */
  438.     @Override
  439.     public UnivariateDerivative2 atan() {
  440.         final double inv = 1 / (1 + f0 * f0);
  441.         return compose(FastMath.atan(f0), inv, -2 * f0 * inv * inv);
  442.     }

  443.     /** {@inheritDoc} */
  444.     @Override
  445.     public UnivariateDerivative2 atan2(final UnivariateDerivative2 x) {
  446.         final double x2    = x.f0 * x.f0;
  447.         final double f02   = f0 + f0;
  448.         final double inv   = 1.0 / (f0 * f0 + x2);
  449.         final double atan0 = FastMath.atan2(f0, x.f0);
  450.         final double atan1 = MathArrays.linearCombination(x.f0, f1, -x.f1, f0) * inv;
  451.         final double c     = MathArrays.linearCombination(f2, x2,
  452.                                                           -2 * f1, x.f0 * x.f1,
  453.                                                           f02, x.f1 * x.f1,
  454.                                                           -f0, x.f0 * x.f2) * inv;
  455.         return new UnivariateDerivative2(atan0, atan1, (c - f02 * atan1 * atan1) / x.f0);
  456.     }

  457.     /** {@inheritDoc} */
  458.     @Override
  459.     public UnivariateDerivative2 cosh() {
  460.         final double c = FastMath.cosh(f0);
  461.         final double s = FastMath.sinh(f0);
  462.         return compose(c, s, c);
  463.     }

  464.     /** {@inheritDoc} */
  465.     @Override
  466.     public UnivariateDerivative2 sinh() {
  467.         final double c = FastMath.cosh(f0);
  468.         final double s = FastMath.sinh(f0);
  469.         return compose(s, c, s);
  470.     }

  471.     /** {@inheritDoc} */
  472.     @Override
  473.     public FieldSinhCosh<UnivariateDerivative2> sinhCosh() {
  474.         final SinhCosh sinhCosh = FastMath.sinhCosh(f0);
  475.         return new FieldSinhCosh<>(compose(sinhCosh.sinh(), sinhCosh.cosh(), sinhCosh.sinh()),
  476.                                    compose(sinhCosh.cosh(), sinhCosh.sinh(), sinhCosh.cosh()));
  477.     }

  478.     /** {@inheritDoc} */
  479.     @Override
  480.     public UnivariateDerivative2 tanh() {
  481.         final double tanh  = FastMath.tanh(f0);
  482.         final double sech2 = 1 - tanh * tanh;
  483.         return compose(tanh, sech2, -2 * sech2 * tanh);
  484.     }

  485.     /** {@inheritDoc} */
  486.     @Override
  487.     public UnivariateDerivative2 acosh() {
  488.         final double inv = 1 / (f0 * f0 - 1);
  489.         final double s   = FastMath.sqrt(inv);
  490.         return compose(FastMath.acosh(f0), s, -f0 * s * inv);
  491.     }

  492.     /** {@inheritDoc} */
  493.     @Override
  494.     public UnivariateDerivative2 asinh() {
  495.         final double inv = 1 / (f0 * f0 + 1);
  496.         final double s   = FastMath.sqrt(inv);
  497.         return compose(FastMath.asinh(f0), s, -f0 * s * inv);
  498.     }

  499.     /** {@inheritDoc} */
  500.     @Override
  501.     public UnivariateDerivative2 atanh() {
  502.         final double inv = 1 / (1 - f0 * f0);
  503.         return compose(FastMath.atanh(f0), inv, 2 * f0 * inv * inv);
  504.     }

  505.     /** {@inheritDoc} */
  506.     @Override
  507.     public UnivariateDerivative2 toDegrees() {
  508.         return new UnivariateDerivative2(FastMath.toDegrees(f0), FastMath.toDegrees(f1), FastMath.toDegrees(f2));
  509.     }

  510.     /** {@inheritDoc} */
  511.     @Override
  512.     public UnivariateDerivative2 toRadians() {
  513.         return new UnivariateDerivative2(FastMath.toRadians(f0), FastMath.toRadians(f1), FastMath.toRadians(f2));
  514.     }

  515.     /** Evaluate Taylor expansion a univariate derivative.
  516.      * @param delta parameter offset Δx
  517.      * @return value of the Taylor expansion at x + Δx
  518.      */
  519.     public double taylor(final double delta) {
  520.         return f0 + delta * (f1 + 0.5 * delta * f2);
  521.     }

  522.     /** {@inheritDoc} */
  523.     @Override
  524.     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2[] a, final UnivariateDerivative2[] b) {

  525.         // extract values and derivatives
  526.         final int      n  = a.length;
  527.         final double[] a0 = new double[n];
  528.         final double[] b0 = new double[n];
  529.         final double[] a1 = new double[2 * n];
  530.         final double[] b1 = new double[2 * n];
  531.         final double[] a2 = new double[3 * n];
  532.         final double[] b2 = new double[3 * n];
  533.         for (int i = 0; i < n; ++i) {
  534.             final UnivariateDerivative2 ai = a[i];
  535.             final UnivariateDerivative2 bi = b[i];
  536.             a0[i]         = ai.f0;
  537.             b0[i]         = bi.f0;
  538.             a1[2 * i]     = ai.f0;
  539.             a1[2 * i + 1] = ai.f1;
  540.             b1[2 * i]     = bi.f1;
  541.             b1[2 * i + 1] = bi.f0;
  542.             a2[3 * i]     = ai.f0;
  543.             a2[3 * i + 1] = ai.f1 + ai.f1;
  544.             a2[3 * i + 2] = ai.f2;
  545.             b2[3 * i]     = bi.f2;
  546.             b2[3 * i + 1] = bi.f1;
  547.             b2[3 * i + 2] = bi.f0;
  548.         }

  549.         return new UnivariateDerivative2(MathArrays.linearCombination(a0, b0),
  550.                                          MathArrays.linearCombination(a1, b1),
  551.                                          MathArrays.linearCombination(a2, b2));

  552.     }

  553.     /** {@inheritDoc} */
  554.     @Override
  555.     public UnivariateDerivative2 linearCombination(final double[] a, final UnivariateDerivative2[] b) {

  556.         // extract values and derivatives
  557.         final int      n  = b.length;
  558.         final double[] b0 = new double[n];
  559.         final double[] b1 = new double[n];
  560.         final double[] b2 = new double[n];
  561.         for (int i = 0; i < n; ++i) {
  562.             b0[i] = b[i].f0;
  563.             b1[i] = b[i].f1;
  564.             b2[i] = b[i].f2;
  565.         }

  566.         return new UnivariateDerivative2(MathArrays.linearCombination(a, b0),
  567.                                          MathArrays.linearCombination(a, b1),
  568.                                          MathArrays.linearCombination(a, b2));

  569.     }

  570.     /** {@inheritDoc} */
  571.     @Override
  572.     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
  573.                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2) {
  574.         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
  575.                                                                       a2.f0, b2.f0),
  576.                                          MathArrays.linearCombination(a1.f0, b1.f1,
  577.                                                                       a1.f1, b1.f0,
  578.                                                                       a2.f0, b2.f1,
  579.                                                                       a2.f1, b2.f0),
  580.                                          MathArrays.linearCombination(new double[] {
  581.                                                                           a1.f0, 2 * a1.f1, a1.f2,
  582.                                                                           a2.f0, 2 * a2.f1, a2.f2
  583.                                                                       }, new double[] {
  584.                                                                           b1.f2, b1.f1, b1.f0,
  585.                                                                           b2.f2, b2.f1, b2.f0
  586.                                                                       }));
  587.     }

  588.     /** {@inheritDoc} */
  589.     @Override
  590.     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
  591.                                                    final double a2, final UnivariateDerivative2 b2) {
  592.         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
  593.                                                                       a2, b2.f0),
  594.                                          MathArrays.linearCombination(a1, b1.f1,
  595.                                                                       a2, b2.f1),
  596.                                          MathArrays.linearCombination(a1, b1.f2,
  597.                                                                       a2, b2.f2));
  598.     }

  599.     /** {@inheritDoc} */
  600.     @Override
  601.     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
  602.                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2,
  603.                                                    final UnivariateDerivative2 a3, final UnivariateDerivative2 b3) {
  604.         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
  605.                                                                       a2.f0, b2.f0,
  606.                                                                       a3.f0, b3.f0),
  607.                                          MathArrays.linearCombination(new double[] {
  608.                                                                           a1.f0, a1.f1,
  609.                                                                           a2.f0, a2.f1,
  610.                                                                           a3.f0, a3.f1
  611.                                                                       }, new double[] {
  612.                                                                           b1.f1, b1.f0,
  613.                                                                           b2.f1, b2.f0,
  614.                                                                           b3.f1, b3.f0
  615.                                                                       }),
  616.                                          MathArrays.linearCombination(new double[] {
  617.                                                                           a1.f0, 2 * a1.f1, a1.f2,
  618.                                                                           a2.f0, 2 * a2.f1, a2.f2,
  619.                                                                           a3.f0, 2 * a3.f1, a3.f2
  620.                                                                       }, new double[] {
  621.                                                                           b1.f2, b1.f1, b1.f0,
  622.                                                                           b2.f2, b2.f1, b2.f0,
  623.                                                                           b3.f2, b3.f1, b3.f0
  624.                                                                       }));
  625.     }

  626.     /** {@inheritDoc} */
  627.     @Override
  628.     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
  629.                                                    final double a2, final UnivariateDerivative2 b2,
  630.                                                    final double a3, final UnivariateDerivative2 b3) {
  631.         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
  632.                                                                       a2, b2.f0,
  633.                                                                       a3, b3.f0),
  634.                                          MathArrays.linearCombination(a1, b1.f1,
  635.                                                                       a2, b2.f1,
  636.                                                                       a3, b3.f1),
  637.                                          MathArrays.linearCombination(a1, b1.f2,
  638.                                                                       a2, b2.f2,
  639.                                                                       a3, b3.f2));
  640.     }

  641.     /** {@inheritDoc} */
  642.     @Override
  643.     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
  644.                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2,
  645.                                                    final UnivariateDerivative2 a3, final UnivariateDerivative2 b3,
  646.                                                    final UnivariateDerivative2 a4, final UnivariateDerivative2 b4) {
  647.         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
  648.                                                                       a2.f0, b2.f0,
  649.                                                                       a3.f0, b3.f0,
  650.                                                                       a4.f0, b4.f0),
  651.                                          MathArrays.linearCombination(new double[] {
  652.                                                                           a1.f0, a1.f1,
  653.                                                                           a2.f0, a2.f1,
  654.                                                                           a3.f0, a3.f1,
  655.                                                                           a4.f0, a4.f1
  656.                                                                       }, new double[] {
  657.                                                                           b1.f1, b1.f0,
  658.                                                                           b2.f1, b2.f0,
  659.                                                                           b3.f1, b3.f0,
  660.                                                                           b4.f1, b4.f0
  661.                                                                       }),
  662.                                          MathArrays.linearCombination(new double[] {
  663.                                                                           a1.f0, 2 * a1.f1, a1.f2,
  664.                                                                           a2.f0, 2 * a2.f1, a2.f2,
  665.                                                                           a3.f0, 2 * a3.f1, a3.f2,
  666.                                                                           a4.f0, 2 * a4.f1, a4.f2
  667.                                                                       }, new double[] {
  668.                                                                           b1.f2, b1.f1, b1.f0,
  669.                                                                           b2.f2, b2.f1, b2.f0,
  670.                                                                           b3.f2, b3.f1, b3.f0,
  671.                                                                           b4.f2, b4.f1, b4.f0
  672.                                                                       }));
  673.     }

  674.     /** {@inheritDoc} */
  675.     @Override
  676.     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
  677.                                                    final double a2, final UnivariateDerivative2 b2,
  678.                                                    final double a3, final UnivariateDerivative2 b3,
  679.                                                    final double a4, final UnivariateDerivative2 b4) {
  680.         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
  681.                                                                       a2, b2.f0,
  682.                                                                       a3, b3.f0,
  683.                                                                       a4, b4.f0),
  684.                                          MathArrays.linearCombination(a1, b1.f1,
  685.                                                                       a2, b2.f1,
  686.                                                                       a3, b3.f1,
  687.                                                                       a4, b4.f1),
  688.                                          MathArrays.linearCombination(a1, b1.f2,
  689.                                                                       a2, b2.f2,
  690.                                                                       a3, b3.f2,
  691.                                                                       a4, b4.f2));
  692.     }

  693.     /** {@inheritDoc} */
  694.     @Override
  695.     public UnivariateDerivative2 getPi() {
  696.         return PI;
  697.     }

  698.     /** Test for the equality of two univariate derivatives.
  699.      * <p>
  700.      * univariate derivatives are considered equal if they have the same derivatives.
  701.      * </p>
  702.      * @param other Object to test for equality to this
  703.      * @return true if two univariate derivatives are equal
  704.      */
  705.     @Override
  706.     public boolean equals(Object other) {

  707.         if (this == other) {
  708.             return true;
  709.         }

  710.         if (other instanceof UnivariateDerivative2) {
  711.             final UnivariateDerivative2 rhs = (UnivariateDerivative2) other;
  712.             return f0 == rhs.f0 && f1 == rhs.f1 && f2 == rhs.f2;
  713.         }

  714.         return false;

  715.     }

  716.     /** Get a hashCode for the univariate derivative.
  717.      * @return a hash code value for this object
  718.      */
  719.     @Override
  720.     public int hashCode() {
  721.         return 317 - 41 * Double.hashCode(f0) + 57 * Double.hashCode(f1) - 103 * Double.hashCode(f2);
  722.     }

  723.     /** {@inheritDoc}
  724.      * <p>
  725.      * Comparison performed considering that derivatives are intrinsically linked to monomials in the corresponding
  726.      * Taylor expansion and that the higher the degree, the smaller the term.
  727.      * </p>
  728.      * @since 3.0
  729.      */
  730.     @Override
  731.     public int compareTo(final UnivariateDerivative2 o) {
  732.         final int cF0 = Double.compare(f0, o.getReal());
  733.         if (cF0 == 0) {
  734.             final int cF1 = Double.compare(f1, o.getFirstDerivative());
  735.             if (cF1 == 0) {
  736.                 return Double.compare(f2, o.getSecondDerivative());
  737.             } else {
  738.                 return cF1;
  739.             }
  740.         } else {
  741.             return cF0;
  742.         }
  743.     }

  744. }