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 }