Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3c010ea
feat(barrier): add SOCP cone primitives and NT kernels
yan-zaretskiy Apr 7, 2026
9ee0ed7
feat(barrier): integrate H^-2 cone blocks into the augmented system
yan-zaretskiy Apr 7, 2026
41f763c
fix(barrier): stabilize SOCP barrier convergence
yan-zaretskiy Apr 7, 2026
c99368f
refactor(dual_simplex): keep cone layout packed through presolve
yan-zaretskiy Apr 7, 2026
a5dba68
test(dual_simplex): expand SOCP barrier coverage and tighten layout c…
yan-zaretskiy Apr 7, 2026
f4b9c8e
feat(mps_parser): add QCMATRIX parsing and quadratic-constraint model…
Apr 15, 2026
43f09b4
fix: address review suggestions (chatbot)
yuwenchen95 Apr 15, 2026
ac9dd8a
complete parsder for linear cost, ROW and RHS for QCQP
yuwenchen95 Apr 17, 2026
0bd6499
Add support for reading and writting quadratical constrains into MPS;…
yuwenchen95 Apr 20, 2026
d693509
Merge branch 'NVIDIA:main' into mps-socp
yuwenchen95 Apr 20, 2026
21b0f9a
Restrict quadratic constraints to be convex with type 'L'
yuwenchen95 Apr 20, 2026
e6e1f42
Clean up for the MPS parser
yuwenchen95 Apr 22, 2026
b9d3a48
merge the parser into SOCP implementation
yuwenchen95 Apr 22, 2026
8ff6ce1
minor adjustment for parser
yuwenchen95 Apr 22, 2026
6617f94
Add bridging for mps model to user_problem model
yuwenchen95 Apr 23, 2026
62380e4
Update QCQP dataset for parser check and address minor issues
yuwenchen95 Apr 23, 2026
969ff06
modified test check for the MPS parser
yuwenchen95 Apr 23, 2026
0065a10
Merge branch 'mps-socp' into socp-merge
yuwenchen95 Apr 23, 2026
926633a
Remove unused temp_file_3 in mps_parser_test
yuwenchen95 Apr 23, 2026
6f2b1fb
undo std::span for CI tests
yuwenchen95 Apr 24, 2026
9defd60
Apply pre-commit fixes
yuwenchen95 Apr 24, 2026
3389255
Merge branch 'mps-socp' into socp-merge
yuwenchen95 Apr 24, 2026
0a31a44
minior correction for bound check and update dataset for qcqp
yuwenchen95 Apr 24, 2026
5dd5ef2
Merge branch 'main' into mps-socp
yuwenchen95 Apr 24, 2026
0bfc961
Merge branch 'mps-socp' into socp-merge
yuwenchen95 Apr 24, 2026
d172213
Print # of quadratic constraints and cones
chris-maes Apr 24, 2026
f70e45d
Refresh SOCP barrier kernels
yan-zaretskiy Apr 28, 2026
a20ac27
Support direct MPS SOC conversion
yan-zaretskiy Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class mip_solution_interface_t;
template <typename i_t, typename f_t>
class cpu_optimization_problem_t : public optimization_problem_interface_t<i_t, f_t> {
public:
using typename optimization_problem_interface_t<i_t, f_t>::quadratic_constraint_t;

cpu_optimization_problem_t();

// Setters
Expand Down Expand Up @@ -113,6 +115,10 @@ class cpu_optimization_problem_t : public optimization_problem_interface_t<i_t,
const std::vector<f_t>& get_quadratic_objective_values() const override;
bool has_quadratic_objective() const override;

void set_quadratic_constraints(std::vector<quadratic_constraint_t> constraints) override;
bool has_quadratic_constraints() const override;
const std::vector<quadratic_constraint_t>& get_quadratic_constraints() const override;

// Host getters - these are the only supported getters for CPU implementation
std::vector<f_t> get_constraint_matrix_values_host() const override;
std::vector<i_t> get_constraint_matrix_indices_host() const override;
Expand Down Expand Up @@ -185,6 +191,8 @@ class cpu_optimization_problem_t : public optimization_problem_interface_t<i_t,
std::vector<i_t> Q_indices_;
std::vector<f_t> Q_values_;

std::vector<quadratic_constraint_t> quadratic_constraints_{};

std::vector<f_t> variable_lower_bounds_;
std::vector<f_t> variable_upper_bounds_;
std::vector<f_t> constraint_lower_bounds_;
Expand Down
10 changes: 10 additions & 0 deletions cpp/include/cuopt/linear_programming/optimization_problem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class optimization_problem_t : public optimization_problem_interface_t<i_t, f_t>
static_assert(std::is_floating_point<f_t>::value,
"'optimization_problem_t' accepts only floating point types for weights");

// nvcc does not always find base typedefs in derived class scope; inject explicitly.
using typename optimization_problem_interface_t<i_t, f_t>::quadratic_constraint_t;

/**
* @brief A device-side view of the `optimization_problem_t` structure with
* the RAII stuffs stripped out, to make it easy to work inside kernels
Expand Down Expand Up @@ -196,6 +199,8 @@ class optimization_problem_t : public optimization_problem_interface_t<i_t, f_t>
i_t size_offsets,
bool validate_positive_semi_definite = false) override;

void set_quadratic_constraints(std::vector<quadratic_constraint_t> constraints) override;

/** @copydoc optimization_problem_interface_t::set_variable_lower_bounds */
void set_variable_lower_bounds(const f_t* variable_lower_bounds, i_t size) override;
/** @copydoc optimization_problem_interface_t::set_variable_upper_bounds */
Expand Down Expand Up @@ -259,7 +264,9 @@ class optimization_problem_t : public optimization_problem_interface_t<i_t, f_t>
const std::vector<i_t>& get_quadratic_objective_offsets() const override;
const std::vector<i_t>& get_quadratic_objective_indices() const override;
const std::vector<f_t>& get_quadratic_objective_values() const override;
const std::vector<quadratic_constraint_t>& get_quadratic_constraints() const override;
bool has_quadratic_objective() const override;
bool has_quadratic_constraints() const override;

// ============================================================================
// Host getters
Expand Down Expand Up @@ -376,6 +383,9 @@ class optimization_problem_t : public optimization_problem_interface_t<i_t, f_t>
std::vector<i_t> Q_indices_;
std::vector<f_t> Q_values_;

/** QCQP: quadratic constraints **/
std::vector<quadratic_constraint_t> quadratic_constraints_{};

rmm::device_uvector<f_t> variable_lower_bounds_;
rmm::device_uvector<f_t> variable_upper_bounds_;
rmm::device_uvector<f_t> constraint_lower_bounds_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,52 @@ class optimization_problem_interface_t {
static_assert(std::is_floating_point<f_t>::value,
"'optimization_problem_interface_t' accepts only floating point types for weights");

/** Quadratic constraint bundle used by core optimization problem interfaces. */
struct quadratic_constraint_t {
i_t constraint_row_index{};
std::string constraint_row_name{};
char constraint_row_type{};
std::vector<f_t> linear_values{};
std::vector<i_t> linear_indices{};
f_t rhs_value{f_t(0)};
std::vector<f_t> quadratic_values{};
std::vector<i_t> quadratic_indices{};
std::vector<i_t> quadratic_offsets{};
};

virtual ~optimization_problem_interface_t() = default;

/**
* @brief Store quadratic constraints for MPS round-trip (linear + Q parts per QC row).
*/
virtual void set_quadratic_constraints(std::vector<quadratic_constraint_t> constraints) = 0;
template <typename qc_t,
typename = std::enable_if_t<!std::is_same_v<qc_t, quadratic_constraint_t>>>
void set_quadratic_constraints(const std::vector<qc_t>& constraints)
{
std::vector<quadratic_constraint_t> converted_constraints;
converted_constraints.reserve(constraints.size());
for (const auto& qc : constraints) {
converted_constraints.push_back(
{static_cast<i_t>(qc.constraint_row_index),
qc.constraint_row_name,
qc.constraint_row_type,
std::vector<f_t>(qc.linear_values.begin(), qc.linear_values.end()),
std::vector<i_t>(qc.linear_indices.begin(), qc.linear_indices.end()),
static_cast<f_t>(qc.rhs_value),
std::vector<f_t>(qc.quadratic_values.begin(), qc.quadratic_values.end()),
std::vector<i_t>(qc.quadratic_indices.begin(), qc.quadratic_indices.end()),
std::vector<i_t>(qc.quadratic_offsets.begin(), qc.quadratic_offsets.end())});
}
set_quadratic_constraints(std::move(converted_constraints));
}

/** @brief Whether quadratic constraint metadata is present (for MPS export). */
virtual bool has_quadratic_constraints() const = 0;

/** @brief Quadratic constraints for MPS export (empty if none). */
virtual const std::vector<quadratic_constraint_t>& get_quadratic_constraints() const = 0;

// ============================================================================
// Setters (accept both CPU and GPU pointers)
// ============================================================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ void populate_from_mps_data_model(optimization_problem_interface_t<i_t, f_t>* pr
q_offsets.data(),
n_vars + 1);
}
// Handle quadratic constraints if present
if (data_model.has_quadratic_constraints()) {
problem->set_quadratic_constraints(data_model.get_quadratic_constraints());
}
}

