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    }