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

Add lazy constraints #1636

Draft
wants to merge 70 commits into
base: latest
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
bdf0d2a
Avoid duplication with Highs::startCallback(const int callback_type) …
jajhall Feb 8, 2024
3b4cbfd
Now switching off presolve when lazy constraints are permitted
jajhall Feb 8, 2024
900be85
Now calling user_callback in HighsMipSolverData::defineLazyConstraints
jajhall Feb 8, 2024
3e917ed
tsp-p01 now uses p01.tsp and includes tsp.cpp
jajhall Feb 8, 2024
2b1a92a
Replaced ../check/instances/p01.mps by ../check/instances/p01.tsp
jajhall Feb 8, 2024
04eef96
Now extracting tours from MIP solution
jajhall Feb 8, 2024
76277db
Now forming cutset in userDefineLazyConstraints
jajhall Feb 8, 2024
7fca5fe
Now defining lazy constraints as HighsCutSet in defineLazyConstraints
jajhall Feb 8, 2024
8c33e07
Added first lazy constraints to LP relaxation, but need to be in the …
jajhall Feb 9, 2024
fe6127a
Merge branch 'latest' into add-lazy-constraints
jajhall Feb 10, 2024
b844212
Corrected a couple of printf errors when using HIGHSINT64
jajhall Feb 11, 2024
25f0e31
Merge branch 'latest' into add-lazy-constraints
jajhall Feb 16, 2024
c9c0588
Now adding lazy constraints to cutpool and LP
jajhall Feb 16, 2024
5f743b0
Need to define whether new lazy constraints have been defined to avoi…
jajhall Feb 16, 2024
e94ce1f
Avoiding error report if lazy constraints are added
jajhall Feb 16, 2024
8e8f52b
Solves p01
jajhall Feb 17, 2024
87f63ed
Need to learn more about the cut pool
jajhall Feb 18, 2024
3966c47
Added origin to HighsCutPool::addCut
jajhall Feb 18, 2024
5061eca
Now reporting the cut pool
jajhall Feb 18, 2024
6448614
Merge branch 'latest' into add-lazy-constraints
jajhall Feb 19, 2024
cc5aa90
Fixed error spotted by Derya in writeModelAsMps
jajhall Feb 19, 2024
ad4c409
Need to get better idea of LP relaxation
jajhall Feb 19, 2024
25ed626
Better to distinguish my origin as debug_origin
jajhall Feb 19, 2024
088ae2c
Move HighsCutPool::debugOriginString to HighsMipSolver and distinguis…
jajhall Feb 19, 2024
cfe38ed
Move HighsCutPool::debugOriginString to HighsMipSolver and distinguis…
jajhall Feb 19, 2024
a3fccbb
Moved HighsCutPool::debugOriginString to HighsMipSolver as debugCutOr…
jajhall Feb 19, 2024
69a6dfb
Rationalised HighsLpRelaxation::debugReport and HighsCutPool::debugRe…
jajhall Feb 19, 2024
67933d1
Introduced inLp to HighsCutPool::addCut
jajhall Feb 23, 2024
bdca318
Removed debug printing
jajhall Feb 23, 2024
e1c98b3
Formatted and solving TSP p01 again
jajhall Feb 23, 2024
6197f89
Merge branch 'latest' into add-lazy-constraints
jajhall Feb 23, 2024
9ede661
Further reversions; formatted
jajhall Feb 23, 2024
b4d86ed
Added getNumLpCuts() to HighsCutPool
jajhall Feb 24, 2024
0b31a34
Added skeleton HighsLpRelaxation::addModelConstraints
jajhall Feb 24, 2024
0855037
Started adding lazy constraints to model after presolve and LP relaxa…
jajhall Feb 25, 2024
f85c0d2
Where is the presolved model for modificaiton?
jajhall Feb 25, 2024
aac4702
Now inserting lazy constraints as rows
jajhall Feb 26, 2024
79c5e9c
Now to fix domain activities
jajhall Feb 26, 2024
a1fdd40
Getting further through p01
jajhall Feb 26, 2024
68fc421
Rename kCutOrigin kLpRowOrigin
jajhall Feb 26, 2024
16f6a2c
enum cutOrigin* now enum lpRowOrigin
jajhall Feb 26, 2024
9002d58
Added dantzig.tsp and added return to bool HighsLpRelaxation::addMode…
jajhall Feb 26, 2024
8a3a97f
Merge branch 'latest' into add-lazy-constraints
jajhall Feb 26, 2024
e42dce5
Solving dantzig.tsp
jajhall Feb 26, 2024
aad4f36
Now maintaining the model and lpsolver model OK
jajhall Feb 27, 2024
290f919
Merge branch 'latest' into add-lazy-constraints
jajhall Feb 28, 2024
50c6e15
Merge branch 'latest' into add-lazy-constraints
jajhall Mar 1, 2024
f3e1ae3
Merge branch 'latest' into add-lazy-constraints
jajhall Mar 1, 2024
8bb59b2
Fixed long-standing bug in Highs::getCols and Highs::getRows
jajhall Mar 1, 2024
87a5ff4
Now failing after insertion of lazy constraints befor cuts
jajhall Mar 1, 2024
ffefa3f
Now seems to be inserting lazy constraints correctly
jajhall Mar 2, 2024
c1a5a5e
Progress: now to track down invalid read of size 1
jajhall Mar 2, 2024
cb81a81
firstrootbasis now resized OK
jajhall Mar 2, 2024
bc3afb7
Removed code relating to lazy constraints as cuts, and HighsLpRelaxat…
jajhall Mar 2, 2024
cd415b8
Removed debug assert
jajhall Mar 2, 2024
98a445f
Avoiding CI failure in unit tests LP-getrows LP-getcols where 1 is am…
jajhall Mar 2, 2024
6e4bf33
Another try
jajhall Mar 2, 2024
486f89a
Can't use null test
jajhall Mar 2, 2024
54dda95
Eliminated the 1-row/col test in TestLpModification
jajhall Mar 2, 2024
eae13f7
Chasing the CI failure
jajhall Mar 3, 2024
4170068
Chasing the CI failure
jajhall Mar 3, 2024
dffd97d
Formatted
jajhall Mar 3, 2024
87aaff7
Institutionalised possiblyResetLocalDomain
jajhall Mar 4, 2024
ddc6893
Added possiblyResetLocalDomain after addIncumbent calls in HighsSearc…
jajhall Mar 4, 2024
800f851
Cannot assume Highs::getIterate() will be OK
jajhall Mar 4, 2024
71440a2
OK to abandon getIterate
jajhall Mar 4, 2024
dd6042d
Merge branch 'latest' into add-lazy-constraints
jajhall Mar 7, 2024
5cc96b8
Removed some incorrect asserts
jajhall Mar 7, 2024
321e578
Merged latest into this branch; formatted
jajhall Mar 7, 2024
ff3135a
Merge branch 'latest' into add-lazy-constraints
jajhall Mar 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions check/TestCallbacks.cpp
Expand Up @@ -169,10 +169,10 @@ HighsCallbackFunctionType userMipCutPoolCallback =
int(data_out->cutpool_num_nz));
for (HighsInt iCut = 0; iCut < data_out->cutpool_num_cut; iCut++) {
printf("Cut %d\n", int(iCut));
for (HighsInt iEl = data_out->cutpool_start[iCut];
iEl < data_out->cutpool_start[iCut + 1]; iEl++) {
printf(" %2d %11.5g\n", int(data_out->cutpool_index[iEl]),
data_out->cutpool_value[iEl]);
for (HighsInt iEl = data_out->cutpool_ARstart[iCut];
iEl < data_out->cutpool_ARstart[iCut + 1]; iEl++) {
printf(" %2d %11.5g\n", int(data_out->cutpool_ARindex[iEl]),
data_out->cutpool_ARvalue[iEl]);
}
}
}
Expand Down
140 changes: 105 additions & 35 deletions check/TestLpModification.cpp
Expand Up @@ -7,7 +7,7 @@
#include "util/HighsRandom.h"
#include "util/HighsUtils.h"

