| 2751 | } |
| 2752 | |
| 2753 | void HighsMipSolverData::queryExternalSolution( |
| 2754 | const double mipsolver_objective_value, |
| 2755 | const ExternalMipSolutionQueryOrigin external_solution_query_origin) { |
| 2756 | assert(!mipsolver.submip); |
| 2757 | HighsCallback* callback = mipsolver.callback_; |
| 2758 | const bool use_callback = |
| 2759 | callback->user_callback && callback->active[kCallbackMipUserSolution]; |
| 2760 | if (use_callback) { |
| 2761 | setCallbackDataOut(mipsolver_objective_value); |
| 2762 | callback->data_out.external_solution_query_origin = |
| 2763 | external_solution_query_origin; |
| 2764 | callback->clearHighsCallbackInput(); |
| 2765 | |
| 2766 | const bool interrupt = |
| 2767 | callback->callbackAction(kCallbackMipUserSolution, "MIP User solution"); |
| 2768 | assert(!interrupt); |
| 2769 | if (callback->data_in.user_has_solution) { |
| 2770 | // Objective is assumed to be original_offset + |
| 2771 | // (original_c)^T(original_x), but MIP solver bounds are based on the |
| 2772 | // reduced objective (reduced_c)^T(reduced_x) |
| 2773 | // |
| 2774 | // Now, original_sense*[reduced_offset + (reduced_c)^T(reduced_x)] is an |
| 2775 | // objective in the original space, so |
| 2776 | // |
| 2777 | // f0 + c0^Tx0 = s*(f1 + c1^Tx1) |
| 2778 | // |
| 2779 | // where 0 => original; 1 => reduced |
| 2780 | // |
| 2781 | // This allows the reduced objective value to be deduced as |
| 2782 | // |
| 2783 | // c1^Tx1 = s*(f0 + c0^Tx0) - f1 |
| 2784 | // |
| 2785 | // (reduced_c)^T(reduced_x) = original_sense*[original_offset + |
| 2786 | // (original_c)^T(original_x) - reduced_offset] |
| 2787 | const auto& user_solution = callback->data_in.user_solution; |
| 2788 | double bound_violation_ = 0; |
| 2789 | double row_violation_ = 0; |
| 2790 | double integrality_violation_ = 0; |
| 2791 | HighsCDouble user_solution_quad_objective_value = 0; |
| 2792 | const bool feasible = mipsolver.solutionFeasible( |
| 2793 | mipsolver.orig_model_, user_solution, nullptr, bound_violation_, |
| 2794 | row_violation_, integrality_violation_, |
| 2795 | user_solution_quad_objective_value); |
| 2796 | double user_solution_objective_value = |
| 2797 | double(user_solution_quad_objective_value); |
| 2798 | if (!feasible) { |
| 2799 | highsLogUser( |
| 2800 | mipsolver.options_mip_->log_options, HighsLogType::kWarning, |
| 2801 | "User-supplied solution has with objective %g has violations: " |
| 2802 | "bound = %.4g; integrality = %.4g; row = %.4g\n", |
| 2803 | user_solution_objective_value, bound_violation_, |
| 2804 | integrality_violation_, row_violation_); |
| 2805 | return; |
| 2806 | } |
| 2807 | std::vector<double> reduced_user_solution; |
| 2808 | reduced_user_solution = |
| 2809 | postSolveStack.getReducedPrimalSolution(user_solution); |
| 2810 | const bool print_display_line = true; |
no test coverage detected