/**
Expand Down Expand Up @@ -266,6 +270,10 @@ void populate_from_data_model_view(optimization_problem_interface_t<i_t, f_t>* p
if (data_model->get_row_names().size() != 0) {
problem->set_row_names(data_model->get_row_names());
}

if (data_model->has_quadratic_constraints()) {
problem->set_quadratic_constraints(data_model->get_quadratic_constraints());
}
}

} // namespace cuopt::linear_programming
32 changes: 32 additions & 0 deletions cpp/libmps_parser/include/mps_parser/data_model_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

#include <mps_parser/mps_data_model.hpp>
#include <mps_parser/utilities/span.hpp>

#include <cstdint>
Expand Down Expand Up @@ -415,6 +416,35 @@ class data_model_view_t {
*/
bool is_Q_symmetrized() const noexcept;

/**
* @brief Quadratic constraints (MPS QCMATRIX); owned copy for writers when not using spans.
*/
void set_quadratic_constraints(
std::vector<typename mps_data_model_t<i_t, f_t>::quadratic_constraint_t> constraints);
template <typename qc_t>
void set_quadratic_constraints(const std::vector<qc_t>& constraints)
{
quadratic_constraints_.clear();
quadratic_constraints_.reserve(constraints.size());
for (const auto& qc : constraints) {
quadratic_constraints_.push_back(
{static_cast<i_t>(qc.constraint_row_index),
qc.constraint_row_name,
qc.constraint_row_type,
std::vector<f_t>(qc.linear_values.begin(), qc.linear_values.end()),
std::vector<i_t>(qc.linear_indices.begin(), qc.linear_indices.end()),
static_cast<f_t>(qc.rhs_value),
std::vector<f_t>(qc.quadratic_values.begin(), qc.quadratic_values.end()),
std::vector<i_t>(qc.quadratic_indices.begin(), qc.quadratic_indices.end()),
std::vector<i_t>(qc.quadratic_offsets.begin(), qc.quadratic_offsets.end())});
}
}

