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 x2    = x.f0.multiply(x.f0);
610         final T f02   = f0.add(f0);
611         final T inv   = f0.square().add(x2).reciprocal();
612         final T atan0 = FastMath.atan2(f0, x.f0);
613         final T atan1 = f0.linearCombination(x.f0, f1, x.f1.negate(), f0).multiply(inv);
614         final T c     = f0.linearCombination(f2, x2,
615                                              f1.multiply(-2), x.f0.multiply(x.f1),
616                                              f02, x.f1.multiply(x.f1),
617                                              f0.negate(), x.f0.multiply(x.f2)).multiply(inv);
618         return new FieldUnivariateDerivative2<>(atan0,
619                                                 atan1,
620                                                 c.subtract(f02.multiply(atan1).multiply(atan1)).divide(x.f0));
621     }
622 
623     /** {@inheritDoc} */
624     @Override
625     public FieldUnivariateDerivative2<T> cosh() {
626         final T c = FastMath.cosh(f0);
627         final T s = FastMath.sinh(f0);
628         return compose(c, s, c);
629     }
630 
631     /** {@inheritDoc} */
632     @Override
633     public FieldUnivariateDerivative2<T> sinh() {
634         final T c = FastMath.cosh(f0);
635         final T s = FastMath.sinh(f0);
636         return compose(s, c, s);
637     }
638 
639     /** {@inheritDoc} */
640     @Override
641     public FieldSinhCosh<FieldUnivariateDerivative2<T>> sinhCosh() {
642         final FieldSinhCosh<T> sinhCosh = FastMath.sinhCosh(f0);
643         return new FieldSinhCosh<>(compose(sinhCosh.sinh(), sinhCosh.cosh(), sinhCosh.sinh()),
644                                    compose(sinhCosh.cosh(), sinhCosh.sinh(), sinhCosh.cosh()));
645     }
646 
647     /** {@inheritDoc} */
648     @Override
649     public FieldUnivariateDerivative2<T> tanh() {
650         final T tanh  = FastMath.tanh(f0);
651         final T sech2 = tanh.multiply(tanh).negate().add(1);
652         return compose(tanh, sech2, sech2.multiply(-2).multiply(tanh));
653     }
654 
655     /** {@inheritDoc} */
656     @Override
657     public FieldUnivariateDerivative2<T> acosh() {
658         final T inv = f0.square().subtract(1).reciprocal();
659         final T s   = inv.sqrt();
660         return compose(FastMath.acosh(f0), s, f0.negate().multiply(s).multiply(inv));
661     }
662 
663     /** {@inheritDoc} */
664     @Override
665     public FieldUnivariateDerivative2<T> asinh() {
666         final T inv = f0.square().add(1).reciprocal();
667         final T s   = inv.sqrt();
668         return compose(FastMath.asinh(f0), s, f0.negate().multiply(s).multiply(inv));
669     }
670 
671     /** {@inheritDoc} */
672     @Override
673     public FieldUnivariateDerivative2<T> atanh() {
674         final T inv = f0.square().negate().add(1).reciprocal();
675         return compose(FastMath.atanh(f0), inv, f0.add(f0).multiply(inv).multiply(inv));
676     }
677 
678     /** {@inheritDoc} */
679     @Override
680     public FieldUnivariateDerivative2<T> toDegrees() {
681         return new FieldUnivariateDerivative2<>(FastMath.toDegrees(f0), FastMath.toDegrees(f1), FastMath.toDegrees(f2));
682     }
683 
684     /** {@inheritDoc} */
685     @Override
686     public FieldUnivariateDerivative2<T> toRadians() {
687         return new FieldUnivariateDerivative2<>(FastMath.toRadians(f0), FastMath.toRadians(f1), FastMath.toRadians(f2));
688     }
689 
690     /** Evaluate Taylor expansion a univariate derivative.
691      * @param delta parameter offset Δx
692      * @return value of the Taylor expansion at x + Δx
693      */
694     public T taylor(final double delta) {
695         return f0.add(f1.add(f2.multiply(0.5 * delta)).multiply(delta));
696     }
697 
698     /** Evaluate Taylor expansion a univariate derivative.
699      * @param delta parameter offset Δx
700      * @return value of the Taylor expansion at x + Δx
701      */
702     public T taylor(final T delta) {
703         return f0.add(f1.add(f2.multiply(delta.multiply(0.5))).multiply(delta));
704     }
705 
706     /**
707      * Compute a linear combination.
708      * @param a Factors.
709      * @param b Factors.
710      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
711      * @throws MathIllegalArgumentException if arrays dimensions don't match
712      */
713     public FieldUnivariateDerivative2<T> linearCombination(final T[] a, final FieldUnivariateDerivative2<T>[] b) {
714 
715         // extract values and derivatives
716         final Field<T> field = b[0].f0.getField();
717         final int      n  = b.length;
718         final T[] b0 = MathArrays.buildArray(field, n);
719         final T[] b1 = MathArrays.buildArray(field, n);
720         final T[] b2 = MathArrays.buildArray(field, n);
721         for (int i = 0; i < n; ++i) {
722             b0[i] = b[i].f0;
723             b1[i] = b[i].f1;
724             b2[i] = b[i].f2;
725         }
726 
727         return new FieldUnivariateDerivative2<>(b[0].f0.linearCombination(a, b0),
728                                                 b[0].f0.linearCombination(a, b1),
729                                                 b[0].f0.linearCombination(a, b2));
730 
731     }
732 
733     /** {@inheritDoc} */
734     @Override
735     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T>[] a,
736                                                            final FieldUnivariateDerivative2<T>[] b) {
737 
738         // extract values and derivatives
739         final Field<T> field = a[0].f0.getField();
740         final int n  = a.length;
741         final T[] a0 = MathArrays.buildArray(field, n);
742         final T[] b0 = MathArrays.buildArray(field, n);
743         final T[] a1 = MathArrays.buildArray(field, 2 * n);
744         final T[] b1 = MathArrays.buildArray(field, 2 * n);
745         final T[] a2 = MathArrays.buildArray(field, 3 * n);
746         final T[] b2 = MathArrays.buildArray(field, 3 * n);
747         for (int i = 0; i < n; ++i) {
748             final FieldUnivariateDerivative2<T> ai = a[i];
749             final FieldUnivariateDerivative2<T> bi = b[i];
750             a0[i]         = ai.f0;
751             b0[i]         = bi.f0;
752             a1[2 * i]     = ai.f0;
753             a1[2 * i + 1] = ai.f1;
754             b1[2 * i]     = bi.f1;
755             b1[2 * i + 1] = bi.f0;
756             a2[3 * i]     = ai.f0;
757             a2[3 * i + 1] = ai.f1.add(ai.f1);
758             a2[3 * i + 2] = ai.f2;
759             b2[3 * i]     = bi.f2;
760             b2[3 * i + 1] = bi.f1;
761             b2[3 * i + 2] = bi.f0;
762         }
763 
764         return new FieldUnivariateDerivative2<>(a[0].f0.linearCombination(a0, b0),
765                                                 a[0].f0.linearCombination(a1, b1),
766                                                 a[0].f0.linearCombination(a2, b2));
767 
768     }
769 
770     /** {@inheritDoc} */
771     @Override
772     public FieldUnivariateDerivative2<T> linearCombination(final double[] a, final FieldUnivariateDerivative2<T>[] b) {
773 
774         // extract values and derivatives
775         final Field<T> field = b[0].f0.getField();
776         final int      n  = b.length;
777         final T[] b0 = MathArrays.buildArray(field, n);
778         final T[] b1 = MathArrays.buildArray(field, n);
779         final T[] b2 = MathArrays.buildArray(field, n);
780         for (int i = 0; i < n; ++i) {
781             b0[i] = b[i].f0;
782             b1[i] = b[i].f1;
783             b2[i] = b[i].f2;
784         }
785 
786         return new FieldUnivariateDerivative2<>(b[0].f0.linearCombination(a, b0),
787                                                 b[0].f0.linearCombination(a, b1),
788                                                 b[0].f0.linearCombination(a, b2));
789 
790     }
791 
792     /** {@inheritDoc} */
793     @Override
794     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
795                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2) {
796         final Field<T> field = a1.f0.getField();
797         final T[]      u2    = MathArrays.buildArray(field, 6);
798         final T[]      v2    = MathArrays.buildArray(field, 6);
799         u2[0] = a1.f0;
800         u2[1] = a1.f1.add(a1.f1);
801         u2[2] = a1.f2;
802         u2[3] = a2.f0;
803         u2[4] = a2.f1.add(a2.f1);
804         u2[5] = a2.f2;
805         v2[0] = b1.f2;
806         v2[1] = b1.f1;
807         v2[2] = b1.f0;
808         v2[3] = b2.f2;
809         v2[4] = b2.f1;
810         v2[5] = b2.f0;
811         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
812                                                                         a2.f0, b2.f0),
813                                                 a1.f0.linearCombination(a1.f0, b1.f1,
814                                                                         a1.f1, b1.f0,
815                                                                         a2.f0, b2.f1,
816                                                                         a2.f1, b2.f0),
817                                                 a1.f0.linearCombination(u2, v2));
818     }
819 
820     /** {@inheritDoc} */
821     @Override
822     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
823                                                            final double a2, final FieldUnivariateDerivative2<T> b2) {
824         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
825                                                                         a2, b2.f0),
826                                                 b1.f0.linearCombination(a1, b1.f1,
827                                                                         a2, b2.f1),
828                                                 b1.f0.linearCombination(a1, b1.f2,
829                                                                         a2, b2.f2));
830     }
831 
832     /** {@inheritDoc} */
833     @Override
834     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
835                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2,
836                                                            final FieldUnivariateDerivative2<T> a3, final FieldUnivariateDerivative2<T> b3) {
837         final Field<T> field = a1.f0.getField();
838         final T[]      u1     = MathArrays.buildArray(field, 6);
839         final T[]      v1     = MathArrays.buildArray(field, 6);
840         u1[0] = a1.f0;
841         u1[1] = a1.f1;
842         u1[2] = a2.f0;
843         u1[3] = a2.f1;
844         u1[4] = a3.f0;
845         u1[5] = a3.f1;
846         v1[0] = b1.f1;
847         v1[1] = b1.f0;
848         v1[2] = b2.f1;
849         v1[3] = b2.f0;
850         v1[4] = b3.f1;
851         v1[5] = b3.f0;
852         final T[]      u2     = MathArrays.buildArray(field, 9);
853         final T[]      v2     = MathArrays.buildArray(field, 9);
854         u2[0] = a1.f0;
855         u2[1] = a1.f1.add(a1.f1);
856         u2[2] = a1.f2;
857         u2[3] = a2.f0;
858         u2[4] = a2.f1.add(a2.f1);
859         u2[5] = a2.f2;
860         u2[6] = a3.f0;
861         u2[7] = a3.f1.add(a3.f1);
862         u2[8] = a3.f2;
863         v2[0] = b1.f2;
864         v2[1] = b1.f1;
865         v2[2] = b1.f0;
866         v2[3] = b2.f2;
867         v2[4] = b2.f1;
868         v2[5] = b2.f0;
869         v2[6] = b3.f2;
870         v2[7] = b3.f1;
871         v2[8] = b3.f0;
872         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
873                                                                         a2.f0, b2.f0,
874                                                                         a3.f0, b3.f0),
875                                                 a1.f0.linearCombination(u1, v1),
876                                                 a1.f0.linearCombination(u2, v2));
877     }
878 
879     /**
880      * Compute a linear combination.
881      * @param a1 first factor of the first term
882      * @param b1 second factor of the first term
883      * @param a2 first factor of the second term
884      * @param b2 second factor of the second term
885      * @param a3 first factor of the third term
886      * @param b3 second factor of the third term
887      * @return a<sub>1</sub>&times;b<sub>1</sub> +
888      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
889      * @see #linearCombination(double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2)
890      * @see #linearCombination(double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2, double, FieldUnivariateDerivative2)
891      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
892      */
893     public FieldUnivariateDerivative2<T> linearCombination(final T a1, final FieldUnivariateDerivative2<T> b1,
894                                                            final T a2, final FieldUnivariateDerivative2<T> b2,
895                                                            final T a3, final FieldUnivariateDerivative2<T> b3) {
896         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
897                                                                         a2, b2.f0,
898                                                                         a3, b3.f0),
899                                                 b1.f0.linearCombination(a1, b1.f1,
900                                                                         a2, b2.f1,
901                                                                         a3, b3.f1),
902                                                 b1.f0.linearCombination(a1, b1.f2,
903                                                                         a2, b2.f2,
904                                                                         a3, b3.f2));
905     }
906 
907     /** {@inheritDoc} */
908     @Override
909     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
910                                                            final double a2, final FieldUnivariateDerivative2<T> b2,
911                                                            final double a3, final FieldUnivariateDerivative2<T> b3) {
912         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
913                                                                         a2, b2.f0,
914                                                                         a3, b3.f0),
915                                                 b1.f0.linearCombination(a1, b1.f1,
916                                                                         a2, b2.f1,
917                                                                         a3, b3.f1),
918                                                 b1.f0.linearCombination(a1, b1.f2,
919                                                                         a2, b2.f2,
920                                                                         a3, b3.f2));
921     }
922 
923     /** {@inheritDoc} */
924     @Override
925     public FieldUnivariateDerivative2<T> linearCombination(final FieldUnivariateDerivative2<T> a1, final FieldUnivariateDerivative2<T> b1,
926                                                            final FieldUnivariateDerivative2<T> a2, final FieldUnivariateDerivative2<T> b2,
927                                                            final FieldUnivariateDerivative2<T> a3, final FieldUnivariateDerivative2<T> b3,
928                                                            final FieldUnivariateDerivative2<T> a4, final FieldUnivariateDerivative2<T> b4) {
929         final Field<T> field = a1.f0.getField();
930         final T[] u1 = MathArrays.buildArray(field, 8);
931         final T[] v1 = MathArrays.buildArray(field, 8);
932         u1[0] = a1.f0;
933         u1[1] = a1.f1;
934         u1[2] = a2.f0;
935         u1[3] = a2.f1;
936         u1[4] = a3.f0;
937         u1[5] = a3.f1;
938         u1[6] = a4.f0;
939         u1[7] = a4.f1;
940         v1[0] = b1.f1;
941         v1[1] = b1.f0;
942         v1[2] = b2.f1;
943         v1[3] = b2.f0;
944         v1[4] = b3.f1;
945         v1[5] = b3.f0;
946         v1[6] = b4.f1;
947         v1[7] = b4.f0;
948         final T[] u2 = MathArrays.buildArray(field, 12);
949         final T[] v2 = MathArrays.buildArray(field, 12);
950         u2[ 0] = a1.f0;
951         u2[ 1] = a1.f1.add(a1.f1);
952         u2[ 2] = a1.f2;
953         u2[ 3] = a2.f0;
954         u2[ 4] = a2.f1.add(a2.f1);
955         u2[ 5] = a2.f2;
956         u2[ 6] = a3.f0;
957         u2[ 7] = a3.f1.add(a3.f1);
958         u2[ 8] = a3.f2;
959         u2[ 9] = a4.f0;
960         u2[10] = a4.f1.add(a4.f1);
961         u2[11] = a4.f2;
962         v2[ 0] = b1.f2;
963         v2[ 1] = b1.f1;
964         v2[ 2] = b1.f0;
965         v2[ 3] = b2.f2;
966         v2[ 4] = b2.f1;
967         v2[ 5] = b2.f0;
968         v2[ 6] = b3.f2;
969         v2[ 7] = b3.f1;
970         v2[ 8] = b3.f0;
971         v2[ 9] = b4.f2;
972         v2[10] = b4.f1;
973         v2[11] = b4.f0;
974         return new FieldUnivariateDerivative2<>(a1.f0.linearCombination(a1.f0, b1.f0,
975                                                                         a2.f0, b2.f0,
976                                                                         a3.f0, b3.f0,
977                                                                         a4.f0, b4.f0),
978                                                 a1.f0.linearCombination(u1, v1),
979                                                 a1.f0.linearCombination(u2, v2));
980     }
981 
982     /** {@inheritDoc} */
983     @Override
984     public FieldUnivariateDerivative2<T> linearCombination(final double a1, final FieldUnivariateDerivative2<T> b1,
985                                                            final double a2, final FieldUnivariateDerivative2<T> b2,
986                                                            final double a3, final FieldUnivariateDerivative2<T> b3,
987                                                            final double a4, final FieldUnivariateDerivative2<T> b4) {
988         return new FieldUnivariateDerivative2<>(b1.f0.linearCombination(a1, b1.f0,
989                                                                         a2, b2.f0,
990                                                                         a3, b3.f0,
991                                                                         a4, b4.f0),
992                                                 b1.f0.linearCombination(a1, b1.f1,
993                                                                         a2, b2.f1,
994                                                                         a3, b3.f1,
995                                                                         a4, b4.f1),
996                                                 b1.f0.linearCombination(a1, b1.f2,
997                                                                         a2, b2.f2,
998                                                                         a3, b3.f2,
999                                                                         a4, b4.f2));
1000     }
1001 
1002     /** {@inheritDoc} */
1003     @Override
1004     public FieldUnivariateDerivative2<T> getPi() {
1005         final T zero = getValueField().getZero();
1006         return new FieldUnivariateDerivative2<>(zero.getPi(), zero, zero);
1007     }
1008 
1009     /** Test for the equality of two univariate derivatives.
1010      * <p>
1011      * univariate derivatives are considered equal if they have the same derivatives.
1012      * </p>
1013      * @param other Object to test for equality to this
1014      * @return true if two univariate derivatives are equal
1015      */
1016     @Override
1017     public boolean equals(Object other) {
1018 
1019         if (this == other) {
1020             return true;
1021         }
1022 
1023         if (other instanceof FieldUnivariateDerivative2) {
1024             @SuppressWarnings("unchecked")
1025             final FieldUnivariateDerivative2<T> rhs = (FieldUnivariateDerivative2<T>) other;
1026             return f0.equals(rhs.f0) && f1.equals(rhs.f1) && f2.equals(rhs.f2);
1027         }
1028 
1029         return false;
1030 
1031     }
1032 
1033     /** Get a hashCode for the univariate derivative.
1034      * @return a hash code value for this object
1035      */
1036     @Override
1037     public int hashCode() {
1038         return 317 - 41 * f0.hashCode() + 57 * f1.hashCode() - 103 * f2.hashCode();
1039     }
1040 
1041 }