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.MathIllegalArgumentException;
22  import org.hipparchus.exception.MathRuntimeException;
23  import org.hipparchus.util.FieldSinCos;
24  import org.hipparchus.util.FieldSinhCosh;
25  import org.hipparchus.util.MathArrays;
26  import org.hipparchus.util.MathUtils;
27  
28  import java.util.Arrays;
29  
30  /** Class representing both the value and the differentials of a function.
31   * <p>This class is similar to {@link DerivativeStructure} except function
32   * parameters and value can be any {@link CalculusFieldElement}.</p>
33   * <p>Instances of this class are guaranteed to be immutable.</p>
34   * @see DerivativeStructure
35   * @see FDSFactory
36   * @see DSCompiler
37   * @param <T> the type of the field elements
38   */
39  public class FieldDerivativeStructure<T extends CalculusFieldElement<T>>
40      implements FieldDerivative<T, FieldDerivativeStructure<T>> {
41  
42      /** Factory that built the instance. */
43      private final FDSFactory<T> factory;
44  
45      /** Combined array holding all values. */
46      private final T[] data;
47  
48      /** Build an instance with all values and derivatives set to 0.
49       * @param factory factory that built the instance
50       * @param data combined array holding all values
51       */
52      FieldDerivativeStructure(final FDSFactory<T> factory, final T[] data) {
53          this.factory = factory;
54          this.data    = data.clone();
55      }
56  
57      /** Build an instance with all values and derivatives set to 0.
58       * @param factory factory that built the instance
59       * @since 1.4
60       */
61      FieldDerivativeStructure(final FDSFactory<T> factory) {
62          this.factory = factory;
63          this.data    = MathArrays.buildArray(factory.getValueField(), factory.getCompiler().getSize());
64      }
65  
66      /** {@inheritDoc} */
67      @Override
68      public FieldDerivativeStructure<T> newInstance(final double value) {
69          return factory.constant(value);
70      }
71  
72      /** {@inheritDoc} */
73      @Override
74      public FieldDerivativeStructure<T> newInstance(final T value) {
75          return factory.constant(value);
76      }
77  
78      /** {@inheritDoc} */
79      @Override
80      public FieldDerivativeStructure<T> withValue(final T value) {
81          final FieldDerivativeStructure<T> ds = factory.build();
82          System.arraycopy(data, 1, ds.data, 1, data.length - 1);
83          ds.data[0] = value;
84          return ds;
85      }
86  
87      /** Get the factory that built the instance.
88       * @return factory that built the instance
89       */
90      public FDSFactory<T> getFactory() {
91          return factory;
92      }
93  
94      /** {@inheritDoc} */
95      @Override
96      public int getFreeParameters() {
97          return getFactory().getCompiler().getFreeParameters();
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     public int getOrder() {
103         return getFactory().getCompiler().getOrder();
104     }
105 
106     /** Set a derivative component.
107      * <p>
108      * This method is package-private (no modifier specified), as it is intended
109      * to be used only by Hipparchus classes since it relied on the ordering of
110      * derivatives within the class. This allows avoiding checks on the index,
111      * for performance reasons.
112      * </p>
113      * @param index index of the derivative
114      * @param value of the derivative to set
115      * @since 1.4
116      */
117     void setDerivativeComponent(final int index, final T value) {
118         data[index] = value;
119     }
120 
121     /** Get a derivative component.
122      * <p>
123      * This method is package-private (no modifier specified), as it is intended
124      * to be used only by Hipparchus classes since it relied on the ordering of
125      * derivatives within the class. This allows avoiding checks on the index,
126      * for performance reasons.
127      * </p>
128      * @param index index of the derivative
129      * @return value of the derivative
130      * @since 2.2
131      */
132     T getDerivativeComponent(final int index) {
133         return data[index];
134     }
135 
136     /** {@inheritDoc} */
137     @Override
138     public FieldDerivativeStructure<T> getAddendum() {
139         final T[] addendum = data.clone();
140         addendum[0] = addendum[0].getField().getZero();
141         return new FieldDerivativeStructure<>(factory, addendum);
142     }
143 
144     /** Get the value part of the derivative structure.
145      * @return value part of the derivative structure
146      * @see #getPartialDerivative(int...)
147      */
148     @Override
149     public T getValue() {
150         return data[0];
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public T getPartialDerivative(final int ... orders)
156         throws MathIllegalArgumentException {
157         return data[factory.getCompiler().getPartialDerivativeIndex(orders)];
158     }
159 
160     /** Get all partial derivatives.
161      * @return a fresh copy of partial derivatives, in an array sorted according to
162      * {@link DSCompiler#getPartialDerivativeIndex(int...)}
163      */
164     public T[] getAllDerivatives() {
165         return data.clone();
166     }
167 
168     /** {@inheritDoc}
169      */
170     @Override
171     public FieldDerivativeStructure<T> add(final double a) {
172         final FieldDerivativeStructure<T> ds = factory.build();
173         System.arraycopy(data, 0, ds.data, 0, data.length);
174         ds.data[0] = ds.data[0].add(a);
175         return ds;
176     }
177 
178     /** {@inheritDoc}
179      * @exception MathIllegalArgumentException if number of free parameters
180      * or orders do not match
181      */
182     @Override
183     public FieldDerivativeStructure<T> add(final FieldDerivativeStructure<T> a)
184         throws MathIllegalArgumentException {
185         factory.checkCompatibility(a.factory);
186         final FieldDerivativeStructure<T> ds = factory.build();
187         factory.getCompiler().add(data, 0, a.data, 0, ds.data, 0);
188         return ds;
189     }
190 
191     /** {@inheritDoc}
192      */
193     @Override
194     public FieldDerivativeStructure<T> subtract(final double a) {
195         final FieldDerivativeStructure<T> ds = factory.build();
196         System.arraycopy(data, 0, ds.data, 0, data.length);
197         ds.data[0] = ds.data[0].subtract(a);
198         return ds;
199     }
200 
201     /** {@inheritDoc}
202      * @exception MathIllegalArgumentException if number of free parameters
203      * or orders do not match
204      */
205     @Override
206     public FieldDerivativeStructure<T> subtract(final FieldDerivativeStructure<T> a)
207         throws MathIllegalArgumentException {
208         factory.checkCompatibility(a.factory);
209         final FieldDerivativeStructure<T> ds = factory.build();
210         factory.getCompiler().subtract(data, 0, a.data, 0, ds.data, 0);
211         return ds;
212     }
213 
214     /** '&times;' operator.
215      * @param a right hand side parameter of the operator
216      * @return this&times;a
217      */
218     public FieldDerivativeStructure<T> multiply(final T a) {
219         final FieldDerivativeStructure<T> ds = factory.build();
220         for (int i = 0; i < ds.data.length; ++i) {
221             ds.data[i] = data[i].multiply(a);
222         }
223         return ds;
224     }
225 
226     /** {@inheritDoc}
227      */
228     @Override
229     public FieldDerivativeStructure<T> multiply(final double a) {
230         final FieldDerivativeStructure<T> ds = factory.build();
231         for (int i = 0; i < ds.data.length; ++i) {
232             ds.data[i] = data[i].multiply(a);
233         }
234         return ds;
235     }
236 
237     /** {@inheritDoc}
238      * @exception MathIllegalArgumentException if number of free parameters
239      * or orders do not match
240      */
241     @Override
242     public FieldDerivativeStructure<T> multiply(final FieldDerivativeStructure<T> a)
243         throws MathIllegalArgumentException {
244         factory.checkCompatibility(a.factory);
245         final FieldDerivativeStructure<T> result = factory.build();
246         factory.getCompiler().multiply(data, 0, a.data, 0, result.data, 0);
247         return result;
248     }
249 
250     /** {@inheritDoc} */
251     @Override
252     public FieldDerivativeStructure<T> square() {
253         return multiply(this);
254     }
255 
256     /** '&divide;' operator.
257      * @param a right hand side parameter of the operator
258      * @return this&divide;a
259      */
260     public FieldDerivativeStructure<T> divide(final T a) {
261         final FieldDerivativeStructure<T> ds = factory.build();
262         for (int i = 0; i < ds.data.length; ++i) {
263             ds.data[i] = data[i].divide(a);
264         }
265         return ds;
266     }
267 
268     /** {@inheritDoc}
269      */
270     @Override
271     public FieldDerivativeStructure<T> divide(final double a) {
272         final FieldDerivativeStructure<T> ds = factory.build();
273         for (int i = 0; i < ds.data.length; ++i) {
274             ds.data[i] = data[i].divide(a);
275         }
276         return ds;
277     }
278 
279     /** {@inheritDoc}
280      * @exception MathIllegalArgumentException if number of free parameters
281      * or orders do not match
282      */
283     @Override
284     public FieldDerivativeStructure<T> divide(final FieldDerivativeStructure<T> a)
285         throws MathIllegalArgumentException {
286         factory.checkCompatibility(a.factory);
287         final FieldDerivativeStructure<T> result = factory.build();
288         factory.getCompiler().divide(data, 0, a.data, 0, result.data, 0);
289         return result;
290     }
291 
292     /** IEEE remainder operator.
293      * @param a right hand side parameter of the operator
294      * @return this - n &times; a where n is the closest integer to this/a
295      * (the even integer is chosen for n if this/a is halfway between two integers)
296      */
297     public FieldDerivativeStructure<T> remainder(final T a) {
298         final FieldDerivativeStructure<T> ds = factory.build();
299         System.arraycopy(data, 0, ds.data, 0, data.length);
300         ds.data[0] = data[0].remainder(a);
301         return ds;
302     }
303 
304     /** {@inheritDoc} */
305     @Override
306     public FieldDerivativeStructure<T> remainder(final double a) {
307         final FieldDerivativeStructure<T> ds = factory.build();
308         System.arraycopy(data, 0, ds.data, 0, data.length);
309         ds.data[0] = data[0].remainder(a);
310         return ds;
311     }
312 
313     /** {@inheritDoc}
314      * @exception MathIllegalArgumentException if number of free parameters
315      * or orders do not match
316      */
317     @Override
318     public FieldDerivativeStructure<T> remainder(final FieldDerivativeStructure<T> a)
319         throws MathIllegalArgumentException {
320         factory.checkCompatibility(a.factory);
321         final FieldDerivativeStructure<T> result = factory.build();
322         factory.getCompiler().remainder(data, 0, a.data, 0, result.data, 0);
323         return result;
324     }
325 
326     /** {@inheritDoc} */
327     @Override
328     public FieldDerivativeStructure<T> negate() {
329         final FieldDerivativeStructure<T> ds = factory.build();
330         for (int i = 0; i < ds.data.length; ++i) {
331             ds.data[i] = data[i].negate();
332         }
333         return ds;
334     }
335 
336     /** {@inheritDoc}
337      */
338     @Override
339     public FieldDerivativeStructure<T> abs() {
340         if (Double.doubleToLongBits(data[0].getReal()) < 0) {
341             // we use the bits representation to also handle -0.0
342             return negate();
343         } else {
344             return this;
345         }
346     }
347 
348     /**
349      * Returns the instance with the sign of the argument.
350      * A NaN {@code sign} argument is treated as positive.
351      *
352      * @param sign the sign for the returned value
353      * @return the instance with the same sign as the {@code sign} argument
354      */
355     public FieldDerivativeStructure<T> copySign(final T sign) {
356         long m = Double.doubleToLongBits(data[0].getReal());
357         long s = Double.doubleToLongBits(sign.getReal());
358         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
359             return this;
360         }
361         return negate(); // flip sign
362     }
363 
364     /** {@inheritDoc}
365      */
366     @Override
367     public FieldDerivativeStructure<T> copySign(final double sign) {
368         long m = Double.doubleToLongBits(data[0].getReal());
369         long s = Double.doubleToLongBits(sign);
370         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
371             return this;
372         }
373         return negate(); // flip sign
374     }
375 
376     /** {@inheritDoc}
377      */
378     @Override
379     public FieldDerivativeStructure<T> copySign(final FieldDerivativeStructure<T> sign) {
380         long m = Double.doubleToLongBits(data[0].getReal());
381         long s = Double.doubleToLongBits(sign.data[0].getReal());
382         if ((m >= 0 && s >= 0) || (m < 0 && s < 0)) { // Sign is currently OK
383             return this;
384         }
385         return negate(); // flip sign
386     }
387 
388     /** {@inheritDoc}
389      */
390     @Override
391     public FieldDerivativeStructure<T> scalb(final int n) {
392         final FieldDerivativeStructure<T> ds = factory.build();
393         for (int i = 0; i < ds.data.length; ++i) {
394             ds.data[i] = data[i].scalb(n);
395         }
396         return ds;
397     }
398 
399     /** {@inheritDoc}
400      * @exception MathIllegalArgumentException if number of free parameters
401      * or orders do not match
402      */
403     @Override
404     public FieldDerivativeStructure<T> hypot(final FieldDerivativeStructure<T> y)
405         throws MathIllegalArgumentException {
406 
407         factory.checkCompatibility(y.factory);
408 
409         if (data[0].isInfinite() || y.data[0].isInfinite()) {
410             return factory.constant(Double.POSITIVE_INFINITY);
411         } else if (data[0].isNaN() || y.data[0].isNaN()) {
412             return factory.constant(Double.NaN);
413         } else {
414 
415             final int expX = getExponent();
416             final int expY = y.getExponent();
417             if (expX > expY + 27) {
418                 // y is negligible with respect to x
419                 return abs();
420             } else if (expY > expX + 27) {
421                 // x is negligible with respect to y
422                 return y.abs();
423             } else {
424 
425                 // find an intermediate scale to avoid both overflow and underflow
426                 final int middleExp = (expX + expY) / 2;
427 
428                 // scale parameters without losing precision
429                 final FieldDerivativeStructure<T> scaledX = scalb(-middleExp);
430                 final FieldDerivativeStructure<T> scaledY = y.scalb(-middleExp);
431 
432                 // compute scaled hypotenuse
433                 final FieldDerivativeStructure<T> scaledH =
434                         scaledX.multiply(scaledX).add(scaledY.multiply(scaledY)).sqrt();
435 
436                 // remove scaling
437                 return scaledH.scalb(middleExp);
438 
439             }
440 
441         }
442     }
443 
444     /**
445      * Returns the hypotenuse of a triangle with sides {@code x} and {@code y}
446      * - sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
447      * avoiding intermediate overflow or underflow.
448      *
449      * <ul>
450      * <li> If either argument is infinite, then the result is positive infinity.</li>
451      * <li> else, if either argument is NaN then the result is NaN.</li>
452      * </ul>
453      *
454      * @param x a value
455      * @param y a value
456      * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
457      * @exception MathIllegalArgumentException if number of free parameters
458      * or orders do not match
459      * @param <T> the type of the field elements
460      */
461     public static <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T>
462         hypot(final FieldDerivativeStructure<T> x, final FieldDerivativeStructure<T> y)
463         throws MathIllegalArgumentException {
464         return x.hypot(y);
465     }
466 
467     /** Compute composition of the instance by a univariate function.
468      * @param f array of value and derivatives of the function at
469      * the current point (i.e. [f({@link #getValue()}),
470      * f'({@link #getValue()}), f''({@link #getValue()})...]).
471      * @return f(this)
472      * @exception MathIllegalArgumentException if the number of derivatives
473      * in the array is not equal to {@link #getOrder() order} + 1
474      */
475     @SafeVarargs
476     public final FieldDerivativeStructure<T> compose(final T ... f)
477         throws MathIllegalArgumentException {
478 
479         MathUtils.checkDimension(f.length, getOrder() + 1);
480         final FieldDerivativeStructure<T> result = factory.build();
481         factory.getCompiler().compose(data, 0, f, result.data, 0);
482         return result;
483     }
484 
485     /** Compute composition of the instance by a univariate function.
486      * @param f array of value and derivatives of the function at
487      * the current point (i.e. [f({@link #getValue()}),
488      * f'({@link #getValue()}), f''({@link #getValue()})...]).
489      * @return f(this)
490      * @exception MathIllegalArgumentException if the number of derivatives
491      * in the array is not equal to {@link #getOrder() order} + 1
492      */
493     public FieldDerivativeStructure<T> compose(final double ... f)
494         throws MathIllegalArgumentException {
495 
496         MathUtils.checkDimension(f.length, getOrder() + 1);
497         final FieldDerivativeStructure<T> result = factory.build();
498         factory.getCompiler().compose(data, 0, f, result.data, 0);
499         return result;
500     }
501 
502     /** {@inheritDoc} */
503     @Override
504     public FieldDerivativeStructure<T> reciprocal() {
505         final FieldDerivativeStructure<T> result = factory.build();
506         factory.getCompiler().reciprocal(data, 0, result.data, 0);
507         return result;
508     }
509 
510     /** {@inheritDoc}
511      */
512     @Override
513     public FieldDerivativeStructure<T> sqrt() {
514         final FieldDerivativeStructure<T> result = factory.build();
515         factory.getCompiler().sqrt(data, 0, result.data, 0);
516         return result;
517     }
518 
519     /** {@inheritDoc}
520      */
521     @Override
522     public FieldDerivativeStructure<T> rootN(final int n) {
523         final FieldDerivativeStructure<T> result = factory.build();
524         factory.getCompiler().rootN(data, 0, n, result.data, 0);
525         return result;
526     }
527 
528     /** {@inheritDoc} */
529     @Override
530     public Field<FieldDerivativeStructure<T>> getField() {
531         return factory.getDerivativeField();
532     }
533 
534     /** Compute a<sup>x</sup> where a is a double and x a {@link FieldDerivativeStructure}
535      * @param a number to exponentiate
536      * @param x power to apply
537      * @param <T> the type of the field elements
538      * @return a<sup>x</sup>
539      */
540     public static <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T> pow(final double a, final FieldDerivativeStructure<T> x) {
541         final FieldDerivativeStructure<T> result = x.factory.build();
542         x.factory.getCompiler().pow(a, x.data, 0, result.data, 0);
543         return result;
544     }
545 
546     /** {@inheritDoc}
547      */
548     @Override
549     public FieldDerivativeStructure<T> pow(final double p) {
550         final FieldDerivativeStructure<T> result = factory.build();
551         factory.getCompiler().pow(data, 0, p, result.data, 0);
552         return result;
553     }
554 
555     /** {@inheritDoc}
556      */
557     @Override
558     public FieldDerivativeStructure<T> pow(final int n) {
559         final FieldDerivativeStructure<T> result = factory.build();
560         factory.getCompiler().pow(data, 0, n, result.data, 0);
561         return result;
562     }
563 
564     /** {@inheritDoc}
565      * @exception MathIllegalArgumentException if number of free parameters
566      * or orders do not match
567      */
568     @Override
569     public FieldDerivativeStructure<T> pow(final FieldDerivativeStructure<T> e)
570         throws MathIllegalArgumentException {
571         factory.checkCompatibility(e.factory);
572         final FieldDerivativeStructure<T> result = factory.build();
573         factory.getCompiler().pow(data, 0, e.data, 0, result.data, 0);
574         return result;
575     }
576 
577     /** {@inheritDoc}
578      */
579     @Override
580     public FieldDerivativeStructure<T> exp() {
581         final FieldDerivativeStructure<T> result = factory.build();
582         factory.getCompiler().exp(data, 0, result.data, 0);
583         return result;
584     }
585 
586     /** {@inheritDoc}
587      */
588     @Override
589     public FieldDerivativeStructure<T> expm1() {
590         final FieldDerivativeStructure<T> result = factory.build();
591         factory.getCompiler().expm1(data, 0, result.data, 0);
592         return result;
593     }
594 
595     /** {@inheritDoc}
596      */
597     @Override
598     public FieldDerivativeStructure<T> log() {
599         final FieldDerivativeStructure<T> result = factory.build();
600         factory.getCompiler().log(data, 0, result.data, 0);
601         return result;
602     }
603 
604     /** {@inheritDoc}
605      */
606     @Override
607     public FieldDerivativeStructure<T> log1p() {
608         final FieldDerivativeStructure<T> result = factory.build();
609         factory.getCompiler().log1p(data, 0, result.data, 0);
610         return result;
611     }
612 
613     /** Base 10 logarithm.
614      * @return base 10 logarithm of the instance
615      */
616     @Override
617     public FieldDerivativeStructure<T> log10() {
618         final FieldDerivativeStructure<T> result = factory.build();
619         factory.getCompiler().log10(data, 0, result.data, 0);
620         return result;
621     }
622 
623     /** {@inheritDoc}
624      */
625     @Override
626     public FieldDerivativeStructure<T> cos() {
627         final FieldDerivativeStructure<T> result = factory.build();
628         factory.getCompiler().cos(data, 0, result.data, 0);
629         return result;
630     }
631 
632     /** {@inheritDoc}
633      */
634     @Override
635     public FieldDerivativeStructure<T> sin() {
636         final FieldDerivativeStructure<T> result = factory.build();
637         factory.getCompiler().sin(data, 0, result.data, 0);
638         return result;
639     }
640 
641     /** {@inheritDoc}
642      */
643     @Override
644     public FieldSinCos<FieldDerivativeStructure<T>> sinCos() {
645         final FieldDerivativeStructure<T> sin = factory.build();
646         final FieldDerivativeStructure<T> cos = factory.build();
647         factory.getCompiler().sinCos(data, 0, sin.data, 0, cos.data, 0);
648         return new FieldSinCos<>(sin, cos);
649     }
650 
651     /** {@inheritDoc}
652      */
653     @Override
654     public FieldDerivativeStructure<T> tan() {
655         final FieldDerivativeStructure<T> result = factory.build();
656         factory.getCompiler().tan(data, 0, result.data, 0);
657         return result;
658     }
659 
660     /** {@inheritDoc}
661      */
662     @Override
663     public FieldDerivativeStructure<T> acos() {
664         final FieldDerivativeStructure<T> result = factory.build();
665         factory.getCompiler().acos(data, 0, result.data, 0);
666         return result;
667     }
668 
669     /** {@inheritDoc}
670      */
671     @Override
672     public FieldDerivativeStructure<T> asin() {
673         final FieldDerivativeStructure<T> result = factory.build();
674         factory.getCompiler().asin(data, 0, result.data, 0);
675         return result;
676     }
677 
678     /** {@inheritDoc}
679      */
680     @Override
681     public FieldDerivativeStructure<T> atan() {
682         final FieldDerivativeStructure<T> result = factory.build();
683         factory.getCompiler().atan(data, 0, result.data, 0);
684         return result;
685     }
686 
687     /** {@inheritDoc}
688      */
689     @Override
690     public FieldDerivativeStructure<T> atan2(final FieldDerivativeStructure<T> x)
691         throws MathIllegalArgumentException {
692         factory.checkCompatibility(x.factory);
693         final FieldDerivativeStructure<T> result = factory.build();
694         factory.getCompiler().atan2(data, 0, x.data, 0, result.data, 0);
695         return result;
696     }
697 
698     /** Two arguments arc tangent operation.
699      * @param y first argument of the arc tangent
700      * @param x second argument of the arc tangent
701      * @param <T> the type of the field elements
702      * @return atan2(y, x)
703      * @exception MathIllegalArgumentException if number of free parameters
704      * or orders do not match
705      */
706     public static <T extends CalculusFieldElement<T>> FieldDerivativeStructure<T> atan2(final FieldDerivativeStructure<T> y,
707                                                                                         final FieldDerivativeStructure<T> x)
708         throws MathIllegalArgumentException {
709         return y.atan2(x);
710     }
711 
712     /** {@inheritDoc}
713      */
714     @Override
715     public FieldDerivativeStructure<T> cosh() {
716         final FieldDerivativeStructure<T> result = factory.build();
717         factory.getCompiler().cosh(data, 0, result.data, 0);
718         return result;
719     }
720 
721     /** {@inheritDoc}
722      */
723     @Override
724     public FieldDerivativeStructure<T> sinh() {
725         final FieldDerivativeStructure<T> result = factory.build();
726         factory.getCompiler().sinh(data, 0, result.data, 0);
727         return result;
728     }
729 
730     /** {@inheritDoc}
731      */
732     @Override
733     public FieldSinhCosh<FieldDerivativeStructure<T>> sinhCosh() {
734         final FieldDerivativeStructure<T> sinh = factory.build();
735         final FieldDerivativeStructure<T> cosh = factory.build();
736         factory.getCompiler().sinhCosh(data, 0, sinh.data, 0, cosh.data, 0);
737         return new FieldSinhCosh<>(sinh, cosh);
738     }
739 
740     /** {@inheritDoc}
741      */
742     @Override
743     public FieldDerivativeStructure<T> tanh() {
744         final FieldDerivativeStructure<T> result = factory.build();
745         factory.getCompiler().tanh(data, 0, result.data, 0);
746         return result;
747     }
748 
749     /** {@inheritDoc}
750      */
751     @Override
752     public FieldDerivativeStructure<T> acosh() {
753         final FieldDerivativeStructure<T> result = factory.build();
754         factory.getCompiler().acosh(data, 0, result.data, 0);
755         return result;
756     }
757 
758     /** {@inheritDoc}
759      */
760     @Override
761     public FieldDerivativeStructure<T> asinh() {
762         final FieldDerivativeStructure<T> result = factory.build();
763         factory.getCompiler().asinh(data, 0, result.data, 0);
764         return result;
765     }
766 
767     /** {@inheritDoc}
768      */
769     @Override
770     public FieldDerivativeStructure<T> atanh() {
771         final FieldDerivativeStructure<T> result = factory.build();
772         factory.getCompiler().atanh(data, 0, result.data, 0);
773         return result;
774     }
775 
776     /** {@inheritDoc} */
777     @Override
778     public FieldDerivativeStructure<T> toDegrees() {
779         final FieldDerivativeStructure<T> ds = factory.build();
780         for (int i = 0; i < ds.data.length; ++i) {
781             ds.data[i] = data[i].toDegrees();
782         }
783         return ds;
784     }
785 
786     /** {@inheritDoc} */
787     @Override
788     public FieldDerivativeStructure<T> toRadians() {
789         final FieldDerivativeStructure<T> ds = factory.build();
790         for (int i = 0; i < ds.data.length; ++i) {
791             ds.data[i] = data[i].toRadians();
792         }
793         return ds;
794     }
795 
796     /** Integrate w.r.t. one independent variable.
797      * <p>
798      * Rigorously, if the derivatives of a function are known up to
799      * order N, the ones of its M-th integral w.r.t. a given variable
800      * (seen as a function itself) are actually known up to order N+M.
801      * However, this method still casts the output as a DerivativeStructure
802      * of order N. The integration constants are systematically set to zero.
803      * </p>
804      * @param varIndex Index of independent variable w.r.t. which integration is done.
805      * @param integrationOrder Number of times the integration operator must be applied. If non-positive, call the
806      *                         differentiation operator.
807      * @return DerivativeStructure on which integration operator has been applied a certain number of times.
808      * @since 2.2
809      */
810     public FieldDerivativeStructure<T> integrate(final int varIndex, final int integrationOrder) {
811 
812         // Deal first with trivial case
813         if (integrationOrder > getOrder()) {
814             return factory.constant(0.);
815         } else if (integrationOrder == 0) {
816             return factory.build(data);
817         }
818 
819         // Call 'inverse' (not rigorously) operation if necessary
820         if (integrationOrder < 0) {
821             return differentiate(varIndex, -integrationOrder);
822         }
823 
824         final T[] newData = MathArrays.buildArray(factory.getValueField(), data.length);
825         final DSCompiler dsCompiler = factory.getCompiler();
826         for (int i = 0; i < newData.length; i++) {
827             if (!data[i].isZero()) {
828                 final int[] orders = dsCompiler.getPartialDerivativeOrders(i);
829                 int sum = 0;
830                 for (int order : orders) {
831                     sum += order;
832                 }
833                 if (sum + integrationOrder <= getOrder()) {
834                     final int saved = orders[varIndex];
835                     orders[varIndex] += integrationOrder;
836                     final int index = dsCompiler.getPartialDerivativeIndex(orders);
837                     orders[varIndex] = saved;
838                     newData[index] = data[i];
839                 }
840             }
841         }
842 
843         return factory.build(newData);
844     }
845 
846     /** Differentiate w.r.t. one independent variable.
847      * <p>
848      * Rigorously, if the derivatives of a function are known up to
849      * order N, the ones of its M-th derivative w.r.t. a given variable
850      * (seen as a function itself) are only known up to order N-M.
851      * However, this method still casts the output as a DerivativeStructure
852      * of order N with zeroes for the higher order terms.
853      * </p>
854      * @param varIndex Index of independent variable w.r.t. which differentiation is done.
855      * @param differentiationOrder Number of times the differentiation operator must be applied. If non-positive, call
856      *                             the integration operator instead.
857      * @return DerivativeStructure on which differentiation operator has been applied a certain number of times
858      * @since 2.2
859      */
860     public FieldDerivativeStructure<T> differentiate(final int varIndex, final int differentiationOrder) {
861 
862         // Deal first with trivial case
863         if (differentiationOrder > getOrder()) {
864             return factory.constant(0.);
865         } else if (differentiationOrder == 0) {
866             return factory.build(data);
867         }
868 
869         // Call 'inverse' (not rigorously) operation if necessary
870         if (differentiationOrder < 0) {
871             return integrate(varIndex, -differentiationOrder);
872         }
873 
874         final T[] newData = MathArrays.buildArray(factory.getValueField(), data.length);
875         final DSCompiler dsCompiler = factory.getCompiler();
876         for (int i = 0; i < newData.length; i++) {
877             if (!data[i].isZero()) {
878                 final int[] orders = dsCompiler.getPartialDerivativeOrders(i);
879                 if (orders[varIndex] - differentiationOrder >= 0) {
880                     final int saved = orders[varIndex];
881                     orders[varIndex] -= differentiationOrder;
882                     final int index = dsCompiler.getPartialDerivativeIndex(orders);
883                     orders[varIndex] = saved;
884                     newData[index] = data[i];
885                 }
886             }
887         }
888 
889         return factory.build(newData);
890     }
891 
892     /** Evaluate Taylor expansion of a derivative structure.
893      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
894      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
895      * @throws MathRuntimeException if factorials becomes too large
896      */
897     @SafeVarargs
898     public final T taylor(final T ... delta) throws MathRuntimeException {
899         return factory.getCompiler().taylor(data, 0, delta);
900     }
901 
902     /** Evaluate Taylor expansion of a derivative structure.
903      * @param delta parameters offsets (&Delta;x, &Delta;y, ...)
904      * @return value of the Taylor expansion at x + &Delta;x, y + &Delta;y, ...
905      * @throws MathRuntimeException if factorials becomes too large
906      */
907     public T taylor(final double ... delta) throws MathRuntimeException {
908         return factory.getCompiler().taylor(data, 0, delta);
909     }
910 
911     /** Rebase instance with respect to low level parameter functions.
912      * <p>
913      * The instance is considered to be a function of {@link #getFreeParameters()
914      * n free parameters} up to order {@link #getOrder() o} \(f(p_0, p_1, \ldots p_{n-1})\).
915      * Its {@link #getPartialDerivative(int...) partial derivatives} are therefore
916      * \(f, \frac{\partial f}{\partial p_0}, \frac{\partial f}{\partial p_1}, \ldots
917      * \frac{\partial^2 f}{\partial p_0^2}, \frac{\partial^2 f}{\partial p_0 p_1},
918      * \ldots \frac{\partial^o f}{\partial p_{n-1}^o}\). The free parameters
919      * \(p_0, p_1, \ldots p_{n-1}\) are considered to be functions of \(m\) lower
920      * level other parameters \(q_0, q_1, \ldots q_{m-1}\).
921      * </p>
922      * \( \begin{align}
923      * p_0 &amp; = p_0(q_0, q_1, \ldots q_{m-1})\\
924      * p_1 &amp; = p_1(q_0, q_1, \ldots q_{m-1})\\
925      * p_{n-1} &amp; = p_{n-1}(q_0, q_1, \ldots q_{m-1})
926      * \end{align}\)
927      * <p>
928      * This method compute the composition of the partial derivatives of \(f\)
929      * and the partial derivatives of \(p_0, p_1, \ldots p_{n-1}\), i.e. the
930      * {@link #getPartialDerivative(int...) partial derivatives} of the value
931      * returned will be
932      * \(f, \frac{\partial f}{\partial q_0}, \frac{\partial f}{\partial q_1}, \ldots
933      * \frac{\partial^2 f}{\partial q_0^2}, \frac{\partial^2 f}{\partial q_0 q_1},
934      * \ldots \frac{\partial^o f}{\partial q_{m-1}^o}\).
935      * </p>
936      * <p>
937      * The number of parameters must match {@link #getFreeParameters()} and the
938      * derivation orders of the instance and parameters must also match.
939      * </p>
940      * @param p base parameters with respect to which partial derivatives
941      * were computed in the instance
942      * @return derivative structure with partial derivatives computed
943      * with respect to the lower level parameters used in the \(p_i\)
944      * @since 2.2
945      */
946     public FieldDerivativeStructure<T> rebase(@SuppressWarnings("unchecked") final FieldDerivativeStructure<T>... p) {
947 
948         MathUtils.checkDimension(getFreeParameters(), p.length);
949 
950         // handle special case of no variables at all
951         if (p.length == 0) {
952             return this;
953         }
954 
955         final int pSize = p[0].getFactory().getCompiler().getSize();
956         final T[] pData = MathArrays.buildArray(p[0].getFactory().getValueField(), p.length * pSize);
957         for (int i = 0; i < p.length; ++i) {
958             MathUtils.checkDimension(getOrder(), p[i].getOrder());
959             MathUtils.checkDimension(p[0].getFreeParameters(), p[i].getFreeParameters());
960             System.arraycopy(p[i].data, 0, pData, i * pSize, pSize);
961         }
962 
963         final FieldDerivativeStructure<T> result = p[0].factory.build();
964         factory.getCompiler().rebase(data, 0, p[0].factory.getCompiler(), pData, result.data, 0);
965         return result;
966 
967     }
968 
969     /** {@inheritDoc}
970      * @exception MathIllegalArgumentException if number of free parameters
971      * or orders do not match
972      */
973     @Override
974     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T>[] a,
975                                                          final FieldDerivativeStructure<T>[] b)
976         throws MathIllegalArgumentException {
977 
978         // compute an accurate value, taking care of cancellations
979         final T[] aT = MathArrays.buildArray(factory.getValueField(), a.length);
980         for (int i = 0; i < a.length; ++i) {
981             aT[i] = a[i].getValue();
982         }
983         final T[] bT = MathArrays.buildArray(factory.getValueField(), b.length);
984         for (int i = 0; i < b.length; ++i) {
985             bT[i] = b[i].getValue();
986         }
987         final T accurateValue = aT[0].linearCombination(aT, bT);
988 
989         // compute a simple value, with all partial derivatives
990         FieldDerivativeStructure<T> simpleValue = a[0].getField().getZero();
991         for (int i = 0; i < a.length; ++i) {
992             simpleValue = simpleValue.add(a[i].multiply(b[i]));
993         }
994 
995         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
996         final T[] all = simpleValue.getAllDerivatives();
997         all[0] = accurateValue;
998         return factory.build(all);
999 
1000     }
1001 
1002     /**
1003      * Compute a linear combination.
1004      * @param a Factors.
1005      * @param b Factors.
1006      * @return <code>&Sigma;<sub>i</sub> a<sub>i</sub> b<sub>i</sub></code>.
1007      * @throws MathIllegalArgumentException if arrays dimensions don't match
1008      */
1009     public FieldDerivativeStructure<T> linearCombination(final T[] a, final FieldDerivativeStructure<T>[] b)
1010                     throws MathIllegalArgumentException {
1011 
1012         // compute an accurate value, taking care of cancellations
1013         final T[] bT = MathArrays.buildArray(factory.getValueField(), b.length);
1014         for (int i = 0; i < b.length; ++i) {
1015             bT[i] = b[i].getValue();
1016         }
1017         final T accurateValue = bT[0].linearCombination(a, bT);
1018 
1019         // compute a simple value, with all partial derivatives
1020         FieldDerivativeStructure<T> simpleValue = b[0].getField().getZero();
1021         for (int i = 0; i < a.length; ++i) {
1022             simpleValue = simpleValue.add(b[i].multiply(a[i]));
1023         }
1024 
1025         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
1026         final T[] all = simpleValue.getAllDerivatives();
1027         all[0] = accurateValue;
1028         return factory.build(all);
1029 
1030     }
1031 
1032     /** {@inheritDoc}
1033      * @exception MathIllegalArgumentException if number of free parameters
1034      * or orders do not match
1035      */
1036     @Override
1037     public FieldDerivativeStructure<T> linearCombination(final double[] a, final FieldDerivativeStructure<T>[] b)
1038         throws MathIllegalArgumentException {
1039 
1040         // compute an accurate value, taking care of cancellations
1041         final T[] bT = MathArrays.buildArray(factory.getValueField(), b.length);
1042         for (int i = 0; i < b.length; ++i) {
1043             bT[i] = b[i].getValue();
1044         }
1045         final T accurateValue = bT[0].linearCombination(a, bT);
1046 
1047         // compute a simple value, with all partial derivatives
1048         FieldDerivativeStructure<T> simpleValue = b[0].getField().getZero();
1049         for (int i = 0; i < a.length; ++i) {
1050             simpleValue = simpleValue.add(b[i].multiply(a[i]));
1051         }
1052 
1053         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
1054         final T[] all = simpleValue.getAllDerivatives();
1055         all[0] = accurateValue;
1056         return factory.build(all);
1057 
1058     }
1059 
1060     /** {@inheritDoc}
1061      * @exception MathIllegalArgumentException if number of free parameters
1062      * or orders do not match
1063      */
1064     @Override
1065     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T> a1, final FieldDerivativeStructure<T> b1,
1066                                                          final FieldDerivativeStructure<T> a2, final FieldDerivativeStructure<T> b2)
1067         throws MathIllegalArgumentException {
1068 
1069         // compute an accurate value, taking care of cancellations
1070         final T accurateValue = a1.getValue().linearCombination(a1.getValue(), b1.getValue(),
1071                                                                 a2.getValue(), b2.getValue());
1072 
1073         // compute a simple value, with all partial derivatives
1074         final FieldDerivativeStructure<T> simpleValue = a1.multiply(b1).add(a2.multiply(b2));
1075 
1076         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
1077         final T[] all = simpleValue.getAllDerivatives();
1078         all[0] = accurateValue;
1079         return factory.build(all);
1080 
1081     }
1082 
1083     /**
1084      * Compute a linear combination.
1085      * @param a1 first factor of the first term
1086      * @param b1 second factor of the first term
1087      * @param a2 first factor of the second term
1088      * @param b2 second factor of the second term
1089      * @return a<sub>1</sub>&times;b<sub>1</sub> +
1090      * a<sub>2</sub>&times;b<sub>2</sub>
1091      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure)
1092      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure)
1093      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
1094      */
1095     public FieldDerivativeStructure<T> linearCombination(final T a1, final FieldDerivativeStructure<T> b1,
1096                                                          final T a2, final FieldDerivativeStructure<T> b2)
1097         throws MathIllegalArgumentException {
1098 
1099         factory.checkCompatibility(b1.factory);
1100         factory.checkCompatibility(b2.factory);
1101 
1102         final FieldDerivativeStructure<T> ds = factory.build();
1103         factory.getCompiler().linearCombination(a1, b1.data, 0,
1104                                                 a2, b2.data, 0,
1105                                                 ds.data, 0);
1106 
1107         return ds;
1108 
1109     }
1110 
1111     /** {@inheritDoc}
1112      * @exception MathIllegalArgumentException if number of free parameters
1113      * or orders do not match
1114      */
1115     @Override
1116     public FieldDerivativeStructure<T> linearCombination(final double a1, final FieldDerivativeStructure<T> b1,
1117                                                          final double a2, final FieldDerivativeStructure<T> b2)
1118         throws MathIllegalArgumentException {
1119 
1120         factory.checkCompatibility(b1.factory);
1121         factory.checkCompatibility(b2.factory);
1122 
1123         final FieldDerivativeStructure<T> ds = factory.build();
1124         factory.getCompiler().linearCombination(a1, b1.data, 0,
1125                                                 a2, b2.data, 0,
1126                                                 ds.data, 0);
1127 
1128         return ds;
1129 
1130     }
1131 
1132     /** {@inheritDoc}
1133      * @exception MathIllegalArgumentException if number of free parameters
1134      * or orders do not match
1135      */
1136     @Override
1137     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T> a1, final FieldDerivativeStructure<T> b1,
1138                                                          final FieldDerivativeStructure<T> a2, final FieldDerivativeStructure<T> b2,
1139                                                          final FieldDerivativeStructure<T> a3, final FieldDerivativeStructure<T> b3)
1140         throws MathIllegalArgumentException {
1141 
1142         // compute an accurate value, taking care of cancellations
1143         final T accurateValue = a1.getValue().linearCombination(a1.getValue(), b1.getValue(),
1144                                                                 a2.getValue(), b2.getValue(),
1145                                                                 a3.getValue(), b3.getValue());
1146 
1147         // compute a simple value, with all partial derivatives
1148         final FieldDerivativeStructure<T> simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3));
1149 
1150         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
1151         final T[] all = simpleValue.getAllDerivatives();
1152         all[0] = accurateValue;
1153         return factory.build(all);
1154 
1155     }
1156 
1157     /**
1158      * Compute a linear combination.
1159      * @param a1 first factor of the first term
1160      * @param b1 second factor of the first term
1161      * @param a2 first factor of the second term
1162      * @param b2 second factor of the second term
1163      * @param a3 first factor of the third term
1164      * @param b3 second factor of the third term
1165      * @return a<sub>1</sub>&times;b<sub>1</sub> +
1166      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub>
1167      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure)
1168      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure)
1169      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
1170      */
1171     public FieldDerivativeStructure<T> linearCombination(final T a1, final FieldDerivativeStructure<T> b1,
1172                                                          final T a2, final FieldDerivativeStructure<T> b2,
1173                                                          final T a3, final FieldDerivativeStructure<T> b3)
1174         throws MathIllegalArgumentException {
1175 
1176         factory.checkCompatibility(b1.factory);
1177         factory.checkCompatibility(b2.factory);
1178         factory.checkCompatibility(b3.factory);
1179 
1180         final FieldDerivativeStructure<T> ds = factory.build();
1181         factory.getCompiler().linearCombination(a1, b1.data, 0,
1182                                                 a2, b2.data, 0,
1183                                                 a3, b3.data, 0,
1184                                                 ds.data, 0);
1185 
1186         return ds;
1187 
1188     }
1189 
1190     /** {@inheritDoc}
1191      * @exception MathIllegalArgumentException if number of free parameters
1192      * or orders do not match
1193      */
1194     @Override
1195     public FieldDerivativeStructure<T> linearCombination(final double a1, final FieldDerivativeStructure<T> b1,
1196                                                          final double a2, final FieldDerivativeStructure<T> b2,
1197                                                          final double a3, final FieldDerivativeStructure<T> b3)
1198         throws MathIllegalArgumentException {
1199 
1200         factory.checkCompatibility(b1.factory);
1201         factory.checkCompatibility(b2.factory);
1202         factory.checkCompatibility(b3.factory);
1203 
1204         final FieldDerivativeStructure<T> ds = factory.build();
1205         factory.getCompiler().linearCombination(a1, b1.data, 0,
1206                                                 a2, b2.data, 0,
1207                                                 a3, b3.data, 0,
1208                                                 ds.data, 0);
1209 
1210         return ds;
1211 
1212     }
1213 
1214     /** {@inheritDoc}
1215      * @exception MathIllegalArgumentException if number of free parameters
1216      * or orders do not match
1217      */
1218     @Override
1219     public FieldDerivativeStructure<T> linearCombination(final FieldDerivativeStructure<T> a1, final FieldDerivativeStructure<T> b1,
1220                                                          final FieldDerivativeStructure<T> a2, final FieldDerivativeStructure<T> b2,
1221                                                          final FieldDerivativeStructure<T> a3, final FieldDerivativeStructure<T> b3,
1222                                                          final FieldDerivativeStructure<T> a4, final FieldDerivativeStructure<T> b4)
1223         throws MathIllegalArgumentException {
1224 
1225         // compute an accurate value, taking care of cancellations
1226         final T accurateValue = a1.getValue().linearCombination(a1.getValue(), b1.getValue(),
1227                                                                 a2.getValue(), b2.getValue(),
1228                                                                 a3.getValue(), b3.getValue(),
1229                                                                 a4.getValue(), b4.getValue());
1230 
1231         // compute a simple value, with all partial derivatives
1232         final FieldDerivativeStructure<T> simpleValue = a1.multiply(b1).add(a2.multiply(b2)).add(a3.multiply(b3)).add(a4.multiply(b4));
1233 
1234         // create a result with accurate value and all derivatives (not necessarily as accurate as the value)
1235         final T[] all = simpleValue.getAllDerivatives();
1236         all[0] = accurateValue;
1237         return factory.build(all);
1238 
1239     }
1240 
1241     /**
1242      * Compute a linear combination.
1243      * @param a1 first factor of the first term
1244      * @param b1 second factor of the first term
1245      * @param a2 first factor of the second term
1246      * @param b2 second factor of the second term
1247      * @param a3 first factor of the third term
1248      * @param b3 second factor of the third term
1249      * @param a4 first factor of the third term
1250      * @param b4 second factor of the third term
1251      * @return a<sub>1</sub>&times;b<sub>1</sub> +
1252      * a<sub>2</sub>&times;b<sub>2</sub> + a<sub>3</sub>&times;b<sub>3</sub> +
1253      * a<sub>4</sub>&times;b<sub>4</sub>
1254      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure)
1255      * @see #linearCombination(double, FieldDerivativeStructure, double, FieldDerivativeStructure, double, FieldDerivativeStructure)
1256      * @exception MathIllegalArgumentException if number of free parameters or orders are inconsistent
1257      */
1258     public FieldDerivativeStructure<T> linearCombination(final T a1, final FieldDerivativeStructure<T> b1,
1259                                                          final T a2, final FieldDerivativeStructure<T> b2,
1260                                                          final T a3, final FieldDerivativeStructure<T> b3,
1261                                                          final T a4, final FieldDerivativeStructure<T> b4)
1262         throws MathIllegalArgumentException {
1263 
1264         factory.checkCompatibility(b1.factory);
1265         factory.checkCompatibility(b2.factory);
1266         factory.checkCompatibility(b3.factory);
1267         factory.checkCompatibility(b4.factory);
1268 
1269         final FieldDerivativeStructure<T> ds = factory.build();
1270         factory.getCompiler().linearCombination(a1, b1.data, 0,
1271                                                 a2, b2.data, 0,
1272                                                 a3, b3.data, 0,
1273                                                 a4, b4.data, 0,
1274                                                 ds.data, 0);
1275 
1276         return ds;
1277 
1278     }
1279 
1280     /** {@inheritDoc}
1281      * @exception MathIllegalArgumentException if number of free parameters
1282      * or orders do not match
1283      */
1284     @Override
1285     public FieldDerivativeStructure<T> linearCombination(final double a1, final FieldDerivativeStructure<T> b1,
1286                                                          final double a2, final FieldDerivativeStructure<T> b2,
1287                                                          final double a3, final FieldDerivativeStructure<T> b3,
1288                                                          final double a4, final FieldDerivativeStructure<T> b4)
1289         throws MathIllegalArgumentException {
1290 
1291         factory.checkCompatibility(b1.factory);
1292         factory.checkCompatibility(b2.factory);
1293         factory.checkCompatibility(b3.factory);
1294         factory.checkCompatibility(b4.factory);
1295 
1296         final FieldDerivativeStructure<T> ds = factory.build();
1297         factory.getCompiler().linearCombination(a1, b1.data, 0,
1298                                                 a2, b2.data, 0,
1299                                                 a3, b3.data, 0,
1300                                                 a4, b4.data, 0,
1301                                                 ds.data, 0);
1302 
1303         return ds;
1304 
1305     }
1306 
1307     /** {@inheritDoc}
1308      */
1309     @Override
1310     public FieldDerivativeStructure<T> getPi() {
1311         return factory.getDerivativeField().getPi();
1312     }
1313 
1314     /**
1315      * Test for the equality of two derivative structures.
1316      * <p>
1317      * Derivative structures are considered equal if they have the same number
1318      * of free parameters, the same derivation order, and the same derivatives.
1319      * </p>
1320      * @param other Object to test for equality to this
1321      * @return true if two derivative structures are equal
1322      */
1323     @Override
1324     public boolean equals(Object other) {
1325 
1326         if (this == other) {
1327             return true;
1328         }
1329 
1330         if (other instanceof FieldDerivativeStructure &&
1331             ((FieldDerivativeStructure<?>) other).getField().equals(getField())) {
1332             final FieldDerivativeStructure<T> rhs = (FieldDerivativeStructure<T>) other;
1333             return (getFreeParameters() == rhs.getFreeParameters()) &&
1334                    (getOrder() == rhs.getOrder()) &&
1335                    MathArrays.equals(data, rhs.data);
1336         }
1337 
1338         return false;
1339 
1340     }
1341 
1342     /**
1343      * Get a hashCode for the derivative structure.
1344      * @return a hash code value for this object
1345      */
1346     @Override
1347     public int hashCode() {
1348         return 227 + 229 * getFreeParameters() + 233 * getOrder() + 239 * Arrays.hashCode(data);
1349     }
1350 
1351 }