Skip to content

Fix Ruiz equilibration skip heuristic to also check column imbalance - #1601

Merged
rapids-bot[bot] merged 6 commits into
NVIDIA:mainfrom
mlubin:fix-ruiz-skip-column-imbalance
Jul 24, 2026
Merged

Fix Ruiz equilibration skip heuristic to also check column imbalance#1601
rapids-bot[bot] merged 6 commits into
NVIDIA:mainfrom
mlubin:fix-ruiz-skip-column-imbalance

Conversation

@mlubin

@mlubinmlubin commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

The skip heuristic in scaling() only measured row-norm imbalance, so a QP/SOCP with balanced rows but severely imbalanced columns (e.g. QPLIB_8515, where free variables appear only with ~1e-8 coefficients against O(1) rows) received no scaling at all. The resulting augmented KKT system was so ill-conditioned that barrier terminated at a suboptimal point while reporting convergence (320.13 vs the true optimum 320.00 on QPLIB_8515, non-deterministically across runs). With the column check, Ruiz runs and the instance solves to 319.999989 in 14 iterations instead of 338.

Adds QPLIB_8515 as a downloaded test dataset (new
download_qplib_test_dataset.sh, wired into ci/test_cpp.sh and CONTRIBUTING.md) and a full-solve regression test that asserts the optimal objective matches the QPLIB reference value.

A summary of impacts on public benchmark instances that are affected:

Improvements

InstanceSourceIterationsSolve time (s)Rel. obj. errorNotes
QPLIB_8515QPLIB177 → 142.62 → 0.363.2e-04 → 9.4e-107.3× faster; now matches reference objective
PRIMALC1Maros–Mészáros23 → 160.13 → 0.130 → 4.7e-08
PRIMALC2Maros–Mészáros25 → 160.13 → 0.120 → 2.8e-08
PRIMALC5Maros–Mészáros21 → 150.13 → 0.120 → 1.9e-08
PRIMALC8Maros–Mészáros26 → 150.14 → 0.125.5e-09 → 5.5e-09
QPCBLENDMaros–Mészáros17 → 170.13 → 0.145.6e-08 → 7.4e-09accuracy only; time unchanged

Neutral

InstanceSourceIterationsSolve time (s)Rel. obj. errorNotes
QPLIB_8938QPLIB18 → 170.43 → 0.402.1e-07 → 3.9e-07
DTOC3Maros–Mészáros12 → 120.83 → 0.830 → 0
STADAT2Maros–Mészáros20 → 170.86 → 0.810 → 3.6e-07
STADAT3Maros–Mészáros20 → 180.86 → 0.850 → 2.8e-07
dsNRLCBLIB41 → 4167.8 → 69.12.4e-07 → 2.4e-07
wbNRLCBLIB28 → 2925.9 → 28.45.3e-06 → 4.8e-06
firL1CBLIB24 → 2428.2 → 30.03.5e-06 → 1.1e-05both errors well inside 1e-4 tolerance
firLinfCBLIB23 → 2484.7 → 91.31.3e-06 → 4.0e-07+8% time, better accuracy
firL1LinfalphCBLIB36 → 3771.4 → 76.41.3e-07 → 7.3e-08+7% time, better accuracy

Regressions

InstanceSourceIterationsSolve time (s)Rel. obj. errorNotes
db-plate-yield-lineCBLIB42 → 466.4 → 8.79.9e-07 → 1.4e-06reproducible: main stable at 42 it / ~6 s; branch 47–56 it / 8.5–9.5 s across reruns
STADAT1Maros–Mészáros64 → 3810.93 → 1.460 → 0mixed: main flipped optimal/suboptimal across reruns; branch always optimal (193–381 it)
HUES-MODMaros–Mészáros10 → 260.12 → 0.147.0e-05 → 7.0e-05iteration count only; sub-second solve
HUESTISMaros–Mészáros15 → 320.12 → 0.157.0e-05 → 7.0e-05iteration count only; sub-second solve
QPLIB_9008QPLIB54.1 → 169.0both variants fail numerically ("search direction computation failed"); branch takes 3.1× longer to fail

Adds a --qcqp_hyper_ruiz_equilibration flag to override the behavior.

@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.

@mlubin
mlubinforce-pushed the fix-ruiz-skip-column-imbalance branch 4 times, most recently from 8ba9578 to ed675a1CompareJuly 21, 2026 21:41
@mlubinmlubin added bug Something isn't working non-breaking Introduces a non-breaking change labels Jul 21, 2026
@mlubin

