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