Skip to content

Commit afbb89c

Browse files
authored
Remove wrong exception of unsupported QCQP (#1493)
We were wrongly throwing an exception when the rotated cones and quadratic objectives were present. ## Issue Authors: - Rajesh Gandham (https://github.com/rg20) Approvers: - Yuwen Chen (https://github.com/yuwenchen95) - Miles Lubin (https://github.com/mlubin) URL: #1493
1 parent 9b40707 commit afbb89c

3 files changed

Lines changed: 45 additions & 11 deletions

File tree

cpp/src/barrier/cusparse_view.cu

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,14 @@ void my_cusparsespmv_preprocess(cusparseHandle_t handle,
114114
}
115115
#endif
116116

117-
static cusparseSpMVAlg_t get_spmv_alg(int num_rows)
117+
static cusparseSpMVAlg_t get_spmv_alg([[maybe_unused]] int num_rows)
118118
{
119-
// The older version of ALG2 has a bug with single row matrices
120-
if (num_rows == 1 &&
121-
(CUSPARSE_VER_MAJOR * 1000 + CUSPARSE_VER_MINOR * 100 + CUSPARSE_VER_PATCH < 12603)) {
122-
return CUSPARSE_SPMV_CSR_ALG1;
123-
}
119+
// ALG2 has a bug in cuSPARSE < 13.0 where beta=1 accumulate mode ignores existing y values.
120+
// ALG1 uses a deterministic row-split algorithm, while ALG2 uses a merge-based
121+
// algorithm that may be faster but can use atomics. ALG1 is safe for reproducibility.
122+
constexpr int cusparse_version =
123+
CUSPARSE_VER_MAJOR * 1000 + CUSPARSE_VER_MINOR * 100 + CUSPARSE_VER_PATCH;
124+
if (cusparse_version < 13000) { return CUSPARSE_SPMV_CSR_ALG1; }
124125
return CUSPARSE_SPMV_CSR_ALG2;
125126
}
126127

cpp/src/barrier/translate_soc.hpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -871,11 +871,6 @@ void convert_quadratic_constraints_to_second_order_cones(
871871

872872
// Convert rotated SOC cones to standard SOC cones.
873873
if (!rotated_cones.empty()) {
874-
cuopt_expects(user_problem.Q_values.empty(),
875-
error_type_t::ValidationError,
876-
"Rotated SOC conversion is currently not supported when the objective has "
877-
"quadratic terms");
878-
879874
const f_t inf = std::numeric_limits<f_t>::infinity();
880875
const f_t inv_sqrt_2 = f_t(1) / std::sqrt(f_t(2));
881876
const f_t half = f_t(0.5);

cpp/tests/socp/general_quadratic_test.cu

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <cuopt/error.hpp>
1313
#include <cuopt/mathematical_optimization/io/parser.hpp>
1414
#include <cuopt/mathematical_optimization/optimization_problem_interface.hpp>
15+
#include <cuopt/mathematical_optimization/pdlp/solver_settings.hpp>
16+
#include <cuopt/mathematical_optimization/solve.hpp>
1517
#include <dual_simplex/solve.hpp>
1618
#include <dual_simplex/user_problem.hpp>
1719
#include <linear_algebra/sparse_matrix.hpp>
@@ -907,4 +909,40 @@ TEST(general_quadratic, rotated_soc_heads_free_rejected)
907909
cuopt::logic_error);
908910
}
909911

912+
// Test QCQP with rotated SOC constraint and quadratic objective using high-level API.
913+
// This is the recommended way to solve QCQP problems.
914+
// minimize (1/2)*x^2 - x (quadratic objective)
915+
// subject to x^2 - 2*t*u <= 0 (rotated SOC)
916+
// t = 1, u = 0.5
917+
// Optimal: x = 1, objective = -0.5
918+
TEST(general_quadratic, qcqp_rotated_soc)
919+
{
920+
raft::handle_t handle{};
921+
922+
auto problem = io::read_lp_from_string<i_t, f_t>(R"LP(
923+
Minimize
924+
- x + [ x ^2 ] / 2
925+
Subject To
926+
t_eq: t = 1
927+
u_eq: u = 0.5
928+
rsoc: [ x ^2 - 2 t * u ] <= 0
929+
Bounds
930+
x free
931+
t >= 0
932+
u >= 0
933+
End
934+
)LP");
935+
936+
ASSERT_TRUE(problem.has_quadratic_objective());
937+
ASSERT_TRUE(problem.has_quadratic_constraints());
938+
ASSERT_EQ(problem.get_quadratic_constraints().size(), 1u);
939+
940+
pdlp_solver_settings_t<i_t, f_t> settings;
941+
auto solution = solve_lp(&handle, problem, settings);
942+
943+
EXPECT_EQ(solution.get_termination_status(), pdlp_termination_status_t::Optimal);
944+
// Optimal: x=1, objective = (1/2)*1 - 1 = -0.5
945+
EXPECT_NEAR(solution.get_objective_value(), -0.5, 1e-4);
946+
}
947+
910948
} // namespace cuopt::mathematical_optimization::barrier::test

0 commit comments

Comments
 (0)