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 java.util.Arrays;
20  
21  import org.hipparchus.CalculusFieldElement;
22  import org.hipparchus.Field;
23  import org.hipparchus.exception.LocalizedCoreFormats;
24  import org.hipparchus.exception.MathIllegalArgumentException;
25  import org.hipparchus.util.FastMath;
26  import org.hipparchus.util.FieldSinCos;
27  import org.hipparchus.util.FieldSinhCosh;
28  import org.hipparchus.util.MathArrays;
29  import org.hipparchus.util.MathUtils;
30  
31  /** Class representing both the value and the differentials of a function.
32   * <p>This class is a stripped-down version of {@link FieldDerivativeStructure}
33   * with {@link FieldDerivativeStructure#getOrder() derivation order} limited to one.
34   * It should have less overhead than {@link FieldDerivativeStructure} in its domain.</p>
35   * <p>This class is an implementation of Rall's numbers. Rall's numbers are an
36   * extension to the real numbers used throughout mathematical expressions; they hold
37   * the derivative together with the value of a function.</p>
38   * <p>{@link FieldGradient} instances can be used directly thanks to
39   * the arithmetic operators to the mathematical functions provided as
40   * methods by this class (+, -, *, /, %, sin, cos ...).</p>
41   * <p>Implementing complex expressions by hand using {@link Derivative}-based
42   * classes (or in fact any {@link org.hipparchus.CalculusFieldElement} class) is
43   * a tedious and error-prone task but has the advantage of not requiring users
44   * to compute the derivatives by themselves and allowing to switch for one
45   * derivative implementation to another as they all share the same filed API.</p>
46   * <p>Instances of this class are guaranteed to be immutable.</p>
47   * @param <T> the type of the function parameters and value
48   * @see DerivativeStructure
49   * @see UnivariateDerivative1
50   * @see UnivariateDerivative2
51   * @see Gradient
52   * @see FieldDerivativeStructure
53   * @see FieldUnivariateDerivative1
54   * @see FieldUnivariateDerivative2
55   * @since 1.7
56   */
57  public class FieldGradient<T extends CalculusFieldElement<T>> implements FieldDerivative1<T, FieldGradient<T>> {
58  
59      /** Value of the function. */
60      private final T value;
61  
62      /** Gradient of the function. */
63      private final T[] grad;
64  
65      /** Build an instance with values and unitialized derivatives array.
66       * @param value value of the function
67       * @param freeParameters number of free parameters
68       */
69      private FieldGradient(final T value, int freeParameters) {
70          this.value = value;
71          this.grad  = MathArrays.buildArray(value.getField(), freeParameters);
72      }
73  
74      /** Build an instance with values and derivative.
75       * @param value value of the function
76       * @param gradient gradient of the function
77       */
78      @SafeVarargs
79      public FieldGradient(final T value, final T... gradient) {
80          this(value, gradient.length);
81          System.arraycopy(gradient, 0, grad, 0, grad.length);
82      }
83  
84      /** Build an instance from a {@link FieldDerivativeStructure}.
85       * @param ds derivative structure
86       * @exception MathIllegalArgumentException if {@code ds} order
87       * is not 1
88       */
89      public FieldGradient(final FieldDerivativeStructure<T> ds) throws MathIllegalArgumentException {
90          this(ds.getValue(), ds.getFreeParameters());
91          MathUtils.checkDimension(ds.getOrder(), 1);
92          System.arraycopy(ds.getAllDerivatives(), 1, grad, 0, grad.length);
93      }
94  
95      /** Build an instance corresponding to a constant value.
96       * @param freeParameters number of free parameters (i.e. dimension of the gradient)
97       * @param value constant value of the function
98       * @param <T> the type of the function parameters and value
99       * @return a {@code FieldGradient} with a constant value and all derivatives set to 0.0
100      */
101     public static <T extends CalculusFieldElement<T>> FieldGradient<T> constant(final int freeParameters, final T value) {
102         final FieldGradient<T> g = new FieldGradient<>(value, freeParameters);
103         Arrays.fill(g.grad, value.getField().getZero());
104         return g;
105     }
106 
107     /** Build a {@code Gradient} representing a variable.
108      * <p>Instances built using this method are considered
109      * to be the free variables with respect to which differentials
110      * are computed. As such, their differential with respect to
111      * themselves is +1.</p>
112      * @param freeParameters number of free parameters (i.e. dimension of the gradient)
113      * @param index index of the variable (from 0 to {@link #getFreeParameters() getFreeParameters()} - 1)
114      * @param value value of the variable
115      * @param <T> the type of the function parameters and value
116      * @return a {@code FieldGradient} with a constant value and all derivatives set to 0.0 except the
117      * one at {@code index} which will be set to 1.0
118      */
119     public static <T extends CalculusFieldElement<T>> FieldGradient<T> variable(final int freeParameters,
120                                                                                 final int index, final T value) {
121         final FieldGradient<T> g = new FieldGradient<>(value, freeParameters);
122         final Field<T> field = value.getField();
123         Arrays.fill(g.grad, field.getZero());
124         g.grad[index] = field.getOne();
125         return g;
126     }
127 
128     /** Get the {@link Field} the value and parameters of the function belongs to.
129      * @return {@link Field} the value and parameters of the function belongs to
130      */
131     public Field<T> getValueField() {
132         return value.getField();
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     public FieldGradient<T> newInstance(final double c) {
138         return newInstance(getValueField().getZero().newInstance(c));
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     public FieldGradient<T> newInstance(final T c) {
144         return new FieldGradient<>(c, MathArrays.buildArray(value.getField(), grad.length));
145     }
146 
147     /** {@inheritDoc} */
148     @Override
149     public FieldGradient<T> withValue(final T v) {
150         return new FieldGradient<>(v, grad);
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public FieldGradient<T> getAddendum() {
156         return new FieldGradient<>(value.getField().getZero(), grad);
157     }
158 
159     /** Get the value part of the function.
160      * @return value part of the value of the function
161      */
162     @Override
163     public T getValue() {
164         return value;
165     }
166 
167     /** Get the gradient part of the function.
168      * @return gradient part of the value of the function
169      */
170     public T[] getGradient() {
171         return grad.clone();
172     }
173 
174     /** Get the number of free parameters.
175      * @return number of free parameters
176      */
177     @Override
178     public int getFreeParameters() {
179         return grad.length;
180     }
181 
182     /** {@inheritDoc} */
183     @Override
184     public T getPartialDerivative(final int ... orders)
185         throws MathIllegalArgumentException {
186 
187         // check the number of components
188         if (orders.length != grad.length) {
189             throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
190                                                    orders.length, grad.length);
191         }
192 
193         // check that either all derivation orders are set to 0,
194         // or that only one is set to 1 and all other ones are set to 0
195         int selected = -1;
196         for (int i = 0; i < orders.length; ++i) {
197             if (orders[i] != 0) {
198                 if (selected >= 0 || orders[i] != 1) {
199                      throw new MathIllegalArgumentException(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED,
200                                                            orders[i]);
201                 }
202                 // found the component set to derivation order 1
203                 selected = i;
204             }
205         }
206 
207         return (selected < 0) ? value : grad[selected];
208 
209     }
210 
211     /** Get the partial derivative with respect to one parameter.
212      * @param n index of the parameter (counting from 0)
213      * @return partial derivative with respect to the n<sup>th</sup> parameter
214      * @exception MathIllegalArgumentException if n is either negative or larger
215      * or equal to {@link #getFreeParameters()}
216      */
217     public T getPartialDerivative(final int n) throws MathIllegalArgumentException {
218         if (n < 0 || n >= grad.length) {
219             throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, n, 0, grad.length - 1);
220         }
221         return grad[n];
222     }
223 
224     /** Convert the instance to a {@link FieldDerivativeStructure}.
225      * @return derivative structure with same value and derivative as the instance
226      */
227     public FieldDerivativeStructure<T> toDerivativeStructure() {
228         final T[] derivatives = MathArrays.buildArray(getValueField(), 1 + grad.length);
229         derivatives[0] = value;
230         System.arraycopy(grad, 0, derivatives, 1, grad.length);
231         return getField().getConversionFactory().build(derivatives);
232     }
233 
234     /** {@inheritDoc} */
235     @Override
236     public FieldGradient<T> add(final double a) {
237         return new FieldGradient<>(value.add(a), grad);
238     }
239 
240     /** {@inheritDoc} */
241     @Override
242     public FieldGradient<T> add(final FieldGradient<T> a) {
243         final FieldGradient<T> result = newInstance(value.add(a.value));
244         for (int i = 0; i < grad.length; ++i) {
245             result.grad[i] = grad[i].add(a.grad[i]);
246         }
247         return result;
248     }
249 
250     /** {@inheritDoc} */
251     @Override
252     public FieldGradient<T> subtract(final double a) {
253         return new FieldGradient<>(value.subtract(a), grad);
254     }
255 
256     /** {@inheritDoc} */
257     @Override
258     public FieldGradient<T> subtract(final FieldGradient<T> a) {
259         final FieldGradient<T> result = newInstance(value.subtract(a.value));
260         for (int i = 0; i < grad.length; ++i) {
261             result.grad[i] = grad[i].subtract(a.grad[i]);
262         }
263         return result;
264     }
265 
266     /** '&times;' operator.
267      * @param n right hand side parameter of the operator
268      * @return this&times;n
269      */
270     public FieldGradient<T> multiply(final T n) {
271         final FieldGradient<T> result = newInstance(value.multiply(n));
272         for (int i = 0; i < grad.length; ++i) {
273             result.grad[i] = grad[i].multiply(n);
274         }
275         return result;
276     }
277 
278     /** {@inheritDoc} */
279     @Override
280     public FieldGradient<T> multiply(final int n) {
281         final FieldGradient<T> result = newInstance(value.multiply(n));
282         for (int i = 0; i < grad.length; ++i) {
283             result.grad[i] = grad[i].multiply(n);
284         }
285         return result;
286     }
287 
288     /** {@inheritDoc} */
289     @Override
290     public FieldGradient<T> multiply(final double a) {
291         final FieldGradient<T> result = newInstance(value.multiply(a));
292         for (int i = 0; i < grad.length; ++i) {
293             result.grad[i] = grad[i].multiply(a);
294         }
295         return result;
296     }
297 
298     /** {@inheritDoc} */
299     @Override
300     public FieldGradient<T> multiply(final FieldGradient<T> a) {
301         final FieldGradient<T> result = newInstance(value.multiply(a.value));
302         for (int i = 0; i < grad.length; ++i) {
303             result.grad[i] = grad[i].multiply(a.value).add(value.multiply(a.grad[i]));
304         }
305         return result;
306     }
307 
308     /** '&divide;' operator.
309      * @param a right hand side parameter of the operator
310      * @return this&divide;a
311      */
312     public FieldGradient<T> divide(final T a) {
313         final FieldGradient<T> result = newInstance(value.divide(a));
314         for (int i = 0; i < grad.length; ++i) {
315             result.grad[i] = grad[i].divide(a);
316         }
317         return result;
318     }
319 
320     /** {@inheritDoc} */
321     @Override
322     public FieldGradient<T> divide(final double a) {
323         final FieldGradient<T> result = newInstance(value.divide(a));
324         for (int i = 0; i < grad.length; ++i) {
325             result.grad[i] = grad[i].divide(a);
326         }
327         return result;
328     }
329 
330     /** {@inheritDoc} */
331     @Override
332     public FieldGradient<T> divide(final FieldGradient<T> a) {
333         final T inv1 = a.value.reciprocal();
334         final T inv2 = inv1.multiply(inv1);
335         final FieldGradient<T> result = newInstance(value.multiply(inv1));
336         for (int i = 0; i < grad.length; ++i) {
337             result.grad[i] = grad[i].multiply(a.value).subtract(value.multiply(a.grad[i])).multiply(inv2);
338         }
339         return result;
340     }
341 
342     /** IEEE remainder operator.
343      * @param a right hand side parameter of the operator
344      * @return this - n &times; a where n is the closest integer to this/a
345      * (the even integer is chosen for n if this/a is halfway between two integers)
346      */
347     public FieldGradient<T> remainder(final T a) {
348         return new FieldGradient<>(FastMath.IEEEremainder(value, a), grad);
349     }
350 
351     /** {@inheritDoc} */
352     @Override
353     public FieldGradient<T> remainder(final double a) {
354         return new FieldGradient<>(FastMath.IEEEremainder(value, a), grad);
355     }
356 
357     /** {@inheritDoc} */
358     @Override
359     public FieldGradient<T> remainder(final FieldGradient<T> a) {
360 
361         // compute k such that lhs % rhs = lhs - k rhs
362         final T rem = FastMath.IEEEremainder(value, a.value);
363         final T k   = FastMath.rint(value.subtract(rem).divide(a.value));
364 
365         final FieldGradient<T> result = newInstance(rem);
366         for (int i = 0; i < grad.length; ++i) {
367             result.grad[i] = grad[i].subtract(k.multiply(a.grad[i]));
368         }
369         return result;
370 
371     }
372 
373     /** {@inheritDoc} */
374     @Override
375     public FieldGradient<T> negate() {
376         final FieldGradient<T> result = newInstance(value.negate());
377         for (int i = 0; i < grad.length; ++i) {
378             result.grad[i] = grad[i].negate();
379         }
380         return result;
381     }
382 
383     /** {@inheritDoc} */
384     @Override
385     public FieldGradient<T> abs() {
386         if (Double.doubleToLongBits(value.getReal()) < 0) {
387             // we use the bits representation to also handle -0.0
388             return negate();
389         } else {
390             return this;
391         }
392     }
393 
394     /**
395      * Returns the instance with the sign of the argument.
396      * A NaN {@code sign} argument is treated as positive.
397      *
398      * @param sign the sign for the returned value
399      * @return the instance with the same sign as the {@code sign} argument
400      */
401     public FieldGradient<T> copySign(final T sign) {
402         long m = Double.doubleToLongBits(value.getReal());
403         long s = Double.doubleToLongBits(sign.getReal());
404         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
405             return this;
406         }
407         return negate(); // flip sign
408     }
409 
410     /** {@inheritDoc} */
411     @Override
412     public FieldGradient<T> copySign(final FieldGradient<T> sign) {
413         long m = Double.doubleToLongBits(value.getReal());
414         long s = Double.doubleToLongBits(sign.value.getReal());
415         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
416             return this;
417         }
418         return negate(); // flip sign
419     }
420 
421     /** {@inheritDoc} */
422     @Override
423     public FieldGradient<T> copySign(final double sign) {
424         long m = Double.doubleToLongBits(value.getReal());
425         long s = Double.doubleToLongBits(sign);
426         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
427             return this;
428         }
429         return negate(); // flip sign
430     }
431 
432     /** {@inheritDoc} */
433     @Override
434     public FieldGradient<T> scalb(final int n) {
435         final FieldGradient<T> result = newInstance(FastMath.scalb(value, n));
436         for (int i = 0; i < grad.length; ++i) {
437             result.grad[i] = FastMath.scalb(grad[i], n);
438         }
439         return result;
440     }
441 
442     /** {@inheritDoc} */
443     @Override
444     public FieldGradient<T> hypot(final FieldGradient<T> y) {
445 
446         if (Double.isInfinite(value.getReal()) || Double.isInfinite(y.value.getReal())) {
447             return newInstance(Double.POSITIVE_INFINITY);
448         } else if (Double.isNaN(value.getReal()) || Double.isNaN(y.value.getReal())) {
449             return newInstance(Double.NaN);
450         } else {
451 
452             final int expX = getExponent();
453             final int expY = y.getExponent();
454             if (expX > expY + 27) {
455                 // y is negligible with respect to x
456                 return abs();
457             } else if (expY > expX + 27) {
458                 // x is negligible with respect to y
459                 return y.abs();
460             } else {
461 
462                 // find an intermediate scale to avoid both overflow and underflow
463                 final int middleExp = (expX + expY) / 2;
464 
465                 // scale parameters without losing precision
466                 final FieldGradient<T> scaledX = scalb(-middleExp);
467                 final FieldGradient<T> scaledY = y.scalb(-middleExp);
468 
469                 // compute scaled hypotenuse
470                 final FieldGradient<T> scaledH =
471                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
472 
473                 // remove scaling
474                 return scaledH.scalb(middleExp);
475 
476             }
477 
478         }
479     }
480 
481     /** Compute composition of the instance by a function.
482      * @param g0 value of the function at the current point (i.e. at {@code g(getValue())})
483      * @param g1 first derivative of the function at the current point (i.e. at {@code g'(getValue())})
484      * @return g(this)
485      */
486     @Override
487     public FieldGradient<T> compose(final T g0, final T g1) {
488         final FieldGradient<T> result = newInstance(g0);
489         for (int i = 0; i < grad.length; ++i) {
490             result.grad[i] = g1.multiply(grad[i]);
491         }
492         return result;
493     }
494 
495     /** {@inheritDoc} */
496     @Override
497     public FieldGradient<T> rootN(final int n) {
498         if (n == 2) {
499             return sqrt();
500         } else if (n == 3) {
501             return cbrt();
502         } else {
503             final T r = FastMath.pow(value, 1.0 / n);
504             return compose(r, FastMath.pow(r, n - 1).multiply(n).reciprocal());
505         }
506     }
507 
508     /** {@inheritDoc} */
509     @Override
510     public FieldGradientField<T> getField() {
511         return FieldGradientField.getField(getValueField(), getFreeParameters());
512     }
513 
514     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldGradient}
515      * @param a number to exponentiate
516      * @param x power to apply
517      * @param <T> the type of the function parameters and value
518      * @return a<sup>x</sup>
519      */
520     public static <T extends CalculusFieldElement<T>> FieldGradient<T> pow(final double a, final FieldGradient<T> x) {
521         if (a == 0) {
522             return x.getField().getZero();
523         } else {
524             final T aX    = FastMath.pow(x.value.newInstance(a), x.value);
525             final T aXlnA = aX.multiply(FastMath.log(a));
526             final FieldGradient<T> result = x.newInstance(aX);
527             for (int i = 0; i < x.grad.length; ++i) {
528                 result.grad[i] =  aXlnA.multiply(x.grad[i]);
529             }
530             return result;
531         }
532     }
533 
534     /** {@inheritDoc} */
535     @Override
536     public FieldGradient<T> pow(final double p) {
537         if (p == 0) {
538             return getField().getOne();
539         } else {
540             final T f0Pm1 = FastMath.pow(value, p - 1);
541             return compose(f0Pm1.multiply(value), f0Pm1.multiply(p));
542         }
543     }
544 
545     /** {@inheritDoc} */
546     @Override
547     public FieldGradient<T> pow(final int n) {
548         if (n == 0) {
549             return getField().getOne();
550         } else {
551             final T f0Nm1 = FastMath.pow(value, n - 1);
552             return compose(f0Nm1.multiply(value), f0Nm1.multiply(n));
553         }
554     }
555 
556     /** {@inheritDoc} */
557     @Override
558     public FieldSinCos<FieldGradient<T>> sinCos() {
559         final FieldSinCos<T> sinCos = FastMath.sinCos(value);
560         final FieldGradient<T> sin = newInstance(sinCos.sin());
561         final FieldGradient<T> cos = newInstance(sinCos.cos());
562         final T mSin = sinCos.sin().negate();
563         for (int i = 0; i < grad.length; ++i) {
564             sin.grad[i] =  grad[i].multiply(sinCos.cos());
565             cos.grad[i] =  grad[i].multiply(mSin);
566         }
567         return new FieldSinCos<>(sin, cos);
568     }
569 
570     /** {@inheritDoc} */
571     @Override
572     public FieldGradient<T> atan2(final FieldGradient<T> x) {
573         final T inv = value.square().add(x.value.multiply(x.value)).reciprocal();
574         final FieldGradient<T> result = newInstance(FastMath.atan2(value, x.value));
575         final T xValueInv = x.value.multiply(inv);
576         final T mValueInv = value.negate().multiply(inv);
577         for (int i = 0; i < grad.length; ++i) {
578             result.grad[i] = xValueInv.multiply(grad[i]).add(x.grad[i].multiply(mValueInv));
579         }
580         return result;
581     }
582 
583     /** {@inheritDoc} */
584     @Override
585     public FieldSinhCosh<FieldGradient<T>> sinhCosh() {
586         final FieldSinhCosh<T> sinhCosh = FastMath.sinhCosh(value);
587         final FieldGradient<T> sinh = newInstance(sinhCosh.sinh());
588         final FieldGradient<T> cosh = newInstance(sinhCosh.cosh());
589         for (int i = 0; i < grad.length; ++i) {
590             sinh.grad[i] = grad[i].multiply(sinhCosh.cosh());
591             cosh.grad[i] = grad[i].multiply(sinhCosh.sinh());
592         }
593         return new FieldSinhCosh<>(sinh, cosh);
594     }
595 
596     /** {@inheritDoc} */
597     @Override
598     public FieldGradient<T> toDegrees() {
599         final FieldGradient<T> result = newInstance(FastMath.toDegrees(value));
600         for (int i = 0; i < grad.length; ++i) {
601             result.grad[i] = FastMath.toDegrees(grad[i]);
602         }
603         return result;
604     }
605 
606     /** {@inheritDoc} */
607     @Override
608     public FieldGradient<T> toRadians() {
609         final FieldGradient<T> result = newInstance(FastMath.toRadians(value));
610         for (int i = 0; i < grad.length; ++i) {
611             result.grad[i] = FastMath.toRadians(grad[i]);
612         }
613         return result;
614     }
615 
616     /** Evaluate Taylor expansion of a gradient.
617      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
618      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
619      */
620     public T taylor(final double... delta) {
621         T result = value;
622         for (int i = 0; i < grad.length; ++i) {
623             result = result.add(grad[i].multiply(delta[i]));
624         }
625         return result;
626     }
627 
628     /** Evaluate Taylor expansion of a gradient.
629      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
630      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
631      */
632     public T taylor(@SuppressWarnings("unchecked") final T... delta) {
633         T result = value;
634         for (int i = 0; i < grad.length; ++i) {
635             result = result.add(grad[i].multiply(delta[i]));
636         }
637         return result;
638     }
639 
640     /** {@inheritDoc} */
641     @Override
642     public FieldGradient<T> linearCombination(final FieldGradient<T>[] a, final FieldGradient<T>[] b) {
643 
644         // extract values and first derivatives
645         final Field<T> field = a[0].value.getField();
646         final int n  = a.length;
647         final T[] a0 = MathArrays.buildArray(field, n);
648         final T[] b0 = MathArrays.buildArray(field, n);
649         final T[] a1 = MathArrays.buildArray(field, 2 * n);
650         final T[] b1 = MathArrays.buildArray(field, 2 * n);
651         for (int i = 0; i < n; ++i) {
652             final FieldGradient<T> ai = a[i];
653             final FieldGradient<T> bi = b[i];
654             a0[i]         = ai.value;
655             b0[i]         = bi.value;
656             a1[2 * i]     = ai.value;
657             b1[2 * i + 1] = bi.value;
658         }
659 
660         final FieldGradient<T> result = newInstance(a[0].value.linearCombination(a0, b0));
661         for (int k = 0; k < grad.length; ++k) {
662             for (int i = 0; i < n; ++i) {
663                 a1[2 * i + 1] = a[i].grad[k];
664                 b1[2 * i]     = b[i].grad[k];
665             }
666             result.grad[k] = a[0].value.linearCombination(a1, b1);
667         }
668         return result;
669 
670     }
671 
672     /**
673      * Compute a linear combination.
674      * @param a Factors.
675      * @param b Factors.
676      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
677      * @throws MathIllegalArgumentException if arrays dimensions don't match
678      */
679     public FieldGradient<T> linearCombination(final T[] a, final FieldGradient<T>[] b) {
680 
681         // extract values and first derivatives
682         final Field<T> field = b[0].value.getField();
683         final int      n  = b.length;
684         final T[] b0 = MathArrays.buildArray(field, n);
685         final T[] b1 = MathArrays.buildArray(field, n);
686         for (int i = 0; i < n; ++i) {
687             b0[i] = b[i].value;
688         }
689 
690         final FieldGradient<T> result = newInstance(b[0].value.linearCombination(a, b0));
691         for (int k = 0; k < grad.length; ++k) {
692             for (int i = 0; i < n; ++i) {
693                 b1[i] = b[i].grad[k];
694             }
695             result.grad[k] = b[0].value.linearCombination(a, b1);
696         }
697         return result;
698 
699     }
700 
701     /** {@inheritDoc} */
702     @Override
703     public FieldGradient<T> linearCombination(final double[] a, final FieldGradient<T>[] b) {
704 
705         // extract values and first derivatives
706         final Field<T> field = b[0].value.getField();
707         final int      n  = b.length;
708         final T[] b0 = MathArrays.buildArray(field, n);
709         final T[] b1 = MathArrays.buildArray(field, n);
710         for (int i = 0; i < n; ++i) {
711             b0[i] = b[i].value;
712         }
713 
714         final FieldGradient<T> result = newInstance(b[0].value.linearCombination(a, b0));
715         for (int k = 0; k < grad.length; ++k) {
716             for (int i = 0; i < n; ++i) {
717                 b1[i] = b[i].grad[k];
718             }
719             result.grad[k] = b[0].value.linearCombination(a, b1);
720         }
721         return result;
722 
723     }
724 
725     /** {@inheritDoc} */
726     @Override
727     public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
728                                               final FieldGradient<T> a2, final FieldGradient<T> b2) {
729         final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
730                                                                                a2.value, b2.value));
731         for (int i = 0; i < b1.grad.length; ++i) {
732             result.grad[i] = a1.value.linearCombination(a1.value,       b1.grad[i],
733                                                             a1.grad[i], b1.value,
734                                                             a2.value,       b2.grad[i],
735                                                             a2.grad[i], b2.value);
736         }
737         return result;
738     }
739 
740     /** {@inheritDoc} */
741     @Override
742     public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
743                                               final double a2, final FieldGradient<T> b2) {
744         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
745                                                                                a2, b2.value));
746         for (int i = 0; i < b1.grad.length; ++i) {
747             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
748                                                             a2, b2.grad[i]);
749         }
750         return result;
751     }
752 
753     /** {@inheritDoc} */
754     @Override
755     public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
756                                               final FieldGradient<T> a2, final FieldGradient<T> b2,
757                                               final FieldGradient<T> a3, final FieldGradient<T> b3) {
758         final Field<T> field = a1.value.getField();
759         final T[] a = MathArrays.buildArray(field, 6);
760         final T[] b = MathArrays.buildArray(field, 6);
761         a[0] = a1.value;
762         a[2] = a2.value;
763         a[4] = a3.value;
764         b[1] = b1.value;
765         b[3] = b2.value;
766         b[5] = b3.value;
767         final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
768                                                                                a2.value, b2.value,
769                                                                                a3.value, b3.value));
770         for (int i = 0; i < b1.grad.length; ++i) {
771             a[1] = a1.grad[i];
772             a[3] = a2.grad[i];
773             a[5] = a3.grad[i];
774             b[0] = b1.grad[i];
775             b[2] = b2.grad[i];
776             b[4] = b3.grad[i];
777             result.grad[i] = a1.value.linearCombination(a, b);
778         }
779         return result;
780     }
781 
782     /**
783      * Compute a linear combination.
784      * @param a1 first factor of the first term
785      * @param b1 second factor of the first term
786      * @param a2 first factor of the second term
787      * @param b2 second factor of the second term
788      * @param a3 first factor of the third term
789      * @param b3 second factor of the third term
790      * @return a<sub>1</sub>&times;b<sub>1</sub> +
791      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
792      * @see #linearCombination(double, FieldGradient, double, FieldGradient)
793      * @see #linearCombination(double, FieldGradient, double, FieldGradient, double, FieldGradient, double, FieldGradient)
794      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
795      */
796     public FieldGradient<T> linearCombination(final T a1, final FieldGradient<T> b1,
797                                               final T a2, final FieldGradient<T> b2,
798                                               final T a3, final FieldGradient<T> b3) {
799         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
800                                                                                a2, b2.value,
801                                                                                a3, b3.value));
802         for (int i = 0; i < b1.grad.length; ++i) {
803             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
804                                                         a2, b2.grad[i],
805                                                         a3, b3.grad[i]);
806         }
807         return result;
808     }
809 
810     /** {@inheritDoc} */
811     @Override
812     public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
813                                               final double a2, final FieldGradient<T> b2,
814                                               final double a3, final FieldGradient<T> b3) {
815         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
816                                                                                a2, b2.value,
817                                                                                a3, b3.value));
818         for (int i = 0; i < b1.grad.length; ++i) {
819             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
820                                                             a2, b2.grad[i],
821                                                             a3, b3.grad[i]);
822         }
823         return result;
824     }
825 
826     /** {@inheritDoc} */
827     @Override
828     public FieldGradient<T> linearCombination(final FieldGradient<T> a1, final FieldGradient<T> b1,
829                                               final FieldGradient<T> a2, final FieldGradient<T> b2,
830                                               final FieldGradient<T> a3, final FieldGradient<T> b3,
831                                               final FieldGradient<T> a4, final FieldGradient<T> b4) {
832         final Field<T> field = a1.value.getField();
833         final T[] a = MathArrays.buildArray(field, 8);
834         final T[] b = MathArrays.buildArray(field, 8);
835         a[0] = a1.value;
836         a[2] = a2.value;
837         a[4] = a3.value;
838         a[6] = a4.value;
839         b[1] = b1.value;
840         b[3] = b2.value;
841         b[5] = b3.value;
842         b[7] = b4.value;
843         final FieldGradient<T> result = newInstance(a1.value.linearCombination(a1.value, b1.value,
844                                                                                a2.value, b2.value,
845                                                                                a3.value, b3.value,
846                                                                                a4.value, b4.value));
847         for (int i = 0; i < b1.grad.length; ++i) {
848             a[1] = a1.grad[i];
849             a[3] = a2.grad[i];
850             a[5] = a3.grad[i];
851             a[7] = a4.grad[i];
852             b[0] = b1.grad[i];
853             b[2] = b2.grad[i];
854             b[4] = b3.grad[i];
855             b[6] = b4.grad[i];
856             result.grad[i] = a1.value.linearCombination(a, b);
857         }
858         return result;
859     }
860 
861     /** {@inheritDoc} */
862     @Override
863     public FieldGradient<T> linearCombination(final double a1, final FieldGradient<T> b1,
864                                               final double a2, final FieldGradient<T> b2,
865                                               final double a3, final FieldGradient<T> b3,
866                                               final double a4, final FieldGradient<T> b4) {
867         final FieldGradient<T> result = newInstance(b1.value.linearCombination(a1, b1.value,
868                                                                                a2, b2.value,
869                                                                                a3, b3.value,
870                                                                                a4, b4.value));
871         for (int i = 0; i < b1.grad.length; ++i) {
872             result.grad[i] = b1.value.linearCombination(a1, b1.grad[i],
873                                                             a2, b2.grad[i],
874                                                             a3, b3.grad[i],
875                                                             a4, b4.grad[i]);
876         }
877         return result;
878     }
879 
880     /**
881      * Add an independent variable to the Taylor expansion.
882      * @return object with one more variable
883      * @since 4.0
884      */
885     public FieldGradient<T> stackVariable() {
886         final T[] gradient = MathArrays.buildArray(getValueField(), this.getFreeParameters() + 1);
887         System.arraycopy(this.grad, 0, gradient, 0, this.getFreeParameters());
888         return new FieldGradient<>(this.value, gradient);
889     }
890 
891     /** {@inheritDoc} */
892     @Override
893     public FieldGradient<T> getPi() {
894         return new FieldGradient<>(getValueField().getZero().getPi(), getFreeParameters());
895     }
896 
897     /** Test for the equality of two univariate derivatives.
898      * <p>
899      * univariate derivatives are considered equal if they have the same derivatives.
900      * </p>
901      * @param other Object to test for equality to this
902      * @return true if two univariate derivatives are equal
903      */
904     @Override
905     public boolean equals(Object other) {
906 
907         if (this == other) {
908             return true;
909         }
910 
911         if (other instanceof FieldGradient) {
912             @SuppressWarnings("unchecked")
913             final FieldGradient<T> rhs = (FieldGradient<T>) other;
914             if (!value.equals(rhs.value) || grad.length != rhs.grad.length) {
915                 return false;
916             }
917             for (int i = 0; i < grad.length; ++i) {
918                 if (!grad[i].equals(rhs.grad[i])) {
919                     return false;
920                 }
921             }
922             return true;
923         }
924 
925         return false;
926 
927     }
928 
929     /** Get a hashCode for the univariate derivative.
930      * @return a hash code value for this object
931      */
932     @Override
933     public int hashCode() {
934         return 129 + 7 *value.hashCode() - 15 * Arrays.hashCode(grad);
935     }
936 
937 }