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