Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 1990 #1995

Merged
merged 6 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading