DerivativeStructure.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) 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 ASF 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.  *      http://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.apache.commons.math4.legacy.analysis.differentiation;

  18. import java.util.Arrays;

  19. import org.apache.commons.numbers.core.Sum;
  20. import org.apache.commons.math4.legacy.core.Field;
  21. import org.apache.commons.math4.legacy.core.FieldElement;
  22. import org.apache.commons.math4.legacy.core.RealFieldElement;
  23. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  24. import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
  25. import org.apache.commons.math4.core.jdkmath.JdkMath;
  26. import org.apache.commons.math4.legacy.core.MathArrays;

  27. /** Class representing both the value and the differentials of a function.
  28.  * <p>This class is the workhorse of the differentiation package.</p>
  29.  * <p>This class is an implementation of the extension to Rall's
  30.  * numbers described in Dan Kalman's paper <a
  31.  * href="http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf">Doubly
  32.  * Recursive Multivariate Automatic Differentiation</a>, Mathematics Magazine, vol. 75,
  33.  * no. 3, June 2002. Rall's numbers are an extension to the real numbers used
  34.  * throughout mathematical expressions; they hold the derivative together with the
  35.  * value of a function. Dan Kalman's derivative structures hold all partial derivatives
  36.  * up to any specified order, with respect to any number of free parameters. Rall's
  37.  * numbers therefore can be seen as derivative structures for order one derivative and
  38.  * one free parameter, and real numbers can be seen as derivative structures with zero
  39.  * order derivative and no free parameters.</p>
  40.  * <p>{@link DerivativeStructure} instances can be used directly thanks to
  41.  * the arithmetic operators to the mathematical functions provided as
  42.  * methods by this class (+, -, *, /, %, sin, cos ...).</p>
  43.  * <p>Implementing complex expressions by hand using these classes is
  44.  * a tedious and error-prone task but has the advantage of having no limitation
  45.  * on the derivation order despite not requiring users to compute the derivatives by
  46.  * themselves. Implementing complex expression can also be done by developing computation
  47.  * code using standard primitive double values and to use {@link
  48.  * UnivariateFunctionDifferentiator differentiators} to create the {@link
  49.  * DerivativeStructure}-based instances. This method is simpler but may be limited in
  50.  * the accuracy and derivation orders and may be computationally intensive (this is
  51.  * typically the case for {@link FiniteDifferencesDifferentiator finite differences
  52.  * differentiator}.</p>
  53.  * <p>Instances of this class are guaranteed to be immutable.</p>
  54.  * @see DSCompiler
  55.  * @since 3.1
  56.  */
  57. public class DerivativeStructure implements RealFieldElement<DerivativeStructure> {
  58.     /** Compiler for the current dimensions. */
  59.     private DSCompiler compiler;

  60.     /** Combined array holding all values. */
  61.     private final double[] data;

  62.     /** Build an instance with all values and derivatives set to 0.
  63.      * @param compiler compiler to use for computation
  64.      */
  65.     private DerivativeStructure(final DSCompiler compiler) {
  66.         this.compiler = compiler;
  67.         this.data     = new double[compiler.getSize()];
  68.     }

  69.     /** Build an instance with all values and derivatives set to 0.
  70.      * @param parameters number of free parameters
  71.      * @param order derivation order
  72.      * @throws NumberIsTooLargeException if order is too large.
  73.      */
  74.     public DerivativeStructure(final int parameters, final int order) {
  75.         this(DSCompiler.getCompiler(parameters, order));
  76.     }

  77.     /** Build an instance representing a constant value.
  78.      * @param parameters number of free parameters
  79.      * @param order derivation order
  80.      * @param value value of the constant
  81.      * @throws NumberIsTooLargeException if order is too large.
  82.      * @see #DerivativeStructure(int, int, int, double)
  83.      */
  84.     public DerivativeStructure(final int parameters, final int order, final double value) {
  85.         this(parameters, order);
  86.         this.data[0] = value;
  87.     }

  88.     /** Build an instance representing a variable.
  89.      * <p>Instances built using this constructor are considered
  90.      * to be the free variables with respect to which differentials
  91.      * are computed. As such, their differential with respect to
  92.      * themselves is +1.</p>
  93.      * @param parameters number of free parameters
  94.      * @param order derivation order
  95.      * @param index index of the variable (from 0 to {@code parameters - 1})
  96.      * @param value value of the variable
  97.      * @throws NumberIsTooLargeException if {@code index &ge; parameters}.
  98.      * @see #DerivativeStructure(int, int, double)
  99.      */
  100.     public DerivativeStructure(final int parameters, final int order,
  101.                                final int index, final double value) {
  102.         this(parameters, order, value);

  103.         if (index >= parameters) {
  104.             throw new NumberIsTooLargeException(index, parameters, false);
  105.         }

  106.         if (order > 0) {
  107.             // the derivative of the variable with respect to itself is 1.
  108.             data[DSCompiler.getCompiler(index, order).getSize()] = 1.0;
  109.         }
  110.     }

  111.     /** Linear combination constructor.
  112.      * The derivative structure built will be a1 * ds1 + a2 * ds2
  113.      * @param a1 first scale factor
  114.      * @param ds1 first base (unscaled) derivative structure
  115.      * @param a2 second scale factor
  116.      * @param ds2 second base (unscaled) derivative structure
  117.      * @throws org.apache.commons.math4.legacy.exception.DimensionMismatchException
  118.      * if number of free parameters or orders are inconsistent
  119.      */
  120.     public DerivativeStructure(final double a1, final DerivativeStructure ds1,
  121.                                final double a2, final DerivativeStructure ds2) {
  122.         this(ds1.compiler);
  123.         compiler.checkCompatibility(ds2.compiler);
  124.         compiler.linearCombination(a1, ds1.data, 0, a2, ds2.data, 0, data, 0);
  125.     }

  126.     /** Linear combination constructor.
  127.      * The derivative structure built will be a1 * ds1 + a2 * ds2 + a3 * ds3
  128.      * @param a1 first scale factor
  129.      * @param ds1 first base (unscaled) derivative structure
  130.      * @param a2 second scale factor
  131.      * @param ds2 second base (unscaled) derivative structure
  132.      * @param a3 third scale factor
  133.      * @param ds3 third base (unscaled) derivative structure
  134.      * @throws org.apache.commons.math4.legacy.exception.DimensionMismatchException
  135.      * if number of free parameters or orders are inconsistent.
  136.      */
  137.     public DerivativeStructure(final double a1, final DerivativeStructure ds1,
  138.                                final double a2, final DerivativeStructure ds2,
  139.                                final double a3, final DerivativeStructure ds3) {
  140.         this(ds1.compiler);
  141.         compiler.checkCompatibility(ds2.compiler);
  142.         compiler.checkCompatibility(ds3.compiler);
  143.         compiler.linearCombination(a1, ds1.data, 0, a2, ds2.data, 0, a3, ds3.data, 0, data, 0);
  144.     }

  145.     /** Linear combination constructor.
  146.      * The derivative structure built will be a1 * ds1 + a2 * ds2 + a3 * ds3 + a4 * ds4
  147.      * @param a1 first scale factor
  148.      * @param ds1 first base (unscaled) derivative structure
  149.      * @param a2 second scale factor
  150.      * @param ds2 second base (unscaled) derivative structure
  151.      * @param a3 third scale factor
  152.      * @param ds3 third base (unscaled) derivative structure
  153.      * @param a4 fourth scale factor
  154.      * @param ds4 fourth base (unscaled) derivative structure
  155.      * @throws DimensionMismatchException if number of free parameters or orders are inconsistent.
  156.      */
  157.     public DerivativeStructure(final double a1, final DerivativeStructure ds1,
  158.                                final double a2, final DerivativeStructure ds2,
  159.                                final double a3, final DerivativeStructure ds3,
  160.                                final double a4, final DerivativeStructure ds4) {
  161.         this(ds1.compiler);
  162.         compiler.checkCompatibility(ds2.compiler);
  163.         compiler.checkCompatibility(ds3.compiler);
  164.         compiler.checkCompatibility(ds4.compiler);
  165.         compiler.linearCombination(a1, ds1.data, 0, a2, ds2.data, 0,
  166.                                    a3, ds3.data, 0, a4, ds4.data, 0,
  167.                                    data, 0);
  168.     }

  169.     /** Build an instance from all its derivatives.
  170.      * @param parameters number of free parameters
  171.      * @param order derivation order
  172.      * @param derivatives derivatives sorted according to
  173.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  174.      * @throws DimensionMismatchException if derivatives array does not match the
  175.      * {@link DSCompiler#getSize() size} expected by the compiler.
  176.      * @throws NumberIsTooLargeException if order is too large.
  177.      * @see #getAllDerivatives()
  178.      */
  179.     public DerivativeStructure(final int parameters, final int order, final double ... derivatives) {
  180.         this(parameters, order);
  181.         if (derivatives.length != data.length) {
  182.             throw new DimensionMismatchException(derivatives.length, data.length);
  183.         }
  184.         System.arraycopy(derivatives, 0, data, 0, data.length);
  185.     }

  186.     /** Copy constructor.
  187.      * @param ds instance to copy
  188.      */
  189.     private DerivativeStructure(final DerivativeStructure ds) {
  190.         this.compiler = ds.compiler;
  191.         this.data     = ds.data.clone();
  192.     }

  193.     /** Get the number of free parameters.
  194.      * @return number of free parameters
  195.      */
  196.     public int getFreeParameters() {
  197.         return compiler.getFreeParameters();
  198.     }

  199.     /** Get the derivation order.
  200.      * @return derivation order
  201.      */
  202.     public int getOrder() {
  203.         return compiler.getOrder();
  204.     }

  205.     /** Create a constant compatible with instance order and number of parameters.
  206.      * <p>
  207.      * This method is a convenience factory method, it simply calls
  208.      * {@code new DerivativeStructure(getFreeParameters(), getOrder(), c)}
  209.      * </p>
  210.      * @param c value of the constant
  211.      * @return a constant compatible with instance order and number of parameters
  212.      * @see #DerivativeStructure(int, int, double)
  213.      * @since 3.3
  214.      */
  215.     public DerivativeStructure createConstant(final double c) {
  216.         return new DerivativeStructure(getFreeParameters(), getOrder(), c);
  217.     }

  218.     /** {@inheritDoc}
  219.      * @since 3.2
  220.      */
  221.     @Override
  222.     public double getReal() {
  223.         return data[0];
  224.     }

  225.     /** Get the value part of the derivative structure.
  226.      * @return value part of the derivative structure
  227.      * @see #getPartialDerivative(int...)
  228.      */
  229.     public double getValue() {
  230.         return data[0];
  231.     }

  232.     /** Get a partial derivative.
  233.      * @param orders derivation orders with respect to each variable (if all orders are 0,
  234.      * the value is returned)
  235.      * @return partial derivative
  236.      * @see #getValue()
  237.      * @throws DimensionMismatchException if the numbers of variables does not
  238.      * match the instance.
  239.      * @throws NumberIsTooLargeException if the sum of derivation orders is larger than
  240.      * the instance limits.
  241.      */
  242.     public double getPartialDerivative(final int ... orders) {
  243.         return data[compiler.getPartialDerivativeIndex(orders)];
  244.     }

  245.     /** Get all partial derivatives.
  246.      * @return a fresh copy of partial derivatives, in an array sorted according to
  247.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  248.      */
  249.     public double[] getAllDerivatives() {
  250.         return data.clone();
  251.     }

  252.     /** {@inheritDoc}
  253.      * @since 3.2
  254.      */
  255.     @Override
  256.     public DerivativeStructure add(final double a) {
  257.         final DerivativeStructure ds = new DerivativeStructure(this);
  258.         ds.data[0] += a;
  259.         return ds;
  260.     }

  261.     /** {@inheritDoc}
  262.      * @throws DimensionMismatchException if number of free parameters
  263.      * or orders do not match.
  264.      */
  265.     @Override
  266.     public DerivativeStructure add(final DerivativeStructure a) {
  267.         compiler.checkCompatibility(a.compiler);
  268.         final DerivativeStructure ds = new DerivativeStructure(this);
  269.         compiler.add(data, 0, a.data, 0, ds.data, 0);
  270.         return ds;
  271.     }

  272.     /** {@inheritDoc}
  273.      * @since 3.2
  274.      */
  275.     @Override
  276.     public DerivativeStructure subtract(final double a) {
  277.         return add(-a);
  278.     }

  279.     /** {@inheritDoc}
  280.      * @throws DimensionMismatchException if number of free parameters
  281.      * or orders do not match
  282.      */
  283.     @Override
  284.     public DerivativeStructure subtract(final DerivativeStructure a) {
  285.         compiler.checkCompatibility(a.compiler);
  286.         final DerivativeStructure ds = new DerivativeStructure(this);
  287.         compiler.subtract(data, 0, a.data, 0, ds.data, 0);
  288.         return ds;
  289.     }

  290.     /** {@inheritDoc} */
  291.     @Override
  292.     public DerivativeStructure multiply(final int n) {
  293.         return multiply((double) n);
  294.     }

  295.     /** {@inheritDoc}
  296.      * @since 3.2
  297.      */
  298.     @Override
  299.     public DerivativeStructure multiply(final double a) {
  300.         final DerivativeStructure ds = new DerivativeStructure(this);
  301.         for (int i = 0; i < ds.data.length; ++i) {
  302.             ds.data[i] *= a;
  303.         }
  304.         return ds;
  305.     }

  306.     /** {@inheritDoc}
  307.      * @throws DimensionMismatchException if number of free parameters
  308.      * or orders do not match
  309.      */
  310.     @Override
  311.     public DerivativeStructure multiply(final DerivativeStructure a) {
  312.         compiler.checkCompatibility(a.compiler);
  313.         final DerivativeStructure result = new DerivativeStructure(compiler);
  314.         compiler.multiply(data, 0, a.data, 0, result.data, 0);
  315.         return result;
  316.     }

  317.     /** {@inheritDoc}
  318.      * @since 3.2
  319.      */
  320.     @Override
  321.     public DerivativeStructure divide(final double a) {
  322.         final DerivativeStructure ds = new DerivativeStructure(this);
  323.         for (int i = 0; i < ds.data.length; ++i) {
  324.             ds.data[i] /= a;
  325.         }
  326.         return ds;
  327.     }

  328.     /** {@inheritDoc}
  329.      * @throws DimensionMismatchException if number of free parameters
  330.      * or orders do not match
  331.      */
  332.     @Override
  333.     public DerivativeStructure divide(final DerivativeStructure a) {
  334.         compiler.checkCompatibility(a.compiler);
  335.         final DerivativeStructure result = new DerivativeStructure(compiler);
  336.         compiler.divide(data, 0, a.data, 0, result.data, 0);
  337.         return result;
  338.     }

  339.     /** {@inheritDoc} */
  340.     @Override
  341.     public DerivativeStructure remainder(final double a) {
  342.         final DerivativeStructure ds = new DerivativeStructure(this);
  343.         ds.data[0] = JdkMath.IEEEremainder(ds.data[0], a);
  344.         return ds;
  345.     }

  346.     /** {@inheritDoc}
  347.      * @throws DimensionMismatchException if number of free parameters
  348.      * or orders do not match
  349.      * @since 3.2
  350.      */
  351.     @Override
  352.     public DerivativeStructure remainder(final DerivativeStructure a) {
  353.         compiler.checkCompatibility(a.compiler);
  354.         final DerivativeStructure result = new DerivativeStructure(compiler);
  355.         compiler.remainder(data, 0, a.data, 0, result.data, 0);
  356.         return result;
  357.     }

  358.     /** {@inheritDoc} */
  359.     @Override
  360.     public DerivativeStructure negate() {
  361.         final DerivativeStructure ds = new DerivativeStructure(compiler);
  362.         for (int i = 0; i < ds.data.length; ++i) {
  363.             ds.data[i] = -data[i];
  364.         }
  365.         return ds;
  366.     }

  367.     /** {@inheritDoc}
  368.      * @since 3.2
  369.      */
  370.     @Override
  371.     public DerivativeStructure abs() {
  372.         if (Double.doubleToLongBits(data[0]) < 0) {
  373.             // we use the bits representation to also handle -0.0
  374.             return negate();
  375.         } else {
  376.             return this;
  377.         }
  378.     }

  379.     /** {@inheritDoc}
  380.      * @since 3.2
  381.      */
  382.     @Override
  383.     public DerivativeStructure ceil() {
  384.         return new DerivativeStructure(compiler.getFreeParameters(),
  385.                                        compiler.getOrder(),
  386.                                        JdkMath.ceil(data[0]));
  387.     }

  388.     /** {@inheritDoc}
  389.      * @since 3.2
  390.      */
  391.     @Override
  392.     public DerivativeStructure floor() {
  393.         return new DerivativeStructure(compiler.getFreeParameters(),
  394.                                        compiler.getOrder(),
  395.                                        JdkMath.floor(data[0]));
  396.     }

  397.     /** {@inheritDoc}
  398.      * @since 3.2
  399.      */
  400.     @Override
  401.     public DerivativeStructure rint() {
  402.         return new DerivativeStructure(compiler.getFreeParameters(),
  403.                                        compiler.getOrder(),
  404.                                        JdkMath.rint(data[0]));
  405.     }

  406.     /** {@inheritDoc} */
  407.     @Override
  408.     public long round() {
  409.         return JdkMath.round(data[0]);
  410.     }

  411.     /** {@inheritDoc}
  412.      * @since 3.2
  413.      */
  414.     @Override
  415.     public DerivativeStructure signum() {
  416.         return new DerivativeStructure(compiler.getFreeParameters(),
  417.                                        compiler.getOrder(),
  418.                                        JdkMath.signum(data[0]));
  419.     }

  420.     /** {@inheritDoc}
  421.      * @since 3.2
  422.      */
  423.     @Override
  424.     public DerivativeStructure copySign(final DerivativeStructure sign){
  425.         long m = Double.doubleToLongBits(data[0]);
  426.         long s = Double.doubleToLongBits(sign.data[0]);
  427.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  428.             return this;
  429.         }
  430.         return negate(); // flip sign
  431.     }

  432.     /** {@inheritDoc}
  433.      * @since 3.2
  434.      */
  435.     @Override
  436.     public DerivativeStructure copySign(final double sign) {
  437.         long m = Double.doubleToLongBits(data[0]);
  438.         long s = Double.doubleToLongBits(sign);
  439.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  440.             return this;
  441.         }
  442.         return negate(); // flip sign
  443.     }

  444.     /**
  445.      * Return the exponent of the instance value, removing the bias.
  446.      * <p>
  447.      * For double numbers of the form 2<sup>x</sup>, the unbiased
  448.      * exponent is exactly x.
  449.      * </p>
  450.      * @return exponent for instance in IEEE754 representation, without bias
  451.      */
  452.     public int getExponent() {
  453.         return JdkMath.getExponent(data[0]);
  454.     }

  455.     /** {@inheritDoc}
  456.      * @since 3.2
  457.      */
  458.     @Override
  459.     public DerivativeStructure scalb(final int n) {
  460.         final DerivativeStructure ds = new DerivativeStructure(compiler);
  461.         for (int i = 0; i < ds.data.length; ++i) {
  462.             ds.data[i] = JdkMath.scalb(data[i], n);
  463.         }
  464.         return ds;
  465.     }

  466.     /** {@inheritDoc}
  467.      * @throws DimensionMismatchException if number of free parameters
  468.      * or orders do not match
  469.      * @since 3.2
  470.      */
  471.     @Override
  472.     public DerivativeStructure hypot(final DerivativeStructure y) {
  473.         compiler.checkCompatibility(y.compiler);

  474.         if (Double.isInfinite(data[0]) || Double.isInfinite(y.data[0])) {
  475.             return new DerivativeStructure(compiler.getFreeParameters(),
  476.                                            compiler.getFreeParameters(),
  477.                                            Double.POSITIVE_INFINITY);
  478.         } else if (Double.isNaN(data[0]) || Double.isNaN(y.data[0])) {
  479.             return new DerivativeStructure(compiler.getFreeParameters(),
  480.                                            compiler.getFreeParameters(),
  481.                                            Double.NaN);
  482.         } else {

  483.             final int expX = getExponent();
  484.             final int expY = y.getExponent();
  485.             if (expX > expY + 27) {
  486.                 // y is neglectible with respect to x
  487.                 return abs();
  488.             } else if (expY > expX + 27) {
  489.                 // x is neglectible with respect to y
  490.                 return y.abs();
  491.             } else {

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

  494.                 // scale parameters without losing precision
  495.                 final DerivativeStructure scaledX = scalb(-middleExp);
  496.                 final DerivativeStructure scaledY = y.scalb(-middleExp);

  497.                 // compute scaled hypotenuse
  498.                 final DerivativeStructure scaledH =
  499.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  500.                 // remove scaling
  501.                 return scaledH.scalb(middleExp);
  502.             }
  503.         }
  504.     }

  505.     /**
  506.      * Returns the hypotenuse of a triangle with sides {@code x} and {@code y}
  507.      * - sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
  508.      * avoiding intermediate overflow or underflow.
  509.      *
  510.      * <ul>
  511.      * <li> If either argument is infinite, then the result is positive infinity.</li>
  512.      * <li> else, if either argument is NaN then the result is NaN.</li>
  513.      * </ul>
  514.      *
  515.      * @param x a value
  516.      * @param y a value
  517.      * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
  518.      * @throws DimensionMismatchException if number of free parameters
  519.      * or orders do not match
  520.      * @since 3.2
  521.      */
  522.     public static DerivativeStructure hypot(final DerivativeStructure x, final DerivativeStructure y) {
  523.         return x.hypot(y);
  524.     }

  525.     /** Compute composition of the instance by a univariate function.
  526.      * @param f array of value and derivatives of the function at
  527.      * the current point (i.e. [f({@link #getValue()}),
  528.      * f'({@link #getValue()}), f''({@link #getValue()})...]).
  529.      * @return f(this)
  530.      * @throws DimensionMismatchException if the number of derivatives
  531.      * in the array is not equal to {@link #getOrder() order} + 1
  532.      */
  533.     public DerivativeStructure compose(final double ... f) {
  534.         if (f.length != getOrder() + 1) {
  535.             throw new DimensionMismatchException(f.length, getOrder() + 1);
  536.         }
  537.         final DerivativeStructure result = new DerivativeStructure(compiler);
  538.         compiler.compose(data, 0, f, result.data, 0);
  539.         return result;
  540.     }

  541.     /** {@inheritDoc} */
  542.     @Override
  543.     public DerivativeStructure reciprocal() {
  544.         final DerivativeStructure result = new DerivativeStructure(compiler);
  545.         compiler.pow(data, 0, -1, result.data, 0);
  546.         return result;
  547.     }

  548.     /** {@inheritDoc}
  549.      * @since 3.2
  550.      */
  551.     @Override
  552.     public DerivativeStructure sqrt() {
  553.         return rootN(2);
  554.     }

  555.     /** {@inheritDoc}
  556.      * @since 3.2
  557.      */
  558.     @Override
  559.     public DerivativeStructure cbrt() {
  560.         return rootN(3);
  561.     }

  562.     /** {@inheritDoc}
  563.      * @since 3.2
  564.      */
  565.     @Override
  566.     public DerivativeStructure rootN(final int n) {
  567.         final DerivativeStructure result = new DerivativeStructure(compiler);
  568.         compiler.rootN(data, 0, n, result.data, 0);
  569.         return result;
  570.     }

  571.     /** {@inheritDoc} */
  572.     @Override
  573.     public Field<DerivativeStructure> getField() {
  574.         return new Field<DerivativeStructure>() {

  575.             /** {@inheritDoc} */
  576.             @Override
  577.             public DerivativeStructure getZero() {
  578.                 return new DerivativeStructure(compiler.getFreeParameters(), compiler.getOrder(), 0.0);
  579.             }

  580.             /** {@inheritDoc} */
  581.             @Override
  582.             public DerivativeStructure getOne() {
  583.                 return new DerivativeStructure(compiler.getFreeParameters(), compiler.getOrder(), 1.0);
  584.             }

  585.             /** {@inheritDoc} */
  586.             @Override
  587.             public Class<? extends FieldElement<DerivativeStructure>> getRuntimeClass() {
  588.                 return DerivativeStructure.class;
  589.             }
  590.         };
  591.     }

  592.     /** Compute a<sup>x</sup> where a is a double and x a {@link DerivativeStructure}.
  593.      * @param a number to exponentiate
  594.      * @param x power to apply
  595.      * @return a<sup>x</sup>
  596.      * @since 3.3
  597.      */
  598.     public static DerivativeStructure pow(final double a, final DerivativeStructure x) {
  599.         final DerivativeStructure result = new DerivativeStructure(x.compiler);
  600.         x.compiler.pow(a, x.data, 0, result.data, 0);
  601.         return result;
  602.     }

  603.     /** {@inheritDoc}
  604.      * @since 3.2
  605.      */
  606.     @Override
  607.     public DerivativeStructure pow(final double p) {
  608.         final DerivativeStructure result = new DerivativeStructure(compiler);
  609.         compiler.pow(data, 0, p, result.data, 0);
  610.         return result;
  611.     }

  612.     /** {@inheritDoc}
  613.      * @since 3.2
  614.      */
  615.     @Override
  616.     public DerivativeStructure pow(final int n) {
  617.         final DerivativeStructure result = new DerivativeStructure(compiler);
  618.         compiler.pow(data, 0, n, result.data, 0);
  619.         return result;
  620.     }

  621.     /** {@inheritDoc}
  622.      * @throws DimensionMismatchException if number of free parameters
  623.      * or orders do not match
  624.      * @since 3.2
  625.      */
  626.     @Override
  627.     public DerivativeStructure pow(final DerivativeStructure e) {
  628.         compiler.checkCompatibility(e.compiler);
  629.         final DerivativeStructure result = new DerivativeStructure(compiler);
  630.         compiler.pow(data, 0, e.data, 0, result.data, 0);
  631.         return result;
  632.     }

  633.     /** {@inheritDoc}
  634.      * @since 3.2
  635.      */
  636.     @Override
  637.     public DerivativeStructure exp() {
  638.         final DerivativeStructure result = new DerivativeStructure(compiler);
  639.         compiler.exp(data, 0, result.data, 0);
  640.         return result;
  641.     }

  642.     /** {@inheritDoc}
  643.      * @since 3.2
  644.      */
  645.     @Override
  646.     public DerivativeStructure expm1() {
  647.         final DerivativeStructure result = new DerivativeStructure(compiler);
  648.         compiler.expm1(data, 0, result.data, 0);
  649.         return result;
  650.     }

  651.     /** {@inheritDoc}
  652.      * @since 3.2
  653.      */
  654.     @Override
  655.     public DerivativeStructure log() {
  656.         final DerivativeStructure result = new DerivativeStructure(compiler);
  657.         compiler.log(data, 0, result.data, 0);
  658.         return result;
  659.     }

  660.     /** {@inheritDoc}
  661.      * @since 3.2
  662.      */
  663.     @Override
  664.     public DerivativeStructure log1p() {
  665.         final DerivativeStructure result = new DerivativeStructure(compiler);
  666.         compiler.log1p(data, 0, result.data, 0);
  667.         return result;
  668.     }

  669.     /** Base 10 logarithm.
  670.      * @return base 10 logarithm of the instance
  671.      */
  672.     @Override
  673.     public DerivativeStructure log10() {
  674.         final DerivativeStructure result = new DerivativeStructure(compiler);
  675.         compiler.log10(data, 0, result.data, 0);
  676.         return result;
  677.     }

  678.     /** {@inheritDoc}
  679.      * @since 3.2
  680.      */
  681.     @Override
  682.     public DerivativeStructure cos() {
  683.         final DerivativeStructure result = new DerivativeStructure(compiler);
  684.         compiler.cos(data, 0, result.data, 0);
  685.         return result;
  686.     }

  687.     /** {@inheritDoc}
  688.      * @since 3.2
  689.      */
  690.     @Override
  691.     public DerivativeStructure sin() {
  692.         final DerivativeStructure result = new DerivativeStructure(compiler);
  693.         compiler.sin(data, 0, result.data, 0);
  694.         return result;
  695.     }

  696.     /** {@inheritDoc}
  697.      * @since 3.2
  698.      */
  699.     @Override
  700.     public DerivativeStructure tan() {
  701.         final DerivativeStructure result = new DerivativeStructure(compiler);
  702.         compiler.tan(data, 0, result.data, 0);
  703.         return result;
  704.     }

  705.     /** {@inheritDoc}
  706.      * @since 3.2
  707.      */
  708.     @Override
  709.     public DerivativeStructure acos() {
  710.         final DerivativeStructure result = new DerivativeStructure(compiler);
  711.         compiler.acos(data, 0, result.data, 0);
  712.         return result;
  713.     }

  714.     /** {@inheritDoc}
  715.      * @since 3.2
  716.      */
  717.     @Override
  718.     public DerivativeStructure asin() {
  719.         final DerivativeStructure result = new DerivativeStructure(compiler);
  720.         compiler.asin(data, 0, result.data, 0);
  721.         return result;
  722.     }

  723.     /** {@inheritDoc}
  724.      * @since 3.2
  725.      */
  726.     @Override
  727.     public DerivativeStructure atan() {
  728.         final DerivativeStructure result = new DerivativeStructure(compiler);
  729.         compiler.atan(data, 0, result.data, 0);
  730.         return result;
  731.     }

  732.     /** {@inheritDoc}
  733.      * @since 3.2
  734.      */
  735.     @Override
  736.     public DerivativeStructure atan2(final DerivativeStructure x) {
  737.         compiler.checkCompatibility(x.compiler);
  738.         final DerivativeStructure result = new DerivativeStructure(compiler);
  739.         compiler.atan2(data, 0, x.data, 0, result.data, 0);
  740.         return result;
  741.     }

  742.     /** Two arguments arc tangent operation.
  743.      * @param y first argument of the arc tangent
  744.      * @param x second argument of the arc tangent
  745.      * @return atan2(y, x)
  746.      * @throws DimensionMismatchException if number of free parameters
  747.      * or orders do not match
  748.      * @since 3.2
  749.      */
  750.     public static DerivativeStructure atan2(final DerivativeStructure y, final DerivativeStructure x) {
  751.         return y.atan2(x);
  752.     }

  753.     /** {@inheritDoc}
  754.      * @since 3.2
  755.      */
  756.     @Override
  757.     public DerivativeStructure cosh() {
  758.         final DerivativeStructure result = new DerivativeStructure(compiler);
  759.         compiler.cosh(data, 0, result.data, 0);
  760.         return result;
  761.     }

  762.     /** {@inheritDoc}
  763.      * @since 3.2
  764.      */
  765.     @Override
  766.     public DerivativeStructure sinh() {
  767.         final DerivativeStructure result = new DerivativeStructure(compiler);
  768.         compiler.sinh(data, 0, result.data, 0);
  769.         return result;
  770.     }

  771.     /** {@inheritDoc}
  772.      * @since 3.2
  773.      */
  774.     @Override
  775.     public DerivativeStructure tanh() {
  776.         final DerivativeStructure result = new DerivativeStructure(compiler);
  777.         compiler.tanh(data, 0, result.data, 0);
  778.         return result;
  779.     }

  780.     /** {@inheritDoc}
  781.      * @since 3.2
  782.      */
  783.     @Override
  784.     public DerivativeStructure acosh() {
  785.         final DerivativeStructure result = new DerivativeStructure(compiler);
  786.         compiler.acosh(data, 0, result.data, 0);
  787.         return result;
  788.     }

  789.     /** {@inheritDoc}
  790.      * @since 3.2
  791.      */
  792.     @Override
  793.     public DerivativeStructure asinh() {
  794.         final DerivativeStructure result = new DerivativeStructure(compiler);
  795.         compiler.asinh(data, 0, result.data, 0);
  796.         return result;
  797.     }

  798.     /** {@inheritDoc}
  799.      * @since 3.2
  800.      */
  801.     @Override
  802.     public DerivativeStructure atanh() {
  803.         final DerivativeStructure result = new DerivativeStructure(compiler);
  804.         compiler.atanh(data, 0, result.data, 0);
  805.         return result;
  806.     }

  807.     /** Convert radians to degrees, with error of less than 0.5 ULP.
  808.      *  @return instance converted into degrees
  809.      */
  810.     public DerivativeStructure toDegrees() {
  811.         final DerivativeStructure ds = new DerivativeStructure(compiler);
  812.         for (int i = 0; i < ds.data.length; ++i) {
  813.             ds.data[i] = JdkMath.toDegrees(data[i]);
  814.         }
  815.         return ds;
  816.     }

  817.     /** Convert degrees to radians, with error of less than 0.5 ULP.
  818.      *  @return instance converted into radians
  819.      */
  820.     public DerivativeStructure toRadians() {
  821.         final DerivativeStructure ds = new DerivativeStructure(compiler);
  822.         for (int i = 0; i < ds.data.length; ++i) {
  823.             ds.data[i] = JdkMath.toRadians(data[i]);
  824.         }
  825.         return ds;
  826.     }

  827.     /** Evaluate Taylor expansion a derivative structure.
  828.      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
  829.      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
  830.      * @throws org.apache.commons.math4.legacy.exception.MathArithmeticException
  831.      * if factorials becomes too large
  832.      */
  833.     public double taylor(final double ... delta) {
  834.         return compiler.taylor(data, 0, delta);
  835.     }

  836.     /** {@inheritDoc}
  837.      * @throws DimensionMismatchException if number of free parameters
  838.      * or orders do not match
  839.      * @since 3.2
  840.      */
  841.     @Override
  842.     public DerivativeStructure linearCombination(final DerivativeStructure[] a, final DerivativeStructure[] b) {
  843.         // compute an accurate value, taking care of cancellations
  844.         final double[] aDouble = new double[a.length];
  845.         for (int i = 0; i < a.length; ++i) {
  846.             aDouble[i] = a[i].getValue();
  847.         }
  848.         final double[] bDouble = new double[b.length];
  849.         for (int i = 0; i < b.length; ++i) {
  850.             bDouble[i] = b[i].getValue();
  851.         }
  852.         final double accurateValue = Sum.ofProducts(aDouble, bDouble).getAsDouble();

  853.         // compute a simple value, with all partial derivatives
  854.         DerivativeStructure simpleValue = a[0].getField().getZero();
  855.         for (int i = 0; i < a.length; ++i) {
  856.             simpleValue = simpleValue.add(a[i].multiply(b[i]));
  857.         }

  858.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  859.         final double[] all = simpleValue.getAllDerivatives();
  860.         all[0] = accurateValue;
  861.         return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), all);
  862.     }

  863.     /** {@inheritDoc}
  864.      * @throws DimensionMismatchException if number of free parameters
  865.      * or orders do not match
  866.      * @since 3.2
  867.      */
  868.     @Override
  869.     public DerivativeStructure linearCombination(final double[] a, final DerivativeStructure[] b) {
  870.         // compute an accurate value, taking care of cancellations
  871.         final double[] bDouble = new double[b.length];
  872.         for (int i = 0; i < b.length; ++i) {
  873.             bDouble[i] = b[i].getValue();
  874.         }
  875.         final double accurateValue = Sum.ofProducts(a, bDouble).getAsDouble();

  876.         // compute a simple value, with all partial derivatives
  877.         DerivativeStructure simpleValue = b[0].getField().getZero();
  878.         for (int i = 0; i < a.length; ++i) {
  879.             simpleValue = simpleValue.add(b[i].multiply(a[i]));
  880.         }

  881.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  882.         final double[] all = simpleValue.getAllDerivatives();
  883.         all[0] = accurateValue;
  884.         return new DerivativeStructure(simpleValue.getFreeParameters(), simpleValue.getOrder(), all);
  885.     }

  886.     /** {@inheritDoc}
  887.      * @throws DimensionMismatchException if number of free parameters
  888.      * or orders do not match
  889.      * @since 3.2
  890.      */
  891.     @Override
  892.     public DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1,
  893.                                                  final DerivativeStructure a2, final DerivativeStructure b2) {
  894.         // compute an accurate value, taking care of cancellations
  895.         final double accurateValue = Sum.create()
  896.             .addProduct(a1.getValue(), b1.getValue())
  897.             .addProduct(a2.getValue(), b2.getValue()).getAsDouble();

  898.         // compute a simple value, with all partial derivatives
  899.         final DerivativeStructure simpleValue = a1.multiply(b1).add(a2.multiply(b2));

  900.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  901.         final double[] all = simpleValue.getAllDerivatives();
  902.         all[0] = accurateValue;
  903.         return new DerivativeStructure(getFreeParameters(), getOrder(), all);
  904.     }

  905.     /** {@inheritDoc}
  906.      * @throws DimensionMismatchException if number of free parameters
  907.      * or orders do not match
  908.      * @since 3.2
  909.      */
  910.     @Override
  911.     public DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1,
  912.                                                  final double a2, final DerivativeStructure b2) {
  913.         // compute an accurate value, taking care of cancellations
  914.         final double accurateValue = Sum.create()
  915.             .addProduct(a1, b1.getValue())
  916.             .addProduct(a2, b2.getValue()).getAsDouble();

  917.         // compute a simple value, with all partial derivatives
  918.         final DerivativeStructure simpleValue = b1.multiply(a1).add(b2.multiply(a2));

  919.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  920.         final double[] all = simpleValue.getAllDerivatives();
  921.         all[0] = accurateValue;
  922.         return new DerivativeStructure(getFreeParameters(), getOrder(), all);
  923.     }

  924.     /** {@inheritDoc}
  925.      * @throws DimensionMismatchException if number of free parameters
  926.      * or orders do not match
  927.      * @since 3.2
  928.      */
  929.     @Override
  930.     public DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1,
  931.                                                  final DerivativeStructure a2, final DerivativeStructure b2,
  932.                                                  final DerivativeStructure a3, final DerivativeStructure b3) {
  933.         // compute an accurate value, taking care of cancellations
  934.         final double accurateValue = Sum.create()
  935.             .addProduct(a1.getValue(), b1.getValue())
  936.             .addProduct(a2.getValue(), b2.getValue())
  937.             .addProduct(a3.getValue(), b3.getValue()).getAsDouble();

  938.         // compute a simple value, with all partial derivatives
  939.         final DerivativeStructure simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3));

  940.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  941.         final double[] all = simpleValue.getAllDerivatives();
  942.         all[0] = accurateValue;
  943.         return new DerivativeStructure(getFreeParameters(), getOrder(), all);
  944.     }

  945.     /** {@inheritDoc}
  946.      * @throws DimensionMismatchException if number of free parameters
  947.      * or orders do not match
  948.      * @since 3.2
  949.      */
  950.     @Override
  951.     public DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1,
  952.                                                  final double a2, final DerivativeStructure b2,
  953.                                                  final double a3, final DerivativeStructure b3) {
  954.         // compute an accurate value, taking care of cancellations
  955.         final double accurateValue = Sum.create()
  956.             .addProduct(a1, b1.getValue())
  957.             .addProduct(a2, b2.getValue())
  958.             .addProduct(a3, b3.getValue()).getAsDouble();

  959.         // compute a simple value, with all partial derivatives
  960.         final DerivativeStructure simpleValue = b1.multiply(a1).add(b2.multiply(a2)).add(b3.multiply(a3));

  961.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  962.         final double[] all = simpleValue.getAllDerivatives();
  963.         all[0] = accurateValue;
  964.         return new DerivativeStructure(getFreeParameters(), getOrder(), all);
  965.     }

  966.     /** {@inheritDoc}
  967.      * @throws DimensionMismatchException if number of free parameters
  968.      * or orders do not match
  969.      * @since 3.2
  970.      */
  971.     @Override
  972.     public DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1,
  973.                                                  final DerivativeStructure a2, final DerivativeStructure b2,
  974.                                                  final DerivativeStructure a3, final DerivativeStructure b3,
  975.                                                  final DerivativeStructure a4, final DerivativeStructure b4) {
  976.         // compute an accurate value, taking care of cancellations
  977.         final double accurateValue = Sum.create()
  978.             .addProduct(a1.getValue(), b1.getValue())
  979.             .addProduct(a2.getValue(), b2.getValue())
  980.             .addProduct(a3.getValue(), b3.getValue())
  981.             .addProduct(a4.getValue(), b4.getValue()).getAsDouble();

  982.         // compute a simple value, with all partial derivatives
  983.         final DerivativeStructure simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3)).add(a4.multiply(b4));

  984.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  985.         final double[] all = simpleValue.getAllDerivatives();
  986.         all[0] = accurateValue;
  987.         return new DerivativeStructure(getFreeParameters(), getOrder(), all);
  988.     }

  989.     /** {@inheritDoc}
  990.      * @throws DimensionMismatchException if number of free parameters
  991.      * or orders do not match
  992.      * @since 3.2
  993.      */
  994.     @Override
  995.     public DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1,
  996.                                                  final double a2, final DerivativeStructure b2,
  997.                                                  final double a3, final DerivativeStructure b3,
  998.                                                  final double a4, final DerivativeStructure b4) {
  999.         // compute an accurate value, taking care of cancellations
  1000.         final double accurateValue = Sum.create()
  1001.             .addProduct(a1, b1.getValue())
  1002.             .addProduct(a2, b2.getValue())
  1003.             .addProduct(a3, b3.getValue())
  1004.             .addProduct(a4, b4.getValue()).getAsDouble();

  1005.         // compute a simple value, with all partial derivatives
  1006.         final DerivativeStructure simpleValue = b1.multiply(a1).add(b2.multiply(a2)).add(b3.multiply(a3)).add(b4.multiply(a4));

  1007.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  1008.         final double[] all = simpleValue.getAllDerivatives();
  1009.         all[0] = accurateValue;
  1010.         return new DerivativeStructure(getFreeParameters(), getOrder(), all);
  1011.     }

  1012.     /**
  1013.      * Test for the equality of two derivative structures.
  1014.      * <p>
  1015.      * Derivative structures are considered equal if they have the same number
  1016.      * of free parameters, the same derivation order, and the same derivatives.
  1017.      * </p>
  1018.      * @param other Object to test for equality to this
  1019.      * @return true if two derivative structures are equal
  1020.      * @since 3.2
  1021.      */
  1022.     @Override
  1023.     public boolean equals(Object other) {

  1024.         if (this == other) {
  1025.             return true;
  1026.         }

  1027.         if (other instanceof DerivativeStructure) {
  1028.             final DerivativeStructure rhs = (DerivativeStructure)other;
  1029.             return getFreeParameters() == rhs.getFreeParameters() &&
  1030.                    getOrder() == rhs.getOrder() &&
  1031.                    MathArrays.equals(data, rhs.data);
  1032.         }

  1033.         return false;
  1034.     }

  1035.     /**
  1036.      * Get a hashCode for the derivative structure.
  1037.      * @return a hash code value for this object
  1038.      * @since 3.2
  1039.      */
  1040.     @Override
  1041.     public int hashCode() {
  1042.         return 227 + 229 * getFreeParameters() + 233 * getOrder() + 239 * Arrays.hashCode(data);
  1043.     }
  1044. }