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