Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
da142c1
Archive sparse-CG and CUDA Graph research snapshot
Ztang-Yit-Xiaang Jun 24, 2026
af052f4
Add torch OSQP dense reference work
Ztang-Yit-Xiaang Jun 26, 2026
3a8ba26
Record Torch OSQP evidence regeneration
Ztang-Yit-Xiaang Jun 27, 2026
cdbad24
Refresh Torch OSQP completion audit
Ztang-Yit-Xiaang Jun 28, 2026
90f0bcb
Record Torch OSQP audit provenance refresh
Ztang-Yit-Xiaang Jun 28, 2026
ab84fee
Update Torch OSQP release audit status
Ztang-Yit-Xiaang Jul 1, 2026
02e24fb
Move stability conditioning diagnostic to CPU
Ztang-Yit-Xiaang Jul 1, 2026
1eb86db
Record Torch OSQP release evidence refresh
Ztang-Yit-Xiaang Jul 2, 2026
5544bfe
Write partial stability evidence on timeout
Ztang-Yit-Xiaang Jul 2, 2026
e010733
Clarify CUDA evidence promotion boundary
Ztang-Yit-Xiaang Jul 2, 2026
5915574
Record Torch OSQP timeout evidence reporting
Ztang-Yit-Xiaang Jul 2, 2026
d9d5b9d
Fix pipeline PDF table header rendering
Ztang-Yit-Xiaang Jul 2, 2026
a7005e8
Record pipeline PDF regeneration
Ztang-Yit-Xiaang Jul 2, 2026
e328fbf
Record pushed archive branch status
Ztang-Yit-Xiaang Jul 2, 2026
8fa903c
Record archive branch evidence refresh
Ztang-Yit-Xiaang Jul 2, 2026
16bf5cf
Remove obsolete ruff ignore
Ztang-Yit-Xiaang Jul 2, 2026
34ee8c5
Record ruff config evidence refresh
Ztang-Yit-Xiaang Jul 2, 2026
d12f475
docs: sync Torch-OSQP release-readiness package
Ztang-Yit-Xiaang Jul 6, 2026
88bfd16
docs: record fork nightly stability evidence
Ztang-Yit-Xiaang Jul 6, 2026
45d1d5b
update
Ztang-Yit-Xiaang Jul 10, 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
1,470 changes: 1,470 additions & 0 deletions .codex/code-edit-log.md

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions .github/workflows/torch-osqp-core.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Torch OSQP core

on:
push:
pull_request:
workflow_dispatch:

jobs:
deterministic-core:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
python: "3.10"
torch: "torch==2.8.0"
- os: ubuntu-latest
python: "3.12"
torch: "torch"
- os: ubuntu-latest
python: "3.13"
torch: "torch"
- os: windows-latest
python: "3.10"
torch: "torch==2.8.0"
- os: windows-latest
python: "3.12"
torch: "torch"
- os: macos-latest
python: "3.10"
torch: "torch==2.8.0"
- os: macos-latest
python: "3.12"
torch: "torch"
runs-on: ${{ matrix.os }}
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Install CPU test environment
shell: bash
run: |
python -m pip install --upgrade pip
if [[ "$RUNNER_OS" == "macOS" ]]; then
python -m pip install "${{ matrix.torch }}"
else
python -m pip install "${{ matrix.torch }}" --index-url https://download.pytorch.org/whl/cpu
fi
python -m pip install numpy scipy osqp pytest gurobipy
python -m pip install -e . --no-deps
- name: Run deterministic and end-to-end gates
run: python -m pytest tests -q
57 changes: 57 additions & 0 deletions .github/workflows/torch-osqp-cuda-promotion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Torch OSQP CUDA promotion gate

on:
workflow_dispatch:

jobs:
cuda-real-hardware:
runs-on: [self-hosted, cuda]
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Verify preinstalled CUDA PyTorch
run: >-
python -c "import torch; assert torch.cuda.is_available();
print(torch.__version__, torch.cuda.get_device_name())"
- name: Install non-Torch test dependencies
run: >-
python -m pip install numpy scipy osqp pytest gurobipy
- name: Install PyGRANSO without replacing CUDA PyTorch
run: python -m pip install -e . --no-deps
- name: CUDA float64 correctness and stress
run: >-
python torch_osqp_stability.py
--device cuda
--dtype float64
--seeds 100
--stress-seeds 100
--time-limit-seconds 7200
--output artifacts/cuda-float64
- name: CUDA qualified float32 correctness
run: >-
python torch_osqp_stability.py
--device cuda
--dtype float32
--seeds 100
--stress-seeds 100
--time-limit-seconds 7200
--output artifacts/cuda-float32
- name: End-to-end five-times promotion ceiling
run: >-
python bench_pygranso_osqp_workloads.py
--workloads B1 B2 B3
--repeats 5
--warmups 2
--maxit 20
--maximum-slowdown 5
--enforce-gate
--export-csv artifacts/cuda-performance.csv
--export-md artifacts/cuda-performance.md
- uses: actions/upload-artifact@v4
if: always()
with:
name: torch-osqp-cuda-promotion
path: artifacts
46 changes: 46 additions & 0 deletions .github/workflows/torch-osqp-nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Torch OSQP nightly stability

