diff --git a/ortools/math_opt/solvers/highs_solver.cc b/ortools/math_opt/solvers/highs_solver.cc index 25f66f1e7f..42e30f9033 100644 --- a/ortools/math_opt/solvers/highs_solver.cc +++ b/ortools/math_opt/solvers/highs_solver.cc @@ -14,7 +14,6 @@ // Unimplemented features: // * Quadratic objective // * TODO(b/272767311): initial basis, more precise returned basis. -// * Starting solution // * TODO(b/271104776): Returning rays #include "ortools/math_opt/solvers/highs_solver.h" @@ -925,6 +924,21 @@ absl::StatusOr HighsSolver::Solve( return absl::OkStatus(); }; + if (model_parameters.solution_hints_size() > 0) { + // Take the first solution hint and set the solution. + const SolutionHintProto& hint = model_parameters.solution_hints(0); + HighsInt num_entries = hint.variable_values().ids_size(); + std::vector index(num_entries); + std::vector value(num_entries); + size_t i = 0; + for (const auto [id, val] : MakeView(hint.variable_values())) { + index[i] = variable_data_.at(id).index; + value[i] = val; + ++i; + } + RETURN_IF_ERROR(ToStatus(highs_->setSolution(num_entries, index.data(), value.data()))); + } + RETURN_IF_ERROR(ListInvertedBounds().ToStatus()); // TODO(b/271595607): delete this code once we upgrade HiGHS, if HiGHS does // return a proper infeasibility status for models with empty integer bounds. diff --git a/ortools/math_opt/solvers/highs_solver_test.cc b/ortools/math_opt/solvers/highs_solver_test.cc index ccb276129b..6c3805bdda 100644 --- a/ortools/math_opt/solvers/highs_solver_test.cc +++ b/ortools/math_opt/solvers/highs_solver_test.cc @@ -162,11 +162,20 @@ INSTANTIATE_TEST_SUITE_P(HighsLpModelSolveParametersTest, Values(LpModelSolveParametersTestParameters( SolverType::kHighs, /*exact_zeros=*/true, /*supports_duals=*/true, - /*supports_primal_only_warm_starts=*/false))); + /*supports_primal_only_warm_starts=*/true))); -// MIP hint appears to be supported by Highs::setSolution, this is not yet -// implemented. -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MipSolutionHintTest); +SolutionHintTestParams MakeHighsSolutionHintParams() { + SolveParameters solve_params; + solve_params.presolve = Emphasis::kOff; + (*solve_params.highs.mutable_int_options())["mip_max_nodes"] = 0; + std::string hint_message_regex = + "Attempting to find feasible solution by " + "solving MIP for user-supplied values of"; + return SolutionHintTestParams(SolverType::kHighs, solve_params, std::nullopt, + hint_message_regex); +} +INSTANTIATE_TEST_SUITE_P(HighsSolutionHintTest, MipSolutionHintTest, + Values(MakeHighsSolutionHintParams())); // HiGHS does not support branching priority. GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BranchPrioritiesTest);