const bool dev_run = false;
const bool dev_run = true;
// const double inf = kHighsInf;
const double double_equal_tolerance = 1e-5;
void HighsStatusReport(const HighsLogOptions& log_options, std::string message,
Expand Down Expand Up @@ -471,8 +471,8 @@ TEST_CASE("LP-modification", "[highs_data]") {
REQUIRE(return_status == HighsStatus::kOk);

REQUIRE(avgas_highs.addCols(num_col, colCost.data(), colLower.data(),
colUpper.data(), 0, NULL, NULL,
NULL) == HighsStatus::kOk);
colUpper.data(), 0, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(avgas_highs.addRows(num_row, rowLower.data(), rowUpper.data(),
num_row_nz, ARstart.data(), ARindex.data(),
ARvalue.data()) == HighsStatus::kOk);
Expand Down Expand Up @@ -504,8 +504,8 @@ TEST_CASE("LP-modification", "[highs_data]") {

// Adding column vectors to model with no rows returns OK
REQUIRE(highs.addCols(num_col, colCost.data(), colLower.data(),
colUpper.data(), 0, NULL, NULL,
NULL) == HighsStatus::kOk);
colUpper.data(), 0, nullptr, nullptr,
nullptr) == HighsStatus::kOk);

callRun(highs, options.log_options, "highs.run()", HighsStatus::kOk);

Expand Down Expand Up @@ -599,8 +599,8 @@ TEST_CASE("LP-modification", "[highs_data]") {

// Adding column vectors to model with no rows returns OK
REQUIRE(highs.addCols(num_col, colCost.data(), colLower.data(),
colUpper.data(), 0, NULL, NULL,
NULL) == HighsStatus::kOk);
colUpper.data(), 0, nullptr, nullptr,
nullptr) == HighsStatus::kOk);

