    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.math3.analysis.differentiation;
    018
    019    import java.io.Serializable;
    020
    021    import org.apache.commons.math3.Field;
    022    import org.apache.commons.math3.FieldElement;
    023    import org.apache.commons.math3.exception.DimensionMismatchException;
    024    import org.apache.commons.math3.exception.NumberIsTooLargeException;
    025    import org.apache.commons.math3.util.FastMath;
    026
    027    /** Class representing both the value and the differentials of a function.
    028     * <p>This class is the workhorse of the differentiation package.</p>
    029     * <p>This class is an implementation of the extension to Rall's
    030     * numbers described in Dan Kalman's paper <a
    031     * href="http://www.math.american.edu/People/kalman/pdffiles/mmgautodiff.pdf">Doubly
    032     * Recursive Multivariate Automatic Differentiation</a>, Mathematics Magazine, vol. 75,
    033     * no. 3, June 2002.</p>. Rall's numbers are an extension to the real numbers used
    034     * throughout mathematical expressions; they hold the derivative together with the
    035     * value of a function. Dan Kalman's derivative structures hold all partial derivatives
    036     * up to any specified order, with respect to any number of free parameters. Rall's
    037     * numbers therefore can be seen as derivative structures for order one derivative and
    038     * one free parameter, and real numbers can be seen as derivative structures with zero
    039     * order derivative and no free parameters.</p>
    040     * <p>{@link DerivativeStructure} instances can be used directly thanks to
    041     * the arithmetic operators to the mathematical functions provided as static
    042     * methods by this class (+, -, *, /, %, sin, cos ...).</p>
    043     * <p>Implementing complex expressions by hand using these classes is
    044     * a tedious and error-prone task but has the advantage of having no limitation
    045     * on the derivation order despite no requiring users to compute the derivatives by
    046     * themselves. Implementing complex expression can also be done by developing computation
    047     * code using standard primitive double values and to use {@link
    048     * UnivariateFunctionDifferentiator differentiators} to create the {@link
    049     * DerivativeStructure}-based instances. This method is simpler but may be limited in
    050     * the accuracy and derivation orders and may be computationally intensive (this is
    051     * typically the case for {@link FiniteDifferencesDifferentiator finite differences
    052     * differentiator}.</p>
    053     * <p>Instances of this class are guaranteed to be immutable.</p>
    054     * @see DSCompiler
    055     * @version $Id: DerivativeStructure.java 1416643 2012-12-03 19:37:14Z tn $
    056     * @since 3.1
    057     */
    058    public class DerivativeStructure implements FieldElement<DerivativeStructure>, Serializable {
    059
    060        /** Serializable UID. */
    061        private static final long serialVersionUID = 20120730L;
    062
    063        /** Compiler for the current dimensions. */
    064        private transient DSCompiler compiler;
    065
    066        /** Combined array holding all values. */
    067        private final double[] data;
    068
    069        /** Build an instance with all values and derivatives set to 0.
    070         * @param compiler compiler to use for computation
    071         */
    072        private DerivativeStructure(final DSCompiler compiler) {
    073            this.compiler = compiler;
    074            this.data     = new double[compiler.getSize()];
    075        }
    076
    077        /** Build an instance with all values and derivatives set to 0.
    078         * @param parameters number of free parameters
    079         * @param order derivation order
    080         */
    081        public DerivativeStructure(final int parameters, final int order) {
    082            this(DSCompiler.getCompiler(parameters, order));
    083        }
    084
    085        /** Build an instance representing a constant value.
    086         * @param parameters number of free parameters
    087         * @param order derivation order
    088         * @param value value of the constant
    089         * @see #DerivativeStructure(int, int, int, double)
    090         */
    091        public DerivativeStructure(final int parameters, final int order, final double value) {
    092            this(parameters, order);
    093            this.data[0] = value;
    094        }
    095
    096        /** Build an instance representing a variable.
    097         * <p>Instances built using this constructor are considered
    098         * to be the free variables with respect to which differentials
    099         * are computed. As such, their differential with respect to
    100         * themselves is +1.</p>
    101         * @param parameters number of free parameters
    102         * @param order derivation order
    103         * @param index index of the variable (from 0 to {@code parameters - 1})
    104         * @param value value of the variable
    105         * @exception NumberIsTooLargeException if {@code index >= parameters}.
    106         * @see #DerivativeStructure(int, int, double)
    107         */
    108        public DerivativeStructure(final int parameters, final int order,
    109                                   final int index, final double value)
    110            throws NumberIsTooLargeException {
    111            this(parameters, order, value);
    112
    113            if (index >= parameters) {
    114                throw new NumberIsTooLargeException(index, parameters, false);
    115            }
    116
    117            if (order > 0) {
    118                // the derivative of the variable with respect to itself is 1.
    119                data[DSCompiler.getCompiler(index, order).getSize()] = 1.0;
    120            }
    121
    122        }
    123
    124        /** Linear combination constructor.
    125         * The derivative structure built will be a1 * ds1 + a2 * ds2
    126         * @param a1 first scale factor
    127         * @param ds1 first base (unscaled) derivative structure
    128         * @param a2 second scale factor
    129         * @param ds2 second base (unscaled) derivative structure
    130         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    131         */
    132        public DerivativeStructure(final double a1, final DerivativeStructure ds1,
    133                                   final double a2, final DerivativeStructure ds2)
    134            throws DimensionMismatchException {
    135            this(ds1.compiler);
    136            compiler.checkCompatibility(ds2.compiler);
    137            compiler.linearCombination(a1, ds1.data, 0, a2, ds2.data, 0, data, 0);
    138        }
    139
    140        /** Linear combination constructor.
    141         * The derivative structure built will be a1 * ds1 + a2 * ds2 + a3 * ds3
    142         * @param a1 first scale factor
    143         * @param ds1 first base (unscaled) derivative structure
    144         * @param a2 second scale factor
    145         * @param ds2 second base (unscaled) derivative structure
    146         * @param a3 third scale factor
    147         * @param ds3 third base (unscaled) derivative structure
    148         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    149         */
    150        public DerivativeStructure(final double a1, final DerivativeStructure ds1,
    151                                   final double a2, final DerivativeStructure ds2,
    152                                   final double a3, final DerivativeStructure ds3)
    153            throws DimensionMismatchException {
    154            this(ds1.compiler);
    155            compiler.checkCompatibility(ds2.compiler);
    156            compiler.checkCompatibility(ds3.compiler);
    157            compiler.linearCombination(a1, ds1.data, 0, a2, ds2.data, 0, a3, ds3.data, 0, data, 0);
    158        }
    159
    160        /** Linear combination constructor.
    161         * The derivative structure built will be a1 * ds1 + a2 * ds2 + a3 * ds3 + a4 * ds4
    162         * @param a1 first scale factor
    163         * @param ds1 first base (unscaled) derivative structure
    164         * @param a2 second scale factor
    165         * @param ds2 second base (unscaled) derivative structure
    166         * @param a3 third scale factor
    167         * @param ds3 third base (unscaled) derivative structure
    168         * @param a4 fourth scale factor
    169         * @param ds4 fourth base (unscaled) derivative structure
    170         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    171         */
    172        public DerivativeStructure(final double a1, final DerivativeStructure ds1,
    173                                   final double a2, final DerivativeStructure ds2,
    174                                   final double a3, final DerivativeStructure ds3,
    175                                   final double a4, final DerivativeStructure ds4)
    176            throws DimensionMismatchException {
    177            this(ds1.compiler);
    178            compiler.checkCompatibility(ds2.compiler);
    179            compiler.checkCompatibility(ds3.compiler);
    180            compiler.checkCompatibility(ds4.compiler);
    181            compiler.linearCombination(a1, ds1.data, 0, a2, ds2.data, 0,
    182                                       a3, ds3.data, 0, a4, ds4.data, 0,
    183                                       data, 0);
    184        }
    185
    186        /** Build an instance from all its derivatives.
    187         * @param parameters number of free parameters
    188         * @param order derivation order
    189         * @param derivatives derivatives sorted according to
    190         * {@link DSCompiler#getPartialDerivativeIndex(int...)}
    191         * @exception DimensionMismatchException if derivatives array does not match the
    192         * {@link DSCompiler#getSize() size} expected by the compiler
    193         * @see #getAllDerivatives()
    194         */
    195        public DerivativeStructure(final int parameters, final int order, final double ... derivatives)
    196            throws DimensionMismatchException {
    197            this(parameters, order);
    198            if (derivatives.length != data.length) {
    199                throw new DimensionMismatchException(derivatives.length, data.length);
    200            }
    201            System.arraycopy(derivatives, 0, data, 0, data.length);
    202        }
    203
    204        /** Copy constructor.
    205         * @param ds instance to copy
    206         */
    207        private DerivativeStructure(final DerivativeStructure ds) {
    208            this.compiler = ds.compiler;
    209            this.data     = ds.data.clone();
    210        }
    211
    212        /** Get the number of free parameters.
    213         * @return number of free parameters
    214         */
    215        public int getFreeParameters() {
    216            return compiler.getFreeParameters();
    217        }
    218
    219        /** Get the derivation order.
    220         * @return derivation order
    221         */
    222        public int getOrder() {
    223            return compiler.getOrder();
    224        }
    225
    226        /** Get the value part of the derivative structure.
    227         * @return value part of the derivative structure
    228         * @see #getPartialDerivative(int...)
    229         */
    230        public double getValue() {
    231            return data[0];
    232        }
    233
    234        /** Get a partial derivative.
    235         * @param orders derivation orders with respect to each variable (if all orders are 0,
    236         * the value is returned)
    237         * @return partial derivative
    238         * @see #getValue()
    239         * @exception DimensionMismatchException if the numbers of variables does not
    240         * match the instance
    241         * @exception NumberIsTooLargeException if sum of derivation orders is larger
    242         * than the instance limits
    243         */
    244        public double getPartialDerivative(final int ... orders)
    245            throws DimensionMismatchException, NumberIsTooLargeException {
    246            return data[compiler.getPartialDerivativeIndex(orders)];
    247        }
    248
    249        /** Get all partial derivatives.
    250         * @return a fresh copy of partial derivatives, in an array sorted according to
    251         * {@link DSCompiler#getPartialDerivativeIndex(int...)}
    252         */
    253        public double[] getAllDerivatives() {
    254            return data.clone();
    255        }
    256
    257        /** '+' operator.
    258         * @param a right hand side parameter of the operator
    259         * @return this+a
    260         */
    261        public DerivativeStructure add(final double a) {
    262            final DerivativeStructure ds = new DerivativeStructure(this);
    263            ds.data[0] += a;
    264            return ds;
    265        }
    266
    267        /** '+' operator.
    268         * @param a right hand side parameter of the operator
    269         * @return this+a
    270         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    271         */
    272        public DerivativeStructure add(final DerivativeStructure a)
    273            throws DimensionMismatchException {
    274            compiler.checkCompatibility(a.compiler);
    275            final DerivativeStructure ds = new DerivativeStructure(this);
    276            compiler.add(data, 0, a.data, 0, ds.data, 0);
    277            return ds;
    278        }
    279
    280        /** '-' operator.
    281         * @param a right hand side parameter of the operator
    282         * @return this-a
    283         */
    284        public DerivativeStructure subtract(final double a) {
    285            return add(-a);
    286        }
    287
    288        /** '-' operator.
    289         * @param a right hand side parameter of the operator
    290         * @return this-a
    291         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    292         */
    293        public DerivativeStructure subtract(final DerivativeStructure a)
    294            throws DimensionMismatchException {
    295            compiler.checkCompatibility(a.compiler);
    296            final DerivativeStructure ds = new DerivativeStructure(this);
    297            compiler.subtract(data, 0, a.data, 0, ds.data, 0);
    298            return ds;
    299        }
    300
    301        /** {@inheritDoc} */
    302        public DerivativeStructure multiply(final int n) {
    303            return multiply((double) n);
    304        }
    305
    306        /** '&times;' operator.
    307         * @param a right hand side parameter of the operator
    308         * @return this&times;a
    309         */
    310        public DerivativeStructure multiply(final double a) {
    311            final DerivativeStructure ds = new DerivativeStructure(this);
    312            for (int i = 0; i < ds.data.length; ++i) {
    313                ds.data[i] *= a;
    314            }
    315            return ds;
    316        }
    317
    318        /** '&times;' operator.
    319         * @param a right hand side parameter of the operator
    320         * @return this&times;a
    321         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    322         */
    323        public DerivativeStructure multiply(final DerivativeStructure a)
    324            throws DimensionMismatchException {
    325            compiler.checkCompatibility(a.compiler);
    326            final DerivativeStructure result = new DerivativeStructure(compiler);
    327            compiler.multiply(data, 0, a.data, 0, result.data, 0);
    328            return result;
    329        }
    330
    331        /** '&divides;' operator.
    332         * @param a right hand side parameter of the operator
    333         * @return this&divides;a
    334         */
    335        public DerivativeStructure divide(final double a) {
    336            final DerivativeStructure ds = new DerivativeStructure(this);
    337            for (int i = 0; i < ds.data.length; ++i) {
    338                ds.data[i] /= a;
    339            }
    340            return ds;
    341        }
    342
    343        /** '&divides;' operator.
    344         * @param a right hand side parameter of the operator
    345         * @return this&divides;a
    346         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    347         */
    348        public DerivativeStructure divide(final DerivativeStructure a)
    349            throws DimensionMismatchException {
    350            compiler.checkCompatibility(a.compiler);
    351            final DerivativeStructure result = new DerivativeStructure(compiler);
    352            compiler.divide(data, 0, a.data, 0, result.data, 0);
    353            return result;
    354        }
    355
    356        /** '%' operator.
    357         * @param a right hand side parameter of the operator
    358         * @return this%a
    359         */
    360        public DerivativeStructure remainder(final double a) {
    361            final DerivativeStructure ds = new DerivativeStructure(this);
    362            ds.data[0] = ds.data[0] % a;
    363            return ds;
    364        }
    365
    366        /** '%' operator.
    367         * @param a right hand side parameter of the operator
    368         * @return this%a
    369         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    370         */
    371        public DerivativeStructure remainder(final DerivativeStructure a)
    372            throws DimensionMismatchException {
    373            compiler.checkCompatibility(a.compiler);
    374            final DerivativeStructure result = new DerivativeStructure(compiler);
    375            compiler.remainder(data, 0, a.data, 0, result.data, 0);
    376            return result;
    377        }
    378
    379        /** unary '-' operator.
    380         * @return -this
    381         */
    382        public DerivativeStructure negate() {
    383            final DerivativeStructure ds = new DerivativeStructure(compiler);
    384            for (int i = 0; i < ds.data.length; ++i) {
    385                ds.data[i] = -data[i];
    386            }
    387            return ds;
    388        }
    389
    390        /** absolute value.
    391         * @return abs(this)
    392         */
    393        public DerivativeStructure abs() {
    394            if (Double.doubleToLongBits(data[0]) < 0) {
    395                // we use the bits representation to also handle -0.0
    396                return negate();
    397            } else {
    398                return this;
    399            }
    400        }
    401
    402        /** Get the smallest whole number larger than instance.
    403         * @return ceil(this)
    404         */
    405        public DerivativeStructure ceil() {
    406            return new DerivativeStructure(compiler.getFreeParameters(),
    407                                           compiler.getOrder(),
    408                                           FastMath.ceil(data[0]));
    409        }
    410
    411        /** Get the largest whole number smaller than instance.
    412         * @return floor(this)
    413         */
    414        public DerivativeStructure floor() {
    415            return new DerivativeStructure(compiler.getFreeParameters(),
    416                                           compiler.getOrder(),
    417                                           FastMath.floor(data[0]));
    418        }
    419
    420        /** Get the whole number that is the nearest to the instance, or the even one if x is exactly half way between two integers.
    421         * @return a double number r such that r is an integer r - 0.5 <= this <= r + 0.5
    422         */
    423        public DerivativeStructure rint() {
    424            return new DerivativeStructure(compiler.getFreeParameters(),
    425                                           compiler.getOrder(),
    426                                           FastMath.rint(data[0]));
    427        }
    428
    429        /** Get the closest long to instance value.
    430         * @return closest long to {@link #getValue()}
    431         */
    432        public long round() {
    433            return FastMath.round(data[0]);
    434        }
    435
    436        /** Compute the signum of the instance.
    437         * The signum is -1 for negative numbers, +1 for positive numbers and 0 otherwise
    438         * @return -1.0, -0.0, +0.0, +1.0 or NaN depending on sign of a
    439         */
    440        public DerivativeStructure signum() {
    441            return new DerivativeStructure(compiler.getFreeParameters(),
    442                                           compiler.getOrder(),
    443                                           FastMath.signum(data[0]));
    444        }
    445
    446        /**
    447         * Returns the instance with the sign of the argument.
    448         * A NaN {@code sign} argument is treated as positive.
    449         *
    450         * @param sign the sign for the returned value
    451         * @return the instance with the same sign as the {@code sign} argument
    452         */
    453        public DerivativeStructure copySign(final double sign){
    454            long m = Double.doubleToLongBits(data[0]);
    455            long s = Double.doubleToLongBits(sign);
    456            if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
    457                return this;
    458            }
    459            return negate(); // flip sign
    460        }
    461
    462        /**
    463         * Return the exponent of the instance value, removing the bias.
    464         * <p>
    465         * For double numbers of the form 2<sup>x</sup>, the unbiased
    466         * exponent is exactly x.
    467         * </p>
    468         * @return exponent for instance in IEEE754 representation, without bias
    469         */
    470        public int getExponent() {
    471            return FastMath.getExponent(data[0]);
    472        }
    473
    474        /**
    475         * Multiply the instance by a power of 2.
    476         * @param n power of 2
    477         * @return this &times; 2<sup>n</sup>
    478         */
    479        public DerivativeStructure scalb(final int n) {
    480            final DerivativeStructure ds = new DerivativeStructure(compiler);
    481            for (int i = 0; i < ds.data.length; ++i) {
    482                ds.data[i] = FastMath.scalb(data[i], n);
    483            }
    484            return ds;
    485        }
    486
    487        /**
    488         * Returns the hypotenuse of a triangle with sides {@code x} and {@code y}
    489         * - sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)<br/>
    490         * avoiding intermediate overflow or underflow.
    491         *
    492         * <ul>
    493         * <li> If either argument is infinite, then the result is positive infinity.</li>
    494         * <li> else, if either argument is NaN then the result is NaN.</li>
    495         * </ul>
    496         *
    497         * @param x a value
    498         * @param y a value
    499         * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
    500         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    501         */
    502        public static DerivativeStructure hypot(final DerivativeStructure x, final DerivativeStructure y)
    503            throws DimensionMismatchException {
    504
    505            x.compiler.checkCompatibility(y.compiler);
    506
    507            if (Double.isInfinite(x.data[0]) || Double.isInfinite(y.data[0])) {
    508                return new DerivativeStructure(x.compiler.getFreeParameters(),
    509                                               x.compiler.getFreeParameters(),
    510                                               Double.POSITIVE_INFINITY);
    511            } else if (Double.isNaN(x.data[0]) || Double.isNaN(y.data[0])) {
    512                return new DerivativeStructure(x.compiler.getFreeParameters(),
    513                                               x.compiler.getFreeParameters(),
    514                                               Double.NaN);
    515            } else {
    516
    517                final int expX = x.getExponent();
    518                final int expY = y.getExponent();
    519                if (expX > expY + 27) {
    520                    // y is neglectible with respect to x
    521                    return x.abs();
    522                } else if (expY > expX + 27) {
    523                    // x is neglectible with respect to y
    524                    return y.abs();
    525                } else {
    526
    527                    // find an intermediate scale to avoid both overflow and underflow
    528                    final int middleExp = (expX + expY) / 2;
    529
    530                    // scale parameters without losing precision
    531                    final DerivativeStructure scaledX = x.scalb(-middleExp);
    532                    final DerivativeStructure scaledY = y.scalb(-middleExp);
    533
    534                    // compute scaled hypotenuse
    535                    final DerivativeStructure scaledH =
    536                            scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
    537
    538                    // remove scaling
    539                    return scaledH.scalb(middleExp);
    540
    541                }
    542
    543            }
    544        }
    545
    546        /** Compute composition of the instance by a univariate function.
    547         * @param f array of value and derivatives of the function at
    548         * the current point (i.e. [f({@link #getValue()}),
    549         * f'({@link #getValue()}), f''({@link #getValue()})...]).
    550         * @return f(this)
    551         * @exception DimensionMismatchException if the number of derivatives
    552         * in the array is not equal to {@link #getOrder() order} + 1
    553         */
    554        public DerivativeStructure compose(final double ... f) {
    555            if (f.length != getOrder() + 1) {
    556                throw new DimensionMismatchException(f.length, getOrder() + 1);
    557            }
    558            final DerivativeStructure result = new DerivativeStructure(compiler);
    559            compiler.compose(data, 0, f, result.data, 0);
    560            return result;
    561        }
    562
    563        /** {@inheritDoc} */
    564        public DerivativeStructure reciprocal() {
    565            final DerivativeStructure result = new DerivativeStructure(compiler);
    566            compiler.pow(data, 0, -1, result.data, 0);
    567            return result;
    568        }
    569
    570        /** Square root.
    571         * @return square root of the instance
    572         */
    573        public DerivativeStructure sqrt() {
    574            return rootN(2);
    575        }
    576
    577        /** Cubic root.
    578         * @return cubic root of the instance
    579         */
    580        public DerivativeStructure cbrt() {
    581            return rootN(3);
    582        }
    583
    584        /** N<sup>th</sup> root.
    585         * @param n order of the root
    586         * @return n<sup>th</sup> root of the instance
    587         */
    588        public DerivativeStructure rootN(final int n) {
    589            final DerivativeStructure result = new DerivativeStructure(compiler);
    590            compiler.rootN(data, 0, n, result.data, 0);
    591            return result;
    592        }
    593
    594        /** {@inheritDoc} */
    595        public Field<DerivativeStructure> getField() {
    596            return new Field<DerivativeStructure>() {
    597
    598                /** {@inheritDoc} */
    599                public DerivativeStructure getZero() {
    600                    return new DerivativeStructure(compiler.getFreeParameters(), compiler.getOrder(), 0.0);
    601                }
    602
    603                /** {@inheritDoc} */
    604                public DerivativeStructure getOne() {
    605                    return new DerivativeStructure(compiler.getFreeParameters(), compiler.getOrder(), 1.0);
    606                }
    607
    608                /** {@inheritDoc} */
    609                public Class<? extends FieldElement<DerivativeStructure>> getRuntimeClass() {
    610                    return DerivativeStructure.class;
    611                }
    612
    613            };
    614        }
    615
    616        /** Power operation.
    617         * @param p power to apply
    618         * @return this<sup>p</sup>
    619         */
    620        public DerivativeStructure pow(final double p) {
    621            final DerivativeStructure result = new DerivativeStructure(compiler);
    622            compiler.pow(data, 0, p, result.data, 0);
    623            return result;
    624        }
    625
    626        /** Integer power operation.
    627         * @param n power to apply
    628         * @return this<sup>n</sup>
    629         */
    630        public DerivativeStructure pow(final int n) {
    631            final DerivativeStructure result = new DerivativeStructure(compiler);
    632            compiler.pow(data, 0, n, result.data, 0);
    633            return result;
    634        }
    635
    636        /** Power operation.
    637         * @param e exponent
    638         * @return this<sup>e</sup>
    639         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    640         */
    641        public DerivativeStructure pow(final DerivativeStructure e)
    642            throws DimensionMismatchException {
    643            compiler.checkCompatibility(e.compiler);
    644            final DerivativeStructure result = new DerivativeStructure(compiler);
    645            compiler.pow(data, 0, e.data, 0, result.data, 0);
    646            return result;
    647        }
    648
    649        /** Exponential.
    650         * @return exponential of the instance
    651         */
    652        public DerivativeStructure exp() {
    653            final DerivativeStructure result = new DerivativeStructure(compiler);
    654            compiler.exp(data, 0, result.data, 0);
    655            return result;
    656        }
    657
    658        /** Exponential minus 1.
    659         * @return exponential minus one of the instance
    660         */
    661        public DerivativeStructure expm1() {
    662            final DerivativeStructure result = new DerivativeStructure(compiler);
    663            compiler.expm1(data, 0, result.data, 0);
    664            return result;
    665        }
    666
    667        /** Natural logarithm.
    668         * @return logarithm of the instance
    669         */
    670        public DerivativeStructure log() {
    671            final DerivativeStructure result = new DerivativeStructure(compiler);
    672            compiler.log(data, 0, result.data, 0);
    673            return result;
    674        }
    675
    676        /** Shifted natural logarithm.
    677         * @return logarithm of one plus the instance
    678         */
    679        public DerivativeStructure log1p() {
    680            final DerivativeStructure result = new DerivativeStructure(compiler);
    681            compiler.log1p(data, 0, result.data, 0);
    682            return result;
    683        }
    684
    685        /** Base 10 logarithm.
    686         * @return base 10 logarithm of the instance
    687         */
    688        public DerivativeStructure log10() {
    689            final DerivativeStructure result = new DerivativeStructure(compiler);
    690            compiler.log10(data, 0, result.data, 0);
    691            return result;
    692        }
    693
    694        /** Cosine operation.
    695         * @return cos(this)
    696         */
    697        public DerivativeStructure cos() {
    698            final DerivativeStructure result = new DerivativeStructure(compiler);
    699            compiler.cos(data, 0, result.data, 0);
    700            return result;
    701        }
    702
    703        /** Sine operation.
    704         * @return sin(this)
    705         */
    706        public DerivativeStructure sin() {
    707            final DerivativeStructure result = new DerivativeStructure(compiler);
    708            compiler.sin(data, 0, result.data, 0);
    709            return result;
    710        }
    711
    712        /** Tangent operation.
    713         * @return tan(this)
    714         */
    715        public DerivativeStructure tan() {
    716            final DerivativeStructure result = new DerivativeStructure(compiler);
    717            compiler.tan(data, 0, result.data, 0);
    718            return result;
    719        }
    720
    721        /** Arc cosine operation.
    722         * @return acos(this)
    723         */
    724        public DerivativeStructure acos() {
    725            final DerivativeStructure result = new DerivativeStructure(compiler);
    726            compiler.acos(data, 0, result.data, 0);
    727            return result;
    728        }
    729
    730        /** Arc sine operation.
    731         * @return asin(this)
    732         */
    733        public DerivativeStructure asin() {
    734            final DerivativeStructure result = new DerivativeStructure(compiler);
    735            compiler.asin(data, 0, result.data, 0);
    736            return result;
    737        }
    738
    739        /** Arc tangent operation.
    740         * @return atan(this)
    741         */
    742        public DerivativeStructure atan() {
    743            final DerivativeStructure result = new DerivativeStructure(compiler);
    744            compiler.atan(data, 0, result.data, 0);
    745            return result;
    746        }
    747
    748        /** Two arguments arc tangent operation.
    749         * @param y first argument of the arc tangent
    750         * @param x second argument of the arc tangent
    751         * @return atan2(y, x)
    752         * @exception DimensionMismatchException if number of free parameters or orders are inconsistent
    753         */
    754        public static DerivativeStructure atan2(final DerivativeStructure y, final DerivativeStructure x)
    755            throws DimensionMismatchException {
    756            y.compiler.checkCompatibility(x.compiler);
    757            final DerivativeStructure result = new DerivativeStructure(y.compiler);
    758            y.compiler.atan2(y.data, 0, x.data, 0, result.data, 0);
    759            return result;
    760        }
    761
    762        /** Hyperbolic cosine operation.
    763         * @return cosh(this)
    764         */
    765        public DerivativeStructure cosh() {
    766            final DerivativeStructure result = new DerivativeStructure(compiler);
    767            compiler.cosh(data, 0, result.data, 0);
    768            return result;
    769        }
    770
    771        /** Hyperbolic sine operation.
    772         * @return sinh(this)
    773         */
    774        public DerivativeStructure sinh() {
    775            final DerivativeStructure result = new DerivativeStructure(compiler);
    776            compiler.sinh(data, 0, result.data, 0);
    777            return result;
    778        }
    779
    780        /** Hyperbolic tangent operation.
    781         * @return tanh(this)
    782         */
    783        public DerivativeStructure tanh() {
    784            final DerivativeStructure result = new DerivativeStructure(compiler);
    785            compiler.tanh(data, 0, result.data, 0);
    786            return result;
    787        }
    788
    789        /** Inverse hyperbolic cosine operation.
    790         * @return acosh(this)
    791         */
    792        public DerivativeStructure acosh() {
    793            final DerivativeStructure result = new DerivativeStructure(compiler);
    794            compiler.acosh(data, 0, result.data, 0);
    795            return result;
    796        }
    797
    798        /** Inverse hyperbolic sine operation.
    799         * @return asin(this)
    800         */
    801        public DerivativeStructure asinh() {
    802            final DerivativeStructure result = new DerivativeStructure(compiler);
    803            compiler.asinh(data, 0, result.data, 0);
    804            return result;
    805        }
    806
    807        /** Inverse hyperbolic  tangent operation.
    808         * @return atanh(this)
    809         */
    810        public DerivativeStructure atanh() {
    811            final DerivativeStructure result = new DerivativeStructure(compiler);
    812            compiler.atanh(data, 0, result.data, 0);
    813            return result;
    814        }
    815
    816        /** Convert radians to degrees, with error of less than 0.5 ULP
    817         *  @return instance converted into degrees
    818         */
    819        public DerivativeStructure toDegrees() {
    820            final DerivativeStructure ds = new DerivativeStructure(compiler);
    821            for (int i = 0; i < ds.data.length; ++i) {
    822                ds.data[i] = FastMath.toDegrees(data[i]);
    823            }
    824            return ds;
    825        }
    826
    827        /** Convert degrees to radians, with error of less than 0.5 ULP
    828         *  @return instance converted into radians
    829         */
    830        public DerivativeStructure toRadians() {
    831            final DerivativeStructure ds = new DerivativeStructure(compiler);
    832            for (int i = 0; i < ds.data.length; ++i) {
    833                ds.data[i] = FastMath.toRadians(data[i]);
    834            }
    835            return ds;
    836        }
    837
    838        /** Evaluate Taylor expansion a derivative structure.
    839         * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
    840         * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
    841         */
    842        public double taylor(final double ... delta) {
    843            return compiler.taylor(data, 0, delta);
    844        }
    845
    846        /**
    847         * Replace the instance with a data transfer object for serialization.
    848         * @return data transfer object that will be serialized
    849         */
    850        private Object writeReplace() {
    851            return new DataTransferObject(compiler.getFreeParameters(), compiler.getOrder(), data);
    852        }
    853
    854        /** Internal class used only for serialization. */
    855        private static class DataTransferObject implements Serializable {
    856
    857            /** Serializable UID. */
    858            private static final long serialVersionUID = 20120730L;
    859
    860            /** Number of variables.
    861             * @serial
    862             */
    863            private final int variables;
    864
    865            /** Derivation order.
    866             * @serial
    867             */
    868            private final int order;
    869
    870            /** Partial derivatives.
    871             * @serial
    872             */
    873            private final double[] data;
    874
    875            /** Simple constructor.
    876             * @param variables number of variables
    877             * @param order derivation order
    878             * @param data partial derivatives
    879             */
    880            public DataTransferObject(final int variables, final int order, final double[] data) {
    881                this.variables = variables;
    882                this.order     = order;
    883                this.data      = data;
    884            }
    885
    886            /** Replace the deserialized data transfer object with a {@link DerivativeStructure}.
    887             * @return replacement {@link DerivativeStructure}
    888             */
    889            private Object readResolve() {
    890                return new DerivativeStructure(variables, order, data);
    891            }
    892
    893        }
    894
    895    }