Skip to content

Commit

Permalink
Added testing with set and mask; formatted
Browse files Browse the repository at this point in the history
  • Loading branch information
jajhall committed Jan 13, 2025
1 parent 4238871 commit 4079794
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 83 deletions.
223 changes: 181 additions & 42 deletions check/TestLpModification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2273,7 +2273,6 @@ TEST_CASE("row-wise-get-row-avgas", "[highs_data]") {
h.ensureColwise();
testAvgasGetRow(h);
testAvgasGetCol(h);

}

TEST_CASE("hot-start-after-delete", "[highs_data]") {
Expand All @@ -2285,54 +2284,194 @@ TEST_CASE("hot-start-after-delete", "[highs_data]") {
const HighsSolution& solution = h.getSolution();
std::string model = "avgas";
std::string model_file =
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
h.readModel(model_file);
h.run();
printf("Initial solve takes %d iterations and yields objective = %g\n",
int(info.simplex_iteration_count), info.objective_function_value);
h.writeSolution("", 1);
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
printf("Col %2d is %s\n", int(iCol), basis.col_status[iCol] == HighsBasisStatus::kBasic ? "basic" : "nonbasic");
printf("\n");
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
printf("Row %2d is %s\n", int(iRow), basis.row_status[iRow] == HighsBasisStatus::kBasic ? "basic" : "nonbasic");
HighsInt ieration_count0 = info.simplex_iteration_count;
if (dev_run)
printf("Initial solve takes %d iterations and yields objective = %g\n",
int(info.simplex_iteration_count), info.objective_function_value);

double cost;
double lower;
double upper;
HighsInt max_dim = std::max(lp.num_col_, lp.num_row_);
std::vector<double> cost(1);
std::vector<double> lower(1);
std::vector<double> upper(1);
HighsInt nnz;
std::vector<HighsInt> start(1);
std::vector<HighsInt> index(lp.num_row_);
std::vector<double> value(lp.num_row_);
std::vector<HighsInt> index(max_dim);
std::vector<double> value(max_dim);
HighsInt get_num;
HighsInt use_col, use_row;
for (HighsInt k = 0; k < 2; k++) {
if (dev_run) {
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
printf("Col %2d is %s\n", int(iCol),
basis.col_status[iCol] == HighsBasisStatus::kBasic ? "basic"
: "nonbasic");
printf("\n");
}
if (k == 0) {
use_col = 1; // Nonbasic
} else {
use_col = 4; // Basic
}
if (dev_run)
printf(
"\nDeleting and adding column %1d with status \"%s\" and value %g\n",
int(use_col),
h.basisStatusToString(basis.col_status[use_col]).c_str(),
solution.col_value[use_col]);

h.getCols(use_col, use_col, get_num, cost.data(), lower.data(),
upper.data(), nnz, start.data(), index.data(), value.data());

h.deleteCols(use_col, use_col);
if (dev_run) basis.printScalars();

h.addCol(cost[0], lower[0], upper[0], nnz, index.data(), value.data());

h.run();
if (dev_run)
printf(
"After deleting and adding column %1d, solve takes %d iterations and "
"yields objective = %g\n",
int(use_col), int(info.simplex_iteration_count),
info.objective_function_value);
REQUIRE(info.simplex_iteration_count < ieration_count0);
}

for (HighsInt k = 0; k < 2; k++) {
if (dev_run) {
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
printf("Row %2d is %s\n", int(iRow),
basis.row_status[iRow] == HighsBasisStatus::kBasic ? "basic"
: "nonbasic");
}
if (k == 0) {
use_row = 1; // Nonbasic
} else {
use_row = 8; // Basic
}
if (dev_run)
printf("\nDeleting and adding row %1d with status \"%s\" and value %g\n",
int(use_row),
h.basisStatusToString(basis.row_status[use_row]).c_str(),
solution.row_value[use_row]);

h.getRows(use_row, use_row, get_num, lower.data(), upper.data(), nnz,
start.data(), index.data(), value.data());

h.deleteRows(use_row, use_row);
if (dev_run) basis.printScalars();

h.addRow(lower[0], upper[0], nnz, index.data(), value.data());

h.run();
if (dev_run)
printf(
"After deleting and adding row %1d, solve takes %d iterations and "
"yields objective = %g\n",
int(use_row), int(info.simplex_iteration_count),
info.objective_function_value);
REQUIRE(info.simplex_iteration_count < ieration_count0);
}
std::vector<HighsInt> set = {1, 3, 4};
HighsInt num_set_en = set.size();
cost.resize(num_set_en);
lower.resize(num_set_en);
upper.resize(num_set_en);
start.resize(num_set_en);
index.resize(num_set_en * max_dim);
value.resize(num_set_en * max_dim);

h.getCols(num_set_en, set.data(), get_num, cost.data(), lower.data(),
upper.data(), nnz, start.data(), index.data(), value.data());

h.deleteCols(num_set_en, set.data());
if (dev_run) basis.printScalars();

h.addCols(get_num, cost.data(), lower.data(), upper.data(), nnz, start.data(),
index.data(), value.data());

h.run();
if (dev_run)
printf(
"After deleting and adding %d columns in set, solve takes %d "
"iterations and yields objective = %g\n",
int(get_num), int(info.simplex_iteration_count),
info.objective_function_value);
// REQUIRE(info.simplex_iteration_count < ieration_count0);

h.getRows(num_set_en, set.data(), get_num, lower.data(), upper.data(), nnz,
start.data(), index.data(), value.data());

h.deleteRows(num_set_en, set.data());
if (dev_run) basis.printScalars();

h.addRows(get_num, lower.data(), upper.data(), nnz, start.data(),
index.data(), value.data());

h.run();
if (dev_run)
printf(
"After deleting and adding %d rows in set, solve takes %d iterations "
"and yields objective = %g\n",
int(get_num), int(info.simplex_iteration_count),
info.objective_function_value);
// REQUIRE(info.simplex_iteration_count < ieration_count0);
std::vector<HighsInt> mask;
mask.assign(max_dim, 0);
mask[1] = 1;
mask[4] = 1;
mask[5] = 1;

h.getCols(mask.data(), get_num, cost.data(), lower.data(), upper.data(), nnz,
start.data(), index.data(), value.data());

h.deleteCols(mask.data());
if (dev_run) basis.printScalars();

h.addCols(get_num, cost.data(), lower.data(), upper.data(), nnz, start.data(),
index.data(), value.data());

HighsInt use_col = 1;
printf("\nDeleting and adding column %1d with status \"%s\" and value %g\n",
int(use_col), h.basisStatusToString(basis.col_status[use_col]).c_str(), solution.col_value[use_col]);

h.getCols(use_col, use_col, get_num, &cost, &lower, &upper, nnz, start.data(), index.data(), value.data());

h.deleteCols(use_col, use_col);
basis.printScalars();

h.addCol(cost, lower, upper, nnz, index.data(), value.data());

h.run();
printf("After deleting and adding column %1d, solve takes %d iterations and yields objective = %g\n",
int(use_col), int(info.simplex_iteration_count), info.objective_function_value);

HighsInt use_row = 1;
printf("\nDeleting and adding row %1d with status \"%s\" and value %g\n",
int(use_row), h.basisStatusToString(basis.row_status[use_row]).c_str(), solution.row_value[use_row]);

h.getRows(use_row, use_row, get_num, &lower, &upper, nnz, start.data(), index.data(), value.data());

h.deleteRows(use_row, use_row);
basis.printScalars();

h.addRow(lower, upper, nnz, index.data(), value.data());

if (dev_run)
printf(
"After deleting and adding %d columns in mask, solve takes %d "
"iterations and yields objective = %g\n",
int(get_num), int(info.simplex_iteration_count),
info.objective_function_value);
// REQUIRE(info.simplex_iteration_count < ieration_count0);

mask.assign(max_dim, 0);
mask[1] = 1;
mask[4] = 1;
mask[5] = 1;
mask[8] = 1;
mask[9] = 1;
HighsInt num_mask_en = mask.size();
cost.resize(num_mask_en);
lower.resize(num_mask_en);
upper.resize(num_mask_en);
start.resize(num_mask_en);
index.resize(num_mask_en * max_dim);
value.resize(num_mask_en * max_dim);

h.getRows(mask.data(), get_num, lower.data(), upper.data(), nnz, start.data(),
index.data(), value.data());

h.deleteRows(mask.data());
if (dev_run) basis.printScalars();

h.addRows(get_num, lower.data(), upper.data(), nnz, start.data(),
index.data(), value.data());

h.run();
printf("After deleting and adding row %1d, solve takes %d iterations and yields objective = %g\n",
int(use_row), int(info.simplex_iteration_count), info.objective_function_value);
if (dev_run)
printf(
"After deleting and adding %d rows in mask, solve takes %d iterations "
"and yields objective = %g\n",
int(get_num), int(info.simplex_iteration_count),
info.objective_function_value);
// REQUIRE(info.simplex_iteration_count < ieration_count0);
}
9 changes: 5 additions & 4 deletions src/lp_data/Highs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1268,13 +1268,14 @@ HighsStatus Highs::solve() {
options_.solver == kHighsChooseString;
const bool has_basis = basis_.useful;
if (has_basis) {
assert(basis_.col_status.size() == static_cast<size_t>(incumbent_lp.num_col_));
assert(basis_.row_status.size() == static_cast<size_t>(incumbent_lp.num_row_));
assert(basis_.col_status.size() ==
static_cast<size_t>(incumbent_lp.num_col_));
assert(basis_.row_status.size() ==
static_cast<size_t>(incumbent_lp.num_row_));
}
if (basis_.valid) assert(basis_.useful);

if ((has_basis || options_.presolve == kHighsOffString ||
unconstrained_lp) &&
if ((has_basis || options_.presolve == kHighsOffString || unconstrained_lp) &&
solver_will_use_basis) {
// There is a valid basis for the problem, presolve is off, or LP
// has no constraint matrix, and the solver will use the basis
Expand Down
52 changes: 23 additions & 29 deletions src/lp_data/HighsInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
HighsBasis& basis = basis_;
HighsScale& scale = lp.scale_;
bool& useful_basis = basis.useful;

bool& lp_has_scaling = lp.scale_.has_scaling;

// Check that if nonzeros are to be added then the model has a positive number
Expand Down Expand Up @@ -578,10 +578,9 @@ HighsStatus Highs::addRowsInterface(HighsInt ext_num_new_row,
}

void deleteBasisEntries(std::vector<HighsBasisStatus>& status,
bool& deleted_basic,
bool& deleted_nonbasic,
const HighsIndexCollection& index_collection,
const HighsInt entry_dim) {
bool& deleted_basic, bool& deleted_nonbasic,
const HighsIndexCollection& index_collection,
const HighsInt entry_dim) {
assert(ok(index_collection));
assert(static_cast<size_t>(entry_dim) == status.size());
HighsInt from_k;
Expand All @@ -603,11 +602,12 @@ void deleteBasisEntries(std::vector<HighsBasisStatus>& status,
// Account for the initial entries being kept
if (k == from_k) new_num_entry = delete_from_entry;
// Identify whether a basic or a nonbasic entry has been deleted
for (HighsInt entry = delete_from_entry; entry <= delete_to_entry; entry++) {
for (HighsInt entry = delete_from_entry; entry <= delete_to_entry;
entry++) {
if (status[entry] == HighsBasisStatus::kBasic) {
deleted_basic = true;
deleted_basic = true;
} else {
deleted_nonbasic = true;
deleted_nonbasic = true;
}
}
if (delete_to_entry >= entry_dim - 1) break;
Expand All @@ -620,30 +620,24 @@ void deleteBasisEntries(std::vector<HighsBasisStatus>& status,
status.resize(new_num_entry);
}

void deleteBasisCols(HighsBasis& basis,
const HighsIndexCollection& index_collection,
const HighsInt original_num_col) {
void deleteBasisCols(HighsBasis& basis,
const HighsIndexCollection& index_collection,
const HighsInt original_num_col) {
bool deleted_basic;
bool deleted_nonbasic;
deleteBasisEntries(basis.col_status,
deleted_basic,
deleted_nonbasic,
index_collection, original_num_col);
if (deleted_basic)
basis.valid = false;
deleteBasisEntries(basis.col_status, deleted_basic, deleted_nonbasic,
index_collection, original_num_col);
if (deleted_basic) basis.valid = false;
}

void deleteBasisRows(HighsBasis& basis,
const HighsIndexCollection& index_collection,
const HighsInt original_num_row) {
void deleteBasisRows(HighsBasis& basis,
const HighsIndexCollection& index_collection,
const HighsInt original_num_row) {
bool deleted_basic;
bool deleted_nonbasic;
deleteBasisEntries(basis.row_status,
deleted_basic,
deleted_nonbasic,
index_collection, original_num_row);
if (deleted_nonbasic)
basis.valid = false;
deleteBasisEntries(basis.row_status, deleted_basic, deleted_nonbasic,
index_collection, original_num_row);
if (deleted_nonbasic) basis.valid = false;
}

void Highs::deleteColsInterface(HighsIndexCollection& index_collection) {
Expand Down Expand Up @@ -674,7 +668,7 @@ void Highs::deleteColsInterface(HighsIndexCollection& index_collection) {
} else {
assert(!basis.valid);
}

if (lp.scale_.has_scaling) {
deleteScale(lp.scale_.col, index_collection);
lp.scale_.col.resize(lp.num_col_);
Expand Down Expand Up @@ -2044,13 +2038,13 @@ HighsStatus Highs::elasticityFilterReturn(

run_status = this->deleteCols(original_num_col, lp.num_col_ - 1);
assert(run_status == HighsStatus::kOk);
//
//
// Now that deleteRows and deleteCols may yield a valid basis, the
// lack of dual values triggers an assert in
// getKktFailures. Ultimately (#2081) the dual values will be
// available but, for now, make the basis invalid.
basis_.valid = false;

run_status =
this->changeColsCost(0, original_num_col - 1, original_col_cost.data());
assert(run_status == HighsStatus::kOk);
Expand Down
9 changes: 5 additions & 4 deletions src/lp_data/HighsSolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1357,8 +1357,7 @@ HighsStatus formSimplexLpBasisAndFactor(HighsLpSolverObject& solver_object,
// If new scaling is performed, the hot start information is
// no longer valid
if (new_scaling) ekk_instance.clearHotStart();
const bool check_basis = basis.alien ||
(!basis.valid && basis.useful);
const bool check_basis = basis.alien || (!basis.valid && basis.useful);
if (check_basis) {
// The basis needs to be checked for rank deficiency, and possibly
// completed if it is rectangular
Expand Down Expand Up @@ -1616,9 +1615,11 @@ void HighsBasis::print(std::string message) const {
if (!this->useful) return;
this->printScalars(message);
for (HighsInt iCol = 0; iCol < HighsInt(this->col_status.size()); iCol++)
printf("Basis: col_status[%2d] = %d\n", int(iCol), int(this->col_status[iCol]));
printf("Basis: col_status[%2d] = %d\n", int(iCol),
int(this->col_status[iCol]));
for (HighsInt iRow = 0; iRow < HighsInt(this->row_status.size()); iRow++)
printf("Basis: row_status[%2d] = %d\n", int(iRow), int(this->row_status[iRow]));
printf("Basis: row_status[%2d] = %d\n", int(iRow),
int(this->row_status[iRow]));
}

void HighsBasis::printScalars(std::string message) const {
Expand Down
Loading

0 comments on commit 4079794

Please sign in to comment.