Skip to content

Commit

Permalink
Merged parallel-MIP into this branch
Browse files Browse the repository at this point in the history
  • Loading branch information
jajhall committed Feb 26, 2025
2 parents ec595c2 + b450b05 commit 69cbecf
Show file tree
Hide file tree
Showing 29 changed files with 1,285 additions and 331 deletions.
14 changes: 13 additions & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Build changes

Added code coverage report

## Code changes

Any LP offset is communicated to the IPM solver, and used in logging and primal/dual objective calculations.
Expand All @@ -18,4 +20,14 @@ Primal and dual residual tolerances - applied following IPM or PDLP solution - n

Highs::getCols (Highs::getRows) now runs in linear time if the internal constraint matrix is stored column-wise (row-wise). Added ensureColwise/Rowwise to the Highs class, the C API and highspy so that users can set the internal constraint matrix storage orientation

When columns and rows are deleted from the incumbent LP after a basic solution has been found, HiGHS no longer invalidates the basis. Now it maintains the basic and nonbasic status of the remaining variables and constraints. When the model is re-solved, this information is used to construct a starting basis.
When columns and rows are deleted from the incumbent LP after a basic solution has been found, HiGHS no longer invalidates the basis. Now it maintains the basic and nonbasic status of the remaining variables and constraints. When the model is re-solved, this information is used to construct a starting basis.

Fixed bugs in presolve

When running from the command lin, changes to default option values are reported

Added callback to allow users to supply integer feasible solutions to the MIP solver during execution




78 changes: 75 additions & 3 deletions check/TestCallbacks.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// #include <algorithm>
#include <cstdio>
#include <cstring>

Expand All @@ -6,7 +7,7 @@
#include "catch.hpp"
#include "lp_data/HighsCallback.h"

const bool dev_run = false;
const bool dev_run = false; // true;//

const double egout_optimal_objective = 568.1007;
const double egout_objective_target = 610;
Expand All @@ -31,6 +32,12 @@ struct MipData {
HighsVarType* integrality;
};

struct UserMipSolution {
double optimal_objective_value;
double* optimal_solution;
HighsInt require_user_solution_callback_origin;
};

// Callback that saves message for comparison
HighsCallbackFunctionType myLogCallback =
[](int callback_type, const std::string& message,
Expand Down Expand Up @@ -179,6 +186,30 @@ HighsCallbackFunctionType userMipCutPoolCallback =
}
};

HighsCallbackFunctionType userkMipUserSolution =
[](int callback_type, const std::string& message,
const HighsCallbackDataOut* data_out, HighsCallbackDataIn* data_in,
void* user_callback_data) {
UserMipSolution callback_data =
*(static_cast<UserMipSolution*>(user_callback_data));
if (data_out->user_solution_callback_origin ==
callback_data.require_user_solution_callback_origin) {
if (data_out->mip_primal_bound >
callback_data.optimal_objective_value) {
// If current objective value is not optimal, pass the
// optimal solution as a user solution
if (dev_run)
printf(
"userkMipUserSolution: origin = %d; %g = mip_primal_bound > "
"optimal_objective_value = %g\n",
int(data_out->user_solution_callback_origin),
data_out->mip_primal_bound,
callback_data.optimal_objective_value);
data_in->user_solution = callback_data.optimal_solution;
}
}
};

