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