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.optim.nonlinear.vector.constrained;
18  
19  import org.hipparchus.linear.MatrixUtils;
20  import org.hipparchus.linear.RealVector;
21  import org.hipparchus.optim.InitialGuess;
22  import org.hipparchus.optim.OptimizationData;
23  import org.hipparchus.optim.nonlinear.scalar.ObjectiveFunction;
24  
25  import static org.junit.jupiter.api.Assertions.assertEquals;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  public abstract class AbstractConstrainedOptimizerTest {
29  
30      /** Build the optimizer.
31       * @return built optimizer
32       */
33      protected abstract ConstraintOptimizer buildOptimizer();
34  
35      /** Test one problem.
36       * @param expectedSolution expected solution
37       * @param solutionTolerance tolerance on solution (L₁ norm)
38       * @param expectedMultipliers expected multipliers
39       * @param multipliersTolerance tolerance on multipliers  (L₁ norm)
40       * @param expectedValue expected objective function value
41       * @param valueTolerance tolerance on objective function value
42       * @param objectiveFunction objective function
43       * @param initialGuess initial guess (may be null)
44       * @param constraints contraints
45       */
46      protected void doTestProblem(final double[] expectedSolution,
47                                   final double solutionTolerance,
48                                   final double[] expectedMultipliers,
49                                   final double multipliersTolerance,
50                                   final double expectedValue,
51                                   final double valueTolerance,
52                                   final ObjectiveFunction objectiveFunction,
53                                   final double[] initialGuess,
54                                   final Constraint... constraints) {
55  
56          // find optimum solution
57          final ConstraintOptimizer optimizer = buildOptimizer();
58          final OptimizationData[] data = new OptimizationData[constraints.length + (initialGuess == null ? 1 : 2)];
59          data[0] = objectiveFunction;
60          System.arraycopy(constraints, 0, data, 1, constraints.length);
61          if (initialGuess != null) {
62              data[data.length - 1] = new InitialGuess(initialGuess);
63          }
64          final LagrangeSolution    solution  = optimizer.optimize(data);
65  
66          // check result
67          assertEquals(0.0,
68                              MatrixUtils.createRealVector(expectedSolution).subtract(solution.getX()).getL1Norm(),
69                              solutionTolerance);
70          assertEquals(0.0,
71                              MatrixUtils.createRealVector(expectedMultipliers).subtract(solution.getLambda()).getL1Norm(),
72                              multipliersTolerance);
73          assertEquals(expectedValue, solution.getValue(),                                  valueTolerance);
74  
75          // check neighboring points either violate constraints or have worst objective function
76          for (int i = 0; i < expectedSolution.length; ++i) {
77  
78              final RealVector plusShift = MatrixUtils.createRealVector(expectedSolution);
79              plusShift.addToEntry(i, 2 * solutionTolerance);
80              boolean plusIsFeasible = true;
81              for (final Constraint constraint : constraints) {
82                  plusIsFeasible &= constraint.overshoot(constraint.value(plusShift)) <= 0;
83              }
84              if (plusIsFeasible) {
85                  // the plusShift point fulfills all constraints,
86                  // so it must have worst objective function than the expected optimum
87                  assertTrue(objectiveFunction.getObjectiveFunction().value(plusShift.toArray()) > expectedValue);
88              }
89              
90              final RealVector minusShift = MatrixUtils.createRealVector(expectedSolution);
91              minusShift.addToEntry(i, -2 * solutionTolerance);
92              boolean minusIsFeasible = true;
93              for (final Constraint constraint : constraints) {
94                  minusIsFeasible &= constraint.overshoot(constraint.value(minusShift)) <= 0;
95              }
96              if (minusIsFeasible) {
97                  // the minusShift point fulfills all constraints,
98                  // so it must have worst objective function than the expected optimum
99                  assertTrue(objectiveFunction.getObjectiveFunction().value(minusShift.toArray()) > expectedValue);
100             }
101             
102         }
103 
104     }
105 
106 }