FieldDerivativeStructure.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.MathIllegalArgumentException;
  21. import org.hipparchus.exception.MathRuntimeException;
  22. import org.hipparchus.util.FieldSinCos;
  23. import org.hipparchus.util.FieldSinhCosh;
  24. import org.hipparchus.util.MathArrays;
  25. import org.hipparchus.util.MathUtils;

  26. import java.util.Arrays;

  27. /** Class representing both the value and the differentials of a function.
  28.  * <p>This class is similar to {@link DerivativeStructure} except function
  29.  * parameters and value can be any {@link CalculusFieldElement}.</p>
  30.  * <p>Instances of this class are guaranteed to be immutable.</p>
  31.  * @see DerivativeStructure
  32.  * @see FDSFactory
  33.  * @see DSCompiler
  34.  * @param <T> the type of the field elements
  35.  */
  36. public class FieldDerivativeStructure<T extends CalculusFieldElement<T>>
  37.     implements FieldDerivative<T, FieldDerivativeStructure<T>> {

  38.     /** Factory that built the instance. */
  39.     private final FDSFactory<T> factory;

  40.     /** Combined array holding all values. */
  41.     private final T[] data;

  42.     /** Build an instance with all values and derivatives set to 0.
  43.      * @param factory factory that built the instance
  44.      * @param data combined array holding all values
  45.      */
  46.     FieldDerivativeStructure(final FDSFactory<T> factory, final T[] data) {
  47.         this.factory = factory;
  48.         this.data    = data.clone();
  49.     }

  50.     /** Build an instance with all values and derivatives set to 0.
  51.      * @param factory factory that built the instance
  52.      * @since 1.4
  53.      */
  54.     FieldDerivativeStructure(final FDSFactory<T> factory) {
  55.         this.factory = factory;
  56.         this.data    = MathArrays.buildArray(factory.getValueField(), factory.getCompiler().getSize());
  57.     }

  58.     /** {@inheritDoc} */
  59.     @Override
  60.     public FieldDerivativeStructure<T> newInstance(final double value) {
  61.         return factory.constant(value);
  62.     }

  63.     /** {@inheritDoc} */
  64.     @Override
  65.     public FieldDerivativeStructure<T> newInstance(final T value) {
  66.         return factory.constant(value);
  67.     }

  68.     /** {@inheritDoc} */
  69.     @Override
  70.     public FieldDerivativeStructure<T> withValue(final T value) {
  71.         final FieldDerivativeStructure<T> ds = factory.build();
  72.         System.arraycopy(data, 1, ds.data, 1, data.length - 1);
  73.         ds.data[0] = value;
  74.         return ds;
  75.     }

  76.     /** Get the factory that built the instance.
  77.      * @return factory that built the instance
  78.      */
  79.     public FDSFactory<T> getFactory() {
  80.         return factory;
  81.     }

  82.     /** {@inheritDoc} */
  83.     @Override
  84.     public int getFreeParameters() {
  85.         return getFactory().getCompiler().getFreeParameters();
  86.     }

  87.     /** {@inheritDoc} */
  88.     @Override
  89.     public int getOrder() {
  90.         return getFactory().getCompiler().getOrder();
  91.     }

  92.     /** Set a derivative component.
  93.      * <p>
  94.      * This method is package-private (no modifier specified), as it is intended
  95.      * to be used only by Hipparchus classes since it relied on the ordering of
  96.      * derivatives within the class. This allows avoiding checks on the index,
  97.      * for performance reasons.
  98.      * </p>
  99.      * @param index index of the derivative
  100.      * @param value of the derivative to set
  101.      * @since 1.4
  102.      */
  103.     void setDerivativeComponent(final int index, final T value) {
  104.         data[index] = value;
  105.     }

  106.     /** Get a derivative component.
  107.      * <p>
  108.      * This method is package-private (no modifier specified), as it is intended
  109.      * to be used only by Hipparchus classes since it relied on the ordering of
  110.      * derivatives within the class. This allows avoiding checks on the index,
  111.      * for performance reasons.
  112.      * </p>
  113.      * @param index index of the derivative
  114.      * @return value of the derivative
  115.      * @since 2.2
  116.      */
  117.     T getDerivativeComponent(final int index) {
  118.         return data[index];
  119.     }

  120.     /** {@inheritDoc} */
  121.     @Override
  122.     public FieldDerivativeStructure<T> getAddendum() {
  123.         final T[] addendum = data.clone();
  124.         addendum[0] = addendum[0].getField().getZero();
  125.         return new FieldDerivativeStructure<>(factory, addendum);
  126.     }

  127.     /** Get the value part of the derivative structure.
  128.      * @return value part of the derivative structure
  129.      * @see #getPartialDerivative(int...)
  130.      */
  131.     @Override
  132.     public T getValue() {
  133.         return data[0];
  134.     }

  135.     /** {@inheritDoc} */
  136.     @Override
  137.     public T getPartialDerivative(final int ... orders)
  138.         throws MathIllegalArgumentException {
  139.         return data[factory.getCompiler().getPartialDerivativeIndex(orders)];
  140.     }

  141.     /** Get all partial derivatives.
  142.      * @return a fresh copy of partial derivatives, in an array sorted according to
  143.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  144.      */
  145.     public T[] getAllDerivatives() {
  146.         return data.clone();
  147.     }

  148.     /** {@inheritDoc}
  149.      */
  150.     @Override
  151.     public FieldDerivativeStructure<T> add(final double a) {
  152.         final FieldDerivativeStructure<T> ds = factory.build();
  153.         System.arraycopy(data, 0, ds.data, 0, data.length);
  154.         ds.data[0] = ds.data[0].add(a);
  155.         return ds;
  156.     }

  157.     /** {@inheritDoc}
  158.      * @exception MathIllegalArgumentException if number of free parameters
  159.      * or orders do not match
  160.      */
  161.     @Override
  162.     public FieldDerivativeStructure<T> add(final FieldDerivativeStructure<T> a)
  163.         throws MathIllegalArgumentException {
  164.         factory.checkCompatibility(a.factory);
  165.         final FieldDerivativeStructure<T> ds = factory.build();
  166.         factory.getCompiler().add(data, 0, a.data, 0, ds.data, 0);
  167.         return ds;
  168.     }

  169.     /** {@inheritDoc}
  170.      */
  171.     @Override
  172.     public FieldDerivativeStructure<T> subtract(final double a) {
  173.         final FieldDerivativeStructure<T> ds = factory.build();
  174.         System.arraycopy(data, 0, ds.data, 0, data.length);
  175.         ds.data[0] = ds.data[0].subtract(a);
  176.         return ds;
  177.     }

  178.     /** {@inheritDoc}
  179.      * @exception MathIllegalArgumentException if number of free parameters
  180.      * or orders do not match
  181.      */
  182.     @Override
  183.     public FieldDerivativeStructure<T> subtract(final FieldDerivativeStructure<T> a)
  184.         throws MathIllegalArgumentException {
  185.         factory.checkCompatibility(a.factory);
  186.         final FieldDerivativeStructure<T> ds = factory.build();
  187.         factory.getCompiler().subtract(data, 0, a.data, 0, ds.data, 0);
  188.         return ds;
  189.     }

  190.     /** '&times;' operator.
  191.      * @param a right hand side parameter of the operator
  192.      * @return this&times;a
  193.      */
  194.     public FieldDerivativeStructure<T> multiply(final T a) {
  195.         final FieldDerivativeStructure<T> ds = factory.build();
  196.         for (int i = 0; i < ds.data.length; ++i) {
  197.             ds.data[i] = data[i].multiply(a);
  198.         }
  199.         return ds;
  200.     }

  201.     /** {@inheritDoc}
  202.      */
  203.     @Override
  204.     public FieldDerivativeStructure<T> multiply(final double a) {
  205.         final FieldDerivativeStructure<T> ds = factory.build();
  206.         for (int i = 0; i < ds.data.length; ++i) {
  207.             ds.data[i] = data[i].multiply(a);
  208.         }
  209.         return ds;
  210.     }

  211.     /** {@inheritDoc}
  212.      * @exception MathIllegalArgumentException if number of free parameters
  213.      * or orders do not match
  214.      */
  215.     @Override
  216.     public FieldDerivativeStructure<T> multiply(final FieldDerivativeStructure<T> a)
  217.         throws MathIllegalArgumentException {
  218.         factory.checkCompatibility(a.factory);
  219.         final FieldDerivativeStructure<T> result = factory.build();
  220.         factory.getCompiler().multiply(data, 0, a.data, 0, result.data, 0);
  221.         return result;
  222.     }

  223.     /** {@inheritDoc} */
  224.     @Override
  225.     public FieldDerivativeStructure<T> square() {
  226.         return multiply(this);
  227.     }

  228.     /** '&divide;' operator.
  229.      * @param a right hand side parameter of the operator
  230.      * @return this&divide;a
  231.      */
  232.     public FieldDerivativeStructure<T> divide(final T a) {
  233.         final FieldDerivativeStructure<T> ds = factory.build();
  234.         for (int i = 0; i < ds.data.length; ++i) {
  235.             ds.data[i] = data[i].divide(a);
  236.         }
  237.         return ds;
  238.     }

  239.     /** {@inheritDoc}
  240.      */
  241.     @Override
  242.     public FieldDerivativeStructure<T> divide(final double a) {
  243.         final FieldDerivativeStructure<T> ds = factory.build();
  244.         for (int i = 0; i < ds.data.length; ++i) {
  245.             ds.data[i] = data[i].divide(a);
  246.         }
  247.         return ds;
  248.     }

  249.     /** {@inheritDoc}
  250.      * @exception MathIllegalArgumentException if number of free parameters
  251.      * or orders do not match
  252.      */
  253.     @Override
  254.     public FieldDerivativeStructure<T> divide(final FieldDerivativeStructure<T> a)
  255.         throws MathIllegalArgumentException {
  256.         factory.checkCompatibility(a.factory);
  257.         final FieldDerivativeStructure<T> result = factory.build();
  258.         factory.getCompiler().divide(data, 0, a.data, 0, result.data, 0);
  259.         return result;
  260.     }

  261.     /** IEEE remainder operator.
  262.      * @param a right hand side parameter of the operator
  263.      * @return this - n &times; a where n is the closest integer to this/a
  264.      * (the even integer is chosen for n if this/a is halfway between two integers)
  265.      */
  266.     public FieldDerivativeStructure<T> remainder(final T a) {
  267.         final FieldDerivativeStructure<T> ds = factory.build();
  268.         System.arraycopy(data, 0, ds.data, 0, data.length);
  269.         ds.data[0] = data[0].remainder(a);
  270.         return ds;
  271.     }

  272.     /** {@inheritDoc} */
  273.     @Override
  274.     public FieldDerivativeStructure<T> remainder(final double a) {
  275.         final FieldDerivativeStructure<T> ds = factory.build();
  276.         System.arraycopy(data, 0, ds.data, 0, data.length);
  277.         ds.data[0] = data[0].remainder(a);
  278.         return ds;
  279.     }

  280.     /** {@inheritDoc}
  281.      * @exception MathIllegalArgumentException if number of free parameters
  282.      * or orders do not match
  283.      */
  284.     @Override
  285.     public FieldDerivativeStructure<T> remainder(final FieldDerivativeStructure<T> a)
  286.         throws MathIllegalArgumentException {
  287.         factory.checkCompatibility(a.factory);
  288.         final FieldDerivativeStructure<T> result = factory.build();
  289.         factory.getCompiler().remainder(data, 0, a.data, 0, result.data, 0);
  290.         return result;
  291.     }

  292.     /** {@inheritDoc} */
  293.     @Override
  294.     public FieldDerivativeStructure<T> negate() {
  295.         final FieldDerivativeStructure<T> ds = factory.build();
  296.         for (int i = 0; i < ds.data.length; ++i) {
  297.             ds.data[i] = data[i].negate();
  298.         }
  299.         return ds;
  300.     }

  301.     /** {@inheritDoc}
  302.      */
  303.     @Override
  304.     public FieldDerivativeStructure<T> abs() {
  305.         if (Double.doubleToLongBits(data[0].getReal()) < 0) {
  306.             // we use the bits representation to also handle -0.0
  307.             return negate();
  308.         } else {
  309.             return this;
  310.         }
  311.     }

  312.     /**
  313.      * Returns the instance with the sign of the argument.
  314.      * A NaN {@code sign} argument is treated as positive.
  315.      *
  316.      * @param sign the sign for the returned value
  317.      * @return the instance with the same sign as the {@code sign} argument
  318.      */
  319.     public FieldDerivativeStructure<T> copySign(final T sign) {
  320.         long m = Double.doubleToLongBits(data[0].getReal());
  321.         long s = Double.doubleToLongBits(sign.getReal());
  322.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  323.             return this;
  324.         }
  325.         return negate(); // flip sign
  326.     }

  327.     /** {@inheritDoc}
  328.      */
  329.     @Override
  330.     public FieldDerivativeStructure<T> copySign(final double sign) {
  331.         long m = Double.doubleToLongBits(data[0].getReal());
  332.         long s = Double.doubleToLongBits(sign);
  333.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  334.             return this;
  335.         }
  336.         return negate(); // flip sign
  337.     }

  338.     /** {@inheritDoc}
  339.      */
  340.     @Override
  341.     public FieldDerivativeStructure<T> copySign(final FieldDerivativeStructure<T> sign) {
  342.         long m = Double.doubleToLongBits(data[0].getReal());
  343.         long s = Double.doubleToLongBits(sign.data[0].getReal());
  344.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  345.             return this;
  346.         }
  347.         return negate(); // flip sign
  348.     }

  349.     /** {@inheritDoc}
  350.      */
  351.     @Override
  352.     public FieldDerivativeStructure<T> scalb(final int n) {
  353.         final FieldDerivativeStructure<T> ds = factory.build();
  354.         for (int i = 0; i < ds.data.length; ++i) {
  355.             ds.data[i] = data[i].scalb(n);
  356.         }
  357.         return ds;
  358.     }

  359.     /** {@inheritDoc}
  360.      * @exception MathIllegalArgumentException if number of free parameters
  361.      * or orders do not match
  362.      */
  363.     @Override
  364.     public FieldDerivativeStructure<T> hypot(final FieldDerivativeStructure<T> y)
  365.         throws MathIllegalArgumentException {

  366.         factory.checkCompatibility(y.factory);

  367.         if (data[0].isInfinite() || y.data[0].isInfinite()) {
  368.             return factory.constant(Double.POSITIVE_INFINITY);
  369.         } else if (data[0].isNaN() || y.data[0].isNaN()) {
  370.             return factory.constant(Double.NaN);
  371.         } else {

  372.             final int expX = getExponent();
  373.             final int expY = y.getExponent();
  374.             if (expX > expY + 27) {
  375.                 // y is negligible with respect to x
  376.                 return abs();
  377.             } else if (expY > expX + 27) {
  378.                 // x is negligible with respect to y
  379.                 return y.abs();
  380.             } else {

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

  383.                 // scale parameters without losing precision
  384.                 final FieldDerivativeStructure<T> scaledX = scalb(-middleExp);
  385.                 final FieldDerivativeStructure<T> scaledY = y.scalb(-middleExp);

  386.                 // compute scaled hypotenuse
  387.                 final FieldDerivativeStructure<T> scaledH =
  388.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  389.                 // remove scaling
  390.                 return scaledH.scalb(middleExp);

  391.             }

  392.         }
  393.     }

  394.     /**
  395.      * Returns the hypotenuse of a triangle with sides {@code x} and {@code y}
  396.      * - sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
  397.      * avoiding intermediate overflow or underflow.
  398.      *
  399.      * <ul>
  400.      * <li> If either argument is infinite, then the result is positive infinity.</li>
  401.      * <li> else, if either argument is NaN then the result is NaN.</li>
  402.      * </ul>
  403.      *
  404.      * @param x a value
  405.      * @param y a value
  406.      * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
  407.      * @exception MathIllegalArgumentException if number of free parameters
  408.      * or orders do not match
  409.      * @param <T> the type of the field elements
  410.      */
  411.     public static <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T>
  412.         hypot(final FieldDerivativeStructure<T> x, final FieldDerivativeStructure<T> y)
  413.         throws MathIllegalArgumentException {
  414.         return x.hypot(y);
  415.     }

  416.     /** Compute composition of the instance by a univariate function.
  417.      * @param f array of value and derivatives of the function at
  418.      * the current point (i.e. [f({@link #getValue()}),
  419.      * f'({@link #getValue()}), f''({@link #getValue()})...]).
  420.      * @return f(this)
  421.      * @exception MathIllegalArgumentException if the number of derivatives
  422.      * in the array is not equal to {@link #getOrder() order} + 1
  423.      */
  424.     @SafeVarargs
  425.     public final FieldDerivativeStructure<T> compose(final T ... f)
  426.         throws MathIllegalArgumentException {

  427.         MathUtils.checkDimension(f.length, getOrder() + 1);
  428.         final FieldDerivativeStructure<T> result = factory.build();
  429.         factory.getCompiler().compose(data, 0, f, result.data, 0);
  430.         return result;
  431.     }

  432.     /** Compute composition of the instance by a univariate function.
  433.      * @param f array of value and derivatives of the function at
  434.      * the current point (i.e. [f({@link #getValue()}),
  435.      * f'({@link #getValue()}), f''({@link #getValue()})...]).
  436.      * @return f(this)
  437.      * @exception MathIllegalArgumentException if the number of derivatives
  438.      * in the array is not equal to {@link #getOrder() order} + 1
  439.      */
  440.     public FieldDerivativeStructure<T> compose(final double ... f)
  441.         throws MathIllegalArgumentException {

  442.         MathUtils.checkDimension(f.length, getOrder() + 1);
  443.         final FieldDerivativeStructure<T> result = factory.build();
  444.         factory.getCompiler().compose(data, 0, f, result.data, 0);
  445.         return result;
  446.     }

  447.     /** {@inheritDoc} */
  448.     @Override
  449.     public FieldDerivativeStructure<T> reciprocal() {
  450.         final FieldDerivativeStructure<T> result = factory.build();
  451.         factory.getCompiler().reciprocal(data, 0, result.data, 0);
  452.         return result;
  453.     }

  454.     /** {@inheritDoc}
  455.      */
  456.     @Override
  457.     public FieldDerivativeStructure<T> sqrt() {
  458.         final FieldDerivativeStructure<T> result = factory.build();
  459.         factory.getCompiler().sqrt(data, 0, result.data, 0);
  460.         return result;
  461.     }

  462.     /** {@inheritDoc}
  463.      */
  464.     @Override
  465.     public FieldDerivativeStructure<T> rootN(final int n) {
  466.         final FieldDerivativeStructure<T> result = factory.build();
  467.         factory.getCompiler().rootN(data, 0, n, result.data, 0);
  468.         return result;
  469.     }

  470.     /** {@inheritDoc} */
  471.     @Override
  472.     public Field<FieldDerivativeStructure<T>> getField() {
  473.         return factory.getDerivativeField();
  474.     }

  475.     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldDerivativeStructure}
  476.      * @param a number to exponentiate
  477.      * @param x power to apply
  478.      * @param <T> the type of the field elements
  479.      * @return a<sup>x</sup>
  480.      */
  481.     public static <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T> pow(final double a, final FieldDerivativeStructure<T> x) {
  482.         final FieldDerivativeStructure<T> result = x.factory.build();
  483.         x.factory.getCompiler().pow(a, x.data, 0, result.data, 0);
  484.         return result;
  485.     }

  486.     /** {@inheritDoc}
  487.      */
  488.     @Override
  489.     public FieldDerivativeStructure<T> pow(final double p) {
  490.         final FieldDerivativeStructure<T> result = factory.build();
  491.         factory.getCompiler().pow(data, 0, p, result.data, 0);
  492.         return result;
  493.     }

  494.     /** {@inheritDoc}
  495.      */
  496.     @Override
  497.     public FieldDerivativeStructure<T> pow(final int n) {
  498.         final FieldDerivativeStructure<T> result = factory.build();
  499.         factory.getCompiler().pow(data, 0, n, result.data, 0);
  500.         return result;
  501.     }

  502.     /** {@inheritDoc}
  503.      * @exception MathIllegalArgumentException if number of free parameters
  504.      * or orders do not match
  505.      */
  506.     @Override
  507.     public FieldDerivativeStructure<T> pow(final FieldDerivativeStructure<T> e)
  508.         throws MathIllegalArgumentException {
  509.         factory.checkCompatibility(e.factory);
  510.         final FieldDerivativeStructure<T> result = factory.build();
  511.         factory.getCompiler().pow(data, 0, e.data, 0, result.data, 0);
  512.         return result;
  513.     }

  514.     /** {@inheritDoc}
  515.      */
  516.     @Override
  517.     public FieldDerivativeStructure<T> exp() {
  518.         final FieldDerivativeStructure<T> result = factory.build();
  519.         factory.getCompiler().exp(data, 0, result.data, 0);
  520.         return result;
  521.     }

  522.     /** {@inheritDoc}
  523.      */
  524.     @Override
  525.     public FieldDerivativeStructure<T> expm1() {
  526.         final FieldDerivativeStructure<T> result = factory.build();
  527.         factory.getCompiler().expm1(data, 0, result.data, 0);
  528.         return result;
  529.     }

  530.     /** {@inheritDoc}
  531.      */
  532.     @Override
  533.     public FieldDerivativeStructure<T> log() {
  534.         final FieldDerivativeStructure<T> result = factory.build();
  535.         factory.getCompiler().log(data, 0, result.data, 0);
  536.         return result;
  537.     }

  538.     /** {@inheritDoc}
  539.      */
  540.     @Override
  541.     public FieldDerivativeStructure<T> log1p() {
  542.         final FieldDerivativeStructure<T> result = factory.build();
  543.         factory.getCompiler().log1p(data, 0, result.data, 0);
  544.         return result;
  545.     }

  546.     /** Base 10 logarithm.
  547.      * @return base 10 logarithm of the instance
  548.      */
  549.     @Override
  550.     public FieldDerivativeStructure<T> log10() {
  551.         final FieldDerivativeStructure<T> result = factory.build();
  552.         factory.getCompiler().log10(data, 0, result.data, 0);
  553.         return result;
  554.     }

  555.     /** {@inheritDoc}
  556.      */
  557.     @Override
  558.     public FieldDerivativeStructure<T> cos() {
  559.         final FieldDerivativeStructure<T> result = factory.build();
  560.         factory.getCompiler().cos(data, 0, result.data, 0);
  561.         return result;
  562.     }

  563.     /** {@inheritDoc}
  564.      */
  565.     @Override
  566.     public FieldDerivativeStructure<T> sin() {
  567.         final FieldDerivativeStructure<T> result = factory.build();
  568.         factory.getCompiler().sin(data, 0, result.data, 0);
  569.         return result;
  570.     }

  571.     /** {@inheritDoc}
  572.      */
  573.     @Override
  574.     public FieldSinCos<FieldDerivativeStructure<T>> sinCos() {
  575.         final FieldDerivativeStructure<T> sin = factory.build();
  576.         final FieldDerivativeStructure<T> cos = factory.build();
  577.         factory.getCompiler().sinCos(data, 0, sin.data, 0, cos.data, 0);
  578.         return new FieldSinCos<>(sin, cos);
  579.     }

  580.     /** {@inheritDoc}
  581.      */
  582.     @Override
  583.     public FieldDerivativeStructure<T> tan() {
  584.         final FieldDerivativeStructure<T> result = factory.build();
  585.         factory.getCompiler().tan(data, 0, result.data, 0);
  586.         return result;
  587.     }

  588.     /** {@inheritDoc}
  589.      */
  590.     @Override
  591.     public FieldDerivativeStructure<T> acos() {
  592.         final FieldDerivativeStructure<T> result = factory.build();
  593.         factory.getCompiler().acos(data, 0, result.data, 0);
  594.         return result;
  595.     }

  596.     /** {@inheritDoc}
  597.      */
  598.     @Override
  599.     public FieldDerivativeStructure<T> asin() {
  600.         final FieldDerivativeStructure<T> result = factory.build();
  601.         factory.getCompiler().asin(data, 0, result.data, 0);
  602.         return result;
  603.     }

  604.     /** {@inheritDoc}
  605.      */
  606.     @Override
  607.     public FieldDerivativeStructure<T> atan() {
  608.         final FieldDerivativeStructure<T> result = factory.build();
  609.         factory.getCompiler().atan(data, 0, result.data, 0);
  610.         return result;
  611.     }

  612.     /** {@inheritDoc}
  613.      */
  614.     @Override
  615.     public FieldDerivativeStructure<T> atan2(final FieldDerivativeStructure<T> x)
  616.         throws MathIllegalArgumentException {
  617.         factory.checkCompatibility(x.factory);
  618.         final FieldDerivativeStructure<T> result = factory.build();
  619.         factory.getCompiler().atan2(data, 0, x.data, 0, result.data, 0);
  620.         return result;
  621.     }

  622.     /** Two arguments arc tangent operation.
  623.      * @param y first argument of the arc tangent
  624.      * @param x second argument of the arc tangent
  625.      * @param <T> the type of the field elements
  626.      * @return atan2(y, x)
  627.      * @exception MathIllegalArgumentException if number of free parameters
  628.      * or orders do not match
  629.      */
  630.     public static <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T> atan2(final FieldDerivativeStructure<T> y,
  631.                                                                                         final FieldDerivativeStructure<T> x)
  632.         throws MathIllegalArgumentException {
  633.         return y.atan2(x);
  634.     }

  635.     /** {@inheritDoc}
  636.      */
  637.     @Override
  638.     public FieldDerivativeStructure<T> cosh() {
  639.         final FieldDerivativeStructure<T> result = factory.build();
  640.         factory.getCompiler().cosh(data, 0, result.data, 0);
  641.         return result;
  642.     }

  643.     /** {@inheritDoc}
  644.      */
  645.     @Override
  646.     public FieldDerivativeStructure<T> sinh() {
  647.         final FieldDerivativeStructure<T> result = factory.build();
  648.         factory.getCompiler().sinh(data, 0, result.data, 0);
  649.         return result;
  650.     }

  651.     /** {@inheritDoc}
  652.      */
  653.     @Override
  654.     public FieldSinhCosh<FieldDerivativeStructure<T>> sinhCosh() {
  655.         final FieldDerivativeStructure<T> sinh = factory.build();
  656.         final FieldDerivativeStructure<T> cosh = factory.build();
  657.         factory.getCompiler().sinhCosh(data, 0, sinh.data, 0, cosh.data, 0);
  658.         return new FieldSinhCosh<>(sinh, cosh);
  659.     }

  660.     /** {@inheritDoc}
  661.      */
  662.     @Override
  663.     public FieldDerivativeStructure<T> tanh() {
  664.         final FieldDerivativeStructure<T> result = factory.build();
  665.         factory.getCompiler().tanh(data, 0, result.data, 0);
  666.         return result;
  667.     }

  668.     /** {@inheritDoc}
  669.      */
  670.     @Override
  671.     public FieldDerivativeStructure<T> acosh() {
  672.         final FieldDerivativeStructure<T> result = factory.build();
  673.         factory.getCompiler().acosh(data, 0, result.data, 0);
  674.         return result;
  675.     }

  676.     /** {@inheritDoc}
  677.      */
  678.     @Override
  679.     public FieldDerivativeStructure<T> asinh() {
  680.         final FieldDerivativeStructure<T> result = factory.build();
  681.         factory.getCompiler().asinh(data, 0, result.data, 0);
  682.         return result;
  683.     }

  684.     /** {@inheritDoc}
  685.      */
  686.     @Override
  687.     public FieldDerivativeStructure<T> atanh() {
  688.         final FieldDerivativeStructure<T> result = factory.build();
  689.         factory.getCompiler().atanh(data, 0, result.data, 0);
  690.         return result;
  691.     }

  692.     /** {@inheritDoc} */
  693.     @Override
  694.     public FieldDerivativeStructure<T> toDegrees() {
  695.         final FieldDerivativeStructure<T> ds = factory.build();
  696.         for (int i = 0; i < ds.data.length; ++i) {
  697.             ds.data[i] = data[i].toDegrees();
  698.         }
  699.         return ds;
  700.     }

  701.     /** {@inheritDoc} */
  702.     @Override
  703.     public FieldDerivativeStructure<T> toRadians() {
  704.         final FieldDerivativeStructure<T> ds = factory.build();
  705.         for (int i = 0; i < ds.data.length; ++i) {
  706.             ds.data[i] = data[i].toRadians();
  707.         }
  708.         return ds;
  709.     }

  710.     /** Integrate w.r.t. one independent variable.
  711.      * <p>
  712.      * Rigorously, if the derivatives of a function are known up to
  713.      * order N, the ones of its M-th integral w.r.t. a given variable
  714.      * (seen as a function itself) are actually known up to order N+M.
  715.      * However, this method still casts the output as a DerivativeStructure
  716.      * of order N. The integration constants are systematically set to zero.
  717.      * </p>
  718.      * @param varIndex Index of independent variable w.r.t. which integration is done.
  719.      * @param integrationOrder Number of times the integration operator must be applied. If non-positive, call the
  720.      *                         differentiation operator.
  721.      * @return DerivativeStructure on which integration operator has been applied a certain number of times.
  722.      * @since 2.2
  723.      */
  724.     public FieldDerivativeStructure<T> integrate(final int varIndex, final int integrationOrder) {

  725.         // Deal first with trivial case
  726.         if (integrationOrder > getOrder()) {
  727.             return factory.constant(0.);
  728.         } else if (integrationOrder == 0) {
  729.             return factory.build(data);
  730.         }

  731.         // Call 'inverse' (not rigorously) operation if necessary
  732.         if (integrationOrder < 0) {
  733.             return differentiate(varIndex, -integrationOrder);
  734.         }

  735.         final T[] newData = MathArrays.buildArray(factory.getValueField(), data.length);
  736.         final DSCompiler dsCompiler = factory.getCompiler();
  737.         for (int i = 0; i < newData.length; i++) {
  738.             if (!data[i].isZero()) {
  739.                 final int[] orders = dsCompiler.getPartialDerivativeOrders(i);
  740.                 int sum = 0;
  741.                 for (int order : orders) {
  742.                     sum += order;
  743.                 }
  744.                 if (sum + integrationOrder <= getOrder()) {
  745.                     final int saved = orders[varIndex];
  746.                     orders[varIndex] += integrationOrder;
  747.                     final int index = dsCompiler.getPartialDerivativeIndex(orders);
  748.                     orders[varIndex] = saved;
  749.                     newData[index] = data[i];
  750.                 }
  751.             }
  752.         }

  753.         return factory.build(newData);
  754.     }

  755.     /** Differentiate w.r.t. one independent variable.
  756.      * <p>
  757.      * Rigorously, if the derivatives of a function are known up to
  758.      * order N, the ones of its M-th derivative w.r.t. a given variable
  759.      * (seen as a function itself) are only known up to order N-M.
  760.      * However, this method still casts the output as a DerivativeStructure
  761.      * of order N with zeroes for the higher order terms.
  762.      * </p>
  763.      * @param varIndex Index of independent variable w.r.t. which differentiation is done.
  764.      * @param differentiationOrder Number of times the differentiation operator must be applied. If non-positive, call
  765.      *                             the integration operator instead.
  766.      * @return DerivativeStructure on which differentiation operator has been applied a certain number of times
  767.      * @since 2.2
  768.      */
  769.     public FieldDerivativeStructure<T> differentiate(final int varIndex, final int differentiationOrder) {

  770.         // Deal first with trivial case
  771.         if (differentiationOrder > getOrder()) {
  772.             return factory.constant(0.);
  773.         } else if (differentiationOrder == 0) {
  774.             return factory.build(data);
  775.         }

  776.         // Call 'inverse' (not rigorously) operation if necessary
  777.         if (differentiationOrder < 0) {
  778.             return integrate(varIndex, -differentiationOrder);
  779.         }

  780.         final T[] newData = MathArrays.buildArray(factory.getValueField(), data.length);
  781.         final DSCompiler dsCompiler = factory.getCompiler();
  782.         for (int i = 0; i < newData.length; i++) {
  783.             if (!data[i].isZero()) {
  784.                 final int[] orders = dsCompiler.getPartialDerivativeOrders(i);
  785.                 if (orders[varIndex] - differentiationOrder >= 0) {
  786.                     final int saved = orders[varIndex];
  787.                     orders[varIndex] -= differentiationOrder;
  788.                     final int index = dsCompiler.getPartialDerivativeIndex(orders);
  789.                     orders[varIndex] = saved;
  790.                     newData[index] = data[i];
  791.                 }
  792.             }
  793.         }

  794.         return factory.build(newData);
  795.     }

  796.     /** Evaluate Taylor expansion of a derivative structure.
  797.      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
  798.      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
  799.      * @throws MathRuntimeException if factorials becomes too large
  800.      */
  801.     @SafeVarargs
  802.     public final T taylor(final T ... delta) throws MathRuntimeException {
  803.         return factory.getCompiler().taylor(data, 0, delta);
  804.     }

  805.     /** Evaluate Taylor expansion of a derivative structure.
  806.      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
  807.      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
  808.      * @throws MathRuntimeException if factorials becomes too large
  809.      */
  810.     public T taylor(final double ... delta) throws MathRuntimeException {
  811.         return factory.getCompiler().taylor(data, 0, delta);
  812.     }

  813.     /** Rebase instance with respect to low level parameter functions.
  814.      * <p>
  815.      * The instance is considered to be a function of {@link #getFreeParameters()
  816.      * n free parameters} up to order {@link #getOrder() o} \(f(p_0, p_1, \ldots p_{n-1})\).
  817.      * Its {@link #getPartialDerivative(int...) partial derivatives} are therefore
  818.      * \(f, \frac{\partial f}{\partial p_0}, \frac{\partial f}{\partial p_1}, \ldots
  819.      * \frac{\partial^2 f}{\partial p_0^2}, \frac{\partial^2 f}{\partial p_0 p_1},
  820.      * \ldots \frac{\partial^o f}{\partial p_{n-1}^o}\). The free parameters
  821.      * \(p_0, p_1, \ldots p_{n-1}\) are considered to be functions of \(m\) lower
  822.      * level other parameters \(q_0, q_1, \ldots q_{m-1}\).
  823.      * </p>
  824.      * \( \begin{align}
  825.      * p_0 &amp; = p_0(q_0, q_1, \ldots q_{m-1})\\
  826.      * p_1 &amp; = p_1(q_0, q_1, \ldots q_{m-1})\\
  827.      * p_{n-1} &amp; = p_{n-1}(q_0, q_1, \ldots q_{m-1})
  828.      * \end{align}\)
  829.      * <p>
  830.      * This method compute the composition of the partial derivatives of \(f\)
  831.      * and the partial derivatives of \(p_0, p_1, \ldots p_{n-1}\), i.e. the
  832.      * {@link #getPartialDerivative(int...) partial derivatives} of the value
  833.      * returned will be
  834.      * \(f, \frac{\partial f}{\partial q_0}, \frac{\partial f}{\partial q_1}, \ldots
  835.      * \frac{\partial^2 f}{\partial q_0^2}, \frac{\partial^2 f}{\partial q_0 q_1},
  836.      * \ldots \frac{\partial^o f}{\partial q_{m-1}^o}\).
  837.      * </p>
  838.      * <p>
  839.      * The number of parameters must match {@link #getFreeParameters()} and the
  840.      * derivation orders of the instance and parameters must also match.
  841.      * </p>
  842.      * @param p base parameters with respect to which partial derivatives
  843.      * were computed in the instance
  844.      * @return derivative structure with partial derivatives computed
  845.      * with respect to the lower level parameters used in the \(p_i\)
  846.      * @since 2.2
  847.      */
  848.     public FieldDerivativeStructure<T> rebase(@SuppressWarnings("unchecked") final FieldDerivativeStructure<T>... p) {

  849.         MathUtils.checkDimension(getFreeParameters(), p.length);

  850.         // handle special case of no variables at all
  851.         if (p.length == 0) {
  852.             return this;
  853.         }

  854.         final int pSize = p[0].getFactory().getCompiler().getSize();
  855.         final T[] pData = MathArrays.buildArray(p[0].getFactory().getValueField(), p.length * pSize);
  856.         for (int i = 0; i < p.length; ++i) {
  857.             MathUtils.checkDimension(getOrder(), p[i].getOrder());
  858.             MathUtils.checkDimension(p[0].getFreeParameters(), p[i].getFreeParameters());
  859.             System.arraycopy(p[i].data, 0, pData, i * pSize, pSize);
  860.         }

  861.         final FieldDerivativeStructure<T> result = p[0].factory.build();
  862.         factory.getCompiler().rebase(data, 0, p[0].factory.getCompiler(), pData, result.data, 0);
  863.         return result;

  864.     }

  865.     /** {@inheritDoc}
  866.      * @exception MathIllegalArgumentException if number of free parameters
  867.      * or orders do not match
  868.      */
  869.     @Override
  870.     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T>[] a,
  871.                                                          final FieldDerivativeStructure<T>[] b)
  872.         throws MathIllegalArgumentException {

  873.         // compute an accurate value, taking care of cancellations
  874.         final T[] aT = MathArrays.buildArray(factory.getValueField(), a.length);
  875.         for (int i = 0; i < a.length; ++i) {
  876.             aT[i] = a[i].getValue();
  877.         }
  878.         final T[] bT = MathArrays.buildArray(factory.getValueField(), b.length);
  879.         for (int i = 0; i < b.length; ++i) {
  880.             bT[i] = b[i].getValue();
  881.         }
  882.         final T accurateValue = aT[0].linearCombination(aT, bT);

  883.         // compute a simple value, with all partial derivatives
  884.         FieldDerivativeStructure<T> simpleValue = a[0].getField().getZero();
  885.         for (int i = 0; i < a.length; ++i) {
  886.             simpleValue = simpleValue.add(a[i].multiply(b[i]));
  887.         }

  888.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  889.         final T[] all = simpleValue.getAllDerivatives();
  890.         all[0] = accurateValue;
  891.         return factory.build(all);

  892.     }

  893.     /**
  894.      * Compute a linear combination.
  895.      * @param a Factors.
  896.      * @param b Factors.
  897.      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
  898.      * @throws MathIllegalArgumentException if arrays dimensions don't match
  899.      */
  900.     public FieldDerivativeStructure<T> linearCombination(final T[] a, final FieldDerivativeStructure<T>[] b)
  901.                     throws MathIllegalArgumentException {

  902.         // compute an accurate value, taking care of cancellations
  903.         final T[] bT = MathArrays.buildArray(factory.getValueField(), b.length);
  904.         for (int i = 0; i < b.length; ++i) {
  905.             bT[i] = b[i].getValue();
  906.         }
  907.         final T accurateValue = bT[0].linearCombination(a, bT);

  908.         // compute a simple value, with all partial derivatives
  909.         FieldDerivativeStructure<T> simpleValue = b[0].getField().getZero();
  910.         for (int i = 0; i < a.length; ++i) {
  911.             simpleValue = simpleValue.add(b[i].multiply(a[i]));
  912.         }

  913.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  914.         final T[] all = simpleValue.getAllDerivatives();
  915.         all[0] = accurateValue;
  916.         return factory.build(all);

  917.     }

  918.     /** {@inheritDoc}
  919.      * @exception MathIllegalArgumentException if number of free parameters
  920.      * or orders do not match
  921.      */
  922.     @Override
  923.     public FieldDerivativeStructure<T> linearCombination(final double[] a, final FieldDerivativeStructure<T>[] b)
  924.         throws MathIllegalArgumentException {

  925.         // compute an accurate value, taking care of cancellations
  926.         final T[] bT = MathArrays.buildArray(factory.getValueField(), b.length);
  927.         for (int i = 0; i < b.length; ++i) {
  928.             bT[i] = b[i].getValue();
  929.         }
  930.         final T accurateValue = bT[0].linearCombination(a, bT);

  931.         // compute a simple value, with all partial derivatives
  932.         FieldDerivativeStructure<T> simpleValue = b[0].getField().getZero();
  933.         for (int i = 0; i < a.length; ++i) {
  934.             simpleValue = simpleValue.add(b[i].multiply(a[i]));
  935.         }

  936.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  937.         final T[] all = simpleValue.getAllDerivatives();
  938.         all[0] = accurateValue;
  939.         return factory.build(all);

  940.     }

  941.     /** {@inheritDoc}
  942.      * @exception MathIllegalArgumentException if number of free parameters
  943.      * or orders do not match
  944.      */
  945.     @Override
  946.     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T> a1, final FieldDerivativeStructure<T> b1,
  947.                                                          final FieldDerivativeStructure<T> a2, final FieldDerivativeStructure<T> b2)
  948.         throws MathIllegalArgumentException {

  949.         // compute an accurate value, taking care of cancellations
  950.         final T accurateValue = a1.getValue().linearCombination(a1.getValue(), b1.getValue(),
  951.                                                                 a2.getValue(), b2.getValue());

  952.         // compute a simple value, with all partial derivatives
  953.         final FieldDerivativeStructure<T> simpleValue = a1.multiply(b1).add(a2.multiply(b2));

  954.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  955.         final T[] all = simpleValue.getAllDerivatives();
  956.         all[0] = accurateValue;
  957.         return factory.build(all);

  958.     }

  959.     /**
  960.      * Compute a linear combination.
  961.      * @param a1 first factor of the first term
  962.      * @param b1 second factor of the first term
  963.      * @param a2 first factor of the second term
  964.      * @param b2 second factor of the second term
  965.      * @return a<sub>1</sub>&times;b<sub>1</sub> +
  966.      * a<sub>2</sub>&times;b<sub>2</sub>
  967.      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure)
  968.      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure)
  969.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  970.      */
  971.     public FieldDerivativeStructure<T> linearCombination(final T a1, final FieldDerivativeStructure<T> b1,
  972.                                                          final T a2, final FieldDerivativeStructure<T> b2)
  973.         throws MathIllegalArgumentException {

  974.         factory.checkCompatibility(b1.factory);
  975.         factory.checkCompatibility(b2.factory);

  976.         final FieldDerivativeStructure<T> ds = factory.build();
  977.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  978.                                                 a2, b2.data, 0,
  979.                                                 ds.data, 0);

  980.         return ds;

  981.     }

  982.     /** {@inheritDoc}
  983.      * @exception MathIllegalArgumentException if number of free parameters
  984.      * or orders do not match
  985.      */
  986.     @Override
  987.     public FieldDerivativeStructure<T> linearCombination(final double a1, final FieldDerivativeStructure<T> b1,
  988.                                                          final double a2, final FieldDerivativeStructure<T> b2)
  989.         throws MathIllegalArgumentException {

  990.         factory.checkCompatibility(b1.factory);
  991.         factory.checkCompatibility(b2.factory);

  992.         final FieldDerivativeStructure<T> ds = factory.build();
  993.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  994.                                                 a2, b2.data, 0,
  995.                                                 ds.data, 0);

  996.         return ds;

  997.     }

  998.     /** {@inheritDoc}
  999.      * @exception MathIllegalArgumentException if number of free parameters
  1000.      * or orders do not match
  1001.      */
  1002.     @Override
  1003.     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T> a1, final FieldDerivativeStructure<T> b1,
  1004.                                                          final FieldDerivativeStructure<T> a2, final FieldDerivativeStructure<T> b2,
  1005.                                                          final FieldDerivativeStructure<T> a3, final FieldDerivativeStructure<T> b3)
  1006.         throws MathIllegalArgumentException {

  1007.         // compute an accurate value, taking care of cancellations
  1008.         final T accurateValue = a1.getValue().linearCombination(a1.getValue(), b1.getValue(),
  1009.                                                                 a2.getValue(), b2.getValue(),
  1010.                                                                 a3.getValue(), b3.getValue());

  1011.         // compute a simple value, with all partial derivatives
  1012.         final FieldDerivativeStructure<T> simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3));

  1013.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  1014.         final T[] all = simpleValue.getAllDerivatives();
  1015.         all[0] = accurateValue;
  1016.         return factory.build(all);

  1017.     }

  1018.     /**
  1019.      * Compute a linear combination.
  1020.      * @param a1 first factor of the first term
  1021.      * @param b1 second factor of the first term
  1022.      * @param a2 first factor of the second term
  1023.      * @param b2 second factor of the second term
  1024.      * @param a3 first factor of the third term
  1025.      * @param b3 second factor of the third term
  1026.      * @return a<sub>1</sub>&times;b<sub>1</sub> +
  1027.      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
  1028.      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure)
  1029.      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure)
  1030.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  1031.      */
  1032.     public FieldDerivativeStructure<T> linearCombination(final T a1, final FieldDerivativeStructure<T> b1,
  1033.                                                          final T a2, final FieldDerivativeStructure<T> b2,
  1034.                                                          final T a3, final FieldDerivativeStructure<T> b3)
  1035.         throws MathIllegalArgumentException {

  1036.         factory.checkCompatibility(b1.factory);
  1037.         factory.checkCompatibility(b2.factory);
  1038.         factory.checkCompatibility(b3.factory);

  1039.         final FieldDerivativeStructure<T> ds = factory.build();
  1040.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  1041.                                                 a2, b2.data, 0,
  1042.                                                 a3, b3.data, 0,
  1043.                                                 ds.data, 0);

  1044.         return ds;

  1045.     }

  1046.     /** {@inheritDoc}
  1047.      * @exception MathIllegalArgumentException if number of free parameters
  1048.      * or orders do not match
  1049.      */
  1050.     @Override
  1051.     public FieldDerivativeStructure<T> linearCombination(final double a1, final FieldDerivativeStructure<T> b1,
  1052.                                                          final double a2, final FieldDerivativeStructure<T> b2,
  1053.                                                          final double a3, final FieldDerivativeStructure<T> b3)
  1054.         throws MathIllegalArgumentException {

  1055.         factory.checkCompatibility(b1.factory);
  1056.         factory.checkCompatibility(b2.factory);
  1057.         factory.checkCompatibility(b3.factory);

  1058.         final FieldDerivativeStructure<T> ds = factory.build();
  1059.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  1060.                                                 a2, b2.data, 0,
  1061.                                                 a3, b3.data, 0,
  1062.                                                 ds.data, 0);

  1063.         return ds;

  1064.     }

  1065.     /** {@inheritDoc}
  1066.      * @exception MathIllegalArgumentException if number of free parameters
  1067.      * or orders do not match
  1068.      */
  1069.     @Override
  1070.     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T> a1, final FieldDerivativeStructure<T> b1,
  1071.                                                          final FieldDerivativeStructure<T> a2, final FieldDerivativeStructure<T> b2,
  1072.                                                          final FieldDerivativeStructure<T> a3, final FieldDerivativeStructure<T> b3,
  1073.                                                          final FieldDerivativeStructure<T> a4, final FieldDerivativeStructure<T> b4)
  1074.         throws MathIllegalArgumentException {

  1075.         // compute an accurate value, taking care of cancellations
  1076.         final T accurateValue = a1.getValue().linearCombination(a1.getValue(), b1.getValue(),
  1077.                                                                 a2.getValue(), b2.getValue(),
  1078.                                                                 a3.getValue(), b3.getValue(),
  1079.                                                                 a4.getValue(), b4.getValue());

  1080.         // compute a simple value, with all partial derivatives
  1081.         final FieldDerivativeStructure<T> simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3)).add(a4.multiply(b4));

  1082.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  1083.         final T[] all = simpleValue.getAllDerivatives();
  1084.         all[0] = accurateValue;
  1085.         return factory.build(all);

  1086.     }

  1087.     /**
  1088.      * Compute a linear combination.
  1089.      * @param a1 first factor of the first term
  1090.      * @param b1 second factor of the first term
  1091.      * @param a2 first factor of the second term
  1092.      * @param b2 second factor of the second term
  1093.      * @param a3 first factor of the third term
  1094.      * @param b3 second factor of the third term
  1095.      * @param a4 first factor of the third term
  1096.      * @param b4 second factor of the third term
  1097.      * @return a<sub>1</sub>&times;b<sub>1</sub> +
  1098.      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub> +
  1099.      * a<sub>4</sub>&times;b<sub>4</sub>
  1100.      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure)
  1101.      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure)
  1102.      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
  1103.      */
  1104.     public FieldDerivativeStructure<T> linearCombination(final T a1, final FieldDerivativeStructure<T> b1,
  1105.                                                          final T a2, final FieldDerivativeStructure<T> b2,
  1106.                                                          final T a3, final FieldDerivativeStructure<T> b3,
  1107.                                                          final T a4, final FieldDerivativeStructure<T> b4)
  1108.         throws MathIllegalArgumentException {

  1109.         factory.checkCompatibility(b1.factory);
  1110.         factory.checkCompatibility(b2.factory);
  1111.         factory.checkCompatibility(b3.factory);
  1112.         factory.checkCompatibility(b4.factory);

  1113.         final FieldDerivativeStructure<T> ds = factory.build();
  1114.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  1115.                                                 a2, b2.data, 0,
  1116.                                                 a3, b3.data, 0,
  1117.                                                 a4, b4.data, 0,
  1118.                                                 ds.data, 0);

  1119.         return ds;

  1120.     }

  1121.     /** {@inheritDoc}
  1122.      * @exception MathIllegalArgumentException if number of free parameters
  1123.      * or orders do not match
  1124.      */
  1125.     @Override
  1126.     public FieldDerivativeStructure<T> linearCombination(final double a1, final FieldDerivativeStructure<T> b1,
  1127.                                                          final double a2, final FieldDerivativeStructure<T> b2,
  1128.                                                          final double a3, final FieldDerivativeStructure<T> b3,
  1129.                                                          final double a4, final FieldDerivativeStructure<T> b4)
  1130.         throws MathIllegalArgumentException {

  1131.         factory.checkCompatibility(b1.factory);
  1132.         factory.checkCompatibility(b2.factory);
  1133.         factory.checkCompatibility(b3.factory);
  1134.         factory.checkCompatibility(b4.factory);

  1135.         final FieldDerivativeStructure<T> ds = factory.build();
  1136.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  1137.                                                 a2, b2.data, 0,
  1138.                                                 a3, b3.data, 0,
  1139.                                                 a4, b4.data, 0,
  1140.                                                 ds.data, 0);

  1141.         return ds;

  1142.     }

  1143.     /** {@inheritDoc}
  1144.      */
  1145.     @Override
  1146.     public FieldDerivativeStructure<T> getPi() {
  1147.         return factory.getDerivativeField().getPi();
  1148.     }

  1149.     /**
  1150.      * Test for the equality of two derivative structures.
  1151.      * <p>
  1152.      * Derivative structures are considered equal if they have the same number
  1153.      * of free parameters, the same derivation order, and the same derivatives.
  1154.      * </p>
  1155.      * @param other Object to test for equality to this
  1156.      * @return true if two derivative structures are equal
  1157.      */
  1158.     @Override
  1159.     public boolean equals(Object other) {

  1160.         if (this == other) {
  1161.             return true;
  1162.         }

  1163.         if (other instanceof FieldDerivativeStructure &&
  1164.             ((FieldDerivativeStructure<?>) other).getField().equals(getField())) {
  1165.             final FieldDerivativeStructure<T> rhs = (FieldDerivativeStructure<T>) other;
  1166.             return (getFreeParameters() == rhs.getFreeParameters()) &&
  1167.                    (getOrder() == rhs.getOrder()) &&
  1168.                    MathArrays.equals(data, rhs.data);
  1169.         }

  1170.         return false;

  1171.     }

  1172.     /**
  1173.      * Get a hashCode for the derivative structure.
  1174.      * @return a hash code value for this object
  1175.      */
  1176.     @Override
  1177.     public int hashCode() {
  1178.         return 227 + 229 * getFreeParameters() + 233 * getOrder() + 239 * Arrays.hashCode(data);
  1179.     }

  1180. }