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