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.CalculusFieldElementAbstractTest;
21  import org.hipparchus.Field;
22  import org.hipparchus.analysis.FieldUnivariateFunction;
23  import org.hipparchus.exception.LocalizedCoreFormats;
24  import org.hipparchus.exception.MathIllegalArgumentException;
25  import org.hipparchus.util.FastMath;
26  import org.hipparchus.util.FieldSinCos;
27  import org.hipparchus.util.MathArrays;
28  import org.junit.jupiter.api.Test;
29  
30  import static org.junit.jupiter.api.Assertions.assertEquals;
31  import static org.junit.jupiter.api.Assertions.assertNotEquals;
32  import static org.junit.jupiter.api.Assertions.assertNotSame;
33  import static org.junit.jupiter.api.Assertions.assertSame;
34  import static org.junit.jupiter.api.Assertions.fail;
35  
36  /**
37   * Test for class {@link FieldGradient}.
38   */
39  public abstract class FieldGradientAbstractTest<T extends CalculusFieldElement<T>>
40      extends CalculusFieldElementAbstractTest<FieldGradient<T>> {
41  
42      protected abstract Field<T> getValueField();
43  
44      protected FieldGradient<T> build(final double x) {
45          // the function is really a two variables function : f(x) = g(x, 0) with g(x, y) = x + y / 1024
46          return build(x, 1.0, FastMath.scalb(1.0, -10));
47      }
48  
49      protected FieldGradient<T> build(final double x, final double... derivatives) {
50          final Field<T> valueField = getValueField();
51          final T[] gradient = MathArrays.buildArray(valueField, derivatives.length);
52          for (int i = 0; i < gradient.length;++i) {
53              gradient[i] = valueField.getZero().newInstance(derivatives[i]);
54          }
55          return new FieldGradient<>(valueField.getZero().newInstance(x), gradient);
56      }
57  
58      protected T buildScalar(double value) {
59          return getValueField().getZero().newInstance(value);
60      }
61  
62      @Test
63      public void testFieldAdd() {
64          check(build(1.0).add(buildScalar(5.0)), 6.0, 1.0);
65      }
66  
67      @Test
68      public void testFieldSubtract() {
69          check(build(1.0).subtract(buildScalar(5.0)), -4.0, 1.0);
70      }
71  
72      @Test
73      public void testFieldMultiply() {
74          check(build(1.0).multiply(buildScalar(5.0)), 5.0, 5.0);
75      }
76  
77      @Test
78      public void testFieldDivide() {
79          check(build(1.0).divide(buildScalar(5.0)), 0.2, 0.2);
80      }
81  
82      @Test
83      public void testgetGradient() {
84          FieldGradient<T> g = build(-0.5, 2.5, 10.0, -1.0);
85          assertEquals(-0.5, g.getReal(), 1.0e-15);
86          assertEquals(-0.5, g.getValue().getReal(), 1.0e-15);
87          assertEquals(+2.5, g.getGradient()[0].getReal(), 1.0e-15);
88          assertEquals(10.0, g.getGradient()[1].getReal(), 1.0e-15);
89          assertEquals(-1.0, g.getGradient()[2].getReal(), 1.0e-15);
90          assertEquals(+2.5, g.getPartialDerivative(0).getReal(), 1.0e-15);
91          assertEquals(10.0, g.getPartialDerivative(1).getReal(), 1.0e-15);
92          assertEquals(-1.0, g.getPartialDerivative(2).getReal(), 1.0e-15);
93          assertEquals(3, g.getFreeParameters());
94          try {
95              g.getPartialDerivative(-1);
96              fail("an exception should have been thrown");
97          } catch (MathIllegalArgumentException miae) {
98              assertEquals(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, miae.getSpecifier());
99          }
100         try {
101             g.getPartialDerivative(+3);
102             fail("an exception should have been thrown");
103         } catch (MathIllegalArgumentException miae) {
104             assertEquals(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, miae.getSpecifier());
105         }
106     }
107 
108     @Test
109     public void testConstant() {
110         FieldGradient<T> g = FieldGradient.constant(5, getValueField().getZero().newInstance(-4.5));
111         assertEquals(5, g.getFreeParameters());
112         assertEquals(getValueField(), g.getValue().getField());
113         assertEquals(-4.5, g.getValue().getReal(), 1.0e-15);
114         for (int i = 0 ; i < g.getFreeParameters(); ++i) {
115             assertEquals(0.0, g.getPartialDerivative(i).getReal(), 1.0e-15);
116         }
117     }
118 
119     @Test
120     public void testVariable() {
121         FieldGradient<T> g = FieldGradient.variable(5, 1, getValueField().getZero().newInstance(-4.5));
122         assertEquals(5, g.getFreeParameters());
123         assertEquals(getValueField(), g.getValue().getField());
124         assertEquals(-4.5, g.getValue().getReal(), 1.0e-15);
125         for (int i = 0 ; i < g.getFreeParameters(); ++i) {
126             assertEquals(i == 1 ? 1.0 : 0.0, g.getPartialDerivative(i).getReal(), 1.0e-15);
127         }
128     }
129 
130     @Test
131     public void testDoublePow() {
132         assertSame(build(3).getField().getZero(), FieldGradient.pow(0.0, build(1.5)));
133         FieldGradient<T> g = FieldGradient.pow(2.0, build(1.5));
134         FDSFactory<T> factory = new FDSFactory<>(getValueField(), 2, 1);
135         FieldDerivativeStructure<T> ds = factory.constant(2.0).pow(factory.build(1.5, 1.0, FastMath.scalb(1.0, -10)));
136         assertEquals(ds.getValue().getReal(), g.getValue().getReal(), 1.0e-15);
137         final int[] indices = new int[ds.getFreeParameters()];
138         for (int i = 0; i < g.getFreeParameters(); ++i) {
139             indices[i] = 1;
140             assertEquals(ds.getPartialDerivative(indices).getReal(), g.getPartialDerivative(i).getReal(), 1.0e-15);
141             indices[i] = 0;
142         }
143     }
144 
145     @Test
146     public void testTaylor() {
147         assertEquals(2.75, build(2, 1, 0.125).taylor(0.5, 2.0).getReal(), 1.0e-15);
148     }
149 
150     @Test
151     public void testOrder() {
152         assertEquals(1, build(2).getOrder());
153     }
154 
155     @Test
156     public void testGetPartialDerivative() {
157         final FieldGradient<T> g = build(2);
158         assertEquals(2.0,        g.getPartialDerivative(0, 0).getReal(), 1.0e-15); // f(x,y)
159         assertEquals(1.0,        g.getPartialDerivative(1, 0).getReal(), 1.0e-15); // ∂f/∂x
160         assertEquals(1.0 / 1024, g.getPartialDerivative(0, 1).getReal(), 1.0e-15); // ∂f/∂y
161     }
162 
163     @Test
164     public void testGetPartialDerivativeErrors() {
165         final FieldGradient<T> g = build(2);
166         try {
167             g.getPartialDerivative(0, 0, 0);
168             fail("an exception should have been thrown");
169         } catch (MathIllegalArgumentException miae) {
170             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
171             assertEquals(3, ((Integer) miae.getParts()[0]).intValue());
172             assertEquals(2, ((Integer) miae.getParts()[1]).intValue());
173         }
174         try {
175             g.getPartialDerivative(0, 5);
176             fail("an exception should have been thrown");
177         } catch (MathIllegalArgumentException miae) {
178             assertEquals(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, miae.getSpecifier());
179             assertEquals(5, ((Integer) miae.getParts()[0]).intValue());
180         }
181         try {
182             g.getPartialDerivative(1, 1);
183             fail("an exception should have been thrown");
184         } catch (MathIllegalArgumentException miae) {
185             assertEquals(LocalizedCoreFormats.DERIVATION_ORDER_NOT_ALLOWED, miae.getSpecifier());
186             assertEquals(1, ((Integer) miae.getParts()[0]).intValue());
187         }
188     }
189 
190     @Test
191     public void testHashcode() {
192         assertEquals(1608501298, build(2, 1, -0.25).hashCode());
193     }
194 
195     @Test
196     public void testEquals() {
197         FieldGradient<T> g = build(12, -34, 56);
198         assertEquals(g, g);
199         assertNotEquals("", g);
200         assertEquals(g, build(12, -34, 56));
201         assertNotEquals(g, build(21, -34, 56));
202         assertNotEquals(g, build(12, -43, 56));
203         assertNotEquals(g, build(12, -34, 65));
204         assertNotEquals(g, build(21, -43, 65));
205     }
206 
207     @Test
208     public void testRunTimeClass() {
209         Field<FieldGradient<T>> field = build(0.0).getField();
210         assertEquals(FieldGradient.class, field.getRuntimeClass());
211     }
212 
213     @Test
214     public void testConversion() {
215         FieldGradient<T> gA = build(-0.5, 2.5, 4.5);
216         FieldDerivativeStructure<T> ds = gA.toDerivativeStructure();
217         assertEquals(2, ds.getFreeParameters());
218         assertEquals(1, ds.getOrder());
219         assertEquals(-0.5, ds.getValue().getReal(), 1.0e-15);
220         assertEquals(-0.5, ds.getPartialDerivative(0, 0).getReal(), 1.0e-15);
221         assertEquals( 2.5, ds.getPartialDerivative(1, 0).getReal(), 1.0e-15);
222         assertEquals( 4.5, ds.getPartialDerivative(0, 1).getReal(), 1.0e-15);
223         FieldGradient<T> gB = new FieldGradient<>(ds);
224         assertNotSame(gA, gB);
225         assertEquals(gA, gB);
226         try {
227             new FieldGradient<>(new FDSFactory<>(getValueField(), 1, 2).variable(0, 1.0));
228             fail("an exception should have been thrown");
229         } catch (MathIllegalArgumentException miae) {
230             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
231         }
232     }
233 
234     @Test
235     public void testNewInstance() {
236         FieldGradient<T> g = build(5.25);
237         assertEquals(5.25, g.getValue().getReal(), 1.0e-15);
238         assertEquals(1.0,  g.getPartialDerivative(0).getReal(), 1.0e-15);
239         assertEquals(0.0009765625,  g.getPartialDerivative(1).getReal(), 1.0e-15);
240         FieldGradient<T> newInstance = g.newInstance(7.5);
241         assertEquals(7.5, newInstance.getValue().getReal(), 1.0e-15);
242         assertEquals(0.0, newInstance.getPartialDerivative(0).getReal(), 1.0e-15);
243         assertEquals(0.0, newInstance.getPartialDerivative(1).getReal(), 1.0e-15);
244     }
245 
246     protected void checkAgainstDS(final double x, final FieldUnivariateFunction f) {
247         final FieldGradient<T> xG = build(x);
248         final FieldGradient<T> yG = f.value(xG);
249         final FieldDerivativeStructure<T> yDS = f.value(xG.toDerivativeStructure());
250         assertEquals(yDS.getFreeParameters(), yG.getFreeParameters());
251 
252         if (Double.isNaN(yDS.getValue().getReal())) {
253             assertEquals(yDS.getValue().getReal(),
254                                     yG.getValue().getReal());
255         } else {
256             assertEquals(yDS.getValue().getReal(),
257                                     yG.getValue().getReal(),
258                                     1.0e-15 * FastMath.abs(
259                                                     yDS.getValue().getReal()));
260         }
261         final int[] indices = new int[yDS.getFreeParameters()];
262         for (int i = 0; i < yG.getFreeParameters(); ++i) {
263             indices[i] = 1;
264             if (Double.isNaN(yDS.getPartialDerivative(indices).getReal())) {
265                 assertEquals(
266                                 yDS.getPartialDerivative(indices).getReal(),
267                                 yG.getPartialDerivative(i).getReal());
268             } else {
269                 assertEquals(
270                                 yDS.getPartialDerivative(indices).getReal(),
271                                 yG.getPartialDerivative(i).getReal(),
272                                 4.0e-14 * FastMath.abs(yDS.getPartialDerivative(
273                                                 indices).getReal()));
274             }
275             indices[i] = 0;
276         }
277     }
278 
279     @Test
280     public void testArithmeticVsDS() {
281         for (double x = -1.25; x < 1.25; x+= 0.5) {
282             checkAgainstDS(x,
283                            new FieldUnivariateFunction() {
284                                public <S extends CalculusFieldElement<S>> S value(S x) {
285                                    final S y = x.add(3).multiply(x).subtract(5).multiply(0.5);
286                                    return y.negate().divide(4).divide(x).add(y).subtract(x).multiply(2).reciprocal();
287                                }
288                            });
289         }
290     }
291 
292     @Test
293     public void testCopySignField() {
294 
295         FieldGradient<T> minusOne = build(-1.0);
296         assertEquals(+1.0, minusOne.copySign(buildScalar(+1.0)).getReal(), 1.0e-15);
297         assertEquals(-1.0, minusOne.copySign(buildScalar(-1.0)).getReal(), 1.0e-15);
298         assertEquals(+1.0, minusOne.copySign(buildScalar(+0.0)).getReal(), 1.0e-15);
299         assertEquals(-1.0, minusOne.copySign(buildScalar(-0.0)).getReal(), 1.0e-15);
300         assertEquals(+1.0, minusOne.copySign(buildScalar(Double.NaN)).getReal(), 1.0e-15);
301 
302         FieldGradient<T> plusOne = build(1.0);
303         assertEquals(+1.0, plusOne.copySign(buildScalar(+1.0)).getReal(), 1.0e-15);
304         assertEquals(-1.0, plusOne.copySign(buildScalar(-1.0)).getReal(), 1.0e-15);
305         assertEquals(+1.0, plusOne.copySign(buildScalar(+0.0)).getReal(), 1.0e-15);
306         assertEquals(-1.0, plusOne.copySign(buildScalar(-0.0)).getReal(), 1.0e-15);
307         assertEquals(+1.0, plusOne.copySign(buildScalar(Double.NaN)).getReal(), 1.0e-15);
308 
309     }
310 
311     @Test
312     public void testRemainderField() {
313         double epsilon = 2.0e-15;
314         for (double x = -1.7; x < 2; x += 0.2) {
315             FieldGradient<T> dsX = build(x);
316             for (double y = -1.7; y < 2; y += 0.2) {
317                 FieldGradient<T> remainder = dsX.remainder(buildScalar(y));
318                 FieldGradient<T> ref = dsX.subtract(x - FastMath.IEEEremainder(x, y));
319                 FieldGradient<T> zero = remainder.subtract(ref);
320                 assertEquals(0, zero.getPartialDerivative(0).getReal(), epsilon);
321             }
322         }
323     }
324 
325     @Test
326     public void testRemainderDoubleVsDS() {
327         for (double x = -1.25; x < 1.25; x+= 0.5) {
328             checkAgainstDS(x,
329                            new FieldUnivariateFunction() {
330                                public <S extends CalculusFieldElement<S>> S value(S x) {
331                                    return x.remainder(0.5);
332                                }
333                            });
334         }
335     }
336 
337     @Test
338     public void testRemainderGVsDS() {
339         for (double x = -1.25; x < 1.25; x+= 0.5) {
340             checkAgainstDS(x,
341                            new FieldUnivariateFunction() {
342                               public <S extends CalculusFieldElement<S>> S value(S x) {
343                                   return x.remainder(x.divide(0.7));
344                               }
345                            });
346         }
347     }
348 
349     @Test
350     public void testAbsVsDS() {
351         for (double x = -1.25; x < 1.25; x+= 0.5) {
352             checkAgainstDS(x,
353                            new FieldUnivariateFunction() {
354                                public <S extends CalculusFieldElement<S>> S value(S x) {
355                                    return x.abs();
356                                }
357                            });
358         }
359     }
360 
361     @Test
362     public void testScalbVsDS() {
363         for (int n = -4; n < 4; ++n) {
364             final int theN = n;
365             for (double x = -1.25; x < 1.25; x+= 0.5) {
366                 checkAgainstDS(x,
367                                new FieldUnivariateFunction() {
368                                    public <S extends CalculusFieldElement<S>> S value(S x) {
369                                        return x.scalb(theN);
370                                    }
371                                });
372             }
373         }
374     }
375 
376     @Test
377     public void testHypotVsDS() {
378         for (double x = -3.25; x < 3.25; x+= 0.5) {
379             checkAgainstDS(x,
380                            new FieldUnivariateFunction() {
381                                public <S extends CalculusFieldElement<S>> S value(S x) {
382                                    return x.cos().multiply(5).hypot(x.sin().multiply(2));
383                                }
384                            });
385         }
386     }
387 
388     @Test
389     public void testAtan2VsDS() {
390         for (double x = -3.25; x < 3.25; x+= 0.5) {
391             checkAgainstDS(x,
392                            new FieldUnivariateFunction() {
393                                public <S extends CalculusFieldElement<S>> S value(S x) {
394                                    return x.cos().multiply(5).atan2(x.sin().multiply(2));
395                                }
396                            });
397         }
398     }
399 
400     @Test
401     public void testPowersVsDS() {
402         for (double x = -3.25; x < 3.25; x+= 0.5) {
403             checkAgainstDS(x,
404                            new FieldUnivariateFunction() {
405                                public <S extends CalculusFieldElement<S>> S value(S x) {
406                                    final FieldSinCos<S> sc = x.sinCos();
407                                    return x.pow(3.2).add(x.pow(2)).subtract(sc.cos().abs().pow(sc.sin()));
408                                }
409                            });
410         }
411     }
412 
413     @Test
414     public void testRootsVsDS() {
415         for (double x = 0.001; x < 3.25; x+= 0.5) {
416             checkAgainstDS(x,
417                            new FieldUnivariateFunction() {
418                                public <S extends CalculusFieldElement<S>> S value(S x) {
419                                    return x.rootN(5);//x.sqrt().add(x.cbrt()).subtract(x.rootN(5));
420                                }
421                            });
422         }
423     }
424 
425     @Test
426     public void testExpsLogsVsDS() {
427         for (double x = 2.5; x < 3.25; x+= 0.125) {
428             checkAgainstDS(x,
429                            new FieldUnivariateFunction() {
430                                public <S extends CalculusFieldElement<S>> S value(S x) {
431                                    return x.exp().add(x.multiply(0.5).expm1()).log().log10().log1p();
432                                }
433                            });
434         }
435     }
436 
437     @Test
438     public void testTrigonometryVsDS() {
439         for (double x = -3.25; x < 3.25; x+= 0.5) {
440             checkAgainstDS(x,
441                            new FieldUnivariateFunction() {
442                                public <S extends CalculusFieldElement<S>> S value(S x) {
443                                    return x.cos().multiply(x.sin()).atan().divide(12).asin().multiply(0.1).acos().tan();
444                                }
445                            });
446         }
447     }
448 
449     @Test
450     public void testHyperbolicVsDS() {
451         for (double x = -1.25; x < 1.25; x+= 0.5) {
452             checkAgainstDS(x,
453                            new FieldUnivariateFunction() {
454                                public <S extends CalculusFieldElement<S>> S value(S x) {
455                                    return x.cosh().multiply(x.sinh()).multiply(12).abs().acosh().asinh().divide(7).tanh().multiply(0.1).atanh();
456                                }
457                            });
458         }
459     }
460 
461     @Test
462     public void testConvertersVsDS() {
463         for (double x = -1.25; x < 1.25; x+= 0.5) {
464             checkAgainstDS(x,
465                            new FieldUnivariateFunction() {
466                                public <S extends CalculusFieldElement<S>> S value(S x) {
467                                    return x.multiply(5).toDegrees().subtract(x).toRadians();
468                                }
469                            });
470         }
471     }
472 
473     @Test
474     public void testLinearCombination2D2FVsDS() {
475         for (double x = -1.25; x < 1.25; x+= 0.5) {
476             checkAgainstDS(x,
477                            new FieldUnivariateFunction() {
478                                public <S extends CalculusFieldElement<S>> S value(S x) {
479                                    return x.linearCombination(1.0, x.multiply(0.9),
480                                                               2.0, x.multiply(0.8));
481                                }
482                            });
483         }
484     }
485 
486     @Test
487     public void testLinearCombination2F2FVsDS() {
488         for (double x = -1.25; x < 1.25; x+= 0.5) {
489             checkAgainstDS(x,
490                            new FieldUnivariateFunction() {
491                                public <S extends CalculusFieldElement<S>> S value(S x) {
492                                    return x.linearCombination(x.add(1), x.multiply(0.9),
493                                                               x.add(2), x.multiply(0.8));
494                                }
495                            });
496         }
497     }
498 
499     @Test
500     public void testLinearCombination3D3FVsDS() {
501         for (double x = -1.25; x < 1.25; x+= 0.5) {
502             checkAgainstDS(x,
503                            new FieldUnivariateFunction() {
504                                public <S extends CalculusFieldElement<S>> S value(S x) {
505                                    return x.linearCombination(1.0, x.multiply(0.9),
506                                                               2.0, x.multiply(0.8),
507                                                               3.0, x.multiply(0.7));
508                                }
509                            });
510         }
511     }
512 
513     @Test
514     public void testLinearCombination3F3FVsDS() {
515         for (double x = -1.25; x < 1.25; x+= 0.5) {
516             checkAgainstDS(x,
517                            new FieldUnivariateFunction() {
518                                public <S extends CalculusFieldElement<S>> S value(S x) {
519                                    return x.linearCombination(x.add(1), x.multiply(0.9),
520                                                               x.add(2), x.multiply(0.8),
521                                                               x.add(3), x.multiply(0.7));
522                                }
523                            });
524         }
525     }
526 
527     @Test
528     public void testLinearCombination4D4FVsDS() {
529         for (double x = -1.25; x < 1.25; x+= 0.5) {
530             checkAgainstDS(x,
531                            new FieldUnivariateFunction() {
532                                public <S extends CalculusFieldElement<S>> S value(S x) {
533                                    return x.linearCombination(1.0, x.multiply(0.9),
534                                                               2.0, x.multiply(0.8),
535                                                               3.0, x.multiply(0.7),
536                                                               4.0, x.multiply(0.6));
537                                }
538                            });
539         }
540     }
541 
542     @Test
543     public void testLinearCombination4F4FVsDS() {
544         for (double x = -1.25; x < 1.25; x+= 0.5) {
545             checkAgainstDS(x,
546                            new FieldUnivariateFunction() {
547                                public <S extends CalculusFieldElement<S>> S value(S x) {
548                                    return x.linearCombination(x.add(1), x.multiply(0.9),
549                                                               x.add(2), x.multiply(0.8),
550                                                               x.add(3), x.multiply(0.7),
551                                                               x.add(4), x.multiply(0.6));
552                                }
553                            });
554         }
555     }
556 
557     @Test
558     public void testLinearCombinationnDnFVsDS() {
559         for (double x = -1.25; x < 1.25; x+= 0.5) {
560             checkAgainstDS(x,
561                            new FieldUnivariateFunction() {
562                                public <S extends CalculusFieldElement<S>> S value(S x) {
563                                    final S[] b = MathArrays.buildArray(x.getField(), 4);
564                                    b[0] = x.add(0.9);
565                                    b[1] = x.add(0.8);
566                                    b[2] = x.add(0.7);
567                                    b[3] = x.add(0.6);
568                                    return x.linearCombination(new double[] { 1, 2, 3, 4 }, b);
569                                }
570                            });
571         }
572     }
573 
574     @Test
575     public void testLinearCombinationnFnFVsDS() {
576         for (double x = -1.25; x < 1.25; x+= 0.5) {
577             checkAgainstDS(x,
578                            new FieldUnivariateFunction() {
579                                public <S extends CalculusFieldElement<S>> S value(S x) {
580                                    final S[] a = MathArrays.buildArray(x.getField(), 4);
581                                    a[0] = x.add(1);
582                                    a[1] = x.add(2);
583                                    a[2] = x.add(3);
584                                    a[3] = x.add(4);
585                                    final S[] b = MathArrays.buildArray(x.getField(), 4);
586                                    b[0] = x.add(0.9);
587                                    b[1] = x.add(0.8);
588                                    b[2] = x.add(0.7);
589                                    b[3] = x.add(0.6);
590                                    return x.linearCombination(a, b);
591                                }
592                            });
593         }
594     }
595 
596     @Test
597     public void testLinearCombinationField() {
598         final T[] a = MathArrays.buildArray(getValueField(), 3);
599         a[0] = buildScalar(-1321008684645961.0 / 268435456.0);
600         a[1] = buildScalar(-5774608829631843.0 / 268435456.0);
601         a[2] = buildScalar(-7645843051051357.0 / 8589934592.0);
602         final FieldGradient<T>[] b = MathArrays.buildArray(FieldGradientField.getField(getValueField(), 1), 3);
603         b[0] = build(-5712344449280879.0 / 2097152.0);
604         b[1] = build(-4550117129121957.0 / 2097152.0);
605         b[2] = build(8846951984510141.0 / 131072.0);
606 
607         final FieldGradient<T> abSumInline = b[0].linearCombination(a[0], b[0],
608                                                                     a[1], b[1],
609                                                                     a[2], b[2]);
610         final FieldGradient<T> abSumArray = b[0].linearCombination(a, b);
611         assertEquals(abSumInline.getReal(), abSumArray.getReal(), 3.0e-8);
612         assertEquals(-1.8551294182586248737720779899, abSumInline.getReal(), 5.0e-8);
613         assertEquals(abSumInline.getPartialDerivative(0).getReal(), abSumArray.getPartialDerivative(0).getReal(), 3.0e-8);
614     }
615 
616     @Test
617     public void testZero() {
618         FieldGradient<T> zero = build(17.0).getField().getZero();
619         assertEquals(0.0, zero.getValue().getReal(), 1.0e-15);
620         for (int i = 0; i < zero.getFreeParameters(); ++i) {
621             assertEquals(0.0, zero.getPartialDerivative(i).getReal(), 1.0e-15);
622         }
623     }
624 
625     @Test
626     public void testOne() {
627         FieldGradient<T> one = build(17.0).getField().getOne();
628         assertEquals(1.0, one.getValue().getReal(), 1.0e-15);
629         for (int i = 0; i < one.getFreeParameters(); ++i) {
630             assertEquals(0.0, one.getPartialDerivative(i).getReal(), 1.0e-15);
631         }
632     }
633 
634     private void check(FieldGradient<T> g, double value, double... derivatives) {
635 
636         // check value
637         assertEquals(value, g.getReal(), 1.0e-15);
638 
639         // check derivatives
640         for (int i = 0; i < derivatives.length; ++i) {
641             assertEquals(derivatives[i], g.getPartialDerivative(i).getReal(), 1.0e-15);
642         }
643 
644     }
645 }