View Javadoc
1   /*
2    * Licensed to the Hipparchus project under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.hipparchus.analysis.differentiation;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.exception.LocalizedCoreFormats;
22  import org.hipparchus.exception.MathIllegalArgumentException;
23  import org.hipparchus.util.FastMath;
24  import org.hipparchus.util.MathArrays;
25  import org.hipparchus.util.MathUtils;
26  
27  /** Class representing both the value and the differentials of a function.
28   * <p>This class is a stripped-down version of {@link FieldDerivativeStructure}
29   * with only one {@link FieldDerivativeStructure#getFreeParameters() free parameter}
30   * and {@link FieldDerivativeStructure#getOrder() derivation order} also limited to one.
31   * It should have less overhead than {@link FieldDerivativeStructure} in its domain.</p>
32   * <p>This class is an implementation of Rall's numbers. Rall's numbers are an
33   * extension to the real numbers used throughout mathematical expressions; they hold
34   * the derivative together with the value of a function.</p>
35   * <p>{@link FieldUnivariateDerivative1} instances can be used directly thanks to
36   * the arithmetic operators to the mathematical functions provided as
37   * methods by this class (+, -, *, /, %, sin, cos ...).</p>
38   * <p>Implementing complex expressions by hand using {@link Derivative}-based
39   * classes (or in fact any {@link org.hipparchus.CalculusFieldElement} class) is
40   * a tedious and error-prone task but has the advantage of not requiring users
41   * to compute the derivatives by themselves and allowing to switch for one
42   * derivative implementation to another as they all share the same filed API.</p>
43   * <p>Instances of this class are guaranteed to be immutable.</p>
44   * @param <T> the type of the function parameters and value
45   * @see DerivativeStructure
46   * @see UnivariateDerivative1
47   * @see UnivariateDerivative2
48   * @see Gradient
49   * @see FieldDerivativeStructure
50   * @see FieldUnivariateDerivative2
51   * @see FieldGradient
52   * @since 1.7
53   */
54  public class FieldUnivariateDerivative1<T extends CalculusFieldElement<T>>
55      extends FieldUnivariateDerivative<T, FieldUnivariateDerivative1<T>>
56          implements FieldDerivative1<T, FieldUnivariateDerivative1<T>> {
57  
58      /** Value of the function. */
59      private final T f0;
60  
61      /** First derivative of the function. */
62      private final T f1;
63  
64      /** Build an instance with values and derivative.
65       * @param f0 value of the function
66       * @param f1 first derivative of the function
67       */
68      public FieldUnivariateDerivative1(final T f0, final T f1) {
69          this.f0 = f0;
70          this.f1 = f1;
71      }
72  
73      /** Build an instance from a {@link FieldDerivativeStructure}.
74       * @param ds derivative structure
75       * @exception MathIllegalArgumentException if either {@code ds} parameters
76       * is not 1 or {@code ds} order is not 1
77       */
78      public FieldUnivariateDerivative1(final FieldDerivativeStructure<T> ds) throws MathIllegalArgumentException {
79          MathUtils.checkDimension(ds.getFreeParameters(), 1);
80          MathUtils.checkDimension(ds.getOrder(), 1);
81          this.f0 = ds.getValue();
82          this.f1 = ds.getPartialDerivative(1);
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      public FieldUnivariateDerivative1<T> newInstance(final double value) {
88          final T zero = f0.getField().getZero();
89          return new FieldUnivariateDerivative1<>(zero.newInstance(value), zero);
90      }
91  
92      /** {@inheritDoc} */
93      @Override
94      public FieldUnivariateDerivative1<T> newInstance(final T value) {
95          final T zero = f0.getField().getZero();
96          return new FieldUnivariateDerivative1<>(value, zero);
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public FieldUnivariateDerivative1<T> withValue(final T value) {
102         return new FieldUnivariateDerivative1<>(value, f1);
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public FieldUnivariateDerivative1<T> getAddendum() {
108         return new FieldUnivariateDerivative1<>(f0.getField().getZero(), f1);
109     }
110 
111     /** Get the value part of the univariate derivative.
112      * @return value part of the univariate derivative
113      */
114     @Override
115     public T getValue() {
116         return f0;
117     }
118 
119     /** Get a derivative from the univariate derivative.
120      * @param n derivation order (must be between 0 and {@link #getOrder()}, both inclusive)
121      * @return n<sup>th</sup> derivative, or {@code NaN} if n is
122      * either negative or strictly larger than {@link #getOrder()}
123      */
124     @Override
125     public T getDerivative(final int n) {
126         switch (n) {
127             case 0 :
128                 return f0;
129             case 1 :
130                 return f1;
131             default :
132                 throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, n);
133         }
134     }
135 
136     /** Get the first derivative.
137      * @return first derivative
138      * @see #getValue()
139      */
140     public T getFirstDerivative() {
141         return f1;
142     }
143 
144     /** Get the {@link Field} the value and parameters of the function belongs to.
145      * @return {@link Field} the value and parameters of the function belongs to
146      */
147     public Field<T> getValueField() {
148         return f0.getField();
149     }
150 
151     /** Convert the instance to a {@link FieldDerivativeStructure}.
152      * @return derivative structure with same value and derivative as the instance
153      */
154     @Override
155     public FieldDerivativeStructure<T> toDerivativeStructure() {
156         return getField().getConversionFactory().build(f0, f1);
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public FieldUnivariateDerivative1<T> add(final double a) {
162         return new FieldUnivariateDerivative1<>(f0.add(a), f1);
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public FieldUnivariateDerivative1<T> add(final FieldUnivariateDerivative1<T> a) {
168         return new FieldUnivariateDerivative1<>(f0.add(a.f0), f1.add(a.f1));
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public FieldUnivariateDerivative1<T> subtract(final double a) {
174         return new FieldUnivariateDerivative1<>(f0.subtract(a), f1);
175     }
176 
177     /** {@inheritDoc} */
178     @Override
179     public FieldUnivariateDerivative1<T> subtract(final FieldUnivariateDerivative1<T> a) {
180         return new FieldUnivariateDerivative1<>(f0.subtract(a.f0), f1.subtract(a.f1));
181     }
182 
183     /** '&times;' operator.
184      * @param a right hand side parameter of the operator
185      * @return this&times;a
186      */
187     public FieldUnivariateDerivative1<T> multiply(final T a) {
188         return new FieldUnivariateDerivative1<>(f0.multiply(a), f1.multiply(a));
189     }
190 
191     /** {@inheritDoc} */
192     @Override
193     public FieldUnivariateDerivative1<T> multiply(final int n) {
194         return new FieldUnivariateDerivative1<>(f0.multiply(n), f1.multiply(n));
195     }
196 
197     /** {@inheritDoc} */
198     @Override
199     public FieldUnivariateDerivative1<T> multiply(final double a) {
200         return new FieldUnivariateDerivative1<>(f0.multiply(a), f1.multiply(a));
201     }
202 
203     /** {@inheritDoc} */
204     @Override
205     public FieldUnivariateDerivative1<T> multiply(final FieldUnivariateDerivative1<T> a) {
206         return new FieldUnivariateDerivative1<>(f0.multiply(a.f0),
207                                                 a.f0.linearCombination(f1, a.f0, f0, a.f1));
208     }
209 
210     /** '&divide;' operator.
211      * @param a right hand side parameter of the operator
212      * @return this&divide;a
213      */
214     public FieldUnivariateDerivative1<T> divide(final T a) {
215         final T inv1 = a.reciprocal();
216         return new FieldUnivariateDerivative1<>(f0.multiply(inv1), f1.multiply(inv1));
217     }
218 
219     /** {@inheritDoc} */
220     @Override
221     public FieldUnivariateDerivative1<T> divide(final double a) {
222         final double inv1 = 1.0 / a;
223         return new FieldUnivariateDerivative1<>(f0.multiply(inv1), f1.multiply(inv1));
224     }
225 
226     /** {@inheritDoc} */
227     @Override
228     public FieldUnivariateDerivative1<T> divide(final FieldUnivariateDerivative1<T> a) {
229         final T inv1 = a.f0.reciprocal();
230         final T inv2 = inv1.multiply(inv1);
231         return new FieldUnivariateDerivative1<>(f0.multiply(inv1),
232                                                 a.f0.linearCombination(f1, a.f0, f0.negate(), a.f1).multiply(inv2));
233     }
234 
235     /** IEEE remainder operator.
236      * @param a right hand side parameter of the operator
237      * @return this - n &times; a where n is the closest integer to this/a
238      * (the even integer is chosen for n if this/a is halfway between two integers)
239      */
240     public FieldUnivariateDerivative1<T> remainder(final T a) {
241         return new FieldUnivariateDerivative1<>(FastMath.IEEEremainder(f0, a), f1);
242     }
243 
244     /** {@inheritDoc} */
245     @Override
246     public FieldUnivariateDerivative1<T> remainder(final double a) {
247         return new FieldUnivariateDerivative1<>(FastMath.IEEEremainder(f0, a), f1);
248     }
249 
250     /** {@inheritDoc} */
251     @Override
252     public FieldUnivariateDerivative1<T> remainder(final FieldUnivariateDerivative1<T> a) {
253 
254         // compute k such that lhs % rhs = lhs - k rhs
255         final T rem = FastMath.IEEEremainder(f0, a.f0);
256         final T k   = FastMath.rint(f0.subtract(rem).divide(a.f0));
257 
258         return new FieldUnivariateDerivative1<>(rem, f1.subtract(k.multiply(a.f1)));
259 
260     }
261 
262     /** {@inheritDoc} */
263     @Override
264     public FieldUnivariateDerivative1<T> negate() {
265         return new FieldUnivariateDerivative1<>(f0.negate(), f1.negate());
266     }
267 
268     /** {@inheritDoc} */
269     @Override
270     public FieldUnivariateDerivative1<T> abs() {
271         if (Double.doubleToLongBits(f0.getReal()) < 0) {
272             // we use the bits representation to also handle -0.0
273             return negate();
274         } else {
275             return this;
276         }
277     }
278 
279     /**
280      * Returns the instance with the sign of the argument.
281      * A NaN {@code sign} argument is treated as positive.
282      *
283      * @param sign the sign for the returned value
284      * @return the instance with the same sign as the {@code sign} argument
285      */
286     public FieldUnivariateDerivative1<T> copySign(final T sign) {
287         long m = Double.doubleToLongBits(f0.getReal());
288         long s = Double.doubleToLongBits(sign.getReal());
289         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
290             return this;
291         }
292         return negate(); // flip sign
293     }
294 
295     /** {@inheritDoc} */
296     @Override
297     public FieldUnivariateDerivative1<T> copySign(final FieldUnivariateDerivative1<T> sign) {
298         long m = Double.doubleToLongBits(f0.getReal());
299         long s = Double.doubleToLongBits(sign.f0.getReal());
300         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
301             return this;
302         }
303         return negate(); // flip sign
304     }
305 
306     /** {@inheritDoc} */
307     @Override
308     public FieldUnivariateDerivative1<T> copySign(final double sign) {
309         long m = Double.doubleToLongBits(f0.getReal());
310         long s = Double.doubleToLongBits(sign);
311         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
312             return this;
313         }
314         return negate(); // flip sign
315     }
316 
317     /** {@inheritDoc} */
318     @Override
319     public FieldUnivariateDerivative1<T> scalb(final int n) {
320         return new FieldUnivariateDerivative1<>(FastMath.scalb(f0, n), FastMath.scalb(f1, n));
321     }
322 
323     /** {@inheritDoc} */
324     @Override
325     public FieldUnivariateDerivative1<T> hypot(final FieldUnivariateDerivative1<T> y) {
326 
327         if (Double.isInfinite(f0.getReal()) || Double.isInfinite(y.f0.getReal())) {
328             return new FieldUnivariateDerivative1<>(f0.newInstance(Double.POSITIVE_INFINITY),
329                                                     f0.getField().getZero());
330         } else if (Double.isNaN(f0.getReal()) || Double.isNaN(y.f0.getReal())) {
331             return new FieldUnivariateDerivative1<>(f0.newInstance(Double.NaN),
332                                                     f0.getField().getZero());
333         } else {
334 
335             final int expX = getExponent();
336             final int expY = y.getExponent();
337             if (expX > expY + 27) {
338                 // y is negligible with respect to x
339                 return abs();
340             } else if (expY > expX + 27) {
341                 // x is negligible with respect to y
342                 return y.abs();
343             } else {
344 
345                 // find an intermediate scale to avoid both overflow and underflow
346                 final int middleExp = (expX + expY) / 2;
347 
348                 // scale parameters without losing precision
349                 final FieldUnivariateDerivative1<T> scaledX = scalb(-middleExp);
350                 final FieldUnivariateDerivative1<T> scaledY = y.scalb(-middleExp);
351 
352                 // compute scaled hypotenuse
353                 final FieldUnivariateDerivative1<T> scaledH =
354                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
355 
356                 // remove scaling
357                 return scaledH.scalb(middleExp);
358 
359             }
360 
361         }
362     }
363 
364     /** Compute composition of the instance by a function.
365      * @param g0 value of the function at the current point (i.e. at {@code g(getValue())})
366      * @param g1 first derivative of the function at the current point (i.e. at {@code g'(getValue())})
367      * @return g(this)
368      */
369     @Override
370     public FieldUnivariateDerivative1<T> compose(final T g0, final T g1) {
371         return new FieldUnivariateDerivative1<>(g0, g1.multiply(f1));
372     }
373 
374     /** {@inheritDoc} */
375     @Override
376     public FieldUnivariateDerivative1<T> rootN(final int n) {
377         if (n == 2) {
378             return sqrt();
379         } else if (n == 3) {
380             return cbrt();
381         } else {
382             final T r = FastMath.pow(f0, 1.0 / n);
383             return compose(r, FastMath.pow(r, n - 1).multiply(n).reciprocal());
384         }
385     }
386 
387     /** {@inheritDoc} */
388     @Override
389     public FieldUnivariateDerivative1Field<T> getField() {
390         return FieldUnivariateDerivative1Field.getUnivariateDerivative1Field(f0.getField());
391     }
392 
393     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldUnivariateDerivative1}
394      * @param a number to exponentiate
395      * @param x power to apply
396      * @param <T> the type of the function parameters and value
397      * @return a<sup>x</sup>
398      */
399     public static <T extends CalculusFieldElement<T>> FieldUnivariateDerivative1<T> pow(final double a, final FieldUnivariateDerivative1<T> x) {
400         if (a == 0) {
401             return x.getField().getZero();
402         } else {
403             final T aX = FastMath.pow(x.f0.newInstance(a), x.f0);
404             return new FieldUnivariateDerivative1<>(aX, aX.multiply(FastMath.log(a)).multiply(x.f1));
405         }
406     }
407 
408     /** {@inheritDoc} */
409     @Override
410     public FieldUnivariateDerivative1<T> pow(final double p) {
411         if (p == 0) {
412             return getField().getOne();
413         } else {
414             final T f0Pm1 = FastMath.pow(f0, p - 1);
415             return compose(f0Pm1.multiply(f0), f0Pm1.multiply(p));
416         }
417     }
418 
419     /** {@inheritDoc} */
420     @Override
421     public FieldUnivariateDerivative1<T> pow(final int n) {
422         if (n == 0) {
423             return getField().getOne();
424         } else {
425             final T f0Nm1 = FastMath.pow(f0, n - 1);
426             return compose(f0Nm1.multiply(f0), f0Nm1.multiply(n));
427         }
428     }
429 
430     /** {@inheritDoc} */
431     @Override
432     public FieldUnivariateDerivative1<T> atan2(final FieldUnivariateDerivative1<T> x) {
433         final T inv = f0.square().add(x.f0.multiply(x.f0)).reciprocal();
434         return new FieldUnivariateDerivative1<>(FastMath.atan2(f0, x.f0),
435                                                 f0.linearCombination(x.f0, f1, x.f1.negate(), f0).multiply(inv));
436     }
437 
438     /** {@inheritDoc} */
439     @Override
440     public FieldUnivariateDerivative1<T> toDegrees() {
441         return new FieldUnivariateDerivative1<>(FastMath.toDegrees(f0), FastMath.toDegrees(f1));
442     }
443 
444     /** {@inheritDoc} */
445     @Override
446     public FieldUnivariateDerivative1<T> toRadians() {
447         return new FieldUnivariateDerivative1<>(FastMath.toRadians(f0), FastMath.toRadians(f1));
448     }
449 
450     /** Evaluate Taylor expansion of a univariate derivative.
451      * @param delta parameter offset Δx
452      * @return value of the Taylor expansion at x + Δx
453      */
454     public T taylor(final double delta) {
455         return f0.add(f1.multiply(delta));
456     }
457 
458     /** Evaluate Taylor expansion of a univariate derivative.
459      * @param delta parameter offset Δx
460      * @return value of the Taylor expansion at x + Δx
461      */
462     public T taylor(final T delta) {
463         return f0.add(f1.multiply(delta));
464     }
465 
466     /**
467      * Compute a linear combination.
468      * @param a Factors.
469      * @param b Factors.
470      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
471      * @throws MathIllegalArgumentException if arrays dimensions don't match
472      */
473     public FieldUnivariateDerivative1<T> linearCombination(final T[] a, final FieldUnivariateDerivative1<T>[] b) {
474 
475         // extract values and first derivatives
476         final Field<T> field = b[0].f0.getField();
477         final int      n  = b.length;
478         final T[] b0 = MathArrays.buildArray(field, n);
479         final T[] b1 = MathArrays.buildArray(field, n);
480         for (int i = 0; i < n; ++i) {
481             b0[i] = b[i].f0;
482             b1[i] = b[i].f1;
483         }
484 
485         return new FieldUnivariateDerivative1<>(b[0].f0.linearCombination(a, b0),
486                                                 b[0].f0.linearCombination(a, b1));
487 
488     }
489 
490     /** {@inheritDoc} */
491     @Override
492     public FieldUnivariateDerivative1<T> linearCombination(final FieldUnivariateDerivative1<T>[] a,
493                                                            final FieldUnivariateDerivative1<T>[] b) {
494 
495         // extract values and first derivatives
496         final Field<T> field = a[0].f0.getField();
497         final int n  = a.length;
498         final T[] a0 = MathArrays.buildArray(field, n);
499         final T[] b0 = MathArrays.buildArray(field, n);
500         final T[] a1 = MathArrays.buildArray(field, 2 * n);
501         final T[] b1 = MathArrays.buildArray(field, 2 * n);
502         for (int i = 0; i < n; ++i) {
503             final FieldUnivariateDerivative1<T> ai = a[i];
504             final FieldUnivariateDerivative1<T> bi = b[i];
505             a0[i]         = ai.f0;
506             b0[i]         = bi.f0;
507             a1[2 * i]     = ai.f0;
508             a1[2 * i + 1] = ai.f1;
509             b1[2 * i]     = bi.f1;
510             b1[2 * i + 1] = bi.f0;
511         }
512 
513         return new FieldUnivariateDerivative1<>(a[0].f0.linearCombination(a0, b0),
514                                                 a[0].f0.linearCombination(a1, b1));
515 
516     }
517 
518     /** {@inheritDoc} */
519     @Override
520     public FieldUnivariateDerivative1<T> linearCombination(final double[] a, final FieldUnivariateDerivative1<T>[] b) {
521 
522         // extract values and first derivatives
523         final Field<T> field = b[0].f0.getField();
524         final int      n  = b.length;
525         final T[] b0 = MathArrays.buildArray(field, n);
526         final T[] b1 = MathArrays.buildArray(field, n);
527         for (int i = 0; i < n; ++i) {
528             b0[i] = b[i].f0;
529             b1[i] = b[i].f1;
530         }
531 
532         return new FieldUnivariateDerivative1<>(b[0].f0.linearCombination(a, b0),
533                                                 b[0].f0.linearCombination(a, b1));
534 
535     }
536 
537     /** {@inheritDoc} */
538     @Override
539     public FieldUnivariateDerivative1<T> linearCombination(final FieldUnivariateDerivative1<T> a1, final FieldUnivariateDerivative1<T> b1,
540                                                            final FieldUnivariateDerivative1<T> a2, final FieldUnivariateDerivative1<T> b2) {
541         return new FieldUnivariateDerivative1<>(a1.f0.linearCombination(a1.f0, b1.f0,
542                                                                         a2.f0, b2.f0),
543                                                 a1.f0.linearCombination(a1.f0, b1.f1,
544                                                                         a1.f1, b1.f0,
545                                                                         a2.f0, b2.f1,
546                                                                         a2.f1, b2.f0));
547     }
548 
549     /** {@inheritDoc} */
550     @Override
551     public FieldUnivariateDerivative1<T> linearCombination(final double a1, final FieldUnivariateDerivative1<T> b1,
552                                                            final double a2, final FieldUnivariateDerivative1<T> b2) {
553         return new FieldUnivariateDerivative1<>(b1.f0.linearCombination(a1, b1.f0,
554                                                                         a2, b2.f0),
555                                                 b1.f0.linearCombination(a1, b1.f1,
556                                                                         a2, b2.f1));
557     }
558 
559     /** {@inheritDoc} */
560     @Override
561     public FieldUnivariateDerivative1<T> linearCombination(final FieldUnivariateDerivative1<T> a1, final FieldUnivariateDerivative1<T> b1,
562                                                            final FieldUnivariateDerivative1<T> a2, final FieldUnivariateDerivative1<T> b2,
563                                                            final FieldUnivariateDerivative1<T> a3, final FieldUnivariateDerivative1<T> b3) {
564         final Field<T> field = a1.f0.getField();
565         final T[] a = MathArrays.buildArray(field, 6);
566         final T[] b = MathArrays.buildArray(field, 6);
567         a[0] = a1.f0;
568         a[1] = a1.f1;
569         a[2] = a2.f0;
570         a[3] = a2.f1;
571         a[4] = a3.f0;
572         a[5] = a3.f1;
573         b[0] = b1.f1;
574         b[1] = b1.f0;
575         b[2] = b2.f1;
576         b[3] = b2.f0;
577         b[4] = b3.f1;
578         b[5] = b3.f0;
579         return new FieldUnivariateDerivative1<>(a1.f0.linearCombination(a1.f0, b1.f0,
580                                                                         a2.f0, b2.f0,
581                                                                         a3.f0, b3.f0),
582                                                 a1.f0.linearCombination(a, b));
583     }
584 
585     /**
586      * Compute a linear combination.
587      * @param a1 first factor of the first term
588      * @param b1 second factor of the first term
589      * @param a2 first factor of the second term
590      * @param b2 second factor of the second term
591      * @param a3 first factor of the third term
592      * @param b3 second factor of the third term
593      * @return a<sub>1</sub>&times;b<sub>1</sub> +
594      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
595      * @see #linearCombination(double, FieldUnivariateDerivative1, double, FieldUnivariateDerivative1)
596      * @see #linearCombination(double, FieldUnivariateDerivative1, double, FieldUnivariateDerivative1, double, FieldUnivariateDerivative1, double, FieldUnivariateDerivative1)
597      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
598      */
599     public FieldUnivariateDerivative1<T> linearCombination(final T a1, final FieldUnivariateDerivative1<T> b1,
600                                                            final T a2, final FieldUnivariateDerivative1<T> b2,
601                                                            final T a3, final FieldUnivariateDerivative1<T> b3) {
602         return new FieldUnivariateDerivative1<>(b1.f0.linearCombination(a1, b1.f0,
603                                                                         a2, b2.f0,
604                                                                         a3, b3.f0),
605                                                 b1.f0.linearCombination(a1, b1.f1,
606                                                                         a2, b2.f1,
607                                                                         a3, b3.f1));
608     }
609 
610     /** {@inheritDoc} */
611     @Override
612     public FieldUnivariateDerivative1<T> linearCombination(final double a1, final FieldUnivariateDerivative1<T> b1,
613                                                            final double a2, final FieldUnivariateDerivative1<T> b2,
614                                                            final double a3, final FieldUnivariateDerivative1<T> b3) {
615         return new FieldUnivariateDerivative1<>(b1.f0.linearCombination(a1, b1.f0,
616                                                                         a2, b2.f0,
617                                                                         a3, b3.f0),
618                                                 b1.f0.linearCombination(a1, b1.f1,
619                                                                         a2, b2.f1,
620                                                                         a3, b3.f1));
621     }
622 
623     /** {@inheritDoc} */
624     @Override
625     public FieldUnivariateDerivative1<T> linearCombination(final FieldUnivariateDerivative1<T> a1, final FieldUnivariateDerivative1<T> b1,
626                                                            final FieldUnivariateDerivative1<T> a2, final FieldUnivariateDerivative1<T> b2,
627                                                            final FieldUnivariateDerivative1<T> a3, final FieldUnivariateDerivative1<T> b3,
628                                                            final FieldUnivariateDerivative1<T> a4, final FieldUnivariateDerivative1<T> b4) {
629         final Field<T> field = a1.f0.getField();
630         final T[] a = MathArrays.buildArray(field, 8);
631         final T[] b = MathArrays.buildArray(field, 8);
632         a[0] = a1.f0;
633         a[1] = a1.f1;
634         a[2] = a2.f0;
635         a[3] = a2.f1;
636         a[4] = a3.f0;
637         a[5] = a3.f1;
638         a[6] = a4.f0;
639         a[7] = a4.f1;
640         b[0] = b1.f1;
641         b[1] = b1.f0;
642         b[2] = b2.f1;
643         b[3] = b2.f0;
644         b[4] = b3.f1;
645         b[5] = b3.f0;
646         b[6] = b4.f1;
647         b[7] = b4.f0;
648         return new FieldUnivariateDerivative1<>(a1.f0.linearCombination(a1.f0, b1.f0,
649                                                                         a2.f0, b2.f0,
650                                                                         a3.f0, b3.f0,
651                                                                         a4.f0, b4.f0),
652                                                 a1.f0.linearCombination(a, b));
653     }
654 
655     /** {@inheritDoc} */
656     @Override
657     public FieldUnivariateDerivative1<T> linearCombination(final double a1, final FieldUnivariateDerivative1<T> b1,
658                                                            final double a2, final FieldUnivariateDerivative1<T> b2,
659                                                            final double a3, final FieldUnivariateDerivative1<T> b3,
660                                                            final double a4, final FieldUnivariateDerivative1<T> b4) {
661         return new FieldUnivariateDerivative1<>(b1.f0.linearCombination(a1, b1.f0,
662                                                                         a2, b2.f0,
663                                                                         a3, b3.f0,
664                                                                         a4, b4.f0),
665                                                 b1.f0.linearCombination(a1, b1.f1,
666                                                                         a2, b2.f1,
667                                                                         a3, b3.f1,
668                                                                         a4, b4.f1));
669     }
670 
671     /** {@inheritDoc} */
672     @Override
673     public FieldUnivariateDerivative1<T> getPi() {
674         final T zero = getValueField().getZero();
675         return new FieldUnivariateDerivative1<>(zero.getPi(), zero);
676     }
677 
678     /** Test for the equality of two univariate derivatives.
679      * <p>
680      * univariate derivatives are considered equal if they have the same derivatives.
681      * </p>
682      * @param other Object to test for equality to this
683      * @return true if two univariate derivatives are equal
684      */
685     @Override
686     public boolean equals(Object other) {
687 
688         if (this == other) {
689             return true;
690         }
691 
692         if (other instanceof FieldUnivariateDerivative1) {
693             @SuppressWarnings("unchecked")
694             final FieldUnivariateDerivative1<T> rhs = (FieldUnivariateDerivative1<T>) other;
695             return f0.equals(rhs.f0) && f1.equals(rhs.f1);
696         }
697 
698         return false;
699 
700     }
701 
702     /** Get a hashCode for the univariate derivative.
703      * @return a hash code value for this object
704      */
705     @Override
706     public int hashCode() {
707         return 453 - 19 * f0.hashCode() + 37 * f1.hashCode();
708     }
709 
710 }