From 545b7b13ae3649d524092ae6815b777a9f54243b Mon Sep 17 00:00:00 2001 From: JAJHall Date: Mon, 9 Feb 2026 21:12:47 +0000 Subject: [PATCH 1/5] Moved writing of definitions.md and HighsInfo.md from app/RunHighs.cpp to TestOptions.cpp and TestInfo.cpp --- app/RunHighs.cpp | 4 ---- check/TestInfo.cpp | 10 ++++++++++ check/TestOptions.cpp | 9 +++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/RunHighs.cpp b/app/RunHighs.cpp index 4759019545..27c8eca47d 100644 --- a/app/RunHighs.cpp +++ b/app/RunHighs.cpp @@ -110,10 +110,6 @@ int main(int argc, char** argv) { // Log changes from the default option settings highs.writeOptions("", true); - // Lines to write out documentation of HighsOptions and HighsInfo - // highs.writeOptions("definitions.md"); - // highs.writeInfo("Info.md"); - // Load the model from model_file HighsStatus read_status = highs.readModel(cmd_options.model_file); if (read_status == HighsStatus::kError) { diff --git a/check/TestInfo.cpp b/check/TestInfo.cpp index cfaa3d296c..cdce803ccc 100644 --- a/check/TestInfo.cpp +++ b/check/TestInfo.cpp @@ -8,6 +8,16 @@ const bool dev_run = false; +TEST_CASE("info-md", "[highs_info]") { + Highs h; + h.setOptionValue("output_flag", dev_run); + // Use this name so that it can be copied to docs and provides code + // coverage + const std::string info_file = "HighsInfo.md"; + REQUIRE(h.writeInfo(info_file) == HighsStatus::kOk); + std::remove(info_file.c_str()); +} + TEST_CASE("highs-info", "[highs_info]") { const std::string test_name = Catch::getResultCapture().getCurrentTestName(); const std::string highs_info_file = test_name + ".info"; diff --git a/check/TestOptions.cpp b/check/TestOptions.cpp index dba3f7e51f..6ccf2c07e0 100644 --- a/check/TestOptions.cpp +++ b/check/TestOptions.cpp @@ -11,10 +11,11 @@ const bool dev_run = false; TEST_CASE("definitions-md", "[highs_options]") { Highs h; h.setOptionValue("output_flag", dev_run); - const std::string test_name = Catch::getResultCapture().getCurrentTestName(); - const std::string definitions_file = test_name + ".md"; - REQUIRE(h.writeOptions("definitions_file") == HighsStatus::kOk); - std::remove(definitions_file.c_str()); + // Use this name so that it can be copied to docs and provides code + // coverage + const std::string definitions_file = "definitions.md"; + REQUIRE(h.writeOptions(definitions_file) == HighsStatus::kOk); + // std::remove(definitions_file.c_str()); } TEST_CASE("external-options", "[highs_options]") { From 154a42ea3b6d4d71e8d52f0f7dac4c08e473bf5a Mon Sep 17 00:00:00 2001 From: JAJHall Date: Mon, 9 Feb 2026 21:15:04 +0000 Subject: [PATCH 2/5] Merged latest into this branch and formatted --- check/TestInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check/TestInfo.cpp b/check/TestInfo.cpp index cdce803ccc..35e42aac3f 100644 --- a/check/TestInfo.cpp +++ b/check/TestInfo.cpp @@ -15,7 +15,7 @@ TEST_CASE("info-md", "[highs_info]") { // coverage const std::string info_file = "HighsInfo.md"; REQUIRE(h.writeInfo(info_file) == HighsStatus::kOk); - std::remove(info_file.c_str()); + // std::remove(info_file.c_str()); } TEST_CASE("highs-info", "[highs_info]") { From 48a9bd7315f68a251bf0b2046904baacc0fc8efd Mon Sep 17 00:00:00 2001 From: JAJHall Date: Mon, 9 Feb 2026 21:37:59 +0000 Subject: [PATCH 3/5] Added Code changes to FEATURES.md, and corrected docs/src/interfaces/python/model-py.md --- FEATURES.md | 16 ++++++++++++++++ docs/src/interfaces/python/model-py.md | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 8a660fec59..9391ff674f 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,4 +1,20 @@ ## Code changes +Following PR [#2812](https://github.com/ERGO-Code/HiGHS/pull/2812), +HiGHS can read LP files with keywords as constraint names. + +Following PR [#2818](https://github.com/ERGO-Code/HiGHS/pull/2818), a +potential data race in the HiGHS multithreading system has been fixed + +Following PR [#2825](https://github.com/ERGO-Code/HiGHS/pull/2825), +potential conflict with METIS symbols has been eliminated. + +Following PR [#2832](https://github.com/ERGO-Code/HiGHS/pull/2832), +potential conflict with AMD and RCM symbols has been eliminated. + +Following PR [#2834](https://github.com/ERGO-Code/HiGHS/pull/2834), +there is some minimal documentation of the `highspy`modelling +language. + ## Build changes diff --git a/docs/src/interfaces/python/model-py.md b/docs/src/interfaces/python/model-py.md index 5acd729edc..71157e2c32 100644 --- a/docs/src/interfaces/python/model-py.md +++ b/docs/src/interfaces/python/model-py.md @@ -14,8 +14,8 @@ import highspy h = highspy.Highs() -x1 = h.addVar() -x2 = h.addVar() +x1 = h.addVariable() +x2 = h.addVariable() h.addConstr(x1 + 2*x2 <= 80) h.addConstr(x1 + 4*x2 <= 120) @@ -26,14 +26,14 @@ print("x1 = ", h.val(x1)) print("x2 = ", h.val(x2)) ``` -## addVar +## addVariable Adds a variable to the model. By default it is continuous, non-negative, with zero objective coefficient, and has no name associated with it. ``` -addVar(lb = 0, ub = kHighsInf, obj = 0, type=HighsVarType.kContinuous, name = None) +addVariable(lb = 0, ub = kHighsInf, obj = 0, type=HighsVarType.kContinuous, name = None) ``` ## addConstr From a0cd9ed35ffeda48ecdbeec88e7c03d8b9518234 Mon Sep 17 00:00:00 2001 From: JAJHall Date: Mon, 9 Feb 2026 21:43:53 +0000 Subject: [PATCH 4/5] Updated docs/src/options/definitions.md --- docs/src/options/definitions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/options/definitions.md b/docs/src/options/definitions.md index 42afae527f..30f284e924 100644 --- a/docs/src/options/definitions.md +++ b/docs/src/options/definitions.md @@ -385,7 +385,7 @@ - Default: "false" ## [mip\_allow\_cut\_separation\_at\_nodes](@id option-mip-allow-cut-separation-at-nodes) -- Whether cut separation at nodes is permitted +- Whether cut separation at nodes other than the root node is permitted - Type: boolean - Default: "true" From af1592f85949d133cdcbca8b528ba9eff65ee182 Mon Sep 17 00:00:00 2001 From: JAJHall Date: Tue, 10 Feb 2026 10:45:20 +0000 Subject: [PATCH 5/5] Updated callback documentation, and GetCutPool callback now also gives the general MIP callback data --- docs/src/callbacks.md | 48 ++++++++++++++++++++++++++++++++---- highs/mip/HighsMipSolver.cpp | 7 +++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/docs/src/callbacks.md b/docs/src/callbacks.md index 2c764e97c6..63c2a52630 100644 --- a/docs/src/callbacks.md +++ b/docs/src/callbacks.md @@ -101,6 +101,15 @@ constant in C. A pointer to the improving solution is passed as the `objective_function_value` and `mip_solution` members of the `HighsCallbackDataOut` struct. +### MIP solution callback + +The MIP solution is called whenever the MIP solver +identifies an integer feasible solution, and its callback +type is a cast of `kCallbackMipSolution` in the C++ enum +`HighsCallbackType`, and the `kHighsCallbackMipSolution` +constant in C. A pointer to the solution is passed as the +`objective_function_value` and `mip_solution` members of the +`HighsCallbackDataOut` struct. ### MIP logging callback @@ -118,16 +127,45 @@ type is a cast of `kCallbackMipInterrupt` in the C++ enum C. The simplex iteration count is passed as the `simplex_iteration_count` member of the `HighsCallbackDataOut` struct. +### MIP user solution callback + +The MIP user solution callback is called after setting up the MIP +solver, at five points when exploring the root node, and before each +dive in the branch-and-bound tree search. The origin of the call is +given by the value of the `external_solution_query_origin` member of +the `HighsCallbackDataOut` struct. The aim is to allow potential +feasible primal solutions generated externally to be passed to the +HiGHS MIP solver. Note that by introducing data to the HiGHS MIP +solver at the user's discretion, its behaviour will generally be +non-deterministic. + +### MIP cut pool callback + +The MIP cut pool callback is called after generating cuts at the root +node, and its callback type is a cast of `kCallbackMipGetCutPool` in +the C++ enum `HighsCallbackType`, and the +`kHighsCallbackMipGetCutPool` constant in C. The data supplied +consists of the compressed sparse column representation of the cutpool +constraint matrix, and the corresponding lower and upper bounds. + +## Callback data output + +The `HighsCallbackDataOut` struct supplies data to the user that is +relevant to the particular callback. The general data are + +* `log_type`: An integer cast of the `HighsLogType` value, indicating the severity of the logging message--relevant to the logging callback. +* `running_time`: The excution time of HiGHS--relevant to the interrupt callbacks. +* `simplex_iteration_count`: The number of simplex iterations performed--relevant to the simplex interrupt callback. +* `ipm_iteration_count`: The number of IPM iterations performed--relevant to the IPM interrupt callback. +* `pdlp_iteration_count`: The number of PDLP iterations performed--relevant to the PDLP interrupt callback. + ### MIP callback data -For each of the MIP callbacks, the following `HighsCallbackDataOut` struct members will have value set +For each of the MIP callbacks, the following `HighsCallbackDataOut` +struct members will also have their value set -* `running_time`: execution time of HiGHS * `objective_function_value`: the objective function value of the best integer feasible solution found * `mip_node_count`: the number of MIP nodes explored to date * `mip_primal_bound`: the primal bound * `mip_dual_bound`: the dual bound * `mip_gap`: the (relative) difference between the primal and dual bounds - - - diff --git a/highs/mip/HighsMipSolver.cpp b/highs/mip/HighsMipSolver.cpp index 47a23b93e6..2c7fdd845f 100644 --- a/highs/mip/HighsMipSolver.cpp +++ b/highs/mip/HighsMipSolver.cpp @@ -847,6 +847,7 @@ presolve::HighsPostsolveStack HighsMipSolver::getPostsolveStack() const { void HighsMipSolver::callbackGetCutPool() const { assert(callback_->user_callback); assert(callback_->callbackActive(kCallbackMipGetCutPool)); + callback_->clearHighsCallbackOutput(); HighsCallbackOutput& data_out = callback_->data_out; HighsSparseMatrix cut_matrix; @@ -859,9 +860,9 @@ void HighsMipSolver::callbackGetCutPool() const { data_out.cutpool_index = std::move(cut_matrix.index_); data_out.cutpool_value = std::move(cut_matrix.value_); - callback_->user_callback(kCallbackMipGetCutPool, "MIP cut pool", - &callback_->data_out, &callback_->data_in, - callback_->user_callback_data); + const bool interrupt = mipdata_->interruptFromCallbackWithData( + kCallbackMipGetCutPool, solution_objective_, "MIP cut pool"); + assert(!interrupt); } std::array getGapString(const double gap_,