From d712b853dd6e2dea97a34a95276eb3e18887ba9b Mon Sep 17 00:00:00 2001 From: Sebastian Luther Date: Sat, 17 Aug 2024 21:43:59 +0200 Subject: [PATCH] python: Provide incumbent solution in callback --- examples/call_highs_from_python.py | 2 +- src/highs_bindings.cpp | 5 ++--- src/lp_data/HighsCallbackStruct.h | 1 + src/mip/HighsMipSolverData.cpp | 5 +++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/call_highs_from_python.py b/examples/call_highs_from_python.py index 5de97e9b15..94be817fd0 100644 --- a/examples/call_highs_from_python.py +++ b/examples/call_highs_from_python.py @@ -248,7 +248,7 @@ def user_interrupt_callback( print(f"userCallback(type {callback_type};") print(f"data {local_callback_data:.4g}): {message}") print(f"with objective {data_out.objective_function_value}") - print(f"and solution[0] = {data_out.mip_solution[0]}") + print(f"and solution = {data_out.mip_solution}") # Check and update the objective function value assert ( diff --git a/src/highs_bindings.cpp b/src/highs_bindings.cpp index e7f9e49cac..06cd4f70c2 100644 --- a/src/highs_bindings.cpp +++ b/src/highs_bindings.cpp @@ -1195,12 +1195,11 @@ PYBIND11_MODULE(_core, m) { .def_property( "mip_solution", [](const HighsCallbackDataOut& self) -> py::array { - // XXX: This is clearly wrong, most likely we need to have the - // length as an input data parameter - return py::array(3, self.mip_solution); + return py::array(self.mip_solution_size, self.mip_solution); }, [](HighsCallbackDataOut& self, py::array_t new_mip_solution) { self.mip_solution = new_mip_solution.mutable_data(); + self.mip_solution_size = new_mip_solution.shape(0); }); py::class_(callbacks, "HighsCallbackDataIn") .def(py::init<>()) diff --git a/src/lp_data/HighsCallbackStruct.h b/src/lp_data/HighsCallbackStruct.h index a5f7140834..1429625ea3 100644 --- a/src/lp_data/HighsCallbackStruct.h +++ b/src/lp_data/HighsCallbackStruct.h @@ -37,6 +37,7 @@ typedef struct { double mip_dual_bound; double mip_gap; double* mip_solution; + HighsInt mip_solution_size; HighsInt cutpool_num_col; HighsInt cutpool_num_cut; HighsInt cutpool_num_nz; diff --git a/src/mip/HighsMipSolverData.cpp b/src/mip/HighsMipSolverData.cpp index 9dcd8129b6..09c2f76173 100644 --- a/src/mip/HighsMipSolverData.cpp +++ b/src/mip/HighsMipSolverData.cpp @@ -463,6 +463,8 @@ void HighsMipSolverData::runSetup() { assert(!mipsolver.submip); mipsolver.callback_->clearHighsCallbackDataOut(); mipsolver.callback_->data_out.mip_solution = mipsolver.solution_.data(); + mipsolver.callback_->data_out.mip_solution_size = + mipsolver.solution_.size(); const bool interrupt = interruptFromCallbackWithData( kCallbackMipSolution, mipsolver.solution_objective_, "Feasible solution"); @@ -832,6 +834,7 @@ double HighsMipSolverData::transformNewIntegerFeasibleSolution( mipsolver.callback_->active[kCallbackMipSolution]) { mipsolver.callback_->clearHighsCallbackDataOut(); mipsolver.callback_->data_out.mip_solution = solution.col_value.data(); + mipsolver.callback_->data_out.mip_solution_size = solution.col_value.size(); const bool interrupt = interruptFromCallbackWithData( kCallbackMipSolution, mipsolver_objective_value, "Feasible solution"); assert(!interrupt); @@ -1928,6 +1931,8 @@ void HighsMipSolverData::saveReportMipSolution(const double new_upper_limit) { if (mipsolver.callback_->active[kCallbackMipImprovingSolution]) { mipsolver.callback_->clearHighsCallbackDataOut(); mipsolver.callback_->data_out.mip_solution = mipsolver.solution_.data(); + mipsolver.callback_->data_out.mip_solution_size = + mipsolver.solution_.size(); const bool interrupt = interruptFromCallbackWithData( kCallbackMipImprovingSolution, mipsolver.solution_objective_, "Improving solution");