CARDAL

CARDAL: A Curvature-Aware Rank-Adaptive Distributed Augmented-Lagrangian Solver for Large-Scale SDPs

License Documentation PyPI version arXiv Distributed SDPLIB Interface

CARDAL is an open-source GPU low-rank solver for large-scale semidefinite programs with distributed multi-GPU support. It operates on a Burer-Monteiro low-rank factorization and targets semidefinite programs whose optimal solutions are (or are expected to be) low-rank.

The CARDAL paper is available on arXiv: A Curvature-Aware Rank-Adaptive Distributed Augmented-Lagrangian Solver for Large-Scale SDPs.

Problem Formulation

CARDAL solves standard-form semidefinite programs with block-diagonal PSD variables, an optional nonnegative LP block, and optional unrestricted real variables:

\begin{aligned}
\min \quad &
  \sum_{c=1}^p \langle C_c, X_c\rangle
  + c_{\mathrm{LP}}^\top x_{\mathrm{LP}}
  + c_{\mathrm{free}}^\top x_{\mathrm{free}} \\
\text{s.t.} \quad &
  \sum_{c=1}^p \langle A_{i,c},X_c\rangle
  + a_{i,\mathrm{LP}}^\top x_{\mathrm{LP}}
  + a_{i,\mathrm{free}}^\top x_{\mathrm{free}} = b_i,
  \quad i=1,\dots,m,\\
& X_c \succeq 0,\quad x_{\mathrm{LP}}\ge 0,\quad
  x_{\mathrm{free}}\in\mathbb{R}^{d_{\mathrm{free}}}.
\end{aligned}

$C$ and each $A_i$ are symmetric block-diagonal matrices. Every matrix is stored by its lower triangle only, and off-diagonal entries are not implicitly doubled — the same convention applies to the Python API. Each PSD block $X_c \in \mathbb{R}^{n_c \times n_c}$ is stored as a factor $V_c \in \mathbb{R}^{n_c \times r_c}$ with $X_c = V_c V_c^\top$.

Features

Requirements

When multiple CUDA versions are installed, select one with CUDACXX, for example CUDACXX=/usr/local/cuda-12.6/bin/nvcc.

Installation

Build from source (C++ CLI)

Multi-GPU support (MPI + NCCL) is enabled by default; add -DENABLE_MPI=OFF for a single-GPU-only binary. If the default nvcc is outdated or missing, prefix the first cmake invocation with CUDACXX=/path/to/nvcc.

git clone https://github.com/Lhongpei/CARDAL.git
cd CARDAL
cmake -S . -B build
cmake --build build --clean-first

The main binary lands at ./build/cardal. A sibling binary ./build/cardal_qubo (built when CARDAL_BUILD_QUBO=ON, default) specializes in QUBO-lifted SDPs, takes the same core CLI flags with a QUBO-specific input parser (./build/cardal_qubo -f model.qubo), and the main cardal binary rejects QUBO inputs. Run ./build/cardal_qubo -h for its full syntax.

Python package

CARDAL ships a NumPy-friendly, single-GPU Python package on PyPI:

pip install cardal

The package compiles its CUDA extension during installation, so a working CUDA 12.x toolchain is required. See python/README.md for optional dependencies, source builds, and the complete Python API.

Quickstart

Solve a problem file

CARDAL auto-detects SDPA, MATLAB, and PDSDP input formats:

./build/cardal -f problem.dat-s -O ./output

The solve summary is printed to the terminal. Passing -O ./output also writes the summary, low-rank primal factor, per-cone rank list, and dual solution to ./output. LP and free primal vectors are included when present.

CLI

# From a file (SDPA, MATLAB, or PDSDP; format auto-detected)
./build/cardal -f problem.dat-s -O ./output

Python Interface

import cardal

m = cardal.Model.read_file("problem.dat-s")        # or .dat-s.gz / .mat / .npz
result = m.solve(
    time_sec_limit=60.0,
    eps_primal_relative=1e-4,
    eps_dual_relative=1e-4,
    eps_optimal_relative=1e-4,
)
print(result.status, result.primal_objective, result.rel_objective_gap)

Advanced Usage

CLI reference

./build/cardal -f <PATH> [OPTIONS]

Solver parameters

Option Type Description Default
-e, --eps float Set the primal, dual, and objective-gap tolerances together. 1e-4
--eps-primal float Relative primal residual tolerance. 1e-4
--eps-dual float Relative dual residual tolerance. 1e-4
--eps-gap float Relative objective-gap tolerance. 1e-4
-r, --rank int Initial Burer-Monteiro rank. ceil(2 log m)
-R, --max-rank int Maximum rank of each PSD block. Pataki bound
--augmentation-mode string Rank augmentation backend: random, qp, closed-form, or sdp. random
-i, --inner-iters int L-BFGS iteration limit per outer step. 30000
-o, --outer-iters int Augmented-Lagrangian outer iteration limit. 20000000
-p, --penalty-fac float Penalty coefficient multiplier. 3.3
-c, --init-penalty float Initial penalty coefficient. 2 / sqrt(N)
-M, --max-penalty float Maximum penalty coefficient. 5e5
-L, --lbfgs-hist int L-BFGS history size. 5
-T, --time-limit float Wall-clock limit in seconds; 0 disables it. 3600
-v, --verbose int Log level: 0 silent, 1 summary, 2 iterations, 3 debug. 2
-O, --output-dir path Write the summary and primal/dual solution files. None

Distributed and scaling parameters

Option Type Description Default
-z, --grid-size string MPI grid as row,rank,cone; dimensions must multiply to the MPI process count. Auto
--shuffle string Distributed constraint ordering: none, uniform, block, or col. col
--l-inf-ruiz-iter int Number of L-infinity Ruiz scaling iterations; 0 disables them. 10
--pock-chambolle-alpha float Pock-Chambolle scaling exponent. 1.0
--no-pock-chambolle flag Disable Pock-Chambolle scaling. Off
--no-bound-obj-rescaling flag Disable bound-objective rescaling. Off
--psd-scale-mode string PSD scaling mode: per-element or per-cone. per-element
--no-scaling flag Disable all scaling stages. Off

Run ./build/cardal -h for the authoritative CLI help. The Python interface uses the same solver defaults; its keyword parameters are documented in python/README.md.

Multi-GPU with MPI + NCCL

The same binary auto-detects an MPI launch and switches to the distributed solver — MPI for control-plane messaging, NCCL for on-device collectives:

# 4 GPUs, process grid auto-selected
mpirun -n 4 ./build/cardal -f problem.dat-s -O ./output

# Explicit row x rank x cone grid
mpirun -n 4 ./build/cardal -f problem.dat-s --grid-size 2,2,1
mpirun -n 8 ./build/cardal -f problem.dat-s --grid-size 1,1,8

Troubleshooting

Contributing

Contributions and pull requests are welcome.

Citation

If you use CARDAL in academic work, please cite the companion paper:

@misc{li2026curvatureawarerankadaptivedistributedaugmentedlagrangian,
  title        = {A Curvature-Aware Rank-Adaptive Distributed Augmented-Lagrangian Solver for Large-Scale SDPs},
  author       = {Hongpei Li and Huikang Liu and Dongdong Ge and Yinyu Ye},
  year         = {2026},
  eprint       = {2607.17933},
  archivePrefix = {arXiv},
  primaryClass = {math.OC},
  url          = {https://arxiv.org/abs/2607.17933}
}

Machine-readable citation metadata is also available in CITATION.cff.

License

Copyright 2026 Hongpei Li.

Licensed under the Apache License, Version 2.0. See the LICENSE file for details.