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