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.  *      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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.analysis.differentiation;

  22. import java.io.Serializable;

  23. import org.hipparchus.Field;
  24. import org.hipparchus.exception.MathIllegalArgumentException;
  25. import org.hipparchus.exception.MathRuntimeException;
  26. import org.hipparchus.util.FastMath;
  27. import org.hipparchus.util.FieldSinCos;
  28. import org.hipparchus.util.FieldSinhCosh;
  29. import org.hipparchus.util.MathArrays;
  30. import org.hipparchus.util.MathUtils;

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

  64.     /** Serializable UID. */
  65.     private static final long serialVersionUID = 20161220L;

  66.     /** Factory that built the instance. */
  67.     private final DSFactory factory;

  68.     /** Combined array holding all values. */
  69.     private final double[] data;

  70.     /** Build an instance with all values and derivatives set to 0.
  71.      * @param factory factory that built the instance
  72.      * @param data combined array holding all values
  73.      */
  74.     DerivativeStructure(final DSFactory factory, final double[] data) {
  75.         this.factory = factory;
  76.         this.data    = data.clone();
  77.     }

  78.     /** Build an instance with all values and derivatives set to 0.
  79.      * @param factory factory that built the instance
  80.      * @since 1.4
  81.      */
  82.     DerivativeStructure(final DSFactory factory) {
  83.         this.factory = factory;
  84.         this.data    = new double[factory.getCompiler().getSize()];
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     public DerivativeStructure newInstance(final double value) {
  89.         return factory.constant(value);
  90.     }

  91.     /** {@inheritDoc} */
  92.     @Override
  93.     public DerivativeStructure withValue(final double value) {
  94.         final DerivativeStructure ds = factory.build();
  95.         System.arraycopy(data, 1, ds.data, 1, data.length - 1);
  96.         ds.data[0] = value;
  97.         return ds;
  98.     }

  99.     /** Get the factory that built the instance.
  100.      * @return factory that built the instance
  101.      */
  102.     public DSFactory getFactory() {
  103.         return factory;
  104.     }

  105.     /** {@inheritDoc} */
  106.     @Override
  107.     public int getFreeParameters() {
  108.         return getFactory().getCompiler().getFreeParameters();
  109.     }

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     public int getOrder() {
  113.         return getFactory().getCompiler().getOrder();
  114.     }

  115.     /** Set a derivative component.
  116.      * <p>
  117.      * This method is package-private (no modifier specified), as it is intended
  118.      * to be used only by Hipparchus classes since it relied on the ordering of
  119.      * derivatives within the class. This allows avoiding checks on the index,
  120.      * for performance reasons.
  121.      * </p>
  122.      * @param index index of the derivative
  123.      * @param value of the derivative to set
  124.      * @since 1.4
  125.      */
  126.     void setDerivativeComponent(final int index, final double value) {
  127.         data[index] = value;
  128.     }

  129.     /** Get a derivative component.
  130.      * <p>
  131.      * This method is package-private (no modifier specified), as it is intended
  132.      * to be used only by Hipparchus classes since it relied on the ordering of
  133.      * derivatives within the class. This allows avoiding checks on the index,
  134.      * for performance reasons.
  135.      * </p>
  136.      * @param index index of the derivative
  137.      * @return value of the derivative
  138.      * @since 2.2
  139.      */
  140.     double getDerivativeComponent(final int index) {
  141.         return data[index];
  142.     }

  143.     /** {@inheritDoc} */
  144.     @Override
  145.     public DerivativeStructure getAddendum() {
  146.         final double[] addendum = data.clone();
  147.         addendum[0] = 0;
  148.         return new DerivativeStructure(factory, addendum);
  149.     }

  150.     /** Get the value part of the derivative structure.
  151.      * @return value part of the derivative structure
  152.      * @see #getPartialDerivative(int...)
  153.      */
  154.     @Override
  155.     public double getValue() {
  156.         return data[0];
  157.     }

  158.     /** {@inheritDoc} */
  159.     @Override
  160.     public double getPartialDerivative(final int ... orders)
  161.         throws MathIllegalArgumentException {
  162.         return data[getFactory().getCompiler().getPartialDerivativeIndex(orders)];
  163.     }

  164.     /** Get all partial derivatives.
  165.      * @return a fresh copy of partial derivatives, in an array sorted according to
  166.      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
  167.      */
  168.     public double[] getAllDerivatives() {
  169.         return data.clone();
  170.     }

  171.     /** {@inheritDoc}
  172.      * @exception MathIllegalArgumentException if number of free parameters
  173.      * or orders do not match
  174.      */
  175.     @Override
  176.     public DerivativeStructure add(final DerivativeStructure a)
  177.         throws MathIllegalArgumentException {
  178.         factory.checkCompatibility(a.factory);
  179.         final DerivativeStructure ds = factory.build();
  180.         factory.getCompiler().add(data, 0, a.data, 0, ds.data, 0);
  181.         return ds;
  182.     }

  183.     /** {@inheritDoc}
  184.      * @exception MathIllegalArgumentException if number of free parameters
  185.      * or orders do not match
  186.      */
  187.     @Override
  188.     public DerivativeStructure subtract(final DerivativeStructure a)
  189.         throws MathIllegalArgumentException {
  190.         factory.checkCompatibility(a.factory);
  191.         final DerivativeStructure ds = factory.build();
  192.         factory.getCompiler().subtract(data, 0, a.data, 0, ds.data, 0);
  193.         return ds;
  194.     }

  195.     /** {@inheritDoc}
  196.      */
  197.     @Override
  198.     public DerivativeStructure multiply(final double a) {
  199.         final DerivativeStructure ds = factory.build();
  200.         for (int i = 0; i < ds.data.length; ++i) {
  201.             ds.data[i] = data[i] * a;
  202.         }
  203.         return ds;
  204.     }

  205.     /** {@inheritDoc}
  206.      * @exception MathIllegalArgumentException if number of free parameters
  207.      * or orders do not match
  208.      */
  209.     @Override
  210.     public DerivativeStructure multiply(final DerivativeStructure a)
  211.         throws MathIllegalArgumentException {
  212.         factory.checkCompatibility(a.factory);
  213.         final DerivativeStructure result = factory.build();
  214.         factory.getCompiler().multiply(data, 0, a.data, 0, result.data, 0);
  215.         return result;
  216.     }

  217.     /** {@inheritDoc} */
  218.     @Override
  219.     public DerivativeStructure square() {
  220.         return multiply(this);
  221.     }

  222.     /** {@inheritDoc}
  223.      */
  224.     @Override
  225.     public DerivativeStructure divide(final double a) {
  226.         final DerivativeStructure ds = factory.build();
  227.         final double inv = 1.0 / a;
  228.         for (int i = 0; i < ds.data.length; ++i) {
  229.             ds.data[i] = data[i] * inv;
  230.         }
  231.         return ds;
  232.     }

  233.     /** {@inheritDoc}
  234.      * @exception MathIllegalArgumentException if number of free parameters
  235.      * or orders do not match
  236.      */
  237.     @Override
  238.     public DerivativeStructure divide(final DerivativeStructure a)
  239.         throws MathIllegalArgumentException {
  240.         factory.checkCompatibility(a.factory);
  241.         final DerivativeStructure result = factory.build();
  242.         factory.getCompiler().divide(data, 0, a.data, 0, result.data, 0);
  243.         return result;
  244.     }

  245.     /** {@inheritDoc}
  246.      * @exception MathIllegalArgumentException if number of free parameters
  247.      * or orders do not match
  248.      */
  249.     @Override
  250.     public DerivativeStructure remainder(final DerivativeStructure a)
  251.         throws MathIllegalArgumentException {
  252.         factory.checkCompatibility(a.factory);
  253.         final DerivativeStructure result = factory.build();
  254.         factory.getCompiler().remainder(data, 0, a.data, 0, result.data, 0);
  255.         return result;
  256.     }

  257.     /** {@inheritDoc} */
  258.     @Override
  259.     public DerivativeStructure negate() {
  260.         final DerivativeStructure ds = factory.build();
  261.         for (int i = 0; i < ds.data.length; ++i) {
  262.             ds.data[i] = -data[i];
  263.         }
  264.         return ds;
  265.     }

  266.     /** {@inheritDoc}
  267.      */
  268.     @Override
  269.     public DerivativeStructure abs() {
  270.         if (Double.doubleToLongBits(data[0]) < 0) {
  271.             // we use the bits representation to also handle -0.0
  272.             return negate();
  273.         } else {
  274.             return this;
  275.         }
  276.     }

  277.     /** {@inheritDoc}
  278.      */
  279.     @Override
  280.     public DerivativeStructure copySign(final DerivativeStructure sign) {
  281.         long m = Double.doubleToLongBits(data[0]);
  282.         long s = Double.doubleToLongBits(sign.data[0]);
  283.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  284.             return this;
  285.         }
  286.         return negate(); // flip sign
  287.     }

  288.     /** {@inheritDoc}
  289.      */
  290.     @Override
  291.     public DerivativeStructure copySign(final double sign) {
  292.         long m = Double.doubleToLongBits(data[0]);
  293.         long s = Double.doubleToLongBits(sign);
  294.         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
  295.             return this;
  296.         }
  297.         return negate(); // flip sign
  298.     }

  299.     /** {@inheritDoc}
  300.      */
  301.     @Override
  302.     public DerivativeStructure scalb(final int n) {
  303.         final DerivativeStructure ds = factory.build();
  304.         for (int i = 0; i < ds.data.length; ++i) {
  305.             ds.data[i] = FastMath.scalb(data[i], n);
  306.         }
  307.         return ds;
  308.     }

  309.     /** {@inheritDoc}
  310.      * @exception MathIllegalArgumentException if number of free parameters
  311.      * or orders do not match
  312.      */
  313.     @Override
  314.     public DerivativeStructure hypot(final DerivativeStructure y)
  315.         throws MathIllegalArgumentException {

  316.         factory.checkCompatibility(y.factory);

  317.         if (Double.isInfinite(data[0]) || Double.isInfinite(y.data[0])) {
  318.             return factory.constant(Double.POSITIVE_INFINITY);
  319.         } else if (Double.isNaN(data[0]) || Double.isNaN(y.data[0])) {
  320.             return factory.constant(Double.NaN);
  321.         } else {

  322.             final int expX = getExponent();
  323.             final int expY = y.getExponent();
  324.             if (expX > expY + 27) {
  325.                 // y is negligible with respect to x
  326.                 return abs();
  327.             } else if (expY > expX + 27) {
  328.                 // x is negligible with respect to y
  329.                 return y.abs();
  330.             } else {

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

  333.                 // scale parameters without losing precision
  334.                 final DerivativeStructure scaledX = scalb(-middleExp);
  335.                 final DerivativeStructure scaledY = y.scalb(-middleExp);

  336.                 // compute scaled hypotenuse
  337.                 final DerivativeStructure scaledH =
  338.                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();

  339.                 // remove scaling
  340.                 return scaledH.scalb(middleExp);

  341.             }

  342.         }
  343.     }

  344.     /**
  345.      * Returns the hypotenuse of a triangle with sides {@code x} and {@code y}
  346.      * - sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
  347.      * avoiding intermediate overflow or underflow.
  348.      *
  349.      * <ul>
  350.      * <li> If either argument is infinite, then the result is positive infinity.</li>
  351.      * <li> else, if either argument is NaN then the result is NaN.</li>
  352.      * </ul>
  353.      *
  354.      * @param x a value
  355.      * @param y a value
  356.      * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
  357.      * @exception MathIllegalArgumentException if number of free parameters
  358.      * or orders do not match
  359.      */
  360.     public static DerivativeStructure hypot(final DerivativeStructure x, final DerivativeStructure y)
  361.         throws MathIllegalArgumentException {
  362.         return x.hypot(y);
  363.     }

  364.     /** Compute composition of the instance by a univariate function.
  365.      * @param f array of value and derivatives of the function at
  366.      * the current point (i.e. [f({@link #getValue()}),
  367.      * f'({@link #getValue()}), f''({@link #getValue()})...]).
  368.      * @return f(this)
  369.      * @exception MathIllegalArgumentException if the number of derivatives
  370.      * in the array is not equal to {@link #getOrder() order} + 1
  371.      */
  372.     @Override
  373.     public DerivativeStructure compose(final double ... f)
  374.         throws MathIllegalArgumentException {

  375.         MathUtils.checkDimension(f.length, getOrder() + 1);
  376.         final DerivativeStructure result = factory.build();
  377.         factory.getCompiler().compose(data, 0, f, result.data, 0);
  378.         return result;
  379.     }

  380.     /** {@inheritDoc} */
  381.     @Override
  382.     public DerivativeStructure reciprocal() {
  383.         final DerivativeStructure result = factory.build();
  384.         factory.getCompiler().reciprocal(data, 0, result.data, 0);
  385.         return result;
  386.     }

  387.     /** {@inheritDoc}
  388.      */
  389.     @Override
  390.     public DerivativeStructure sqrt() {
  391.         final DerivativeStructure result = factory.build();
  392.         factory.getCompiler().sqrt(data, 0, result.data, 0);
  393.         return result;
  394.     }

  395.     /** {@inheritDoc}
  396.      */
  397.     @Override
  398.     public DerivativeStructure rootN(final int n) {
  399.         final DerivativeStructure result = factory.build();
  400.         factory.getCompiler().rootN(data, 0, n, result.data, 0);
  401.         return result;
  402.     }

  403.     /** {@inheritDoc} */
  404.     @Override
  405.     public Field<DerivativeStructure> getField() {
  406.         return factory.getDerivativeField();
  407.     }

  408.     /** Compute a<sup>x</sup> where a is a double and x a {@link DerivativeStructure}
  409.      * @param a number to exponentiate
  410.      * @param x power to apply
  411.      * @return a<sup>x</sup>
  412.      */
  413.     public static DerivativeStructure pow(final double a, final DerivativeStructure x) {
  414.         final DerivativeStructure result = x.factory.build();
  415.         x.factory.getCompiler().pow(a, x.data, 0, result.data, 0);
  416.         return result;
  417.     }

  418.     /** {@inheritDoc}
  419.      */
  420.     @Override
  421.     public DerivativeStructure pow(final double p) {
  422.         final DerivativeStructure result = factory.build();
  423.         factory.getCompiler().pow(data, 0, p, result.data, 0);
  424.         return result;
  425.     }

  426.     /** {@inheritDoc}
  427.      */
  428.     @Override
  429.     public DerivativeStructure pow(final int n) {
  430.         final DerivativeStructure result = factory.build();
  431.         factory.getCompiler().pow(data, 0, n, result.data, 0);
  432.         return result;
  433.     }

  434.     /** {@inheritDoc}
  435.      * @exception MathIllegalArgumentException if number of free parameters
  436.      * or orders do not match
  437.      */
  438.     @Override
  439.     public DerivativeStructure pow(final DerivativeStructure e)
  440.         throws MathIllegalArgumentException {
  441.         factory.checkCompatibility(e.factory);
  442.         final DerivativeStructure result = factory.build();
  443.         factory.getCompiler().pow(data, 0, e.data, 0, result.data, 0);
  444.         return result;
  445.     }

  446.     /** {@inheritDoc}
  447.      */
  448.     @Override
  449.     public DerivativeStructure exp() {
  450.         final DerivativeStructure result = factory.build();
  451.         factory.getCompiler().exp(data, 0, result.data, 0);
  452.         return result;
  453.     }

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

  462.     /** {@inheritDoc}
  463.      */
  464.     @Override
  465.     public DerivativeStructure log() {
  466.         final DerivativeStructure result = factory.build();
  467.         factory.getCompiler().log(data, 0, result.data, 0);
  468.         return result;
  469.     }

  470.     /** {@inheritDoc}
  471.      */
  472.     @Override
  473.     public DerivativeStructure log1p() {
  474.         final DerivativeStructure result = factory.build();
  475.         factory.getCompiler().log1p(data, 0, result.data, 0);
  476.         return result;
  477.     }

  478.     /** Base 10 logarithm.
  479.      * @return base 10 logarithm of the instance
  480.      */
  481.     @Override
  482.     public DerivativeStructure log10() {
  483.         final DerivativeStructure result = factory.build();
  484.         factory.getCompiler().log10(data, 0, result.data, 0);
  485.         return result;
  486.     }

  487.     /** {@inheritDoc}
  488.      */
  489.     @Override
  490.     public DerivativeStructure cos() {
  491.         final DerivativeStructure result = factory.build();
  492.         factory.getCompiler().cos(data, 0, result.data, 0);
  493.         return result;
  494.     }

  495.     /** {@inheritDoc}
  496.      */
  497.     @Override
  498.     public DerivativeStructure sin() {
  499.         final DerivativeStructure result = factory.build();
  500.         factory.getCompiler().sin(data, 0, result.data, 0);
  501.         return result;
  502.     }

  503.     /** {@inheritDoc}
  504.      */
  505.     @Override
  506.     public FieldSinCos<DerivativeStructure> sinCos() {
  507.         final DerivativeStructure sin = factory.build();
  508.         final DerivativeStructure cos = factory.build();
  509.         factory.getCompiler().sinCos(data, 0, sin.data, 0, cos.data, 0);
  510.         return new FieldSinCos<>(sin, cos);
  511.     }

  512.     /** {@inheritDoc}
  513.      */
  514.     @Override
  515.     public DerivativeStructure tan() {
  516.         final DerivativeStructure result = factory.build();
  517.         factory.getCompiler().tan(data, 0, result.data, 0);
  518.         return result;
  519.     }

  520.     /** {@inheritDoc}
  521.      */
  522.     @Override
  523.     public DerivativeStructure acos() {
  524.         final DerivativeStructure result = factory.build();
  525.         factory.getCompiler().acos(data, 0, result.data, 0);
  526.         return result;
  527.     }

  528.     /** {@inheritDoc}
  529.      */
  530.     @Override
  531.     public DerivativeStructure asin() {
  532.         final DerivativeStructure result = factory.build();
  533.         factory.getCompiler().asin(data, 0, result.data, 0);
  534.         return result;
  535.     }

  536.     /** {@inheritDoc}
  537.      */
  538.     @Override
  539.     public DerivativeStructure atan() {
  540.         final DerivativeStructure result = factory.build();
  541.         factory.getCompiler().atan(data, 0, result.data, 0);
  542.         return result;
  543.     }

  544.     /** {@inheritDoc}
  545.      */
  546.     @Override
  547.     public DerivativeStructure atan2(final DerivativeStructure x)
  548.         throws MathIllegalArgumentException {
  549.         factory.checkCompatibility(x.factory);
  550.         final DerivativeStructure result = factory.build();
  551.         factory.getCompiler().atan2(data, 0, x.data, 0, result.data, 0);
  552.         return result;
  553.     }

  554.     /** Two arguments arc tangent operation.
  555.      * @param y first argument of the arc tangent
  556.      * @param x second argument of the arc tangent
  557.      * @return atan2(y, x)
  558.      * @exception MathIllegalArgumentException if number of free parameters
  559.      * or orders do not match
  560.      */
  561.     public static DerivativeStructure atan2(final DerivativeStructure y, final DerivativeStructure x)
  562.         throws MathIllegalArgumentException {
  563.         return y.atan2(x);
  564.     }

  565.     /** {@inheritDoc}
  566.      */
  567.     @Override
  568.     public DerivativeStructure cosh() {
  569.         final DerivativeStructure result = factory.build();
  570.         factory.getCompiler().cosh(data, 0, result.data, 0);
  571.         return result;
  572.     }

  573.     /** {@inheritDoc}
  574.      */
  575.     @Override
  576.     public DerivativeStructure sinh() {
  577.         final DerivativeStructure result = factory.build();
  578.         factory.getCompiler().sinh(data, 0, result.data, 0);
  579.         return result;
  580.     }

  581.     /** {@inheritDoc}
  582.      */
  583.     @Override
  584.     public FieldSinhCosh<DerivativeStructure> sinhCosh() {
  585.         final DerivativeStructure sinh = factory.build();
  586.         final DerivativeStructure cosh = factory.build();
  587.         factory.getCompiler().sinhCosh(data, 0, sinh.data, 0, cosh.data, 0);
  588.         return new FieldSinhCosh<>(sinh, cosh);
  589.     }

  590.     /** {@inheritDoc}
  591.      */
  592.     @Override
  593.     public DerivativeStructure tanh() {
  594.         final DerivativeStructure result = factory.build();
  595.         factory.getCompiler().tanh(data, 0, result.data, 0);
  596.         return result;
  597.     }

  598.     /** {@inheritDoc}
  599.      */
  600.     @Override
  601.     public DerivativeStructure acosh() {
  602.         final DerivativeStructure result = factory.build();
  603.         factory.getCompiler().acosh(data, 0, result.data, 0);
  604.         return result;
  605.     }

  606.     /** {@inheritDoc}
  607.      */
  608.     @Override
  609.     public DerivativeStructure asinh() {
  610.         final DerivativeStructure result = factory.build();
  611.         factory.getCompiler().asinh(data, 0, result.data, 0);
  612.         return result;
  613.     }

  614.     /** {@inheritDoc}
  615.      */
  616.     @Override
  617.     public DerivativeStructure atanh() {
  618.         final DerivativeStructure result = factory.build();
  619.         factory.getCompiler().atanh(data, 0, result.data, 0);
  620.         return result;
  621.     }

  622.     /** {@inheritDoc} */
  623.     @Override
  624.     public DerivativeStructure toDegrees() {
  625.         final DerivativeStructure ds = factory.build();
  626.         for (int i = 0; i < ds.data.length; ++i) {
  627.             ds.data[i] = FastMath.toDegrees(data[i]);
  628.         }
  629.         return ds;
  630.     }

  631.     /** {@inheritDoc} */
  632.     @Override
  633.     public DerivativeStructure toRadians() {
  634.         final DerivativeStructure ds = factory.build();
  635.         for (int i = 0; i < ds.data.length; ++i) {
  636.             ds.data[i] = FastMath.toRadians(data[i]);
  637.         }
  638.         return ds;
  639.     }

  640.     /** Integrate w.r.t. one independent variable.
  641.      * <p>
  642.      * Rigorously, if the derivatives of a function are known up to
  643.      * order N, the ones of its M-th integral w.r.t. a given variable
  644.      * (seen as a function itself) are actually known up to order N+M.
  645.      * However, this method still casts the output as a DerivativeStructure
  646.      * of order N. The integration constants are systematically set to zero.
  647.      * </p>
  648.      * @param varIndex Index of independent variable w.r.t. which integration is done.
  649.      * @param integrationOrder Number of times the integration operator must be applied. If non-positive, call the
  650.      *                         differentiation operator.
  651.      * @return DerivativeStructure on which integration operator has been applied a certain number of times.
  652.      * @since 2.2
  653.      */
  654.     public DerivativeStructure integrate(final int varIndex, final int integrationOrder) {

  655.         // Deal first with trivial case
  656.         if (integrationOrder > getOrder()) {
  657.             return factory.constant(0.);
  658.         } else if (integrationOrder == 0) {
  659.             return factory.build(data);
  660.         }

  661.         // Call 'inverse' (not rigorously) operation if necessary
  662.         if (integrationOrder < 0) {
  663.             return differentiate(varIndex, -integrationOrder);
  664.         }

  665.         final double[] newData = new double[data.length];
  666.         final DSCompiler dsCompiler = factory.getCompiler();
  667.         for (int i = 0; i < newData.length; i++) {
  668.             if (data[i] != 0.) {
  669.                 final int[] orders = dsCompiler.getPartialDerivativeOrders(i);
  670.                 int sum = 0;
  671.                 for (int order : orders) {
  672.                     sum += order;
  673.                 }
  674.                 if (sum + integrationOrder <= getOrder()) {
  675.                     final int saved = orders[varIndex];
  676.                     orders[varIndex] += integrationOrder;
  677.                     final int index = dsCompiler.getPartialDerivativeIndex(orders);
  678.                     orders[varIndex] = saved;
  679.                     newData[index] = data[i];
  680.                 }
  681.             }
  682.         }

  683.         return factory.build(newData);
  684.     }

  685.     /** Differentiate w.r.t. one independent variable.
  686.      * <p>
  687.      * Rigorously, if the derivatives of a function are known up to
  688.      * order N, the ones of its M-th derivative w.r.t. a given variable
  689.      * (seen as a function itself) are only known up to order N-M.
  690.      * However, this method still casts the output as a DerivativeStructure
  691.      * of order N with zeroes for the higher order terms.
  692.      * </p>
  693.      * @param varIndex Index of independent variable w.r.t. which differentiation is done.
  694.      * @param differentiationOrder Number of times the differentiation operator must be applied. If non-positive, call
  695.      *                             the integration operator instead.
  696.      * @return DerivativeStructure on which differentiation operator has been applied a certain number of times
  697.      * @since 2.2
  698.      */
  699.     public DerivativeStructure differentiate(final int varIndex, final int differentiationOrder) {

  700.         // Deal first with trivial case
  701.         if (differentiationOrder > getOrder()) {
  702.             return factory.constant(0.);
  703.         } else if (differentiationOrder == 0) {
  704.             return factory.build(data);
  705.         }

  706.         // Call 'inverse' (not rigorously) operation if necessary
  707.         if (differentiationOrder < 0) {
  708.             return integrate(varIndex, -differentiationOrder);
  709.         }

  710.         final double[] newData = new double[data.length];
  711.         final DSCompiler dsCompiler = factory.getCompiler();
  712.         for (int i = 0; i < newData.length; i++) {
  713.             if (data[i] != 0.) {
  714.                 final int[] orders = dsCompiler.getPartialDerivativeOrders(i);
  715.                 if (orders[varIndex] - differentiationOrder >= 0) {
  716.                     final int saved = orders[varIndex];
  717.                     orders[varIndex] -= differentiationOrder;
  718.                     final int index = dsCompiler.getPartialDerivativeIndex(orders);
  719.                     orders[varIndex] = saved;
  720.                     newData[index] = data[i];
  721.                 }
  722.             }
  723.         }

  724.         return factory.build(newData);
  725.     }

  726.     /** Evaluate Taylor expansion a derivative structure.
  727.      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
  728.      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
  729.      * @throws MathRuntimeException if factorials becomes too large
  730.      */
  731.     public double taylor(final double ... delta) throws MathRuntimeException {
  732.         return factory.getCompiler().taylor(data, 0, delta);
  733.     }

  734.     /** Rebase instance with respect to low level parameter functions.
  735.      * <p>
  736.      * The instance is considered to be a function of {@link #getFreeParameters()
  737.      * n free parameters} up to order {@link #getOrder() o} \(f(p_0, p_1, \ldots p_{n-1})\).
  738.      * Its {@link #getPartialDerivative(int...) partial derivatives} are therefore
  739.      * \(f, \frac{\partial f}{\partial p_0}, \frac{\partial f}{\partial p_1}, \ldots
  740.      * \frac{\partial^2 f}{\partial p_0^2}, \frac{\partial^2 f}{\partial p_0 p_1},
  741.      * \ldots \frac{\partial^o f}{\partial p_{n-1}^o}\). The free parameters
  742.      * \(p_0, p_1, \ldots p_{n-1}\) are considered to be functions of \(m\) lower
  743.      * level other parameters \(q_0, q_1, \ldots q_{m-1}\).
  744.      * </p>
  745.      * \( \begin{align}
  746.      * p_0 &amp; = p_0(q_0, q_1, \ldots q_{m-1})\\
  747.      * p_1 &amp; = p_1(q_0, q_1, \ldots q_{m-1})\\
  748.      * p_{n-1} &amp; = p_{n-1}(q_0, q_1, \ldots q_{m-1})
  749.      * \end{align}\)
  750.      * <p>
  751.      * This method compute the composition of the partial derivatives of \(f\)
  752.      * and the partial derivatives of \(p_0, p_1, \ldots p_{n-1}\), i.e. the
  753.      * {@link #getPartialDerivative(int...) partial derivatives} of the value
  754.      * returned will be
  755.      * \(f, \frac{\partial f}{\partial q_0}, \frac{\partial f}{\partial q_1}, \ldots
  756.      * \frac{\partial^2 f}{\partial q_0^2}, \frac{\partial^2 f}{\partial q_0 q_1},
  757.      * \ldots \frac{\partial^o f}{\partial q_{m-1}^o}\).
  758.      * </p>
  759.      * <p>
  760.      * The number of parameters must match {@link #getFreeParameters()} and the
  761.      * derivation orders of the instance and parameters must also match.
  762.      * </p>
  763.      * @param p base parameters with respect to which partial derivatives
  764.      * were computed in the instance
  765.      * @return derivative structure with partial derivatives computed
  766.      * with respect to the lower level parameters used in the \(p_i\)
  767.      * @since 2.2
  768.      */
  769.     public DerivativeStructure rebase(final DerivativeStructure... p) {

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

  771.         // handle special case of no variables at all
  772.         if (p.length == 0) {
  773.             return this;
  774.         }

  775.         final int pSize = p[0].getFactory().getCompiler().getSize();
  776.         final double[] pData = new double[p.length * pSize];
  777.         for (int i = 0; i < p.length; ++i) {
  778.             MathUtils.checkDimension(getOrder(), p[i].getOrder());
  779.             MathUtils.checkDimension(p[0].getFreeParameters(), p[i].getFreeParameters());
  780.             System.arraycopy(p[i].data, 0, pData, i * pSize, pSize);
  781.         }

  782.         final DerivativeStructure result = p[0].factory.build();
  783.         factory.getCompiler().rebase(data, 0, p[0].factory.getCompiler(), pData, result.data, 0);
  784.         return result;

  785.     }

  786.     /** {@inheritDoc}
  787.      * @exception MathIllegalArgumentException if number of free parameters
  788.      * or orders do not match
  789.      */
  790.     @Override
  791.     public DerivativeStructure linearCombination(final DerivativeStructure[] a, final DerivativeStructure[] b)
  792.         throws MathIllegalArgumentException {

  793.         // compute an accurate value, taking care of cancellations
  794.         final double[] aDouble = new double[a.length];
  795.         for (int i = 0; i < a.length; ++i) {
  796.             aDouble[i] = a[i].getValue();
  797.         }
  798.         final double[] bDouble = new double[b.length];
  799.         for (int i = 0; i < b.length; ++i) {
  800.             bDouble[i] = b[i].getValue();
  801.         }
  802.         final double accurateValue = MathArrays.linearCombination(aDouble, bDouble);

  803.         // compute a simple value, with all partial derivatives
  804.         DerivativeStructure simpleValue = a[0].getField().getZero();
  805.         for (int i = 0; i < a.length; ++i) {
  806.             simpleValue = simpleValue.add(a[i].multiply(b[i]));
  807.         }

  808.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  809.         final double[] all = simpleValue.getAllDerivatives();
  810.         all[0] = accurateValue;
  811.         return factory.build(all);

  812.     }

  813.     /** {@inheritDoc}
  814.      * @exception MathIllegalArgumentException if number of free parameters
  815.      * or orders do not match
  816.      */
  817.     @Override
  818.     public DerivativeStructure linearCombination(final double[] a, final DerivativeStructure[] b)
  819.         throws MathIllegalArgumentException {

  820.         // compute an accurate value, taking care of cancellations
  821.         final double[] bDouble = new double[b.length];
  822.         for (int i = 0; i < b.length; ++i) {
  823.             bDouble[i] = b[i].getValue();
  824.         }
  825.         final double accurateValue = MathArrays.linearCombination(a, bDouble);

  826.         // compute a simple value, with all partial derivatives
  827.         DerivativeStructure simpleValue = b[0].getField().getZero();
  828.         for (int i = 0; i < a.length; ++i) {
  829.             simpleValue = simpleValue.add(b[i].multiply(a[i]));
  830.         }

  831.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  832.         final double[] all = simpleValue.getAllDerivatives();
  833.         all[0] = accurateValue;
  834.         return factory.build(all);

  835.     }

  836.     /** {@inheritDoc}
  837.      * @exception MathIllegalArgumentException if number of free parameters
  838.      * or orders do not match
  839.      */
  840.     @Override
  841.     public DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1,
  842.                                                  final DerivativeStructure a2, final DerivativeStructure b2)
  843.         throws MathIllegalArgumentException {

  844.         // compute an accurate value, taking care of cancellations
  845.         final double accurateValue = MathArrays.linearCombination(a1.getValue(), b1.getValue(),
  846.                                                                   a2.getValue(), b2.getValue());

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

  849.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  850.         final double[] all = simpleValue.getAllDerivatives();
  851.         all[0] = accurateValue;
  852.         return factory.build(all);

  853.     }

  854.     /** {@inheritDoc}
  855.      * @exception MathIllegalArgumentException if number of free parameters
  856.      * or orders do not match
  857.      */
  858.     @Override
  859.     public DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1,
  860.                                                  final double a2, final DerivativeStructure b2)
  861.         throws MathIllegalArgumentException {

  862.         factory.checkCompatibility(b1.factory);
  863.         factory.checkCompatibility(b2.factory);

  864.         final DerivativeStructure ds = factory.build();
  865.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  866.                                                 a2, b2.data, 0,
  867.                                                 ds.data, 0);

  868.         return ds;

  869.     }

  870.     /** {@inheritDoc}
  871.      * @exception MathIllegalArgumentException if number of free parameters
  872.      * or orders do not match
  873.      */
  874.     @Override
  875.     public DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1,
  876.                                                  final DerivativeStructure a2, final DerivativeStructure b2,
  877.                                                  final DerivativeStructure a3, final DerivativeStructure b3)
  878.         throws MathIllegalArgumentException {

  879.         // compute an accurate value, taking care of cancellations
  880.         final double accurateValue = MathArrays.linearCombination(a1.getValue(), b1.getValue(),
  881.                                                                   a2.getValue(), b2.getValue(),
  882.                                                                   a3.getValue(), b3.getValue());

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

  885.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  886.         final double[] all = simpleValue.getAllDerivatives();
  887.         all[0] = accurateValue;
  888.         return factory.build(all);

  889.     }

  890.     /** {@inheritDoc}
  891.      * @exception MathIllegalArgumentException if number of free parameters
  892.      * or orders do not match
  893.      */
  894.     @Override
  895.     public DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1,
  896.                                                  final double a2, final DerivativeStructure b2,
  897.                                                  final double a3, final DerivativeStructure b3)
  898.         throws MathIllegalArgumentException {

  899.         factory.checkCompatibility(b1.factory);
  900.         factory.checkCompatibility(b2.factory);
  901.         factory.checkCompatibility(b3.factory);

  902.         final DerivativeStructure ds = factory.build();
  903.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  904.                                                 a2, b2.data, 0,
  905.                                                 a3, b3.data, 0,
  906.                                                 ds.data, 0);

  907.         return ds;

  908.     }

  909.     /** {@inheritDoc}
  910.      * @exception MathIllegalArgumentException if number of free parameters
  911.      * or orders do not match
  912.      */
  913.     @Override
  914.     public DerivativeStructure linearCombination(final DerivativeStructure a1, final DerivativeStructure b1,
  915.                                                  final DerivativeStructure a2, final DerivativeStructure b2,
  916.                                                  final DerivativeStructure a3, final DerivativeStructure b3,
  917.                                                  final DerivativeStructure a4, final DerivativeStructure b4)
  918.         throws MathIllegalArgumentException {

  919.         // compute an accurate value, taking care of cancellations
  920.         final double accurateValue = MathArrays.linearCombination(a1.getValue(), b1.getValue(),
  921.                                                                   a2.getValue(), b2.getValue(),
  922.                                                                   a3.getValue(), b3.getValue(),
  923.                                                                   a4.getValue(), b4.getValue());

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

  926.         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
  927.         final double[] all = simpleValue.getAllDerivatives();
  928.         all[0] = accurateValue;
  929.         return factory.build(all);

  930.     }

  931.     /** {@inheritDoc}
  932.      * @exception MathIllegalArgumentException if number of free parameters
  933.      * or orders do not match
  934.      */
  935.     @Override
  936.     public DerivativeStructure linearCombination(final double a1, final DerivativeStructure b1,
  937.                                                  final double a2, final DerivativeStructure b2,
  938.                                                  final double a3, final DerivativeStructure b3,
  939.                                                  final double a4, final DerivativeStructure b4)
  940.         throws MathIllegalArgumentException {

  941.         factory.checkCompatibility(b1.factory);
  942.         factory.checkCompatibility(b2.factory);
  943.         factory.checkCompatibility(b3.factory);
  944.         factory.checkCompatibility(b4.factory);

  945.         final DerivativeStructure ds = factory.build();
  946.         factory.getCompiler().linearCombination(a1, b1.data, 0,
  947.                                                 a2, b2.data, 0,
  948.                                                 a3, b3.data, 0,
  949.                                                 a4, b4.data, 0,
  950.                                                 ds.data, 0);

  951.         return ds;

  952.     }

  953.     /** {@inheritDoc}
  954.      */
  955.     @Override
  956.     public DerivativeStructure getPi() {
  957.         return factory.getDerivativeField().getPi();
  958.     }

  959.     /**
  960.      * Test for the equality of two derivative structures.
  961.      * <p>
  962.      * Derivative structures are considered equal if they have the same number
  963.      * of free parameters, the same derivation order, and the same derivatives.
  964.      * </p>
  965.      * @param other Object to test for equality to this
  966.      * @return true if two derivative structures are equal
  967.      */
  968.     @Override
  969.     public boolean equals(Object other) {

  970.         if (this == other) {
  971.             return true;
  972.         }

  973.         if (other instanceof DerivativeStructure) {
  974.             final DerivativeStructure rhs = (DerivativeStructure)other;
  975.             return (getFreeParameters() == rhs.getFreeParameters()) &&
  976.                    (getOrder() == rhs.getOrder()) &&
  977.                    MathArrays.equals(data, rhs.data);
  978.         }

  979.         return false;

  980.     }

  981.     /**
  982.      * Get a hashCode for the derivative structure.
  983.      * @return a hash code value for this object
  984.      */
  985.     @Override
  986.     public int hashCode() {
  987.         return 227 + 229 * getFreeParameters() + 233 * getOrder() + 239 * MathUtils.hash(data);
  988.     }

  989. }