bool has_quadratic_constraints() const noexcept;

const std::vector<typename mps_data_model_t<i_t, f_t>::quadratic_constraint_t>&
get_quadratic_constraints() const noexcept;

private:
bool maximize_{false};
span<f_t const> A_;
Expand Down Expand Up @@ -444,6 +474,8 @@ class data_model_view_t {
span<i_t const> Q_objective_indices_;
span<i_t const> Q_objective_offsets_;
bool is_Q_symmetrized_{false};

std::vector<typename mps_data_model_t<i_t, f_t>::quadratic_constraint_t> quadratic_constraints_;
}; // class data_model_view_t

} // namespace cuopt::mps_parser
60 changes: 58 additions & 2 deletions cpp/libmps_parser/include/mps_parser/mps_data_model.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand Down Expand Up @@ -262,6 +262,57 @@ class mps_data_model_t {
const i_t* Q_offsets,
i_t size_offsets);

/**
* @brief One quadratic constraint as parsed from MPS sections (ROWS, COLUMNS, RHS, QCMATRIX).
*
* This bundles all pieces of a quadratic row:
* - row identity and type (from ROWS),
* - sparse linear coefficients (from COLUMNS),
* - RHS value (from RHS),
* - quadratic matrix Q in CSR (from QCMATRIX).
*/
struct quadratic_constraint_t {
/** ROWS declaration index (among all constraint rows), not an index into the linear CSR. */
i_t constraint_row_index{};
std::string constraint_row_name{};
/** MPS ROWS sense for this quadratic row; only 'L' (≤) is supported for convex QCQP at the
* moment. */
char constraint_row_type{};
std::vector<f_t> linear_values{};
std::vector<i_t> linear_indices{};
f_t rhs_value{f_t(0)};
std::vector<f_t> quadratic_values{};
std::vector<i_t> quadratic_indices{};
std::vector<i_t> quadratic_offsets{};
};

