View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) 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 ASF 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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.optim.nonlinear.scalar;
23  
24  import org.hipparchus.analysis.MultivariateFunction;
25  import org.hipparchus.optim.InitialGuess;
26  import org.hipparchus.optim.MaxEval;
27  import org.hipparchus.optim.PointValuePair;
28  import org.hipparchus.optim.nonlinear.scalar.noderiv.AbstractSimplex;
29  import org.hipparchus.optim.nonlinear.scalar.noderiv.NelderMeadSimplex;
30  import org.hipparchus.optim.nonlinear.scalar.noderiv.SimplexOptimizer;
31  import org.junit.jupiter.api.Test;
32  
33  import static org.junit.jupiter.api.Assertions.assertEquals;
34  import static org.junit.jupiter.api.Assertions.assertTrue;
35  
36  class MultivariateFunctionMappingAdapterTest {
37      @Test
38      void testStartSimplexInsideRange() {
39          final BiQuadratic biQuadratic = new BiQuadratic(2.0, 2.5, 1.0, 3.0, 2.0, 3.0);
40          final MultivariateFunctionMappingAdapter wrapped
41              = new MultivariateFunctionMappingAdapter(biQuadratic,
42                                                       biQuadratic.getLower(),
43                                                       biQuadratic.getUpper());
44  
45          SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
46          final AbstractSimplex simplex = new NelderMeadSimplex(new double[][] {
47                  wrapped.boundedToUnbounded(new double[] { 1.5, 2.75 }),
48                  wrapped.boundedToUnbounded(new double[] { 1.5, 2.95 }),
49                  wrapped.boundedToUnbounded(new double[] { 1.7, 2.90 })
50              });
51  
52          final PointValuePair optimum
53              = optimizer.optimize(new MaxEval(300),
54                                   new ObjectiveFunction(wrapped),
55                                   simplex,
56                                   GoalType.MINIMIZE,
57                                   new InitialGuess(wrapped.boundedToUnbounded(new double[] { 1.5, 2.25 })));
58          final double[] bounded = wrapped.unboundedToBounded(optimum.getPoint());
59  
60          assertEquals(biQuadratic.getBoundedXOptimum(), bounded[0], 2e-7);
61          assertEquals(biQuadratic.getBoundedYOptimum(), bounded[1], 2e-7);
62      }
63  
64      @Test
65      void testOptimumOutsideRange() {
66          final BiQuadratic biQuadratic = new BiQuadratic(4.0, 0.0, 1.0, 3.0, 2.0, 3.0);
67          final MultivariateFunctionMappingAdapter wrapped
68              = new MultivariateFunctionMappingAdapter(biQuadratic,
69                                                       biQuadratic.getLower(),
70                                                       biQuadratic.getUpper());
71  
72          SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
73          final AbstractSimplex simplex = new NelderMeadSimplex(new double[][] {
74                  wrapped.boundedToUnbounded(new double[] { 1.5, 2.75 }),
75                  wrapped.boundedToUnbounded(new double[] { 1.5, 2.95 }),
76                  wrapped.boundedToUnbounded(new double[] { 1.7, 2.90 })
77              });
78  
79          final PointValuePair optimum
80              = optimizer.optimize(new MaxEval(100),
81                                   new ObjectiveFunction(wrapped),
82                                   simplex,
83                                   GoalType.MINIMIZE,
84                                   new InitialGuess(wrapped.boundedToUnbounded(new double[] { 1.5, 2.25 })));
85          final double[] bounded = wrapped.unboundedToBounded(optimum.getPoint());
86  
87          assertEquals(biQuadratic.getBoundedXOptimum(), bounded[0], 2e-7);
88          assertEquals(biQuadratic.getBoundedYOptimum(), bounded[1], 2e-7);
89      }
90  
91      @Test
92      void testUnbounded() {
93          final BiQuadratic biQuadratic = new BiQuadratic(4.0, 0.0,
94                                                          Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
95                                                          Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
96          final MultivariateFunctionMappingAdapter wrapped
97              = new MultivariateFunctionMappingAdapter(biQuadratic,
98                                                       biQuadratic.getLower(),
99                                                       biQuadratic.getUpper());
100 
101         SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, 1e-30);
102         final AbstractSimplex simplex = new NelderMeadSimplex(new double[][] {
103                 wrapped.boundedToUnbounded(new double[] { 1.5, 2.75 }),
104                 wrapped.boundedToUnbounded(new double[] { 1.5, 2.95 }),
105                 wrapped.boundedToUnbounded(new double[] { 1.7, 2.90 })
106             });
107 
108         final PointValuePair optimum
109             = optimizer.optimize(new MaxEval(300),
110                                  new ObjectiveFunction(wrapped),
111                                  simplex,
112                                  GoalType.MINIMIZE,
113                                  new InitialGuess(wrapped.boundedToUnbounded(new double[] { 1.5, 2.25 })));
114         final double[] bounded = wrapped.unboundedToBounded(optimum.getPoint());
115 
116         assertEquals(biQuadratic.getBoundedXOptimum(), bounded[0], 2e-7);
117         assertEquals(biQuadratic.getBoundedYOptimum(), bounded[1], 2e-7);
118     }
119 
120     @Test
121     void testHalfBounded() {
122         final BiQuadratic biQuadratic = new BiQuadratic(4.0, 4.0,
123                                                         1.0, Double.POSITIVE_INFINITY,
124                                                         Double.NEGATIVE_INFINITY, 3.0);
125         final MultivariateFunctionMappingAdapter wrapped
126             = new MultivariateFunctionMappingAdapter(biQuadratic,
127                                                      biQuadratic.getLower(),
128                                                      biQuadratic.getUpper());
129 
130         SimplexOptimizer optimizer = new SimplexOptimizer(1e-13, 1e-30);
131         final AbstractSimplex simplex = new NelderMeadSimplex(new double[][] {
132                 wrapped.boundedToUnbounded(new double[] { 1.5, 2.75 }),
133                 wrapped.boundedToUnbounded(new double[] { 1.5, 2.95 }),
134                 wrapped.boundedToUnbounded(new double[] { 1.7, 2.90 })
135             });
136 
137         final PointValuePair optimum
138             = optimizer.optimize(new MaxEval(200),
139                                  new ObjectiveFunction(wrapped),
140                                  simplex,
141                                  GoalType.MINIMIZE,
142                                  new InitialGuess(wrapped.boundedToUnbounded(new double[] { 1.5, 2.25 })));
143         final double[] bounded = wrapped.unboundedToBounded(optimum.getPoint());
144 
145         assertEquals(biQuadratic.getBoundedXOptimum(), bounded[0], 1e-7);
146         assertEquals(biQuadratic.getBoundedYOptimum(), bounded[1], 1e-7);
147     }
148 
149     private static class BiQuadratic implements MultivariateFunction {
150 
151         private final double xOptimum;
152         private final double yOptimum;
153 
154         private final double xMin;
155         private final double xMax;
156         private final double yMin;
157         private final double yMax;
158 
159         public BiQuadratic(final double xOptimum, final double yOptimum,
160                            final double xMin, final double xMax,
161                            final double yMin, final double yMax) {
162             this.xOptimum = xOptimum;
163             this.yOptimum = yOptimum;
164             this.xMin     = xMin;
165             this.xMax     = xMax;
166             this.yMin     = yMin;
167             this.yMax     = yMax;
168         }
169 
170         public double value(double[] point) {
171             // the function should never be called with out of range points
172             assertTrue(point[0] >= xMin);
173             assertTrue(point[0] <= xMax);
174             assertTrue(point[1] >= yMin);
175             assertTrue(point[1] <= yMax);
176 
177             final double dx = point[0] - xOptimum;
178             final double dy = point[1] - yOptimum;
179             return dx * dx + dy * dy;
180 
181         }
182 
183         public double[] getLower() {
184             return new double[] { xMin, yMin };
185         }
186 
187         public double[] getUpper() {
188             return new double[] { xMax, yMax };
189         }
190 
191         public double getBoundedXOptimum() {
192             return (xOptimum < xMin) ? xMin : ((xOptimum > xMax) ? xMax : xOptimum);
193         }
194 
195         public double getBoundedYOptimum() {
196             return (yOptimum < yMin) ? yMin : ((yOptimum > yMax) ? yMax : yOptimum);
197         }
198     }
199 }