From 5415d179a8d13190abbd66a1dca24574750df3af Mon Sep 17 00:00:00 2001 From: jajhall Date: Thu, 2 May 2024 13:37:35 +0100 Subject: [PATCH 01/37] Added writePresolvedModel and unit test --- check/TestPresolve.cpp | 26 ++++++++++++++++++++++++++ src/Highs.h | 11 +++++++++++ src/interfaces/highs_c_api.cpp | 4 ++++ src/interfaces/highs_c_api.h | 10 ++++++++++ src/lp_data/Highs.cpp | 23 ++++++++++++++++------- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/check/TestPresolve.cpp b/check/TestPresolve.cpp index 31f7f99a63..86c5dfc469 100644 --- a/check/TestPresolve.cpp +++ b/check/TestPresolve.cpp @@ -575,3 +575,29 @@ TEST_CASE("postsolve-reduced-to-empty", "[highs_test_presolve]") { REQUIRE(highs.getInfo().num_primal_infeasibilities == 0); REQUIRE(highs.getInfo().num_dual_infeasibilities == 0); } + +TEST_CASE("write-presolved-model", "[highs_test_presolve]") { + std::string presolved_model_file = "temp.mps"; + std::string model_file = + std::string(HIGHS_DIR) + "/check/instances/afiro.mps"; + Highs highs; + highs.setOptionValue("output_flag", dev_run); + REQUIRE(highs.readModel(model_file) == HighsStatus::kOk); + highs.presolve(); + highs.writePresolvedModel(presolved_model_file); + // Read and solve the presolved model using a new Highs instance + Highs highs1; + highs1.setOptionValue("output_flag", dev_run); + highs1.readModel(presolved_model_file); + highs1.run(); + // Extract the optimal solution and basis + HighsSolution solution = highs1.getSolution(); + HighsBasis basis = highs1.getBasis(); + // Perform postsolve using the optimal solution and basis for the + // presolved model + highs.postsolve(solution, basis); + // The solution should be optimal, so no solver is run, and + // simplex_iteration_count is -1 + REQUIRE(highs.getInfo().simplex_iteration_count == -1); + std::remove(presolved_model_file.c_str()); +} diff --git a/src/Highs.h b/src/Highs.h index 62d4eca66e..8bd4cd30b3 100644 --- a/src/Highs.h +++ b/src/Highs.h @@ -770,6 +770,17 @@ class Highs { */ HighsStatus writeModel(const std::string& filename = ""); + /** + * @brief Write out the incumbent presolved model to a file + */ + HighsStatus writePresolvedModel(const std::string& filename = ""); + + /** + * @brief Write out the given model to a file + */ + HighsStatus writeLocalModel(HighsModel& model, + const std::string& filename = ""); + /** * @brief Write out the internal HighsBasis instance to a file */ diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index 6ead1b06e1..be4b9f6183 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -224,6 +224,10 @@ HighsInt Highs_writeModel(void* highs, const char* filename) { return (HighsInt)((Highs*)highs)->writeModel(std::string(filename)); } +HighsInt Highs_writePresolvedModel(void* highs, const char* filename) { + return (HighsInt)((Highs*)highs)->writePresolvedModel(std::string(filename)); +} + HighsInt Highs_writeSolution(const void* highs, const char* filename) { return (HighsInt)((Highs*)highs) ->writeSolution(std::string(filename), kSolutionStyleRaw); diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index f803a92c73..5816dee63b 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -303,6 +303,16 @@ HighsInt Highs_readModel(void* highs, const char* filename); */ HighsInt Highs_writeModel(void* highs, const char* filename); +/** + * Write the presolved model in `highs` to `filename`. + * + * @param highs A pointer to the Highs instance. + * @param filename The filename to write. + * + * @returns A `kHighsStatus` constant indicating whether the call succeeded. + */ +HighsInt Highs_writePresolvedModel(void* highs, const char* filename); + /** * Reset the options and then call `clearModel`. * diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index 482ab3f47c..e68863c03b 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -676,17 +676,26 @@ HighsStatus Highs::readBasis(const std::string& filename) { } HighsStatus Highs::writeModel(const std::string& filename) { + return writeLocalModel(model_, filename); +} + +HighsStatus Highs::writePresolvedModel(const std::string& filename) { + return writeLocalModel(presolved_model_, filename); +} + +HighsStatus Highs::writeLocalModel(HighsModel& model, + const std::string& filename) { HighsStatus return_status = HighsStatus::kOk; // Ensure that the LP is column-wise - model_.lp_.ensureColwise(); + model.lp_.ensureColwise(); // Check for repeated column or row names that would corrupt the file - if (model_.lp_.col_hash_.hasDuplicate(model_.lp_.col_names_)) { + if (model.lp_.col_hash_.hasDuplicate(model.lp_.col_names_)) { highsLogUser(options_.log_options, HighsLogType::kError, "Model has repeated column names\n"); return returnFromHighs(HighsStatus::kError); } - if (model_.lp_.row_hash_.hasDuplicate(model_.lp_.row_names_)) { + if (model.lp_.row_hash_.hasDuplicate(model.lp_.row_names_)) { highsLogUser(options_.log_options, HighsLogType::kError, "Model has repeated row names\n"); return returnFromHighs(HighsStatus::kError); @@ -706,10 +715,10 @@ HighsStatus Highs::writeModel(const std::string& filename) { // Report to user that model is being written highsLogUser(options_.log_options, HighsLogType::kInfo, "Writing the model to %s\n", filename.c_str()); - return_status = interpretCallStatus( - options_.log_options, - writer->writeModelToFile(options_, filename, model_), return_status, - "writeModelToFile"); + return_status = + interpretCallStatus(options_.log_options, + writer->writeModelToFile(options_, filename, model), + return_status, "writeModelToFile"); delete writer; } return returnFromHighs(return_status); From 3493d103390ebbc66367b9e6064749e9d5ed69fc Mon Sep 17 00:00:00 2001 From: jajhall Date: Thu, 2 May 2024 13:43:13 +0100 Subject: [PATCH 02/37] Added writePresolvedModel to C# FORTRAN and Python interfaces --- src/highs_bindings.cpp | 1 + src/interfaces/highs_csharp_api.cs | 10 +++++++++- src/interfaces/highs_fortran_api.f90 | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index 85cd1728f6..f6b5e8e802 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -906,6 +906,7 @@ PYBIND11_MODULE(_core, m) { .def("getRowByName", &highs_getRowByName) .def("writeModel", &Highs::writeModel) + .def("writePresolvedModel", &Highs::writePresolvedModel) .def("crossover", &Highs::crossover) .def("changeObjectiveSense", &Highs::changeObjectiveSense) .def("changeObjectiveOffset", &Highs::changeObjectiveOffset) diff --git a/src/interfaces/highs_csharp_api.cs b/src/interfaces/highs_csharp_api.cs index c0da92697b..0756cc02ea 100644 --- a/src/interfaces/highs_csharp_api.cs +++ b/src/interfaces/highs_csharp_api.cs @@ -189,6 +189,9 @@ private static extern int Highs_call( [DllImport(highslibname)] private static extern int Highs_writeModel(IntPtr highs, string filename); + [DllImport(highslibname)] + private static extern int Highs_writePresolvedModel(IntPtr highs, string filename); + [DllImport(highslibname)] private static extern int Highs_writeSolutionPretty(IntPtr highs, string filename); @@ -597,6 +600,11 @@ public HighsStatus writeModel(string filename) return (HighsStatus)HighsLpSolver.Highs_writeModel(this.highs, filename); } + public HighsStatus writePresolvedModel(string filename) + { + return (HighsStatus)HighsLpSolver.Highs_writePresolvedModel(this.highs, filename); + } + public HighsStatus writeSolutionPretty(string filename) { return (HighsStatus)HighsLpSolver.Highs_writeSolutionPretty(this.highs, filename); @@ -1028,4 +1036,4 @@ public class SolutionInfo /// public double ObjectiveValue { get; set; } } -} \ No newline at end of file +} diff --git a/src/interfaces/highs_fortran_api.f90 b/src/interfaces/highs_fortran_api.f90 index 05e2d17b1b..7014907f7a 100644 --- a/src/interfaces/highs_fortran_api.f90 +++ b/src/interfaces/highs_fortran_api.f90 @@ -125,6 +125,13 @@ function Highs_writeModel ( h, f ) result ( s ) bind ( c, name='Highs_writeModel integer ( c_int ) :: s end function Highs_writeModel + function Highs_writePresolvedModel ( h, f ) result ( s ) bind ( c, name='Highs_writePresolvedModel' ) + use iso_c_binding + type(c_ptr), VALUE :: h + character( c_char ) :: f(*) + integer ( c_int ) :: s + end function Highs_writePresolvedModel + function Highs_writeSolution ( h, f ) result ( s ) bind ( c, name='Highs_writeSolution' ) use iso_c_binding type(c_ptr), VALUE :: h From 9b8af979c89b3023ccf9b018e5b65206b366d6b0 Mon Sep 17 00:00:00 2001 From: jajhall Date: Thu, 2 May 2024 23:42:59 +0100 Subject: [PATCH 03/37] How is a void* passed by reference? --- check/TestCAPI.c | 53 ++++++++++++++++++++++------------ src/interfaces/highs_c_api.cpp | 12 +++++++- src/interfaces/highs_c_api.h | 12 ++++++++ 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index c53823632a..1870d91c76 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -9,7 +9,7 @@ #include #include -const HighsInt dev_run = 0; +const HighsInt dev_run = 1; const double double_equal_tolerance = 1e-5; static void userCallback(const int callback_type, const char* message, @@ -22,7 +22,19 @@ static void userCallback(const int callback_type, const char* message, if (callback_type == kHighsCallbackLogging) { if (dev_run) printf("userCallback(%11.4g): %s\n", local_callback_data, message); } else if (callback_type == kHighsCallbackMipImprovingSolution) { - if (dev_run) printf("userCallback(%11.4g): improving solution with objective = %g\n", local_callback_data, data_out->objective_function_value); + double objective_function_value = 0; + const HighsInt Og1697 = 0; + if (Og1697) { + objective_function_value = data_out->objective_function_value; + } else { + void* objective_function_value_void_p; + HighsInt status = Highs_getCallbackDataOutItem(data_out, "objective_function_value", objective_function_value_void_p); + assert(status == kHighsStatusOk); + double* objective_function_value_p = (double*)(objective_function_value_void_p); + const double lc_objective_function_value = *objective_function_value_p; + objective_function_value = *(double*)(objective_function_value_void_p); + } + if (dev_run) printf("userCallback(%11.4g): improving solution with objective = %g\n", local_callback_data, objective_function_value); } else if (callback_type == kHighsCallbackMipLogging) { if (dev_run) printf("userCallback(%11.4g): MIP logging\n", local_callback_data); data_in->user_interrupt = 1; @@ -1468,7 +1480,8 @@ void test_callback() { void* highs; highs = Highs_create(); - Highs_setBoolOptionValue(highs, "output_flag", dev_run); + //#1697 hack + Highs_setBoolOptionValue(highs, "output_flag", 0);//dev_run); Highs_passMip(highs, num_col, num_row, num_nz, a_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, @@ -1618,23 +1631,25 @@ void test_setSolution() { } */ int main() { - minimal_api_illegal_lp(); + //#1697 hack + // minimal_api_illegal_lp(); test_callback(); - version_api(); - full_api(); - minimal_api_lp(); - minimal_api_mip(); - minimal_api_qp(); - full_api_options(); - full_api_lp(); - full_api_mip(); - full_api_qp(); - pass_presolve_get_lp(); - options(); - test_getColsByRange(); - test_passHessian(); - test_ranging(); - test_getModel(); + // version_api(); + // full_api(); + // minimal_api_lp(); + // minimal_api_mip(); + // minimal_api_qp(); + // full_api_options(); + // full_api_lp(); + // full_api_mip(); + // full_api_qp(); + // pass_presolve_get_lp(); + // options(); + // test_getColsByRange(); + // test_passHessian(); + // test_ranging(); + // test_getModel(); + // test_setSolution(); return 0; } diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index be4b9f6183..0fc5b35699 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -688,7 +688,17 @@ double Highs_getRunTime(const void* highs) { return (double)((Highs*)highs)->getRunTime(); } -HighsInt Highs_zeroAllClocks(const void* highs) { +HighsInt Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name, void* item) { + HighsInt comparison = strcmp(item_name, "objective_function_value"); + printf("Highs_getCallbackDataOutItem: comparison = %d\n", int(comparison)); + if (!strcmp(item_name, "objective_function_value")) { + item = (void*)(&data_out->objective_function_value); + return kHighsStatusOk; + } + return kHighsStatusError; +} + + HighsInt Highs_zeroAllClocks(const void* highs) { ((Highs*)highs)->zeroAllClocks(); return (HighsInt)HighsStatus::kOk; } diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index 5816dee63b..4c29d8c6cb 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -1151,6 +1151,18 @@ HighsInt Highs_startCallback(void* highs, const int callback_type); */ HighsInt Highs_stopCallback(void* highs, const int callback_type); +/** + * Get a callback data item + * + * @param data_out A pointer to the HighsCallbackDataOut instance. + * @param item_name A pointer to the name of the item. + * @param item A pointer to the item. + * + * @returns A `kHighsStatus` constant indicating whether the call succeeded. + */ +HighsInt Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name, + void* item); + /** * Return the cumulative wall-clock time spent in `Highs_run`. * From 2481cd68f76ec2efcc98a72c25cdb66a6c11415c Mon Sep 17 00:00:00 2001 From: galabovaa Date: Fri, 3 May 2024 15:42:56 +0300 Subject: [PATCH 04/37] Delete HiGHS.sln --- HiGHS.sln | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 HiGHS.sln diff --git a/HiGHS.sln b/HiGHS.sln deleted file mode 100644 index 2b2af78bcf..0000000000 --- a/HiGHS.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.002.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Highs", "nuget\Highs.csproj", "{B5010BDA-D356-4C6E-915A-73D687AFFA3B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B5010BDA-D356-4C6E-915A-73D687AFFA3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5010BDA-D356-4C6E-915A-73D687AFFA3B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5010BDA-D356-4C6E-915A-73D687AFFA3B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5010BDA-D356-4C6E-915A-73D687AFFA3B}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8BD47AC6-90FE-4BAC-9FE1-A7E738E2C3B2} - EndGlobalSection -EndGlobal From 145fc4fb91242d3c9aa3efa6a63a803ae07759b6 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 15:55:21 +0300 Subject: [PATCH 05/37] deprecate compilation date --- check/TestCAPI.c | 3 ++- check/TestHighsVersion.cpp | 3 ++- examples/call_highs_from_c.c | 4 +++- examples/call_highs_from_c_minimal.c | 4 +++- src/Highs.h | 12 ++++++------ src/highs_bindings.cpp | 1 - src/interfaces/highs_c_api.cpp | 3 ++- src/interfaces/highs_c_api.h | 14 +++++++------- src/lp_data/Highs.cpp | 2 +- 9 files changed, 26 insertions(+), 20 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index c53823632a..534ea530a3 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -71,7 +71,8 @@ void version_api() { printf("HiGHS version minor %"HIGHSINT_FORMAT"\n", Highs_versionMinor()); printf("HiGHS version patch %"HIGHSINT_FORMAT"\n", Highs_versionPatch()); printf("HiGHS githash: %s\n", Highs_githash()); - printf("HiGHS compilation date %s\n", Highs_compilationDate()); + // Compilation date is deprecated. + // printf("HiGHS compilation date %s\n", Highs_compilationDate()); } } diff --git a/check/TestHighsVersion.cpp b/check/TestHighsVersion.cpp index da9d6015eb..6a133d1a03 100644 --- a/check/TestHighsVersion.cpp +++ b/check/TestHighsVersion.cpp @@ -22,7 +22,8 @@ TEST_CASE("HighsVersion", "[highs_version]") { printf("HiGHS minor version %d\n", int(minor)); printf("HiGHS patch version %d\n", int(patch)); printf("HiGHS githash: %s\n", highsGithash()); - printf("HiGHS compilation date: %s\n", highsCompilationDate()); + // Compilation date is deprecated. + // printf("HiGHS compilation date: %s\n", highsCompilationDate()); printf("HiGHS local version: %s\n", local_version.c_str()); } REQUIRE(major == HIGHS_VERSION_MAJOR); diff --git a/examples/call_highs_from_c.c b/examples/call_highs_from_c.c index 8d69108abb..6b89169f03 100644 --- a/examples/call_highs_from_c.c +++ b/examples/call_highs_from_c.c @@ -308,7 +308,9 @@ void full_api() { printf(" Minor version %" HIGHSINT_FORMAT "\n", Highs_versionMinor()); printf(" Patch version %" HIGHSINT_FORMAT "\n", Highs_versionPatch()); printf(" Githash %s\n", Highs_githash()); - printf(" compilation date %s\n", Highs_compilationDate()); + + // Compilation date is deprecated. + // printf(" compilation date %s\n", Highs_compilationDate()); // This example does exactly the same as the minimal example above, // but illustrates the full C API. It first forms and solves the LP // diff --git a/examples/call_highs_from_c_minimal.c b/examples/call_highs_from_c_minimal.c index 46561aceb2..7fd2490656 100644 --- a/examples/call_highs_from_c_minimal.c +++ b/examples/call_highs_from_c_minimal.c @@ -285,7 +285,9 @@ void full_api() { printf(" Minor version %" HIGHSINT_FORMAT "\n", Highs_versionMinor()); printf(" Patch version %" HIGHSINT_FORMAT "\n", Highs_versionPatch()); printf(" Githash %s\n", Highs_githash()); - printf(" compilation date %s\n", Highs_compilationDate()); + + // Compilation date is deprecated. + // printf(" compilation date %s\n", Highs_compilationDate()); // This example does exactly the same as the minimal example above, // but illustrates the full C API. It first forms and solves the LP // diff --git a/src/Highs.h b/src/Highs.h index 8bd4cd30b3..b7783e2289 100644 --- a/src/Highs.h +++ b/src/Highs.h @@ -37,7 +37,6 @@ HighsInt highsVersionMajor(); HighsInt highsVersionMinor(); HighsInt highsVersionPatch(); const char* highsGithash(); -const char* highsCompilationDate(); /** * @brief Class to set parameters and run HiGHS @@ -78,11 +77,6 @@ class Highs { */ std::string githash() const { return highsGithash(); } - /** - * @brief Return compilation date - */ - std::string compilationDate() const { return highsCompilationDate(); } - /** * @brief Reset the options and then call clearModel() */ @@ -1215,6 +1209,12 @@ class Highs { // Start of deprecated methods + /** + * @brief Return compilation date + */ + std::string compilationDate() const { return "deprecated"; } + const char* highsCompilationDate(); + HighsStatus setLogCallback(void (*user_log_callback)(HighsLogType, const char*, void*), void* user_log_callback_data = nullptr); diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index f6b5e8e802..1722e92f48 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -817,7 +817,6 @@ PYBIND11_MODULE(_core, m) { .def("versionMinor", &Highs::versionMinor) .def("versionPatch", &Highs::versionPatch) .def("githash", &Highs::githash) - .def("compilationDate", &Highs::compilationDate) .def("clear", &Highs::clear) .def("clearModel", &Highs::clearModel) .def("clearSolver", &Highs::clearSolver) diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index be4b9f6183..8651ff90d5 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -175,7 +175,6 @@ HighsInt Highs_versionMajor(void) { return highsVersionMajor(); } HighsInt Highs_versionMinor(void) { return highsVersionMinor(); } HighsInt Highs_versionPatch(void) { return highsVersionPatch(); } const char* Highs_githash(void) { return highsGithash(); } -const char* Highs_compilationDate(void) { return highsCompilationDate(); } HighsInt Highs_presolve(void* highs) { return (HighsInt)((Highs*)highs)->presolve(); @@ -1348,6 +1347,8 @@ void Highs_resetGlobalScheduler(HighsInt blocking) { // * Deprecated methods* // ********************* +const char* Highs_compilationDate(void) { return "Deprecated"; } + HighsInt Highs_call(const HighsInt num_col, const HighsInt num_row, const HighsInt num_nz, const double* col_cost, const double* col_lower, const double* col_upper, diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index 5816dee63b..78d3fd13fb 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -276,13 +276,6 @@ HighsInt Highs_versionPatch(void); */ const char* Highs_githash(void); -/** - * Return the HiGHS compilation date. - * - * @returns Thse HiGHS compilation date. - */ -const char* Highs_compilationDate(void); - /** * Read a model from `filename` into `highs`. * @@ -2162,6 +2155,13 @@ void Highs_resetGlobalScheduler(const HighsInt blocking); // * Deprecated methods* // ********************* +/** + * Return the HiGHS compilation date. + * + * @returns Thse HiGHS compilation date. + */ +const char* Highs_compilationDate(void); + // These are deprecated because they don't follow the style guide. Constants // must begin with `k`. const HighsInt HighsStatuskError = -1; diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index e68863c03b..5d66084b88 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -48,7 +48,7 @@ HighsInt highsVersionMajor() { return HIGHS_VERSION_MAJOR; } HighsInt highsVersionMinor() { return HIGHS_VERSION_MINOR; } HighsInt highsVersionPatch() { return HIGHS_VERSION_PATCH; } const char* highsGithash() { return HIGHS_GITHASH; } -const char* highsCompilationDate() { return HIGHS_COMPILATION_DATE; } +const char* highsCompilationDate() { return "deprecated"; } Highs::Highs() {} From b784629a76cbeb22a47aec2983d1123b7134bc0d Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 15:59:47 +0300 Subject: [PATCH 06/37] fix .cmake.in --- highs-config.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/highs-config.cmake.in b/highs-config.cmake.in index 5c6a81898b..2c0b3c3408 100644 --- a/highs-config.cmake.in +++ b/highs-config.cmake.in @@ -2,7 +2,7 @@ set(HIGHS_DIR "@HIGHS_INSTALL_DIR@") -if (FAST_BUILD) +if (@FAST_BUILD@) if(NOT TARGET highs) include("${CMAKE_CURRENT_LIST_DIR}/highs-targets.cmake") endif() From ab766f8e0e287bfc876755b92981ce717933bdba Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 16:27:33 +0300 Subject: [PATCH 07/37] add rpath to binary --- app/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index d4c2af8a8c..0363d7dcab 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -29,6 +29,14 @@ if(FAST_BUILD) target_link_libraries(highs-bin highs) + if(APPLE) + set_target_properties(highs-bin PROPERTIES INSTALL_RPATH + "@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path") + elseif (UNIX) + set_target_properties(highs-bin PROPERTIES INSTALL_RPATH + "$ORIGIN:$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") + endif() + # install the binary install(TARGETS highs-bin EXPORT highs-targets RUNTIME) From 44f519121279406f9a7ae00dc3cf3dfbc470fe24 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 21:40:58 +0300 Subject: [PATCH 08/37] add iteration counts for mac arm to cmake tests --- check/CMakeLists.txt | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index 5370a90b6a..b0b76b5488 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -170,6 +170,20 @@ if (NOT FAST_BUILD OR ALL_TESTS) "standgub\;68\; 1.2576995000\;" "standmps\;218\; 1.4060175000\;" ) + + set(successMacArmInstances + "25fv47\;3103\; 5.5018458883\;" + "80bau3b\;3705\; 9.8722419241\;" + "adlittle\;74\; 2.2549496316\;" + "afiro\;22\;-4.6475314286\;" + "etamacro\;531\;-7.5571523330\;" + "greenbea\;5156\;-7.2555248130\;" + "shell\;623\; 1.2088253460\;" + "stair\;531\;-2.5126695119\;" + "standata\;72\; 1.2576995000\;" + "standgub\;68\; 1.2576995000\;" + "standmps\;218\; 1.4060175000\;" + ) set(infeasibleInstances "bgetam\; infeasible" @@ -269,8 +283,21 @@ if (NOT FAST_BUILD OR ALL_TESTS) endforeach(instance) endmacro(add_instancetests) + message(STATUS APPLE) +# if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")) + if (APPLE) + message(STATUS "yapplessss") + endif() + + # add tests for success and fail instances - add_instancetests(successInstances "Optimal") + if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")) + add_instancetests(successMacArmInstances "Optimal") + message(STATUS "yyyyyy") + else() + add_instancetests(successInstances "Optimal") + endif() + add_instancetests(failInstances "Fail") add_instancetests(infeasibleInstances "Infeasible") #add_instancetests(unboundedInstances "Unbounded") From bc58794588501894ecb4257b214e2a8201f9b7ae Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 21:46:48 +0300 Subject: [PATCH 09/37] workflow action version --- .github/workflows/build-meson.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-meson.yml b/.github/workflows/build-meson.yml index b6c22c2674..f55b678e87 100644 --- a/.github/workflows/build-meson.yml +++ b/.github/workflows/build-meson.yml @@ -16,6 +16,7 @@ jobs: - name: Install Conda environment uses: mamba-org/setup-micromamba@v1 with: + micromamba-version: '1.8.1-0' environment-name: highsdev create-args: >- python==3.8 From fdff2a2407255f2a1f9f3d106916c1cd45e17393 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 21:51:29 +0300 Subject: [PATCH 10/37] system packages --- .github/workflows/build-python-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 3ef5c6d4cf..40bc12bd0f 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -55,11 +55,11 @@ jobs: - name: Install correct python version uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: '3.9' - name: Build sdist run: | - python -m pip install build + python -m pip install build --break-system-packages python -m build --sdist - name: Install sdist From 159be58b0567574ffe74646f85d02415ff35b77f Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 21:53:22 +0300 Subject: [PATCH 11/37] to mac test --- .github/workflows/build-python-package.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 40bc12bd0f..b54d4cae31 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -34,7 +34,7 @@ jobs: - name: Build sdist run: | - python3 -m pip install build + python3 -m pip install build --break-system-packages python3 -m build --sdist - name: Install sdist @@ -55,11 +55,11 @@ jobs: - name: Install correct python version uses: actions/setup-python@v5 with: - python-version: '3.9' + python-version: 3.9 - name: Build sdist run: | - python -m pip install build --break-system-packages + python -m pip install build python -m build --sdist - name: Install sdist From aba519e392440d0cbf6972bdff2a347bd81f772e Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 21:56:54 +0300 Subject: [PATCH 12/37] user --- .github/workflows/build-python-package.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index b54d4cae31..bd74c0204b 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -34,17 +34,17 @@ jobs: - name: Build sdist run: | - python3 -m pip install build --break-system-packages + python3 -m pip install build --user python3 -m build --sdist - name: Install sdist run: | ls dist - python3 -m pip install dist/*.tar.gz + python3 -m pip install dist/*.tar.gza --user - name: Test highspy run: | - python3 -m pip install pytest + python3 -m pip install pytest --user python3 -m pytest $GITHUB_WORKSPACE build_sdist_win: From cf9ccb3ef67212366e96c97a46fb3c69d1aa034b Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 21:59:20 +0300 Subject: [PATCH 13/37] setup python --- .github/workflows/build-meson.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-meson.yml b/.github/workflows/build-meson.yml index f55b678e87..a9b27ceec8 100644 --- a/.github/workflows/build-meson.yml +++ b/.github/workflows/build-meson.yml @@ -13,6 +13,12 @@ jobs: with: submodules: "recursive" fetch-depth: 0 + + - name: Install correct python version + uses: actions/setup-python@v5 + with: + python-version: '3.8' + - name: Install Conda environment uses: mamba-org/setup-micromamba@v1 with: From 7274db65e2d42e70fc34632e839d1d1f91b4d705 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:04:06 +0300 Subject: [PATCH 14/37] sdist --- .github/workflows/build-python-package.yml | 6 +++--- check/CMakeLists.txt | 8 -------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index bd74c0204b..a2da18c804 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -34,17 +34,17 @@ jobs: - name: Build sdist run: | - python3 -m pip install build --user + python3 -m pip install build --break-system-packages python3 -m build --sdist - name: Install sdist run: | ls dist - python3 -m pip install dist/*.tar.gza --user + python3 -m pip install dist/*.tar.gza - name: Test highspy run: | - python3 -m pip install pytest --user + python3 -m pip install pytest python3 -m pytest $GITHUB_WORKSPACE build_sdist_win: diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index b0b76b5488..0367e593be 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -283,17 +283,9 @@ if (NOT FAST_BUILD OR ALL_TESTS) endforeach(instance) endmacro(add_instancetests) - message(STATUS APPLE) -# if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")) - if (APPLE) - message(STATUS "yapplessss") - endif() - - # add tests for success and fail instances if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")) add_instancetests(successMacArmInstances "Optimal") - message(STATUS "yyyyyy") else() add_instancetests(successInstances "Optimal") endif() From ffaa38bb3712396db01ce48203ad16ff9e716745 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:05:13 +0300 Subject: [PATCH 15/37] install --- .github/workflows/build-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index a2da18c804..0cb4e345d2 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -40,7 +40,7 @@ jobs: - name: Install sdist run: | ls dist - python3 -m pip install dist/*.tar.gza + python3 -m pip install dist/*.tar.gza --break-system-packages - name: Test highspy run: | From 05c9df3cd1f042ed3fac5541fb83d59ef8e6d9ea Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:14:00 +0300 Subject: [PATCH 16/37] fix typo --- .github/workflows/build-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index 0cb4e345d2..e64fa5910a 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -40,7 +40,7 @@ jobs: - name: Install sdist run: | ls dist - python3 -m pip install dist/*.tar.gza --break-system-packages + python3 -m pip install dist/*.tar.gz --break-system-packages - name: Test highspy run: | From 6ab3873f57b4e8337550e23e382adf6980a9a8be Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:16:32 +0300 Subject: [PATCH 17/37] testing --- .github/workflows/build-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-python-package.yml b/.github/workflows/build-python-package.yml index e64fa5910a..6de25261d1 100644 --- a/.github/workflows/build-python-package.yml +++ b/.github/workflows/build-python-package.yml @@ -44,7 +44,7 @@ jobs: - name: Test highspy run: | - python3 -m pip install pytest + python3 -m pip install pytest --break-system-packages python3 -m pytest $GITHUB_WORKSPACE build_sdist_win: From 3306a87d0c82e9d216e161b307c989f960c584b8 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:17:45 +0300 Subject: [PATCH 18/37] mamba python version --- .github/workflows/build-meson.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-meson.yml b/.github/workflows/build-meson.yml index a9b27ceec8..6974138618 100644 --- a/.github/workflows/build-meson.yml +++ b/.github/workflows/build-meson.yml @@ -17,7 +17,7 @@ jobs: - name: Install correct python version uses: actions/setup-python@v5 with: - python-version: '3.8' + python-version: '3.9' - name: Install Conda environment uses: mamba-org/setup-micromamba@v1 @@ -25,7 +25,7 @@ jobs: micromamba-version: '1.8.1-0' environment-name: highsdev create-args: >- - python==3.8 + python==3.9 meson pkgconfig ninja From 905dbb87af80aa5557de403d7265cb64b2807cf3 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:27:05 +0300 Subject: [PATCH 19/37] workaround meson mamba --- .github/workflows/build-meson.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-meson.yml b/.github/workflows/build-meson.yml index 6974138618..089d63aac7 100644 --- a/.github/workflows/build-meson.yml +++ b/.github/workflows/build-meson.yml @@ -7,22 +7,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] # windows-latest takes to long + # macos-latest issue with micromamba action + # windows-latest takes to long + os: [ubuntu-latest] steps: - uses: actions/checkout@v4 with: submodules: "recursive" fetch-depth: 0 - - name: Install correct python version - uses: actions/setup-python@v5 - with: - python-version: '3.9' - - name: Install Conda environment uses: mamba-org/setup-micromamba@v1 with: - micromamba-version: '1.8.1-0' environment-name: highsdev create-args: >- python==3.9 From ee940fc1d230fce8e8b15c63a453e86366fad953 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:28:36 +0300 Subject: [PATCH 20/37] python version --- .github/workflows/build-meson.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-meson.yml b/.github/workflows/build-meson.yml index 089d63aac7..f1bef1f5eb 100644 --- a/.github/workflows/build-meson.yml +++ b/.github/workflows/build-meson.yml @@ -21,7 +21,7 @@ jobs: with: environment-name: highsdev create-args: >- - python==3.9 + python==3.8 meson pkgconfig ninja From 009ac45a7fe362ca9f1de5ab2b132b1051e38a9f Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Fri, 3 May 2024 22:53:07 +0300 Subject: [PATCH 21/37] check python package --- .github/workflows/check-python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-python-package.yml b/.github/workflows/check-python-package.yml index d5dc93cbf4..3d7462cc40 100644 --- a/.github/workflows/check-python-package.yml +++ b/.github/workflows/check-python-package.yml @@ -26,7 +26,7 @@ jobs: - name: Build sdist run: | - python3 -m pip install build setuptools twine + python3 -m pip install build setuptools twine --break-system-packages python3 -m build --sdist python3 -m build --wheel twine check dist/* From 9038435641a18427f6ca65f56b4f0c90f6a60069 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Sat, 4 May 2024 13:38:01 +0300 Subject: [PATCH 22/37] remove more dates --- CMakeLists.txt | 5 +++-- src/HConfig.h.bazel.in | 1 - src/HConfig.h.in | 1 - src/HConfig.h.meson.in | 1 - src/meson.build | 36 +++++++++++++++++++++--------------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1c7373bb3..2dd88b3e97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,8 +384,9 @@ else() endif() message(STATUS "Git hash: " ${GITHASH}) -string(TIMESTAMP TODAY "%Y-%m-%d") -message(STATUS "Compilation date: " ${TODAY}) +# Deprecate +# string(TIMESTAMP TODAY "%Y-%m-%d") +# message(STATUS "Compilation date: " ${TODAY}) configure_file(${HIGHS_SOURCE_DIR}/src/HConfig.h.in ${HIGHS_BINARY_DIR}/HConfig.h) diff --git a/src/HConfig.h.bazel.in b/src/HConfig.h.bazel.in index 3b395dc8b4..d6cd6003fa 100644 --- a/src/HConfig.h.bazel.in +++ b/src/HConfig.h.bazel.in @@ -12,7 +12,6 @@ /* #undef HIGHS_HAVE_BITSCAN_REVERSE */ #define HIGHS_GITHASH "50670fd4c" -#define HIGHS_COMPILATION_DATE "2024-03-07" #define HIGHS_VERSION_MAJOR 1 #define HIGHS_VERSION_MINOR 7 #define HIGHS_VERSION_PATCH 0 diff --git a/src/HConfig.h.in b/src/HConfig.h.in index 3e5f873674..198e07b0d3 100644 --- a/src/HConfig.h.in +++ b/src/HConfig.h.in @@ -13,7 +13,6 @@ #cmakedefine HIGHS_HAVE_BITSCAN_REVERSE #define HIGHS_GITHASH "@GITHASH@" -#define HIGHS_COMPILATION_DATE "@TODAY@" #define HIGHS_VERSION_MAJOR @HIGHS_VERSION_MAJOR@ #define HIGHS_VERSION_MINOR @HIGHS_VERSION_MINOR@ #define HIGHS_VERSION_PATCH @HIGHS_VERSION_PATCH@ diff --git a/src/HConfig.h.meson.in b/src/HConfig.h.meson.in index 47faf75410..7b2fb3318c 100644 --- a/src/HConfig.h.meson.in +++ b/src/HConfig.h.meson.in @@ -10,7 +10,6 @@ #mesondefine HIGHS_HAVE_BITSCAN_REVERSE #define HIGHS_GITHASH "_HIGHS_GITHASH_" -#define HIGHS_COMPILATION_DATE @HIGHS_COMPILATION_DATE@ #define HIGHS_VERSION_MAJOR @HIGHS_VERSION_MAJOR@ #define HIGHS_VERSION_MINOR @HIGHS_VERSION_MINOR@ #define HIGHS_VERSION_PATCH @HIGHS_VERSION_PATCH@ diff --git a/src/meson.build b/src/meson.build index 864c44e9ce..7fa9dd9a51 100644 --- a/src/meson.build +++ b/src/meson.build @@ -30,22 +30,28 @@ import datetime import os import time -build_date = datetime.datetime.utcfromtimestamp( - int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) -) -build_date_str = build_date.strftime('%Y-%m-%d') -print(build_date_str) - ''' - # Note: this is not guaranteed to work on Windows. This should be removed - # (as proposed in gh-1735), and otherwise moved into a .py script with - # a `#!/usr/bin/env python3` shebang, and `python3 -c` dropped. - today_cmd = run_command('python3', '-c', - python_getdate, - check: false) - today_str = today_cmd.stdout().strip() -endif +# (ig) +# Deprecate compilation date + +# build_date = datetime.datetime.utcfromtimestamp( +# int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) +# ) +# build_date_str = build_date.strftime('%Y-%m-%d') +# print(build_date_str) +# ''' +# # Note: this is not guaranteed to work on Windows. This should be removed +# # (as proposed in gh-1735), and otherwise moved into a .py script with +# # a `#!/usr/bin/env python3` shebang, and `python3 -c` dropped. +# today_cmd = run_command('python3', '-c', +# python_getdate, +# check: false) +# today_str = today_cmd.stdout().strip() +# endif +# conf_data.set_quoted('HIGHS_COMPILATION_DATE', +# today_str) + conf_data.set_quoted('HIGHS_COMPILATION_DATE', - today_str) + "deprecated") # Conditional compiler options _mm_pause_code = ''' From 2df7f7f9a63b1ce257fadea9f9feb52dc4f3731a Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Sat, 4 May 2024 13:40:47 +0300 Subject: [PATCH 23/37] meson single quotes --- src/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meson.build b/src/meson.build index 7fa9dd9a51..5d8bdbb5f1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -51,7 +51,7 @@ import time # today_str) conf_data.set_quoted('HIGHS_COMPILATION_DATE', - "deprecated") + 'deprecated') # Conditional compiler options _mm_pause_code = ''' From 3b07c85ba5fe1762ddd236d506ead13a956d145b Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Sat, 4 May 2024 14:20:14 +0300 Subject: [PATCH 24/37] remove datetime from meson build --- src/meson.build | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/meson.build b/src/meson.build index 5d8bdbb5f1..61dd94f9e7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -23,12 +23,12 @@ else conf_data.set('HIGHSINT64', false) endif # Date -today_str = 'unknown' -if (not meson.is_subproject()) - python_getdate = ''' -import datetime -import os -import time +# today_str = 'unknown' +# if (not meson.is_subproject()) +# python_getdate = ''' +# import datetime +# import os +# import time # (ig) # Deprecate compilation date From 05ade6b29ae946c95cc4588906b822c45416e7fc Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 09:31:13 +0100 Subject: [PATCH 25/37] Now returning const void* from Highs_getCallbackDataOutItem --- check/TestCAPI.c | 5 ++--- src/interfaces/highs_c_api.cpp | 9 +++++---- src/interfaces/highs_c_api.h | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 1870d91c76..2f9c4366e8 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -27,9 +27,8 @@ static void userCallback(const int callback_type, const char* message, if (Og1697) { objective_function_value = data_out->objective_function_value; } else { - void* objective_function_value_void_p; - HighsInt status = Highs_getCallbackDataOutItem(data_out, "objective_function_value", objective_function_value_void_p); - assert(status == kHighsStatusOk); + const void* objective_function_value_void_p = + Highs_getCallbackDataOutItem(data_out, "objective_function_value"); double* objective_function_value_p = (double*)(objective_function_value_void_p); const double lc_objective_function_value = *objective_function_value_p; objective_function_value = *(double*)(objective_function_value_void_p); diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index 0fc5b35699..0b2a0d4317 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -688,14 +688,15 @@ double Highs_getRunTime(const void* highs) { return (double)((Highs*)highs)->getRunTime(); } -HighsInt Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name, void* item) { +const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name) { HighsInt comparison = strcmp(item_name, "objective_function_value"); printf("Highs_getCallbackDataOutItem: comparison = %d\n", int(comparison)); if (!strcmp(item_name, "objective_function_value")) { - item = (void*)(&data_out->objective_function_value); - return kHighsStatusOk; + const double* objective_function_value_p = &data_out->objective_function_value; + const void* void_p = (void*)(objective_function_value_p); + return void_p; } - return kHighsStatusError; + return nullptr; } HighsInt Highs_zeroAllClocks(const void* highs) { diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index 4c29d8c6cb..431a89a431 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -1160,8 +1160,7 @@ HighsInt Highs_stopCallback(void* highs, const int callback_type); * * @returns A `kHighsStatus` constant indicating whether the call succeeded. */ -HighsInt Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name, - void* item); +const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name); /** * Return the cumulative wall-clock time spent in `Highs_run`. From 28eb9e8d6779a6181740baa2765d08233aaf3bda Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 09:45:12 +0100 Subject: [PATCH 26/37] Titdied up and keeping things simple by taking nullptr return as error --- check/TestCAPI.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 2f9c4366e8..1ad1a7716a 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -22,18 +22,11 @@ static void userCallback(const int callback_type, const char* message, if (callback_type == kHighsCallbackLogging) { if (dev_run) printf("userCallback(%11.4g): %s\n", local_callback_data, message); } else if (callback_type == kHighsCallbackMipImprovingSolution) { - double objective_function_value = 0; - const HighsInt Og1697 = 0; - if (Og1697) { - objective_function_value = data_out->objective_function_value; - } else { - const void* objective_function_value_void_p = + const void* objective_function_value_p = Highs_getCallbackDataOutItem(data_out, "objective_function_value"); - double* objective_function_value_p = (double*)(objective_function_value_void_p); - const double lc_objective_function_value = *objective_function_value_p; - objective_function_value = *(double*)(objective_function_value_void_p); - } - if (dev_run) printf("userCallback(%11.4g): improving solution with objective = %g\n", local_callback_data, objective_function_value); + assert(objective_function_value_p); + if (dev_run) printf("userCallback(%11.4g): improving solution with objective = %g\n", + local_callback_data, *(double*)(objective_function_value_p)); } else if (callback_type == kHighsCallbackMipLogging) { if (dev_run) printf("userCallback(%11.4g): MIP logging\n", local_callback_data); data_in->user_interrupt = 1; From 989b3a1f57119bf8a37944536ca50edea384f722 Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 11:20:28 +0100 Subject: [PATCH 27/37] Now checking all members of data_out --- check/TestCAPI.c | 136 ++++++++++++++++++++++++++++++++- src/interfaces/highs_c_api.cpp | 47 ++++++++++-- src/interfaces/highs_c_api.h | 27 ++++++- 3 files changed, 198 insertions(+), 12 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 1ad1a7716a..39c453cefe 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -12,6 +12,74 @@ const HighsInt dev_run = 1; const double double_equal_tolerance = 1e-5; +void checkGetCallbackDataOutPointer(const HighsCallbackDataOut* data_out, const char* name, HighsInt valid) { + const void* name_p = Highs_getCallbackDataOutItem(data_out, name); + if (valid) { + if (!name_p) printf("checkGetCallbackDataOutItem fail for %s (valid = %d)\n", name, (int)valid); + assert(name_p); + } else { + if (name_p) printf("checkGetCallbackDataOutItem fail for %s (valid = %d)\n", + name, (int)valid); + assert(!name_p); + } +} + +void checkGetCallbackDataOutHighsInt(const HighsCallbackDataOut* data_out, const char* name, HighsInt value) { + const void* name_p = Highs_getCallbackDataOutItem(data_out, name); + if (!name_p) { + printf("checkGetCallbackDataOutItem fail for %s\n", name); + assert(name_p); + } else { + HighsInt check_value = *(HighsInt*)(name_p); + HighsInt value_ok = check_value == value; + if (!value_ok) printf("checkGetCallbackDataOutItem fail for %s (%d = check_value != value = %d)\n", + name, (int)check_value, (int)value); + assert(value_ok); + } +} + +void checkGetCallbackDataOutInt(const HighsCallbackDataOut* data_out, const char* name, int value) { + const void* name_p = Highs_getCallbackDataOutItem(data_out, name); + if (!name_p) { + printf("checkGetCallbackDataOutInt fail for %s\n", name); + assert(name_p); + } else { + int check_value = *(int*)(name_p); + int value_ok = check_value == value; + if (!value_ok) printf("checkGetCallbackDataOutInt fail for %s (%d = check_value != value = %d)\n", + name, check_value, value); + assert(value_ok); + } +} + +void checkGetCallbackDataOutInt64(const HighsCallbackDataOut* data_out, const char* name, int64_t value) { + const void* name_p = Highs_getCallbackDataOutItem(data_out, name); + if (!name_p) { + printf("checkGetCallbackDataOutInt64 fail for %s\n", name); + assert(name_p); + } else { + int64_t check_value = *(int*)(name_p); + int value_ok = check_value == value; + if (!value_ok) printf("checkGetCallbackDataOutInt64 fail for %s (%d = check_value != value = %d)\n", + name, (int)check_value, (int)value); + assert(value_ok); + } +} + +void checkGetCallbackDataOutDouble(const HighsCallbackDataOut* data_out, const char* name, double value) { + const void* name_p = Highs_getCallbackDataOutItem(data_out, name); + if (!name_p) { + printf("checkGetCallbackDataOutDouble fail for %s\n", name); + assert(name_p); + } else { + double check_value = *(double*)(name_p); + double value_ok = check_value == value; + if (!value_ok) printf("checkGetCallbackDataOutDouble fail for %s (%g = check_value != value = %g)\n", + name, check_value, value); + assert(value_ok); + } +} + static void userCallback(const int callback_type, const char* message, const HighsCallbackDataOut* data_out, HighsCallbackDataIn* data_in, @@ -22,11 +90,75 @@ static void userCallback(const int callback_type, const char* message, if (callback_type == kHighsCallbackLogging) { if (dev_run) printf("userCallback(%11.4g): %s\n", local_callback_data, message); } else if (callback_type == kHighsCallbackMipImprovingSolution) { + // Test the accessor function for data_out + // + // Check that passing an valid name returns a non-null pointer, + // and that the corresponding value is the same as obtained using + // the struct const void* objective_function_value_p = - Highs_getCallbackDataOutItem(data_out, "objective_function_value"); + Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutObjectiveFunctionValueName); assert(objective_function_value_p); + double objective_function_value = *(double*)(objective_function_value_p); + assert(objective_function_value == data_out->objective_function_value); if (dev_run) printf("userCallback(%11.4g): improving solution with objective = %g\n", - local_callback_data, *(double*)(objective_function_value_p)); + local_callback_data, objective_function_value); + // Now test all more simply + checkGetCallbackDataOutInt(data_out, + kHighsCallbackDataOutLogTypeName, -1); + checkGetCallbackDataOutDouble(data_out, + kHighsCallbackDataOutRunningTimeName, + data_out->running_time); + checkGetCallbackDataOutHighsInt(data_out, + kHighsCallbackDataOutSimplexIterationCountName, + data_out->simplex_iteration_count); + checkGetCallbackDataOutHighsInt(data_out, + kHighsCallbackDataOutIpmIterationCountName, + data_out->ipm_iteration_count); + checkGetCallbackDataOutHighsInt(data_out, + kHighsCallbackDataOutPdlpIterationCountName, + data_out->pdlp_iteration_count); + checkGetCallbackDataOutDouble(data_out, + kHighsCallbackDataOutObjectiveFunctionValueName, + data_out->objective_function_value); + checkGetCallbackDataOutInt64(data_out, + kHighsCallbackDataOutMipNodeCountName, + data_out->mip_node_count); + checkGetCallbackDataOutDouble(data_out, + kHighsCallbackDataOutMipPrimalBoundName, + data_out->mip_primal_bound); + checkGetCallbackDataOutDouble(data_out, + kHighsCallbackDataOutMipDualBoundName, + data_out->mip_dual_bound); + checkGetCallbackDataOutDouble(data_out, + kHighsCallbackDataOutMipGapName, + data_out->mip_gap); + checkGetCallbackDataOutHighsInt(data_out, + kHighsCallbackDataOutCutpoolNumColName, 0); + checkGetCallbackDataOutHighsInt(data_out, + kHighsCallbackDataOutCutpoolNumCutName, 0); + checkGetCallbackDataOutHighsInt(data_out, + kHighsCallbackDataOutCutpoolNumNzName, 0); + + // Check that passing an unrecognised name returns NULL + const void* foo_p = Highs_getCallbackDataOutItem(data_out, "foo"); + assert(!foo_p); + // Check that passing the name of an assigned vector returns + // non-NULL, and that the corresponding value is the same as + // obtained using the struct + const void* mip_solution_void_p = + Highs_getCallbackDataOutItem(data_out, + kHighsCallbackDataOutMipSolutionName); + assert(mip_solution_void_p); + double mip_solution0 = *(double*)(mip_solution_void_p); + assert(mip_solution0 == *(data_out->mip_solution)); + if (dev_run) printf("userCallback(%11.4g): improving solution with value[0] = %g\n", + local_callback_data, mip_solution0); + // Check that passing names of the unassigned vectors returns NULL + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolStartName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolIndexName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolValueName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolLowerName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolUpperName)); } else if (callback_type == kHighsCallbackMipLogging) { if (dev_run) printf("userCallback(%11.4g): MIP logging\n", local_callback_data); data_in->user_interrupt = 1; diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index 0b2a0d4317..4614d037d6 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -689,12 +689,47 @@ double Highs_getRunTime(const void* highs) { } const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name) { - HighsInt comparison = strcmp(item_name, "objective_function_value"); - printf("Highs_getCallbackDataOutItem: comparison = %d\n", int(comparison)); - if (!strcmp(item_name, "objective_function_value")) { - const double* objective_function_value_p = &data_out->objective_function_value; - const void* void_p = (void*)(objective_function_value_p); - return void_p; + // Accessor function for HighsCallbackDataOut + // + // Remember that pointers in HighsCallbackDataOut don't need to be referenced! + if (!strcmp(item_name, kHighsCallbackDataOutLogTypeName)) { + return (void*)(&data_out->log_type); + } else if (!strcmp(item_name, kHighsCallbackDataOutRunningTimeName)) { + return (void*)(&data_out->running_time); + } else if (!strcmp(item_name, kHighsCallbackDataOutSimplexIterationCountName)) { + return (void*)(&data_out->simplex_iteration_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutIpmIterationCountName)) { + return (void*)(&data_out->ipm_iteration_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutPdlpIterationCountName)) { + return (void*)(&data_out->pdlp_iteration_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutObjectiveFunctionValueName)) { + return (void*)(&data_out->objective_function_value); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipNodeCountName)) { + return (void*)(&data_out->mip_node_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipPrimalBoundName)) { + return (void*)(&data_out->mip_primal_bound); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipDualBoundName)) { + return (void*)(&data_out->mip_dual_bound); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipGapName)) { + return (void*)(&data_out->mip_gap); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipSolutionName)) { + return (void*)(data_out->mip_solution); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumColName)) { + return (void*)(&data_out->cutpool_num_col); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumCutName)) { + return (void*)(&data_out->cutpool_num_cut); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumNzName)) { + return (void*)(&data_out->cutpool_num_nz); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolStartName)) { + return (void*)(data_out->cutpool_start); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolIndexName)) { + return (void*)(data_out->cutpool_index); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolValueName)) { + return (void*)(data_out->cutpool_value); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolLowerName)) { + return (void*)(data_out->cutpool_lower); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolUpperName)) { + return (void*)(data_out->cutpool_upper); } return nullptr; } diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index 431a89a431..39fac84a52 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -108,6 +108,26 @@ const HighsInt kHighsCallbackMipInterrupt = 6; const HighsInt kHighsCallbackMipGetCutPool = 7; const HighsInt kHighsCallbackMipDefineLazyConstraints = 8; +const char* kHighsCallbackDataOutLogTypeName = "log_type"; +const char* kHighsCallbackDataOutRunningTimeName = "running_time"; +const char* kHighsCallbackDataOutSimplexIterationCountName = "simplex_iteration_count"; +const char* kHighsCallbackDataOutIpmIterationCountName = "ipm_iteration_count"; +const char* kHighsCallbackDataOutPdlpIterationCountName = "pdlp_iteration_count"; +const char* kHighsCallbackDataOutObjectiveFunctionValueName = "objective_function_value"; +const char* kHighsCallbackDataOutMipNodeCountName = "mip_node_count"; +const char* kHighsCallbackDataOutMipPrimalBoundName = "mip_primal_bound"; +const char* kHighsCallbackDataOutMipDualBoundName = "mip_dual_bound"; +const char* kHighsCallbackDataOutMipGapName = "mip_gap"; +const char* kHighsCallbackDataOutMipSolutionName = "mip_solution"; +const char* kHighsCallbackDataOutCutpoolNumColName = "cutpool_num_col"; +const char* kHighsCallbackDataOutCutpoolNumCutName = "cutpool_num_cut"; +const char* kHighsCallbackDataOutCutpoolNumNzName = "cutpool_num_nz"; +const char* kHighsCallbackDataOutCutpoolStartName = "cutpool_start"; +const char* kHighsCallbackDataOutCutpoolIndexName = "cutpool_index"; +const char* kHighsCallbackDataOutCutpoolValueName = "cutpool_value"; +const char* kHighsCallbackDataOutCutpoolLowerName = "cutpool_lower"; +const char* kHighsCallbackDataOutCutpoolUpperName = "cutpool_upper"; + #ifdef __cplusplus extern "C" { #endif @@ -1152,13 +1172,12 @@ HighsInt Highs_startCallback(void* highs, const int callback_type); HighsInt Highs_stopCallback(void* highs, const int callback_type); /** - * Get a callback data item + * Get a void* pointer to a callback data item * * @param data_out A pointer to the HighsCallbackDataOut instance. - * @param item_name A pointer to the name of the item. - * @param item A pointer to the item. + * @param item_name The name of the item. * - * @returns A `kHighsStatus` constant indicating whether the call succeeded. + * @returns A void* pointer to the callback data item, or NULL if item_name not valid */ const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name); From bbc12674286ffb739d00c26653824a3dba061e74 Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 11:56:08 +0100 Subject: [PATCH 28/37] Removed temporary dev hacks --- check/TestCAPI.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 30bd8c8d4d..551e42c7eb 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -9,7 +9,7 @@ #include #include -const HighsInt dev_run = 1; +const HighsInt dev_run = 0; const double double_equal_tolerance = 1e-5; void checkGetCallbackDataOutPointer(const HighsCallbackDataOut* data_out, const char* name, HighsInt valid) { @@ -1605,8 +1605,7 @@ void test_callback() { void* highs; highs = Highs_create(); - //#1697 hack - Highs_setBoolOptionValue(highs, "output_flag", 0);//dev_run); + Highs_setBoolOptionValue(highs, "output_flag", dev_run); Highs_passMip(highs, num_col, num_row, num_nz, a_format, sense, offset, col_cost, col_lower, col_upper, row_lower, row_upper, @@ -1756,25 +1755,23 @@ void test_setSolution() { } */ int main() { - //#1697 hack - // minimal_api_illegal_lp(); - test_callback(); - // version_api(); - // full_api(); - // minimal_api_lp(); - // minimal_api_mip(); - // minimal_api_qp(); - // full_api_options(); - // full_api_lp(); - // full_api_mip(); - // full_api_qp(); - // pass_presolve_get_lp(); - // options(); - // test_getColsByRange(); - // test_passHessian(); - // test_ranging(); - // test_getModel(); - + minimal_api_illegal_lp(); + test_callback(); + version_api(); + full_api(); + minimal_api_lp(); + minimal_api_mip(); + minimal_api_qp(); + full_api_options(); + full_api_lp(); + full_api_mip(); + full_api_qp(); + pass_presolve_get_lp(); + options(); + test_getColsByRange(); + test_passHessian(); + test_ranging(); + test_getModel(); // test_setSolution(); return 0; } From 56836d034a6210458ed8685f37667a116b896827 Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 18:05:56 +0100 Subject: [PATCH 29/37] Now switching the use of constant definitions of CallbackDataOut item names via #define USE_CallbackDataOut_NAME --- check/TestCAPI.c | 151 ++++++++++++++++++++++++++----- src/interfaces/highs_c_api.cpp | 157 ++++++++++++++++++++++++++++----- src/interfaces/highs_c_api.h | 18 ++-- 3 files changed, 280 insertions(+), 46 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 551e42c7eb..551f04accb 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -91,12 +91,23 @@ static void userCallback(const int callback_type, const char* message, if (dev_run) printf("userCallback(%11.4g): %s\n", local_callback_data, message); } else if (callback_type == kHighsCallbackMipImprovingSolution) { // Test the accessor function for data_out +#ifdef USE_CallbackDataOut_NAME + if (dev_run) printf("Using constant definitions of CallbackDataOut item names\n"); +#else + if (dev_run) printf("Using explicit CallbackDataOut item names\n"); +#endif // // Check that passing an valid name returns a non-null pointer, // and that the corresponding value is the same as obtained using // the struct const void* objective_function_value_p = - Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutObjectiveFunctionValueName); + Highs_getCallbackDataOutItem(data_out, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutObjectiveFunctionValueName +#else + "objective_function_value" +#endif + ); assert(objective_function_value_p); double objective_function_value = *(double*)(objective_function_value_p); assert(objective_function_value == data_out->objective_function_value); @@ -104,40 +115,105 @@ static void userCallback(const int callback_type, const char* message, local_callback_data, objective_function_value); // Now test all more simply checkGetCallbackDataOutInt(data_out, - kHighsCallbackDataOutLogTypeName, -1); +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutLogTypeName +#else + "log_type" +#endif + , -1); checkGetCallbackDataOutDouble(data_out, - kHighsCallbackDataOutRunningTimeName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutRunningTimeName +#else + "running_time" +#endif + , data_out->running_time); checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutSimplexIterationCountName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutSimplexIterationCountName +#else + "simplex_iteration_count" +#endif + , data_out->simplex_iteration_count); checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutIpmIterationCountName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutIpmIterationCountName +#else + "ipm_iteration_count" +#endif + , data_out->ipm_iteration_count); checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutPdlpIterationCountName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutPdlpIterationCountName +#else + "pdlp_iteration_count" +#endif + , data_out->pdlp_iteration_count); checkGetCallbackDataOutDouble(data_out, - kHighsCallbackDataOutObjectiveFunctionValueName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutObjectiveFunctionValueName +#else + "objective_function_value" +#endif + , data_out->objective_function_value); checkGetCallbackDataOutInt64(data_out, - kHighsCallbackDataOutMipNodeCountName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipNodeCountName +#else + "mip_node_count" +#endif + , data_out->mip_node_count); checkGetCallbackDataOutDouble(data_out, - kHighsCallbackDataOutMipPrimalBoundName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipPrimalBoundName +#else + "mip_primal_bound" +#endif + , data_out->mip_primal_bound); checkGetCallbackDataOutDouble(data_out, - kHighsCallbackDataOutMipDualBoundName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipDualBoundName +#else + "mip_dual_bound" +#endif + , data_out->mip_dual_bound); checkGetCallbackDataOutDouble(data_out, - kHighsCallbackDataOutMipGapName, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipGapName +#else + "mip_gap" +#endif + , data_out->mip_gap); checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutCutpoolNumColName, 0); +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolNumColName +#else + "cutpool_num_col" +#endif + , 0); checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutCutpoolNumCutName, 0); +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolNumCutName +#else + "cutpool_num_cut" +#endif + , 0); checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutCutpoolNumNzName, 0); +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolNumNzName +#else + "cutpool_num_nz" +#endif + , 0); // Check that passing an unrecognised name returns NULL const void* foo_p = Highs_getCallbackDataOutItem(data_out, "foo"); @@ -147,18 +223,53 @@ static void userCallback(const int callback_type, const char* message, // obtained using the struct const void* mip_solution_void_p = Highs_getCallbackDataOutItem(data_out, - kHighsCallbackDataOutMipSolutionName); +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipSolutionName +#else + "mip_solution" +#endif + ); assert(mip_solution_void_p); double mip_solution0 = *(double*)(mip_solution_void_p); assert(mip_solution0 == *(data_out->mip_solution)); if (dev_run) printf("userCallback(%11.4g): improving solution with value[0] = %g\n", local_callback_data, mip_solution0); // Check that passing names of the unassigned vectors returns NULL - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolStartName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolIndexName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolValueName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolLowerName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolUpperName)); + assert(!Highs_getCallbackDataOutItem(data_out, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolStartName +#else + "cutpool_start" +#endif + )); + assert(!Highs_getCallbackDataOutItem(data_out, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolIndexName +#else + "cutpool_index" +#endif + )); + assert(!Highs_getCallbackDataOutItem(data_out, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolValueName +#else + "cutpool_value" +#endif + )); + assert(!Highs_getCallbackDataOutItem(data_out, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolLowerName +#else + "cutpool_lower" +#endif + )); + assert(!Highs_getCallbackDataOutItem(data_out, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolUpperName +#else + "cutpool_upper" +#endif + )); } else if (callback_type == kHighsCallbackMipLogging) { if (dev_run) printf("userCallback(%11.4g): MIP logging\n", local_callback_data); data_in->user_interrupt = 1; diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index ba243c9a31..b74dfdb810 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -687,53 +687,168 @@ double Highs_getRunTime(const void* highs) { return (double)((Highs*)highs)->getRunTime(); } -const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name) { +const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, + const char* item_name) { // Accessor function for HighsCallbackDataOut // // Remember that pointers in HighsCallbackDataOut don't need to be referenced! - if (!strcmp(item_name, kHighsCallbackDataOutLogTypeName)) { + if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutLogTypeName +#else + "log_type" +#endif + )) { return (void*)(&data_out->log_type); - } else if (!strcmp(item_name, kHighsCallbackDataOutRunningTimeName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutRunningTimeName +#else + "running_time" +#endif + )) { return (void*)(&data_out->running_time); - } else if (!strcmp(item_name, kHighsCallbackDataOutSimplexIterationCountName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutSimplexIterationCountName +#else + "simplex_iteration_count" +#endif + )) { return (void*)(&data_out->simplex_iteration_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutIpmIterationCountName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutIpmIterationCountName +#else + "ipm_iteration_count" +#endif + )) { return (void*)(&data_out->ipm_iteration_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutPdlpIterationCountName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutPdlpIterationCountName +#else + "pdlp_iteration_count" +#endif + )) { return (void*)(&data_out->pdlp_iteration_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutObjectiveFunctionValueName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutObjectiveFunctionValueName +#else + "objective_function_value" +#endif + )) { return (void*)(&data_out->objective_function_value); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipNodeCountName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipNodeCountName +#else + "mip_node_count" +#endif + )) { return (void*)(&data_out->mip_node_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipPrimalBoundName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipPrimalBoundName +#else + "mip_primal_bound" +#endif + )) { return (void*)(&data_out->mip_primal_bound); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipDualBoundName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipDualBoundName +#else + "mip_dual_bound" +#endif + )) { return (void*)(&data_out->mip_dual_bound); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipGapName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipGapName +#else + "mip_gap" +#endif + )) { return (void*)(&data_out->mip_gap); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipSolutionName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutMipSolutionName +#else + "mip_solution" +#endif + )) { return (void*)(data_out->mip_solution); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumColName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolNumColName +#else + "cutpool_num_col" +#endif + )) { return (void*)(&data_out->cutpool_num_col); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumCutName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolNumCutName +#else + "cutpool_num_cut" +#endif + )) { return (void*)(&data_out->cutpool_num_cut); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumNzName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolNumNzName +#else + "cutpool_num_nz" +#endif + )) { return (void*)(&data_out->cutpool_num_nz); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolStartName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolStartName +#else + "cutpool_start" +#endif + )) { return (void*)(data_out->cutpool_start); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolIndexName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolIndexName +#else + "cutpool_index" +#endif + )) { return (void*)(data_out->cutpool_index); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolValueName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolValueName +#else + "cutpool_value" +#endif + )) { return (void*)(data_out->cutpool_value); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolLowerName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolLowerName +#else + "cutpool_lower" +#endif + )) { return (void*)(data_out->cutpool_lower); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolUpperName)) { + } else if (!strcmp(item_name, +#ifdef USE_CallbackDataOut_NAME + kHighsCallbackDataOutCutpoolUpperName +#else + "cutpool_upper" +#endif + )) { return (void*)(data_out->cutpool_upper); } return nullptr; } - HighsInt Highs_zeroAllClocks(const void* highs) { +HighsInt Highs_zeroAllClocks(const void* highs) { ((Highs*)highs)->zeroAllClocks(); return (HighsInt)HighsStatus::kOk; } diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index 74227456be..6d1f1f76fa 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -108,12 +108,17 @@ const HighsInt kHighsCallbackMipInterrupt = 6; const HighsInt kHighsCallbackMipGetCutPool = 7; const HighsInt kHighsCallbackMipDefineLazyConstraints = 8; +//#define USE_CallbackDataOut_NAME +#ifdef USE_CallbackDataOut_NAME const char* kHighsCallbackDataOutLogTypeName = "log_type"; const char* kHighsCallbackDataOutRunningTimeName = "running_time"; -const char* kHighsCallbackDataOutSimplexIterationCountName = "simplex_iteration_count"; +const char* kHighsCallbackDataOutSimplexIterationCountName = + "simplex_iteration_count"; const char* kHighsCallbackDataOutIpmIterationCountName = "ipm_iteration_count"; -const char* kHighsCallbackDataOutPdlpIterationCountName = "pdlp_iteration_count"; -const char* kHighsCallbackDataOutObjectiveFunctionValueName = "objective_function_value"; +const char* kHighsCallbackDataOutPdlpIterationCountName = + "pdlp_iteration_count"; +const char* kHighsCallbackDataOutObjectiveFunctionValueName = + "objective_function_value"; const char* kHighsCallbackDataOutMipNodeCountName = "mip_node_count"; const char* kHighsCallbackDataOutMipPrimalBoundName = "mip_primal_bound"; const char* kHighsCallbackDataOutMipDualBoundName = "mip_dual_bound"; @@ -127,6 +132,7 @@ const char* kHighsCallbackDataOutCutpoolIndexName = "cutpool_index"; const char* kHighsCallbackDataOutCutpoolValueName = "cutpool_value"; const char* kHighsCallbackDataOutCutpoolLowerName = "cutpool_lower"; const char* kHighsCallbackDataOutCutpoolUpperName = "cutpool_upper"; +#endif #ifdef __cplusplus extern "C" { @@ -1170,9 +1176,11 @@ HighsInt Highs_stopCallback(void* highs, const int callback_type); * @param data_out A pointer to the HighsCallbackDataOut instance. * @param item_name The name of the item. * - * @returns A void* pointer to the callback data item, or NULL if item_name not valid + * @returns A void* pointer to the callback data item, or NULL if item_name not + * valid */ -const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, const char* item_name); +const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, + const char* item_name); /** * Return the cumulative wall-clock time spent in `Highs_run`. From 4f738369d88da35ccf14a4998d57f75cd5c089d9 Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 19:34:58 +0100 Subject: [PATCH 30/37] Now defining kHighsCallbackDataOut_*_Name in TestCAPI.c ifndef USE_CallbackDataOut_NAME --- check/TestCAPI.c | 173 ++++++++++++----------------------------------- 1 file changed, 42 insertions(+), 131 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 551f04accb..a7fd3bee28 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -12,6 +12,28 @@ const HighsInt dev_run = 0; const double double_equal_tolerance = 1e-5; +#ifndef USE_CallbackDataOut_NAME +const char* kHighsCallbackDataOutLogTypeName = "log_type"; +const char* kHighsCallbackDataOutRunningTimeName = "running_time"; +const char* kHighsCallbackDataOutSimplexIterationCountName = "simplex_iteration_count"; +const char* kHighsCallbackDataOutIpmIterationCountName = "ipm_iteration_count"; +const char* kHighsCallbackDataOutPdlpIterationCountName = "pdlp_iteration_count"; +const char* kHighsCallbackDataOutObjectiveFunctionValueName = "objective_function_value"; +const char* kHighsCallbackDataOutMipNodeCountName = "mip_node_count"; +const char* kHighsCallbackDataOutMipPrimalBoundName = "mip_primal_bound"; +const char* kHighsCallbackDataOutMipDualBoundName = "mip_dual_bound"; +const char* kHighsCallbackDataOutMipGapName = "mip_gap"; +const char* kHighsCallbackDataOutMipSolutionName = "mip_solution"; +const char* kHighsCallbackDataOutCutpoolNumColName = "cutpool_num_col"; +const char* kHighsCallbackDataOutCutpoolNumCutName = "cutpool_num_cut"; +const char* kHighsCallbackDataOutCutpoolNumNzName = "cutpool_num_nz"; +const char* kHighsCallbackDataOutCutpoolStartName = "cutpool_start"; +const char* kHighsCallbackDataOutCutpoolIndexName = "cutpool_index"; +const char* kHighsCallbackDataOutCutpoolValueName = "cutpool_value"; +const char* kHighsCallbackDataOutCutpoolLowerName = "cutpool_lower"; +const char* kHighsCallbackDataOutCutpoolUpperName = "cutpool_upper"; +#endif + void checkGetCallbackDataOutPointer(const HighsCallbackDataOut* data_out, const char* name, HighsInt valid) { const void* name_p = Highs_getCallbackDataOutItem(data_out, name); if (valid) { @@ -91,23 +113,12 @@ static void userCallback(const int callback_type, const char* message, if (dev_run) printf("userCallback(%11.4g): %s\n", local_callback_data, message); } else if (callback_type == kHighsCallbackMipImprovingSolution) { // Test the accessor function for data_out -#ifdef USE_CallbackDataOut_NAME - if (dev_run) printf("Using constant definitions of CallbackDataOut item names\n"); -#else - if (dev_run) printf("Using explicit CallbackDataOut item names\n"); -#endif // // Check that passing an valid name returns a non-null pointer, // and that the corresponding value is the same as obtained using // the struct const void* objective_function_value_p = - Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutObjectiveFunctionValueName -#else - "objective_function_value" -#endif - ); + Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutObjectiveFunctionValueName); assert(objective_function_value_p); double objective_function_value = *(double*)(objective_function_value_p); assert(objective_function_value == data_out->objective_function_value); @@ -115,105 +126,40 @@ static void userCallback(const int callback_type, const char* message, local_callback_data, objective_function_value); // Now test all more simply checkGetCallbackDataOutInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutLogTypeName -#else - "log_type" -#endif - , -1); + kHighsCallbackDataOutLogTypeName, -1); checkGetCallbackDataOutDouble(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutRunningTimeName -#else - "running_time" -#endif - , + kHighsCallbackDataOutRunningTimeName, data_out->running_time); checkGetCallbackDataOutHighsInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutSimplexIterationCountName -#else - "simplex_iteration_count" -#endif - , + kHighsCallbackDataOutSimplexIterationCountName, data_out->simplex_iteration_count); checkGetCallbackDataOutHighsInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutIpmIterationCountName -#else - "ipm_iteration_count" -#endif - , + kHighsCallbackDataOutIpmIterationCountName, data_out->ipm_iteration_count); checkGetCallbackDataOutHighsInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutPdlpIterationCountName -#else - "pdlp_iteration_count" -#endif - , + kHighsCallbackDataOutPdlpIterationCountName, data_out->pdlp_iteration_count); checkGetCallbackDataOutDouble(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutObjectiveFunctionValueName -#else - "objective_function_value" -#endif - , + kHighsCallbackDataOutObjectiveFunctionValueName, data_out->objective_function_value); checkGetCallbackDataOutInt64(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipNodeCountName -#else - "mip_node_count" -#endif - , + kHighsCallbackDataOutMipNodeCountName, data_out->mip_node_count); checkGetCallbackDataOutDouble(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipPrimalBoundName -#else - "mip_primal_bound" -#endif - , + kHighsCallbackDataOutMipPrimalBoundName, data_out->mip_primal_bound); checkGetCallbackDataOutDouble(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipDualBoundName -#else - "mip_dual_bound" -#endif - , + kHighsCallbackDataOutMipDualBoundName, data_out->mip_dual_bound); checkGetCallbackDataOutDouble(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipGapName -#else - "mip_gap" -#endif - , + kHighsCallbackDataOutMipGapName, data_out->mip_gap); checkGetCallbackDataOutHighsInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolNumColName -#else - "cutpool_num_col" -#endif - , 0); + kHighsCallbackDataOutCutpoolNumColName, 0); checkGetCallbackDataOutHighsInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolNumCutName -#else - "cutpool_num_cut" -#endif - , 0); + kHighsCallbackDataOutCutpoolNumCutName, 0); checkGetCallbackDataOutHighsInt(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolNumNzName -#else - "cutpool_num_nz" -#endif - , 0); + kHighsCallbackDataOutCutpoolNumNzName, 0); // Check that passing an unrecognised name returns NULL const void* foo_p = Highs_getCallbackDataOutItem(data_out, "foo"); @@ -223,53 +169,18 @@ static void userCallback(const int callback_type, const char* message, // obtained using the struct const void* mip_solution_void_p = Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipSolutionName -#else - "mip_solution" -#endif - ); + kHighsCallbackDataOutMipSolutionName); assert(mip_solution_void_p); double mip_solution0 = *(double*)(mip_solution_void_p); assert(mip_solution0 == *(data_out->mip_solution)); if (dev_run) printf("userCallback(%11.4g): improving solution with value[0] = %g\n", local_callback_data, mip_solution0); // Check that passing names of the unassigned vectors returns NULL - assert(!Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolStartName -#else - "cutpool_start" -#endif - )); - assert(!Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolIndexName -#else - "cutpool_index" -#endif - )); - assert(!Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolValueName -#else - "cutpool_value" -#endif - )); - assert(!Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolLowerName -#else - "cutpool_lower" -#endif - )); - assert(!Highs_getCallbackDataOutItem(data_out, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolUpperName -#else - "cutpool_upper" -#endif - )); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolStartName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolIndexName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolValueName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolLowerName)); + assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolUpperName)); } else if (callback_type == kHighsCallbackMipLogging) { if (dev_run) printf("userCallback(%11.4g): MIP logging\n", local_callback_data); data_in->user_interrupt = 1; From 77eabe1a34518a8cf9971717bc12888f7776538f Mon Sep 17 00:00:00 2001 From: jajhall Date: Sun, 5 May 2024 21:50:28 +0100 Subject: [PATCH 31/37] Removed checks on unassigned cutpool data --- check/TestCAPI.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index a7fd3bee28..5b25c13c89 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -154,12 +154,14 @@ static void userCallback(const int callback_type, const char* message, checkGetCallbackDataOutDouble(data_out, kHighsCallbackDataOutMipGapName, data_out->mip_gap); - checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutCutpoolNumColName, 0); - checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutCutpoolNumCutName, 0); - checkGetCallbackDataOutHighsInt(data_out, - kHighsCallbackDataOutCutpoolNumNzName, 0); + // Cutpool data structure is not assigned, so num_col, num_cut and + // num_nz are unassigned + // checkGetCallbackDataOutHighsInt(data_out, + // kHighsCallbackDataOutCutpoolNumColName, 0); + // checkGetCallbackDataOutHighsInt(data_out, + // kHighsCallbackDataOutCutpoolNumCutName, 0); + // checkGetCallbackDataOutHighsInt(data_out, + // kHighsCallbackDataOutCutpoolNumNzName, 0); // Check that passing an unrecognised name returns NULL const void* foo_p = Highs_getCallbackDataOutItem(data_out, "foo"); @@ -175,12 +177,13 @@ static void userCallback(const int callback_type, const char* message, assert(mip_solution0 == *(data_out->mip_solution)); if (dev_run) printf("userCallback(%11.4g): improving solution with value[0] = %g\n", local_callback_data, mip_solution0); - // Check that passing names of the unassigned vectors returns NULL - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolStartName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolIndexName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolValueName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolLowerName)); - assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolUpperName)); + // Cutpool data structure is not assigned, so cannot check that + // passing names of the unassigned vectors returns NULL + // assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolStartName)); + // assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolIndexName)); + // assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolValueName)); + // assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolLowerName)); + // assert(!Highs_getCallbackDataOutItem(data_out, kHighsCallbackDataOutCutpoolUpperName)); } else if (callback_type == kHighsCallbackMipLogging) { if (dev_run) printf("userCallback(%11.4g): MIP logging\n", local_callback_data); data_in->user_interrupt = 1; From 91f66bbebf7140249bda2280bd341cb69699ec68 Mon Sep 17 00:00:00 2001 From: jajhall Date: Mon, 6 May 2024 07:27:01 +0100 Subject: [PATCH 32/37] Added const to const char* --- check/TestCAPI.c | 22 ----- src/interfaces/highs_c_api.cpp | 150 +++++---------------------------- src/interfaces/highs_c_api.h | 42 +++++---- 3 files changed, 39 insertions(+), 175 deletions(-) diff --git a/check/TestCAPI.c b/check/TestCAPI.c index 5b25c13c89..c23c4174ba 100644 --- a/check/TestCAPI.c +++ b/check/TestCAPI.c @@ -12,28 +12,6 @@ const HighsInt dev_run = 0; const double double_equal_tolerance = 1e-5; -#ifndef USE_CallbackDataOut_NAME -const char* kHighsCallbackDataOutLogTypeName = "log_type"; -const char* kHighsCallbackDataOutRunningTimeName = "running_time"; -const char* kHighsCallbackDataOutSimplexIterationCountName = "simplex_iteration_count"; -const char* kHighsCallbackDataOutIpmIterationCountName = "ipm_iteration_count"; -const char* kHighsCallbackDataOutPdlpIterationCountName = "pdlp_iteration_count"; -const char* kHighsCallbackDataOutObjectiveFunctionValueName = "objective_function_value"; -const char* kHighsCallbackDataOutMipNodeCountName = "mip_node_count"; -const char* kHighsCallbackDataOutMipPrimalBoundName = "mip_primal_bound"; -const char* kHighsCallbackDataOutMipDualBoundName = "mip_dual_bound"; -const char* kHighsCallbackDataOutMipGapName = "mip_gap"; -const char* kHighsCallbackDataOutMipSolutionName = "mip_solution"; -const char* kHighsCallbackDataOutCutpoolNumColName = "cutpool_num_col"; -const char* kHighsCallbackDataOutCutpoolNumCutName = "cutpool_num_cut"; -const char* kHighsCallbackDataOutCutpoolNumNzName = "cutpool_num_nz"; -const char* kHighsCallbackDataOutCutpoolStartName = "cutpool_start"; -const char* kHighsCallbackDataOutCutpoolIndexName = "cutpool_index"; -const char* kHighsCallbackDataOutCutpoolValueName = "cutpool_value"; -const char* kHighsCallbackDataOutCutpoolLowerName = "cutpool_lower"; -const char* kHighsCallbackDataOutCutpoolUpperName = "cutpool_upper"; -#endif - void checkGetCallbackDataOutPointer(const HighsCallbackDataOut* data_out, const char* name, HighsInt valid) { const void* name_p = Highs_getCallbackDataOutItem(data_out, name); if (valid) { diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index b74dfdb810..c0c880df1b 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -692,157 +692,45 @@ const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, // Accessor function for HighsCallbackDataOut // // Remember that pointers in HighsCallbackDataOut don't need to be referenced! - if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutLogTypeName -#else - "log_type" -#endif - )) { + if (!strcmp(item_name, kHighsCallbackDataOutLogTypeName)) { return (void*)(&data_out->log_type); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutRunningTimeName -#else - "running_time" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutRunningTimeName)) { return (void*)(&data_out->running_time); } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutSimplexIterationCountName -#else - "simplex_iteration_count" -#endif - )) { + kHighsCallbackDataOutSimplexIterationCountName)) { return (void*)(&data_out->simplex_iteration_count); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutIpmIterationCountName -#else - "ipm_iteration_count" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutIpmIterationCountName)) { return (void*)(&data_out->ipm_iteration_count); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutPdlpIterationCountName -#else - "pdlp_iteration_count" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutPdlpIterationCountName)) { return (void*)(&data_out->pdlp_iteration_count); } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutObjectiveFunctionValueName -#else - "objective_function_value" -#endif - )) { + kHighsCallbackDataOutObjectiveFunctionValueName)) { return (void*)(&data_out->objective_function_value); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipNodeCountName -#else - "mip_node_count" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutMipNodeCountName)) { return (void*)(&data_out->mip_node_count); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipPrimalBoundName -#else - "mip_primal_bound" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutMipPrimalBoundName)) { return (void*)(&data_out->mip_primal_bound); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipDualBoundName -#else - "mip_dual_bound" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutMipDualBoundName)) { return (void*)(&data_out->mip_dual_bound); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipGapName -#else - "mip_gap" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutMipGapName)) { return (void*)(&data_out->mip_gap); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutMipSolutionName -#else - "mip_solution" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutMipSolutionName)) { return (void*)(data_out->mip_solution); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolNumColName -#else - "cutpool_num_col" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumColName)) { return (void*)(&data_out->cutpool_num_col); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolNumCutName -#else - "cutpool_num_cut" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumCutName)) { return (void*)(&data_out->cutpool_num_cut); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolNumNzName -#else - "cutpool_num_nz" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumNzName)) { return (void*)(&data_out->cutpool_num_nz); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolStartName -#else - "cutpool_start" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolStartName)) { return (void*)(data_out->cutpool_start); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolIndexName -#else - "cutpool_index" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolIndexName)) { return (void*)(data_out->cutpool_index); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolValueName -#else - "cutpool_value" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolValueName)) { return (void*)(data_out->cutpool_value); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolLowerName -#else - "cutpool_lower" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolLowerName)) { return (void*)(data_out->cutpool_lower); - } else if (!strcmp(item_name, -#ifdef USE_CallbackDataOut_NAME - kHighsCallbackDataOutCutpoolUpperName -#else - "cutpool_upper" -#endif - )) { + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolUpperName)) { return (void*)(data_out->cutpool_upper); } return nullptr; diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index 6d1f1f76fa..d7b31ade02 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -108,31 +108,29 @@ const HighsInt kHighsCallbackMipInterrupt = 6; const HighsInt kHighsCallbackMipGetCutPool = 7; const HighsInt kHighsCallbackMipDefineLazyConstraints = 8; -//#define USE_CallbackDataOut_NAME -#ifdef USE_CallbackDataOut_NAME -const char* kHighsCallbackDataOutLogTypeName = "log_type"; -const char* kHighsCallbackDataOutRunningTimeName = "running_time"; -const char* kHighsCallbackDataOutSimplexIterationCountName = +const char* const kHighsCallbackDataOutLogTypeName = "log_type"; +const char* const kHighsCallbackDataOutRunningTimeName = "running_time"; +const char* const kHighsCallbackDataOutSimplexIterationCountName = "simplex_iteration_count"; -const char* kHighsCallbackDataOutIpmIterationCountName = "ipm_iteration_count"; -const char* kHighsCallbackDataOutPdlpIterationCountName = +const char* const kHighsCallbackDataOutIpmIterationCountName = + "ipm_iteration_count"; +const char* const kHighsCallbackDataOutPdlpIterationCountName = "pdlp_iteration_count"; -const char* kHighsCallbackDataOutObjectiveFunctionValueName = +const char* const kHighsCallbackDataOutObjectiveFunctionValueName = "objective_function_value"; -const char* kHighsCallbackDataOutMipNodeCountName = "mip_node_count"; -const char* kHighsCallbackDataOutMipPrimalBoundName = "mip_primal_bound"; -const char* kHighsCallbackDataOutMipDualBoundName = "mip_dual_bound"; -const char* kHighsCallbackDataOutMipGapName = "mip_gap"; -const char* kHighsCallbackDataOutMipSolutionName = "mip_solution"; -const char* kHighsCallbackDataOutCutpoolNumColName = "cutpool_num_col"; -const char* kHighsCallbackDataOutCutpoolNumCutName = "cutpool_num_cut"; -const char* kHighsCallbackDataOutCutpoolNumNzName = "cutpool_num_nz"; -const char* kHighsCallbackDataOutCutpoolStartName = "cutpool_start"; -const char* kHighsCallbackDataOutCutpoolIndexName = "cutpool_index"; -const char* kHighsCallbackDataOutCutpoolValueName = "cutpool_value"; -const char* kHighsCallbackDataOutCutpoolLowerName = "cutpool_lower"; -const char* kHighsCallbackDataOutCutpoolUpperName = "cutpool_upper"; -#endif +const char* const kHighsCallbackDataOutMipNodeCountName = "mip_node_count"; +const char* const kHighsCallbackDataOutMipPrimalBoundName = "mip_primal_bound"; +const char* const kHighsCallbackDataOutMipDualBoundName = "mip_dual_bound"; +const char* const kHighsCallbackDataOutMipGapName = "mip_gap"; +const char* const kHighsCallbackDataOutMipSolutionName = "mip_solution"; +const char* const kHighsCallbackDataOutCutpoolNumColName = "cutpool_num_col"; +const char* const kHighsCallbackDataOutCutpoolNumCutName = "cutpool_num_cut"; +const char* const kHighsCallbackDataOutCutpoolNumNzName = "cutpool_num_nz"; +const char* const kHighsCallbackDataOutCutpoolStartName = "cutpool_start"; +const char* const kHighsCallbackDataOutCutpoolIndexName = "cutpool_index"; +const char* const kHighsCallbackDataOutCutpoolValueName = "cutpool_value"; +const char* const kHighsCallbackDataOutCutpoolLowerName = "cutpool_lower"; +const char* const kHighsCallbackDataOutCutpoolUpperName = "cutpool_upper"; #ifdef __cplusplus extern "C" { From 83375582727b96759d671a68ef227c446f2abb65 Mon Sep 17 00:00:00 2001 From: jajhall Date: Mon, 6 May 2024 07:33:42 +0100 Subject: [PATCH 33/37] Better not to have Highs_getCallbackDataOutItem amongst methods requiring const void* highs as first argument --- src/interfaces/highs_c_api.cpp | 99 +++++++++++++++++----------------- src/interfaces/highs_c_api.h | 24 ++++----- 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/src/interfaces/highs_c_api.cpp b/src/interfaces/highs_c_api.cpp index c0c880df1b..427dc4b204 100644 --- a/src/interfaces/highs_c_api.cpp +++ b/src/interfaces/highs_c_api.cpp @@ -687,55 +687,6 @@ double Highs_getRunTime(const void* highs) { return (double)((Highs*)highs)->getRunTime(); } -const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, - const char* item_name) { - // Accessor function for HighsCallbackDataOut - // - // Remember that pointers in HighsCallbackDataOut don't need to be referenced! - if (!strcmp(item_name, kHighsCallbackDataOutLogTypeName)) { - return (void*)(&data_out->log_type); - } else if (!strcmp(item_name, kHighsCallbackDataOutRunningTimeName)) { - return (void*)(&data_out->running_time); - } else if (!strcmp(item_name, - kHighsCallbackDataOutSimplexIterationCountName)) { - return (void*)(&data_out->simplex_iteration_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutIpmIterationCountName)) { - return (void*)(&data_out->ipm_iteration_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutPdlpIterationCountName)) { - return (void*)(&data_out->pdlp_iteration_count); - } else if (!strcmp(item_name, - kHighsCallbackDataOutObjectiveFunctionValueName)) { - return (void*)(&data_out->objective_function_value); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipNodeCountName)) { - return (void*)(&data_out->mip_node_count); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipPrimalBoundName)) { - return (void*)(&data_out->mip_primal_bound); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipDualBoundName)) { - return (void*)(&data_out->mip_dual_bound); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipGapName)) { - return (void*)(&data_out->mip_gap); - } else if (!strcmp(item_name, kHighsCallbackDataOutMipSolutionName)) { - return (void*)(data_out->mip_solution); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumColName)) { - return (void*)(&data_out->cutpool_num_col); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumCutName)) { - return (void*)(&data_out->cutpool_num_cut); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumNzName)) { - return (void*)(&data_out->cutpool_num_nz); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolStartName)) { - return (void*)(data_out->cutpool_start); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolIndexName)) { - return (void*)(data_out->cutpool_index); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolValueName)) { - return (void*)(data_out->cutpool_value); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolLowerName)) { - return (void*)(data_out->cutpool_lower); - } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolUpperName)) { - return (void*)(data_out->cutpool_upper); - } - return nullptr; -} - HighsInt Highs_zeroAllClocks(const void* highs) { ((Highs*)highs)->zeroAllClocks(); return (HighsInt)HighsStatus::kOk; @@ -1392,6 +1343,55 @@ void Highs_resetGlobalScheduler(HighsInt blocking) { Highs::resetGlobalScheduler(blocking != 0); } +const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, + const char* item_name) { + // Accessor function for HighsCallbackDataOut + // + // Remember that pointers in HighsCallbackDataOut don't need to be referenced! + if (!strcmp(item_name, kHighsCallbackDataOutLogTypeName)) { + return (void*)(&data_out->log_type); + } else if (!strcmp(item_name, kHighsCallbackDataOutRunningTimeName)) { + return (void*)(&data_out->running_time); + } else if (!strcmp(item_name, + kHighsCallbackDataOutSimplexIterationCountName)) { + return (void*)(&data_out->simplex_iteration_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutIpmIterationCountName)) { + return (void*)(&data_out->ipm_iteration_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutPdlpIterationCountName)) { + return (void*)(&data_out->pdlp_iteration_count); + } else if (!strcmp(item_name, + kHighsCallbackDataOutObjectiveFunctionValueName)) { + return (void*)(&data_out->objective_function_value); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipNodeCountName)) { + return (void*)(&data_out->mip_node_count); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipPrimalBoundName)) { + return (void*)(&data_out->mip_primal_bound); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipDualBoundName)) { + return (void*)(&data_out->mip_dual_bound); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipGapName)) { + return (void*)(&data_out->mip_gap); + } else if (!strcmp(item_name, kHighsCallbackDataOutMipSolutionName)) { + return (void*)(data_out->mip_solution); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumColName)) { + return (void*)(&data_out->cutpool_num_col); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumCutName)) { + return (void*)(&data_out->cutpool_num_cut); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolNumNzName)) { + return (void*)(&data_out->cutpool_num_nz); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolStartName)) { + return (void*)(data_out->cutpool_start); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolIndexName)) { + return (void*)(data_out->cutpool_index); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolValueName)) { + return (void*)(data_out->cutpool_value); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolLowerName)) { + return (void*)(data_out->cutpool_lower); + } else if (!strcmp(item_name, kHighsCallbackDataOutCutpoolUpperName)) { + return (void*)(data_out->cutpool_upper); + } + return nullptr; +} + // ********************* // * Deprecated methods* // ********************* @@ -1574,3 +1574,4 @@ double Highs_getHighsInfinity(const void* highs) { HighsInt Highs_getScaledModelStatus(const void* highs) { return (HighsInt)((Highs*)highs)->getModelStatus(); } + diff --git a/src/interfaces/highs_c_api.h b/src/interfaces/highs_c_api.h index d7b31ade02..4ecac88764 100644 --- a/src/interfaces/highs_c_api.h +++ b/src/interfaces/highs_c_api.h @@ -1168,18 +1168,6 @@ HighsInt Highs_startCallback(void* highs, const int callback_type); */ HighsInt Highs_stopCallback(void* highs, const int callback_type); -/** - * Get a void* pointer to a callback data item - * - * @param data_out A pointer to the HighsCallbackDataOut instance. - * @param item_name The name of the item. - * - * @returns A void* pointer to the callback data item, or NULL if item_name not - * valid - */ -const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, - const char* item_name); - /** * Return the cumulative wall-clock time spent in `Highs_run`. * @@ -2187,6 +2175,18 @@ HighsInt Highs_getRanging( */ void Highs_resetGlobalScheduler(const HighsInt blocking); +/** + * Get a void* pointer to a callback data item + * + * @param data_out A pointer to the HighsCallbackDataOut instance. + * @param item_name The name of the item. + * + * @returns A void* pointer to the callback data item, or NULL if item_name not + * valid + */ +const void* Highs_getCallbackDataOutItem(const HighsCallbackDataOut* data_out, + const char* item_name); + // ********************* // * Deprecated methods* // ********************* From cad21fe1c1a05884841d96c4c16ea90160d60266 Mon Sep 17 00:00:00 2001 From: jajhall Date: Mon, 6 May 2024 08:00:14 +0100 Subject: [PATCH 34/37] Highs::setSolution now gives logging message and error return if user solution is rejected --- check/TestCheckSolution.cpp | 13 +++++++++++++ src/lp_data/Highs.cpp | 14 +++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/check/TestCheckSolution.cpp b/check/TestCheckSolution.cpp index 3d210bf3da..4f31a90b94 100644 --- a/check/TestCheckSolution.cpp +++ b/check/TestCheckSolution.cpp @@ -330,6 +330,19 @@ TEST_CASE("check-set-mip-solution-extra-row", "[highs_check_solution]") { std::remove(solution_file_name.c_str()); } +TEST_CASE("check-set-illegal-solution", "[highs_check_solution]") { + HighsStatus return_status; + std::string model_file = + std::string(HIGHS_DIR) + "/check/instances/avgas.mps"; + Highs highs; + highs.readModel(model_file); + const HighsLp& lp = highs.getLp(); + HighsSolution solution; + REQUIRE(highs.setSolution(solution) == HighsStatus::kError); + solution.col_value.assign(lp.num_col_, 0); + REQUIRE(highs.setSolution(solution) == HighsStatus::kOk); +} + void runWriteReadCheckSolution(Highs& highs, const std::string model, const HighsModelStatus require_model_status, const HighsInt write_solution_style) { diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index 5d66084b88..2bd876e171 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -1905,7 +1905,19 @@ HighsStatus Highs::setSolution(const HighsSolution& solution) { solution.row_dual.size() >= static_cast(model_.lp_.num_row_); const bool new_solution = new_primal_solution || new_dual_solution; - if (new_solution) invalidateUserSolverData(); + if (new_solution) { + invalidateUserSolverData(); + } else { + // Solution is rejected, so give a logging message and error + // return + highsLogUser(options_.log_options, HighsLogType::kError, + "User solution is rejected due to mismatch between " + "size of col_value and row_dual vectors (%d, %d) and number " + "of columns and rows in the model (%d, %d) \n", + int(solution.col_value.size()), int(solution.row_dual.size()), + int(model_.lp_.num_col_), int(model_.lp_.num_row_)); + return_status = HighsStatus::kError; + } if (new_primal_solution) { solution_.col_value = solution.col_value; From 3642900072536f73a4799857521fd6cb9e838b49 Mon Sep 17 00:00:00 2001 From: jajhall Date: Mon, 6 May 2024 08:53:25 +0100 Subject: [PATCH 35/37] Now checking minimal user solution and basis vector size, logging and returning with error --- check/TestBasis.cpp | 24 +++++++++++++++++++++++- check/TestCheckSolution.cpp | 1 + src/lp_data/Highs.cpp | 24 ++++++++++++++++++------ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/check/TestBasis.cpp b/check/TestBasis.cpp index 5c5e5ec1f1..1a1c91f6c8 100644 --- a/check/TestBasis.cpp +++ b/check/TestBasis.cpp @@ -111,7 +111,7 @@ TEST_CASE("set-pathological-basis", "[highs_basis_data]") { // Set up a basis with everything nonbasic. This will lead to // basic_index being empty when passed to // HFactor::setupGeneral. Previously this led to the creation of - // pointer &basic_index[0] that caused Windows faiure referenced in + // pointer &basic_index[0] that caused Windows failure referenced in // #1129, and reported in #1166. However, now that // basic_index.data() is used to create the pointer, there is no // Windows failure. Within HFactor::setupGeneral and @@ -156,6 +156,28 @@ TEST_CASE("Basis-no-basic", "[highs_basis_data]") { REQUIRE(highs.getModelStatus() == HighsModelStatus::kOptimal); } +TEST_CASE("Basis-singular", "[highs_basis_data]") { + Highs highs; + highs.setOptionValue("output_flag", dev_run); + HighsLp lp; + lp.num_col_ = 2; + lp.num_row_ = 2; + lp.col_cost_ = {1, 1}; + lp.col_lower_ = {0, 0}; + lp.col_upper_ = {1, 1}; + lp.row_lower_ = {1, 1}; + lp.row_upper_ = {2, 2}; + lp.a_matrix_.start_ = {0, 2, 4}; + lp.a_matrix_.index_ = {0, 1, 0, 1}; + lp.a_matrix_.value_ = {1, 2, 2, 4}; + highs.passModel(lp); + HighsBasis basis; + REQUIRE(highs.setBasis(basis) == HighsStatus::kError); + basis.col_status = {HighsBasisStatus::kBasic, HighsBasisStatus::kBasic}; + basis.row_status = {HighsBasisStatus::kLower, HighsBasisStatus::kLower}; + REQUIRE(highs.setBasis(basis) == HighsStatus::kOk); +} + // No commas in test case name. void testBasisReloadModel(Highs& highs, const bool from_file) { // Checks that no simplex iterations are required if a saved optimal diff --git a/check/TestCheckSolution.cpp b/check/TestCheckSolution.cpp index 4f31a90b94..3314cfc368 100644 --- a/check/TestCheckSolution.cpp +++ b/check/TestCheckSolution.cpp @@ -335,6 +335,7 @@ TEST_CASE("check-set-illegal-solution", "[highs_check_solution]") { std::string model_file = std::string(HIGHS_DIR) + "/check/instances/avgas.mps"; Highs highs; + highs.setOptionValue("output_flag", dev_run); highs.readModel(model_file); const HighsLp& lp = highs.getLp(); HighsSolution solution; diff --git a/src/lp_data/Highs.cpp b/src/lp_data/Highs.cpp index 2bd876e171..e71cf0aae5 100644 --- a/src/lp_data/Highs.cpp +++ b/src/lp_data/Highs.cpp @@ -1910,12 +1910,13 @@ HighsStatus Highs::setSolution(const HighsSolution& solution) { } else { // Solution is rejected, so give a logging message and error // return - highsLogUser(options_.log_options, HighsLogType::kError, - "User solution is rejected due to mismatch between " - "size of col_value and row_dual vectors (%d, %d) and number " - "of columns and rows in the model (%d, %d) \n", - int(solution.col_value.size()), int(solution.row_dual.size()), - int(model_.lp_.num_col_), int(model_.lp_.num_row_)); + highsLogUser( + options_.log_options, HighsLogType::kError, + "setSolution: User solution is rejected due to mismatch between " + "size of col_value and row_dual vectors (%d, %d) and number " + "of columns and rows in the model (%d, %d)\n", + int(solution.col_value.size()), int(solution.row_dual.size()), + int(model_.lp_.num_col_), int(model_.lp_.num_row_)); return_status = HighsStatus::kError; } @@ -2064,6 +2065,17 @@ HighsStatus Highs::setBasis(const HighsBasis& basis, : basis.col_status[iCol]; basis_.alien = false; } else { + // Check whether a new basis can be defined + if (!isBasisRightSize(model_.lp_, basis)) { + highsLogUser( + options_.log_options, HighsLogType::kError, + "setBasis: User basis is rejected due to mismatch between " + "size of column and row status vectors (%d, %d) and number " + "of columns and rows in the model (%d, %d)\n", + int(basis_.col_status.size()), int(basis_.row_status.size()), + int(model_.lp_.num_col_), int(model_.lp_.num_row_)); + return HighsStatus::kError; + } HighsBasis modifiable_basis = basis; modifiable_basis.was_alien = true; HighsLpSolverObject solver_object(model_.lp_, modifiable_basis, solution_, From ae25abb7b2b6a61b471bd72735e2fd1f8fac38ff Mon Sep 17 00:00:00 2001 From: jajhall Date: Mon, 6 May 2024 09:04:57 +0100 Subject: [PATCH 36/37] Updated FEATURES.md --- FEATURES.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/FEATURES.md b/FEATURES.md index 389e3e4f9f..7a50344541 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -18,4 +18,16 @@ Added version info to executable Inserting `pdlp_iteration_count` into various structs (for v1.7.0) breaks the C API, so it has been moved to the end of those structs +setBasis has been added to highspy + +writePresolvedModel has been added + +Saved MIP solution pool is populated when presolve reduces MIP to empty + +Compilation date has been removed improve build reproducibility. Methods to print compilation dates are deprecated + +Logging and error return when user-supplied solution or basis is rejected on vector dimensions + + + From 9dd829c9b8aacf87f3d02626517b614c433f9328 Mon Sep 17 00:00:00 2001 From: Ivet Galabova Date: Tue, 7 May 2024 14:31:08 +0300 Subject: [PATCH 37/37] add comment for documentation build --- src/lp_data/HighsCallbackStruct.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lp_data/HighsCallbackStruct.h b/src/lp_data/HighsCallbackStruct.h index 5ed434f7e3..4553707f61 100644 --- a/src/lp_data/HighsCallbackStruct.h +++ b/src/lp_data/HighsCallbackStruct.h @@ -1,4 +1,3 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* This file is part of the HiGHS linear optimization suite */ /* */ @@ -20,6 +19,10 @@ extern "C" { #endif +/** + * Struct to handle callback output data + * + */ typedef struct { int log_type; // cast of HighsLogType double running_time;