Skip to content

Extend the barrier solver to SOCP problems - #1051

Closed
yan-zaretskiy wants to merge 94 commits into
NVIDIA:release/26.06from
yan-zaretskiy:socp-barrier-solver
Closed

Extend the barrier solver to SOCP problems#1051
yan-zaretskiy wants to merge 94 commits into
NVIDIA:release/26.06from
yan-zaretskiy:socp-barrier-solver

Conversation

@yan-zaretskiy

Copy link
Copy Markdown

This is a draft PR that extends the 2x2 augmented system formulation of the barrier solver to solve SOCP problems. It supports both explicit cone variables as well as the cone rows in the Ax=b constraint, both of which can be specified in the CBF format. It uses Nesterov-Todd scaling to make the conic diagonal blocks symmetric.

Build the cone-local Jordan-product, scaling, and corrector kernels needed
for the SOCP barrier path before augmented-system integration.
Wire the SOCP cone Hessian updates into the augmented solve path and fold in
the follow-up cleanup that removes now-redundant kernel plumbing.
Tighten the augmented-system SOCP updates so the barrier path converges on the
mixed LP/QP cone cases covered by the new regression tests.
Flatten the remaining SOCP barrier plumbing, remove superseded cone kernels,
and harden presolve so linear columns stay ahead of the trailing cone block.
…hecks
Add row-cone and presolve regression cases around the SOCP barrier path, clean
up the PR-facing test wording, and align the cone layout validation with the
shared infinity convention.
Signed-off-by: Yan Zaretskiy <yzaretskiy@nvidia.com>
@copy-pr-bot

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@rg20rg20 added feature request New feature or request non-breaking Introduces a non-breaking change labels Apr 23, 2026
@rg20rg20 added this to the 26.06 milestone Apr 23, 2026
}
}
if (!(problem.lower[j] == -inf && problem.upper[j] == inf)) {
presolve_info.phase1_bounded_linear_indices.push_back(j);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not have a variable named phase_1_bounded_linear_indices

}
}

// Barrier presolve phase 2: negate one-sided bounds (-inf < x <= u -> -u <= x < inf).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "Barrier presolve phase 2" from comment.


// The original problem may have nonzero lower bounds
// 0 != l_j <= x_j <= u_j
// Barrier presolve phase 3: shift nonzero lower bounds to zero (cone/stack columns not shifted).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "Barrier phase 3". Put back the original comment that was deleted.
Fine to add something about "Cone variables should not be shifted"

}

// Check for empty rows
// Barrier presolve phase 4: remove empty rows and empty linear columns.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "Barrier presolve phase 4"

if (settings.barrier_presolve && free_variables > 0 && problem.Q.n > 0) {
presolve_info.free_variable_indices.clear();
for (i_t j = 0; j < problem.num_cols; j++) {
// Barrier presolve phase 5: free linear variables — 5a native (QP/SOCP) or 5b v-w split (LP).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "Barrier presolve phase 5" comment. And "5a, 5b"

for (i_t j = 0; j < linear_cols; j++) {
if (problem.lower[j] == -inf && problem.upper[j] == inf) {
presolve_info.free_variable_indices.push_back(j);
presolve_info.native_free_linear_indices.push_back(j);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we changing from free_variable_indices to native_free_linear_indices? Let's keep the old name

}
} else if (settings.barrier_presolve && free_variables > 0) {
settings.log.printf(
"Keeping %d native free linear variables for augmented-system barrier (QP/SOCP)\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Keeping %d free variables"

"Keeping %d native free linear variables for augmented-system barrier (QP/SOCP)\n",
native_free_count);
} else if (settings.barrier_presolve && !has_cones && free_variables > 0) {
// Phase 5b: x_j = v - w with v, w >= 0 (LP without cones; SOCP/QP use phase 5a).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "Phase 5" and "phase 5a" from comment. You could delete this comment.

// becomes
// sum_{k != j} c_k x_k + c_j v - c_j w

std::vector<i_t> pair_index(problem.num_cols, -1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does any of this code need to change. This is for the LP case. Just make sure we aren't in an SOCP or QP and then use this code. I'd suggest reverting these changes.

Q_j[row_starts[partner_row]] = partner_col;
Q_x[row_starts[partner_row]] = qij;
row_starts[partner_row]++;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert all changes from line 1196/1135 to here.

problem.A.i[q] = i;
problem.A.x[q] = -aij;
q++;
csc_matrix_t<i_t, f_t> expanded_A(problem.A.m, num_cols, nnz);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do this expansion only in the SOCP case?

}

if (!presolve_info.phase1_bounded_linear_indices.empty()) {
settings.log.printf("Post-solve: %d linear column(s) had phase-1 bound tightening (x unchanged)\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user should not be expected to know the internal phases of presolve!

Remove this print and this block of code entirely.

const i_t u = free_variable_pairs[k];
const i_t v = free_variable_pairs[k + 1];
input_x[u] -= input_x[v];
remove_partner[v] = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this code needed?

settings.log.printf("Post-solve: Correcting duals for %d bounded free variables\n",
static_cast<i_t>(presolve_info.bounded_free_variables.size()));
const csc_matrix_t<i_t, f_t>& A = original_problem.A;
csr_matrix_t<i_t, f_t> A_row(A.m, A.n, A.nnz());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert these changes. Converting to A_row is not needed

if (w_j == 0.0) { continue; }
const f_t du = w_j / bfv.coefficient;
input_y[bfv.constraint] += du;
for (i_t j = 0; j < A.n; j++) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert these changes.

Comment threadcpp/src/dual_simplex/presolve.hpp
Comment threadcpp/src/dual_simplex/simplex_solver_settings.hpp
Comment threadcpp/src/dual_simplex/simplex_solver_settings.hpp
Comment threadcpp/src/math_optimization/solver_settings.cu
Comment threadcpp/src/pdlp/solve.cu
Comment threadcpp/src/pdlp/solve.cu
Comment threadcpp/src/pdlp/solve.cu
Comment threadcpp/src/pdlp/solve.cu
}
settings.method = method_t::Barrier;
settings.presolver = presolver_t::None;
// Quadratic objective support is minimization-only.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? I thought we supported maximizing with quadratic objectives.

Comment threadcpp/src/pdlp/translate.hpp
Comment thread.claude-plugin/marketplace.json
Comment threadcpp/src/barrier/barrier.cu
Comment threadcpp/src/barrier/barrier.cu
Comment threadcpp/src/barrier/barrier.cu
Comment threadcpp/src/io/mps_parser.cpp
Comment threadcpp/src/io/mps_parser.cpp
Comment threadcpp/src/io/mps_parser.cpp
Comment threadcpp/src/io/mps_parser.cpp
Comment threadcpp/tests/CMakeLists.txt
Comment threadskills/skill-evolution/skill-card.md
Comment threadcpp/tests/dual_simplex/CMakeLists.txt

@rg20rg20 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed only a subset of files. I will continue to review.

Comment threadcpp/src/dual_simplex/scaling.cpp
Comment threadcpp/src/dual_simplex/scaling.cpp
Comment threadcpp/src/dual_simplex/solve.cpp
@chris-maes

Copy link
Copy Markdown
Contributor

This PR is moved to #1290 . Please make all comments and changes on that PR.

yuwenchen95 added a commit to chris-maes/cuopt that referenced this pull request May 26, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature requestNew feature or requestnon-breakingIntroduces a non-breaking changeP0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants

@yan-zaretskiy@chris-maes@mlubin@rg20@yuwenchen95@Iroy30@anandhkb@jolorunyomi@GPUtester@ramakrishnap-nv