Skip to content

Commit 6889c0d

Browse files
authored
Merge pull request #2100 from ERGO-Code/fix-2087
Fix 2087
2 parents fc0d251 + c16e22d commit 6889c0d

File tree

12 files changed

+73
-36
lines changed

12 files changed

+73
-36
lines changed

check/TestIpm.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,22 @@ TEST_CASE("test-1966", "[highs_ipm]") {
134134
printf("Sum dual infeasibilities = %g\n", info.sum_dual_infeasibilities);
135135
}
136136
}
137+
138+
TEST_CASE("test-2087", "[highs_ipm]") {
139+
// Make sure that presolve is performed when re-solving using IPM,
140+
// since optimal basis cannot be used, and ensure that the offset is
141+
// used in IPX
142+
Highs h;
143+
h.setOptionValue("output_flag", dev_run);
144+
// Use shell since it yields an offset after presolve
145+
std::string model = "shell.mps";
146+
std::string filename = std::string(HIGHS_DIR) + "/check/instances/" + model;
147+
h.readModel(filename);
148+
149+
h.setOptionValue("solver", kIpmString);
150+
h.run();
151+
const HighsInt first_ipm_iteration_count = h.getInfo().ipm_iteration_count;
152+
153+
h.run();
154+
REQUIRE(first_ipm_iteration_count == h.getInfo().ipm_iteration_count);
155+
}

check/TestIpx.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ using Int = ipxint;
2222

2323
constexpr HighsInt num_var = 12;
2424
constexpr HighsInt num_constr = 9;
25+
const double offset = 0;
2526
const double obj[] = {-0.2194, 0.0, 0.0, 0.0, 0.0, 0.0,
2627
0.0, 0.0, -0.32, -0.5564, 0.6, -0.48};
2728
const double lb[num_var] = {0.0};
@@ -47,8 +48,8 @@ TEST_CASE("test-ipx", "[highs_ipx]") {
4748
lps.SetParameters(parameters);
4849

4950
// Solve the LP.
50-
Int load_status = lps.LoadModel(num_var, obj, lb, ub, num_constr, Ap, Ai, Ax,
51-
rhs, constr_type);
51+
Int load_status = lps.LoadModel(num_var, offset, obj, lb, ub, num_constr, Ap,
52+
Ai, Ax, rhs, constr_type);
5253
REQUIRE(load_status == 0);
5354

5455
highs::parallel::initialize_scheduler();

src/ipm/IpxWrapper.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,19 @@ HighsStatus solveLpIpx(const HighsOptions& options, HighsTimer& timer,
150150
lps.SetCallback(&callback);
151151

152152
ipx::Int num_col, num_row;
153+
double offset;
153154
std::vector<ipx::Int> Ap, Ai;
154155
std::vector<double> objective, col_lb, col_ub, Av, rhs;
155156
std::vector<char> constraint_type;
156-
fillInIpxData(lp, num_col, num_row, objective, col_lb, col_ub, Ap, Ai, Av,
157-
rhs, constraint_type);
157+
fillInIpxData(lp, num_col, num_row, offset, objective, col_lb, col_ub, Ap, Ai,
158+
Av, rhs, constraint_type);
158159
highsLogUser(options.log_options, HighsLogType::kInfo,
159160
"IPX model has %" HIGHSINT_FORMAT " rows, %" HIGHSINT_FORMAT
160161
" columns and %" HIGHSINT_FORMAT " nonzeros\n",
161162
num_row, num_col, Ap[num_col]);
162163

163164
ipx::Int load_status = lps.LoadModel(
164-
num_col, objective.data(), col_lb.data(), col_ub.data(), num_row,
165+
num_col, offset, objective.data(), col_lb.data(), col_ub.data(), num_row,
165166
Ap.data(), Ai.data(), Av.data(), rhs.data(), constraint_type.data());
166167

167168
if (load_status) {
@@ -387,10 +388,10 @@ HighsStatus solveLpIpx(const HighsOptions& options, HighsTimer& timer,
387388
}
388389

389390
void fillInIpxData(const HighsLp& lp, ipx::Int& num_col, ipx::Int& num_row,
390-
std::vector<double>& obj, std::vector<double>& col_lb,
391-
std::vector<double>& col_ub, std::vector<ipx::Int>& Ap,
392-
std::vector<ipx::Int>& Ai, std::vector<double>& Ax,
393-
std::vector<double>& rhs,
391+
double& offset, std::vector<double>& obj,
392+
std::vector<double>& col_lb, std::vector<double>& col_ub,
393+
std::vector<ipx::Int>& Ap, std::vector<ipx::Int>& Ai,
394+
std::vector<double>& Ax, std::vector<double>& rhs,
394395
std::vector<char>& constraint_type) {
395396
num_col = lp.num_col_;
396397
num_row = lp.num_row_;
@@ -517,6 +518,7 @@ void fillInIpxData(const HighsLp& lp, ipx::Int& num_col, ipx::Int& num_row,
517518
col_ub[lp.num_col_ + slack] = lp.row_upper_[row];
518519
}
519520

521+
offset = HighsInt(lp.sense_) * lp.offset_;
520522
obj.resize(num_col);
521523
for (HighsInt col = 0; col < lp.num_col_; col++) {
522524
obj[col] = (HighsInt)lp.sense_ * lp.col_cost_[col];

src/ipm/IpxWrapper.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ HighsStatus solveLpIpx(const HighsOptions& options, HighsTimer& timer,
2828
HighsCallback& callback);
2929

3030
void fillInIpxData(const HighsLp& lp, ipx::Int& num_col, ipx::Int& num_row,
31-
std::vector<double>& obj, std::vector<double>& col_lb,
32-
std::vector<double>& col_ub, std::vector<ipx::Int>& Ap,
33-
std::vector<ipx::Int>& Ai, std::vector<double>& Ax,
34-
std::vector<double>& rhs,
31+
double& offset, std::vector<double>& obj,
32+
std::vector<double>& col_lb, std::vector<double>& col_ub,
33+
std::vector<ipx::Int>& Ap, std::vector<ipx::Int>& Ai,
34+
std::vector<double>& Ax, std::vector<double>& rhs,
3535
std::vector<char>& constraint_type);
3636

3737
HighsStatus reportIpxSolveStatus(const HighsOptions& options,

src/ipm/ipx/ipx_c.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ ipxint ipx_load_model(void* self, ipxint num_var, const double* obj,
99
const ipxint* Ap, const ipxint* Ai, const double* Ax,
1010
const double* rhs, const char* constr_type) {
1111
LpSolver* solver = static_cast<LpSolver*>(self);
12-
return solver->LoadModel(num_var, obj, lb, ub, num_constr, Ap, Ai, Ax, rhs,
12+
const double offset = 0;
13+
return solver->LoadModel(num_var, offset, obj, lb, ub, num_constr, Ap, Ai, Ax, rhs,
1314
constr_type);
1415
}
1516

src/ipm/ipx/iterate.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,8 @@ void Iterate::ComputeObjectives() const {
617617
if (postprocessed_) {
618618
// Compute objective values as defined for the LP model.
619619
offset_ = 0.0;
620-
pobjective_ = Dot(c, x_);
621-
dobjective_ = Dot(b, y_);
620+
pobjective_ = model_.offset() + Dot(c, x_);
621+
dobjective_ = model_.offset() + Dot(b, y_);
622622
for (Int j = 0; j < n+m; j++) {
623623
if (std::isfinite(lb[j]))
624624
dobjective_ += lb[j] * zl_[j];
@@ -630,7 +630,7 @@ void Iterate::ComputeObjectives() const {
630630
// (after fixing and implying variables). The offset is such that
631631
// pobjective_ + offset_ is the primal objective after postprocessing.
632632
offset_ = 0.0;
633-
pobjective_ = 0.0;
633+
pobjective_ = model_.offset();
634634
for (Int j = 0; j < n+m; j++) {
635635
if (StateOf(j) != State::fixed)
636636
pobjective_ += c[j] * x_[j];
@@ -643,7 +643,7 @@ void Iterate::ComputeObjectives() const {
643643
offset_ += (zl_[j]-zu_[j]) * x_[j];
644644
}
645645
}
646-
dobjective_ = Dot(b, y_);
646+
dobjective_ = model_.offset() + Dot(b, y_);
647647
for (Int j = 0; j < n+m; j++) {
648648
if (has_barrier_lb(j))
649649
dobjective_ += lb[j] * zl_[j];

src/ipm/ipx/lp_solver.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212

1313
namespace ipx {
1414

15-
Int LpSolver::LoadModel(Int num_var, const double* obj, const double* lb,
15+
Int LpSolver::LoadModel(Int num_var, const double offset,
16+
const double* obj, const double* lb,
1617
const double* ub, Int num_constr, const Int* Ap,
1718
const Int* Ai, const double* Ax, const double* rhs,
1819
const char* constr_type) {
1920
ClearModel();
2021
Int errflag = model_.Load(control_, num_constr, num_var, Ap, Ai, Ax, rhs,
21-
constr_type, obj, lb, ub);
22+
constr_type, offset, obj, lb, ub);
2223
model_.GetInfo(&info_);
2324
return errflag;
2425
}

src/ipm/ipx/lp_solver.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class LpSolver {
2828
// IPX_ERROR_invalid_dimension
2929
// IPX_ERROR_invalid_matrix
3030
// IPX_ERROR_invalid_vector
31-
Int LoadModel(Int num_var, const double* obj, const double* lb,
31+
Int LoadModel(Int num_var, const double offset,
32+
const double* obj, const double* lb,
3233
const double* ub, Int num_constr, const Int* Ap,
3334
const Int* Ai, const double* Ax, const double* rhs,
3435
const char* constr_type);

src/ipm/ipx/model.cc

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ namespace ipx {
99

1010
Int Model::Load(const Control& control, Int num_constr, Int num_var,
1111
const Int* Ap, const Int* Ai, const double* Ax,
12-
const double* rhs, const char* constr_type, const double* obj,
13-
const double* lbuser, const double* ubuser) {
12+
const double* rhs, const char* constr_type, const double offset,
13+
const double* obj, const double* lbuser, const double* ubuser) {
1414
clear();
1515
Int errflag = CopyInput(num_constr, num_var, Ap, Ai, Ax, rhs, constr_type,
16-
obj, lbuser, ubuser);
16+
offset, obj, lbuser, ubuser);
1717
if (errflag)
1818
return errflag;
1919
std::stringstream h_logging_stream;
@@ -336,8 +336,8 @@ void Model::EvaluateInteriorSolution(const Vector& x_solver,
336336
presidual = std::max(presidual, Infnorm(ru));
337337
double dresidual = Infnorm(rc);
338338

339-
double pobjective = Dot(scaled_obj_, x);
340-
double dobjective = Dot(scaled_rhs_, y);
339+
double pobjective = offset_ + Dot(scaled_obj_, x);
340+
double dobjective = offset_ + Dot(scaled_rhs_, y);
341341
for (Int j = 0; j < num_var_; j++) {
342342
if (std::isfinite(scaled_lbuser_[j]))
343343
dobjective += scaled_lbuser_[j] * zl[j];
@@ -541,7 +541,7 @@ static Int CheckMatrix(Int m, Int n, const Int *Ap, const Int *Ai, const double
541541

542542
Int Model::CopyInput(Int num_constr, Int num_var, const Int* Ap, const Int* Ai,
543543
const double* Ax, const double* rhs,
544-
const char* constr_type, const double* obj,
544+
const char* constr_type, const double offset, const double* obj,
545545
const double* lbuser, const double* ubuser) {
546546
if (!(Ap && Ai && Ax && rhs && constr_type && obj && lbuser && ubuser)) {
547547
return IPX_ERROR_argument_null;
@@ -569,6 +569,7 @@ Int Model::CopyInput(Int num_constr, Int num_var, const Int* Ap, const Int* Ai,
569569
boxed_vars_.push_back(j);
570570
}
571571
constr_type_ = std::vector<char>(constr_type, constr_type+num_constr);
572+
offset_ = offset;
572573
scaled_obj_ = Vector(obj, num_var);
573574
scaled_rhs_ = Vector(rhs, num_constr);
574575
scaled_lbuser_ = Vector(lbuser, num_var);

src/ipm/ipx/model.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ class Model {
5858
// IPX_ERROR_invalid_vector
5959
Int Load(const Control& control, Int num_constr, Int num_var,
6060
const Int* Ap, const Int* Ai, const double* Ax,
61-
const double* rhs, const char* constr_type, const double* obj,
62-
const double* lbuser, const double* ubuser);
61+
const double* rhs, const char* constr_type, const double offset,
62+
const double* obj, const double* lbuser, const double* ubuser);
6363
// Performs Flippo's test for deciding dualization
6464
bool filippoDualizationTest() const;
6565
// Writes statistics of input data and preprocessing to @info.
@@ -93,6 +93,9 @@ class Model {
9393
const SparseMatrix& AI() const { return AI_; }
9494
const SparseMatrix& AIt() const { return AIt_; }
9595

96+
// Returns the offset
97+
const double offset() const { return offset_; }
98+
9699
// Returns a reference to a model vector.
97100
const Vector& b() const { return b_; }
98101
const Vector& c() const { return c_; }
@@ -207,7 +210,7 @@ class Model {
207210
// IPX_ERROR_invalid_vector
208211
Int CopyInput(Int num_constr, Int num_var, const Int* Ap, const Int* Ai,
209212
const double* Ax, const double* rhs, const char* constr_type,
210-
const double* obj, const double* lbuser,
213+
const double offset, const double* obj, const double* lbuser,
211214
const double* ubuser);
212215

213216
// Scales A_, scaled_obj_, scaled_rhs_, scaled_lbuser_ and scaled_ubuser_
@@ -376,6 +379,7 @@ class Model {
376379
std::vector<char> constr_type_;
377380
double norm_obj_{0.0}; // Infnorm(obj) as given by user
378381
double norm_rhs_{0.0}; // Infnorm(rhs,lb,ub) as given by user
382+
double offset_;
379383
Vector scaled_obj_;
380384
Vector scaled_rhs_;
381385
Vector scaled_lbuser_;

0 commit comments

Comments
 (0)