callRun(highs, options.log_options, "highs.run()", HighsStatus::kOk);

Expand Down Expand Up @@ -684,8 +684,8 @@ TEST_CASE("LP-modification", "[highs_data]") {

// Adding column vectors to model with no rows returns OK
REQUIRE(highs.addCols(num_col, colCost.data(), colLower.data(),
colUpper.data(), 0, NULL, NULL,
NULL) == HighsStatus::kOk);
colUpper.data(), 0, nullptr, nullptr,
nullptr) == HighsStatus::kOk);

callRun(highs, options.log_options, "highs.run()", HighsStatus::kOk);

Expand Down Expand Up @@ -765,7 +765,7 @@ TEST_CASE("LP-modification", "[highs_data]") {

// Adding row vectors to model with no columns returns OK
REQUIRE(highs.addRows(row0135789_num_row, row0135789_lower, row0135789_upper,
0, NULL, NULL, NULL) == HighsStatus::kOk);
0, nullptr, nullptr, nullptr) == HighsStatus::kOk);

callRun(highs, options.log_options, "highs.run()", HighsStatus::kOk);

Expand Down Expand Up @@ -871,8 +871,8 @@ TEST_CASE("LP-modification", "[highs_data]") {

// Adding column vectors to model with no rows returns OK
REQUIRE(highs.addCols(num_col, colCost.data(), colLower.data(),
colUpper.data(), 0, NULL, NULL,
NULL) == HighsStatus::kOk);
colUpper.data(), 0, nullptr, nullptr,
nullptr) == HighsStatus::kOk);

callRun(highs, options.log_options, "highs.run()", HighsStatus::kOk);

