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  
18  package org.hipparchus.analysis.differentiation;
19  
20  import org.hipparchus.CalculusFieldElement;
21  import org.hipparchus.Field;
22  import org.hipparchus.exception.LocalizedCoreFormats;
23  import org.hipparchus.exception.MathIllegalArgumentException;
24  import org.hipparchus.linear.FieldQRDecomposer;
25  import org.hipparchus.util.Binary64Field;
26  import org.hipparchus.util.FastMath;
27  import org.hipparchus.util.MathArrays;
28  import org.junit.jupiter.api.Test;
29  
30  import java.lang.reflect.Array;
31  
32  import static org.junit.jupiter.api.Assertions.assertEquals;
33  import static org.junit.jupiter.api.Assertions.fail;
34  
35  /**
36   * Test for class {@linkFieldTaylorMap<T>}.
37   */
38  class FieldTaylorMapTest {
39  
40      @Test
41      void testNullPoint() {
42          doTestNullPoint(Binary64Field.getInstance());
43      }
44  
45      @Test
46      void testDim0Point() {
47          doTestDim0Point(Binary64Field.getInstance());
48      }
49  
50      @Test
51      void testNullFunctions() {
52          doTestNullFunctions(Binary64Field.getInstance());
53      }
54  
55      @Test
56      void testNoFunctions() {
57          doTestNoFunctions(Binary64Field.getInstance());
58      }
59  
60      @Test
61      void testIncompatiblePointAndFunctions() {
62          doTestIncompatiblePointAndFunctions(Binary64Field.getInstance());
63      }
64  
65      @Test
66      void testIncompatible() {
67          doTestIncompatible(Binary64Field.getInstance());
68      }
69  
70      @Test
71      void testNbParameters() {
72          doTestNbParameters(Binary64Field.getInstance());
73      }
74  
75      @Test
76      void testNbFunctions() {
77          doTestNbFunctions(Binary64Field.getInstance());
78      }
79  
80      @Test
81      void testIdentity() {
82          doTestIdentity(Binary64Field.getInstance());
83      }
84  
85      @Test
86      void testValue() {
87          doTestValue(Binary64Field.getInstance());
88      }
89  
90      @Test
91      void testCompose() {
92          doTestCompose(Binary64Field.getInstance());
93      }
94  
95      @Test
96      void testInvertNonSquare() {
97          doTestInvertNonSquare(Binary64Field.getInstance());
98      }
99  
100     @Test
101     void testInvertMonoDimensional() {
102         doTestInvertMonoDimensional(Binary64Field.getInstance());
103     }
104 
105     @Test
106     void testInvertBiDimensional() {
107         doTestInvertBiDimensional(Binary64Field.getInstance());
108     }
109 
110     @SuppressWarnings("unchecked")
111     private <T extends CalculusFieldElement<T>> void doTestNullPoint(final Field<T> field) {
112         try {
113             new FieldTaylorMap<>(null, (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 2));
114             fail("an exception should have been thrown");
115         } catch (MathIllegalArgumentException miae) {
116             assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
117             assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
118         }
119     }
120 
121     @SuppressWarnings("unchecked")
122     private <T extends CalculusFieldElement<T>> void doTestDim0Point(final Field<T> field) {
123         try {
124             new FieldTaylorMap<>(MathArrays.buildArray(field, 0), (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 2));
125             fail("an exception should have been thrown");
126         } catch (MathIllegalArgumentException miae) {
127             assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
128             assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
129         }
130     }
131 
132     private <T extends CalculusFieldElement<T>> void doTestNullFunctions(final Field<T> field) {
133         try {
134             new FieldTaylorMap<>(MathArrays.buildArray(field, 2), null);
135             fail("an exception should have been thrown");
136         } catch (MathIllegalArgumentException miae) {
137             assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
138             assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
139         }
140     }
141 
142     @SuppressWarnings("unchecked")
143     private <T extends CalculusFieldElement<T>> void doTestNoFunctions(final Field<T> field) {
144         try {
145             new FieldTaylorMap<>(MathArrays.buildArray(field, 2), (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 0));
146             fail("an exception should have been thrown");
147         } catch (MathIllegalArgumentException miae) {
148             assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
149             assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
150         }
151     }
152 
153     private <T extends CalculusFieldElement<T>> void doTestIncompatiblePointAndFunctions(final Field<T> field) {
154         FDSFactory<T> factory = new FDSFactory<>(field, 6, 6);
155         @SuppressWarnings("unchecked")
156         FieldDerivativeStructure<T>[] functions = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class,
157                                                                                                     factory.getCompiler().getFreeParameters());
158         for (int i = 0; i < functions.length; ++i) {
159             functions[i] = factory.constant(0);
160         }
161         try {
162             new FieldTaylorMap<>(MathArrays.buildArray(field, functions.length - 1), functions);
163             fail("an exception should have been thrown");
164         } catch (MathIllegalArgumentException miae) {
165             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
166             assertEquals(5, ((Integer) miae.getParts()[0]).intValue());
167             assertEquals(6, ((Integer) miae.getParts()[1]).intValue());
168         }
169     }
170 
171     private <T extends CalculusFieldElement<T>> void doTestIncompatible(final Field<T> field) {
172         FDSFactory<T> factory = new FDSFactory<>(field, 6, 6);
173         @SuppressWarnings("unchecked")
174         FieldDerivativeStructure<T>[] functions = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class,
175                                                                                                     factory.getCompiler().getFreeParameters());
176         for (int i = 0; i < functions.length - 1; ++i) {
177             functions[i] = factory.constant(0);
178         }
179         functions[functions.length - 1] = new FDSFactory<>(field,
180                                                            factory.getCompiler().getFreeParameters(),
181                                                            factory.getCompiler().getOrder() - 1).
182                                           constant(1.0);
183         try {
184             new FieldTaylorMap<>(MathArrays.buildArray(field, functions.length), functions);
185             fail("an exception should have been thrown");
186         } catch (MathIllegalArgumentException miae) {
187             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
188             assertEquals(6, ((Integer) miae.getParts()[0]).intValue());
189             assertEquals(5, ((Integer) miae.getParts()[1]).intValue());
190         }
191     }
192 
193     private <T extends CalculusFieldElement<T>> void doTestNbParameters(final Field<T> field) {
194         final int nbParameters = 6;
195         final int nbFunctions  = 3;
196         FDSFactory<T> factory = new FDSFactory<>(field, nbParameters, 6);
197         @SuppressWarnings("unchecked")
198         FieldDerivativeStructure<T>[] functions = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class,
199                                                                                                     nbFunctions);
200         for (int i = 0; i < functions.length; ++i) {
201             functions[i] = factory.constant(0);
202         }
203         assertEquals(nbParameters,
204                             new FieldTaylorMap<>(MathArrays.buildArray(field, nbParameters), functions).getFreeParameters());
205     }
206 
207     private <T extends CalculusFieldElement<T>> void doTestNbFunctions(final Field<T> field) {
208         final int nbParameters = 6;
209         final int nbFunctions  = 3;
210         FDSFactory<T> factory = new FDSFactory<>(field, nbParameters, 6);
211         @SuppressWarnings("unchecked")
212         FieldDerivativeStructure<T>[] functions = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class,
213                                                                                                     nbFunctions);
214         for (int i = 0; i < functions.length; ++i) {
215             functions[i] = factory.constant(0);
216         }
217         assertEquals(nbFunctions,
218                             new FieldTaylorMap<>(MathArrays.buildArray(field, nbParameters), functions).getNbFunctions());
219     }
220 
221     private <T extends CalculusFieldElement<T>> void doTestIdentity(final Field<T> field) {
222         final FieldTaylorMap<T> map = new FieldTaylorMap<>(field, 7, 3, 4);
223         for (int i = 0; i < map.getNbFunctions(); ++i) {
224 
225             final FieldDerivativeStructure<T> mi = map.getFunction(i);
226 
227             assertEquals(0.0, mi.getValue().getReal(), 1.0e-15);
228 
229             int[] orders = new int[7];
230             orders[i] = 1;
231             int expectedOne = mi.getFactory().getCompiler().getPartialDerivativeIndex(orders);
232 
233             for (int j = 0; j < mi.getFactory().getCompiler().getSize(); ++j) {
234                 assertEquals(j == expectedOne ? 1.0 : 0.0, mi.getAllDerivatives()[j].getReal(), 1.0e-15);
235             }
236 
237         }
238     }
239 
240     @SuppressWarnings("unchecked")
241     private <T extends CalculusFieldElement<T>> void doTestValue(final Field<T> field) {
242 
243         final FDSFactory<T>               factory = new FDSFactory<>(field, 2, 3);
244         final FieldDerivativeStructure<T> p0      = factory.variable(0, field.getZero().newInstance( 1.0));
245         final FieldDerivativeStructure<T> p1      = factory.variable(1, field.getZero().newInstance(-3.0));
246         final FieldDerivativeStructure<T> f0      = p0.sin();
247         final FieldDerivativeStructure<T> f1      = p0.add(p1);
248         final T[] p = MathArrays.buildArray(field, 2);
249         p[0] = p0.getValue();
250         p[1] = p1.getValue();
251         final FieldDerivativeStructure<T>[] f = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 2);
252         f[0] = f0;
253         f[1] = f1;
254         final FieldTaylorMap<T> map = new FieldTaylorMap<>(p, f);
255 
256         for (double dp0 = -0.1; dp0 < 0.1; dp0 += 0.01) {
257             final T dp0T = field.getZero().newInstance(dp0);
258             for (double dp1 = -0.1; dp1 < 0.1; dp1 += 0.01) {
259                 final T dp1T = field.getZero().newInstance(dp1);
260                 assertEquals(f0.taylor(dp0, dp1).getReal(), map.value(dp0, dp1)[0].getReal(),   1.0e-15);
261                 assertEquals(f1.taylor(dp0, dp1).getReal(), map.value(dp0, dp1)[1].getReal(),   1.0e-15);
262                 assertEquals(f0.taylor(dp0, dp1).getReal(), map.value(dp0T, dp1T)[0].getReal(), 1.0e-15);
263                 assertEquals(f1.taylor(dp0, dp1).getReal(), map.value(dp0T, dp1T)[1].getReal(), 1.0e-15);
264             }
265         }
266 
267     }
268 
269     private <T extends CalculusFieldElement<T>> void doTestCompose(final Field<T> field) {
270 
271         final FDSFactory<T>               factory2 = new FDSFactory<>(field, 2, 2);
272         final FDSFactory<T>               factory3 = new FDSFactory<>(field, 3, factory2.getCompiler().getOrder());
273         final FieldDerivativeStructure<T> p0       = factory2.variable(0,  1.0);
274         final FieldDerivativeStructure<T> p1       = factory2.variable(1, -3.0);
275         final FieldDerivativeStructure<T> g0       = p0.sin();
276         final FieldDerivativeStructure<T> g1       = p0.add(p1);
277         final FieldDerivativeStructure<T> g2       = p1.multiply(p0);
278         final FieldDerivativeStructure<T> f0       = factory3.variable(0,  g0.getValue()).
279                                                      add(factory3.variable(1, g1.getValue()));
280         final FieldDerivativeStructure<T> f1       = factory3.variable(0,  g0.getValue()).
281                                                      subtract(factory3.variable(1, g1.getValue())).
282                                                      add(factory3.variable(2, g2.getValue()));
283         final T[] p = MathArrays.buildArray(field, 2);
284         p[0] = p0.getValue();
285         p[1] = p1.getValue();
286         @SuppressWarnings("unchecked")
287         final FieldDerivativeStructure<T>[] g = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 3);
288         g[0] = g0;
289         g[1] = g1;
290         g[2] = g2;
291         final T[] gT = MathArrays.buildArray(field, 3);
292         gT[0] = g0.getValue();
293         gT[1] = g1.getValue();
294         gT[2] = g2.getValue();
295         @SuppressWarnings("unchecked")
296         final FieldDerivativeStructure<T>[] f = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 2);
297         f[0] = f0;
298         f[1] = f1;
299         final FieldTaylorMap<T>           mapG     = new FieldTaylorMap<>(p,  g);
300         final FieldTaylorMap<T>           mapF     = new FieldTaylorMap<>(gT, f);
301         final FieldTaylorMap<T>           composed = mapF.compose(mapG);
302 
303         for (double dp0 = -0.1; dp0 < 0.1; dp0 += 0.01) {
304             for (double dp1 = -0.1; dp1 < 0.1; dp1 += 0.01) {
305                 assertEquals(g0.taylor(dp0, dp1).add(g1.taylor(dp0, dp1)).getReal(),
306                                     composed.value(dp0, dp1)[0].getReal(),
307                                     1.0e-15);
308                 assertEquals(g0.taylor(dp0, dp1).subtract(g1.taylor(dp0, dp1)).add(g2.taylor(dp0, dp1)).getReal(),
309                                     composed.value(dp0, dp1)[1].getReal(),
310                                     1.0e-15);
311             }
312         }
313 
314         assertEquals(p0.getValue().getReal(), mapG.getPoint()[0].getReal(),     1.0e-15);
315         assertEquals(p1.getValue().getReal(), mapG.getPoint()[1].getReal(),     1.0e-15);
316         assertEquals(g0.getValue().getReal(), mapF.getPoint()[0].getReal(),     1.0e-15);
317         assertEquals(g1.getValue().getReal(), mapF.getPoint()[1].getReal(),     1.0e-15);
318         assertEquals(g2.getValue().getReal(), mapF.getPoint()[2].getReal(),     1.0e-15);
319         assertEquals(p0.getValue().getReal(), composed.getPoint()[0].getReal(), 1.0e-15);
320         assertEquals(p1.getValue().getReal(), composed.getPoint()[1].getReal(), 1.0e-15);
321 
322         // the partial derivatives of f are only (∂f/∂g₀, ∂f/∂g₁, ∂f/∂g₂)
323         assertEquals(+1.0, mapF.getFunction(0).getPartialDerivative(1, 0, 0).getReal(), 1.0e-15);
324         assertEquals(+1.0, mapF.getFunction(0).getPartialDerivative(0, 1, 0).getReal(), 1.0e-15);
325         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 0, 1).getReal(), 1.0e-15);
326         assertEquals(+1.0, mapF.getFunction(1).getPartialDerivative(1, 0, 0).getReal(), 1.0e-15);
327         assertEquals(-1.0, mapF.getFunction(1).getPartialDerivative(0, 1, 0).getReal(), 1.0e-15);
328         assertEquals(+1.0, mapF.getFunction(1).getPartialDerivative(0, 0, 1).getReal(), 1.0e-15);
329 
330         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(2, 0, 0).getReal(), 1.0e-15);
331         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(1, 1, 0).getReal(), 1.0e-15);
332         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(1, 0, 1).getReal(), 1.0e-15);
333         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 2, 0).getReal(), 1.0e-15);
334         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 1, 1).getReal(), 1.0e-15);
335         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 0, 2).getReal(), 1.0e-15);
336         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(2, 0, 0).getReal(), 1.0e-15);
337         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(1, 1, 0).getReal(), 1.0e-15);
338         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(1, 0, 1).getReal(), 1.0e-15);
339         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(0, 2, 0).getReal(), 1.0e-15);
340         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(0, 1, 1).getReal(), 1.0e-15);
341         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(0, 0, 2).getReal(), 1.0e-15);
342 
343         // the partial derivatives of the composed map are (∂f/∂p₀, ∂f/∂p₁)
344         assertEquals(FastMath.cos(p0.getValue()).getReal() + 1.0,                           composed.getFunction(0).getPartialDerivative(1, 0).getReal(), 1.0e-15);
345         assertEquals(+1.0,                                                                  composed.getFunction(0).getPartialDerivative(0, 1).getReal(), 1.0e-15);
346         assertEquals(FastMath.cos(p0.getValue()).getReal() - 1.0 + p1.getValue().getReal(), composed.getFunction(1).getPartialDerivative(1, 0).getReal(), 1.0e-15);
347         assertEquals(-1.0 + p0.getValue().getReal(),                                        composed.getFunction(1).getPartialDerivative(0, 1).getReal(), 1.0e-15);
348         assertEquals(-FastMath.sin(p0.getValue()).getReal(),                                composed.getFunction(0).getPartialDerivative(2, 0).getReal(), 1.0e-15);
349         assertEquals( 0.0,                                                                  composed.getFunction(0).getPartialDerivative(1, 1).getReal(), 1.0e-15);
350         assertEquals( 0.0,                                                                  composed.getFunction(0).getPartialDerivative(0, 2).getReal(), 1.0e-15);
351         assertEquals(-FastMath.sin(p0.getValue()).getReal(),                                composed.getFunction(1).getPartialDerivative(2, 0).getReal(), 1.0e-15);
352         assertEquals(+1.0,                                                                  composed.getFunction(1).getPartialDerivative(1, 1).getReal(), 1.0e-15);
353         assertEquals( 0.0,                                                                  composed.getFunction(1).getPartialDerivative(0, 2).getReal(), 1.0e-15);
354 
355     }
356 
357     private <T extends CalculusFieldElement<T>> void doTestInvertNonSquare(final Field<T> field) {
358         final FDSFactory<T>           factory   = new FDSFactory<>(field, 2, 2);
359         final FieldDerivativeStructure<T> p0        = factory.variable(0,  1.0);
360         final FieldDerivativeStructure<T> p1        = factory.variable(1, -3.0);
361         final T[] p = MathArrays.buildArray(field, 2);
362         p[0] = p0.getValue();
363         p[1] = p1.getValue();
364         @SuppressWarnings("unchecked")
365         final FieldDerivativeStructure<T>[] f = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 3);
366         f[0] = p0;
367         f[1] = p1;
368         f[2] = p0.add(p1);
369         final FieldTaylorMap<T> nonSquare = new FieldTaylorMap<>(p, f);
370         assertEquals(2, nonSquare.getFreeParameters());
371         assertEquals(3, nonSquare.getNbFunctions());
372         try {
373             nonSquare.invert(new FieldQRDecomposer<>(field.getZero().newInstance(1.0e-10)));
374             fail("an exception should have been thrown");
375         } catch (MathIllegalArgumentException miae) {
376             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
377             assertEquals(3, ((Integer) miae.getParts()[0]).intValue());
378             assertEquals(2, ((Integer) miae.getParts()[1]).intValue());
379         }
380     }
381 
382     private <T extends CalculusFieldElement<T>> void doTestInvertMonoDimensional(final Field<T> field) {
383         final FDSFactory<T> factory = new FDSFactory<>(field, 1, 6);
384         for (double x = 0.0; x < 3.0; x += 0.01) {
385             final FieldDerivativeStructure<T> xDS = factory.variable(0, x);
386             final T[] p = MathArrays.buildArray(field, 1);
387             p[0] = xDS.getValue();
388             @SuppressWarnings("unchecked")
389             final FieldDerivativeStructure<T>[] f = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 1);
390             f[0] = xDS.exp();
391             final FieldTaylorMap<T> expMap = new FieldTaylorMap<>(p, f);
392             final FieldTaylorMap<T> inverse = expMap.invert(new FieldQRDecomposer<>(field.getZero().newInstance(1.0e-10)));
393             final FieldDerivativeStructure<T> log = factory.variable(0, expMap.getFunction(0).getValue()).log();
394             FieldDerivativeStructureAbstractTest.checkEquals(log, inverse.getFunction(0), 4.7e-13);
395         }
396     }
397 
398     private <T extends CalculusFieldElement<T>> void doTestInvertBiDimensional(final Field<T> field) {
399         final FDSFactory<T> factory = new FDSFactory<>(field, 2, 4);
400         for (double x = -2.0 + FastMath.scalb(1.0, -6); x < 2.0; x += FastMath.scalb(1.0, -5)) {
401             final FieldDerivativeStructure<T> xDS = factory.variable(0, x);
402             for (double y = -2.0 + FastMath.scalb(1.0, -6); y < 2.0; y += FastMath.scalb(1.0, -5)) {
403                 final FieldDerivativeStructure<T> yDS = factory.variable(1, y);
404                 final T[] p = MathArrays.buildArray(field, 2);
405                 p[0] = xDS.getValue();
406                 p[1] = yDS.getValue();
407                 @SuppressWarnings("unchecked")
408                 final FieldDerivativeStructure<T>[] f = (FieldDerivativeStructure<T>[]) Array.newInstance(FieldDerivativeStructure.class, 2);
409                 f[0] = FastMath.hypot(xDS, yDS);
410                 f[1] = FastMath.atan2(yDS, xDS);
411                 final FieldTaylorMap<T> polarMap = new FieldTaylorMap<>(p, f);
412                 final FieldTaylorMap<T> cartMap  = polarMap.invert(new FieldQRDecomposer<>(field.getZero().newInstance(1.0e-10)));
413                 final FieldTaylorMap<T> idMap    = cartMap.compose(polarMap);
414                 FieldDerivativeStructureAbstractTest.checkEquals(xDS, idMap.getFunction(0), 2.8e-9);
415                 FieldDerivativeStructureAbstractTest.checkEquals(yDS, idMap.getFunction(1), 2.8e-9);
416             }
417         }
418     }
419 
420 }