std::function<void(int, const std::string&, const HighsCallbackDataOut*,
HighsCallbackDataIn*, void*)>
userDataCallback = [](int callback_type, const std::string& message,
Expand Down Expand Up @@ -375,8 +406,49 @@ TEST_CASE("highs-callback-mip-cut-pool", "[highs-callback]") {
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.readModel(filename);
// MipData user_callback_data;
highs.setCallback(userMipCutPoolCallback); //, p_user_callback_data);
highs.setCallback(userMipCutPoolCallback);
highs.startCallback(kCallbackMipGetCutPool);
highs.run();
}

TEST_CASE("highs-callback-mip-user-solution", "[highs-callback]") {
// const std::vector<std::string> model = {"rgn", "flugpl", "gt2", "egout",
// "bell5", "lseu", "sp150x300d"};//, "p0548", "dcmulti"}; const
// std::vector<HighsInt> require_origin = {0, 1, 2, 3, 4, 5, 6};
const std::vector<std::string> model = {"p0548", "flugpl", "gt2", "egout",
"sp150x300d"};
const std::vector<HighsInt> require_origin = {0, 1, 2, 3, 4}; //, 4, 5, 6};
assert(model.size() == require_origin.size());
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.setOptionValue("mip_rel_gap", 0);
HighsInt from_model = 0;
HighsInt to_model = HighsInt(model.size());
for (HighsInt iModel = from_model; iModel < to_model; iModel++) {
const std::string filename =
std::string(HIGHS_DIR) + "/check/instances/" + model[iModel] + ".mps";
highs.readModel(filename);
highs.run();
std::vector<double> optimal_solution = highs.getSolution().col_value;
double objective_function_value0 = highs.getInfo().objective_function_value;
highs.clearSolver();

UserMipSolution user_callback_data;
user_callback_data.optimal_objective_value = objective_function_value0;
user_callback_data.optimal_solution = optimal_solution.data();
user_callback_data.require_user_solution_callback_origin =
require_origin[iModel];
void* p_user_callback_data = (void*)(&user_callback_data);

// highs.setOptionValue("presolve", kHighsOffString);
highs.setCallback(userkMipUserSolution, p_user_callback_data);
highs.startCallback(kCallbackMipUserSolution);
highs.run();
highs.stopCallback(kCallbackMipUserSolution);
double objective_function_value1 = highs.getInfo().objective_function_value;
double objective_diff =
std::fabs(objective_function_value1 - objective_function_value0) /
std::max(1.0, std::fabs(objective_function_value0));
REQUIRE(objective_diff < 1e-12);
}
}
1 change: 1 addition & 0 deletions check/TestEkk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ void ekk_solve(Highs& highs, std::string presolve,
}

REQUIRE(highs.resetOptions() == HighsStatus::kOk);
highs.setOptionValue("output_flag", dev_run);
}

void ekk_distillation(Highs& highs) {
Expand Down
12 changes: 12 additions & 0 deletions check/TestMipSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,10 +800,22 @@ void rowlessMIP(Highs& highs) {
TEST_CASE("issue-2122", "[highs_test_mip_solver]") {
std::string filename = std::string(HIGHS_DIR) + "/check/instances/2122.lp";
Highs highs;
highs.setOptionValue("output_flag", dev_run);
highs.setOptionValue("mip_rel_gap", 0);
highs.setOptionValue("mip_abs_gap", 0);
highs.readModel(filename);
const HighsModelStatus require_model_status = HighsModelStatus::kOptimal;
const double optimal_objective = -187612.944194;
solve(highs, kHighsOnString, require_model_status, optimal_objective);
}

TEST_CASE("issue-2171", "[highs_test_mip_solver]") {
std::string filename = std::string(HIGHS_DIR) + "/check/instances/2171.mps";
Highs highs;
highs.setOptionValue("mip_rel_gap", 0);
highs.setOptionValue("mip_abs_gap", 0);
highs.readModel(filename);
const HighsModelStatus require_model_status = HighsModelStatus::kOptimal;
const double optimal_objective = -22375.7585461;
solve(highs, kHighsOnString, require_model_status, optimal_objective);
}
2 changes: 2 additions & 0 deletions check/TestSpecialLps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ void solve(Highs& highs, std::string presolve, std::string solver,
REQUIRE(iteration_count == require_iteration_count);
}
REQUIRE(highs.resetOptions() == HighsStatus::kOk);
highs.setOptionValue("output_flag", dev_run);
}

void distillation(Highs& highs) {
Expand Down Expand Up @@ -591,6 +592,7 @@ void singularStartingBasis(Highs& highs) {
optimal_objective, dev_run));

REQUIRE(highs.resetOptions() == HighsStatus::kOk);
highs.setOptionValue("output_flag", dev_run);

special_lps.reportSolution(highs, dev_run);
}
Expand Down
Loading

0 comments on commit 69cbecf

Please sign in to comment.