Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
test_util.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <cstdint>
17#include <limits>
18#include <optional>
19#include <string>
20#include <vector>
21
22#include "Eigen/Core"
23#include "Eigen/SparseCore"
24#include "gtest/gtest.h"
25#include "ortools/base/gmock.h"
27
29
30using ::Eigen::VectorXd;
31using ::testing::ElementsAre;
32
33constexpr double kInfinity = std::numeric_limits<double>::infinity();
34
36 QuadraticProgram lp(4, 4);
37 lp.constraint_lower_bounds = VectorXd{{12, -kInfinity, -4, -1}};
38 lp.constraint_upper_bounds = VectorXd{{12, 7, kInfinity, 1}};
39 lp.variable_lower_bounds = VectorXd{{-kInfinity, -2, -kInfinity, 2.5}};
40 lp.variable_upper_bounds = VectorXd{{kInfinity, kInfinity, 6, 3.5}};
41 std::vector<Eigen::Triplet<double, int64_t>> triplets = {
42 {0, 0, 2}, {0, 1, 1}, {0, 2, 1}, {0, 3, 2}, {1, 0, 1},
43 {1, 2, 1}, {2, 0, 4}, {3, 2, 1.5}, {3, 3, -1}};
44 lp.constraint_matrix.setFromTriplets(triplets.begin(), triplets.end());
45
46 lp.objective_vector = VectorXd{{5.5, -2, -1, 1}};
47 lp.objective_offset = -14;
48 return lp;
49}
50
51void VerifyTestLp(const QuadraticProgram& qp, bool maximize) {
52 const double objective_sign = maximize ? -1 : 1;
53 EXPECT_THAT(objective_sign * qp.objective_offset, testing::DoubleEq(-14));
54 EXPECT_THAT(objective_sign * qp.objective_vector,
55 ElementsAre(5.5, -2, -1, 1));
56 EXPECT_EQ(qp.objective_scaling_factor, objective_sign);
57 EXPECT_FALSE(qp.objective_matrix.has_value());
58 EXPECT_THAT(qp.variable_lower_bounds,
59 ElementsAre(-kInfinity, -2, -kInfinity, 2.5));
60 EXPECT_THAT(qp.variable_upper_bounds,
61 ElementsAre(kInfinity, kInfinity, 6, 3.5));
62 EXPECT_THAT(qp.constraint_lower_bounds, ElementsAre(12, -kInfinity, -4, -1));
63 EXPECT_THAT(qp.constraint_upper_bounds, ElementsAre(12, 7, kInfinity, 1));
64 EXPECT_THAT(ToDense(qp.constraint_matrix),
65 EigenArrayEq<double>(
66 {{2, 1, 1, 2}, {1, 0, 1, 0}, {4, 0, 0, 0}, {0, 0, 1.5, -1}}));
67}
68
70 QuadraticProgram lp(4, 3);
71 lp.objective_offset = -14;
72 lp.objective_vector = VectorXd{{5, 2, 1, 1}};
73 lp.constraint_lower_bounds = VectorXd{{12, 7, 1}};
74 lp.constraint_upper_bounds = VectorXd{{12, kInfinity, kInfinity}};
75 lp.variable_lower_bounds = VectorXd{{0, 0, 0, 0}};
76 lp.variable_upper_bounds = VectorXd{{2, 4, 6, 3}};
77 lp.constraint_matrix.coeffRef(0, 0) = 2.0;
78 lp.constraint_matrix.coeffRef(0, 1) = 1.0;
79 lp.constraint_matrix.coeffRef(0, 2) = 1.0;
80 lp.constraint_matrix.coeffRef(0, 3) = 2.0;
81 lp.constraint_matrix.coeffRef(1, 0) = 1.0;
82 lp.constraint_matrix.coeffRef(1, 2) = 1.0;
83 lp.constraint_matrix.coeffRef(2, 2) = 1.0;
84 lp.constraint_matrix.coeffRef(2, 3) = -1.0;
85 lp.constraint_matrix.makeCompressed();
86 return lp;
87}
88
90 QuadraticProgram lp(6, 3);
91 lp.objective_offset = 4;
92 lp.objective_vector = VectorXd{{-1.0, -1.0, 1.0, -1.0, 1.0, -1.0}};
93 lp.constraint_lower_bounds = VectorXd{{-1.0, -1.0, -1.0}};
94 lp.constraint_upper_bounds = VectorXd{{kInfinity, kInfinity, kInfinity}};
95 lp.variable_lower_bounds = VectorXd{{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
96 lp.variable_upper_bounds = VectorXd{{1.0, 1.0, 1.0, 1.0, 1.0, 1.0}};
97 lp.constraint_matrix.coeffRef(0, 1) = -1.0;
98 lp.constraint_matrix.coeffRef(0, 2) = 1.0;
99 lp.constraint_matrix.coeffRef(0, 5) = -1.0;
100 lp.constraint_matrix.coeffRef(1, 3) = -1.0;
101 lp.constraint_matrix.coeffRef(1, 4) = 1.0;
102 lp.constraint_matrix.coeffRef(1, 5) = -1.0;
103 lp.constraint_matrix.coeffRef(2, 0) = -1.0;
104 lp.constraint_matrix.coeffRef(2, 1) = -1.0;
105 lp.constraint_matrix.coeffRef(2, 3) = 1.0;
106 lp.constraint_matrix.makeCompressed();
107 return lp;
108}
109
111 QuadraticProgram lp(6, 3);
112 lp.objective_offset = 3;
113 lp.objective_vector = VectorXd{{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0}};
114 lp.constraint_lower_bounds = VectorXd{{-1.0, -1.0, -1.0}};
115 lp.constraint_upper_bounds = VectorXd{{kInfinity, kInfinity, kInfinity}};
116 lp.variable_lower_bounds = VectorXd{{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
117 lp.variable_upper_bounds = VectorXd{{1.0, 1.0, 1.0, 1.0, 1.0, 1.0}};
118 lp.constraint_matrix.coeffRef(0, 0) = -1.0;
119 lp.constraint_matrix.coeffRef(0, 1) = -1.0;
120 lp.constraint_matrix.coeffRef(0, 3) = 1.0;
121 lp.constraint_matrix.coeffRef(1, 0) = -1.0;
122 lp.constraint_matrix.coeffRef(1, 2) = -1.0;
123 lp.constraint_matrix.coeffRef(1, 4) = 1.0;
124 lp.constraint_matrix.coeffRef(2, 1) = -1.0;
125 lp.constraint_matrix.coeffRef(2, 2) = -1.0;
126 lp.constraint_matrix.coeffRef(2, 5) = 1.0;
127 lp.constraint_matrix.makeCompressed();
128 return lp;
129}
130
132 QuadraticProgram qp(2, 1);
133 qp.constraint_lower_bounds = VectorXd{{-kInfinity}};
134 qp.constraint_upper_bounds = VectorXd{{1}};
135 qp.variable_lower_bounds = VectorXd{{1, -2}};
136 qp.variable_upper_bounds = VectorXd{{2, 4}};
137 qp.objective_vector = VectorXd{{-1, -1}};
138 qp.objective_offset = 5;
139 std::vector<Eigen::Triplet<double, int64_t>> constraint_triplets = {
140 {0, 0, 1}, {0, 1, 1}};
141 qp.constraint_matrix.setFromTriplets(constraint_triplets.begin(),
142 constraint_triplets.end());
144 Eigen::DiagonalMatrix<double, Eigen::Dynamic>{{4.0, 1.0}};
145 return qp;
146}
147
149 QuadraticProgram qp(2, 1);
150 qp.constraint_lower_bounds = VectorXd{{2}};
151 qp.constraint_upper_bounds = VectorXd{{2}};
152 qp.variable_lower_bounds = VectorXd{{0, 0}};
153 qp.variable_upper_bounds = VectorXd{{kInfinity, kInfinity}};
154 qp.objective_vector = VectorXd{{-3, -1}};
155 qp.objective_offset = 0;
156 std::vector<Eigen::Triplet<double, int64_t>> constraint_triplets = {
157 {0, 0, 1}, {0, 1, -1}};
158 qp.constraint_matrix.setFromTriplets(constraint_triplets.begin(),
159 constraint_triplets.end());
161 Eigen::DiagonalMatrix<double, Eigen::Dynamic>({{1.0, 1.0}});
162 return qp;
163}
164
166 QuadraticProgram qp(3, 2);
167 qp.constraint_lower_bounds = VectorXd{{1, 4}};
168 qp.constraint_upper_bounds = VectorXd{{1, 4}};
169 qp.variable_lower_bounds = VectorXd{{0, 0, 0}};
170 qp.variable_upper_bounds = VectorXd{{kInfinity, kInfinity, kInfinity}};
171 qp.objective_vector = VectorXd{{1, 0, -1}};
172 qp.objective_offset = 0;
173 std::vector<Eigen::Triplet<double, int64_t>> constraint_triplets = {
174 {0, 0, 1}, {0, 2, -1}, {1, 0, 2}};
175 qp.constraint_matrix.setFromTriplets(constraint_triplets.begin(),
176 constraint_triplets.end());
178 Eigen::DiagonalMatrix<double, Eigen::Dynamic>({{0.0, 1.0, 2.0}});
179 return qp;
180}
181
183 QuadraticProgram lp(2, 1);
184 lp.constraint_matrix.coeffRef(0, 0) = 1.0;
185 lp.constraint_matrix.coeffRef(0, 1) = -1.0;
186 lp.constraint_lower_bounds = VectorXd{{2.0}};
187 lp.constraint_upper_bounds = VectorXd{{1.0}};
188 lp.variable_lower_bounds = VectorXd{{0.0, 0.0}};
189 lp.variable_upper_bounds = VectorXd{{kInfinity, kInfinity}};
190 lp.constraint_matrix.makeCompressed();
191 lp.objective_vector = VectorXd{{1.0, 1.0}};
192 return lp;
193}
194
196 QuadraticProgram lp(2, 1);
197 lp.constraint_matrix.coeffRef(0, 0) = 1.0;
198 lp.constraint_matrix.coeffRef(0, 1) = -1.0;
199 lp.constraint_matrix.makeCompressed();
200 lp.constraint_lower_bounds = VectorXd{{-kInfinity}};
201 lp.constraint_upper_bounds = VectorXd{{1.0}};
202 lp.variable_lower_bounds = VectorXd{{2.0, 0.0}};
203 lp.variable_upper_bounds = VectorXd{{1.0, kInfinity}};
204 lp.objective_vector = VectorXd{{1.0, 1.0}};
205 return lp;
206}
207
209 QuadraticProgram lp(2, 2);
210 lp.constraint_matrix.coeffRef(0, 0) = 1.0;
211 lp.constraint_matrix.coeffRef(0, 1) = -1.0;
212 lp.constraint_matrix.coeffRef(1, 0) = -1.0;
213 lp.constraint_matrix.coeffRef(1, 1) = 1.0;
214 lp.constraint_lower_bounds = VectorXd{{-kInfinity, -kInfinity}};
215 lp.variable_lower_bounds = VectorXd{{0.0, 0.0}};
216 lp.variable_upper_bounds = VectorXd{{kInfinity, kInfinity}};
217 lp.constraint_matrix.makeCompressed();
218
219 lp.constraint_upper_bounds = VectorXd{{1.0, -2.0}};
220 lp.objective_vector = VectorXd{{1.0, 1.0}};
221 return lp;
222}
223
230
236
238 QuadraticProgram lp(2, 2);
239 lp.constraint_matrix.coeffRef(0, 0) = 1.0;
240 lp.constraint_matrix.coeffRef(0, 1) = 1.0;
241 lp.constraint_matrix.coeffRef(1, 0) = 1.0;
242 lp.constraint_matrix.coeffRef(1, 1) = 2.0;
243 lp.constraint_lower_bounds = VectorXd{{-kInfinity, -kInfinity}};
244 lp.constraint_upper_bounds = VectorXd{{2.0, 2.0}};
245 lp.variable_lower_bounds = VectorXd{{0.5, 0.5}};
246 lp.variable_upper_bounds = VectorXd{{2.0, 2.0}};
247 lp.constraint_matrix.makeCompressed();
248
249 lp.objective_vector = VectorXd{{-4.0, 0.0}};
250 return lp;
251}
252
254 QuadraticProgram lp(2, 0);
255 lp.variable_lower_bounds = VectorXd{{0.0, -kInfinity}};
256 lp.variable_upper_bounds = VectorXd{{kInfinity, 0.0}};
257 lp.objective_vector = VectorXd{{4.0, 0.0}};
258 return lp;
259}
260
261void VerifyTestDiagonalQp1(const QuadraticProgram& qp, bool maximize) {
262 const double objective_sign = maximize ? -1 : 1;
263 EXPECT_EQ(qp.objective_scaling_factor, objective_sign);
264 EXPECT_THAT(objective_sign * qp.objective_offset, testing::DoubleEq(5));
265 EXPECT_THAT(objective_sign * qp.objective_vector, ElementsAre(-1, -1));
266 ASSERT_TRUE(qp.objective_matrix.has_value());
267 EXPECT_THAT(objective_sign * qp.objective_matrix->diagonal(),
268 EigenArrayEq<double>({4, 1}));
269 EXPECT_THAT(qp.variable_lower_bounds, ElementsAre(1, -2));
270 EXPECT_THAT(qp.variable_upper_bounds, ElementsAre(2, 4));
271 EXPECT_THAT(qp.constraint_lower_bounds, ElementsAre(-kInfinity));
272 EXPECT_THAT(qp.constraint_upper_bounds, ElementsAre(1));
273 EXPECT_THAT(ToDense(qp.constraint_matrix), EigenArrayEq<double>({{1, 1}}));
274}
275
276::Eigen::ArrayXXd ToDense(
277 const Eigen::SparseMatrix<double, Eigen::ColMajor, int64_t>& sparse_mat) {
278 return ::Eigen::ArrayXXd(::Eigen::MatrixXd(sparse_mat));
279}
280
281} // namespace operations_research::pdlp
Validation utilities for solvers.proto.
QuadraticProgram SmallPrimalDualInfeasibleLp()
Definition test_util.cc:231
QuadraticProgram TestDiagonalQp1()
Definition test_util.cc:131
QuadraticProgram CorrelationClusteringStarLp()
Definition test_util.cc:110
QuadraticProgram SmallDualInfeasibleLp()
Definition test_util.cc:224
QuadraticProgram SmallInitializationLp()
Definition test_util.cc:237
QuadraticProgram TestDiagonalQp3()
Definition test_util.cc:165
QuadraticProgram TinyLp()
Definition test_util.cc:69
void VerifyTestLp(const QuadraticProgram &qp, bool maximize)
Verifies that the given QuadraticProgram equals TestLp().
Definition test_util.cc:51
::Eigen::ArrayXXd ToDense(const Eigen::SparseMatrix< double, Eigen::ColMajor, int64_t > &sparse_mat)
Definition test_util.cc:276
QuadraticProgram TestLp()
Definition test_util.cc:35
QuadraticProgram SmallInconsistentVariableBoundsLp()
Definition test_util.cc:195
QuadraticProgram LpWithoutConstraints()
Definition test_util.cc:253
QuadraticProgram TestDiagonalQp2()
Definition test_util.cc:148
QuadraticProgram SmallInvalidProblemLp()
Definition test_util.cc:182
void VerifyTestDiagonalQp1(const QuadraticProgram &qp, bool maximize)
Definition test_util.cc:261
QuadraticProgram CorrelationClusteringLp()
| /
Definition test_util.cc:89
QuadraticProgram SmallPrimalInfeasibleLp()
Definition test_util.cc:208
std::optional< Eigen::DiagonalMatrix< double, Eigen::Dynamic > > objective_matrix
Eigen::SparseMatrix< double, Eigen::ColMajor, int64_t > constraint_matrix