Skip to content

Commit 55231fb

Browse files
committed
Merge branch 'hipo-status' into hipo-uplook
2 parents 7a1ffd5 + ac438eb commit 55231fb

14 files changed

Lines changed: 325 additions & 300 deletions

highs/ipm/IpxWrapper.cpp

Lines changed: 7 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -491,15 +491,8 @@ HighsStatus solveHipo(const HighsOptions& options, HighsTimer& timer,
491491
// const bool report_solve_data =
492492
// kHighsAnalysisLevelSolverSummaryData & options.highs_analysis_level;
493493

494-
// Differently from IPX, HiPO returns a single status. So, dealing with
495-
// statuses is a bit different.
496494
// hipo.solved(), hipo.stopped(), hipo.failed() can be used to query if the
497495
// status belongs to the solved, stopped or failed group.
498-
// If primal-dual feasible solution is found (non-vertex solution), then the
499-
// status is kStatusPDfeas.
500-
// If crossover is successful, then the status is kStatusBasic.
501-
// Otherwise, the specific crossover status can be accessed through the
502-
// ipx_info stored in hipo_info.
503496

504497
// Get solver and solution information.
505498
const hipo::Info hipo_info = hipo.getInfo();
@@ -584,16 +577,14 @@ HighsStatus solveHipo(const HighsOptions& options, HighsTimer& timer,
584577
}
585578

586579
// Status should be optimal or imprecise
587-
if (ipxStatusError(solve_status != hipo::kStatusPDFeas &&
588-
solve_status != hipo::kStatusBasic &&
580+
if (ipxStatusError(solve_status != hipo::kStatusOptimal &&
589581
solve_status != hipo::kStatusImprecise,
590582
options, "Hipo",
591583
"status should be optimal or imprecise but value is",
592584
solve_status))
593585
return HighsStatus::kError;
594586

595587
const bool have_basic_solution =
596-
hipo_info.ipx_used &&
597588
hipo_info.ipx_info.status_crossover != IPX_STATUS_not_run;
598589

599590
const bool imprecise_solution =
@@ -1397,51 +1388,15 @@ HighsStatus reportHipoStatus(const HighsOptions& options,
13971388
return HighsStatus::kOk;
13981389
}
13991390

1400-
// these are warnings
1401-
else if (status == hipo::kStatusTimeLimit) {
1402-
highsLogUser(options.log_options, HighsLogType::kWarning,
1403-
"Hipo: Time limit\n");
1404-
return HighsStatus::kWarning;
1405-
} else if (status == hipo::kStatusUserInterrupt) {
1406-
highsLogUser(options.log_options, HighsLogType::kWarning,
1407-
"Hipo: User interrupt\n");
1408-
return HighsStatus::kWarning;
1409-
} else if (status == hipo::kStatusMaxIter) {
1410-
highsLogUser(options.log_options, HighsLogType::kWarning,
1411-
"Hipo: Reached maximum iterations\n");
1412-
return HighsStatus::kWarning;
1413-
} else if (status == hipo::kStatusNoProgress) {
1414-
highsLogUser(options.log_options, HighsLogType::kWarning,
1415-
"Hipo: No progress\n");
1416-
return HighsStatus::kWarning;
1417-
} else if (status == hipo::kStatusImprecise) {
1418-
highsLogUser(options.log_options, HighsLogType::kWarning,
1419-
"Hipo: Imprecise solution\n");
1391+
else if (hipo.stopped()) {
1392+
highsLogUser(options.log_options, HighsLogType::kWarning, "Hipo: %s\n",
1393+
hipo::statusString((hipo::Status)status).c_str());
14201394
return HighsStatus::kWarning;
14211395
}
14221396

1423-
// these are errors
1424-
else if (status == hipo::kStatusError) {
1425-
highsLogUser(options.log_options, HighsLogType::kError,
1426-
"Hipo: Internal error\n");
1427-
} else if (status == hipo::kStatusOverflow) {
1428-
highsLogUser(options.log_options, HighsLogType::kError,
1429-
"Hipo: Integer overflow\n");
1430-
} else if (status == hipo::kStatusErrorAnalyse) {
1431-
highsLogUser(options.log_options, HighsLogType::kError,
1432-
"Hipo: Error in analyse phase\n");
1433-
} else if (status == hipo::kStatusErrorFactorise) {
1434-
highsLogUser(options.log_options, HighsLogType::kError,
1435-
"Hipo: Error in factorise phase\n");
1436-
} else if (status == hipo::kStatusErrorSolve) {
1437-
highsLogUser(options.log_options, HighsLogType::kError,
1438-
"Hipo: Error in solve phase\n");
1439-
} else if (status == hipo::kStatusBadModel) {
1440-
highsLogUser(options.log_options, HighsLogType::kError,
1441-
"Hipo: Invalid model\n");
1442-
} else {
1443-
highsLogUser(options.log_options, HighsLogType::kError,
1444-
"Hipo: Unrecognized status\n");
1397+
else if (hipo.failed()) {
1398+
highsLogUser(options.log_options, HighsLogType::kError, "Hipo: %s\n",
1399+
hipo::statusString((hipo::Status)status).c_str());
14451400
}
14461401
return HighsStatus::kError;
14471402
}

highs/ipm/hipo/ipm/FactorHighsSolver.cpp

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ Int FactorHighsSolver::analyseAS(Symbolic& S) {
4040
// Perform analyse phase of augmented system and return symbolic factorisation
4141
// in object S and the status.
4242

43-
if (kkt_.rowsAS.empty() || kkt_.ptrAS.empty()) return kStatusErrorAnalyse;
43+
if (kkt_.rowsAS.empty() || kkt_.ptrAS.empty()) return kErrorAnalyse;
4444

4545
const Int m = model_.A().num_row_;
4646
const Int n = model_.A().num_col_;
4747

48-
// create vector of signs of pivots
4948
std::vector<Int> pivot_signs(n + m, -1);
5049
for (Int i = 0; i < m; ++i) pivot_signs[n + i] = 1;
5150

@@ -64,9 +63,8 @@ Int FactorHighsSolver::analyseNE(Symbolic& S) {
6463
// in object S and the status. Structure of the matrix must be already
6564
// computed.
6665

67-
if (kkt_.rowsNE.empty() || kkt_.ptrNE.empty()) return kStatusErrorAnalyse;
66+
if (kkt_.rowsNE.empty() || kkt_.ptrNE.empty()) return kErrorAnalyse;
6867

69-
// create vector of signs of pivots
7068
std::vector<Int> pivot_signs(model_.A().num_row_, 1);
7169

7270
logger_.printInfo("Performing NE analyse phase\n");
@@ -84,7 +82,6 @@ Int FactorHighsSolver::analyseNE(Symbolic& S) {
8482
// =========================================================================
8583

8684
Int FactorHighsSolver::factorAS(const std::vector<double>& scaling) {
87-
// only execute factorisation if it has not been done yet
8885
assert(!this->valid_);
8986

9087
kkt_.buildASvalues(scaling);
@@ -95,16 +92,15 @@ Int FactorHighsSolver::factorAS(const std::vector<double>& scaling) {
9592
Clock clock;
9693
if (FH_.factorise(kkt_.S, kkt_.n(), kkt_.nz(), kkt_.rowsAS.data(),
9794
kkt_.ptrAS.data(), kkt_.valAS.data()))
98-
return kStatusErrorFactorise;
95+
return kErrorFactorise;
9996
info_.factor_time += clock.stop();
10097
info_.factor_number++;
10198

10299
this->valid_ = true;
103-
return kStatusOk;
100+
return kOk;
104101
}
105102

106103
Int FactorHighsSolver::factorNE(const std::vector<double>& scaling) {
107-
// only execute factorisation if it has not been done yet
108104
assert(!this->valid_);
109105

110106
kkt_.buildNEvalues(scaling);
@@ -115,12 +111,12 @@ Int FactorHighsSolver::factorNE(const std::vector<double>& scaling) {
115111
Clock clock;
116112
if (FH_.factorise(kkt_.S, kkt_.n(), kkt_.nz(), kkt_.rowsNE.data(),
117113
kkt_.ptrNE.data(), kkt_.valNE.data()))
118-
return kStatusErrorFactorise;
114+
return kErrorFactorise;
119115
info_.factor_time += clock.stop();
120116
info_.factor_number++;
121117

122118
this->valid_ = true;
123-
return kStatusOk;
119+
return kOk;
124120
}
125121

126122
// =========================================================================
@@ -131,48 +127,43 @@ Int FactorHighsSolver::solveAS(const std::vector<double>& rhs_x,
131127
const std::vector<double>& rhs_y,
132128
std::vector<double>& lhs_x,
133129
std::vector<double>& lhs_y) {
134-
// only execute the solve if factorisation is valid
135130
assert(this->valid_);
136131

137132
Int n = rhs_x.size();
138133

139-
// create single rhs
140134
std::vector<double> rhs;
141135
rhs.insert(rhs.end(), rhs_x.begin(), rhs_x.end());
142136
rhs.insert(rhs.end(), rhs_y.begin(), rhs_y.end());
143137

144138
Clock clock;
145-
if (FH_.solve(rhs.data())) return kStatusErrorSolve;
139+
if (FH_.solve(rhs.data())) return kErrorSolve;
146140

147141
info_.solve_time += clock.stop();
148142
info_.solve_number++;
149143

150144
data_.back().num_solves++;
151145

152-
// split lhs
153146
lhs_x = std::vector<double>(rhs.begin(), rhs.begin() + n);
154147
lhs_y = std::vector<double>(rhs.begin() + n, rhs.end());
155148

156-
return kStatusOk;
149+
return kOk;
157150
}
158151

159152
Int FactorHighsSolver::solveNE(const std::vector<double>& rhs,
160153
std::vector<double>& lhs) {
161-
// only execute the solve if factorisation is valid
162154
assert(this->valid_);
163155

164-
// initialise lhs with rhs
165156
lhs = rhs;
166157

167158
Clock clock;
168-
if (FH_.solve(lhs.data())) return kStatusErrorSolve;
159+
if (FH_.solve(lhs.data())) return kErrorSolve;
169160

170161
info_.solve_time += clock.stop();
171162
info_.solve_number++;
172163

173164
data_.back().num_solves++;
174165

175-
return kStatusOk;
166+
return kOk;
176167
}
177168

178169
// =========================================================================
@@ -195,20 +186,17 @@ Int FactorHighsSolver::setup() {
195186

196187
kkt_.S.print(logger_, logger_.debug(1));
197188

198-
// Warn about large memory consumption
199189
if (kkt_.S.storage() > kLargeStorageGB * 1024 * 1024 * 1024) {
200190
logger_.printw("Large amount of memory required\n");
201191
}
202192

203193
logger_.print("\n");
204194
}
205195

206-
return kStatusOk;
196+
return kOk;
207197
}
208198

209199
Int FactorHighsSolver::chooseNla() {
210-
// Choose whether to use augmented system or normal equations.
211-
212200
Symbolic symb_NE{};
213201
Symbolic symb_AS{};
214202
bool failure_NE = false;
@@ -238,7 +226,7 @@ Int FactorHighsSolver::chooseNla() {
238226
Int status = kkt_.buildNEstructure();
239227
if (status) {
240228
failure_NE = true;
241-
if (status == kStatusOverflow) {
229+
if (status == kErrorOverflow) {
242230
logger_.printInfo("Integer overflow forming NE matrix\n");
243231
overflow_NE = true;
244232
}
@@ -261,7 +249,7 @@ Int FactorHighsSolver::chooseNla() {
261249
Int AS_status = kkt_.buildASstructure();
262250
if (!AS_status) AS_status = analyseAS(symb_AS);
263251
if (AS_status) failure_AS = true;
264-
if (AS_status == kStatusOverflow) {
252+
if (AS_status == kErrorOverflow) {
265253
logger_.printInfo("Integer overflow forming AS matrix\n");
266254
overflow_AS = true;
267255
}
@@ -301,11 +289,10 @@ Int FactorHighsSolver::chooseNla() {
301289
run_analyse_AS();
302290
}
303291

304-
Int status = kStatusOk;
292+
Int status = kOk;
305293

306294
std::stringstream log_stream;
307295

308-
// Decision may be forced by failures
309296
if (failure_NE && !failure_AS) {
310297
options_.nla = kHipoAugmentedString;
311298
log_stream << textline("Newton system:") << "AS preferred (NE failed)\n";
@@ -314,9 +301,9 @@ Int FactorHighsSolver::chooseNla() {
314301
log_stream << textline("Newton system:") << "NE preferred (AS failed)\n";
315302
} else if (failure_AS && failure_NE) {
316303
if (overflow_AS && overflow_NE)
317-
status = kStatusOverflow;
304+
status = kErrorOverflow;
318305
else
319-
status = kStatusErrorAnalyse;
306+
status = kErrorAnalyse;
320307

321308
logger_.printe("Both NE and AS failed analyse phase\n");
322309
} else {
@@ -325,7 +312,6 @@ Int FactorHighsSolver::chooseNla() {
325312
double ops_NE = symb_NE.flops() + symb_NE.spops() * kSpopsWeight;
326313
double ops_AS = symb_AS.flops() + symb_AS.spops() * kSpopsWeight;
327314

328-
// Average size of supernodes
329315
double sn_size_NE = (double)symb_NE.size() / symb_NE.sn();
330316
double sn_size_AS = (double)symb_AS.size() / symb_AS.sn();
331317

@@ -348,7 +334,7 @@ Int FactorHighsSolver::chooseNla() {
348334

349335
logger_.print(log_stream.str().c_str());
350336

351-
if (status == kStatusOk) {
337+
if (status == kOk) {
352338
if (options_.nla == kHipoAugmentedString) {
353339
kkt_.S = std::move(symb_AS);
354340
kkt_.freeNEmemory();
@@ -370,7 +356,6 @@ Int FactorHighsSolver::chooseOrdering(const std::vector<Int>& rows,
370356
// - If ordering is "amd", "metis", "rcm" run only the ordering requested.
371357
// - If ordering is "choose", run "amd", "metis", and choose the best.
372358

373-
// select which fill-reducing orderings should be tried
374359
std::vector<std::string> orderings_to_try;
375360
if (options_.ordering != kHighsChooseString)
376361
orderings_to_try.push_back(options_.ordering);
@@ -387,7 +372,7 @@ Int FactorHighsSolver::chooseOrdering(const std::vector<Int>& rows,
387372
if (nla == "NE") {
388373
if (ptr.back() >= kkt_.NE_nz_limit.load(std::memory_order_relaxed)) {
389374
logger_.printInfo("NE interrupted\n");
390-
return kStatusErrorAnalyse;
375+
return kErrorAnalyse;
391376
}
392377
}
393378

@@ -516,7 +501,7 @@ Int FactorHighsSolver::chooseOrdering(const std::vector<Int>& rows,
516501
ordering = orderings_to_try[chosen];
517502
}
518503

519-
return num_success > 0 ? kStatusOk : kStatusErrorAnalyse;
504+
return num_success > 0 ? kOk : kErrorAnalyse;
520505
}
521506

522507
Int FactorHighsSolver::setNla() {
@@ -530,24 +515,24 @@ Int FactorHighsSolver::setNla() {
530515
if (options_.nla == kHipoAugmentedString) {
531516
Int status = kkt_.buildASstructure();
532517
if (!status) status = analyseAS(kkt_.S);
533-
if (status == kStatusOverflow) {
518+
if (status == kErrorOverflow) {
534519
logger_.printe("AS requested, integer overflow\n");
535-
return kStatusOverflow;
520+
return kErrorOverflow;
536521
} else if (status) {
537522
logger_.printe("AS requested, failed analyse phase\n");
538-
return kStatusErrorAnalyse;
523+
return kErrorAnalyse;
539524
}
540525
log_stream << textline("Newton system:") << "AS requested\n";
541526

542527
} else if (options_.nla == kHipoNormalEqString) {
543528
Int status = kkt_.buildNEstructure();
544529
if (!status) status = analyseNE(kkt_.S);
545-
if (status == kStatusOverflow) {
530+
if (status == kErrorOverflow) {
546531
logger_.printe("NE requested, integer overflow\n");
547-
return kStatusOverflow;
532+
return kErrorOverflow;
548533
} else if (status) {
549534
logger_.printe("NE requested, failed analyse phase\n");
550-
return kStatusErrorAnalyse;
535+
return kErrorAnalyse;
551536
}
552537
log_stream << textline("Newton system:") << "NE requested\n";
553538

@@ -564,15 +549,14 @@ Int FactorHighsSolver::setNla() {
564549
<< '\n';
565550
logger_.print(log_stream.str().c_str());
566551

567-
return kStatusOk;
552+
return kOk;
568553
}
569554

570555
static bool usingAppleBlas() {
571556
return strstr(HighsExtras::blas::getInfo()->provider, "Apple") != nullptr;
572557
}
573558

574559
void FactorHighsSolver::setParallel() {
575-
// Set parallel options
576560
bool parallel_tree = false;
577561
bool parallel_node = false;
578562

highs/ipm/hipo/ipm/FactorHighsSolver.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
namespace hipo {
1616

1717
class FactorHighsSolver : public LinearSolver {
18-
// object to perform factorisation
1918
FHsolver FH_;
2019

2120
KktMatrix& kkt_;
@@ -44,7 +43,6 @@ class FactorHighsSolver : public LinearSolver {
4443
const Regularisation& regul, Info& info, IpmData& record,
4544
const Logger& logger);
4645

47-
// Override functions
4846
Int factorAS(const std::vector<double>& scaling) override;
4947
Int factorNE(const std::vector<double>& scaling) override;
5048
Int solveNE(const std::vector<double>& rhs,

highs/ipm/hipo/ipm/Info.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ struct Info {
1616
Int m_original, n_original;
1717

1818
// Status of solver, see IpmStatus.h
19-
Status status = kStatusNotRun;
19+
Status status = kStatusNotSet;
20+
Int error = kOk;
2021

2122
// residuals and objectives of final solution
2223
double p_res_rel, p_res_abs, d_res_rel, d_res_abs, p_obj, d_obj, pd_gap;

0 commit comments

Comments
 (0)