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.exception.LocalizedCoreFormats;
20  import org.hipparchus.exception.MathIllegalArgumentException;
21  import org.hipparchus.util.FastMath;
22  import org.hipparchus.util.FieldSinCos;
23  import org.hipparchus.util.FieldSinhCosh;
24  import org.hipparchus.util.MathArrays;
25  import org.hipparchus.util.MathUtils;
26  import org.hipparchus.util.SinCos;
27  import org.hipparchus.util.SinhCosh;
28  
29  /** Class representing both the value and the differentials of a function.
30   * <p>This class is a stripped-down version of {@link DerivativeStructure}
31   * with only one {@link DerivativeStructure#getFreeParameters() free parameter}
32   * and {@link DerivativeStructure#getOrder() derivation order} also limited to two.
33   * It should have less overhead than {@link DerivativeStructure} 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 UnivariateDerivative2} 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   * @see DerivativeStructure
46   * @see UnivariateDerivative2
47   * @see Gradient
48   * @see FieldDerivativeStructure
49   * @see FieldUnivariateDerivative2
50   * @see FieldUnivariateDerivative2
51   * @see FieldGradient
52   * @since 1.7
53   */
54  public class UnivariateDerivative2 extends UnivariateDerivative<UnivariateDerivative2> {
55  
56      /** The constant value of π as a {@code UnivariateDerivative2}.
57       * @since 2.0
58       */
59      public static final UnivariateDerivative2 PI = new UnivariateDerivative2(FastMath.PI, 0.0, 0.0);
60  
61      /** Serializable UID. */
62      private static final long serialVersionUID = 20200520L;
63  
64      /** Value of the function. */
65      private final double f0;
66  
67      /** First derivative of the function. */
68      private final double f1;
69  
70      /** Second derivative of the function. */
71      private final double f2;
72  
73      /** Build an instance with values and derivative.
74       * @param f0 value of the function
75       * @param f1 first derivative of the function
76       * @param f2 second derivative of the function
77       */
78      public UnivariateDerivative2(final double f0, final double f1, final double f2) {
79          this.f0 = f0;
80          this.f1 = f1;
81          this.f2 = f2;
82      }
83  
84      /** Build an instance from a {@link DerivativeStructure}.
85       * @param ds derivative structure
86       * @exception MathIllegalArgumentException if either {@code ds} parameters
87       * is not 1 or {@code ds} order is not 2
88       */
89      public UnivariateDerivative2(final DerivativeStructure ds) throws MathIllegalArgumentException {
90          MathUtils.checkDimension(ds.getFreeParameters(), 1);
91          MathUtils.checkDimension(ds.getOrder(), 2);
92          this.f0 = ds.getValue();
93          this.f1 = ds.getPartialDerivative(1);
94          this.f2 = ds.getPartialDerivative(2);
95      }
96  
97      /** {@inheritDoc} */
98      @Override
99      public UnivariateDerivative2 newInstance(final double value) {
100         return new UnivariateDerivative2(value, 0.0, 0.0);
101     }
102 
103     @Override
104     public UnivariateDerivative2 withValue(final double value) {
105         return new UnivariateDerivative2(value, f1, f2);
106     }
107 
108     /** {@inheritDoc} */
109     @Override
110     public double getValue() {
111         return f0;
112     }
113 
114     /** {@inheritDoc} */
115     @Override
116     public double getDerivative(final int n) {
117         switch (n) {
118             case 0 :
119                 return f0;
120             case 1 :
121                 return f1;
122             case 2 :
123                 return f2;
124             default :
125                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
126         }
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public int getOrder() {
132         return 2;
133     }
134 
135     /** Get the first derivative.
136      * @return first derivative
137      * @see #getValue()
138      * @see #getSecondDerivative()
139      */
140     public double getFirstDerivative() {
141         return f1;
142     }
143 
144     /** Get the second derivative.
145      * @return second derivative
146      * @see #getValue()
147      * @see #getFirstDerivative()
148      */
149     public double getSecondDerivative() {
150         return f2;
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public DerivativeStructure toDerivativeStructure() {
156         return getField().getConversionFactory().build(f0, f1, f2);
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public UnivariateDerivative2 add(final UnivariateDerivative2 a) {
162         return new UnivariateDerivative2(f0 + a.f0, f1 + a.f1, f2 + a.f2);
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public UnivariateDerivative2 subtract(final UnivariateDerivative2 a) {
168         return new UnivariateDerivative2(f0 - a.f0, f1 - a.f1, f2 - a.f2);
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public UnivariateDerivative2 multiply(final int n) {
174         return new UnivariateDerivative2(f0 * n, f1 * n, f2 * n);
175     }
176 
177     /** {@inheritDoc} */
178     @Override
179     public UnivariateDerivative2 multiply(final double a) {
180         return new UnivariateDerivative2(f0 * a, f1 * a, f2 * a);
181     }
182 
183     /** {@inheritDoc} */
184     @Override
185     public UnivariateDerivative2 multiply(final UnivariateDerivative2 a) {
186         return new UnivariateDerivative2(f0 * a.f0,
187                                          MathArrays.linearCombination(f1, a.f0, f0, a.f1),
188                                          MathArrays.linearCombination(f2, a.f0, 2 * f1, a.f1, f0, a.f2));
189     }
190 
191     /** {@inheritDoc} */
192     @Override
193     public UnivariateDerivative2 square() {
194         return new UnivariateDerivative2(f0 * f0, 2 * f0 * f1, 2 * (f0 * f2 + f1 * f1));
195     }
196 
197     /** {@inheritDoc} */
198     @Override
199     public UnivariateDerivative2 divide(final double a) {
200         final double inv1 = 1.0 / a;
201         return new UnivariateDerivative2(f0 * inv1, f1 * inv1, f2 * inv1);
202     }
203 
204     /** {@inheritDoc} */
205     @Override
206     public UnivariateDerivative2 divide(final UnivariateDerivative2 a) {
207         final double inv1 = 1.0 / a.f0;
208         final double inv2 = inv1 * inv1;
209         final double inv3 = inv1 * inv2;
210         return new UnivariateDerivative2(f0 * inv1,
211                                          MathArrays.linearCombination(f1, a.f0, -f0, a.f1) * inv2,
212                                          MathArrays.linearCombination(f2, a.f0 * a.f0,
213                                                                       -2 * f1, a.f0 * a.f1,
214                                                                        2 * f0, a.f1 * a.f1,
215                                                                        -f0, a.f0 * a.f2) * inv3);
216     }
217 
218     /** {@inheritDoc} */
219     @Override
220     public UnivariateDerivative2 remainder(final UnivariateDerivative2 a) {
221 
222         // compute k such that lhs % rhs = lhs - k rhs
223         final double rem = FastMath.IEEEremainder(f0, a.f0);
224         final double k   = FastMath.rint((f0 - rem) / a.f0);
225 
226         return new UnivariateDerivative2(rem, f1 - k * a.f1, f2 - k * a.f2);
227 
228     }
229 
230     /** {@inheritDoc} */
231     @Override
232     public UnivariateDerivative2 negate() {
233         return new UnivariateDerivative2(-f0, -f1, -f2);
234     }
235 
236     /** {@inheritDoc} */
237     @Override
238     public UnivariateDerivative2 abs() {
239         if (Double.doubleToLongBits(f0) < 0) {
240             // we use the bits representation to also handle -0.0
241             return negate();
242         } else {
243             return this;
244         }
245     }
246 
247     /** {@inheritDoc} */
248     @Override
249     public UnivariateDerivative2 copySign(final UnivariateDerivative2 sign) {
250         long m = Double.doubleToLongBits(f0);
251         long s = Double.doubleToLongBits(sign.f0);
252         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
253             return this;
254         }
255         return negate(); // flip sign
256     }
257 
258     /** {@inheritDoc} */
259     @Override
260     public UnivariateDerivative2 copySign(final double sign) {
261         long m = Double.doubleToLongBits(f0);
262         long s = Double.doubleToLongBits(sign);
263         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
264             return this;
265         }
266         return negate(); // flip sign
267     }
268 
269     /** {@inheritDoc} */
270     @Override
271     public UnivariateDerivative2 scalb(final int n) {
272         return new UnivariateDerivative2(FastMath.scalb(f0, n), FastMath.scalb(f1, n), FastMath.scalb(f2, n));
273     }
274 
275     /** {@inheritDoc} */
276     @Override
277     public UnivariateDerivative2 hypot(final UnivariateDerivative2 y) {
278 
279         if (Double.isInfinite(f0) || Double.isInfinite(y.f0)) {
280             return new UnivariateDerivative2(Double.POSITIVE_INFINITY, 0.0, 0.0);
281         } else if (Double.isNaN(f0) || Double.isNaN(y.f0)) {
282             return new UnivariateDerivative2(Double.NaN, 0.0, 0.0);
283         } else {
284 
285             final int expX = getExponent();
286             final int expY = y.getExponent();
287             if (expX > expY + 27) {
288                 // y is negligible with respect to x
289                 return abs();
290             } else if (expY > expX + 27) {
291                 // x is negligible with respect to y
292                 return y.abs();
293             } else {
294 
295                 // find an intermediate scale to avoid both overflow and underflow
296                 final int middleExp = (expX + expY) / 2;
297 
298                 // scale parameters without losing precision
299                 final UnivariateDerivative2 scaledX = scalb(-middleExp);
300                 final UnivariateDerivative2 scaledY = y.scalb(-middleExp);
301 
302                 // compute scaled hypotenuse
303                 final UnivariateDerivative2 scaledH =
304                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
305 
306                 // remove scaling
307                 return scaledH.scalb(middleExp);
308 
309             }
310 
311         }
312     }
313 
314     /** {@inheritDoc} */
315     @Override
316     public UnivariateDerivative2 reciprocal() {
317         final double inv1 = 1.0 / f0;
318         final double inv2 = inv1 * inv1;
319         final double inv3 = inv1 * inv2;
320         return new UnivariateDerivative2(inv1, -f1 * inv2, MathArrays.linearCombination(2 * f1, f1, -f0, f2) * inv3);
321     }
322 
323     /** {@inheritDoc} */
324     @Override
325     public UnivariateDerivative2 compose(final double... f) {
326         MathUtils.checkDimension(f.length, getOrder() + 1);
327         return new UnivariateDerivative2(f[0],
328                                          f[1] * f1,
329                                          MathArrays.linearCombination(f[1], f2, f[2], f1 * f1));
330     }
331 
332     /** {@inheritDoc} */
333     @Override
334     public UnivariateDerivative2 sqrt() {
335         final double s0 = FastMath.sqrt(f0);
336         final double s0twice = 2. * s0;
337         final double s1 = f1 / s0twice;
338         final double s2 = (f2 - 2. * s1 * s1) / s0twice;
339         return new UnivariateDerivative2(s0, s1, s2);
340     }
341 
342     /** {@inheritDoc} */
343     @Override
344     public UnivariateDerivative2 cbrt() {
345         final double c  = FastMath.cbrt(f0);
346         final double c2 = c * c;
347         return compose(c, 1 / (3 * c2), -1 / (4.5 * c2 * f0));
348     }
349 
350     /** {@inheritDoc} */
351     @Override
352     public UnivariateDerivative2 rootN(final int n) {
353         if (n == 2) {
354             return sqrt();
355         } else if (n == 3) {
356             return cbrt();
357         } else {
358             final double r = FastMath.pow(f0, 1.0 / n);
359             final double z = n * FastMath.pow(r, n - 1);
360             return compose(r, 1 / z, (1 - n) / (z * z * r));
361         }
362     }
363 
364     /** {@inheritDoc} */
365     @Override
366     public UnivariateDerivative2Field getField() {
367         return UnivariateDerivative2Field.getInstance();
368     }
369 
370     /** Compute a<sup>x</sup> where a is a double and x a {@link UnivariateDerivative2}
371      * @param a number to exponentiate
372      * @param x power to apply
373      * @return a<sup>x</sup>
374      */
375     public static UnivariateDerivative2 pow(final double a, final UnivariateDerivative2 x) {
376         if (a == 0) {
377             return x.getField().getZero();
378         } else {
379             final double aX    = FastMath.pow(a, x.f0);
380             final double lnA   = FastMath.log(a);
381             final double aXlnA = aX * lnA;
382             return new UnivariateDerivative2(aX, aXlnA * x.f1, aXlnA * (x.f1 * x.f1 * lnA + x.f2));
383         }
384     }
385 
386     /** {@inheritDoc} */
387     @Override
388     public UnivariateDerivative2 pow(final double p) {
389         if (p == 0) {
390             return getField().getOne();
391         } else {
392             final double f0Pm2 = FastMath.pow(f0, p - 2);
393             final double f0Pm1 = f0Pm2 * f0;
394             final double f0P   = f0Pm1 * f0;
395             return compose(f0P, p * f0Pm1, p * (p - 1) * f0Pm2);
396         }
397     }
398 
399     /** {@inheritDoc} */
400     @Override
401     public UnivariateDerivative2 pow(final int n) {
402         if (n == 0) {
403             return getField().getOne();
404         } else {
405             final double f0Nm2 = FastMath.pow(f0, n - 2);
406             final double f0Nm1 = f0Nm2 * f0;
407             final double f0N   = f0Nm1 * f0;
408             return compose(f0N, n * f0Nm1, n * (n - 1) * f0Nm2);
409         }
410     }
411 
412     /** {@inheritDoc} */
413     @Override
414     public UnivariateDerivative2 exp() {
415         final double exp = FastMath.exp(f0);
416         return compose(exp, exp, exp);
417     }
418 
419     /** {@inheritDoc} */
420     @Override
421     public UnivariateDerivative2 expm1() {
422         final double exp   = FastMath.exp(f0);
423         final double expM1 = FastMath.expm1(f0);
424         return compose(expM1, exp, exp);
425     }
426 
427     /** {@inheritDoc} */
428     @Override
429     public UnivariateDerivative2 log() {
430         final double inv = 1 / f0;
431         return compose(FastMath.log(f0), inv, -inv * inv);
432     }
433 
434     /** {@inheritDoc} */
435     @Override
436     public UnivariateDerivative2 log1p() {
437         final double inv = 1 / (1 + f0);
438         return compose(FastMath.log1p(f0), inv, -inv * inv);
439     }
440 
441     /** {@inheritDoc} */
442     @Override
443     public UnivariateDerivative2 log10() {
444         final double invF0 = 1 / f0;
445         final double inv = invF0 / FastMath.log(10.0);
446         return compose(FastMath.log10(f0), inv, -inv * invF0);
447     }
448 
449     /** {@inheritDoc} */
450     @Override
451     public UnivariateDerivative2 cos() {
452         final SinCos sinCos = FastMath.sinCos(f0);
453         return compose(sinCos.cos(), -sinCos.sin(), -sinCos.cos());
454     }
455 
456     /** {@inheritDoc} */
457     @Override
458     public UnivariateDerivative2 sin() {
459         final SinCos sinCos = FastMath.sinCos(f0);
460         return compose(sinCos.sin(), sinCos.cos(), -sinCos.sin());
461     }
462 
463     /** {@inheritDoc} */
464     @Override
465     public FieldSinCos<UnivariateDerivative2> sinCos() {
466         final SinCos sinCos = FastMath.sinCos(f0);
467         return new FieldSinCos<>(compose(sinCos.sin(),  sinCos.cos(), -sinCos.sin()),
468                                  compose(sinCos.cos(), -sinCos.sin(), -sinCos.cos()));
469     }
470 
471     /** {@inheritDoc} */
472     @Override
473     public UnivariateDerivative2 tan() {
474         final double tan  = FastMath.tan(f0);
475         final double sec2 = 1 + tan * tan;
476         return compose(tan, sec2, 2 * sec2 * tan);
477     }
478 
479     /** {@inheritDoc} */
480     @Override
481     public UnivariateDerivative2 acos() {
482         final double inv = 1.0 / (1 - f0 * f0);
483         final double mS  = -FastMath.sqrt(inv);
484         return compose(FastMath.acos(f0), mS, mS * f0 * inv);
485     }
486 
487     /** {@inheritDoc} */
488     @Override
489     public UnivariateDerivative2 asin() {
490         final double inv = 1.0 / (1 - f0 * f0);
491         final double s   = FastMath.sqrt(inv);
492         return compose(FastMath.asin(f0), s, s * f0 * inv);
493     }
494 
495     /** {@inheritDoc} */
496     @Override
497     public UnivariateDerivative2 atan() {
498         final double inv = 1 / (1 + f0 * f0);
499         return compose(FastMath.atan(f0), inv, -2 * f0 * inv * inv);
500     }
501 
502     /** {@inheritDoc} */
503     @Override
504     public UnivariateDerivative2 atan2(final UnivariateDerivative2 x) {
505         final double x2    = x.f0 * x.f0;
506         final double f02   = f0 + f0;
507         final double inv   = 1.0 / (f0 * f0 + x2);
508         final double atan0 = FastMath.atan2(f0, x.f0);
509         final double atan1 = MathArrays.linearCombination(x.f0, f1, -x.f1, f0) * inv;
510         final double c     = MathArrays.linearCombination(f2, x2,
511                                                           -2 * f1, x.f0 * x.f1,
512                                                           f02, x.f1 * x.f1,
513                                                           -f0, x.f0 * x.f2) * inv;
514         return new UnivariateDerivative2(atan0, atan1, (c - f02 * atan1 * atan1) / x.f0);
515     }
516 
517     /** {@inheritDoc} */
518     @Override
519     public UnivariateDerivative2 cosh() {
520         final double c = FastMath.cosh(f0);
521         final double s = FastMath.sinh(f0);
522         return compose(c, s, c);
523     }
524 
525     /** {@inheritDoc} */
526     @Override
527     public UnivariateDerivative2 sinh() {
528         final double c = FastMath.cosh(f0);
529         final double s = FastMath.sinh(f0);
530         return compose(s, c, s);
531     }
532 
533     /** {@inheritDoc} */
534     @Override
535     public FieldSinhCosh<UnivariateDerivative2> sinhCosh() {
536         final SinhCosh sinhCosh = FastMath.sinhCosh(f0);
537         return new FieldSinhCosh<>(compose(sinhCosh.sinh(), sinhCosh.cosh(), sinhCosh.sinh()),
538                                    compose(sinhCosh.cosh(), sinhCosh.sinh(), sinhCosh.cosh()));
539     }
540 
541     /** {@inheritDoc} */
542     @Override
543     public UnivariateDerivative2 tanh() {
544         final double tanh  = FastMath.tanh(f0);
545         final double sech2 = 1 - tanh * tanh;
546         return compose(tanh, sech2, -2 * sech2 * tanh);
547     }
548 
549     /** {@inheritDoc} */
550     @Override
551     public UnivariateDerivative2 acosh() {
552         final double inv = 1 / (f0 * f0 - 1);
553         final double s   = FastMath.sqrt(inv);
554         return compose(FastMath.acosh(f0), s, -f0 * s * inv);
555     }
556 
557     /** {@inheritDoc} */
558     @Override
559     public UnivariateDerivative2 asinh() {
560         final double inv = 1 / (f0 * f0 + 1);
561         final double s   = FastMath.sqrt(inv);
562         return compose(FastMath.asinh(f0), s, -f0 * s * inv);
563     }
564 
565     /** {@inheritDoc} */
566     @Override
567     public UnivariateDerivative2 atanh() {
568         final double inv = 1 / (1 - f0 * f0);
569         return compose(FastMath.atanh(f0), inv, 2 * f0 * inv * inv);
570     }
571 
572     /** {@inheritDoc} */
573     @Override
574     public UnivariateDerivative2 toDegrees() {
575         return new UnivariateDerivative2(FastMath.toDegrees(f0), FastMath.toDegrees(f1), FastMath.toDegrees(f2));
576     }
577 
578     /** {@inheritDoc} */
579     @Override
580     public UnivariateDerivative2 toRadians() {
581         return new UnivariateDerivative2(FastMath.toRadians(f0), FastMath.toRadians(f1), FastMath.toRadians(f2));
582     }
583 
584     /** Evaluate Taylor expansion a univariate derivative.
585      * @param delta parameter offset Δx
586      * @return value of the Taylor expansion at x + Δx
587      */
588     public double taylor(final double delta) {
589         return f0 + delta * (f1 + 0.5 * delta * f2);
590     }
591 
592     /** {@inheritDoc} */
593     @Override
594     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2[] a, final UnivariateDerivative2[] b) {
595 
596         // extract values and derivatives
597         final int      n  = a.length;
598         final double[] a0 = new double[n];
599         final double[] b0 = new double[n];
600         final double[] a1 = new double[2 * n];
601         final double[] b1 = new double[2 * n];
602         final double[] a2 = new double[3 * n];
603         final double[] b2 = new double[3 * n];
604         for (int i = 0; i < n; ++i) {
605             final UnivariateDerivative2 ai = a[i];
606             final UnivariateDerivative2 bi = b[i];
607             a0[i]         = ai.f0;
608             b0[i]         = bi.f0;
609             a1[2 * i]     = ai.f0;
610             a1[2 * i + 1] = ai.f1;
611             b1[2 * i]     = bi.f1;
612             b1[2 * i + 1] = bi.f0;
613             a2[3 * i]     = ai.f0;
614             a2[3 * i + 1] = ai.f1 + ai.f1;
615             a2[3 * i + 2] = ai.f2;
616             b2[3 * i]     = bi.f2;
617             b2[3 * i + 1] = bi.f1;
618             b2[3 * i + 2] = bi.f0;
619         }
620 
621         return new UnivariateDerivative2(MathArrays.linearCombination(a0, b0),
622                                          MathArrays.linearCombination(a1, b1),
623                                          MathArrays.linearCombination(a2, b2));
624 
625     }
626 
627     /** {@inheritDoc} */
628     @Override
629     public UnivariateDerivative2 linearCombination(final double[] a, final UnivariateDerivative2[] b) {
630 
631         // extract values and derivatives
632         final int      n  = b.length;
633         final double[] b0 = new double[n];
634         final double[] b1 = new double[n];
635         final double[] b2 = new double[n];
636         for (int i = 0; i < n; ++i) {
637             b0[i] = b[i].f0;
638             b1[i] = b[i].f1;
639             b2[i] = b[i].f2;
640         }
641 
642         return new UnivariateDerivative2(MathArrays.linearCombination(a, b0),
643                                          MathArrays.linearCombination(a, b1),
644                                          MathArrays.linearCombination(a, b2));
645 
646     }
647 
648     /** {@inheritDoc} */
649     @Override
650     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
651                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2) {
652         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
653                                                                       a2.f0, b2.f0),
654                                          MathArrays.linearCombination(a1.f0, b1.f1,
655                                                                       a1.f1, b1.f0,
656                                                                       a2.f0, b2.f1,
657                                                                       a2.f1, b2.f0),
658                                          MathArrays.linearCombination(new double[] {
659                                                                           a1.f0, 2 * a1.f1, a1.f2,
660                                                                           a2.f0, 2 * a2.f1, a2.f2
661                                                                       }, new double[] {
662                                                                           b1.f2, b1.f1, b1.f0,
663                                                                           b2.f2, b2.f1, b2.f0
664                                                                       }));
665     }
666 
667     /** {@inheritDoc} */
668     @Override
669     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
670                                                    final double a2, final UnivariateDerivative2 b2) {
671         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
672                                                                       a2, b2.f0),
673                                          MathArrays.linearCombination(a1, b1.f1,
674                                                                       a2, b2.f1),
675                                          MathArrays.linearCombination(a1, b1.f2,
676                                                                       a2, b2.f2));
677     }
678 
679     /** {@inheritDoc} */
680     @Override
681     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
682                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2,
683                                                    final UnivariateDerivative2 a3, final UnivariateDerivative2 b3) {
684         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
685                                                                       a2.f0, b2.f0,
686                                                                       a3.f0, b3.f0),
687                                          MathArrays.linearCombination(new double[] {
688                                                                           a1.f0, a1.f1,
689                                                                           a2.f0, a2.f1,
690                                                                           a3.f0, a3.f1
691                                                                       }, new double[] {
692                                                                           b1.f1, b1.f0,
693                                                                           b2.f1, b2.f0,
694                                                                           b3.f1, b3.f0
695                                                                       }),
696                                          MathArrays.linearCombination(new double[] {
697                                                                           a1.f0, 2 * a1.f1, a1.f2,
698                                                                           a2.f0, 2 * a2.f1, a2.f2,
699                                                                           a3.f0, 2 * a3.f1, a3.f2
700                                                                       }, new double[] {
701                                                                           b1.f2, b1.f1, b1.f0,
702                                                                           b2.f2, b2.f1, b2.f0,
703                                                                           b3.f2, b3.f1, b3.f0
704                                                                       }));
705     }
706 
707     /** {@inheritDoc} */
708     @Override
709     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
710                                                    final double a2, final UnivariateDerivative2 b2,
711                                                    final double a3, final UnivariateDerivative2 b3) {
712         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
713                                                                       a2, b2.f0,
714                                                                       a3, b3.f0),
715                                          MathArrays.linearCombination(a1, b1.f1,
716                                                                       a2, b2.f1,
717                                                                       a3, b3.f1),
718                                          MathArrays.linearCombination(a1, b1.f2,
719                                                                       a2, b2.f2,
720                                                                       a3, b3.f2));
721     }
722 
723     /** {@inheritDoc} */
724     @Override
725     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
726                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2,
727                                                    final UnivariateDerivative2 a3, final UnivariateDerivative2 b3,
728                                                    final UnivariateDerivative2 a4, final UnivariateDerivative2 b4) {
729         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
730                                                                       a2.f0, b2.f0,
731                                                                       a3.f0, b3.f0,
732                                                                       a4.f0, b4.f0),
733                                          MathArrays.linearCombination(new double[] {
734                                                                           a1.f0, a1.f1,
735                                                                           a2.f0, a2.f1,
736                                                                           a3.f0, a3.f1,
737                                                                           a4.f0, a4.f1
738                                                                       }, new double[] {
739                                                                           b1.f1, b1.f0,
740                                                                           b2.f1, b2.f0,
741                                                                           b3.f1, b3.f0,
742                                                                           b4.f1, b4.f0
743                                                                       }),
744                                          MathArrays.linearCombination(new double[] {
745                                                                           a1.f0, 2 * a1.f1, a1.f2,
746                                                                           a2.f0, 2 * a2.f1, a2.f2,
747                                                                           a3.f0, 2 * a3.f1, a3.f2,
748                                                                           a4.f0, 2 * a4.f1, a4.f2
749                                                                       }, new double[] {
750                                                                           b1.f2, b1.f1, b1.f0,
751                                                                           b2.f2, b2.f1, b2.f0,
752                                                                           b3.f2, b3.f1, b3.f0,
753                                                                           b4.f2, b4.f1, b4.f0
754                                                                       }));
755     }
756 
757     /** {@inheritDoc} */
758     @Override
759     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
760                                                    final double a2, final UnivariateDerivative2 b2,
761                                                    final double a3, final UnivariateDerivative2 b3,
762                                                    final double a4, final UnivariateDerivative2 b4) {
763         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
764                                                                       a2, b2.f0,
765                                                                       a3, b3.f0,
766                                                                       a4, b4.f0),
767                                          MathArrays.linearCombination(a1, b1.f1,
768                                                                       a2, b2.f1,
769                                                                       a3, b3.f1,
770                                                                       a4, b4.f1),
771                                          MathArrays.linearCombination(a1, b1.f2,
772                                                                       a2, b2.f2,
773                                                                       a3, b3.f2,
774                                                                       a4, b4.f2));
775     }
776 
777     /** {@inheritDoc} */
778     @Override
779     public UnivariateDerivative2 getPi() {
780         return PI;
781     }
782 
783     /** Test for the equality of two univariate derivatives.
784      * <p>
785      * univariate derivatives are considered equal if they have the same derivatives.
786      * </p>
787      * @param other Object to test for equality to this
788      * @return true if two univariate derivatives are equal
789      */
790     @Override
791     public boolean equals(Object other) {
792 
793         if (this == other) {
794             return true;
795         }
796 
797         if (other instanceof UnivariateDerivative2) {
798             final UnivariateDerivative2 rhs = (UnivariateDerivative2) other;
799             return f0 == rhs.f0 && f1 == rhs.f1 && f2 == rhs.f2;
800         }
801 
802         return false;
803 
804     }
805 
806     /** Get a hashCode for the univariate derivative.
807      * @return a hash code value for this object
808      */
809     @Override
810     public int hashCode() {
811         return 317 - 41 * Double.hashCode(f0) + 57 * Double.hashCode(f1) - 103 * Double.hashCode(f2);
812     }
813 
814     /** {@inheritDoc}
815      * <p>
816      * Comparison performed considering that derivatives are intrinsically linked to monomials in the corresponding
817      * Taylor expansion and that the higher the degree, the smaller the term.
818      * </p>
819      * @since 3.0
820      */
821     @Override
822     public int compareTo(final UnivariateDerivative2 o) {
823         final int cF0 = Double.compare(f0, o.getReal());
824         if (cF0 == 0) {
825             final int cF1 = Double.compare(f1, o.getFirstDerivative());
826             if (cF1 == 0) {
827                 return Double.compare(f2, o.getSecondDerivative());
828             } else {
829                 return cF1;
830             }
831         } else {
832             return cF0;
833         }
834     }
835 
836 }