on:
schedule:
- cron: "17 5 * * *"
workflow_dispatch:

jobs:
cpu-stability:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
dtype: [float32, float64]
runs-on: ${{ matrix.os }}
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install current stable CPU environment
shell: bash
run: |
python -m pip install --upgrade pip
if [[ "$RUNNER_OS" == "macOS" ]]; then
python -m pip install torch
else
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
fi
python -m pip install numpy scipy osqp pytest gurobipy
python -m pip install -e . --no-deps
- name: Generate fixed-seed evidence
run: >-
python torch_osqp_stability.py
--device cpu
--dtype ${{ matrix.dtype }}
--seeds 100
--stress-seeds 100
--time-limit-seconds 7200
--output artifacts/${{ matrix.os }}-${{ matrix.dtype }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: torch-osqp-${{ matrix.os }}-${{ matrix.dtype }}
path: artifacts/${{ matrix.os }}-${{ matrix.dtype }}
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,9 @@ examples/TMLR/user_grad_constr_dl_orthogonal_constraint.py.lprof
examples/TMLR/constr_dl_orthogonal_constraint.py.lprof
examples/TODO

*neural-structural-optimization*
*neural-structural-optimization*

# Generated Torch-OSQP evidence and PDF render scratch. Release artifacts are
# force-added deliberately after their source commit is cleanly identified.
tmp/
output/
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,54 @@ By default, `pip` or `uv` may install a CPU-only build of PyTorch. For **GPU (CU

Set `opts.torch_device = torch.device("cuda")` when calling PyGRANSO to use the GPU.

### OSQP backend options

PyGRANSO uses OSQP for its internal quadprog-compatible QP subproblems. The
Torch route is a correctness-first dense reference implementation with a
replaceable linear-solver boundary. It is not a sparse large-scale solver.

- `opts.osqp_algebra = "auto"` follows `opts.torch_device`: CPU uses builtin
OSQP; a validated accelerator uses Torch inside the supported KKT and memory
envelope. Unsupported or unsuccessful Torch solves visibly fall back to
builtin OSQP and retain structured fallback diagnostics.
- `opts.osqp_algebra = "builtin"` forces CPU OSQP.
- `opts.osqp_algebra = "torch"` explicitly requests the dense Torch reference
route on `opts.torch_device`. Above the validated `n + m <= 2400` KKT limit,
it warns and attempts the solve rather than silently changing backend.
- `opts.osqp_settings` overrides common settings shared by builtin and Torch.
Defaults are dtype-aware (`1e-8` for float64 and `1e-5` for float32) and
enable 10-pass Ruiz scaling, deterministic adaptive rho, polishing, and
structurally compatible warm starts.

Float64 is authoritative through estimated KKT conditioning around `1e8`.
Float32 is a qualified route with a conservative conditioning envelope around
`1e2`; harder float32 cases are retained as stress evidence rather than
claimed support.

Archived sparse-CG and CUDA Graph settings are recognized for one migration
release but raise an actionable deprecation error. The research implementation
is preserved on `archive/sparse-cg-cuda-graph`.

Torch support is promoted backend-by-backend. CPU and CUDA require their own
release gates. ROCm remains unclaimed until real-hardware CI is available. MPS
is float32-only and remains unclaimed until reusable LU is validated on Apple
hardware; float64 MPS auto requests return the builtin CPU float64 solution.

The current local NVIDIA run passed the fixed-seed correctness buckets but
failed the end-to-end promotion gate at 12.48x, 21.33x, and 43.46x builtin CPU
runtime on representative B1/B2/B3 workloads, so CUDA remains unpromoted and
`auto` falls back visibly to builtin OSQP.

PyGRANSO does not differentiate through the OSQP QP solve; autograd is used to
compute the objective and constraint gradients before QP construction.

### Verify installation

- **CPU:** `python test_cpu.py`
- **CUDA:** `python test_cuda.py`
- **Torch OSQP core:** `python -m pytest tests -q`
- **Stability evidence:** `python torch_osqp_stability.py --seeds 100`
- **Dense reference benchmark:** `python bench_osqp_dense_reference.py`

Then check the [example folder](./examples) or the [example section](https://ncvx.org/examples) on the documentation website to get started.

Expand Down Expand Up @@ -163,4 +207,3 @@ Thanks to other contributors and bug reporters:
- [Ying Cui](https://sites.google.com/site/optyingcui/home): Advised the adversarial robustness problems.

- [Chen Jiang](https://github.com/shoopshoop): Tested perceptual attack example (ex6). Tested PyGRANSO on Win10. Debugged updatePenaltyParameter function.

Loading