FieldUnivariateDerivative2.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.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.exception.LocalizedCoreFormats;
  21. import org.hipparchus.exception.MathIllegalArgumentException;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.FieldSinCos;
  24. import org.hipparchus.util.FieldSinhCosh;
  25. import org.hipparchus.util.MathArrays;
  26. import org.hipparchus.util.MathUtils;

  27. /** Class representing both the value and the differentials of a function.
  28.  * <p>This class is a stripped-down version of {@link FieldDerivativeStructure}
  29.  * with only one {@link FieldDerivativeStructure#getFreeParameters() free parameter}
  30.  * and {@link FieldDerivativeStructure#getOrder() derivation order} limited to two.
  31.  * It should have less overhead than {@link FieldDerivativeStructure} 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 FieldUnivariateDerivative2} 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.  * @param <T> the type of the function parameters and value
  45.  * @see DerivativeStructure
  46.  * @see UnivariateDerivative1
  47.  * @see UnivariateDerivative2
  48.  * @see Gradient
  49.  * @see FieldDerivativeStructure
  50.  * @see FieldUnivariateDerivative1
  51.  * @see FieldGradient
  52.  * @since 1.7
  53.  */
  54. public class FieldUnivariateDerivative2<T extends CalculusFieldElement<T>>
  55.     extends FieldUnivariateDerivative<T, FieldUnivariateDerivative2<T>> {

  56.     /** Value of the function. */
  57.     private final T f0;

  58.     /** First derivative of the function. */
  59.     private final T f1;

  60.     /** Second derivative of the function. */
  61.     private final T f2;

  62.     /** Build an instance with values and derivative.
  63.      * @param f0 value of the function
  64.      * @param f1 first derivative of the function
  65.      * @param f2 second derivative of the function
  66.      */
  67.     public FieldUnivariateDerivative2(final T f0, final T f1, final T f2) {
  68.         this.f0 = f0;
  69.         this.f1 = f1;
  70.         this.f2 = f2;
  71.     }

  72.     /** Build an instance from a {@link FieldDerivativeStructure}.
  73.      * @param ds derivative structure
  74.      * @exception MathIllegalArgumentException if either {@code ds} parameters
  75.      * is not 1 or {@code ds} order is not 2
  76.      */
  77.     public FieldUnivariateDerivative2(final FieldDerivativeStructure<T> ds) throws MathIllegalArgumentException {
  78.         MathUtils.checkDimension(ds.getFreeParameters(), 1);
  79.         MathUtils.checkDimension(ds.getOrder(), 2);
  80.         this.f0 = ds.getValue();
  81.         this.f1 = ds.getPartialDerivative(1);
  82.         this.f2 = ds.getPartialDerivative(2);
  83.     }

  84.     /** {@inheritDoc} */
  85.     @Override
  86.     public FieldUnivariateDerivative2<T> newInstance(final double value) {
  87.         final T zero = f0.getField().getZero();
  88.         return new FieldUnivariateDerivative2<>(zero.newInstance(value), zero, zero);
  89.     }

  90.     /** {@inheritDoc} */
  91.     @Override
  92.     public FieldUnivariateDerivative2<T> newInstance(final T value) {
  93.         final T zero = f0.getField().getZero();
  94.         return new FieldUnivariateDerivative2<>(value, zero, zero);
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public FieldUnivariateDerivative2<T> withValue(final T value) {
  99.         return new FieldUnivariateDerivative2<>(value, f1, f2);
  100.     }

  101.     /** {@inheritDoc} */
  102.     @Override
  103.     public FieldUnivariateDerivative2<T> getAddendum() {
  104.         return new FieldUnivariateDerivative2<>(f0.getField().getZero(), f1, f2);
  105.     }

  106.     /** Get the value part of the univariate derivative.
  107.      * @return value part of the univariate derivative
  108.      */
  109.     @Override
  110.     public T getValue() {
  111.         return f0;
  112.     }

  113.     /** Get a derivative from the univariate derivative.
  114.      * @param n derivation order (must be between 0 and {@link #getOrder()}, both inclusive)
  115.      * @return n<sup>th</sup> derivative, or {@code NaN} if n is
  116.      * either negative or strictly larger than {@link #getOrder()}
  117.      */
  118.     @Override
  119.     public T getDerivative(final int n) {
  120.         switch (n) {
  121.             case 0 :
  122.                 return f0;
  123.             case 1 :
  124.                 return f1;
  125.             case 2 :
  126.                 return f2;
  127.             default :
  128.                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
  129.         }
  130.     }

  131.     /** Get the derivation order.
  132.      * @return derivation order
  133.      */
  134.     @Override
  135.     public int getOrder() {
  136.         return 2;
  137.     }

  138.     /** Get the first derivative.
  139.      * @return first derivative
  140.      * @see #getValue()
  141.      */
  142.     public T getFirstDerivative() {
  143.         return f1;
  144.     }

  145.     /** Get the second derivative.
  146.      * @return second derivative
  147.      * @see #getValue()
  148.      * @see #getFirstDerivative()
  149.      */
  150.     public T getSecondDerivative() {
  151.         return f2;
  152.     }

  153.     /** Get the {@link Field} the value and parameters of the function belongs to.
  154.      * @return {@link Field} the value and parameters of the function belongs to
  155.      */
  156.     public Field<T> getValueField() {
  157.         return f0.getField();
  158.     }

  159.     /** Convert the instance to a {@link FieldDerivativeStructure}.
  160.      * @return derivative structure with same value and derivative as the instance
  161.      */
  162.     @Override
  163.     public FieldDerivativeStructure<T> toDerivativeStructure() {
  164.         return getField().getConversionFactory().build(f0, f1, f2);
  165.     }

  166.     /** {@inheritDoc} */
  167.     @Override
  168.     public FieldUnivariateDerivative2<T> add(final double a) {
  169.         return new FieldUnivariateDerivative2<>(f0.add(a), f1, f2);
  170.     }

  171.     /** {@inheritDoc} */
  172.     @Override
  173.     public FieldUnivariateDerivative2<T> add(final FieldUnivariateDerivative2<T> a) {
  174.         return new FieldUnivariateDerivative2<>(f0.add(a.f0), f1.add(a.f1), f2.add(a.f2));
  175.     }

  176.     /** {@inheritDoc} */
  177.     @Override
  178.     public FieldUnivariateDerivative2<T> subtract(final double a) {
  179.         return new FieldUnivariateDerivative2<>(f0.subtract(a), f1, f2);
  180.     }

  181.     /** {@inheritDoc} */
  182.     @Override
  183.     public FieldUnivariateDerivative2<T> subtract(final FieldUnivariateDerivative2<T> a) {
  184.         return new FieldUnivariateDerivative2<>(f0.subtract(a.f0), f1.subtract(a.f1), f2.subtract(a.f2));
  185.     }

  186.     /** '&times;' operator.
  187.      * @param a right hand side parameter of the operator
  188.      * @return this&times;a
  189.      */
  190.     public FieldUnivariateDerivative2<T> multiply(final T a) {
  191.         return new FieldUnivariateDerivative2<>(f0.multiply(a), f1.multiply(a), f2.multiply(a));
  192.     }

  193.     /** {@inheritDoc} */
  194.     @Override
  195.     public FieldUnivariateDerivative2<T> multiply(final int n) {
  196.         return new FieldUnivariateDerivative2<>(f0.multiply(n), f1.multiply(n), f2.multiply(n));
  197.     }

  198.     /** {@inheritDoc} */
  199.     @Override
  200.     public FieldUnivariateDerivative2<T> multiply(final double a) {
  201.         return new FieldUnivariateDerivative2<>(f0.multiply(a), f1.multiply(a), f2.multiply(a));
  202.     }

  203.     /** {@inheritDoc} */
  204.     @Override
  205.     public FieldUnivariateDerivative2<T> multiply(final FieldUnivariateDerivative2<T> a) {
  206.         return new FieldUnivariateDerivative2<>(f0.multiply(a.f0),
  207.                                                 a.f0.linearCombination(f1, a.f0, f0, a.f1),
  208.                                                 a.f0.linearCombination(f2, a.f0, f1.add(f1), a.f1, f0, a.f2));
  209.     }

  210.     /** {@inheritDoc} */
  211.     @Override
  212.     public FieldUnivariateDerivative2<T> square() {
  213.         return multiply(this);
  214.     }

  215.     /** '&divide;' operator.
  216.      * @param a right hand side parameter of the operator
  217.      * @return this&divide;a
  218.      */
  219.     public FieldUnivariateDerivative2<T> divide(final T a) {
  220.         final T inv1 = a.reciprocal();
  221.         return new FieldUnivariateDerivative2<>(f0.multiply(inv1), f1.multiply(inv1), f2.multiply(inv1));
  222.     }

  223.     /** {@inheritDoc} */
  224.     @Override
  225.     public FieldUnivariateDerivative2<T> divide(final double a) {
  226.         final double inv1 = 1.0 / a;
  227.         return new FieldUnivariateDerivative2<>(f0.multiply(inv1), f1.multiply(inv1), f2.multiply(inv1));
  228.     }

  229.     /** {@inheritDoc} */
  230.     @Override
  231.     public FieldUnivariateDerivative2<T> divide(final FieldUnivariateDerivative2<T> a) {
  232.         final T inv1 = a.f0.reciprocal();
  233.         final T inv2 = inv1.multiply(inv1);
  234.         final T inv3 = inv1.multiply(inv2);
  235.         return new FieldUnivariateDerivative2<>(f0.multiply(inv1),
  236.                                                 a.f0.linearCombination(f1, a.f0, f0.negate(), a.f1).multiply(inv2),
  237.                                                 a.f0.linearCombination(f2, a.f0.multiply(a.f0),
  238.                                                                        f1.multiply(-2), a.f0.multiply(a.f1),
  239.                                                                        f0.add(f0), a.f1.multiply(a.f1),
  240.                                                                        f0.negate(), a.f0.multiply(a.f2)).multiply(inv3));
  241.     }

  242.     /** IEEE remainder operator.
  243.      * @param a right hand side parameter of the operator
  244.      * @return this - n &times; a where n is the closest integer to this/a
  245.      * (the even integer is chosen for n if this/a is halfway between two integers)
  246.      */
  247.     public FieldUnivariateDerivative2<T> remainder(final T a) {
  248.         return new FieldUnivariateDerivative2<>(FastMath.IEEEremainder(f0, a), f1, f2);
  249.     }

  250.     /** {@inheritDoc} */
  251.     @Override
  252.     public FieldUnivariateDerivative2<T> remainder(final double a) {
  253.         return new FieldUnivariateDerivative2<>(FastMath.IEEEremainder(f0, a), f1, f2);
  254.     }

  255.     /** {@inheritDoc} */
  256.     @Override
  257.     public FieldUnivariateDerivative2<T> remainder(final FieldUnivariateDerivative2<T> a) {

  258.         // compute k such that lhs % rhs = lhs - k rhs
  259.         final T rem = FastMath.IEEEremainder(f0, a.f0);
  260.         final T k   = FastMath.rint(f0.subtract(rem).divide(a.f0));

  261.         return new FieldUnivariateDerivative2<>(rem,
  262.                                                 f1.subtract(k.multiply(a.f1)),
  263.                                                 f2.subtract(k.multiply(a.f2)));

  264.     }

  265.     /** {@inheritDoc} */
  266.     @Override
  267.     public FieldUnivariateDerivative2<T> negate() {
  268.         return new FieldUnivariateDerivative2<>(f0.negate(), f1.negate(), f2.negate());
  269.     }

  270.     /** {@inheritDoc} */
  271.     @Override
  272.     public FieldUnivariateDerivative2<T> abs() {
  273.         if (Double.doubleToLongBits(f0.getReal()) < 0) {
  274.             // we use the bits representation to also handle -0.0
  275.             return negate();
  276.         } else {
  277.             return this;
  278.         }
  279.     }

  280.     /**
  281.      * Returns the instance with the sign of the argument.
  282.      * A NaN {@code sign} argument is treated as positive.
  283.      *
  284.      * @param sign the sign for the returned value
  285.      * @return the instance with the same sign as the {@code sign} argument
  286.      */
  287.     public FieldUnivariateDerivative2<T> copySign(final T sign) {
  288.         long m = Double.doubleToLongBits(f0.getReal());
  289.         long s = Double.doubleToLongBits(sign.getReal());
  290.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  291.             return this;
  292.         }
  293.         return negate(); // flip sign
  294.     }

  295.     /** {@inheritDoc} */
  296.     @Override
  297.     public FieldUnivariateDerivative2<T> copySign(final FieldUnivariateDerivative2<T> sign) {
  298.         long m = Double.doubleToLongBits(f0.getReal());
  299.         long s = Double.doubleToLongBits(sign.f0.getReal());
  300.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  301.             return this;
  302.         }
  303.         return negate(); // flip sign
  304.     }

  305.     /** {@inheritDoc} */
  306.     @Override
  307.     public FieldUnivariateDerivative2<T> copySign(final double sign) {
  308.         long m = Double.doubleToLongBits(f0.getReal());
  309.         long s = Double.doubleToLongBits(sign);
  310.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  311.             return this;
  312.         }
  313.         return negate(); // flip sign
  314.     }

  315.     /** {@inheritDoc} */
  316.     @Override
  317.     public FieldUnivariateDerivative2<T> scalb(final int n) {
  318.         return new FieldUnivariateDerivative2<>(FastMath.scalb(f0, n),
  319.                                                 FastMath.scalb(f1, n),
  320.                                                 FastMath.scalb(f2, n));
  321.     }

  322.     /** {@inheritDoc} */
  323.     @Override
  324.     public FieldUnivariateDerivative2<T> hypot(final FieldUnivariateDerivative2<T> y) {

  325.         if (Double.isInfinite(f0.getReal()) || Double.isInfinite(y.f0.getReal())) {
  326.             final T zero = f0.getField().getZero();
  327.             return new FieldUnivariateDerivative2<>(f0.newInstance(Double.POSITIVE_INFINITY),
  328.                                                     zero, zero);
  329.         } else if (Double.isNaN(f0.getReal()) || Double.isNaN(y.f0.getReal())) {
  330.             final T zero = f0.getField().getZero();
  331.             return new FieldUnivariateDerivative2<>(f0.newInstance(Double.NaN),
  332.                                                     zero, zero);
  333.         } else {

  334.             final int expX = getExponent();
  335.             final int expY = y.getExponent();
  336.             if (expX > expY + 27) {
  337.                 // y is negligible with respect to x
  338.                 return abs();
  339.             } else if (expY > expX + 27) {
  340.                 // x is negligible with respect to y
  341.                 return y.abs();
  342.             } else {

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

  345.                 // scale parameters without losing precision
  346.                 final FieldUnivariateDerivative2<T> scaledX = scalb(-middleExp);
  347.                 final FieldUnivariateDerivative2<T> scaledY = y.scalb(-middleExp);

  348.                 // compute scaled hypotenuse
  349.                 final FieldUnivariateDerivative2<T> scaledH =
  350.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  351.                 // remove scaling
  352.                 return scaledH.scalb(middleExp);

  353.             }

  354.         }
  355.     }

  356.     /** {@inheritDoc} */
  357.     @Override
  358.     public FieldUnivariateDerivative2<T> reciprocal() {
  359.         final T inv1 = f0.reciprocal();
  360.         final T inv2 = inv1.multiply(inv1);
  361.         final T inv3 = inv1.multiply(inv2);
  362.         return new FieldUnivariateDerivative2<>(inv1,
  363.                                                 f1.negate().multiply(inv2),
  364.                                                 f0.linearCombination(f1.add(f1), f1, f0.negate(), f2).multiply(inv3));
  365.     }

  366.     /** Compute composition of the instance by a function.
  367.      * @param g0 value of the function at the current point (i.e. at {@code g(getValue())})
  368.      * @param g1 first derivative of the function at the current point (i.e. at {@code g'(getValue())})
  369.      * @param g2 second derivative of the function at the current point (i.e. at {@code g''(getValue())})
  370.      * @return g(this)
  371.      */
  372.     public FieldUnivariateDerivative2<T> compose(final T g0, final T g1, final T g2) {
  373.         return new FieldUnivariateDerivative2<>(g0,
  374.                                                 g1.multiply(f1),
  375.                                                 f0.linearCombination(g1, f2, g2, f1.square()));
  376.     }

  377.     /** {@inheritDoc} */
  378.     @Override
  379.     public FieldUnivariateDerivative2<T> sqrt() {
  380.         final T s0 = FastMath.sqrt(f0);
  381.         final T s0twice = s0.multiply(2);
  382.         final T s1 = f1.divide(s0twice);
  383.         final T s2 = (f2.subtract(s1.square().multiply(2))).divide(s0twice);
  384.         return new FieldUnivariateDerivative2<>(s0, s1, s2);
  385.     }

  386.     /** {@inheritDoc} */
  387.     @Override
  388.     public FieldUnivariateDerivative2<T> cbrt() {
  389.         final T c  = FastMath.cbrt(f0);
  390.         final T c2 = c.square();
  391.         return compose(c, c2.multiply(3).reciprocal(), c2.multiply(-4.5).multiply(f0).reciprocal());
  392.     }

  393.     /** {@inheritDoc} */
  394.     @Override
  395.     public FieldUnivariateDerivative2<T> rootN(final int n) {
  396.         if (n == 2) {
  397.             return sqrt();
  398.         } else if (n == 3) {
  399.             return cbrt();
  400.         } else {
  401.             final T r = FastMath.pow(f0, 1.0 / n);
  402.             final T z = FastMath.pow(r, n - 1).multiply(n);
  403.             return compose(r, z.reciprocal(), z.square().multiply(r).reciprocal().multiply(1 -n));
  404.         }
  405.     }

  406.     /** {@inheritDoc} */
  407.     @Override
  408.     public FieldUnivariateDerivative2Field<T> getField() {
  409.         return FieldUnivariateDerivative2Field.getUnivariateDerivative2Field(f0.getField());
  410.     }

  411.     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldUnivariateDerivative2}
  412.      * @param a number to exponentiate
  413.      * @param x power to apply
  414.      * @param <T> the type of the function parameters and value
  415.      * @return a<sup>x</sup>
  416.      */
  417.     public static <T extends CalculusFieldElement<T>> FieldUnivariateDerivative2<T> pow(final double a, final FieldUnivariateDerivative2<T> x) {
  418.         if (a == 0) {
  419.             return x.getField().getZero();
  420.         } else {
  421.             final T      aX    = FastMath.pow(x.f0.newInstance(a), x.f0);
  422.             final double lnA   = FastMath.log(a);
  423.             final T      aXlnA = aX.multiply(lnA);
  424.             return new FieldUnivariateDerivative2<>(aX,
  425.                                                     aXlnA.multiply(x.f1),
  426.                                                     aXlnA.multiply(x.f1.multiply(x.f1).multiply(lnA).add(x.f2)));
  427.         }
  428.     }

  429.     /** {@inheritDoc} */
  430.     @Override
  431.     public FieldUnivariateDerivative2<T> pow(final double p) {
  432.         if (p == 0) {
  433.             return getField().getOne();
  434.         } else {
  435.             final T f0Pm2 = FastMath.pow(f0, p - 2);
  436.             final T f0Pm1 = f0Pm2.multiply(f0);
  437.             final T f0P   = f0Pm1.multiply(f0);
  438.             return compose(f0P, f0Pm1.multiply(p), f0Pm2.multiply(p * (p - 1)));
  439.         }
  440.     }

  441.     /** {@inheritDoc} */
  442.     @Override
  443.     public FieldUnivariateDerivative2<T> pow(final int n) {
  444.         if (n == 0) {
  445.             return getField().getOne();
  446.         } else {
  447.             final T f0Nm2 = FastMath.pow(f0, n - 2);
  448.             final T f0Nm1 = f0Nm2.multiply(f0);
  449.             final T f0N   = f0Nm1.multiply(f0);
  450.             return compose(f0N, f0Nm1.multiply(n), f0Nm2.multiply(n * (n - 1)));
  451.         }
  452.     }

  453.     /** {@inheritDoc} */
  454.     @Override
  455.     public FieldUnivariateDerivative2<T> exp() {
  456.         final T exp = FastMath.exp(f0);
  457.         return compose(exp, exp, exp);
  458.     }

  459.     /** {@inheritDoc} */
  460.     @Override
  461.     public FieldUnivariateDerivative2<T> expm1() {
  462.         final T exp   = FastMath.exp(f0);
  463.         final T expM1 = FastMath.expm1(f0);
  464.         return compose(expM1, exp, exp);
  465.     }

  466.     /** {@inheritDoc} */
  467.     @Override
  468.     public FieldUnivariateDerivative2<T> log() {
  469.         final T inv = f0.reciprocal();
  470.         return compose(FastMath.log(f0), inv, inv.multiply(inv).negate());
  471.     }

  472.     /** {@inheritDoc} */
  473.     @Override
  474.     public FieldUnivariateDerivative2<T> log1p() {
  475.         final T inv = f0.add(1).reciprocal();
  476.         return compose(FastMath.log1p(f0), inv, inv.multiply(inv).negate());
  477.     }

  478.     /** {@inheritDoc} */
  479.     @Override
  480.     public FieldUnivariateDerivative2<T> log10() {
  481.         final T invF0 = f0.reciprocal();
  482.         final T inv = invF0.divide(FastMath.log(10.0));
  483.         return compose(FastMath.log10(f0), inv, inv.multiply(invF0).negate());
  484.     }

  485.     /** {@inheritDoc} */
  486.     @Override
  487.     public FieldUnivariateDerivative2<T> cos() {
  488.         final FieldSinCos<T> sinCos = FastMath.sinCos(f0);
  489.         return compose(sinCos.cos(), sinCos.sin().negate(), sinCos.cos().negate());
  490.     }

  491.     /** {@inheritDoc} */
  492.     @Override
  493.     public FieldUnivariateDerivative2<T> sin() {
  494.         final FieldSinCos<T> sinCos = FastMath.sinCos(f0);
  495.         return compose(sinCos.sin(), sinCos.cos(), sinCos.sin().negate());
  496.     }

  497.     /** {@inheritDoc} */
  498.     @Override
  499.     public FieldSinCos<FieldUnivariateDerivative2<T>> sinCos() {
  500.         final FieldSinCos<T> sinCos = FastMath.sinCos(f0);
  501.         final T mSin = sinCos.sin().negate();
  502.         final T mCos = sinCos.cos().negate();
  503.         return new FieldSinCos<>(compose(sinCos.sin(), sinCos.cos(), mSin),
  504.                                  compose(sinCos.cos(), mSin, mCos));
  505.     }

  506.     /** {@inheritDoc} */
  507.     @Override
  508.     public FieldUnivariateDerivative2<T> tan() {
  509.         final T tan  = FastMath.tan(f0);
  510.         final T sec2 = tan.multiply(tan).add(1);
  511.         return compose(tan, sec2, sec2.add(sec2).multiply(tan));
  512.     }

  513.     /** {@inheritDoc} */
  514.     @Override
  515.     public FieldUnivariateDerivative2<T> acos() {
  516.         final T inv = f0.square().negate().add(1).reciprocal();
  517.         final T mS  = inv.sqrt().negate();
  518.         return compose(FastMath.acos(f0), mS, mS.multiply(f0).multiply(inv));
  519.     }

  520.     /** {@inheritDoc} */
  521.     @Override
  522.     public FieldUnivariateDerivative2<T> asin() {
  523.         final T inv = f0.square().negate().add(1).reciprocal();
  524.         final T s   = inv.sqrt();
  525.         return compose(FastMath.asin(f0), s, s.multiply(f0).multiply(inv));
  526.     }

  527.     /** {@inheritDoc} */
  528.     @Override
  529.     public FieldUnivariateDerivative2<T> atan() {
  530.         final T inv = f0.square().add(1).reciprocal();
  531.         return compose(FastMath.atan(f0), inv, f0.multiply(-2).multiply(inv).multiply(inv));
  532.     }

  533.     /** {@inheritDoc} */
  534.     @Override
  535.     public FieldUnivariateDerivative2<T> atan2(final FieldUnivariateDerivative2<T> x) {
  536.         final T x2    = x.f0.multiply(x.f0);
  537.         final T f02   = f0.add(f0);
  538.         final T inv   = f0.square().add(x2).reciprocal();
  539.         final T atan0 = FastMath.atan2(f0, x.f0);
  540.         final T atan1 = f0.linearCombination(x.f0, f1, x.f1.negate(), f0).multiply(inv);
  541.         final T c     = f0.linearCombination(f2, x2,
  542.                                              f1.multiply(-2), x.f0.multiply(x.f1),
  543.                                              f02, x.f1.multiply(x.f1),
  544.                                              f0.negate(), x.f0.multiply(x.f2)).multiply(inv);
  545.         return new FieldUnivariateDerivative2<>(atan0,
  546.                                                 atan1,
  547.                                                 c.subtract(f02.multiply(atan1).multiply(atan1)).divide(x.f0));
  548.     }

  549.     /** {@inheritDoc} */
  550.     @Override
  551.     public FieldUnivariateDerivative2<T> cosh() {
  552.         final T c = FastMath.cosh(f0);
  553.         final T s = FastMath.sinh(f0);
  554.         return compose(c, s, c);
  555.     }

  556.     /** {@inheritDoc} */
  557.     @Override
  558.     public FieldUnivariateDerivative2<T> sinh() {
  559.         final T c = FastMath.cosh(f0);
  560.         final T s = FastMath.sinh(f0);
  561.         return compose(s, c, s);
  562.     }

  563.     /** {@inheritDoc} */
  564.     @Override
  565.     public FieldSinhCosh<FieldUnivariateDerivative2<T>> sinhCosh() {
  566.         final FieldSinhCosh<T> sinhCosh = FastMath.sinhCosh(f0);
  567.         return new FieldSinhCosh<>(compose(sinhCosh.sinh(), sinhCosh.cosh(), sinhCosh.sinh()),
  568.                                    compose(sinhCosh.cosh(), sinhCosh.sinh(), sinhCosh.cosh()));
  569.     }

  570.     /** {@inheritDoc} */
  571.     @Override
  572.     public FieldUnivariateDerivative2<T> tanh() {
  573.         final T tanh  = FastMath.tanh(f0);
  574.         final T sech2 = tanh.multiply(tanh).negate().add(1);
  575.         return compose(tanh, sech2, sech2.multiply(-2).multiply(tanh));
  576.     }

  577.     /** {@inheritDoc} */
  578.     @Override
  579.     public FieldUnivariateDerivative2<T> acosh() {
  580.         final T inv = f0.square().subtract(1).reciprocal();
  581.         final T s   = inv.sqrt();
  582.         return compose(FastMath.acosh(f0), s, f0.negate().multiply(s).multiply(inv));
  583.     }

  584.     /** {@inheritDoc} */
  585.     @Override
  586.     public FieldUnivariateDerivative2<T> asinh() {
  587.         final T inv = f0.square().add(1).reciprocal();
  588.         final T s   = inv.sqrt();
  589.         return compose(FastMath.asinh(f0), s, f0.negate().multiply(s).multiply(inv));
  590.     }

  591.     /** {@inheritDoc} */
  592.     @Override
  593.     public FieldUnivariateDerivative2<T> atanh() {
  594.         final T inv = f0.square().negate().add(1).reciprocal();
  595.         return compose(FastMath.atanh(f0), inv, f0.add(f0).multiply(inv).multiply(inv));
  596.     }

  597.     /** {@inheritDoc} */
  598.     @Override
  599.     public FieldUnivariateDerivative2<T> toDegrees() {
  600.         return new FieldUnivariateDerivative2<>(FastMath.toDegrees(f0), FastMath.toDegrees(f1), FastMath.toDegrees(f2));
  601.     }

  602.     /** {@inheritDoc} */
  603.     @Override
  604.     public FieldUnivariateDerivative2<T> toRadians() {
  605.         return new FieldUnivariateDerivative2<>(FastMath.toRadians(f0), FastMath.toRadians(f1), FastMath.toRadians(f2));
  606.     }

  607.     /** Evaluate Taylor expansion a univariate derivative.
  608.      * @param delta parameter offset Δx
  609.      * @return value of the Taylor expansion at x + Δx
  610.      */
  611.     public T taylor(final double delta) {
  612.         return f0.add(f1.add(f2.multiply(0.5 * delta)).multiply(delta));
  613.     }

  614.     /** Evaluate Taylor expansion a univariate derivative.
  615.      * @param delta parameter offset Δx
  616.      * @return value of the Taylor expansion at x + Δx
  617.      */
  618.     public T taylor(final T delta) {
  619.         return f0.add(f1.add(f2.multiply(delta.multiply(0.5))).multiply(delta));
  620.     }

  621.     /**
  622.      * Compute a linear combination.
  623.      * @param a Factors.
  624.      * @param b Factors.
  625.      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
  626.      * @throws MathIllegalArgumentException if arrays dimensions don't match
  627.      */
  628.     public FieldUnivariateDerivative2<T> linearCombination(final T[] a, final FieldUnivariateDerivative2<T>[] b) {

  629.         // extract values and derivatives
  630.         final Field<T> field = b[0].f0.getField();
  631.         final int      n  = b.length;
  632.         final T[] b0 = MathArrays.buildArray(field, n);
  633.         final T[] b1 = MathArrays.buildArray(field, n);
  634.         final T[] b2 = MathArrays.buildArray(field, n);
  635.         for (int i = 0; i < n; ++i) {
  636.             b0[i] = b[i].f0;
  637.             b1[i] = b[i].f1;
  638.             b2[i] = b[i].f2;
  639.         }

  640.         return new FieldUnivariateDerivative2<>(b[0].f0.linearCombination(a, b0),
  641.                                                 b[0].f0.linearCombination(a, b1),
  642.                                                 b[0].f0.linearCombination(a, b2));

  643.     }

  644.     /** {@inheritDoc} */
  645.     @Override
  646.     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T>[] a,
  647.                                                            final FieldUnivariateDerivative2<T>[] b) {

  648.         // extract values and derivatives
  649.         final Field<T> field = a[0].f0.getField();
  650.         final int n  = a.length;
  651.         final T[] a0 = MathArrays.buildArray(field, n);
  652.         final T[] b0 = MathArrays.buildArray(field, n);
  653.         final T[] a1 = MathArrays.buildArray(field, 2 * n);
  654.         final T[] b1 = MathArrays.buildArray(field, 2 * n);
  655.         final T[] a2 = MathArrays.buildArray(field, 3 * n);
  656.         final T[] b2 = MathArrays.buildArray(field, 3 * n);
  657.         for (int i = 0; i < n; ++i) {
  658.             final FieldUnivariateDerivative2<T> ai = a[i];
  659.             final FieldUnivariateDerivative2<T> bi = b[i];
  660.             a0[i]         = ai.f0;
  661.             b0[i]         = bi.f0;
  662.             a1[2 * i]     = ai.f0;
  663.             a1[2 * i + 1] = ai.f1;
  664.             b1[2 * i]     = bi.f1;
  665.             b1[2 * i + 1] = bi.f0;
  666.             a2[3 * i]     = ai.f0;
  667.             a2[3 * i + 1] = ai.f1.add(ai.f1);
  668.             a2[3 * i + 2] = ai.f2;
  669.             b2[3 * i]     = bi.f2;
  670.             b2[3 * i + 1] = bi.f1;
  671.             b2[3 * i + 2] = bi.f0;
  672.         }

  673.         return new FieldUnivariateDerivative2<>(a[0].f0.linearCombination(a0, b0),
  674.                                                 a[0].f0.linearCombination(a1, b1),
  675.                                                 a[0].f0.linearCombination(a2, b2));

  676.     }

  677.     /** {@inheritDoc} */
  678.     @Override
  679.     public FieldUnivariateDerivative2<T> linearCombination(final double[] a, final FieldUnivariateDerivative2<T>[] b) {

  680.         // extract values and derivatives
  681.         final Field<T> field = b[0].f0.getField();
  682.         final int      n  = b.length;
  683.         final T[] b0 = MathArrays.buildArray(field, n);
  684.         final T[] b1 = MathArrays.buildArray(field, n);
  685.         final T[] b2 = MathArrays.buildArray(field, n);
  686.         for (int i = 0; i < n; ++i) {
  687.             b0[i] = b[i].f0;
  688.             b1[i] = b[i].f1;
  689.             b2[i] = b[i].f2;
  690.         }

  691.         return new FieldUnivariateDerivative2<>(b[0].f0.linearCombination(a, b0),
  692.                                                 b[0].f0.linearCombination(a, b1),
  693.                                                 b[0].f0.linearCombination(a, b2));

  694.     }

  695.     /** {@inheritDoc} */
  696.     @Override
  697.     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
  698.                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2) {
  699.         final Field<T> field = a1.f0.getField();
  700.         final T[]      u2    = MathArrays.buildArray(field, 6);
  701.         final T[]      v2    = MathArrays.buildArray(field, 6);
  702.         u2[0] = a1.f0;
  703.         u2[1] = a1.f1.add(a1.f1);
  704.         u2[2] = a1.f2;
  705.         u2[3] = a2.f0;
  706.         u2[4] = a2.f1.add(a2.f1);
  707.         u2[5] = a2.f2;
  708.         v2[0] = b1.f2;
  709.         v2[1] = b1.f1;
  710.         v2[2] = b1.f0;
  711.         v2[3] = b2.f2;
  712.         v2[4] = b2.f1;
  713.         v2[5] = b2.f0;
  714.         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
  715.                                                                         a2.f0, b2.f0),
  716.                                                 a1.f0.linearCombination(a1.f0, b1.f1,
  717.                                                                         a1.f1, b1.f0,
  718.                                                                         a2.f0, b2.f1,
  719.                                                                         a2.f1, b2.f0),
  720.                                                 a1.f0.linearCombination(u2, v2));
  721.     }

  722.     /** {@inheritDoc} */
  723.     @Override
  724.     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
  725.                                                            final double a2, final FieldUnivariateDerivative2<T> b2) {
  726.         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
  727.                                                                         a2, b2.f0),
  728.                                                 b1.f0.linearCombination(a1, b1.f1,
  729.                                                                         a2, b2.f1),
  730.                                                 b1.f0.linearCombination(a1, b1.f2,
  731.                                                                         a2, b2.f2));
  732.     }

  733.     /** {@inheritDoc} */
  734.     @Override
  735.     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
  736.                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2,
  737.                                                            final FieldUnivariateDerivative2<T> a3, final FieldUnivariateDerivative2<T> b3) {
  738.         final Field<T> field = a1.f0.getField();
  739.         final T[]      u1     = MathArrays.buildArray(field, 6);
  740.         final T[]      v1     = MathArrays.buildArray(field, 6);
  741.         u1[0] = a1.f0;
  742.         u1[1] = a1.f1;
  743.         u1[2] = a2.f0;
  744.         u1[3] = a2.f1;
  745.         u1[4] = a3.f0;
  746.         u1[5] = a3.f1;
  747.         v1[0] = b1.f1;
  748.         v1[1] = b1.f0;
  749.         v1[2] = b2.f1;
  750.         v1[3] = b2.f0;
  751.         v1[4] = b3.f1;
  752.         v1[5] = b3.f0;
  753.         final T[]      u2     = MathArrays.buildArray(field, 9);
  754.         final T[]      v2     = MathArrays.buildArray(field, 9);
  755.         u2[0] = a1.f0;
  756.         u2[1] = a1.f1.add(a1.f1);
  757.         u2[2] = a1.f2;
  758.         u2[3] = a2.f0;
  759.         u2[4] = a2.f1.add(a2.f1);
  760.         u2[5] = a2.f2;
  761.         u2[6] = a3.f0;
  762.         u2[7] = a3.f1.add(a3.f1);
  763.         u2[8] = a3.f2;
  764.         v2[0] = b1.f2;
  765.         v2[1] = b1.f1;
  766.         v2[2] = b1.f0;
  767.         v2[3] = b2.f2;
  768.         v2[4] = b2.f1;
  769.         v2[5] = b2.f0;
  770.         v2[6] = b3.f2;
  771.         v2[7] = b3.f1;
  772.         v2[8] = b3.f0;
  773.         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
  774.                                                                         a2.f0, b2.f0,
  775.                                                                         a3.f0, b3.f0),
  776.                                                 a1.f0.linearCombination(u1, v1),
  777.                                                 a1.f0.linearCombination(u2, v2));
  778.     }

  779.     /**
  780.      * Compute a linear combination.
  781.      * @param a1 first factor of the first term
  782.      * @param b1 second factor of the first term
  783.      * @param a2 first factor of the second term
  784.      * @param b2 second factor of the second term
  785.      * @param a3 first factor of the third term
  786.      * @param b3 second factor of the third term
  787.      * @return a<sub>1</sub>&times;b<sub>1</sub> +
  788.      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
  789.      * @see #linearCombination(double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2)
  790.      * @see #linearCombination(double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2)
  791.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  792.      */
  793.     public FieldUnivariateDerivative2<T> linearCombination(final T a1, final FieldUnivariateDerivative2<T> b1,
  794.                                                            final T a2, final FieldUnivariateDerivative2<T> b2,
  795.                                                            final T a3, final FieldUnivariateDerivative2<T> b3) {
  796.         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
  797.                                                                         a2, b2.f0,
  798.                                                                         a3, b3.f0),
  799.                                                 b1.f0.linearCombination(a1, b1.f1,
  800.                                                                         a2, b2.f1,
  801.                                                                         a3, b3.f1),
  802.                                                 b1.f0.linearCombination(a1, b1.f2,
  803.                                                                         a2, b2.f2,
  804.                                                                         a3, b3.f2));
  805.     }

  806.     /** {@inheritDoc} */
  807.     @Override
  808.     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
  809.                                                            final double a2, final FieldUnivariateDerivative2<T> b2,
  810.                                                            final double a3, final FieldUnivariateDerivative2<T> b3) {
  811.         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
  812.                                                                         a2, b2.f0,
  813.                                                                         a3, b3.f0),
  814.                                                 b1.f0.linearCombination(a1, b1.f1,
  815.                                                                         a2, b2.f1,
  816.                                                                         a3, b3.f1),
  817.                                                 b1.f0.linearCombination(a1, b1.f2,
  818.                                                                         a2, b2.f2,
  819.                                                                         a3, b3.f2));
  820.     }

  821.     /** {@inheritDoc} */
  822.     @Override
  823.     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
  824.                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2,
  825.                                                            final FieldUnivariateDerivative2<T> a3, final FieldUnivariateDerivative2<T> b3,
  826.                                                            final FieldUnivariateDerivative2<T> a4, final FieldUnivariateDerivative2<T> b4) {
  827.         final Field<T> field = a1.f0.getField();
  828.         final T[] u1 = MathArrays.buildArray(field, 8);
  829.         final T[] v1 = MathArrays.buildArray(field, 8);
  830.         u1[0] = a1.f0;
  831.         u1[1] = a1.f1;
  832.         u1[2] = a2.f0;
  833.         u1[3] = a2.f1;
  834.         u1[4] = a3.f0;
  835.         u1[5] = a3.f1;
  836.         u1[6] = a4.f0;
  837.         u1[7] = a4.f1;
  838.         v1[0] = b1.f1;
  839.         v1[1] = b1.f0;
  840.         v1[2] = b2.f1;
  841.         v1[3] = b2.f0;
  842.         v1[4] = b3.f1;
  843.         v1[5] = b3.f0;
  844.         v1[6] = b4.f1;
  845.         v1[7] = b4.f0;
  846.         final T[] u2 = MathArrays.buildArray(field, 12);
  847.         final T[] v2 = MathArrays.buildArray(field, 12);
  848.         u2[ 0] = a1.f0;
  849.         u2[ 1] = a1.f1.add(a1.f1);
  850.         u2[ 2] = a1.f2;
  851.         u2[ 3] = a2.f0;
  852.         u2[ 4] = a2.f1.add(a2.f1);
  853.         u2[ 5] = a2.f2;
  854.         u2[ 6] = a3.f0;
  855.         u2[ 7] = a3.f1.add(a3.f1);
  856.         u2[ 8] = a3.f2;
  857.         u2[ 9] = a4.f0;
  858.         u2[10] = a4.f1.add(a4.f1);
  859.         u2[11] = a4.f2;
  860.         v2[ 0] = b1.f2;
  861.         v2[ 1] = b1.f1;
  862.         v2[ 2] = b1.f0;
  863.         v2[ 3] = b2.f2;
  864.         v2[ 4] = b2.f1;
  865.         v2[ 5] = b2.f0;
  866.         v2[ 6] = b3.f2;
  867.         v2[ 7] = b3.f1;
  868.         v2[ 8] = b3.f0;
  869.         v2[ 9] = b4.f2;
  870.         v2[10] = b4.f1;
  871.         v2[11] = b4.f0;
  872.         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
  873.                                                                         a2.f0, b2.f0,
  874.                                                                         a3.f0, b3.f0,
  875.                                                                         a4.f0, b4.f0),
  876.                                                 a1.f0.linearCombination(u1, v1),
  877.                                                 a1.f0.linearCombination(u2, v2));
  878.     }

  879.     /** {@inheritDoc} */
  880.     @Override
  881.     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
  882.                                                            final double a2, final FieldUnivariateDerivative2<T> b2,
  883.                                                            final double a3, final FieldUnivariateDerivative2<T> b3,
  884.                                                            final double a4, final FieldUnivariateDerivative2<T> b4) {
  885.         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
  886.                                                                         a2, b2.f0,
  887.                                                                         a3, b3.f0,
  888.                                                                         a4, b4.f0),
  889.                                                 b1.f0.linearCombination(a1, b1.f1,
  890.                                                                         a2, b2.f1,
  891.                                                                         a3, b3.f1,
  892.                                                                         a4, b4.f1),
  893.                                                 b1.f0.linearCombination(a1, b1.f2,
  894.                                                                         a2, b2.f2,
  895.                                                                         a3, b3.f2,
  896.                                                                         a4, b4.f2));
  897.     }

  898.     /** {@inheritDoc} */
  899.     @Override
  900.     public FieldUnivariateDerivative2<T> getPi() {
  901.         final T zero = getValueField().getZero();
  902.         return new FieldUnivariateDerivative2<>(zero.getPi(), zero, zero);
  903.     }

  904.     /** Test for the equality of two univariate derivatives.
  905.      * <p>
  906.      * univariate derivatives are considered equal if they have the same derivatives.
  907.      * </p>
  908.      * @param other Object to test for equality to this
  909.      * @return true if two univariate derivatives are equal
  910.      */
  911.     @Override
  912.     public boolean equals(Object other) {

  913.         if (this == other) {
  914.             return true;
  915.         }

  916.         if (other instanceof FieldUnivariateDerivative2) {
  917.             @SuppressWarnings("unchecked")
  918.             final FieldUnivariateDerivative2<T> rhs = (FieldUnivariateDerivative2<T>) other;
  919.             return f0.equals(rhs.f0) && f1.equals(rhs.f1) && f2.equals(rhs.f2);
  920.         }

  921.         return false;

  922.     }

  923.     /** Get a hashCode for the univariate derivative.
  924.      * @return a hash code value for this object
  925.      */
  926.     @Override
  927.     public int hashCode() {
  928.         return 317 - 41 * f0.hashCode() + 57 * f1.hashCode() - 103 * f2.hashCode();
  929.     }

  930. }