Skip to content

Commit 74b4e7d

Browse files
committed
Now have MipProblemData as record of sub-mip dimensions and largest knapsack or Ines sub-MIP; tracking max_submip_level more clearly; and added writeLpToMps for dumping out Ines MIPs
1 parent 12d8ce1 commit 74b4e7d

File tree

7 files changed

+158
-81
lines changed

7 files changed

+158
-81
lines changed

highs/lp_data/HighsLpUtils.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "HConfig.h"
1717
#include "io/Filereader.h"
18+
#include "io/FilereaderMps.h"
1819
#include "io/HMPSIO.h"
1920
#include "io/HighsIO.h"
2021
#include "lp_data/HighsModelUtils.h"
@@ -3513,3 +3514,13 @@ void getSubVectorsTranspose(const HighsIndexCollection& index_collection,
35133514
}
35143515
}
35153516
}
3517+
3518+
HighsStatus writeLpToMps(const HighsOptions& options, const HighsLp& lp,
3519+
const std::string& file_name_prefix) {
3520+
HighsModel model;
3521+
model.lp_ = lp;
3522+
HighsStatus call_status = normaliseNames(options.log_options, model.lp_);
3523+
if (call_status == HighsStatus::kError) return call_status;
3524+
const std::string file_name = file_name_prefix + ".mps";
3525+
return FilereaderMps().writeModelToFile(options, file_name, model);
3526+
}

highs/lp_data/HighsLpUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,4 +305,6 @@ void getSubVectorsTranspose(const HighsIndexCollection& index_collection,
305305
HighsInt* sub_matrix_index,
306306
double* sub_matrix_value);
307307

308+
HighsStatus writeLpToMps(const HighsOptions& options, const HighsLp& lp,
309+
const std::string& file_name_prefix);
308310
#endif // LP_DATA_HIGHSLPUTILS_H_

