diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index edc7a00d1d..4d9a2b7425 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -1374,6 +1374,7 @@ class iteration_data_t { dense_vector_t dual_res = z_tilde; dual_res.axpy(-1.0, lp.objective, 1.0); cusparse_view.transpose_spmv(1.0, solution.y, 1.0, dual_res); + if (Q.n > 0) { matrix_vector_multiply(Q, -1.0, x, 1.0, dual_res); } f_t dual_residual_norm = vector_norm_inf(dual_res, stream_view_); #ifdef PRINT_INFO settings_.log.printf("Solution Dual residual: %e\n", dual_residual_norm); diff --git a/cpp/tests/qp/unit_tests/lp_parser_solve_test.cu b/cpp/tests/qp/unit_tests/lp_parser_solve_test.cu index 2a37f43008..241a7cb1f7 100644 --- a/cpp/tests/qp/unit_tests/lp_parser_solve_test.cu +++ b/cpp/tests/qp/unit_tests/lp_parser_solve_test.cu @@ -206,4 +206,26 @@ End {4.0, 2.0}); } +// Dual residual check for QP. +TEST(lp_parser_solve, qp_diagonal_only_dual_residual) +{ + raft::handle_t handle; + auto problem = io::read_lp_from_string(R"LP( +Minimize + obj: -8 x1 - 16 x2 + [ 2 x1 ^ 2 + 8 x2 ^ 2 ] / 2 +Subject To + c1: x1 + x2 >= 5 +Bounds + 0 <= x1 <= 10 + 0 <= x2 <= 10 +End +)LP"); + auto settings = pdlp_solver_settings_t(); + auto solution = solve_lp(&handle, problem, settings); + + ASSERT_EQ(solution.get_termination_status(), pdlp_termination_status_t::Optimal); + EXPECT_NEAR(solution.get_objective_value(), -32.0, 1e-4); + EXPECT_NEAR(solution.get_additional_termination_information().l2_dual_residual, 0.0, 1e-4); +} + } // namespace cuopt::mathematical_optimization