Skip to content

Commit fe84e8d

Browse files
authored
Merge pull request #2708 from ERGO-Code/fix-2700
Simplex sub-solver timing now distinguishes primal and dual simplex
2 parents cd202e8 + 4269687 commit fe84e8d

File tree

5 files changed

+98
-57
lines changed

5 files changed

+98
-57
lines changed

highs/lp_data/HConst.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,10 @@ enum IisStatus : int {
303303

304304
enum SubSolverIndex : int {
305305
kSubSolverMip = 0,
306-
kSubSolverSimplexBasis,
307-
kSubSolverSimplexNoBasis,
306+
kSubSolverDuSimplexBasis,
307+
kSubSolverDuSimplexNoBasis,
308+
kSubSolverPrSimplexBasis,
309+
kSubSolverPrSimplexNoBasis,
308310
kSubSolverHipo,
309311
kSubSolverIpx,
310312
kSubSolverHipoAc,

highs/lp_data/HighsInterface.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4327,8 +4327,10 @@ void HighsSubSolverCallTime::initialise() {
43274327
this->num_call.assign(kSubSolverCount, 0);
43284328
this->run_time.assign(kSubSolverCount, 0);
43294329
this->name.assign(kSubSolverCount, "");
4330-
this->name[kSubSolverSimplexBasis] = "Simplex (basis)";
4331-
this->name[kSubSolverSimplexNoBasis] = "Simplex (no basis)";
4330+
this->name[kSubSolverDuSimplexBasis] = "Du simplex (basis)";
4331+
this->name[kSubSolverDuSimplexNoBasis] = "Du simplex (no basis)";
4332+
this->name[kSubSolverPrSimplexBasis] = "Pr simplex (basis)";
4333+
this->name[kSubSolverPrSimplexNoBasis] = "Pr simplex (no basis)";
43324334
this->name[kSubSolverHipo] = "HiPO";
43334335
this->name[kSubSolverIpx] = "IPX";
43344336
this->name[kSubSolverHipoAc] = "HiPO (AC)";
@@ -4359,7 +4361,7 @@ void Highs::reportSubSolverCallTime() const {
43594361
std::stringstream ss;
43604362
ss.str(std::string());
43614363
ss << highsFormatToString(
4362-
"\nSub-solver timing\nSolver Calls Time "
4364+
"\nSub-solver timing\nSolver Calls Time "
43634365
"Time/call");
43644366
if (mip_time > 0) ss << " MIP%";
43654367
highsLogUser(options_.log_options, HighsLogType::kInfo, "%s\n",
@@ -4370,7 +4372,7 @@ void Highs::reportSubSolverCallTime() const {
43704372
if (this->sub_solver_call_time_.num_call[Ix]) {
43714373
ss.str(std::string());
43724374
ss << highsFormatToString(
4373-
"%-18s %9d %11.4e %11.4e",
4375+
"%-21s %9d %11.4e %11.4e",
43744376
this->sub_solver_call_time_.name[Ix].c_str(),
43754377
int(this->sub_solver_call_time_.num_call[Ix]),
43764378
this->sub_solver_call_time_.run_time[Ix],
@@ -4389,7 +4391,7 @@ void Highs::reportSubSolverCallTime() const {
43894391
}
43904392
if (mip_time > 0)
43914393
highsLogUser(options_.log_options, HighsLogType::kInfo,
4392-
"TOTAL (excluding AC) %11.4e %5.1f\n",
4394+
"TOTAL (excluding AC) %11.4e %5.1f\n",
43934395
sum_mip_sub_solve_time,
43944396
1e2 * sum_mip_sub_solve_time / mip_time);
43954397
}

highs/mip/HighsMipAnalysis.cpp

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ void HighsMipAnalysis::mipTimerAdd(const HighsInt mip_clock,
102102
// , const HighsInt thread_id
103103
) const {
104104
if (!analyse_mip_time) return;
105+
if (num_call == 0) {
106+
assert(time == 0);
107+
return;
108+
}
105109
HighsInt highs_timer_clock = mip_clocks.clock_[mip_clock];
106110
mip_clocks.timer_pointer_->add(highs_timer_clock, num_call, time);
107111
}
@@ -120,36 +124,30 @@ void HighsMipAnalysis::mipTimerUpdate(
120124
// If IPM has not been run first, then check that simplex call
121125
// counts are consistent with valid_basis and presolve
122126
if (valid_basis) {
123-
mipTimerAdd(kMipClockSimplexBasisSolveLp,
124-
sub_solver_call_time.num_call[kSubSolverSimplexBasis],
125-
sub_solver_call_time.run_time[kSubSolverSimplexBasis]);
126-
assert(sub_solver_call_time.num_call[kSubSolverSimplexNoBasis] == 0);
127-
} else if (presolve) {
128-
mipTimerAdd(kMipClockSimplexBasisSolveLp,
129-
sub_solver_call_time.num_call[kSubSolverSimplexBasis],
130-
sub_solver_call_time.run_time[kSubSolverSimplexBasis]);
131-
mipTimerAdd(kMipClockSimplexNoBasisSolveLp,
132-
sub_solver_call_time.num_call[kSubSolverSimplexNoBasis],
133-
sub_solver_call_time.run_time[kSubSolverSimplexNoBasis]);
134-
} else {
135-
mipTimerAdd(kMipClockSimplexNoBasisSolveLp,
136-
sub_solver_call_time.num_call[kSubSolverSimplexNoBasis],
137-
sub_solver_call_time.run_time[kSubSolverSimplexNoBasis]);
138-
assert(sub_solver_call_time.num_call[kSubSolverSimplexBasis] == 0);
127+
assert(sub_solver_call_time.num_call[kSubSolverDuSimplexNoBasis] == 0);
128+
} else if (!presolve) {
129+
assert(sub_solver_call_time.num_call[kSubSolverDuSimplexBasis] == 0);
139130
}
140131
} else {
141132
// IPM has been run first, then at least one of the simplex call
142133
// counts should be zero
143-
assert(sub_solver_call_time.num_call[kSubSolverSimplexBasis] *
144-
sub_solver_call_time.num_call[kSubSolverSimplexNoBasis] ==
145-
0);
146-
mipTimerAdd(kMipClockSimplexBasisSolveLp,
147-
sub_solver_call_time.num_call[kSubSolverSimplexBasis],
148-
sub_solver_call_time.run_time[kSubSolverSimplexBasis]);
149-
mipTimerAdd(kMipClockSimplexNoBasisSolveLp,
150-
sub_solver_call_time.num_call[kSubSolverSimplexNoBasis],
151-
sub_solver_call_time.run_time[kSubSolverSimplexNoBasis]);
134+
assert(sub_solver_call_time.num_call[kSubSolverDuSimplexBasis] == 0 ||
135+
sub_solver_call_time.num_call[kSubSolverDuSimplexNoBasis] == 0);
152136
}
137+
138+
mipTimerAdd(kMipClockDuSimplexBasisSolveLp,
139+
sub_solver_call_time.num_call[kSubSolverDuSimplexBasis],
140+
sub_solver_call_time.run_time[kSubSolverDuSimplexBasis]);
141+
mipTimerAdd(kMipClockDuSimplexNoBasisSolveLp,
142+
sub_solver_call_time.num_call[kSubSolverDuSimplexNoBasis],
143+
sub_solver_call_time.run_time[kSubSolverDuSimplexNoBasis]);
144+
mipTimerAdd(kMipClockPrSimplexBasisSolveLp,
145+
sub_solver_call_time.num_call[kSubSolverPrSimplexBasis],
146+
sub_solver_call_time.run_time[kSubSolverPrSimplexBasis]);
147+
mipTimerAdd(kMipClockPrSimplexNoBasisSolveLp,
148+
sub_solver_call_time.num_call[kSubSolverPrSimplexNoBasis],
149+
sub_solver_call_time.run_time[kSubSolverPrSimplexNoBasis]);
150+
153151
if (sub_solver_call_time.num_call[kSubSolverHipo]) {
154152
const HighsInt mip_clock = analytic_centre
155153
? kMipClockHipoSolveAnalyticCentreLp
@@ -181,9 +179,9 @@ void HighsMipAnalysis::reportMipSolveLpClock(const bool header) {
181179
double total_time = mip_clocks.timer_pointer_->read(0);
182180
if (total_time < 0.01) return;
183181
HighsInt simplex_basis_solve_iclock =
184-
mip_clocks.clock_[kMipClockSimplexBasisSolveLp];
182+
mip_clocks.clock_[kMipClockDuSimplexBasisSolveLp];
185183
HighsInt simplex_no_basis_solve_iclock =
186-
mip_clocks.clock_[kMipClockSimplexNoBasisSolveLp];
184+
mip_clocks.clock_[kMipClockDuSimplexNoBasisSolveLp];
187185
HighsInt ipm_solve_iclock = mip_clocks.clock_[kMipClockIpxSolveLp];
188186
// HighsInt num_no_basis_solve =
189187
// mip_clocks.timer_pointer_->clock_num_call[no_basis_solve_iclock]; HighsInt
@@ -301,8 +299,8 @@ void HighsMipAnalysis::checkSubSolverCallTime(
301299
error = true;
302300
}
303301
};
304-
check(kSubSolverSimplexBasis, kMipClockSimplexBasisSolveLp);
305-
check(kSubSolverSimplexNoBasis, kMipClockSimplexNoBasisSolveLp);
302+
check(kSubSolverDuSimplexBasis, kMipClockDuSimplexBasisSolveLp);
303+
check(kSubSolverDuSimplexNoBasis, kMipClockDuSimplexNoBasisSolveLp);
306304
check(kSubSolverHipo, kMipClockHipoSolveLp);
307305
check(kSubSolverIpx, kMipClockIpxSolveLp);
308306
check(kSubSolverHipoAc, kMipClockHipoSolveAnalyticCentreLp);

highs/mip/MipTimer.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,14 @@ enum iClockMip {
9696
kMipClockModKSepa,
9797

9898
// LP solves
99-
kMipClockSimplexBasisSolveLp,
100-
kMipClockSimplexNoBasisSolveLp,
99+
kMipClockDuSimplexBasisSolveLp,
100+
kMipClockDuSimplexNoBasisSolveLp,
101101
kMipClockHipoSolveAnalyticCentreLp,
102102
kMipClockIpxSolveAnalyticCentreLp,
103103
kMipClockHipoSolveLp,
104104
kMipClockIpxSolveLp,
105+
kMipClockPrSimplexBasisSolveLp,
106+
kMipClockPrSimplexNoBasisSolveLp,
105107

106108
// Sub-MIP solves
107109
kMipClockSubMipSolve,
@@ -136,11 +138,11 @@ class MipTimer {
136138
// clock[kMipClockHipoSolveAnalyticCentreLp] and
137139
// clock[kMipClockIpxSolveAnalyticCentreLp] aren't changed by inserting new
138140
// clocks
139-
clock[kMipClockSimplexBasisSolveLp] =
140-
timer_pointer->clock_def("Solve LP - simplex basis");
141-
clock[kMipClockSimplexNoBasisSolveLp] =
142-
timer_pointer->clock_def("Solve LP - simplex no basis");
143-
assert(clock[kMipClockSimplexNoBasisSolveLp] == 8);
141+
clock[kMipClockDuSimplexBasisSolveLp] =
142+
timer_pointer->clock_def("Solve LP - du simplex basis");
143+
clock[kMipClockDuSimplexNoBasisSolveLp] =
144+
timer_pointer->clock_def("Solve LP - du simplex no basis");
145+
assert(clock[kMipClockDuSimplexNoBasisSolveLp] == 8);
144146
clock[kMipClockHipoSolveAnalyticCentreLp] =
145147
timer_pointer->clock_def("Solve LP: HiPO analytic centre");
146148
clock[kMipClockIpxSolveAnalyticCentreLp] =
@@ -149,6 +151,10 @@ class MipTimer {
149151
assert(clock[kMipClockIpxSolveAnalyticCentreLp] == 10);
150152
clock[kMipClockHipoSolveLp] = timer_pointer->clock_def("Solve LP: HiPO");
151153
clock[kMipClockIpxSolveLp] = timer_pointer->clock_def("Solve LP: IPX");
154+
clock[kMipClockPrSimplexBasisSolveLp] =
155+
timer_pointer->clock_def("Solve LP - pr simplex basis");
156+
clock[kMipClockPrSimplexNoBasisSolveLp] =
157+
timer_pointer->clock_def("Solve LP - pr simplex no basis");
152158

153159
// Level 1 - Should correspond to kMipClockTotal
154160
clock[kMipClockInit] = timer_pointer->clock_def("Initialise");
@@ -366,8 +372,10 @@ class MipTimer {
366372

367373
void reportMipSolveLpClock(const HighsTimerClock& mip_timer_clock) {
368374
const std::vector<HighsInt> mip_clock_list{
369-
kMipClockSimplexBasisSolveLp,
370-
kMipClockSimplexNoBasisSolveLp,
375+
kMipClockDuSimplexBasisSolveLp,
376+
kMipClockDuSimplexNoBasisSolveLp,
377+
kMipClockPrSimplexBasisSolveLp,
378+
kMipClockPrSimplexNoBasisSolveLp,
371379
kMipClockHipoSolveAnalyticCentreLp,
372380
kMipClockIpxSolveAnalyticCentreLp,
373381
kMipClockHipoSolveLp,

highs/simplex/HApp.h

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,34 @@ inline HighsStatus returnFromSolveLpSimplex(HighsLpSolverObject& solver_object,
4343
// Identify which clock to stop. Can't inspect the basis, as there
4444
// will generally be one after simplex, so have to deduce whether
4545
// there was one before
46-
const HighsInt sub_solver_ix =
47-
solver_object.sub_solver_call_time_.run_time[kSubSolverSimplexBasis] < 0
48-
? kSubSolverSimplexBasis
49-
: kSubSolverSimplexNoBasis;
50-
const HighsInt sub_solver_not_ix = sub_solver_ix == kSubSolverSimplexBasis
51-
? kSubSolverSimplexNoBasis
52-
: kSubSolverSimplexBasis;
53-
assert(solver_object.sub_solver_call_time_.run_time[sub_solver_not_ix] >= 0);
54-
(void)sub_solver_not_ix;
55-
assert(solver_object.sub_solver_call_time_.run_time[sub_solver_ix] < 0);
46+
HighsInt sub_solver_ix = -1;
47+
if (solver_object.sub_solver_call_time_.run_time[kSubSolverDuSimplexBasis] <
48+
0)
49+
sub_solver_ix = kSubSolverDuSimplexBasis;
50+
if (solver_object.sub_solver_call_time_.run_time[kSubSolverDuSimplexNoBasis] <
51+
0)
52+
sub_solver_ix = kSubSolverDuSimplexNoBasis;
53+
if (solver_object.sub_solver_call_time_.run_time[kSubSolverPrSimplexBasis] <
54+
0)
55+
sub_solver_ix = kSubSolverPrSimplexBasis;
56+
if (solver_object.sub_solver_call_time_.run_time[kSubSolverPrSimplexNoBasis] <
57+
0)
58+
sub_solver_ix = kSubSolverPrSimplexNoBasis;
59+
// Ensure that one clock has been identified
60+
assert(sub_solver_ix >= 0);
61+
// Check that only one clock was started
62+
if (sub_solver_ix != kSubSolverDuSimplexBasis)
63+
assert(solver_object.sub_solver_call_time_
64+
.run_time[kSubSolverDuSimplexBasis] >= 0);
65+
if (sub_solver_ix != kSubSolverDuSimplexNoBasis)
66+
assert(solver_object.sub_solver_call_time_
67+
.run_time[kSubSolverDuSimplexNoBasis] >= 0);
68+
if (sub_solver_ix != kSubSolverPrSimplexBasis)
69+
assert(solver_object.sub_solver_call_time_
70+
.run_time[kSubSolverPrSimplexBasis] >= 0);
71+
if (sub_solver_ix != kSubSolverPrSimplexNoBasis)
72+
assert(solver_object.sub_solver_call_time_
73+
.run_time[kSubSolverPrSimplexNoBasis] >= 0);
5674
// Update the call count and run time
5775
solver_object.sub_solver_call_time_.num_call[sub_solver_ix]++;
5876
solver_object.sub_solver_call_time_.run_time[sub_solver_ix] +=
@@ -117,8 +135,21 @@ inline HighsStatus solveLpSimplex(HighsLpSolverObject& solver_object) {
117135
assert(retained_ekk_data_ok);
118136
return_status = HighsStatus::kError;
119137
}
120-
const HighsInt sub_solver_ix =
121-
basis.valid ? kSubSolverSimplexBasis : kSubSolverSimplexNoBasis;
138+
HighsInt sub_solver_ix = -1;
139+
if (options.simplex_strategy == kSimplexStrategyPrimal) {
140+
if (basis.valid) {
141+
sub_solver_ix = kSubSolverPrSimplexBasis;
142+
} else {
143+
sub_solver_ix = kSubSolverPrSimplexNoBasis;
144+
}
145+
} else {
146+
if (basis.valid) {
147+
sub_solver_ix = kSubSolverDuSimplexBasis;
148+
} else {
149+
sub_solver_ix = kSubSolverDuSimplexNoBasis;
150+
}
151+
}
152+
assert(sub_solver_ix >= 0);
122153
assert(solver_object.sub_solver_call_time_.run_time.size() > 0);
123154
solver_object.sub_solver_call_time_.run_time[sub_solver_ix] =
124155
-solver_object.timer_.read();

0 commit comments

Comments
 (0)