Skip to content

Commit

Permalink
Merge pull request #1995 from ERGO-Code/fix-1990
Browse files Browse the repository at this point in the history
Fix 1990
  • Loading branch information
jajhall authored Oct 24, 2024
2 parents 320480c + abf2c68 commit cceea9a
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 18 deletions.
15 changes: 13 additions & 2 deletions check/TestQpSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,20 @@ TEST_CASE("test-qp-hot-start", "[qpsolver]") {
highs.setSolution(solution);
basis.alien = true;
highs.setBasis(basis);
return_status = highs.run();
REQUIRE(return_status == HighsStatus::kOk);
REQUIRE(highs.run() == HighsStatus::kOk);
REQUIRE(info.qp_iteration_count == 0);
if (k == 0) {
// Modify the constraint so that the solution and basis are not
// feasible and one iteration is needed
REQUIRE(highs.changeCoeff(0, 1, 2.0) == HighsStatus::kOk);
REQUIRE(highs.changeRowBounds(0, 4.0, kHighsInf) == HighsStatus::kOk);
highs.clearSolver();
basis.alien = false;
highs.setBasis(basis);
highs.setSolution(solution);
return_status = highs.run();
REQUIRE(info.qp_iteration_count == 1);
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/qpsolver/a_quass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ static QpAsmStatus quass2highs(Instance& instance, Settings& settings,
highs_model_status = HighsModelStatus::kTimeLimit;
qp_asm_return_status = QpAsmStatus::kWarning;
break;
case QpModelStatus::kInterrupt:
highs_model_status = HighsModelStatus::kInterrupt;
qp_asm_return_status = QpAsmStatus::kWarning;
break;
case QpModelStatus::kUndetermined:
highs_model_status = HighsModelStatus::kSolveError;
qp_asm_return_status = QpAsmStatus::kError;
Expand Down Expand Up @@ -159,7 +163,7 @@ QpAsmStatus solveqp(Instance& instance, Settings& settings, Statistics& stats,
computeStartingPointHighs(instance, settings, stats, qp_model_status,
startinfo, highs_model_status, highs_basis,
highs_solution, qp_timer);
if (qp_model_status == QpModelStatus::kInfeasible) {
if (qp_model_status != QpModelStatus::kNotset) {
return quass2highs(instance, settings, stats, qp_model_status,
qp_solution, highs_model_status, highs_basis,
highs_solution);
Expand Down
2 changes: 1 addition & 1 deletion src/qpsolver/devexharrispricing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class DevexHarrisPricing : public Pricing {
: runtime(rt),
basis(bas),
redcosts(rc),
weights(std::vector<double>(rt.instance.num_var, 1.0)) {};
weights(std::vector<double>(rt.instance.num_var, 1.0)){};

HighsInt price(const QpVector& x, const QpVector& gradient) {
HighsInt minidx = chooseconstrainttodrop(redcosts.getReducedCosts());
Expand Down
48 changes: 34 additions & 14 deletions src/qpsolver/feasibility_highs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,17 @@ static void computeStartingPointHighs(
if (have_starting_point) {
use_basis = highs_basis;
use_solution = highs_solution;
// Have to assume that the supplied basis is feasible
modelstatus = QpModelStatus::kNotset;
} else {
Highs highs;

// set HiGHS to be silent
highs.setOptionValue("output_flag", false);

highs.setOptionValue("presolve", "on");

// Set the residual time limit
const double use_time_limit =
settings.time_limit < kHighsInf
? settings.time_limit - timer.readRunHighsClock()
: kHighsInf;

std::max(settings.time_limit - timer.readRunHighsClock(), 0.001);
highs.setOptionValue("time_limit", use_time_limit);

HighsLp lp;
Expand Down Expand Up @@ -118,19 +116,37 @@ static void computeStartingPointHighs(
}

HighsStatus status = highs.run();
if (status != HighsStatus::kOk) {
if (status == HighsStatus::kError) {
modelstatus = QpModelStatus::kError;
return;
}

stats.phase1_iterations = highs.getInfo().simplex_iteration_count;

HighsModelStatus phase1stat = highs.getModelStatus();
if (phase1stat == HighsModelStatus::kInfeasible) {
modelstatus = QpModelStatus::kInfeasible;
return;
switch (phase1stat) {
case HighsModelStatus::kOptimal:
modelstatus = QpModelStatus::kNotset;
break;
case HighsModelStatus::kInfeasible:
modelstatus = QpModelStatus::kInfeasible;
break;
case HighsModelStatus::kTimeLimit:
modelstatus = QpModelStatus::kTimeLimit;
break;
case HighsModelStatus::kInterrupt:
modelstatus = QpModelStatus::kInterrupt;
break;
default:
modelstatus = QpModelStatus::kError;
}

stats.phase1_iterations = highs.getInfo().simplex_iteration_count;

if (modelstatus != QpModelStatus::kNotset) return;

// Should only get here if feasibility problem is solved to
// optimality - hence there is a feasible basis
assert(phase1stat == HighsModelStatus::kOptimal);

use_basis = highs.getBasis();
use_solution = highs.getSolution();
}
Expand Down Expand Up @@ -245,8 +261,12 @@ static void computeStartingPointHighs(
printf(")\n");
}

assert((HighsInt)(initial_active.size() + initial_inactive.size()) ==
instance.num_var);
// This used to be an assert
if ((HighsInt)(initial_active.size() + initial_inactive.size()) !=
instance.num_var) {
modelstatus = QpModelStatus::kError;
return;
}

if (!have_starting_point) {
// When starting from a feasible basis, there will generally be
Expand Down
1 change: 1 addition & 0 deletions src/qpsolver/qpconst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum class QpModelStatus {
kIterationLimit,
kTimeLimit,
kLargeNullspace,
kInterrupt,
kError
};

Expand Down

0 comments on commit cceea9a

Please sign in to comment.