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.exception.LocalizedCoreFormats;
21  import org.hipparchus.exception.MathIllegalArgumentException;
22  import org.hipparchus.linear.QRDecomposer;
23  import org.hipparchus.util.FastMath;
24  import org.junit.jupiter.api.Test;
25  
26  import static org.junit.jupiter.api.Assertions.assertEquals;
27  import static org.junit.jupiter.api.Assertions.fail;
28  
29  /**
30   * Test for class {@link TaylorMap}.
31   */
32  class TaylorMapTest {
33  
34      @Test
35      void testNullPoint() {
36          try {
37              new TaylorMap(null, new DerivativeStructure[2]);
38              fail("an exception should have been thrown");
39          } catch (MathIllegalArgumentException miae) {
40              assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
41              assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
42          }
43      }
44  
45      @Test
46      void testDim0Point() {
47          try {
48              new TaylorMap(new double[0], new DerivativeStructure[2]);
49              fail("an exception should have been thrown");
50          } catch (MathIllegalArgumentException miae) {
51              assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
52              assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
53          }
54      }
55  
56      @Test
57      void testNullFunctions() {
58          try {
59              new TaylorMap(new double[2], null);
60              fail("an exception should have been thrown");
61          } catch (MathIllegalArgumentException miae) {
62              assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
63              assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
64          }
65      }
66  
67      @Test
68      void testNoFunctions() {
69          try {
70              new TaylorMap(new double[2], new DerivativeStructure[0]);
71              fail("an exception should have been thrown");
72          } catch (MathIllegalArgumentException miae) {
73              assertEquals(LocalizedCoreFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, miae.getSpecifier());
74              assertEquals(0, ((Integer) miae.getParts()[0]).intValue());
75          }
76      }
77  
78      @Test
79      void testIncompatiblePointAndFunctions() {
80          DSFactory factory = new DSFactory(6, 6);
81          DerivativeStructure[] functions = new DerivativeStructure[factory.getCompiler().getFreeParameters()];
82          for (int i = 0; i < functions.length; ++i) {
83              functions[i] = factory.constant(0);
84          }
85          try {
86              new TaylorMap(new double[functions.length - 1], functions);
87              fail("an exception should have been thrown");
88          } catch (MathIllegalArgumentException miae) {
89              assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
90              assertEquals(5, ((Integer) miae.getParts()[0]).intValue());
91              assertEquals(6, ((Integer) miae.getParts()[1]).intValue());
92          }
93      }
94  
95      @Test
96      void testIncompatible() {
97          DSFactory factory = new DSFactory(6, 6);
98          DerivativeStructure[] functions = new DerivativeStructure[factory.getCompiler().getFreeParameters()];
99          for (int i = 0; i < functions.length - 1; ++i) {
100             functions[i] = factory.constant(0);
101         }
102         functions[functions.length - 1] = new DSFactory(factory.getCompiler().getFreeParameters(),
103                                                         factory.getCompiler().getOrder() - 1).
104                                           constant(1.0);
105         try {
106             new TaylorMap(new double[functions.length], functions);
107             fail("an exception should have been thrown");
108         } catch (MathIllegalArgumentException miae) {
109             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
110             assertEquals(6, ((Integer) miae.getParts()[0]).intValue());
111             assertEquals(5, ((Integer) miae.getParts()[1]).intValue());
112         }
113     }
114 
115     @Test
116     void testNbParameters() {
117         final int nbParameters = 6;
118         final int nbFunctions  = 3;
119         DSFactory factory = new DSFactory(nbParameters, 6);
120         DerivativeStructure[] functions = new DerivativeStructure[nbFunctions];
121         for (int i = 0; i < functions.length; ++i) {
122             functions[i] = factory.constant(0);
123         }
124         assertEquals(nbParameters,
125                             new TaylorMap(new double[nbParameters], functions).getFreeParameters());
126     }
127 
128     @Test
129     void testNbFunctions() {
130         final int nbParameters = 6;
131         final int nbFunctions  = 3;
132         DSFactory factory = new DSFactory(nbParameters, 6);
133         DerivativeStructure[] functions = new DerivativeStructure[nbFunctions];
134         for (int i = 0; i < functions.length; ++i) {
135             functions[i] = factory.constant(0);
136         }
137         assertEquals(nbFunctions,
138                             new TaylorMap(new double[nbParameters], functions).getNbFunctions());
139     }
140 
141     @Test
142     void testIdentity() {
143         final TaylorMap map = new TaylorMap(7, 3, 4);
144         for (int i = 0; i < map.getNbFunctions(); ++i) {
145 
146             final DerivativeStructure mi = map.getFunction(i);
147 
148             assertEquals(0.0, mi.getValue(), 1.0e-15);
149 
150             int[] orders = new int[7];
151             orders[i] = 1;
152             int expectedOne = mi.getFactory().getCompiler().getPartialDerivativeIndex(orders);
153 
154             for (int j = 0; j < mi.getFactory().getCompiler().getSize(); ++j) {
155                 assertEquals(j == expectedOne ? 1.0 : 0.0, mi.getAllDerivatives()[j], 1.0e-15);
156             }
157 
158         }
159     }
160 
161     @Test
162     void testValue() {
163 
164         final DSFactory           factory = new DSFactory(2, 3);
165         final DerivativeStructure p0      = factory.variable(0,  1.0);
166         final DerivativeStructure p1      = factory.variable(1, -3.0);
167         final DerivativeStructure f0      = p0.sin();
168         final DerivativeStructure f1      = p0.add(p1);
169         final TaylorMap           map     = new TaylorMap(new double[] { p0.getValue(), p1.getValue() },
170                                                           new DerivativeStructure[] { f0, f1 });
171 
172         for (double dp0 = -0.1; dp0 < 0.1; dp0 += 0.01) {
173             for (double dp1 = -0.1; dp1 < 0.1; dp1 += 0.01) {
174                 assertEquals(f0.taylor(dp0, dp1), map.value(dp0, dp1)[0], 1.0e-15);
175                 assertEquals(f1.taylor(dp0, dp1), map.value(dp0, dp1)[1], 1.0e-15);
176             }
177         }
178 
179     }
180 
181     @Test
182     void testCompose() {
183 
184         final DSFactory           factory2 = new DSFactory(2, 2);
185         final DSFactory           factory3 = new DSFactory(3, factory2.getCompiler().getOrder());
186         final DerivativeStructure p0       = factory2.variable(0,  1.0);
187         final DerivativeStructure p1       = factory2.variable(1, -3.0);
188         final DerivativeStructure g0       = p0.sin();
189         final DerivativeStructure g1       = p0.add(p1);
190         final DerivativeStructure g2       = p1.multiply(p0);
191         final DerivativeStructure f0       = factory3.variable(0,  g0.getValue()).
192                                              add(factory3.variable(1, g1.getValue()));
193         final DerivativeStructure f1       = factory3.variable(0,  g0.getValue()).
194                                              subtract(factory3.variable(1, g1.getValue())).
195                                              add(factory3.variable(2, g2.getValue()));
196         final TaylorMap           mapG     = new TaylorMap(new double[] { p0.getValue(), p1.getValue() },
197                                                            new DerivativeStructure[] { g0, g1, g2 });
198         final TaylorMap           mapF     = new TaylorMap(new double[] { g0.getValue(), g1.getValue(), g2.getValue() },
199                                                            new DerivativeStructure[] { f0, f1 });
200         final TaylorMap           composed = mapF.compose(mapG);
201 
202         for (double dp0 = -0.1; dp0 < 0.1; dp0 += 0.01) {
203             for (double dp1 = -0.1; dp1 < 0.1; dp1 += 0.01) {
204                 assertEquals(g0.taylor(dp0, dp1) + g1.taylor(dp0, dp1),
205                                     composed.value(dp0, dp1)[0],
206                                     1.0e-15);
207                 assertEquals(g0.taylor(dp0, dp1) - g1.taylor(dp0, dp1) + g2.taylor(dp0, dp1),
208                                     composed.value(dp0, dp1)[1],
209                                     1.0e-15);
210             }
211         }
212 
213         assertEquals(p0.getValue(), mapG.getPoint()[0],     1.0e-15);
214         assertEquals(p1.getValue(), mapG.getPoint()[1],     1.0e-15);
215         assertEquals(g0.getValue(), mapF.getPoint()[0],     1.0e-15);
216         assertEquals(g1.getValue(), mapF.getPoint()[1],     1.0e-15);
217         assertEquals(g2.getValue(), mapF.getPoint()[2],     1.0e-15);
218         assertEquals(p0.getValue(), composed.getPoint()[0], 1.0e-15);
219         assertEquals(p1.getValue(), composed.getPoint()[1], 1.0e-15);
220 
221         // the partial derivatives of f are only (∂f/∂g₀, ∂f/∂g₁, ∂f/∂g₂)
222         assertEquals(+1.0, mapF.getFunction(0).getPartialDerivative(1, 0, 0), 1.0e-15);
223         assertEquals(+1.0, mapF.getFunction(0).getPartialDerivative(0, 1, 0), 1.0e-15);
224         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 0, 1), 1.0e-15);
225         assertEquals(+1.0, mapF.getFunction(1).getPartialDerivative(1, 0, 0), 1.0e-15);
226         assertEquals(-1.0, mapF.getFunction(1).getPartialDerivative(0, 1, 0), 1.0e-15);
227         assertEquals(+1.0, mapF.getFunction(1).getPartialDerivative(0, 0, 1), 1.0e-15);
228 
229         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(2, 0, 0), 1.0e-15);
230         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(1, 1, 0), 1.0e-15);
231         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(1, 0, 1), 1.0e-15);
232         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 2, 0), 1.0e-15);
233         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 1, 1), 1.0e-15);
234         assertEquals( 0.0, mapF.getFunction(0).getPartialDerivative(0, 0, 2), 1.0e-15);
235         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(2, 0, 0), 1.0e-15);
236         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(1, 1, 0), 1.0e-15);
237         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(1, 0, 1), 1.0e-15);
238         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(0, 2, 0), 1.0e-15);
239         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(0, 1, 1), 1.0e-15);
240         assertEquals( 0.0, mapF.getFunction(1).getPartialDerivative(0, 0, 2), 1.0e-15);
241 
242         // the partial derivatives of the composed map are (∂f/∂p₀, ∂f/∂p₁)
243         assertEquals(FastMath.cos(p0.getValue()) + 1.0,                 composed.getFunction(0).getPartialDerivative(1, 0), 1.0e-15);
244         assertEquals(+1.0,                                              composed.getFunction(0).getPartialDerivative(0, 1), 1.0e-15);
245         assertEquals(FastMath.cos(p0.getValue()) - 1.0 + p1.getValue(), composed.getFunction(1).getPartialDerivative(1, 0), 1.0e-15);
246         assertEquals(-1.0 + p0.getValue(),                              composed.getFunction(1).getPartialDerivative(0, 1), 1.0e-15);
247         assertEquals(-FastMath.sin(p0.getValue()),                      composed.getFunction(0).getPartialDerivative(2, 0), 1.0e-15);
248         assertEquals( 0.0,                                              composed.getFunction(0).getPartialDerivative(1, 1), 1.0e-15);
249         assertEquals( 0.0,                                              composed.getFunction(0).getPartialDerivative(0, 2), 1.0e-15);
250         assertEquals(-FastMath.sin(p0.getValue()),                      composed.getFunction(1).getPartialDerivative(2, 0), 1.0e-15);
251         assertEquals(+1.0,                                              composed.getFunction(1).getPartialDerivative(1, 1), 1.0e-15);
252         assertEquals( 0.0,                                              composed.getFunction(1).getPartialDerivative(0, 2), 1.0e-15);
253 
254     }
255 
256     @Test
257     void testInvertNonSquare() {
258         final DSFactory           factory   = new DSFactory(2, 2);
259         final DerivativeStructure p0        = factory.variable(0,  1.0);
260         final DerivativeStructure p1        = factory.variable(1, -3.0);
261         final TaylorMap           nonSquare = new TaylorMap(new double[] { p0.getValue(), p1.getValue() },
262                                                             new DerivativeStructure[] { p0, p1, p0.add(p1) });
263         assertEquals(2, nonSquare.getFreeParameters());
264         assertEquals(3, nonSquare.getNbFunctions());
265         try {
266             nonSquare.invert(new QRDecomposer(1.0e-10));
267             fail("an exception should have been thrown");
268         } catch (MathIllegalArgumentException miae) {
269             assertEquals(LocalizedCoreFormats.DIMENSIONS_MISMATCH, miae.getSpecifier());
270             assertEquals(3, ((Integer) miae.getParts()[0]).intValue());
271             assertEquals(2, ((Integer) miae.getParts()[1]).intValue());
272         }
273     }
274 
275     @Test
276     void testInvertMonoDimensional() {
277         final DSFactory factory = new DSFactory(1, 6);
278         for (double x = 0.0; x < 3.0; x += 0.01) {
279             final DerivativeStructure xDS = factory.variable(0, x);
280             final TaylorMap expMap = new TaylorMap(new double[] { xDS.getValue() },
281                                                    new DerivativeStructure[]  { xDS.exp() });
282             final TaylorMap inverse = expMap.invert(new QRDecomposer(1.0e-10));
283             final DerivativeStructure log = factory.variable(0, expMap.getFunction(0).getValue()).log();
284             DerivativeStructureTest.checkEquals(log, inverse.getFunction(0), 4.7e-13);
285         }
286     }
287 
288     @Test
289     void testInvertBiDimensional() {
290         final DSFactory factory = new DSFactory(2, 4);
291         for (double x = -2.0 + FastMath.scalb(1.0, -6); x < 2.0; x += FastMath.scalb(1.0, -5)) {
292             final DerivativeStructure xDS = factory.variable(0, x);
293             for (double y = -2.0 + FastMath.scalb(1.0, -6); y < 2.0; y += FastMath.scalb(1.0, -5)) {
294                 final DerivativeStructure yDS = factory.variable(1, y);
295                 final TaylorMap polarMap = new TaylorMap(new double[] { xDS.getValue(), yDS.getValue() },
296                                                          new DerivativeStructure[]  { FastMath.hypot(xDS, yDS), FastMath.atan2(yDS, xDS)});
297                 final TaylorMap cartMap  = polarMap.invert(new QRDecomposer(1.0e-10));
298                 final TaylorMap idMap    = cartMap.compose(polarMap);
299                 DerivativeStructureTest.checkEquals(xDS, idMap.getFunction(0), 2.8e-9);
300                 DerivativeStructureTest.checkEquals(yDS, idMap.getFunction(1), 2.8e-9);
301             }
302         }
303     }
304 
305 }