/**
* @brief Append one complete quadratic constraint (row + linear + rhs + quadratic Q).
* @note Pointer+size signature is kept for current CI/toolchain compatibility; `std::span`
* can be revisited later when compatibility constraints are lifted.
* @param linear_values, linear_indices Same nnz; can be empty for a purely quadratic row (rare).
* @param quadratic_values, quadratic_indices CSR nnz; may be empty if Q is empty.
* @param quadratic_offsets CSR row starts; must be non-empty.
* @param constraint_row_type MPS ROWS type; must be 'L'. 'G' and 'E' quadratic rows are not
* supported.
*/
void append_quadratic_constraint(i_t constraint_row_index,
const std::string& constraint_row_name,
char constraint_row_type,
const f_t* linear_values,
i_t linear_nnz,
const i_t* linear_indices,
i_t linear_indices_nnz,
f_t rhs_value,
const f_t* quadratic_values,
i_t quadratic_size_values,
const i_t* quadratic_indices,
i_t quadratic_size_indices,
const i_t* quadratic_offsets,
i_t quadratic_size_offsets);

const std::vector<quadratic_constraint_t>& get_quadratic_constraints() const;

i_t get_n_variables() const;
i_t get_n_constraints() const;
i_t get_nnz() const;
Expand Down Expand Up @@ -306,6 +357,8 @@ class mps_data_model_t {

bool has_quadratic_objective() const noexcept;

bool has_quadratic_constraints() const noexcept;

/** whether to maximize or minimize the objective function */
bool maximize_;
/**
Expand Down Expand Up @@ -342,7 +395,7 @@ class mps_data_model_t {
std::string problem_name_;
/** names of each of the variables in the OP */
std::vector<std::string> var_names_{};
/** names of each of the rows (aka constraints or objective) in the OP */
/** names of linear constraint rows in exported MPS order. */
std::vector<std::string> row_names_{};
/** number of variables */
i_t n_vars_{0};
Expand All @@ -361,6 +414,9 @@ class mps_data_model_t {
std::vector<i_t> Q_objective_indices_;
std::vector<i_t> Q_objective_offsets_;

/** One full quadratic constraint per QCMATRIX block, in order of appearance in the file */
std::vector<quadratic_constraint_t> quadratic_constraints_;

}; // class mps_data_model_t

} // namespace cuopt::mps_parser
4 changes: 3 additions & 1 deletion cpp/libmps_parser/include/mps_parser/parser.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand All @@ -23,6 +23,8 @@ namespace cuopt::mps_parser {
* QPS files (for quadratic programming). QPS files are MPS files with additional
* sections:
* - QUADOBJ: Defines quadratic terms in the objective function
* - QMATRIX: Full symmetric quadratic objective matrix (alternative to QUADOBJ)
* - QCMATRIX: Symmetric quadratic terms for a named constraint row (QCQP)
*
* Note: Compressed MPS files .mps.gz, .mps.bz2 can only be read if the compression
* libraries zlib or libbzip2 are installed, respectively.
Expand Down
4 changes: 3 additions & 1 deletion cpp/libmps_parser/include/mps_parser/utilities/span.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand All @@ -18,6 +18,8 @@ class span {
span(T* ptr, std::size_t size) : ptr_(ptr), size_(size) {}
std::size_t size() const noexcept { return size_; }
const T* data() const noexcept { return ptr_; }
T& operator[](std::size_t i) noexcept { return ptr_[i]; }
T const& operator[](std::size_t i) const noexcept { return ptr_[i]; }

private:
T* ptr_{nullptr};
Expand Down
20 changes: 20 additions & 0 deletions cpp/libmps_parser/src/data_model_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,26 @@ bool data_model_view_t<i_t, f_t>::is_Q_symmetrized() const noexcept
return is_Q_symmetrized_;
}

template <typename i_t, typename f_t>
void data_model_view_t<i_t, f_t>::set_quadratic_constraints(
std::vector<typename mps_data_model_t<i_t, f_t>::quadratic_constraint_t> constraints)
{
quadratic_constraints_ = std::move(constraints);
}

template <typename i_t, typename f_t>
bool data_model_view_t<i_t, f_t>::has_quadratic_constraints() const noexcept
{
return !quadratic_constraints_.empty();
}

template <typename i_t, typename f_t>
const std::vector<typename mps_data_model_t<i_t, f_t>::quadratic_constraint_t>&
data_model_view_t<i_t, f_t>::get_quadratic_constraints() const noexcept
{
return quadratic_constraints_;
}

// NOTE: Explicitly instantiate all types here in order to avoid linker error
template class data_model_view_t<int, float>;

Expand Down
Loading