forked from ERGO-Code/HiGHS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTestIpm.cpp
More file actions
226 lines (209 loc) · 7.81 KB
/
Copy pathTestIpm.cpp
File metadata and controls
226 lines (209 loc) · 7.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#include <cmath>
#include "HCheckConfig.h"
#include "Highs.h"
#include "catch.hpp"
// I use dev_run to switch on/off printing and logging used for
// development of the unit test
const bool dev_run = false;
const double inf = kHighsInf;
TEST_CASE("test-analytic-centre", "[highs_ipm]") {
// std::string model = "greenbea.mps";
// std::string model = "adlittle.mps";
std::string model = "afiro.mps";
std::string filename = std::string(HIGHS_DIR) + "/check/instances/" + model;
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(filename);
HighsLp lp = highs.getLp();
lp.col_cost_.assign(lp.num_col_, 0);
highs.passModel(lp);
highs.setOptionValue("run_centring", true);
highs.setOptionValue("ipm_optimality_tolerance", 1e-2);
HighsStatus run_status = highs.run();
REQUIRE(run_status == HighsStatus::kOk);
highs.resetGlobalScheduler(true);
}
TEST_CASE("test-analytic-centre-infeasible", "[highs_ipm]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
HighsLp lp;
lp.num_col_ = 2;
lp.num_row_ = 1;
lp.col_cost_.assign(lp.num_col_, 0);
lp.col_lower_.assign(lp.num_col_, 0);
lp.col_upper_.assign(lp.num_col_, inf);
lp.row_lower_ = {-inf};
lp.row_upper_ = {-1};
lp.a_matrix_.start_ = {0, 1, 2};
lp.a_matrix_.index_ = {0, 0};
lp.a_matrix_.value_ = {1, 1};
highs.passModel(lp);
highs.setOptionValue("presolve", kHighsOffString);
highs.setOptionValue("run_centring", true);
highs.setOptionValue("ipm_optimality_tolerance", 1e-2);
HighsStatus run_status = highs.run();
REQUIRE(run_status == HighsStatus::kOk);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
highs.resetGlobalScheduler(true);
}
TEST_CASE("test-analytic-centre-box", "[highs_ipm]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
const HighsInt dim = 4;
HighsLp lp;
lp.num_col_ = dim;
lp.col_cost_.assign(dim, 0);
lp.col_lower_.assign(dim, -1);
lp.col_upper_.assign(dim, 1);
highs.passModel(lp);
std::vector<HighsInt> index = {0, 1};
std::vector<double> value = {1, 1};
const double root2 = std::sqrt(2.0);
highs.addRow(-root2, root2, 2, index.data(), value.data());
value[1] = -1;
highs.addRow(-root2, root2, 2, index.data(), value.data());
highs.setOptionValue("run_centring", true);
highs.setOptionValue("presolve", kHighsOffString);
highs.setOptionValue("ipm_optimality_tolerance", 1e-2);
HighsStatus run_status = highs.run();
const HighsSolution& solution = highs.getSolution();
double solution_norm = 0;
for (HighsInt ix = 0; ix < dim; ix++) {
if (dev_run)
printf("Analytic centre solution %d is %g\n", int(ix),
solution.col_value[ix]);
solution_norm += std::fabs(solution.col_value[ix]);
}
REQUIRE(solution_norm < 1e-6);
if (dev_run) printf("Analytic centre solution norm is %g\n", solution_norm);
highs.resetGlobalScheduler(true);
}
TEST_CASE("test-1966", "[highs_ipm]") {
// This is the primal-dual infeasible instance
// ("PrimalAndDualInfeasible") from OR-Tools that exposed the need
// for primal_solution_status and dual_solution_status not to be set
// to kSolutionStatusFeasible when there are no primal/dual
// infeasiblities, but meaningful primal/dual residual errors
//
// Takehome: make sure HiGHS unit tests include what failed in unit
// tests elsewhere!
Highs highs;
highs.setOptionValue("output_flag", dev_run);
const HighsInfo& info = highs.getInfo();
HighsLp lp;
lp.sense_ = ObjSense::kMaximize;
lp.num_col_ = 2;
lp.num_row_ = 2;
lp.col_cost_ = {2, -1};
lp.col_lower_ = {0, 0};
lp.col_upper_ = {kHighsInf, kHighsInf};
lp.row_lower_ = {-kHighsInf, 2};
lp.row_upper_ = {1, kHighsInf};
lp.a_matrix_.start_ = {0, 2, 4};
lp.a_matrix_.index_ = {0, 1, 0, 1};
lp.a_matrix_.value_ = {1, -1, 1, -1};
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
highs.passModel(lp);
highs.setOptionValue("presolve", kHighsOffString);
// if (dev_run) highs.writeModel("");
HighsModelStatus require_model_status = HighsModelStatus::kNotset;
int to_k = 2;
#ifdef HIPO
to_k = 3;
#endif
for (int k = 0; k < to_k; k++) {
if (k == 0) {
highs.setOptionValue("solver", kPdlpString);
if (dev_run) printf("Solving with PDLP\n");
require_model_status = HighsModelStatus::kUnboundedOrInfeasible;
} else if (k == 1) {
highs.setOptionValue("solver", kIpxString);
if (dev_run) printf("Solving with IPX\n");
require_model_status = HighsModelStatus::kInfeasible;
} else {
highs.setOptionValue("solver", kHipoString);
if (dev_run) printf("Solving with HiPO\n");
require_model_status = HighsModelStatus::kInfeasible;
}
highs.run();
REQUIRE(info.primal_solution_status != kSolutionStatusFeasible);
REQUIRE(info.dual_solution_status != kSolutionStatusFeasible);
REQUIRE(highs.getModelStatus() == require_model_status);
if (dev_run) {
// Nice illustration that IPX
//
// * identifies "infeasible"
//
// * gets no primal or dual infeasibilies
//
// * gets primal and dual residual errors
//
// whereas PDLP
//
// * identifies only "infeasible or unbounded"
//
// * gets primal infeasibilies and no primal residual errors
//
// * gets no primal infeasibilies but primal residual errors
//
// highs.writeSolution("", kSolutionStylePretty);
printf("Primal solution status = %d\n", int(info.primal_solution_status));
printf("Dual solution status = %d\n", int(info.dual_solution_status));
printf("Num primal infeasibilities = %d\n",
int(info.num_primal_infeasibilities));
printf("Max primal infeasibility = %g\n",
info.max_primal_infeasibility);
printf("Sum primal infeasibilities = %g\n",
info.sum_primal_infeasibilities);
printf("Num dual infeasibilities = %d\n",
int(info.num_dual_infeasibilities));
printf("Max dual infeasibility = %g\n",
info.max_dual_infeasibility);
printf("Sum dual infeasibilities = %g\n",
info.sum_dual_infeasibilities);
printf("Num primal residual errors = %d\n",
int(info.num_primal_residual_errors));
printf("Max primal residual error = %g\n",
info.max_primal_residual_error);
printf("Num dual residual errors = %d\n",
int(info.num_dual_residual_errors));
printf("Max dual residual error = %g\n",
info.max_dual_residual_error);
printf("Primal-dual objective error = %g\n",
info.primal_dual_objective_error);
}
highs.clearSolver();
}
highs.resetGlobalScheduler(true);
}
TEST_CASE("test-2087", "[highs_ipm]") {
// Make sure that presolve is performed when re-solving using IPM,
// since optimal basis cannot be used, and ensure that the offset is
// used in IPX
Highs h;
h.setOptionValue("output_flag", dev_run);
// Use shell since it yields an offset after presolve
std::string model = "shell.mps";
std::string filename = std::string(HIGHS_DIR) + "/check/instances/" + model;
h.readModel(filename);
h.setOptionValue("solver", kIpmString);
h.run();
const HighsInt first_ipm_iteration_count = h.getInfo().ipm_iteration_count;
h.run();
REQUIRE(first_ipm_iteration_count == h.getInfo().ipm_iteration_count);
h.resetGlobalScheduler(true);
}
TEST_CASE("test-2527", "[highs_ipm]") {
std::string filename =
std::string(HIGHS_DIR) + "/check/instances/primal1.mps";
Highs h;
h.setOptionValue("output_flag", dev_run);
REQUIRE(h.readModel(filename) == HighsStatus::kOk);
HighsLp lp = h.getLp();
lp.col_cost_.assign(lp.num_col_, 0);
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
h.setOptionValue("solver", kIpmString);
h.setOptionValue("presolve", kHighsOffString);
REQUIRE(h.run() == HighsStatus::kOk);
h.resetGlobalScheduler(true);
}