View Javadoc
1   /*
2    * Licensed to the Hipparchus project under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.hipparchus.analysis.differentiation;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.exception.LocalizedCoreFormats;
22  import org.hipparchus.exception.MathIllegalArgumentException;
23  import org.hipparchus.util.FastMath;
24  import org.hipparchus.util.FieldSinCos;
25  import org.hipparchus.util.FieldSinhCosh;
26  import org.hipparchus.util.MathArrays;
27  import org.hipparchus.util.MathUtils;
28  
29  /** Class representing both the value and the differentials of a function.
30   * <p>This class is a stripped-down version of {@link FieldDerivativeStructure}
31   * with only one {@link FieldDerivativeStructure#getFreeParameters() free parameter}
32   * and {@link FieldDerivativeStructure#getOrder() derivation order} limited to two.
33   * It should have less overhead than {@link FieldDerivativeStructure} in its domain.</p>
34   * <p>This class is an implementation of Rall's numbers. Rall's numbers are an
35   * extension to the real numbers used throughout mathematical expressions; they hold
36   * the derivative together with the value of a function.</p>
37   * <p>{@link FieldUnivariateDerivative2} instances can be used directly thanks to
38   * the arithmetic operators to the mathematical functions provided as
39   * methods by this class (+, -, *, /, %, sin, cos ...).</p>
40   * <p>Implementing complex expressions by hand using these classes is
41   * a tedious and error-prone task but has the advantage of having no limitation
42   * on the derivation order despite not requiring users to compute the derivatives by
43   * themselves.</p>
44   * <p>Instances of this class are guaranteed to be immutable.</p>
45   * @param <T> the type of the function parameters and value
46   * @see DerivativeStructure
47   * @see UnivariateDerivative1
48   * @see UnivariateDerivative2
49   * @see Gradient
50   * @see FieldDerivativeStructure
51   * @see FieldUnivariateDerivative1
52   * @see FieldGradient
53   * @since 1.7
54   */
55  public class FieldUnivariateDerivative2<T extends CalculusFieldElement<T>>
56      extends FieldUnivariateDerivative<T, FieldUnivariateDerivative2<T>> {
57  
58      /** Value of the function. */
59      private final T f0;
60  
61      /** First derivative of the function. */
62      private final T f1;
63  
64      /** Second derivative of the function. */
65      private final T f2;
66  
67      /** Build an instance with values and derivative.
68       * @param f0 value of the function
69       * @param f1 first derivative of the function
70       * @param f2 second derivative of the function
71       */
72      public FieldUnivariateDerivative2(final T f0, final T f1, final T f2) {
73          this.f0 = f0;
74          this.f1 = f1;
75          this.f2 = f2;
76      }
77  
78      /** Build an instance from a {@link DerivativeStructure}.
79       * @param ds derivative structure
80       * @exception MathIllegalArgumentException if either {@code ds} parameters
81       * is not 1 or {@code ds} order is not 2
82       */
83      public FieldUnivariateDerivative2(final FieldDerivativeStructure<T> ds) throws MathIllegalArgumentException {
84          MathUtils.checkDimension(ds.getFreeParameters(), 1);
85          MathUtils.checkDimension(ds.getOrder(), 2);
86          this.f0 = ds.getValue();
87          this.f1 = ds.getPartialDerivative(1);
88          this.f2 = ds.getPartialDerivative(2);
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public FieldUnivariateDerivative2<T> newInstance(final double value) {
94          final T zero = f0.getField().getZero();
95          return new FieldUnivariateDerivative2<>(zero.newInstance(value), zero, zero);
96      }
97  
98      /** {@inheritDoc} */
99      @Override
100     public FieldUnivariateDerivative2<T> newInstance(final T value) {
101         final T zero = f0.getField().getZero();
102         return new FieldUnivariateDerivative2<>(value, zero, zero);
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public FieldUnivariateDerivative2<T> withValue(final T value) {
108         return new FieldUnivariateDerivative2<>(value, f1, f2);
109     }
110 
111     /** Get the value part of the univariate derivative.
112      * @return value part of the univariate derivative
113      */
114     @Override
115     public T getValue() {
116         return f0;
117     }
118 
119     /** Get a derivative from the univariate derivative.
120      * @param n derivation order (must be between 0 and {@link #getOrder()}, both inclusive)
121      * @return n<sup>th</sup> derivative, or {@code NaN} if n is
122      * either negative or strictly larger than {@link #getOrder()}
123      */
124     @Override
125     public T getDerivative(final int n) {
126         switch (n) {
127             case 0 :
128                 return f0;
129             case 1 :
130                 return f1;
131             case 2 :
132                 return f2;
133             default :
134                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
135         }
136     }
137 
138     /** Get the derivation order.
139      * @return derivation order
140      */
141     @Override
142     public int getOrder() {
143         return 2;
144     }
145 
146     /** Get the first derivative.
147      * @return first derivative
148      * @see #getValue()
149      */
150     public T getFirstDerivative() {
151         return f1;
152     }
153 
154     /** Get the second derivative.
155      * @return second derivative
156      * @see #getValue()
157      * @see #getFirstDerivative()
158      */
159     public T getSecondDerivative() {
160         return f2;
161     }
162 
163     /** Get the {@link Field} the value and parameters of the function belongs to.
164      * @return {@link Field} the value and parameters of the function belongs to
165      */
166     public Field<T> getValueField() {
167         return f0.getField();
168     }
169 
170     /** Convert the instance to a {@link FieldDerivativeStructure}.
171      * @return derivative structure with same value and derivative as the instance
172      */
173     @Override
174     public FieldDerivativeStructure<T> toDerivativeStructure() {
175         return getField().getConversionFactory().build(f0, f1, f2);
176     }
177 
178     /** {@inheritDoc} */
179     @Override
180     public FieldUnivariateDerivative2<T> add(final double a) {
181         return new FieldUnivariateDerivative2<>(f0.add(a), f1, f2);
182     }
183 
184     /** {@inheritDoc} */
185     @Override
186     public FieldUnivariateDerivative2<T> add(final FieldUnivariateDerivative2<T> a) {
187         return new FieldUnivariateDerivative2<>(f0.add(a.f0), f1.add(a.f1), f2.add(a.f2));
188     }
189 
190     /** {@inheritDoc} */
191     @Override
192     public FieldUnivariateDerivative2<T> subtract(final double a) {
193         return new FieldUnivariateDerivative2<>(f0.subtract(a), f1, f2);
194     }
195 
196     /** {@inheritDoc} */
197     @Override
198     public FieldUnivariateDerivative2<T> subtract(final FieldUnivariateDerivative2<T> a) {
199         return new FieldUnivariateDerivative2<>(f0.subtract(a.f0), f1.subtract(a.f1), f2.subtract(a.f2));
200     }
201 
202     /** '&times;' operator.
203      * @param a right hand side parameter of the operator
204      * @return this&times;a
205      */
206     public FieldUnivariateDerivative2<T> multiply(final T a) {
207         return new FieldUnivariateDerivative2<>(f0.multiply(a), f1.multiply(a), f2.multiply(a));
208     }
209 
210     /** {@inheritDoc} */
211     @Override
212     public FieldUnivariateDerivative2<T> multiply(final int n) {
213         return new FieldUnivariateDerivative2<>(f0.multiply(n), f1.multiply(n), f2.multiply(n));
214     }
215 
216     /** {@inheritDoc} */
217     @Override
218     public FieldUnivariateDerivative2<T> multiply(final double a) {
219         return new FieldUnivariateDerivative2<>(f0.multiply(a), f1.multiply(a), f2.multiply(a));
220     }
221 
222     /** {@inheritDoc} */
223     @Override
224     public FieldUnivariateDerivative2<T> multiply(final FieldUnivariateDerivative2<T> a) {
225         return new FieldUnivariateDerivative2<>(f0.multiply(a.f0),
226                                                 a.f0.linearCombination(f1, a.f0, f0, a.f1),
227                                                 a.f0.linearCombination(f2, a.f0, f1.add(f1), a.f1, f0, a.f2));
228     }
229 
230     /** {@inheritDoc} */
231     @Override
232     public FieldUnivariateDerivative2<T> square() {
233         return multiply(this);
234     }
235 
236     /** '&divide;' operator.
237      * @param a right hand side parameter of the operator
238      * @return this&divide;a
239      */
240     public FieldUnivariateDerivative2<T> divide(final T a) {
241         final T inv1 = a.reciprocal();
242         return new FieldUnivariateDerivative2<>(f0.multiply(inv1), f1.multiply(inv1), f2.multiply(inv1));
243     }
244 
245     /** {@inheritDoc} */
246     @Override
247     public FieldUnivariateDerivative2<T> divide(final double a) {
248         final double inv1 = 1.0 / a;
249         return new FieldUnivariateDerivative2<>(f0.multiply(inv1), f1.multiply(inv1), f2.multiply(inv1));
250     }
251 
252     /** {@inheritDoc} */
253     @Override
254     public FieldUnivariateDerivative2<T> divide(final FieldUnivariateDerivative2<T> a) {
255         final T inv1 = a.f0.reciprocal();
256         final T inv2 = inv1.multiply(inv1);
257         final T inv3 = inv1.multiply(inv2);
258         return new FieldUnivariateDerivative2<>(f0.multiply(inv1),
259                                                 a.f0.linearCombination(f1, a.f0, f0.negate(), a.f1).multiply(inv2),
260                                                 a.f0.linearCombination(f2, a.f0.multiply(a.f0),
261                                                                        f1.multiply(-2), a.f0.multiply(a.f1),
262                                                                        f0.add(f0), a.f1.multiply(a.f1),
263                                                                        f0.negate(), a.f0.multiply(a.f2)).multiply(inv3));
264     }
265 
266     /** IEEE remainder operator.
267      * @param a right hand side parameter of the operator
268      * @return this - n &times; a where n is the closest integer to this/a
269      * (the even integer is chosen for n if this/a is halfway between two integers)
270      */
271     public FieldUnivariateDerivative2<T> remainder(final T a) {
272         return new FieldUnivariateDerivative2<>(FastMath.IEEEremainder(f0, a), f1, f2);
273     }
274 
275     /** {@inheritDoc} */
276     @Override
277     public FieldUnivariateDerivative2<T> remainder(final double a) {
278         return new FieldUnivariateDerivative2<>(FastMath.IEEEremainder(f0, a), f1, f2);
279     }
280 
281     /** {@inheritDoc} */
282     @Override
283     public FieldUnivariateDerivative2<T> remainder(final FieldUnivariateDerivative2<T> a) {
284 
285         // compute k such that lhs % rhs = lhs - k rhs
286         final T rem = FastMath.IEEEremainder(f0, a.f0);
287         final T k   = FastMath.rint(f0.subtract(rem).divide(a.f0));
288 
289         return new FieldUnivariateDerivative2<>(rem,
290                                                 f1.subtract(k.multiply(a.f1)),
291                                                 f2.subtract(k.multiply(a.f2)));
292 
293     }
294 
295     /** {@inheritDoc} */
296     @Override
297     public FieldUnivariateDerivative2<T> negate() {
298         return new FieldUnivariateDerivative2<>(f0.negate(), f1.negate(), f2.negate());
299     }
300 
301     /** {@inheritDoc} */
302     @Override
303     public FieldUnivariateDerivative2<T> abs() {
304         if (Double.doubleToLongBits(f0.getReal()) < 0) {
305             // we use the bits representation to also handle -0.0
306             return negate();
307         } else {
308             return this;
309         }
310     }
311 
312     /**
313      * Returns the instance with the sign of the argument.
314      * A NaN {@code sign} argument is treated as positive.
315      *
316      * @param sign the sign for the returned value
317      * @return the instance with the same sign as the {@code sign} argument
318      */
319     public FieldUnivariateDerivative2<T> copySign(final T sign) {
320         long m = Double.doubleToLongBits(f0.getReal());
321         long s = Double.doubleToLongBits(sign.getReal());
322         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
323             return this;
324         }
325         return negate(); // flip sign
326     }
327 
328     /** {@inheritDoc} */
329     @Override
330     public FieldUnivariateDerivative2<T> copySign(final FieldUnivariateDerivative2<T> sign) {
331         long m = Double.doubleToLongBits(f0.getReal());
332         long s = Double.doubleToLongBits(sign.f0.getReal());
333         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
334             return this;
335         }
336         return negate(); // flip sign
337     }
338 
339     /** {@inheritDoc} */
340     @Override
341     public FieldUnivariateDerivative2<T> copySign(final double sign) {
342         long m = Double.doubleToLongBits(f0.getReal());
343         long s = Double.doubleToLongBits(sign);
344         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
345             return this;
346         }
347         return negate(); // flip sign
348     }
349 
350     /** {@inheritDoc} */
351     @Override
352     public FieldUnivariateDerivative2<T> scalb(final int n) {
353         return new FieldUnivariateDerivative2<>(FastMath.scalb(f0, n),
354                                                 FastMath.scalb(f1, n),
355                                                 FastMath.scalb(f2, n));
356     }
357 
358     /** {@inheritDoc} */
359     @Override
360     public FieldUnivariateDerivative2<T> hypot(final FieldUnivariateDerivative2<T> y) {
361 
362         if (Double.isInfinite(f0.getReal()) || Double.isInfinite(y.f0.getReal())) {
363             final T zero = f0.getField().getZero();
364             return new FieldUnivariateDerivative2<>(f0.newInstance(Double.POSITIVE_INFINITY),
365                                                     zero, zero);
366         } else if (Double.isNaN(f0.getReal()) || Double.isNaN(y.f0.getReal())) {
367             final T zero = f0.getField().getZero();
368             return new FieldUnivariateDerivative2<>(f0.newInstance(Double.NaN),
369                                                     zero, zero);
370         } else {
371 
372             final int expX = getExponent();
373             final int expY = y.getExponent();
374             if (expX > expY + 27) {
375                 // y is negligible with respect to x
376                 return abs();
377             } else if (expY > expX + 27) {
378                 // x is negligible with respect to y
379                 return y.abs();
380             } else {
381 
382                 // find an intermediate scale to avoid both overflow and underflow
383                 final int middleExp = (expX + expY) / 2;
384 
385                 // scale parameters without losing precision
386                 final FieldUnivariateDerivative2<T> scaledX = scalb(-middleExp);
387                 final FieldUnivariateDerivative2<T> scaledY = y.scalb(-middleExp);
388 
389                 // compute scaled hypotenuse
390                 final FieldUnivariateDerivative2<T> scaledH =
391                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
392 
393                 // remove scaling
394                 return scaledH.scalb(middleExp);
395 
396             }
397 
398         }
399     }
400 
401     /** {@inheritDoc} */
402     @Override
403     public FieldUnivariateDerivative2<T> reciprocal() {
404         final T inv1 = f0.reciprocal();
405         final T inv2 = inv1.multiply(inv1);
406         final T inv3 = inv1.multiply(inv2);
407         return new FieldUnivariateDerivative2<>(inv1,
408                                                 f1.negate().multiply(inv2),
409                                                 f0.linearCombination(f1.add(f1), f1, f0.negate(), f2).multiply(inv3));
410     }
411 
412     /** Compute composition of the instance by a function.
413      * @param g0 value of the function at the current point (i.e. at {@code g(getValue())})
414      * @param g1 first derivative of the function at the current point (i.e. at {@code g'(getValue())})
415      * @param g2 second derivative of the function at the current point (i.e. at {@code g''(getValue())})
416      * @return g(this)
417      */
418     public FieldUnivariateDerivative2<T> compose(final T g0, final T g1, final T g2) {
419         return new FieldUnivariateDerivative2<>(g0,
420                                                 g1.multiply(f1),
421                                                 f0.linearCombination(g1, f2, g2, f1.square()));
422     }
423 
424     /** {@inheritDoc} */
425     @Override
426     public FieldUnivariateDerivative2<T> sqrt() {
427         final T s0 = FastMath.sqrt(f0);
428         final T s0twice = s0.multiply(2);
429         final T s1 = f1.divide(s0twice);
430         final T s2 = (f2.subtract(s1.square().multiply(2))).divide(s0twice);
431         return new FieldUnivariateDerivative2<>(s0, s1, s2);
432     }
433 
434     /** {@inheritDoc} */
435     @Override
436     public FieldUnivariateDerivative2<T> cbrt() {
437         final T c  = FastMath.cbrt(f0);
438         final T c2 = c.square();
439         return compose(c, c2.multiply(3).reciprocal(), c2.multiply(-4.5).multiply(f0).reciprocal());
440     }
441 
442     /** {@inheritDoc} */
443     @Override
444     public FieldUnivariateDerivative2<T> rootN(final int n) {
445         if (n == 2) {
446             return sqrt();
447         } else if (n == 3) {
448             return cbrt();
449         } else {
450             final T r = FastMath.pow(f0, 1.0 / n);
451             final T z = FastMath.pow(r, n - 1).multiply(n);
452             return compose(r, z.reciprocal(), z.square().multiply(r).reciprocal().multiply(1 -n));
453         }
454     }
455 
456     /** {@inheritDoc} */
457     @Override
458     public FieldUnivariateDerivative2Field<T> getField() {
459         return FieldUnivariateDerivative2Field.getUnivariateDerivative2Field(f0.getField());
460     }
461 
462     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldUnivariateDerivative2}
463      * @param a number to exponentiate
464      * @param x power to apply
465      * @param <T> the type of the function parameters and value
466      * @return a<sup>x</sup>
467      */
468     public static <T extends CalculusFieldElement<T>> FieldUnivariateDerivative2<T> pow(final double a, final FieldUnivariateDerivative2<T> x) {
469         if (a == 0) {
470             return x.getField().getZero();
471         } else {
472             final T      aX    = FastMath.pow(x.f0.newInstance(a), x.f0);
473             final double lnA   = FastMath.log(a);
474             final T      aXlnA = aX.multiply(lnA);
475             return new FieldUnivariateDerivative2<>(aX,
476                                                     aXlnA.multiply(x.f1),
477                                                     aXlnA.multiply(x.f1.multiply(x.f1).multiply(lnA).add(x.f2)));
478         }
479     }
480 
481     /** {@inheritDoc} */
482     @Override
483     public FieldUnivariateDerivative2<T> pow(final double p) {
484         if (p == 0) {
485             return getField().getOne();
486         } else {
487             final T f0Pm2 = FastMath.pow(f0, p - 2);
488             final T f0Pm1 = f0Pm2.multiply(f0);
489             final T f0P   = f0Pm1.multiply(f0);
490             return compose(f0P, f0Pm1.multiply(p), f0Pm2.multiply(p * (p - 1)));
491         }
492     }
493 
494     /** {@inheritDoc} */
495     @Override
496     public FieldUnivariateDerivative2<T> pow(final int n) {
497         if (n == 0) {
498             return getField().getOne();
499         } else {
500             final T f0Nm2 = FastMath.pow(f0, n - 2);
501             final T f0Nm1 = f0Nm2.multiply(f0);
502             final T f0N   = f0Nm1.multiply(f0);
503             return compose(f0N, f0Nm1.multiply(n), f0Nm2.multiply(n * (n - 1)));
504         }
505     }
506 
507     /** {@inheritDoc} */
508     @Override
509     public FieldUnivariateDerivative2<T> exp() {
510         final T exp = FastMath.exp(f0);
511         return compose(exp, exp, exp);
512     }
513 
514     /** {@inheritDoc} */
515     @Override
516     public FieldUnivariateDerivative2<T> expm1() {
517         final T exp   = FastMath.exp(f0);
518         final T expM1 = FastMath.expm1(f0);
519         return compose(expM1, exp, exp);
520     }
521 
522     /** {@inheritDoc} */
523     @Override
524     public FieldUnivariateDerivative2<T> log() {
525         final T inv = f0.reciprocal();
526         return compose(FastMath.log(f0), inv, inv.multiply(inv).negate());
527     }
528 
529     /** {@inheritDoc} */
530     @Override
531     public FieldUnivariateDerivative2<T> log1p() {
532         final T inv = f0.add(1).reciprocal();
533         return compose(FastMath.log1p(f0), inv, inv.multiply(inv).negate());
534     }
535 
536     /** {@inheritDoc} */
537     @Override
538     public FieldUnivariateDerivative2<T> log10() {
539         final T invF0 = f0.reciprocal();
540         final T inv = invF0.divide(FastMath.log(10.0));
541         return compose(FastMath.log10(f0), inv, inv.multiply(invF0).negate());
542     }
543 
544     /** {@inheritDoc} */
545     @Override
546     public FieldUnivariateDerivative2<T> cos() {
547         final FieldSinCos<T> sinCos = FastMath.sinCos(f0);
548         return compose(sinCos.cos(), sinCos.sin().negate(), sinCos.cos().negate());
549     }
550 
551     /** {@inheritDoc} */
552     @Override
553     public FieldUnivariateDerivative2<T> sin() {
554         final FieldSinCos<T> sinCos = FastMath.sinCos(f0);
555         return compose(sinCos.sin(), sinCos.cos(), sinCos.sin().negate());
556     }
557 
558     /** {@inheritDoc} */
559     @Override
560     public FieldSinCos<FieldUnivariateDerivative2<T>> sinCos() {
561         final FieldSinCos<T> sinCos = FastMath.sinCos(f0);
562         final T mSin = sinCos.sin().negate();
563         final T mCos = sinCos.cos().negate();
564         return new FieldSinCos<>(compose(sinCos.sin(), sinCos.cos(), mSin),
565                                  compose(sinCos.cos(), mSin, mCos));
566     }
567 
568     /** {@inheritDoc} */
569     @Override
570     public FieldUnivariateDerivative2<T> tan() {
571         final T tan  = FastMath.tan(f0);
572         final T sec2 = tan.multiply(tan).add(1);
573         return compose(tan, sec2, sec2.add(sec2).multiply(tan));
574     }
575 
576     /** {@inheritDoc} */
577     @Override
578     public FieldUnivariateDerivative2<T> acos() {
579         final T inv = f0.square().negate().add(1).reciprocal();
580         final T mS  = inv.sqrt().negate();
581         return compose(FastMath.acos(f0), mS, mS.multiply(f0).multiply(inv));
582     }
583 
584     /** {@inheritDoc} */
585     @Override
586     public FieldUnivariateDerivative2<T> asin() {
587         final T inv = f0.square().negate().add(1).reciprocal();
588         final T s   = inv.sqrt();
589         return compose(FastMath.asin(f0), s, s.multiply(f0).multiply(inv));
590     }
591 
592     /** {@inheritDoc} */
593     @Override
594     public FieldUnivariateDerivative2<T> atan() {
595         final T inv = f0.square().add(1).reciprocal();
596         return compose(FastMath.atan(f0), inv, f0.multiply(-2).multiply(inv).multiply(inv));
597     }
598 
599     /** {@inheritDoc} */
600     @Override
601     public FieldUnivariateDerivative2<T> atan2(final FieldUnivariateDerivative2<T> x) {
602         final T x2    = x.f0.multiply(x.f0);
603         final T f02   = f0.add(f0);
604         final T inv   = f0.square().add(x2).reciprocal();
605         final T atan0 = FastMath.atan2(f0, x.f0);
606         final T atan1 = f0.linearCombination(x.f0, f1, x.f1.negate(), f0).multiply(inv);
607         final T c     = f0.linearCombination(f2, x2,
608                                              f1.multiply(-2), x.f0.multiply(x.f1),
609                                              f02, x.f1.multiply(x.f1),
610                                              f0.negate(), x.f0.multiply(x.f2)).multiply(inv);
611         return new FieldUnivariateDerivative2<>(atan0,
612                                                 atan1,
613                                                 c.subtract(f02.multiply(atan1).multiply(atan1)).divide(x.f0));
614     }
615 
616     /** {@inheritDoc} */
617     @Override
618     public FieldUnivariateDerivative2<T> cosh() {
619         final T c = FastMath.cosh(f0);
620         final T s = FastMath.sinh(f0);
621         return compose(c, s, c);
622     }
623 
624     /** {@inheritDoc} */
625     @Override
626     public FieldUnivariateDerivative2<T> sinh() {
627         final T c = FastMath.cosh(f0);
628         final T s = FastMath.sinh(f0);
629         return compose(s, c, s);
630     }
631 
632     /** {@inheritDoc} */
633     @Override
634     public FieldSinhCosh<FieldUnivariateDerivative2<T>> sinhCosh() {
635         final FieldSinhCosh<T> sinhCosh = FastMath.sinhCosh(f0);
636         return new FieldSinhCosh<>(compose(sinhCosh.sinh(), sinhCosh.cosh(), sinhCosh.sinh()),
637                                    compose(sinhCosh.cosh(), sinhCosh.sinh(), sinhCosh.cosh()));
638     }
639 
640     /** {@inheritDoc} */
641     @Override
642     public FieldUnivariateDerivative2<T> tanh() {
643         final T tanh  = FastMath.tanh(f0);
644         final T sech2 = tanh.multiply(tanh).negate().add(1);
645         return compose(tanh, sech2, sech2.multiply(-2).multiply(tanh));
646     }
647 
648     /** {@inheritDoc} */
649     @Override
650     public FieldUnivariateDerivative2<T> acosh() {
651         final T inv = f0.square().subtract(1).reciprocal();
652         final T s   = inv.sqrt();
653         return compose(FastMath.acosh(f0), s, f0.negate().multiply(s).multiply(inv));
654     }
655 
656     /** {@inheritDoc} */
657     @Override
658     public FieldUnivariateDerivative2<T> asinh() {
659         final T inv = f0.square().add(1).reciprocal();
660         final T s   = inv.sqrt();
661         return compose(FastMath.asinh(f0), s, f0.negate().multiply(s).multiply(inv));
662     }
663 
664     /** {@inheritDoc} */
665     @Override
666     public FieldUnivariateDerivative2<T> atanh() {
667         final T inv = f0.square().negate().add(1).reciprocal();
668         return compose(FastMath.atanh(f0), inv, f0.add(f0).multiply(inv).multiply(inv));
669     }
670 
671     /** {@inheritDoc} */
672     @Override
673     public FieldUnivariateDerivative2<T> toDegrees() {
674         return new FieldUnivariateDerivative2<>(FastMath.toDegrees(f0), FastMath.toDegrees(f1), FastMath.toDegrees(f2));
675     }
676 
677     /** {@inheritDoc} */
678     @Override
679     public FieldUnivariateDerivative2<T> toRadians() {
680         return new FieldUnivariateDerivative2<>(FastMath.toRadians(f0), FastMath.toRadians(f1), FastMath.toRadians(f2));
681     }
682 
683     /** Evaluate Taylor expansion a univariate derivative.
684      * @param delta parameter offset Δx
685      * @return value of the Taylor expansion at x + Δx
686      */
687     public T taylor(final double delta) {
688         return f0.add(f1.add(f2.multiply(0.5 * delta)).multiply(delta));
689     }
690 
691     /** Evaluate Taylor expansion a univariate derivative.
692      * @param delta parameter offset Δx
693      * @return value of the Taylor expansion at x + Δx
694      */
695     public T taylor(final T delta) {
696         return f0.add(f1.add(f2.multiply(delta.multiply(0.5))).multiply(delta));
697     }
698 
699     /**
700      * Compute a linear combination.
701      * @param a Factors.
702      * @param b Factors.
703      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
704      * @throws MathIllegalArgumentException if arrays dimensions don't match
705      */
706     public FieldUnivariateDerivative2<T> linearCombination(final T[] a, final FieldUnivariateDerivative2<T>[] b) {
707 
708         // extract values and derivatives
709         final Field<T> field = b[0].f0.getField();
710         final int      n  = b.length;
711         final T[] b0 = MathArrays.buildArray(field, n);
712         final T[] b1 = MathArrays.buildArray(field, n);
713         final T[] b2 = MathArrays.buildArray(field, n);
714         for (int i = 0; i < n; ++i) {
715             b0[i] = b[i].f0;
716             b1[i] = b[i].f1;
717             b2[i] = b[i].f2;
718         }
719 
720         return new FieldUnivariateDerivative2<>(b[0].f0.linearCombination(a, b0),
721                                                 b[0].f0.linearCombination(a, b1),
722                                                 b[0].f0.linearCombination(a, b2));
723 
724     }
725 
726     /** {@inheritDoc} */
727     @Override
728     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T>[] a,
729                                                            final FieldUnivariateDerivative2<T>[] b) {
730 
731         // extract values and derivatives
732         final Field<T> field = a[0].f0.getField();
733         final int n  = a.length;
734         final T[] a0 = MathArrays.buildArray(field, n);
735         final T[] b0 = MathArrays.buildArray(field, n);
736         final T[] a1 = MathArrays.buildArray(field, 2 * n);
737         final T[] b1 = MathArrays.buildArray(field, 2 * n);
738         final T[] a2 = MathArrays.buildArray(field, 3 * n);
739         final T[] b2 = MathArrays.buildArray(field, 3 * n);
740         for (int i = 0; i < n; ++i) {
741             final FieldUnivariateDerivative2<T> ai = a[i];
742             final FieldUnivariateDerivative2<T> bi = b[i];
743             a0[i]         = ai.f0;
744             b0[i]         = bi.f0;
745             a1[2 * i]     = ai.f0;
746             a1[2 * i + 1] = ai.f1;
747             b1[2 * i]     = bi.f1;
748             b1[2 * i + 1] = bi.f0;
749             a2[3 * i]     = ai.f0;
750             a2[3 * i + 1] = ai.f1.add(ai.f1);
751             a2[3 * i + 2] = ai.f2;
752             b2[3 * i]     = bi.f2;
753             b2[3 * i + 1] = bi.f1;
754             b2[3 * i + 2] = bi.f0;
755         }
756 
757         return new FieldUnivariateDerivative2<>(a[0].f0.linearCombination(a0, b0),
758                                                 a[0].f0.linearCombination(a1, b1),
759                                                 a[0].f0.linearCombination(a2, b2));
760 
761     }
762 
763     /** {@inheritDoc} */
764     @Override
765     public FieldUnivariateDerivative2<T> linearCombination(final double[] a, final FieldUnivariateDerivative2<T>[] b) {
766 
767         // extract values and derivatives
768         final Field<T> field = b[0].f0.getField();
769         final int      n  = b.length;
770         final T[] b0 = MathArrays.buildArray(field, n);
771         final T[] b1 = MathArrays.buildArray(field, n);
772         final T[] b2 = MathArrays.buildArray(field, n);
773         for (int i = 0; i < n; ++i) {
774             b0[i] = b[i].f0;
775             b1[i] = b[i].f1;
776             b2[i] = b[i].f2;
777         }
778 
779         return new FieldUnivariateDerivative2<>(b[0].f0.linearCombination(a, b0),
780                                                 b[0].f0.linearCombination(a, b1),
781                                                 b[0].f0.linearCombination(a, b2));
782 
783     }
784 
785     /** {@inheritDoc} */
786     @Override
787     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
788                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2) {
789         final Field<T> field = a1.f0.getField();
790         final T[]      u2    = MathArrays.buildArray(field, 6);
791         final T[]      v2    = MathArrays.buildArray(field, 6);
792         u2[0] = a1.f0;
793         u2[1] = a1.f1.add(a1.f1);
794         u2[2] = a1.f2;
795         u2[3] = a2.f0;
796         u2[4] = a2.f1.add(a2.f1);
797         u2[5] = a2.f2;
798         v2[0] = b1.f2;
799         v2[1] = b1.f1;
800         v2[2] = b1.f0;
801         v2[3] = b2.f2;
802         v2[4] = b2.f1;
803         v2[5] = b2.f0;
804         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
805                                                                         a2.f0, b2.f0),
806                                                 a1.f0.linearCombination(a1.f0, b1.f1,
807                                                                         a1.f1, b1.f0,
808                                                                         a2.f0, b2.f1,
809                                                                         a2.f1, b2.f0),
810                                                 a1.f0.linearCombination(u2, v2));
811     }
812 
813     /** {@inheritDoc} */
814     @Override
815     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
816                                                            final double a2, final FieldUnivariateDerivative2<T> b2) {
817         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
818                                                                         a2, b2.f0),
819                                                 b1.f0.linearCombination(a1, b1.f1,
820                                                                         a2, b2.f1),
821                                                 b1.f0.linearCombination(a1, b1.f2,
822                                                                         a2, b2.f2));
823     }
824 
825     /** {@inheritDoc} */
826     @Override
827     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
828                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2,
829                                                            final FieldUnivariateDerivative2<T> a3, final FieldUnivariateDerivative2<T> b3) {
830         final Field<T> field = a1.f0.getField();
831         final T[]      u1     = MathArrays.buildArray(field, 6);
832         final T[]      v1     = MathArrays.buildArray(field, 6);
833         u1[0] = a1.f0;
834         u1[1] = a1.f1;
835         u1[2] = a2.f0;
836         u1[3] = a2.f1;
837         u1[4] = a3.f0;
838         u1[5] = a3.f1;
839         v1[0] = b1.f1;
840         v1[1] = b1.f0;
841         v1[2] = b2.f1;
842         v1[3] = b2.f0;
843         v1[4] = b3.f1;
844         v1[5] = b3.f0;
845         final T[]      u2     = MathArrays.buildArray(field, 9);
846         final T[]      v2     = MathArrays.buildArray(field, 9);
847         u2[0] = a1.f0;
848         u2[1] = a1.f1.add(a1.f1);
849         u2[2] = a1.f2;
850         u2[3] = a2.f0;
851         u2[4] = a2.f1.add(a2.f1);
852         u2[5] = a2.f2;
853         u2[6] = a3.f0;
854         u2[7] = a3.f1.add(a3.f1);
855         u2[8] = a3.f2;
856         v2[0] = b1.f2;
857         v2[1] = b1.f1;
858         v2[2] = b1.f0;
859         v2[3] = b2.f2;
860         v2[4] = b2.f1;
861         v2[5] = b2.f0;
862         v2[6] = b3.f2;
863         v2[7] = b3.f1;
864         v2[8] = b3.f0;
865         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
866                                                                         a2.f0, b2.f0,
867                                                                         a3.f0, b3.f0),
868                                                 a1.f0.linearCombination(u1, v1),
869                                                 a1.f0.linearCombination(u2, v2));
870     }
871 
872     /**
873      * Compute a linear combination.
874      * @param a1 first factor of the first term
875      * @param b1 second factor of the first term
876      * @param a2 first factor of the second term
877      * @param b2 second factor of the second term
878      * @param a3 first factor of the third term
879      * @param b3 second factor of the third term
880      * @return a<sub>1</sub>&times;b<sub>1</sub> +
881      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
882      * @see #linearCombination(double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2)
883      * @see #linearCombination(double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2)
884      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
885      */
886     public FieldUnivariateDerivative2<T> linearCombination(final T a1, final FieldUnivariateDerivative2<T> b1,
887                                                            final T a2, final FieldUnivariateDerivative2<T> b2,
888                                                            final T a3, final FieldUnivariateDerivative2<T> b3) {
889         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
890                                                                         a2, b2.f0,
891                                                                         a3, b3.f0),
892                                                 b1.f0.linearCombination(a1, b1.f1,
893                                                                         a2, b2.f1,
894                                                                         a3, b3.f1),
895                                                 b1.f0.linearCombination(a1, b1.f2,
896                                                                         a2, b2.f2,
897                                                                         a3, b3.f2));
898     }
899 
900     /** {@inheritDoc} */
901     @Override
902     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
903                                                            final double a2, final FieldUnivariateDerivative2<T> b2,
904                                                            final double a3, final FieldUnivariateDerivative2<T> b3) {
905         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
906                                                                         a2, b2.f0,
907                                                                         a3, b3.f0),
908                                                 b1.f0.linearCombination(a1, b1.f1,
909                                                                         a2, b2.f1,
910                                                                         a3, b3.f1),
911                                                 b1.f0.linearCombination(a1, b1.f2,
912                                                                         a2, b2.f2,
913                                                                         a3, b3.f2));
914     }
915 
916     /** {@inheritDoc} */
917     @Override
918     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
919                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2,
920                                                            final FieldUnivariateDerivative2<T> a3, final FieldUnivariateDerivative2<T> b3,
921                                                            final FieldUnivariateDerivative2<T> a4, final FieldUnivariateDerivative2<T> b4) {
922         final Field<T> field = a1.f0.getField();
923         final T[] u1 = MathArrays.buildArray(field, 8);
924         final T[] v1 = MathArrays.buildArray(field, 8);
925         u1[0] = a1.f0;
926         u1[1] = a1.f1;
927         u1[2] = a2.f0;
928         u1[3] = a2.f1;
929         u1[4] = a3.f0;
930         u1[5] = a3.f1;
931         u1[6] = a4.f0;
932         u1[7] = a4.f1;
933         v1[0] = b1.f1;
934         v1[1] = b1.f0;
935         v1[2] = b2.f1;
936         v1[3] = b2.f0;
937         v1[4] = b3.f1;
938         v1[5] = b3.f0;
939         v1[6] = b4.f1;
940         v1[7] = b4.f0;
941         final T[] u2 = MathArrays.buildArray(field, 12);
942         final T[] v2 = MathArrays.buildArray(field, 12);
943         u2[ 0] = a1.f0;
944         u2[ 1] = a1.f1.add(a1.f1);
945         u2[ 2] = a1.f2;
946         u2[ 3] = a2.f0;
947         u2[ 4] = a2.f1.add(a2.f1);
948         u2[ 5] = a2.f2;
949         u2[ 6] = a3.f0;
950         u2[ 7] = a3.f1.add(a3.f1);
951         u2[ 8] = a3.f2;
952         u2[ 9] = a4.f0;
953         u2[10] = a4.f1.add(a4.f1);
954         u2[11] = a4.f2;
955         v2[ 0] = b1.f2;
956         v2[ 1] = b1.f1;
957         v2[ 2] = b1.f0;
958         v2[ 3] = b2.f2;
959         v2[ 4] = b2.f1;
960         v2[ 5] = b2.f0;
961         v2[ 6] = b3.f2;
962         v2[ 7] = b3.f1;
963         v2[ 8] = b3.f0;
964         v2[ 9] = b4.f2;
965         v2[10] = b4.f1;
966         v2[11] = b4.f0;
967         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
968                                                                         a2.f0, b2.f0,
969                                                                         a3.f0, b3.f0,
970                                                                         a4.f0, b4.f0),
971                                                 a1.f0.linearCombination(u1, v1),
972                                                 a1.f0.linearCombination(u2, v2));
973     }
974 
975     /** {@inheritDoc} */
976     @Override
977     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
978                                                            final double a2, final FieldUnivariateDerivative2<T> b2,
979                                                            final double a3, final FieldUnivariateDerivative2<T> b3,
980                                                            final double a4, final FieldUnivariateDerivative2<T> b4) {
981         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
982                                                                         a2, b2.f0,
983                                                                         a3, b3.f0,
984                                                                         a4, b4.f0),
985                                                 b1.f0.linearCombination(a1, b1.f1,
986                                                                         a2, b2.f1,
987                                                                         a3, b3.f1,
988                                                                         a4, b4.f1),
989                                                 b1.f0.linearCombination(a1, b1.f2,
990                                                                         a2, b2.f2,
991                                                                         a3, b3.f2,
992                                                                         a4, b4.f2));
993     }
994 
995     /** {@inheritDoc} */
996     @Override
997     public FieldUnivariateDerivative2<T> getPi() {
998         final T zero = getValueField().getZero();
999         return new FieldUnivariateDerivative2<>(zero.getPi(), zero, zero);
1000     }
1001 
1002     /** Test for the equality of two univariate derivatives.
1003      * <p>
1004      * univariate derivatives are considered equal if they have the same derivatives.
1005      * </p>
1006      * @param other Object to test for equality to this
1007      * @return true if two univariate derivatives are equal
1008      */
1009     @Override
1010     public boolean equals(Object other) {
1011 
1012         if (this == other) {
1013             return true;
1014         }
1015 
1016         if (other instanceof FieldUnivariateDerivative2) {
1017             @SuppressWarnings("unchecked")
1018             final FieldUnivariateDerivative2<T> rhs = (FieldUnivariateDerivative2<T>) other;
1019             return f0.equals(rhs.f0) && f1.equals(rhs.f1) && f2.equals(rhs.f2);
1020         }
1021 
1022         return false;
1023 
1024     }
1025 
1026     /** Get a hashCode for the univariate derivative.
1027      * @return a hash code value for this object
1028      */
1029     @Override
1030     public int hashCode() {
1031         return 317 - 41 * f0.hashCode() + 57 * f1.hashCode() - 103 * f2.hashCode();
1032     }
1033 
1034 }