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