Skip to content

Commit

Permalink
merge latest into release_gil
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbynum committed Aug 20, 2024
2 parents e9f4235 + 61f72a3 commit ec57e11
Show file tree
Hide file tree
Showing 61 changed files with 4,778 additions and 793 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Contact [Julian](https://github.com/jajhall) (General issues and solvers), [Ivet

## Improve the documentation

The top level [documentation](https://ergo-code.github.io/HiGHS/) is created using [Docsy](https://www.docsy.dev/), with the files held on the [HiGHS repository](https://github.com/ERGO-Code/HiGHS/tree/docsy). If your change is small (like fixing typos, or one or two sentence corrections), the easiest way to do this is to fork the branch and create a pull request. (See *Contribute code to HiGHS* below for more on this.) If your change is larger, or touches multiple files, please raise an issue describing what you want to do.
The top level [documentation](https://ergo-code.github.io/HiGHS/) is created using [Docsy](https://www.docsy.dev/), with the files held on the [HiGHS repository](https://github.com/ERGO-Code/HiGHS/tree/master/docs). If your change is small (like fixing typos, or one or two sentence corrections), the easiest way to do this is to fork the branch and create a pull request. (See *Contribute code to HiGHS* below for more on this.) If your change is larger, or touches multiple files, please raise an issue describing what you want to do.

## Raise an issue

Expand Down
22 changes: 9 additions & 13 deletions FEATURES.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
## Build changes

The python wrapper highspy is now available for aarch64 on manylinux
This allows highs to be run through Python on AWS arm64
## Code changes

Bug fix for fortran on macOS
Added `int64_t mip_total_lp_iterations` to `HighsCallbackDataOut` and modified accessor function

## Code changes
`Highs::writeSolution` and `Highs::writeBasis` now being done via `HighsIO` logging, so can be redirected to logging callback.

Introduced `const double kHighsUndefined` as value of undefined values in a user solution. It's equal to `kHighsInf`

Added `Highs::setSolution(const HighsInt num_entries, const HighsInt* index, const double* value);` to allow a sparse primal solution to be defined. When a MIP is solved to do this, the value of (new) option `mip_max_start_nodes` is used for `mip_max_nodes` to avoid excessive cost

The accessor function Highs_getCallbackDataOutItem in the C API means
that `pdlp_iteration_count` can be moved back to where it was inserted
into the `HighsCallbackDataOut` struct in v1.7.0, which broke the C
API. This fixes #1812
Added options `write_presolved_model_to_file` and `write_presolved_model_file` so that presolved model can be written via a command line option

Some duplicate code has been eliminated from the MIP solver, and
modifications made to eliminate compiler warnings
Added `Highs::feasibilityRelaxation` to solve the problem of minimizing a (possibly weighted) sum of (allowable) infeasibilities in an LP/MIP.

Declaration of the (deprecated) method `char* highsCompilationDate()`
has been corrected

Fixed bug when describing integrality status during the human-readable solution write

18 changes: 18 additions & 0 deletions app/RunHighs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ int main(int argc, char** argv) {
return (int)read_solution_status;
}
}
if (options.write_presolved_model_to_file) {
// Run presolve and write the presolved model to a file
HighsStatus status = highs.presolve();
if (status == HighsStatus::kError) return int(status);
HighsPresolveStatus model_presolve_status = highs.getModelPresolveStatus();
const bool ok_to_write =
model_presolve_status == HighsPresolveStatus::kNotReduced ||
model_presolve_status == HighsPresolveStatus::kReduced ||
model_presolve_status == HighsPresolveStatus::kReducedToEmpty ||
model_presolve_status == HighsPresolveStatus::kTimeout;
if (!ok_to_write) {
highsLogUser(log_options, HighsLogType::kInfo,
"No presolved model to write to file\n");
return int(status);
}
status = highs.writePresolvedModel(options.write_presolved_model_file);
return int(status);
}
// Solve the model
HighsStatus run_status = highs.run();
if (run_status == HighsStatus::kError) return int(run_status);
Expand Down
1 change: 1 addition & 0 deletions check/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ if (NOT FAST_BUILD OR ALL_TESTS)
TestHighsSparseMatrix.cpp
TestHSet.cpp
TestICrash.cpp
TestIis.cpp
TestIpm.cpp
TestIpx.cpp
TestLogging.cpp
Expand Down
51 changes: 51 additions & 0 deletions check/TestCAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -1586,6 +1586,55 @@ void test_ranging() {
Highs_destroy(highs);
}

void test_feasibilityRelaxation() {
void* highs;
highs = Highs_create();
const double kHighsInf = Highs_getInfinity(highs);
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
HighsInt return_status;

HighsInt num_col = 2;
HighsInt num_row = 3;
HighsInt num_nz = 6;
HighsInt a_format = kHighsMatrixFormatColwise;
HighsInt sense = kHighsObjSenseMinimize;
double offset = 0;
double col_cost[2] = {1, -2};
double col_lower[2] = {5, -kHighsInf};
double col_upper[2] = {kHighsInf, kHighsInf};
double row_lower[3] = {2, -kHighsInf, -kHighsInf};
double row_upper[3] = {kHighsInf, 1, 20};
HighsInt a_start[2] = {0, 3};
HighsInt a_index[6] = {0, 1, 2, 0, 1, 2};
double a_value[6] = {-1, -3, 20, 21, 2, 1};
HighsInt integrality[2] = {kHighsVarTypeInteger, kHighsVarTypeInteger};

Highs_passMip(highs, num_col, num_row, num_nz, a_format, sense, offset,
col_cost, col_lower, col_upper,
row_lower, row_upper,
a_start, a_index, a_value,
integrality);
Highs_feasibilityRelaxation(highs, 1, 1, 1, NULL, NULL, NULL);
double objective_function_value;
Highs_getDoubleInfoValue(highs, "objective_function_value", &objective_function_value);
double* col_value = (double*)malloc(sizeof(double) * num_col);
double* col_dual = (double*)malloc(sizeof(double) * num_col);
double* row_value = (double*)malloc(sizeof(double) * num_row);
double* row_dual = (double*)malloc(sizeof(double) * num_row);
return_status = Highs_getSolution(highs, col_value, col_dual, row_value, row_dual);
assert( return_status == kHighsStatusOk );
assertDoubleValuesEqual("objective_function_value", objective_function_value, 5);
assertDoubleValuesEqual("solution_value[0]", col_value[0], 1);
assertDoubleValuesEqual("solution_value[1]", col_value[1], 1);

free(col_value);
free(col_dual);
free(row_value);
free(row_dual);

Highs_destroy(highs);
}

void test_callback() {
HighsInt num_col = 7;
HighsInt num_row = 1;
Expand Down Expand Up @@ -1710,6 +1759,7 @@ void test_getModel() {
assert( highsIntArraysEqual(num_nz, ck_a_index, a_index) );
assert( doubleArraysEqual(num_nz, ck_a_value, a_value) );

Highs_destroy(highs);
}

/*
Expand Down Expand Up @@ -1774,6 +1824,7 @@ int main() {
test_getColsByRange();
test_passHessian();
test_ranging();
test_feasibilityRelaxation();
test_getModel();
return 0;
}
Expand Down
31 changes: 24 additions & 7 deletions check/TestCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ HighsCallbackFunctionType userInterruptCallback =
REQUIRE(local_callback_data == kUserCallbackNoData);
}
if (callback_type == kCallbackLogging) {
if (dev_run)
printf("userInterruptCallback(type %2d; data %2d): %s",
callback_type, local_callback_data, message.c_str());
if (dev_run) printf("Callback: %s", message.c_str());
// printf("userInterruptCallback(type %2d; data %2d): %s",
// callback_type, local_callback_data,
// message.c_str());
} else if (callback_type == kCallbackSimplexInterrupt) {
if (dev_run)
printf(
Expand Down Expand Up @@ -190,12 +191,13 @@ std::function<void(int, const std::string&, const HighsCallbackDataOut*,
if (dev_run)
printf(
"userDataCallback: Node count = %" PRId64
"; LP total iterations = %" PRId64
"; Time = %6.2f; "
"Bounds (%11.4g, %11.4g); Gap = %11.4g; Objective = %11.4g: %s\n",
data_out->mip_node_count, data_out->running_time,
data_out->mip_dual_bound, data_out->mip_primal_bound,
data_out->mip_gap, data_out->objective_function_value,
message.c_str());
data_out->mip_node_count, data_out->mip_total_lp_iterations,
data_out->running_time, data_out->mip_dual_bound,
data_out->mip_primal_bound, data_out->mip_gap,
data_out->objective_function_value, message.c_str());
};

TEST_CASE("my-callback-logging", "[highs-callback]") {
Expand Down Expand Up @@ -264,6 +266,21 @@ TEST_CASE("highs-callback-logging", "[highs-callback]") {
highs.run();
}

TEST_CASE("highs-callback-solution-basis-logging", "[highs-callback]") {
std::string filename = std::string(HIGHS_DIR) + "/check/instances/avgas.mps";
int user_callback_data = kUserCallbackData;
void* p_user_callback_data =
reinterpret_cast<void*>(static_cast<intptr_t>(user_callback_data));
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(filename);
highs.run();
highs.setCallback(userInterruptCallback, p_user_callback_data);
highs.startCallback(kCallbackLogging);
if (dev_run) highs.writeSolution("", kSolutionStylePretty);
if (dev_run) highs.writeBasis("");
}

TEST_CASE("highs-callback-simplex-interrupt", "[highs-callback]") {
std::string filename =
std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
Expand Down
51 changes: 51 additions & 0 deletions check/TestCheckSolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,57 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
highs.clear();
}

const bool test6 = other_tests;
if (test6) {
if (dev_run)
printf(
"\n***************************\nSolving from sparse integer "
"solution\n");
HighsInt num_integer_variable = 0;
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
if (lp.integrality_[iCol] == HighsVarType::kInteger)
num_integer_variable++;

highs.setOptionValue("output_flag", dev_run);
highs.readModel(model_file);
std::vector<HighsInt> index;
std::vector<double> value;
// Check that duplicate values are spotted
index.push_back(0);
value.push_back(0);
index.push_back(1);
value.push_back(1);
index.push_back(0);
value.push_back(2);
HighsInt num_entries = index.size();
return_status = highs.setSolution(num_entries, index.data(), value.data());
REQUIRE(return_status == HighsStatus::kWarning);

index.clear();
value.clear();
std::vector<bool> is_set;
is_set.assign(lp.num_col_, false);
HighsInt num_to_set = 2;
assert(num_to_set > 0);
HighsRandom random;
for (HighsInt iSet = 0; iSet < num_to_set;) {
HighsInt iCol = random.integer(lp.num_col_);
if (lp.integrality_[iCol] != HighsVarType::kInteger) continue;
if (is_set[iCol]) continue;
is_set[iCol] = true;
index.push_back(iCol);
value.push_back(optimal_solution.col_value[iCol]);
iSet++;
}
num_entries = index.size();
assert(num_entries == num_to_set);
return_status = highs.setSolution(num_entries, index.data(), value.data());
REQUIRE(return_status == HighsStatus::kOk);
highs.run();
REQUIRE(info.mip_node_count < scratch_num_nodes);
highs.clear();
}
assert(other_tests);
std::remove(solution_file.c_str());
}

Expand Down
Loading

0 comments on commit ec57e11

Please sign in to comment.