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 x2    = x.f0 * x.f0;
513         final double f02   = f0 + f0;
514         final double inv   = 1.0 / (f0 * f0 + x2);
515         final double atan0 = FastMath.atan2(f0, x.f0);
516         final double atan1 = MathArrays.linearCombination(x.f0, f1, -x.f1, f0) * inv;
517         final double c     = MathArrays.linearCombination(f2, x2,
518                                                           -2 * f1, x.f0 * x.f1,
519                                                           f02, x.f1 * x.f1,
520                                                           -f0, x.f0 * x.f2) * inv;
521         return new UnivariateDerivative2(atan0, atan1, (c - f02 * atan1 * atan1) / x.f0);
522     }
523 
524     /** {@inheritDoc} */
525     @Override
526     public UnivariateDerivative2 cosh() {
527         final double c = FastMath.cosh(f0);
528         final double s = FastMath.sinh(f0);
529         return compose(c, s, c);
530     }
531 
532     /** {@inheritDoc} */
533     @Override
534     public UnivariateDerivative2 sinh() {
535         final double c = FastMath.cosh(f0);
536         final double s = FastMath.sinh(f0);
537         return compose(s, c, s);
538     }
539 
540     /** {@inheritDoc} */
541     @Override
542     public FieldSinhCosh<UnivariateDerivative2> sinhCosh() {
543         final SinhCosh sinhCosh = FastMath.sinhCosh(f0);
544         return new FieldSinhCosh<>(compose(sinhCosh.sinh(), sinhCosh.cosh(), sinhCosh.sinh()),
545                                    compose(sinhCosh.cosh(), sinhCosh.sinh(), sinhCosh.cosh()));
546     }
547 
548     /** {@inheritDoc} */
549     @Override
550     public UnivariateDerivative2 tanh() {
551         final double tanh  = FastMath.tanh(f0);
552         final double sech2 = 1 - tanh * tanh;
553         return compose(tanh, sech2, -2 * sech2 * tanh);
554     }
555 
556     /** {@inheritDoc} */
557     @Override
558     public UnivariateDerivative2 acosh() {
559         final double inv = 1 / (f0 * f0 - 1);
560         final double s   = FastMath.sqrt(inv);
561         return compose(FastMath.acosh(f0), s, -f0 * s * inv);
562     }
563 
564     /** {@inheritDoc} */
565     @Override
566     public UnivariateDerivative2 asinh() {
567         final double inv = 1 / (f0 * f0 + 1);
568         final double s   = FastMath.sqrt(inv);
569         return compose(FastMath.asinh(f0), s, -f0 * s * inv);
570     }
571 
572     /** {@inheritDoc} */
573     @Override
574     public UnivariateDerivative2 atanh() {
575         final double inv = 1 / (1 - f0 * f0);
576         return compose(FastMath.atanh(f0), inv, 2 * f0 * inv * inv);
577     }
578 
579     /** {@inheritDoc} */
580     @Override
581     public UnivariateDerivative2 toDegrees() {
582         return new UnivariateDerivative2(FastMath.toDegrees(f0), FastMath.toDegrees(f1), FastMath.toDegrees(f2));
583     }
584 
585     /** {@inheritDoc} */
586     @Override
587     public UnivariateDerivative2 toRadians() {
588         return new UnivariateDerivative2(FastMath.toRadians(f0), FastMath.toRadians(f1), FastMath.toRadians(f2));
589     }
590 
591     /** Evaluate Taylor expansion a univariate derivative.
592      * @param delta parameter offset Δx
593      * @return value of the Taylor expansion at x + Δx
594      */
595     public double taylor(final double delta) {
596         return f0 + delta * (f1 + 0.5 * delta * f2);
597     }
598 
599     /** {@inheritDoc} */
600     @Override
601     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2[] a, final UnivariateDerivative2[] b) {
602 
603         // extract values and derivatives
604         final int      n  = a.length;
605         final double[] a0 = new double[n];
606         final double[] b0 = new double[n];
607         final double[] a1 = new double[2 * n];
608         final double[] b1 = new double[2 * n];
609         final double[] a2 = new double[3 * n];
610         final double[] b2 = new double[3 * n];
611         for (int i = 0; i < n; ++i) {
612             final UnivariateDerivative2 ai = a[i];
613             final UnivariateDerivative2 bi = b[i];
614             a0[i]         = ai.f0;
615             b0[i]         = bi.f0;
616             a1[2 * i]     = ai.f0;
617             a1[2 * i + 1] = ai.f1;
618             b1[2 * i]     = bi.f1;
619             b1[2 * i + 1] = bi.f0;
620             a2[3 * i]     = ai.f0;
621             a2[3 * i + 1] = ai.f1 + ai.f1;
622             a2[3 * i + 2] = ai.f2;
623             b2[3 * i]     = bi.f2;
624             b2[3 * i + 1] = bi.f1;
625             b2[3 * i + 2] = bi.f0;
626         }
627 
628         return new UnivariateDerivative2(MathArrays.linearCombination(a0, b0),
629                                          MathArrays.linearCombination(a1, b1),
630                                          MathArrays.linearCombination(a2, b2));
631 
632     }
633 
634     /** {@inheritDoc} */
635     @Override
636     public UnivariateDerivative2 linearCombination(final double[] a, final UnivariateDerivative2[] b) {
637 
638         // extract values and derivatives
639         final int      n  = b.length;
640         final double[] b0 = new double[n];
641         final double[] b1 = new double[n];
642         final double[] b2 = new double[n];
643         for (int i = 0; i < n; ++i) {
644             b0[i] = b[i].f0;
645             b1[i] = b[i].f1;
646             b2[i] = b[i].f2;
647         }
648 
649         return new UnivariateDerivative2(MathArrays.linearCombination(a, b0),
650                                          MathArrays.linearCombination(a, b1),
651                                          MathArrays.linearCombination(a, b2));
652 
653     }
654 
655     /** {@inheritDoc} */
656     @Override
657     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
658                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2) {
659         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
660                                                                       a2.f0, b2.f0),
661                                          MathArrays.linearCombination(a1.f0, b1.f1,
662                                                                       a1.f1, b1.f0,
663                                                                       a2.f0, b2.f1,
664                                                                       a2.f1, b2.f0),
665                                          MathArrays.linearCombination(new double[] {
666                                                                           a1.f0, 2 * a1.f1, a1.f2,
667                                                                           a2.f0, 2 * a2.f1, a2.f2
668                                                                       }, new double[] {
669                                                                           b1.f2, b1.f1, b1.f0,
670                                                                           b2.f2, b2.f1, b2.f0
671                                                                       }));
672     }
673 
674     /** {@inheritDoc} */
675     @Override
676     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
677                                                    final double a2, final UnivariateDerivative2 b2) {
678         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
679                                                                       a2, b2.f0),
680                                          MathArrays.linearCombination(a1, b1.f1,
681                                                                       a2, b2.f1),
682                                          MathArrays.linearCombination(a1, b1.f2,
683                                                                       a2, b2.f2));
684     }
685 
686     /** {@inheritDoc} */
687     @Override
688     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
689                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2,
690                                                    final UnivariateDerivative2 a3, final UnivariateDerivative2 b3) {
691         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
692                                                                       a2.f0, b2.f0,
693                                                                       a3.f0, b3.f0),
694                                          MathArrays.linearCombination(new double[] {
695                                                                           a1.f0, a1.f1,
696                                                                           a2.f0, a2.f1,
697                                                                           a3.f0, a3.f1
698                                                                       }, new double[] {
699                                                                           b1.f1, b1.f0,
700                                                                           b2.f1, b2.f0,
701                                                                           b3.f1, b3.f0
702                                                                       }),
703                                          MathArrays.linearCombination(new double[] {
704                                                                           a1.f0, 2 * a1.f1, a1.f2,
705                                                                           a2.f0, 2 * a2.f1, a2.f2,
706                                                                           a3.f0, 2 * a3.f1, a3.f2
707                                                                       }, new double[] {
708                                                                           b1.f2, b1.f1, b1.f0,
709                                                                           b2.f2, b2.f1, b2.f0,
710                                                                           b3.f2, b3.f1, b3.f0
711                                                                       }));
712     }
713 
714     /** {@inheritDoc} */
715     @Override
716     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
717                                                    final double a2, final UnivariateDerivative2 b2,
718                                                    final double a3, final UnivariateDerivative2 b3) {
719         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
720                                                                       a2, b2.f0,
721                                                                       a3, b3.f0),
722                                          MathArrays.linearCombination(a1, b1.f1,
723                                                                       a2, b2.f1,
724                                                                       a3, b3.f1),
725                                          MathArrays.linearCombination(a1, b1.f2,
726                                                                       a2, b2.f2,
727                                                                       a3, b3.f2));
728     }
729 
730     /** {@inheritDoc} */
731     @Override
732     public UnivariateDerivative2 linearCombination(final UnivariateDerivative2 a1, final UnivariateDerivative2 b1,
733                                                    final UnivariateDerivative2 a2, final UnivariateDerivative2 b2,
734                                                    final UnivariateDerivative2 a3, final UnivariateDerivative2 b3,
735                                                    final UnivariateDerivative2 a4, final UnivariateDerivative2 b4) {
736         return new UnivariateDerivative2(MathArrays.linearCombination(a1.f0, b1.f0,
737                                                                       a2.f0, b2.f0,
738                                                                       a3.f0, b3.f0,
739                                                                       a4.f0, b4.f0),
740                                          MathArrays.linearCombination(new double[] {
741                                                                           a1.f0, a1.f1,
742                                                                           a2.f0, a2.f1,
743                                                                           a3.f0, a3.f1,
744                                                                           a4.f0, a4.f1
745                                                                       }, new double[] {
746                                                                           b1.f1, b1.f0,
747                                                                           b2.f1, b2.f0,
748                                                                           b3.f1, b3.f0,
749                                                                           b4.f1, b4.f0
750                                                                       }),
751                                          MathArrays.linearCombination(new double[] {
752                                                                           a1.f0, 2 * a1.f1, a1.f2,
753                                                                           a2.f0, 2 * a2.f1, a2.f2,
754                                                                           a3.f0, 2 * a3.f1, a3.f2,
755                                                                           a4.f0, 2 * a4.f1, a4.f2
756                                                                       }, new double[] {
757                                                                           b1.f2, b1.f1, b1.f0,
758                                                                           b2.f2, b2.f1, b2.f0,
759                                                                           b3.f2, b3.f1, b3.f0,
760                                                                           b4.f2, b4.f1, b4.f0
761                                                                       }));
762     }
763 
764     /** {@inheritDoc} */
765     @Override
766     public UnivariateDerivative2 linearCombination(final double a1, final UnivariateDerivative2 b1,
767                                                    final double a2, final UnivariateDerivative2 b2,
768                                                    final double a3, final UnivariateDerivative2 b3,
769                                                    final double a4, final UnivariateDerivative2 b4) {
770         return new UnivariateDerivative2(MathArrays.linearCombination(a1, b1.f0,
771                                                                       a2, b2.f0,
772                                                                       a3, b3.f0,
773                                                                       a4, b4.f0),
774                                          MathArrays.linearCombination(a1, b1.f1,
775                                                                       a2, b2.f1,
776                                                                       a3, b3.f1,
777                                                                       a4, b4.f1),
778                                          MathArrays.linearCombination(a1, b1.f2,
779                                                                       a2, b2.f2,
780                                                                       a3, b3.f2,
781                                                                       a4, b4.f2));
782     }
783 
784     /** {@inheritDoc} */
785     @Override
786     public UnivariateDerivative2 getPi() {
787         return PI;
788     }
789 
790     /** Test for the equality of two univariate derivatives.
791      * <p>
792      * univariate derivatives are considered equal if they have the same derivatives.
793      * </p>
794      * @param other Object to test for equality to this
795      * @return true if two univariate derivatives are equal
796      */
797     @Override
798     public boolean equals(Object other) {
799 
800         if (this == other) {
801             return true;
802         }
803 
804         if (other instanceof UnivariateDerivative2) {
805             final UnivariateDerivative2 rhs = (UnivariateDerivative2) other;
806             return f0 == rhs.f0 && f1 == rhs.f1 && f2 == rhs.f2;
807         }
808 
809         return false;
810 
811     }
812 
813     /** Get a hashCode for the univariate derivative.
814      * @return a hash code value for this object
815      */
816     @Override
817     public int hashCode() {
818         return 317 - 41 * Double.hashCode(f0) + 57 * Double.hashCode(f1) - 103 * Double.hashCode(f2);
819     }
820 
821     /** {@inheritDoc}
822      * <p>
823      * Comparison performed considering that derivatives are intrinsically linked to monomials in the corresponding
824      * Taylor expansion and that the higher the degree, the smaller the term.
825      * </p>
826      * @since 3.0
827      */
828     @Override
829     public int compareTo(final UnivariateDerivative2 o) {
830         final int cF0 = Double.compare(f0, o.getReal());
831         if (cF0 == 0) {
832             final int cF1 = Double.compare(f1, o.getFirstDerivative());
833             if (cF1 == 0) {
834                 return Double.compare(f2, o.getSecondDerivative());
835             } else {
836                 return cF1;
837             }
838         } else {
839             return cF0;
840         }
841     }
842 
843 }