FieldGradient.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 java.util.Arrays;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.hipparchus.Field;
  21. import org.hipparchus.exception.LocalizedCoreFormats;
  22. import org.hipparchus.exception.MathIllegalArgumentException;
  23. import org.hipparchus.util.FastMath;
  24. import org.hipparchus.util.FieldSinCos;
  25. import org.hipparchus.util.FieldSinhCosh;
  26. import org.hipparchus.util.MathArrays;
  27. import org.hipparchus.util.MathUtils;

  28. /** Class representing both the value and the differentials of a function.
  29.  * <p>This class is a stripped-down version of {@link FieldDerivativeStructure}
  30.  * with {@link FieldDerivativeStructure#getOrder() derivation order} limited to one.
  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 FieldGradient} 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 FieldUnivariateDerivative2
  52.  * @since 1.7
  53.  */
  54. public class FieldGradient<T extends CalculusFieldElement<T>> implements FieldDerivative1<T, FieldGradient<T>> {

  55.     /** Value of the function. */
  56.     private final T value;

  57.     /** Gradient of the function. */
  58.     private final T[] grad;

  59.     /** Build an instance with values and unitialized derivatives array.
  60.      * @param value value of the function
  61.      * @param freeParameters number of free parameters
  62.      */
  63.     private FieldGradient(final T value, int freeParameters) {
  64.         this.value = value;
  65.         this.grad  = MathArrays.buildArray(value.getField(), freeParameters);
  66.     }

  67.     /** Build an instance with values and derivative.
  68.      * @param value value of the function
  69.      * @param gradient gradient of the function
  70.      */
  71.     @SafeVarargs
  72.     public FieldGradient(final T value, final T... gradient) {
  73.         this(value, gradient.length);
  74.         System.arraycopy(gradient, 0, grad, 0, grad.length);
  75.     }

  76.     /** Build an instance from a {@link FieldDerivativeStructure}.
  77.      * @param ds derivative structure
  78.      * @exception MathIllegalArgumentException if {@code ds} order
  79.      * is not 1
  80.      */
  81.     public FieldGradient(final FieldDerivativeStructure<T> ds) throws MathIllegalArgumentException {
  82.         this(ds.getValue(), ds.getFreeParameters());
  83.         MathUtils.checkDimension(ds.getOrder(), 1);
  84.         System.arraycopy(ds.getAllDerivatives(), 1, grad, 0, grad.length);
  85.     }

  86.     /** Build an instance corresponding to a constant value.
  87.      * @param freeParameters number of free parameters (i.e. dimension of the gradient)
  88.      * @param value constant value of the function
  89.      * @param <T> the type of the function parameters and value
  90.      * @return a {@code FieldGradient} with a constant value and all derivatives set to 0.0
  91.      */
  92.     public static <T extends CalculusFieldElement<T>> FieldGradient<T> constant(final int freeParameters, final T value) {
  93.         final FieldGradient<T> g = new FieldGradient<>(value, freeParameters);
  94.         Arrays.fill(g.grad, value.getField().getZero());
  95.         return g;
  96.     }

  97.     /** Build a {@code Gradient} representing a variable.
  98.      * <p>Instances built using this method are considered
  99.      * to be the free variables with respect to which differentials
  100.      * are computed. As such, their differential with respect to
  101.      * themselves is +1.</p>
  102.      * @param freeParameters number of free parameters (i.e. dimension of the gradient)
  103.      * @param index index of the variable (from 0 to {@link #getFreeParameters() getFreeParameters()} - 1)
  104.      * @param value value of the variable
  105.      * @param <T> the type of the function parameters and value
  106.      * @return a {@code FieldGradient} with a constant value and all derivatives set to 0.0 except the
  107.      * one at {@code index} which will be set to 1.0
  108.      */
  109.     public static <T extends CalculusFieldElement<T>> FieldGradient<T> variable(final int freeParameters,
  110.                                                                                 final int index, final T value) {
  111.         final FieldGradient<T> g = new FieldGradient<>(value, freeParameters);
  112.         final Field<T> field = value.getField();
  113.         Arrays.fill(g.grad, field.getZero());
  114.         g.grad[index] = field.getOne();
  115.         return g;
  116.     }

  117.     /** Get the {@link Field} the value and parameters of the function belongs to.
  118.      * @return {@link Field} the value and parameters of the function belongs to
  119.      */
  120.     public Field<T> getValueField() {
  121.         return value.getField();
  122.     }

  123.     /** {@inheritDoc} */
  124.     @Override
  125.     public FieldGradient<T> newInstance(final double c) {
  126.         return newInstance(getValueField().getZero().newInstance(c));
  127.     }

  128.     /** {@inheritDoc} */
  129.     @Override
  130.     public FieldGradient<T> newInstance(final T c) {
  131.         return new FieldGradient<>(c, MathArrays.buildArray(value.getField(), grad.length));
  132.     }

  133.     /** {@inheritDoc} */
  134.     @Override
  135.     public FieldGradient<T> withValue(final T v) {
  136.         return new FieldGradient<>(v, grad);
  137.     }

  138.     /** {@inheritDoc} */
  139.     @Override
  140.     public FieldGradient<T> getAddendum() {
  141.         return new FieldGradient<>(value.getField().getZero(), grad);
  142.     }

  143.     /** Get the value part of the function.
  144.      * @return value part of the value of the function
  145.      */
  146.     @Override
  147.     public T getValue() {
  148.         return value;
  149.     }

  150.     /** Get the gradient part of the function.
  151.      * @return gradient part of the value of the function
  152.      */
  153.     public T[] getGradient() {
  154.         return grad.clone();
  155.     }

  156.     /** Get the number of free parameters.
  157.      * @return number of free parameters
  158.      */
  159.     @Override
  160.     public int getFreeParameters() {
  161.         return grad.length;
  162.     }

  163.     /** {@inheritDoc} */
  164.     @Override
  165.     public T getPartialDerivative(final int ... orders)
  166.         throws MathIllegalArgumentException {

  167.         // check the number of components
  168.         if (orders.length != grad.length) {
  169.             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
  170.                                                    orders.length, grad.length);
  171.         }

  172.         // check that either all derivation orders are set to 0,
  173.         // or that only one is set to 1 and all other ones are set to 0
  174.         int selected = -1;
  175.         for (int i = 0; i < orders.length; ++i) {
  176.             if (orders[i] != 0) {
  177.                 if (selected >= 0 || orders[i] != 1) {
  178.                      throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED,
  179.                                                            orders[i]);
  180.                 }
  181.                 // found the component set to derivation order 1
  182.                 selected = i;
  183.             }
  184.         }

  185.         return (selected < 0) ? value : grad[selected];

  186.     }

  187.     /** Get the partial derivative with respect to one parameter.
  188.      * @param n index of the parameter (counting from 0)
  189.      * @return partial derivative with respect to the n<sup>th</sup> parameter
  190.      * @exception MathIllegalArgumentException if n is either negative or larger
  191.      * or equal to {@link #getFreeParameters()}
  192.      */
  193.     public T getPartialDerivative(final int n) throws MathIllegalArgumentException {
  194.         if (n < 0 || n >= grad.length) {
  195.             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, n, 0, grad.length - 1);
  196.         }
  197.         return grad[n];
  198.     }

  199.     /** Convert the instance to a {@link FieldDerivativeStructure}.
  200.      * @return derivative structure with same value and derivative as the instance
  201.      */
  202.     public FieldDerivativeStructure<T> toDerivativeStructure() {
  203.         final T[] derivatives = MathArrays.buildArray(getValueField(), 1 + grad.length);
  204.         derivatives[0] = value;
  205.         System.arraycopy(grad, 0, derivatives, 1, grad.length);
  206.         return getField().getConversionFactory().build(derivatives);
  207.     }

  208.     /** {@inheritDoc} */
  209.     @Override
  210.     public FieldGradient<T> add(final double a) {
  211.         return new FieldGradient<>(value.add(a), grad);
  212.     }

  213.     /** {@inheritDoc} */
  214.     @Override
  215.     public FieldGradient<T> add(final FieldGradient<T> a) {
  216.         final FieldGradient<T> result = newInstance(value.add(a.value));
  217.         for (int i = 0; i < grad.length; ++i) {
  218.             result.grad[i] = grad[i].add(a.grad[i]);
  219.         }
  220.         return result;
  221.     }

  222.     /** {@inheritDoc} */
  223.     @Override
  224.     public FieldGradient<T> subtract(final double a) {
  225.         return new FieldGradient<>(value.subtract(a), grad);
  226.     }

  227.     /** {@inheritDoc} */
  228.     @Override
  229.     public FieldGradient<T> subtract(final FieldGradient<T> a) {
  230.         final FieldGradient<T> result = newInstance(value.subtract(a.value));
  231.         for (int i = 0; i < grad.length; ++i) {
  232.             result.grad[i] = grad[i].subtract(a.grad[i]);
  233.         }
  234.         return result;
  235.     }

  236.     /** '&times;' operator.
  237.      * @param n right hand side parameter of the operator
  238.      * @return this&times;n
  239.      */
  240.     public FieldGradient<T> multiply(final T n) {
  241.         final FieldGradient<T> result = newInstance(value.multiply(n));
  242.         for (int i = 0; i < grad.length; ++i) {
  243.             result.grad[i] = grad[i].multiply(n);
  244.         }
  245.         return result;
  246.     }

  247.     /** {@inheritDoc} */
  248.     @Override
  249.     public FieldGradient<T> multiply(final int n) {
  250.         final FieldGradient<T> result = newInstance(value.multiply(n));
  251.         for (int i = 0; i < grad.length; ++i) {
  252.             result.grad[i] = grad[i].multiply(n);
  253.         }
  254.         return result;
  255.     }

  256.     /** {@inheritDoc} */
  257.     @Override
  258.     public FieldGradient<T> multiply(final double a) {
  259.         final FieldGradient<T> result = newInstance(value.multiply(a));
  260.         for (int i = 0; i < grad.length; ++i) {
  261.             result.grad[i] = grad[i].multiply(a);
  262.         }
  263.         return result;
  264.     }

  265.     /** {@inheritDoc} */
  266.     @Override
  267.     public FieldGradient<T> multiply(final FieldGradient<T> a) {
  268.         final FieldGradient<T> result = newInstance(value.multiply(a.value));
  269.         for (int i = 0; i < grad.length; ++i) {
  270.             result.grad[i] = grad[i].multiply(a.value).add(value.multiply(a.grad[i]));
  271.         }
  272.         return result;
  273.     }

  274.     /** '&divide;' operator.
  275.      * @param a right hand side parameter of the operator
  276.      * @return this&divide;a
  277.      */
  278.     public FieldGradient<T> divide(final T a) {
  279.         final FieldGradient<T> result = newInstance(value.divide(a));
  280.         for (int i = 0; i < grad.length; ++i) {
  281.             result.grad[i] = grad[i].divide(a);
  282.         }
  283.         return result;
  284.     }

  285.     /** {@inheritDoc} */
  286.     @Override
  287.     public FieldGradient<T> divide(final double a) {
  288.         final FieldGradient<T> result = newInstance(value.divide(a));
  289.         for (int i = 0; i < grad.length; ++i) {
  290.             result.grad[i] = grad[i].divide(a);
  291.         }
  292.         return result;
  293.     }

  294.     /** {@inheritDoc} */
  295.     @Override
  296.     public FieldGradient<T> divide(final FieldGradient<T> a) {
  297.         final T inv1 = a.value.reciprocal();
  298.         final T inv2 = inv1.multiply(inv1);
  299.         final FieldGradient<T> result = newInstance(value.multiply(inv1));
  300.         for (int i = 0; i < grad.length; ++i) {
  301.             result.grad[i] = grad[i].multiply(a.value).subtract(value.multiply(a.grad[i])).multiply(inv2);
  302.         }
  303.         return result;
  304.     }

  305.     /** IEEE remainder operator.
  306.      * @param a right hand side parameter of the operator
  307.      * @return this - n &times; a where n is the closest integer to this/a
  308.      * (the even integer is chosen for n if this/a is halfway between two integers)
  309.      */
  310.     public FieldGradient<T> remainder(final T a) {
  311.         return new FieldGradient<>(FastMath.IEEEremainder(value, a), grad);
  312.     }

  313.     /** {@inheritDoc} */
  314.     @Override
  315.     public FieldGradient<T> remainder(final double a) {
  316.         return new FieldGradient<>(FastMath.IEEEremainder(value, a), grad);
  317.     }

  318.     /** {@inheritDoc} */
  319.     @Override
  320.     public FieldGradient<T> remainder(final FieldGradient<T> a) {

  321.         // compute k such that lhs % rhs = lhs - k rhs
  322.         final T rem = FastMath.IEEEremainder(value, a.value);
  323.         final T k   = FastMath.rint(value.subtract(rem).divide(a.value));

  324.         final FieldGradient<T> result = newInstance(rem);
  325.         for (int i = 0; i < grad.length; ++i) {
  326.             result.grad[i] = grad[i].subtract(k.multiply(a.grad[i]));
  327.         }
  328.         return result;

  329.     }

  330.     /** {@inheritDoc} */
  331.     @Override
  332.     public FieldGradient<T> negate() {
  333.         final FieldGradient<T> result = newInstance(value.negate());
  334.         for (int i = 0; i < grad.length; ++i) {
  335.             result.grad[i] = grad[i].negate();
  336.         }
  337.         return result;
  338.     }

  339.     /** {@inheritDoc} */
  340.     @Override
  341.     public FieldGradient<T> abs() {
  342.         if (Double.doubleToLongBits(value.getReal()) < 0) {
  343.             // we use the bits representation to also handle -0.0
  344.             return negate();
  345.         } else {
  346.             return this;
  347.         }
  348.     }

  349.     /**
  350.      * Returns the instance with the sign of the argument.
  351.      * A NaN {@code sign} argument is treated as positive.
  352.      *
  353.      * @param sign the sign for the returned value
  354.      * @return the instance with the same sign as the {@code sign} argument
  355.      */
  356.     public FieldGradient<T> copySign(final T sign) {
  357.         long m = Double.doubleToLongBits(value.getReal());
  358.         long s = Double.doubleToLongBits(sign.getReal());
  359.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  360.             return this;
  361.         }
  362.         return negate(); // flip sign
  363.     }

  364.     /** {@inheritDoc} */
  365.     @Override
  366.     public FieldGradient<T> copySign(final FieldGradient<T> sign) {
  367.         long m = Double.doubleToLongBits(value.getReal());
  368.         long s = Double.doubleToLongBits(sign.value.getReal());
  369.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  370.             return this;
  371.         }
  372.         return negate(); // flip sign
  373.     }

  374.     /** {@inheritDoc} */
  375.     @Override
  376.     public FieldGradient<T> copySign(final double sign) {
  377.         long m = Double.doubleToLongBits(value.getReal());
  378.         long s = Double.doubleToLongBits(sign);
  379.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  380.             return this;
  381.         }
  382.         return negate(); // flip sign
  383.     }

  384.     /** {@inheritDoc} */
  385.     @Override
  386.     public FieldGradient<T> scalb(final int n) {
  387.         final FieldGradient<T> result = newInstance(FastMath.scalb(value, n));
  388.         for (int i = 0; i < grad.length; ++i) {
  389.             result.grad[i] = FastMath.scalb(grad[i], n);
  390.         }
  391.         return result;
  392.     }

  393.     /** {@inheritDoc} */
  394.     @Override
  395.     public FieldGradient<T> hypot(final FieldGradient<T> y) {

  396.         if (Double.isInfinite(value.getReal()) || Double.isInfinite(y.value.getReal())) {
  397.             return newInstance(Double.POSITIVE_INFINITY);
  398.         } else if (Double.isNaN(value.getReal()) || Double.isNaN(y.value.getReal())) {
  399.             return newInstance(Double.NaN);
  400.         } else {

  401.             final int expX = getExponent();
  402.             final int expY = y.getExponent();
  403.             if (expX > expY + 27) {
  404.                 // y is negligible with respect to x
  405.                 return abs();
  406.             } else if (expY > expX + 27) {
  407.                 // x is negligible with respect to y
  408.                 return y.abs();
  409.             } else {

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

  412.                 // scale parameters without losing precision
  413.                 final FieldGradient<T> scaledX = scalb(-middleExp);
  414.                 final FieldGradient<T> scaledY = y.scalb(-middleExp);

  415.                 // compute scaled hypotenuse
  416.                 final FieldGradient<T> scaledH =
  417.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  418.                 // remove scaling
  419.                 return scaledH.scalb(middleExp);

  420.             }

  421.         }
  422.     }

  423.     /** Compute composition of the instance by a function.
  424.      * @param g0 value of the function at the current point (i.e. at {@code g(getValue())})
  425.      * @param g1 first derivative of the function at the current point (i.e. at {@code g'(getValue())})
  426.      * @return g(this)
  427.      */
  428.     @Override
  429.     public FieldGradient<T> compose(final T g0, final T g1) {
  430.         final FieldGradient<T> result = newInstance(g0);
  431.         for (int i = 0; i < grad.length; ++i) {
  432.             result.grad[i] = g1.multiply(grad[i]);
  433.         }
  434.         return result;
  435.     }

  436.     /** {@inheritDoc} */
  437.     @Override
  438.     public FieldGradient<T> rootN(final int n) {
  439.         if (n == 2) {
  440.             return sqrt();
  441.         } else if (n == 3) {
  442.             return cbrt();
  443.         } else {
  444.             final T r = FastMath.pow(value, 1.0 / n);
  445.             return compose(r, FastMath.pow(r, n - 1).multiply(n).reciprocal());
  446.         }
  447.     }

  448.     /** {@inheritDoc} */
  449.     @Override
  450.     public FieldGradientField<T> getField() {
  451.         return FieldGradientField.getField(getValueField(), getFreeParameters());
  452.     }

  453.     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldGradient}
  454.      * @param a number to exponentiate
  455.      * @param x power to apply
  456.      * @param <T> the type of the function parameters and value
  457.      * @return a<sup>x</sup>
  458.      */
  459.     public static <T extends CalculusFieldElement<T>> FieldGradient<T> pow(final double a, final FieldGradient<T> x) {
  460.         if (a == 0) {
  461.             return x.getField().getZero();
  462.         } else {
  463.             final T aX    = FastMath.pow(x.value.newInstance(a), x.value);
  464.             final T aXlnA = aX.multiply(FastMath.log(a));
  465.             final FieldGradient<T> result = x.newInstance(aX);
  466.             for (int i = 0; i < x.grad.length; ++i) {
  467.                 result.grad[i] =  aXlnA.multiply(x.grad[i]);
  468.             }
  469.             return result;
  470.         }
  471.     }

  472.     /** {@inheritDoc} */
  473.     @Override
  474.     public FieldGradient<T> pow(final double p) {
  475.         if (p == 0) {
  476.             return getField().getOne();
  477.         } else {
  478.             final T f0Pm1 = FastMath.pow(value, p - 1);
  479.             return compose(f0Pm1.multiply(value), f0Pm1.multiply(p));
  480.         }
  481.     }

  482.     /** {@inheritDoc} */
  483.     @Override
  484.     public FieldGradient<T> pow(final int n) {
  485.         if (n == 0) {
  486.             return getField().getOne();
  487.         } else {
  488.             final T f0Nm1 = FastMath.pow(value, n - 1);
  489.             return compose(f0Nm1.multiply(value), f0Nm1.multiply(n));
  490.         }
  491.     }

  492.     /** {@inheritDoc} */
  493.     @Override
  494.     public FieldSinCos<FieldGradient<T>> sinCos() {
  495.         final FieldSinCos<T> sinCos = FastMath.sinCos(value);
  496.         final FieldGradient<T> sin = newInstance(sinCos.sin());
  497.         final FieldGradient<T> cos = newInstance(sinCos.cos());
  498.         final T mSin = sinCos.sin().negate();
  499.         for (int i = 0; i < grad.length; ++i) {
  500.             sin.grad[i] =  grad[i].multiply(sinCos.cos());
  501.             cos.grad[i] =  grad[i].multiply(mSin);
  502.         }
  503.         return new FieldSinCos<>(sin, cos);
  504.     }

  505.     /** {@inheritDoc} */
  506.     @Override
  507.     public FieldGradient<T> atan2(final FieldGradient<T> x) {
  508.         final T inv = value.square().add(x.value.multiply(x.value)).reciprocal();
  509.         final FieldGradient<T> result = newInstance(FastMath.atan2(value, x.value));
  510.         final T xValueInv = x.value.multiply(inv);
  511.         final T mValueInv = value.negate().multiply(inv);
  512.         for (int i = 0; i < grad.length; ++i) {
  513.             result.grad[i] = xValueInv.multiply(grad[i]).add(x.grad[i].multiply(mValueInv));
  514.         }
  515.         return result;
  516.     }

  517.     /** {@inheritDoc} */
  518.     @Override
  519.     public FieldSinhCosh<FieldGradient<T>> sinhCosh() {
  520.         final FieldSinhCosh<T> sinhCosh = FastMath.sinhCosh(value);
  521.         final FieldGradient<T> sinh = newInstance(sinhCosh.sinh());
  522.         final FieldGradient<T> cosh = newInstance(sinhCosh.cosh());
  523.         for (int i = 0; i < grad.length; ++i) {
  524.             sinh.grad[i] = grad[i].multiply(sinhCosh.cosh());
  525.             cosh.grad[i] = grad[i].multiply(sinhCosh.sinh());
  526.         }
  527.         return new FieldSinhCosh<>(sinh, cosh);
  528.     }

  529.     /** {@inheritDoc} */
  530.     @Override
  531.     public FieldGradient<T> toDegrees() {
  532.         final FieldGradient<T> result = newInstance(FastMath.toDegrees(value));
  533.         for (int i = 0; i < grad.length; ++i) {
  534.             result.grad[i] = FastMath.toDegrees(grad[i]);
  535.         }
  536.         return result;
  537.     }

  538.     /** {@inheritDoc} */
  539.     @Override
  540.     public FieldGradient<T> toRadians() {
  541.         final FieldGradient<T> result = newInstance(FastMath.toRadians(value));
  542.         for (int i = 0; i < grad.length; ++i) {
  543.             result.grad[i] = FastMath.toRadians(grad[i]);
  544.         }
  545.         return result;
  546.     }

  547.     /** Evaluate Taylor expansion of a gradient.
  548.      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
  549.      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
  550.      */
  551.     public T taylor(final double... delta) {
  552.         T result = value;
  553.         for (int i = 0; i < grad.length; ++i) {
  554.             result = result.add(grad[i].multiply(delta[i]));
  555.         }
  556.         return result;
  557.     }

  558.     /** Evaluate Taylor expansion of a gradient.
  559.      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
  560.      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
  561.      */
  562.     public T taylor(@SuppressWarnings("unchecked") final T... delta) {
  563.         T result = value;
  564.         for (int i = 0; i < grad.length; ++i) {
  565.             result = result.add(grad[i].multiply(delta[i]));
  566.         }
  567.         return result;
  568.     }

  569.     /** {@inheritDoc} */
  570.     @Override
  571.     public FieldGradient<T> linearCombination(final FieldGradient<T>[] a, final FieldGradient<T>[] b) {

  572.         // extract values and first derivatives
  573.         final Field<T> field = a[0].value.getField();
  574.         final int n  = a.length;
  575.         final T[] a0 = MathArrays.buildArray(field, n);
  576.         final T[] b0 = MathArrays.buildArray(field, n);
  577.         final T[] a1 = MathArrays.buildArray(field, 2 * n);
  578.         final T[] b1 = MathArrays.buildArray(field, 2 * n);
  579.         for (int i = 0; i < n; ++i) {
  580.             final FieldGradient<T> ai = a[i];
  581.             final FieldGradient<T> bi = b[i];
  582.             a0[i]         = ai.value;
  583.             b0[i]         = bi.value;
  584.             a1[2 * i]     = ai.value;
  585.             b1[2 * i + 1] = bi.value;
  586.         }

  587.         final FieldGradient<T> result = newInstance(a[0].value.linearCombination(a0, b0));
  588.         for (int k = 0; k < grad.length; ++k) {
  589.             for (int i = 0; i < n; ++i) {
  590.                 a1[2 * i + 1] = a[i].grad[k];
  591.                 b1[2 * i]     = b[i].grad[k];
  592.             }
  593.             result.grad[k] = a[0].value.linearCombination(a1, b1);
  594.         }
  595.         return result;

  596.     }

  597.     /**
  598.      * Compute a linear combination.
  599.      * @param a Factors.
  600.      * @param b Factors.
  601.      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
  602.      * @throws MathIllegalArgumentException if arrays dimensions don't match
  603.      */
  604.     public FieldGradient<T> linearCombination(final T[] a, final FieldGradient<T>[] b) {

  605.         // extract values and first derivatives
  606.         final Field<T> field = b[0].value.getField();
  607.         final int      n  = b.length;
  608.         final T[] b0 = MathArrays.buildArray(field, n);
  609.         final T[] b1 = MathArrays.buildArray(field, n);
  610.         for (int i = 0; i < n; ++i) {
  611.             b0[i] = b[i].value;
  612.         }

  613.         final FieldGradient<T> result = newInstance(b[0].value.linearCombination(a, b0));
  614.         for (int k = 0; k < grad.length; ++k) {
  615.             for (int i = 0; i < n; ++i) {
  616.                 b1[i] = b[i].grad[k];
  617.             }
  618.             result.grad[k] = b[0].value.linearCombination(a, b1);
  619.         }
  620.         return result;

  621.     }

  622.     /** {@inheritDoc} */
  623.     @Override
  624.     public FieldGradient<T> linearCombination(final double[] a, final FieldGradient<T>[] b) {

  625.         // extract values and first derivatives
  626.         final Field<T> field = b[0].value.getField();
  627.         final int      n  = b.length;
  628.         final T[] b0 = MathArrays.buildArray(field, n);
  629.         final T[] b1 = MathArrays.buildArray(field, n);
  630.         for (int i = 0; i < n; ++i) {
  631.             b0[i] = b[i].value;
  632.         }

  633.         final FieldGradient<T> result = newInstance(b[0].value.linearCombination(a, b0));
  634.         for (int k = 0; k < grad.length; ++k) {
  635.             for (int i = 0; i < n; ++i) {
  636.                 b1[i] = b[i].grad[k];
  637.             }
  638.             result.grad[k] = b[0].value.linearCombination(a, b1);
  639.         }
  640.         return result;

  641.     }

  642.     /** {@inheritDoc} */
  643.     @Override
  644.     public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
  645.                                               final FieldGradient<T> a2, final FieldGradient<T> b2) {
  646.         final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
  647.                                                                                a2.value, b2.value));
  648.         for (int i = 0; i < b1.grad.length; ++i) {
  649.             result.grad[i] = a1.value.linearCombination(a1.value,       b1.grad[i],
  650.                                                             a1.grad[i], b1.value,
  651.                                                             a2.value,       b2.grad[i],
  652.                                                             a2.grad[i], b2.value);
  653.         }
  654.         return result;
  655.     }

  656.     /** {@inheritDoc} */
  657.     @Override
  658.     public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
  659.                                               final double a2, final FieldGradient<T> b2) {
  660.         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
  661.                                                                                a2, b2.value));
  662.         for (int i = 0; i < b1.grad.length; ++i) {
  663.             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
  664.                                                             a2, b2.grad[i]);
  665.         }
  666.         return result;
  667.     }

  668.     /** {@inheritDoc} */
  669.     @Override
  670.     public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
  671.                                               final FieldGradient<T> a2, final FieldGradient<T> b2,
  672.                                               final FieldGradient<T> a3, final FieldGradient<T> b3) {
  673.         final Field<T> field = a1.value.getField();
  674.         final T[] a = MathArrays.buildArray(field, 6);
  675.         final T[] b = MathArrays.buildArray(field, 6);
  676.         a[0] = a1.value;
  677.         a[2] = a2.value;
  678.         a[4] = a3.value;
  679.         b[1] = b1.value;
  680.         b[3] = b2.value;
  681.         b[5] = b3.value;
  682.         final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
  683.                                                                                a2.value, b2.value,
  684.                                                                                a3.value, b3.value));
  685.         for (int i = 0; i < b1.grad.length; ++i) {
  686.             a[1] = a1.grad[i];
  687.             a[3] = a2.grad[i];
  688.             a[5] = a3.grad[i];
  689.             b[0] = b1.grad[i];
  690.             b[2] = b2.grad[i];
  691.             b[4] = b3.grad[i];
  692.             result.grad[i] = a1.value.linearCombination(a, b);
  693.         }
  694.         return result;
  695.     }

  696.     /**
  697.      * Compute a linear combination.
  698.      * @param a1 first factor of the first term
  699.      * @param b1 second factor of the first term
  700.      * @param a2 first factor of the second term
  701.      * @param b2 second factor of the second term
  702.      * @param a3 first factor of the third term
  703.      * @param b3 second factor of the third term
  704.      * @return a<sub>1</sub>&times;b<sub>1</sub> +
  705.      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
  706.      * @see #linearCombination(double, FieldGradient, double, FieldGradient)
  707.      * @see #linearCombination(double, FieldGradient, double, FieldGradient, double, FieldGradient, double, FieldGradient)
  708.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  709.      */
  710.     public FieldGradient<T> linearCombination(final T a1, final FieldGradient<T> b1,
  711.                                               final T a2, final FieldGradient<T> b2,
  712.                                               final T a3, final FieldGradient<T> b3) {
  713.         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
  714.                                                                                a2, b2.value,
  715.                                                                                a3, b3.value));
  716.         for (int i = 0; i < b1.grad.length; ++i) {
  717.             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
  718.                                                         a2, b2.grad[i],
  719.                                                         a3, b3.grad[i]);
  720.         }
  721.         return result;
  722.     }

  723.     /** {@inheritDoc} */
  724.     @Override
  725.     public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
  726.                                               final double a2, final FieldGradient<T> b2,
  727.                                               final double a3, final FieldGradient<T> b3) {
  728.         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
  729.                                                                                a2, b2.value,
  730.                                                                                a3, b3.value));
  731.         for (int i = 0; i < b1.grad.length; ++i) {
  732.             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
  733.                                                             a2, b2.grad[i],
  734.                                                             a3, b3.grad[i]);
  735.         }
  736.         return result;
  737.     }

  738.     /** {@inheritDoc} */
  739.     @Override
  740.     public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
  741.                                               final FieldGradient<T> a2, final FieldGradient<T> b2,
  742.                                               final FieldGradient<T> a3, final FieldGradient<T> b3,
  743.                                               final FieldGradient<T> a4, final FieldGradient<T> b4) {
  744.         final Field<T> field = a1.value.getField();
  745.         final T[] a = MathArrays.buildArray(field, 8);
  746.         final T[] b = MathArrays.buildArray(field, 8);
  747.         a[0] = a1.value;
  748.         a[2] = a2.value;
  749.         a[4] = a3.value;
  750.         a[6] = a4.value;
  751.         b[1] = b1.value;
  752.         b[3] = b2.value;
  753.         b[5] = b3.value;
  754.         b[7] = b4.value;
  755.         final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
  756.                                                                                a2.value, b2.value,
  757.                                                                                a3.value, b3.value,
  758.                                                                                a4.value, b4.value));
  759.         for (int i = 0; i < b1.grad.length; ++i) {
  760.             a[1] = a1.grad[i];
  761.             a[3] = a2.grad[i];
  762.             a[5] = a3.grad[i];
  763.             a[7] = a4.grad[i];
  764.             b[0] = b1.grad[i];
  765.             b[2] = b2.grad[i];
  766.             b[4] = b3.grad[i];
  767.             b[6] = b4.grad[i];
  768.             result.grad[i] = a1.value.linearCombination(a, b);
  769.         }
  770.         return result;
  771.     }

  772.     /** {@inheritDoc} */
  773.     @Override
  774.     public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
  775.                                               final double a2, final FieldGradient<T> b2,
  776.                                               final double a3, final FieldGradient<T> b3,
  777.                                               final double a4, final FieldGradient<T> b4) {
  778.         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
  779.                                                                                a2, b2.value,
  780.                                                                                a3, b3.value,
  781.                                                                                a4, b4.value));
  782.         for (int i = 0; i < b1.grad.length; ++i) {
  783.             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
  784.                                                             a2, b2.grad[i],
  785.                                                             a3, b3.grad[i],
  786.                                                             a4, b4.grad[i]);
  787.         }
  788.         return result;
  789.     }

  790.     /**
  791.      * Add an independent variable to the Taylor expansion.
  792.      * @return object with one more variable
  793.      * @since 4.0
  794.      */
  795.     public FieldGradient<T> stackVariable() {
  796.         final T[] gradient = MathArrays.buildArray(getValueField(), this.getFreeParameters() + 1);
  797.         System.arraycopy(this.grad, 0, gradient, 0, this.getFreeParameters());
  798.         return new FieldGradient<>(this.value, gradient);
  799.     }

  800.     /** {@inheritDoc} */
  801.     @Override
  802.     public FieldGradient<T> getPi() {
  803.         return new FieldGradient<>(getValueField().getZero().getPi(), getFreeParameters());
  804.     }

  805.     /** Test for the equality of two univariate derivatives.
  806.      * <p>
  807.      * univariate derivatives are considered equal if they have the same derivatives.
  808.      * </p>
  809.      * @param other Object to test for equality to this
  810.      * @return true if two univariate derivatives are equal
  811.      */
  812.     @Override
  813.     public boolean equals(Object other) {

  814.         if (this == other) {
  815.             return true;
  816.         }

  817.         if (other instanceof FieldGradient) {
  818.             @SuppressWarnings("unchecked")
  819.             final FieldGradient<T> rhs = (FieldGradient<T>) other;
  820.             if (!value.equals(rhs.value) || grad.length != rhs.grad.length) {
  821.                 return false;
  822.             }
  823.             for (int i = 0; i < grad.length; ++i) {
  824.                 if (!grad[i].equals(rhs.grad[i])) {
  825.                     return false;
  826.                 }
  827.             }
  828.             return true;
  829.         }

  830.         return false;

  831.     }

  832.     /** Get a hashCode for the univariate derivative.
  833.      * @return a hash code value for this object
  834.      */
  835.     @Override
  836.     public int hashCode() {
  837.         return 129 + 7 *value.hashCode() - 15 * Arrays.hashCode(grad);
  838.     }

  839. }