Expand Down Expand Up @@ -1077,35 +1077,68 @@ TEST_CASE("LP-modification", "[highs_data]") {
TEST_CASE("LP-getcols", "[highs_data]") {
Highs highs;
if (!dev_run) highs.setOptionValue("output_flag", false);
highs.addCol(-1.0, 0.0, 1.0, 0, NULL, NULL);
highs.addCol(-1.0, 0.0, 1.0, 0, NULL, NULL);
highs.addCol(-1.0, 0.0, 1.0, 0, nullptr, nullptr);
highs.addCol(-1.0, 0.0, 1.0, 0, nullptr, nullptr);
HighsInt aindex[2] = {0, 1};
double avalue[2] = {1.0, -1.0};
highs.addRow(0.0, 0.0, 2, aindex, avalue);
HighsInt num_cols;
HighsInt num_nz;
HighsInt matrix_start[2] = {-1, -1};
highs.getCols(0, 1, num_cols, NULL, NULL, NULL, num_nz, matrix_start, NULL,
NULL);
highs.getCols(0, 1, num_cols, nullptr, nullptr, nullptr, num_nz, matrix_start,
nullptr, nullptr);
REQUIRE(num_cols == 2);
REQUIRE(num_nz == 2);
REQUIRE(matrix_start[0] == 0);
REQUIRE(matrix_start[1] == 1);
HighsInt matrix_indices[2] = {-1, -1};
double matrix_values[2] = {0.0, 0.0};
highs.getCols(0, 1, num_cols, NULL, NULL, NULL, num_nz, matrix_start,
highs.getCols(0, 1, num_cols, nullptr, nullptr, nullptr, num_nz, matrix_start,
matrix_indices, matrix_values);
REQUIRE(matrix_indices[0] == 0);
REQUIRE(matrix_indices[1] == 0);
REQUIRE(matrix_values[0] == 1.0);
REQUIRE(matrix_values[1] == -1.0);
const bool try_null_test = false;
if (try_null_test) {
// Make sure this works for getting one column from an interval
if (dev_run) printf("Get one column from an interval\n");
highs.getCols(1, 1, num_cols, nullptr, nullptr, nullptr, num_nz, nullptr,
nullptr, nullptr);
REQUIRE(num_cols == 1);
REQUIRE(num_nz == 1);
// Make sure this works for getting one column from a set
std::vector<HighsInt> set(1);
set[1] = 1;
if (dev_run) printf("Get one column from a set\n");
highs.getCols(1, set.data(), num_cols, nullptr, nullptr, nullptr, num_nz,
nullptr, nullptr, nullptr);
REQUIRE(num_cols == 1);
REQUIRE(num_nz == 1);

// Link error on some architectures, since 1 seems indistinguishable
// from the pointer to a set
HighsInt to_col = 0;
// Make sure this works for getting no columns from an interval
if (dev_run) printf("Get no columns from an interval\n");
highs.getCols(1, to_col, num_cols, nullptr, nullptr, nullptr, num_nz,
nullptr, nullptr, nullptr);
REQUIRE(num_cols == 0);
REQUIRE(num_nz == 0);
// Make sure this works for getting no columns from a set
if (dev_run) printf("Get no columns from a set\n");
highs.getCols(0, nullptr, num_cols, nullptr, nullptr, nullptr, num_nz,
nullptr, nullptr, nullptr);
REQUIRE(num_cols == 0);
REQUIRE(num_nz == 0);
}
}

TEST_CASE("LP-getrows", "[highs_data]") {
Highs highs;
if (!dev_run) highs.setOptionValue("output_flag", false);
highs.addCol(-1.0, 0.0, 1.0, 0, NULL, NULL);
highs.addCol(-1.0, 0.0, 1.0, 0, NULL, NULL);
highs.addCol(-1.0, 0.0, 1.0, 0, nullptr, nullptr);
highs.addCol(-1.0, 0.0, 1.0, 0, nullptr, nullptr);
HighsInt aindex = 0;
double avalue = 1.0;
highs.addRow(0.0, 0.0, 1, &aindex, &avalue);
Expand All @@ -1115,19 +1148,52 @@ TEST_CASE("LP-getrows", "[highs_data]") {
HighsInt num_rows;
HighsInt num_nz;
HighsInt matrix_start[2] = {-1, -1};
highs.getRows(0, 1, num_rows, NULL, NULL, num_nz, matrix_start, NULL, NULL);
highs.getRows(0, 1, num_rows, nullptr, nullptr, num_nz, matrix_start, nullptr,
nullptr);
REQUIRE(num_rows == 2);
REQUIRE(num_nz == 2);
REQUIRE(matrix_start[0] == 0);
REQUIRE(matrix_start[1] == 1);
HighsInt matrix_indices[2] = {-1, -1};
double matrix_values[2] = {0.0, 0.0};
highs.getRows(0, 1, num_rows, NULL, NULL, num_nz, matrix_start,
highs.getRows(0, 1, num_rows, nullptr, nullptr, num_nz, matrix_start,
matrix_indices, matrix_values);
REQUIRE(matrix_indices[0] == 0);
REQUIRE(matrix_indices[1] == 1);
REQUIRE(matrix_values[0] == 1.0);
REQUIRE(matrix_values[1] == -2.0);
const bool try_null_test = false;
if (try_null_test) {
// Make sure this works for getting one row from an interval
if (dev_run) printf("Get one row from an interval\n");
highs.getRows(1, 1, num_rows, nullptr, nullptr, num_nz, nullptr, nullptr,
nullptr);
REQUIRE(num_rows == 1);
REQUIRE(num_nz == 1);
// Make sure this works for getting one row from a set
std::vector<HighsInt> set(1);
set[1] = 1;
if (dev_run) printf("Get one row from a set\n");
highs.getRows(1, set.data(), num_rows, nullptr, nullptr, num_nz, nullptr,
nullptr, nullptr);
REQUIRE(num_rows == 1);
REQUIRE(num_nz == 1);
// Link error on some architectures, since 1 seems indistinguishable
// from the pointer to a set
HighsInt to_row = 0;
// Make sure this works for getting no rows from an interval
if (dev_run) printf("Get no rows from an interval\n");
highs.getRows(1, to_row, num_rows, nullptr, nullptr, num_nz, nullptr,
nullptr, nullptr);
REQUIRE(num_rows == 0);
REQUIRE(num_nz == 0);
// Make sure this works for getting no rows from a set
if (dev_run) printf("Get no rows from a set\n");
highs.getRows(0, nullptr, num_rows, nullptr, nullptr, num_nz, nullptr,
nullptr, nullptr);
REQUIRE(num_rows == 0);
REQUIRE(num_nz == 0);
}
}

TEST_CASE("LP-interval-changes", "[highs_data]") {
Expand Down Expand Up @@ -1170,13 +1236,13 @@ TEST_CASE("LP-interval-changes", "[highs_data]") {
set_col2345_cost[2] = 4.0;
set_col2345_cost[3] = 5.0;
REQUIRE(highs.getCols(from_col, to_col, get_num_col, og_col2345_cost.data(),
NULL, NULL, get_num_nz, NULL, NULL,
NULL) == HighsStatus::kOk);
nullptr, nullptr, get_num_nz, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(highs.changeColsCost(from_col, to_col, set_col2345_cost.data()) ==
HighsStatus::kOk);
REQUIRE(highs.getCols(from_col, to_col, get_num_col, get_col2345_cost.data(),
NULL, NULL, get_num_nz, NULL, NULL,
NULL) == HighsStatus::kOk);
nullptr, nullptr, get_num_nz, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(get_num_col == set_num_col);
for (HighsInt usr_col = 0; usr_col < get_num_col; usr_col++)
REQUIRE(get_col2345_cost[usr_col] == set_col2345_cost[usr_col]);
Expand Down Expand Up @@ -1207,14 +1273,16 @@ TEST_CASE("LP-interval-changes", "[highs_data]") {
set_col01234_lower[2] = 2.0;
set_col01234_lower[3] = 3.0;
set_col01234_lower[4] = 4.0;
REQUIRE(highs.getCols(from_col, to_col, get_num_col, NULL,
REQUIRE(highs.getCols(from_col, to_col, get_num_col, nullptr,
og_col01234_lower.data(), og_col01234_upper.data(),
get_num_nz, NULL, NULL, NULL) == HighsStatus::kOk);
get_num_nz, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(highs.changeColsBounds(from_col, to_col, set_col01234_lower.data(),
og_col01234_upper.data()) == HighsStatus::kOk);
REQUIRE(highs.getCols(from_col, to_col, get_num_col, NULL,
REQUIRE(highs.getCols(from_col, to_col, get_num_col, nullptr,
get_col01234_lower.data(), og_col01234_upper.data(),
get_num_nz, NULL, NULL, NULL) == HighsStatus::kOk);
get_num_nz, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(get_num_col == set_num_col);
for (HighsInt usr_col = 0; usr_col < get_num_col; usr_col++)
REQUIRE(get_col01234_lower[usr_col] == set_col01234_lower[usr_col]);
Expand Down Expand Up @@ -1246,13 +1314,14 @@ TEST_CASE("LP-interval-changes", "[highs_data]") {
set_row56789_lower[3] = 8.0;
set_row56789_lower[4] = 9.0;
REQUIRE(highs.getRows(from_row, to_row, get_num_row, og_row56789_lower.data(),
og_row56789_upper.data(), get_num_nz, NULL, NULL,
NULL) == HighsStatus::kOk);
og_row56789_upper.data(), get_num_nz, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(highs.changeRowsBounds(from_row, to_row, set_row56789_lower.data(),
og_row56789_upper.data()) == HighsStatus::kOk);
REQUIRE(highs.getRows(from_row, to_row, get_num_row,
get_row56789_lower.data(), og_row56789_upper.data(),
get_num_nz, NULL, NULL, NULL) == HighsStatus::kOk);
get_num_nz, nullptr, nullptr,
nullptr) == HighsStatus::kOk);
REQUIRE(get_num_row == set_num_row);
for (HighsInt usr_row = 0; usr_row < get_num_row; usr_row++)
REQUIRE(get_row56789_lower[usr_row] == set_row56789_lower[usr_row]);
Expand Down Expand Up @@ -1686,8 +1755,9 @@ bool areLpEqual(const HighsLp lp0, const HighsLp lp1,
HighsInt lp1_num_nz = 0;
return_bool = areLpRowEqual(
lp0.num_row_, lp0.row_lower_.data(), lp0.row_upper_.data(), lp0_num_nz,
NULL, NULL, NULL, lp1.num_row_, lp1.row_lower_.data(),
lp1.row_upper_.data(), lp1_num_nz, NULL, NULL, NULL, infinite_bound);
nullptr, nullptr, nullptr, lp1.num_row_, lp1.row_lower_.data(),
lp1.row_upper_.data(), lp1_num_nz, nullptr, nullptr, nullptr,
infinite_bound);
}
return return_bool;
}
Expand Down Expand Up @@ -1820,7 +1890,7 @@ void messageReportLp(const char* message, const HighsLp& lp) {
log_to_console = true;
log_dev_level = kHighsLogDevLevelVerbose;
log_options.output_flag = &output_flag;
log_options.log_stream = NULL;
log_options.log_stream = nullptr;
log_options.log_to_console = &log_to_console;
log_options.log_dev_level = &log_dev_level;
highsLogDev(log_options, HighsLogType::kVerbose, "\nReporting LP: %s\n",
Expand Down