Copy link
Copy Markdown
ContributorAuthor

/ok to test ed675a1

@github-actions

github-actionsBot commented Jul 21, 2026

Copy link
Copy Markdown

CI Test Summary

✅ All 31 test job(s) passed.

# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

INSTANCES=(

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.

Are we only downloading this specific example?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, it's the first instance from qplib that we're using in tests.

Comment threadcpp/src/dual_simplex/scaling.cpp Outdated
}
f_t col_norm_ratio = (min_col_norm > 0) ? max_col_norm / min_col_norm : 1.0;

if (row_norm_ratio < 100.0 && col_norm_ratio < 100.0) {

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 might want to add an option --row-scaling that by default is -1 and we use the heuristic below, but if the user sets --row-scaling=0 they can turn it off, and if they set --row-scaling=1 they can force it on.

@mlubin
mlubin marked this pull request as ready for review July 22, 2026 21:37
@mlubin
mlubin requested review from a team as code ownersJuly 22, 2026 21:37
@coderabbitai

coderabbitaiBot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d66026d8-dfc0-470f-aaf6-b06405397c4e

📥 Commits

Reviewing files that changed from the base of the PR and between a6bcbfa and 378c96b.

📒 Files selected for processing (11)
  • .gitignore
  • CONTRIBUTING.md
  • ci/test_cpp.sh
  • cpp/include/cuopt/mathematical_optimization/constants.h
  • cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp
  • cpp/src/dual_simplex/scaling.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/math_optimization/solver_settings.cu
  • cpp/src/pdlp/solve.cu
  • cpp/tests/dual_simplex/unit_tests/solve_barrier.cu
  • datasets/quadratic_programming/download_qplib_test_dataset.sh
🚧 Files skipped from review as they are similar to previous changes (10)
  • cpp/src/math_optimization/solver_settings.cu
  • ci/test_cpp.sh
  • cpp/src/pdlp/solve.cu
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/include/cuopt/mathematical_optimization/constants.h
  • .gitignore
  • CONTRIBUTING.md
  • datasets/quadratic_programming/download_qplib_test_dataset.sh
  • cpp/src/dual_simplex/scaling.cpp
  • cpp/tests/dual_simplex/unit_tests/solve_barrier.cu

📝 Walkthrough

Walkthrough

Changes

The QPLIB downloader now supports S3 with HTTP fallback and is wired into CI and contributor instructions. QCQP Ruiz equilibration is configurable, and barrier scaling uses both row and column imbalance ratios with QPLIB regression tests.

QPLIB scaling regression

Layer / File(s)Summary
QPLIB dataset acquisition and wiring
datasets/quadratic_programming/download_qplib_test_dataset.sh, ci/test_cpp.sh, CONTRIBUTING.md, .gitignore
Adds S3-first QPLIB downloads with HTTP fallback, CI and documentation commands, and an ignore rule for downloaded instances.
QCQP Ruiz configuration plumbing
cpp/include/cuopt/mathematical_optimization/constants.h, cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp, cpp/src/dual_simplex/simplex_solver_settings.hpp, cpp/src/math_optimization/solver_settings.cu, cpp/src/pdlp/solve.cu
Declares, validates, initializes, and forwards the QCQP Ruiz equilibration setting into barrier solver settings.
Column-aware Ruiz scaling regression
cpp/src/dual_simplex/scaling.cpp, cpp/tests/dual_simplex/unit_tests/solve_barrier.cu
Uses row and column norm ratios for automatic Ruiz-scaling decisions and adds QPLIB_8515 barrier tests for enabled and forced-off behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers:msarahan, chris-maes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 18.18% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly summarizes the main change to the Ruiz equilibration skip heuristic.
Description check✅ PassedThe description matches the implemented scaling fix, dataset support, CI/docs updates, and regression test.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@datasets/quadratic_programming/download_qplib_test_dataset.sh`:
- Line 1: Update the dataset download script to enable strict shell error
handling and ensure a failed wget for QPLIB_8515.lp exits with a nonzero status
instead of being masked by continue.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4a58299f-8732-465d-aa64-49ef9aeee586

📥 Commits

Reviewing files that changed from the base of the PR and between 077e514 and d43e238.

📒 Files selected for processing (6)
  • .gitignore
  • CONTRIBUTING.md
  • ci/test_cpp.sh
  • cpp/src/dual_simplex/scaling.cpp
  • cpp/tests/dual_simplex/unit_tests/solve_barrier.cu
  • datasets/quadratic_programming/download_qplib_test_dataset.sh

@ramakrishnap-nvramakrishnap-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A minor suggestion

Comment thread.gitignore
!datasets/quadratic_programming
!datasets/quadratic_programming/**
# downloaded QPLIB instances (see download_qplib_test_dataset.sh)
datasets/quadratic_programming/qplib/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
datasets/quadratic_programming/qplib/
!datasets/quadratic_programming/qplib/

Should this be

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I think this is correct because we want to ignore the downloaded instances, while not ignoring the checked-in instances.

@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.

Thanks for the improvements!

@mlubin

Copy link
Copy Markdown
ContributorAuthor

/ok to test d43e238

@mlubin

Copy link
Copy Markdown
ContributorAuthor

/ok to test 92e20ef

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/tests/dual_simplex/unit_tests/solve_barrier.cu`:
- Around line 266-269: Update the test around solve_lp and the existing solution
object to first assert optimal termination and verify the objective matches the
319.9999 reference value, then retain the iteration-count assertion. Ensure the
numerical correctness checks occur before validating that more than 50 steps
were taken.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6e24c9fd-4b16-4a8e-86ba-67ccfdf64b5d

📥 Commits

Reviewing files that changed from the base of the PR and between 5ea14b8 and 92e20ef.

📒 Files selected for processing (3)
  • cpp/include/cuopt/mathematical_optimization/constants.h
  • cpp/src/math_optimization/solver_settings.cu
  • cpp/tests/dual_simplex/unit_tests/solve_barrier.cu
🚧 Files skipped from review as they are similar to previous changes (2)
  • cpp/include/cuopt/mathematical_optimization/constants.h
  • cpp/src/math_optimization/solver_settings.cu

Comment threadcpp/tests/dual_simplex/unit_tests/solve_barrier.cu
@mlubin

Copy link
Copy Markdown
ContributorAuthor

/ok to test a6bcbfa

mlubinand others added 3 commits July 24, 2026 09:54
The skip heuristic in scaling() only measured row-norm imbalance, so a
QP/SOCP with balanced rows but severely imbalanced columns (e.g.
QPLIB_8515, where free variables appear only with ~1e-8 coefficients
against O(1) rows) received no scaling at all. The resulting augmented
KKT system was so ill-conditioned that barrier terminated at a
suboptimal point while reporting convergence (320.13 vs the true
optimum 320.00 on QPLIB_8515, non-deterministically across runs). With
the column check, Ruiz runs and the instance solves to 319.999989 in 14
iterations instead of 338.
Adds QPLIB_8515 as a downloaded test dataset (new
download_qplib_test_dataset.sh, wired into ci/test_cpp.sh and
CONTRIBUTING.md) and a full-solve regression test that asserts the
optimal objective matches the QPLIB reference value.
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
The skip heuristic now checks both row-norm and column-norm imbalance,
but the comment still described only row-norm imbalance.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
mlubin added 3 commits July 24, 2026 09:54
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
Drop the redundant force-on solve from the toggle test (it re-treads the equilibrated path); force-off now asserts a >50-iteration blow-up, and the default-path test bounds the equilibrated solve to <30 iterations. Remove the redundant Python registry test (already covered by test_solver_settings) and trim the redundant "hidden from --help" note from the QCQP comments.
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
The tri-state switch in scaling() was hand-aligned in a way clang-format rejects; reformat to satisfy ci/check_style.sh.
Signed-off-by: Miles Lubin <mlubin@nvidia.com>
@mlubin
mlubinforce-pushed the fix-ruiz-skip-column-imbalance branch from a6bcbfa to 378c96bCompareJuly 24, 2026 13:55
@mlubin

Copy link
Copy Markdown
ContributorAuthor

/ok to test 378c96b

@mlubin

Copy link
Copy Markdown
ContributorAuthor

/merge

@rapids-bot
rapids-botBot merged commit 0d93a5a into NVIDIA:mainJul 24, 2026
92 checks passed
@mlubin
mlubin deleted the fix-ruiz-skip-column-imbalance branch July 24, 2026 15:34
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugSomething isn't workingnon-breakingIntroduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@mlubin@rg20@yuwenchen95@ramakrishnap-nv@chris-maes