Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jajhall committed Oct 24, 2024
1 parent cceea9a commit 1d17f81
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/Highs.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,12 @@ class Highs {
* Methods for model output
*/

/**
* @brief Identify and the standard form of the HighsLp instance in
* HiGHS
*/
HighsStatus getStandardFormLp(HighsLp& standard_form_lp);

/**
* @brief Return a const reference to the presolved HighsLp instance in HiGHS
*/
Expand Down Expand Up @@ -1378,6 +1384,10 @@ class Highs {
HighsPresolveStatus::kNotPresolved;
HighsModelStatus model_status_ = HighsModelStatus::kNotset;

std::vector<double> standard_form_cost_;
std::vector<double> standard_form_rhs_;
HighsSparseMatrix standard_form_matrix_;

HEkk ekk_instance_;

HighsPresolveLog presolve_log_;
Expand Down Expand Up @@ -1429,7 +1439,10 @@ class Highs {
//
// Clears the presolved model and its status
void clearPresolve();
//
//
// Clears the standard form LP
void clearStandardFormLp();
//
// Methods to clear solver data for users in Highs class members
// before (possibly) updating them with data from trying to solve
// the incumbent model.
Expand Down Expand Up @@ -1473,6 +1486,7 @@ class Highs {
void underDevelopmentLogMessage(const std::string& method_name);

// Interface methods
HighsStatus formStandardFormLp();
HighsStatus basisForSolution();
HighsStatus addColsInterface(
HighsInt ext_num_new_col, const double* ext_col_cost,
Expand Down
34 changes: 34 additions & 0 deletions src/lp_data/Highs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ HighsStatus Highs::clearModel() {
HighsStatus Highs::clearSolver() {
HighsStatus return_status = HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
invalidateUserSolverData();
return returnFromHighs(return_status);
}
Expand Down Expand Up @@ -1637,6 +1638,13 @@ HighsStatus Highs::run() {
return returnFromRun(return_status, undo_mods);
}

HighsStatus Highs::getStandardFormLp(HighsLp& standard_form_lp) {
HighsStatus status = formStandardFormLp();
if (status != HighsStatus::kOk) return status;
standard_form_lp = this->standard_form_lp_;
return HighsStatus::kOk;
}

HighsStatus Highs::getDualRay(bool& has_dual_ray, double* dual_ray_value) {
// Can't get a ray without an INVERT, but absence is only an error
// when solving an LP #1350
Expand Down Expand Up @@ -2338,6 +2346,7 @@ HighsStatus Highs::addCols(const HighsInt num_new_col, const double* costs,
this->logHeader();
HighsStatus return_status = HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
return_status = interpretCallStatus(
options_.log_options,
addColsInterface(num_new_col, costs, lower_bounds, upper_bounds,
Expand Down Expand Up @@ -2376,6 +2385,7 @@ HighsStatus Highs::addRows(const HighsInt num_new_row,
this->logHeader();
HighsStatus return_status = HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
return_status = interpretCallStatus(
options_.log_options,
addRowsInterface(num_new_row, lower_bounds, upper_bounds, num_new_nz,
Expand All @@ -2391,6 +2401,7 @@ HighsStatus Highs::changeObjectiveSense(const ObjSense sense) {
model_.lp_.sense_ = sense;
// Nontrivial change
clearPresolve();
clearStandardFormLp();
invalidateModelStatusSolutionAndInfo();
}
return returnFromHighs(HighsStatus::kOk);
Expand Down Expand Up @@ -2520,6 +2531,7 @@ HighsStatus Highs::changeColCost(const HighsInt col, const double cost) {
HighsStatus Highs::changeColsCost(const HighsInt from_col,
const HighsInt to_col, const double* cost) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, from_col, to_col, model_.lp_.num_col_);
Expand All @@ -2546,6 +2558,7 @@ HighsStatus Highs::changeColsCost(const HighsInt num_set_entries,
if (doubleUserDataNotNull(options_.log_options, cost, "column costs"))
return HighsStatus::kError;
clearPresolve();
clearStandardFormLp();
// Ensure that the set and data are in ascending order
std::vector<double> local_cost{cost, cost + num_set_entries};
std::vector<HighsInt> local_set{set, set + num_set_entries};
Expand All @@ -2569,6 +2582,7 @@ HighsStatus Highs::changeColsCost(const HighsInt num_set_entries,

HighsStatus Highs::changeColsCost(const HighsInt* mask, const double* cost) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const bool create_error = create(index_collection, mask, model_.lp_.num_col_);
assert(!create_error);
Expand All @@ -2590,6 +2604,7 @@ HighsStatus Highs::changeColsBounds(const HighsInt from_col,
const HighsInt to_col, const double* lower,
const double* upper) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, from_col, to_col, model_.lp_.num_col_);
Expand Down Expand Up @@ -2624,6 +2639,7 @@ HighsStatus Highs::changeColsBounds(const HighsInt num_set_entries,
null_data;
if (null_data) return HighsStatus::kError;
clearPresolve();
clearStandardFormLp();
// Ensure that the set and data are in ascending order
std::vector<double> local_lower{lower, lower + num_set_entries};
std::vector<double> local_upper{upper, upper + num_set_entries};
Expand All @@ -2649,6 +2665,7 @@ HighsStatus Highs::changeColsBounds(const HighsInt num_set_entries,
HighsStatus Highs::changeColsBounds(const HighsInt* mask, const double* lower,
const double* upper) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const bool create_error = create(index_collection, mask, model_.lp_.num_col_);
assert(!create_error);
Expand All @@ -2671,6 +2688,7 @@ HighsStatus Highs::changeRowsBounds(const HighsInt from_row,
const HighsInt to_row, const double* lower,
const double* upper) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, from_row, to_row, model_.lp_.num_row_);
Expand Down Expand Up @@ -2705,6 +2723,7 @@ HighsStatus Highs::changeRowsBounds(const HighsInt num_set_entries,
null_data;
if (null_data) return HighsStatus::kError;
clearPresolve();
clearStandardFormLp();
// Ensure that the set and data are in ascending order
std::vector<double> local_lower{lower, lower + num_set_entries};
std::vector<double> local_upper{upper, upper + num_set_entries};
Expand All @@ -2730,6 +2749,7 @@ HighsStatus Highs::changeRowsBounds(const HighsInt num_set_entries,
HighsStatus Highs::changeRowsBounds(const HighsInt* mask, const double* lower,
const double* upper) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const bool create_error = create(index_collection, mask, model_.lp_.num_row_);
assert(!create_error);
Expand Down Expand Up @@ -3028,6 +3048,7 @@ HighsStatus Highs::getCoeff(const HighsInt row, const HighsInt col,

HighsStatus Highs::deleteCols(const HighsInt from_col, const HighsInt to_col) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, from_col, to_col, model_.lp_.num_col_);
Expand All @@ -3046,6 +3067,7 @@ HighsStatus Highs::deleteCols(const HighsInt num_set_entries,
const HighsInt* set) {
if (num_set_entries == 0) return HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, num_set_entries, set, model_.lp_.num_col_);
Expand All @@ -3059,6 +3081,7 @@ HighsStatus Highs::deleteCols(const HighsInt num_set_entries,

HighsStatus Highs::deleteCols(HighsInt* mask) {
clearPresolve();
clearStandardFormLp();
const HighsInt original_num_col = model_.lp_.num_col_;
HighsIndexCollection index_collection;
const bool create_error = create(index_collection, mask, original_num_col);
Expand All @@ -3072,6 +3095,7 @@ HighsStatus Highs::deleteCols(HighsInt* mask) {

HighsStatus Highs::deleteRows(const HighsInt from_row, const HighsInt to_row) {
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, from_row, to_row, model_.lp_.num_row_);
Expand All @@ -3090,6 +3114,7 @@ HighsStatus Highs::deleteRows(const HighsInt num_set_entries,
const HighsInt* set) {
if (num_set_entries == 0) return HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
HighsIndexCollection index_collection;
const HighsInt create_error =
create(index_collection, num_set_entries, set, model_.lp_.num_row_);
Expand All @@ -3103,6 +3128,7 @@ HighsStatus Highs::deleteRows(const HighsInt num_set_entries,

HighsStatus Highs::deleteRows(HighsInt* mask) {
clearPresolve();
clearStandardFormLp();
const HighsInt original_num_row = model_.lp_.num_row_;
HighsIndexCollection index_collection;
const bool create_error = create(index_collection, mask, original_num_row);
Expand All @@ -3117,6 +3143,7 @@ HighsStatus Highs::deleteRows(HighsInt* mask) {
HighsStatus Highs::scaleCol(const HighsInt col, const double scale_value) {
HighsStatus return_status = HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
HighsStatus call_status = scaleColInterface(col, scale_value);
return_status = interpretCallStatus(options_.log_options, call_status,
return_status, "scaleCol");
Expand All @@ -3127,6 +3154,7 @@ HighsStatus Highs::scaleCol(const HighsInt col, const double scale_value) {
HighsStatus Highs::scaleRow(const HighsInt row, const double scale_value) {
HighsStatus return_status = HighsStatus::kOk;
clearPresolve();
clearStandardFormLp();
HighsStatus call_status = scaleRowInterface(row, scale_value);
return_status = interpretCallStatus(options_.log_options, call_status,
return_status, "scaleRow");
Expand Down Expand Up @@ -3422,6 +3450,12 @@ void Highs::clearPresolve() {
presolve_.clear();
}

void Highs::clearStandardFormLp() {
standard_form_cost_.clear();
standard_form_rhs_.clear();
standard_form_matrix_.clear();
}

void Highs::invalidateUserSolverData() {
invalidateModelStatus();
invalidateSolution();
Expand Down
66 changes: 66 additions & 0 deletions src/lp_data/HighsInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,72 @@
#include "util/HighsMatrixUtils.h"
#include "util/HighsSort.h"

HighsStatus Highs::formStandardFormLp() {
this->clearStandardFormLp();
HighsLp& lp = this->model_.lp_;
// Check for free variables
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
if (lp.col_lower_[iCol] <= -kHighsInf &&
lp.col_upper_[iCol] >= kHighsInf) {
// Free col
highsLogUser(options_.log_options, HighsLogType::kError,
"Cannot generate standard form LP for problems with free variables\n");
return HighsStatus::kError;
}
}
HighsSparseMatrix& matrix = lp.a_matrix_;
// Ensure that the incumbent LP is rowwise
matrix.ensureRowwise();
HighsSparseMatrix local_row;
std::vector<HighsInt>& index = local_row.index_;
std::vector<double> value = local_row.value_;
local_row.num_row_ = 1;
local_row.num_col_ = lp.num_col_;
index.resize(lp.num_col_);
value.resize(lp.num_col_);
local_row.start_.resize(2);
HighsInt& num_nz = local_row.start_[1];
local_row.start_[0] = 0;
HighsInt num_free_row = 0;
std::vector<HighsInt>slack_ix;
HighsInt slack_k = 1;
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
if (lp.row_lower_[iRow] <= -kHighsInf &&
lp.row_upper_[iRow] >= kHighsInf) {
assert(0 == 1);
// Free row
num_free_row++;
continue;
}
if (lp.row_lower_[iRow] == lp.row_upper_[iRow]) {
assert(0 == 2);
// Equality
matrix.getRow(iRow, num_nz, index.data(), value.data());
this->standard_form_matrix_.addRows(local_row);
this->standard_form_rhs_.push_back(lp.row_upper_[iRow]);
continue;
} else if (lp.row_lower_[iRow] <= -kHighsInf) {
assert(0 == 3);
// Upper bounded, so record the slack
assert(lp.row_upper_[iRow] < kHighsInf);
slack_ix.push_back(HighsInt(standard_form_rhs_.size()));
matrix.getRow(iRow, num_nz, index.data(), value.data());
this->standard_form_matrix_.addRows(local_row);
this->standard_form_rhs_.push_back(lp.row_upper_[iRow]);
} else if (lp.row_upper_[iRow] >= kHighsInf) {
assert(0 == 4);
// Lower bounded, so record the slack
assert(lp.row_lower_[iRow] > -kHighsInf);
slack_ix.push_back(HighsInt(standard_form_rhs_.size()));
matrix.getRow(iRow, num_nz, index.data(), value.data());
this->standard_form_matrix_.addRows(local_row);
this->standard_form_rhs_.push_back(lp.row_upper_[iRow]);

}

return HighsStatus::kError;
}

HighsStatus Highs::basisForSolution() {
HighsLp& lp = model_.lp_;
assert(!lp.isMip() || options_.solve_relaxation);
Expand Down

0 comments on commit 1d17f81

Please sign in to comment.