highs/mip/HighsMipSolver.cpp

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,20 @@ using std::fabs;
3030
HighsMipSolver::HighsMipSolver(HighsCallback& callback,
3131
const HighsOptions& options, const HighsLp& lp,
3232
const HighsSolution& solution, bool submip,
33-
HighsInt submip_level)
33+
HighsInt global_submip_level)
3434
: callback_(&callback),
3535
options_mip_(&options),
3636
model_(&lp),
3737
orig_model_(&lp),
3838
solution_objective_(kHighsInf),
3939
submip(submip),
40-
submip_level(submip_level),
40+
global_submip_level(global_submip_level),
4141
rootbasis(nullptr),
4242
pscostinit(nullptr),
4343
clqtableinit(nullptr),
4444
implicinit(nullptr) {
45-
assert(!submip || submip_level > 0);
46-
this->max_submip_level = 0;
45+
assert(!submip || global_submip_level > 0);
46+
this->max_local_submip_level = 0;
4747
if (solution.value_valid) {
4848
#ifndef NDEBUG
4949
// MIP solver doesn't check row residuals, but they should be OK
@@ -894,9 +894,9 @@ void HighsMipSolver::cleanupSolve(const bool mip_logging) {
894894
(long long unsigned)mipdata_->sepa_lp_iterations,
895895
(long long unsigned)mipdata_->heuristic_lp_iterations);
896896

897-
const std::vector<HighsMipProblemData>& mip_problem_data =
898-
this->mipdata_->mip_problem_data_;
899-
HighsInt num_mip = static_cast<HighsInt>(mip_problem_data.size());
897+
const std::vector<HighsMipProblemRecord>& record =
898+
this->mipdata_->mip_problem_data_.record;
899+
HighsInt num_mip = static_cast<HighsInt>(record.size());
900900
HighsInt num_knapsack_mip = 0;
901901
size_t sum_knapsack_num_col = 0;
902902
HighsInt num_ines_mip = 0;
@@ -907,59 +907,60 @@ void HighsMipSolver::cleanupSolve(const bool mip_logging) {
907907
HighsInt min_submip_num_col = kHighsIInf;
908908
HighsInt min_submip_num_row = kHighsIInf;
909909
const bool full_submip_logging = true;
910+
// Must at least have a record for the MIP itself
911+
assert(num_mip > 0);
910912
for (HighsInt iMip = 0; iMip < num_mip; iMip++) {
911-
switch (mip_problem_data[iMip].type) {
913+
switch (record[iMip].type) {
912914
case HighsMipProblemType::kKnapsack:
913915
num_knapsack_mip++;
914-
sum_knapsack_num_col += mip_problem_data[iMip].num_binary;
916+
sum_knapsack_num_col += record[iMip].num_binary;
915917
break;
916918
case HighsMipProblemType::kInes:
917919
num_ines_mip++;
918-
sum_ines_num_col += mip_problem_data[iMip].num_binary;
919-
sum_ines_num_row += mip_problem_data[iMip].num_row;
920+
sum_ines_num_col += record[iMip].num_binary;
921+
sum_ines_num_row += record[iMip].num_row;
920922
break;
921923
case HighsMipProblemType::kOther:
922924
default:
923925
break;
924926
}
925-
HighsInt global_submip_level = mip_problem_data[iMip].submip_level;
926-
max_global_submip_level = std::max(global_submip_level, max_global_submip_level);
927-
HighsInt submip_num_col = mip_problem_data[iMip].num_continuous +
928-
mip_problem_data[iMip].num_binary +
929-
mip_problem_data[iMip].num_general_integer +
930-
mip_problem_data[iMip].num_implied_integer;
931-
HighsInt submip_num_row = mip_problem_data[iMip].num_row;
927+
HighsInt global_submip_level = record[iMip].global_submip_level;
928+
max_global_submip_level =
929+
std::max(global_submip_level, max_global_submip_level);
930+
HighsInt submip_num_col =
931+
record[iMip].num_continuous + record[iMip].num_binary +
932+
record[iMip].num_general_integer + record[iMip].num_implied_integer;
933+
HighsInt submip_num_row = record[iMip].num_row;
932934
HighsInt submip_sum_dim = submip_num_col + submip_num_row;
933-
if (min_submip_sum_dim > submip_sum_dim) {
935+
if (min_submip_sum_dim > submip_sum_dim && submip_sum_dim > 0) {
934936
min_submip_sum_dim = submip_sum_dim;
935937
min_submip_num_col = submip_num_col;
936938
min_submip_num_row = submip_num_row;
937939
}
938-
if (full_submip_logging)
939-
highsLogUser(options_mip_->log_options, HighsLogType::kInfo,
940-
" MIP %3d (level = %2d; %6d conts; %6d bin; "
941-
"%6d gen; %6d impl; cols / rows: %6d / %6d; type %s)\n",
942-
int(iMip), int(global_submip_level),
943-
int(mip_problem_data[iMip].num_continuous),
944-
int(mip_problem_data[iMip].num_binary),
945-
int(mip_problem_data[iMip].num_general_integer),
946-
int(mip_problem_data[iMip].num_implied_integer),
947-
int(submip_num_col), int(submip_num_row),
948-
mip_problem_data[iMip].type == HighsMipProblemType::kKnapsack
949-
? "Knapsack"
950-
: mip_problem_data[iMip].type == HighsMipProblemType::kInes
951-
? "Ines"
952-
: "Other");
940+
if (full_submip_logging && record[iMip].type != HighsMipProblemType::kOther)
941+
highsLogUser(
942+
options_mip_->log_options, HighsLogType::kInfo,
943+
" MIP %3d (level = %2d; %6d conts; %6d bin; "
944+
"%6d gen; %6d impl; cols / rows: %6d / %6d; type %s)\n",
945+
int(iMip), int(global_submip_level), int(record[iMip].num_continuous),
946+
int(record[iMip].num_binary), int(record[iMip].num_general_integer),
947+
int(record[iMip].num_implied_integer), int(submip_num_col),
948+
int(submip_num_row),
949+
record[iMip].type == HighsMipProblemType::kKnapsack ? "Knapsack"
950+
: record[iMip].type == HighsMipProblemType::kInes ? "Ines"
951+
: "Other");
953952
}
954953
highsLogUser(options_mip_->log_options, HighsLogType::kInfo,
955954
" MIPs %d (%d knapsack; %d Ines)\n", int(num_mip),
956955
int(num_knapsack_mip), int(num_ines_mip));
957956

958957
std::stringstream ss;
959958
ss.str(std::string());
960-
assert(submip_level + max_submip_level == max_global_submip_level);
961-
ss << highsFormatToString(" Max sub-MIP level %d", int(submip_level + max_submip_level));
962-
if (max_submip_level > 0)
959+
assert(global_submip_level + max_local_submip_level ==
960+
max_global_submip_level);
961+
ss << highsFormatToString(" Max sub-MIP level %d",
962+
int(global_submip_level + max_local_submip_level));
963+
if (max_local_submip_level > 0)
963964
ss << highsFormatToString(" (min cols/rows: %d/%d)\n",
964965
int(min_submip_num_col), int(min_submip_num_row));
965966
highsLogUser(options_mip_->log_options, HighsLogType::kInfo, "%s\n",
@@ -974,9 +975,21 @@ void HighsMipSolver::cleanupSolve(const bool mip_logging) {
974975
num_knapsack_mip, sum_knapsack_num_col, num_ines_mip,
975976
sum_ines_num_col, sum_ines_num_row);
976977

977-
if (max_submip_level > 0) {
978+
const bool write_ines_model = false;
979+
if (write_ines_model) {
980+
if (!submip && mipdata_->mip_problem_data_.ines_mip.num_col_ > 0) {
981+
const std::string file_name_prefix = model_->model_name_ + "_ines";
982+
highsLogUser(options_mip_->log_options, HighsLogType::kInfo,
983+
"Generating MPS file %s.mps for Ines MIP with %d columns "
984+
"and %d rows\n",
985+
file_name_prefix.c_str(),
986+
int(mipdata_->mip_problem_data_.ines_mip.num_col_),
987+
int(mipdata_->mip_problem_data_.ines_mip.num_row_));
988+
HighsStatus call_status =
989+
writeLpToMps(*options_mip_, mipdata_->mip_problem_data_.ines_mip,
990+
file_name_prefix);
991+
}
978992
}
979-
980993
if (!timeless_log) analysis_.reportMipTimer();
981994

982995
assert(modelstatus_ != HighsModelStatus::kNotset);

highs/mip/HighsMipSolver.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class HighsMipSolver {
4444
std::vector<HighsObjectiveSolution> saved_objective_and_solution_;
4545

4646
bool submip;
47-
HighsInt submip_level;
48-
HighsInt max_submip_level;
47+
HighsInt global_submip_level;
48+
HighsInt max_local_submip_level;
4949
const HighsBasis* rootbasis;
5050
const HighsPseudocostInitialization* pscostinit;
5151
const HighsCliqueTable* clqtableinit;
@@ -85,7 +85,7 @@ class HighsMipSolver {
8585

8686
HighsMipSolver(HighsCallback& callback, const HighsOptions& options,
8787
const HighsLp& lp, const HighsSolution& solution,
88-
bool submip = false, HighsInt submip_level = 0);
88+
bool submip = false, HighsInt global_submip_level = 0);
8989

9090
~HighsMipSolver();
9191

highs/mip/HighsMipSolverData.cpp

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,13 +2686,15 @@ bool HighsMipSolverData::mipIsKnapsack(const bool silent) {
26862686
this->knapsack_capacity_ = std::floor(double_capacity + capacity_margin);
26872687
// Problem is knapsack!
26882688
if (!silent) {
2689-
HighsMipProblemData mip_problem_data;
2690-
mip_problem_data.clear();
2691-
mip_problem_data.submip_level = mipsolver.submip_level;
2692-
mip_problem_data.num_binary = lp.num_col_;
2693-
mip_problem_data.num_row = lp.num_row_;
2694-
mip_problem_data.type = HighsMipProblemType::kKnapsack;
2695-
this->mip_problem_data_.push_back(mip_problem_data);
2689+
HighsMipProblemRecord mip_problem_record;
2690+
mip_problem_record.clear();
2691+
mip_problem_record.global_submip_level = mipsolver.global_submip_level;
2692+
mip_problem_record.num_binary = lp.num_col_;
2693+
mip_problem_record.num_row = lp.num_row_;
2694+
mip_problem_record.type = HighsMipProblemType::kKnapsack;
2695+
this->mip_problem_data_.record.push_back(mip_problem_record);
2696+
if (this->mip_problem_data_.knapsack_mip.num_col_ == 0)
2697+
this->mip_problem_data_.knapsack_mip = lp;
26962698
}
26972699
return true;
26982700
}
@@ -2708,47 +2710,49 @@ bool HighsMipSolverData::mipIsInes(const bool silent) {
27082710
// Origin must be feasible
27092711
const double ines_feas_tol = 0;
27102712
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
2711-
if (lp.row_lower_[0] - ines_feas_tol > 0 ||
2712-
lp.row_upper_[0] + ines_feas_tol < 0)
2713+
if (lp.row_lower_[iRow] - ines_feas_tol > 0 ||
2714+
lp.row_upper_[iRow] + ines_feas_tol < 0)
27132715
return false;
27142716
}
27152717
if (!silent) {
27162718
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
27172719
"MIP is an Ines problem\n");
2718-
HighsMipProblemData mip_problem_data;
2719-
mip_problem_data.clear();
2720-
mip_problem_data.submip_level = mipsolver.submip_level;
2721-
mip_problem_data.num_binary = lp.num_col_;
2722-
mip_problem_data.num_row = lp.num_row_;
2723-
mip_problem_data.type = HighsMipProblemType::kInes;
2724-
this->mip_problem_data_.push_back(mip_problem_data);
2720+
HighsMipProblemRecord mip_problem_record;
2721+
mip_problem_record.clear();
2722+
mip_problem_record.global_submip_level = mipsolver.global_submip_level;
2723+
mip_problem_record.num_binary = lp.num_col_;
2724+
mip_problem_record.num_row = lp.num_row_;
2725+
mip_problem_record.type = HighsMipProblemType::kInes;
2726+
this->mip_problem_data_.record.push_back(mip_problem_record);
2727+
if (this->mip_problem_data_.ines_mip.num_col_ == 0)
2728+
this->mip_problem_data_.ines_mip = lp;
27252729
}
27262730
return true;
27272731
}
27282732

27292733
void HighsMipSolverData::mipIsOther() {
27302734
const HighsLp& lp = *(mipsolver.model_);
2731-
HighsMipProblemData mip_problem_data;
2732-
mip_problem_data.clear();
2733-
mip_problem_data.submip_level = mipsolver.submip_level;
2735+
HighsMipProblemRecord mip_problem_record;
2736+
mip_problem_record.clear();
2737+
mip_problem_record.global_submip_level = mipsolver.global_submip_level;
27342738
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
27352739
if (lp.integrality_[iCol] == HighsVarType::kContinuous) {
2736-
mip_problem_data.num_continuous++;
2740+
mip_problem_record.num_continuous++;
27372741
} else if (lp.integrality_[iCol] == HighsVarType::kInteger) {
27382742
if (lp.col_lower_[iCol] == 0 && lp.col_upper_[iCol] == 1) {
2739-
mip_problem_data.num_binary++;
2743+
mip_problem_record.num_binary++;
27402744
} else {
2741-
mip_problem_data.num_general_integer++;
2745+
mip_problem_record.num_general_integer++;
27422746
}
27432747
} else if (lp.integrality_[iCol] == HighsVarType::kImplicitInteger) {
2744-
mip_problem_data.num_implied_integer++;
2748+
mip_problem_record.num_implied_integer++;
27452749
} else {
27462750
assert(111 == 234);
27472751
}
27482752
}
2749-
mip_problem_data.num_row = lp.num_row_;
2750-
mip_problem_data.type = HighsMipProblemType::kOther;
2751-
this->mip_problem_data_.push_back(mip_problem_data);
2753+
mip_problem_record.num_row = lp.num_row_;
2754+
mip_problem_record.type = HighsMipProblemType::kOther;
2755+
this->mip_problem_data_.record.push_back(mip_problem_record);
27522756
}
27532757

27542758
static double possInfRelDiff(const double v0, const double v1,
@@ -2887,12 +2891,48 @@ void HighsMipSolverData::updatePrimalDualIntegral(const double from_lower_bound,
28872891

28882892
void HighsPrimaDualIntegral::initialise() { this->value = -kHighsInf; }
28892893

2890-
void HighsMipProblemData::clear() {
2891-
this->submip_level = -1;
2894+
void HighsMipProblemRecord::clear() {
2895+
this->global_submip_level = -1;
28922896
this->num_continuous = 0;
28932897
this->num_binary = 0;
28942898
this->num_implied_integer = 0;
28952899
this->num_general_integer = 0;
28962900
this->num_row = 0;
28972901
this->type = HighsMipProblemType::kOther;
28982902
}
2903+
2904+
void HighsMipProblemData::clear() { this->record.clear(); }
2905+
2906+
void HighsMipProblemData::append(const HighsMipProblemData& mip_problem_data) {
2907+
this->record.insert(this->record.end(), mip_problem_data.record.begin(),
2908+
mip_problem_data.record.end());
2909+
HighsInt current_sum =
2910+
this->knapsack_mip.num_col_ + this->knapsack_mip.num_row_;
2911+
HighsInt append_sum = mip_problem_data.knapsack_mip.num_col_ +
2912+
mip_problem_data.knapsack_mip.num_row_;
2913+
if (current_sum < append_sum)
2914+
this->knapsack_mip = mip_problem_data.knapsack_mip;
2915+
current_sum = this->ines_mip.num_col_ + this->ines_mip.num_row_;
2916+
append_sum =
2917+
mip_problem_data.ines_mip.num_col_ + mip_problem_data.ines_mip.num_row_;
2918+
if (current_sum < append_sum) this->ines_mip = mip_problem_data.ines_mip;
2919+
}
2920+
2921+
HighsInt HighsMipProblemData::numRecord() {
2922+
return static_cast<HighsInt>(record.size());
2923+
}
2924+
2925+
HighsInt HighsMipProblemData::numKnapsack() {
2926+
HighsInt num_knapsack = 0;
2927+
for (HighsInt iMip = 0; iMip < this->numRecord(); iMip++)
2928+
if (this->record[iMip].type == HighsMipProblemType::kKnapsack)
2929+
num_knapsack++;
2930+
return num_knapsack;
2931+
}
2932+
2933+
HighsInt HighsMipProblemData::numInes() {
2934+
HighsInt num_ines = 0;
2935+
for (HighsInt iMip = 0; iMip < this->numRecord(); iMip++)
2936+
if (this->record[iMip].type == HighsMipProblemType::kInes) num_ines++;
2937+
return num_ines;
2938+
}

highs/mip/HighsMipSolverData.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232

3333
enum class HighsMipProblemType { kKnapsack = 0, kInes, kOther };
3434

35-
struct HighsMipProblemData {
36-
HighsInt submip_level;
35+
struct HighsMipProblemRecord {
36+
HighsInt global_submip_level;
3737
HighsInt num_continuous;
3838
HighsInt num_binary;
3939
HighsInt num_general_integer;
@@ -43,6 +43,17 @@ struct HighsMipProblemData {
4343
void clear();
4444
};
4545

46+
struct HighsMipProblemData {
47+
std::vector<HighsMipProblemRecord> record;
48+
HighsLp ines_mip;
49+
HighsLp knapsack_mip;
50+
void clear();
51+
void append(const HighsMipProblemData& mip_problem_data);
52+
HighsInt numRecord();
53+
HighsInt numKnapsack();
54+
HighsInt numInes();
55+
};
56+
4657
struct HighsPrimaDualIntegral {
4758
double value;
4859
double prev_lb;
@@ -169,7 +180,7 @@ struct HighsMipSolverData {
169180
HighsInt knapsack_capacity_;
170181
HighsInt knapsack_integral_scale_;
171182

172-
std::vector<HighsMipProblemData> mip_problem_data_;
183+
HighsMipProblemData mip_problem_data_;
173184

174185
HighsMipSolverData(HighsMipSolver& mipsolver)
175186
: mipsolver(mipsolver),

0 commit comments

Comments
 (0)