Skip to content

SCS 3.3.2

Latest

Choose a tag to compare

@bodono bodono released this 15 Nov 12:18
f0036c3

SCS 3.3.2 makes the 3.3 series faster and more robust. A new scale-update rule fixes slow and inaccurate solves of feasibility problems, the cuDSS GPU solver is leaner and faster, problems with many PSD blocks can be projected in parallel, and single-precision builds now work. The C API and ABI are unchanged: scs.h differs from 3.3.1 only in comments, and the shared libraries keep the 3.3 loader identity. The Python and MATLAB releases both use core commit f0036c3aea2b8e3d371f3c5e2ea23a1639ee8354.

Upgrade highlights

  • Scale updates (#508, #510). On feasibility problems with c = 0 and no P, such as those in CVXPY's DQCP bisection, 3.3.1 could need 10 to 300 times more iterations than 3.2.7 or return solved (inaccurate) for an infeasible problem (#499). The scale no longer stalls at its floor: through CVXPY, the issue's three DQCP examples now solve with no inaccurate subproblem, two of them in fewer iterations than 3.2.7. Over the benchmark's feasible problems the new rule solves more problems in fewer iterations (details below). One case from the issue, parity_call015, now returns its certificate but still takes about 70 times the iterations of 3.2.7, and with CVXR's settings that bisection can still end optimal_inaccurate. Solves that update the scale can take a different path from 3.3.1, and the path now depends on the ratio of eps_abs to eps_rel.
  • cuDSS (#513, #525). SCS now runs cuDSS without pivoting, matching or (in double precision) iterative refinement: a plain LDL' factorization, as the CPU direct solver does. Factors are up to four times smaller and each iteration costs one solve: faster than 3.3.1's settings on LPs and QPs, SOCPs and SDPs, and faster on every set of the 3.3.2 benchmark than the interim setting of #513. The tradeoff: a few small, badly conditioned problems converge more slowly or not at all without a refinement step.
  • Parallel PSD projection (#505, #506, #507). The new build option USE_PARALLEL_PSD projects PSD blocks in parallel with OpenMP. It is off by default, and the Python wheels and MATLAB toolbox do not enable it, because it is only faster when the BLAS runs on one thread inside SCS's threads.
  • Single precision (#520). SFLOAT builds, still experimental, failed most of the test suite on every backend. They now pass it and are tested in CI.

The benchmarks page has been rerun for 3.3.2 (#526), with every solver on the same hardware and every solution verified independently. At a target accuracy of 1e-4, SCS with cuDSS is the fastest solver tested on the largest quarter of the QPs and of the LPs, and verifies 29 of the 37 large Mittelmann LPs, more than any other solver, in less than half the runner-up's geometric mean time. SCS is well ahead of every other first-order solver, and on SDPs it verifies 83 of 94, more than any interior-point solver run near its default accuracy. Interior-point solvers remain faster on smaller QPs, on QPs at tighter accuracy and on SDPs that fit in memory. Raw data: campaign scs332_2026-11, full archive on release scs332-2026-11.

Scale updates (#508, #510)

  • Each scale-update sample now blends two primal-to-dual ratios, the distance of each residual from its stopping threshold and the residuals themselves, weighted by how many correct digits each side has. A dual residual as large as its own terms (as when c = 0 and P = 0) no longer reads as permanently behind and drives the scale to its floor. Over the benchmark's feasible sets this solved 664 of 755 problems at 1e-4 (650 before; 22 gained, 8 lost) and 585 of 718 at 1e-6 (570 before), in 0.93x and 0.88x the iterations.
  • adaptive_diag_scale (on by default) now updates the per-row multipliers alone only when they would move by more than the threshold as installed, after each cone block has been given its form. On 213 cone and SDP problems this cut refactorizations to 0.11x to 0.19x. LPs and QPs are unchanged by this part, bit for bit.
  • The scale page describes the rule as the code runs it (#516).

cuDSS GPU solver (#513, #525)

3.3.1 left every cuDSS setting at its default. From cuDSS 1.0 that pivots and applies a matching, which made factors up to four times larger. The KKT matrix of SCS is quasi-definite, so a plain LDL' factorization exists under any ordering.

  • Against 3.3.1's settings on an NVIDIA GB10 with cuDSS 1.0.0, total solve time was 0.92x on 17 LPs and QPs, 0.34x on random SOCPs and 0.97x on 10 SDPLIB problems (geometric means).
  • In the 3.3.2 benchmark on an A100, this setting was faster on every problem set than the interim setting of #513, which added one refinement step per solve. Without refinement there is no safety net: a few small, badly conditioned problems (SDPLIB's control5, control6, hinf3, hinf7 and hinf10, and the LPs pds-10, pds-20 and traininstance6) converged more slowly or not at all, while others now solve that did not. The worst relative residual of a solve in the test suite is about 6e-8, against 5e-11 with cuDSS's defaults.
  • Single-precision builds keep one refinement step per solve. Every supported cuDSS version (0.5 to 1.0) factorizes the same way.

Parallel PSD projection (#505, #506, #507)

  • USE_PARALLEL_PSD (make and CMake; needs USE_OPENMP and USE_LAPACK; Python: use_parallel_psd) projects the real and complex PSD blocks on several threads, chosen at setup from the estimated time of each block. On 4 threads, whole solves of problems with many PSD blocks ran 2.7 to 3.0 times faster. A problem with one dominant block stays serial.
  • A BLAS with its own thread pool, such as a pthreads OpenBLAS left at its default, makes it slower. Read Parallel projection of PSD blocks before turning it on.

Other solver fixes

  • Power cone (#493, fixes #491). The projection is now scale-invariant, with a safeguarded Newton method. 3.3.1 could return solved with the slack outside the cone when the iterates were tiny. Cone time per iteration rose by about 8% on the CVXPY power-cone models measured.
  • Spectral cones (#442). Log-determinant warm starts are reset when the scale changes, and adaptive_diag_scale is no longer switched off for problems with spectral cones.
  • LAPACK failures (#442, #506). An eigendecomposition that LAPACK does not complete now stops the solve with a failure instead of continuing with a partly projected block.
  • GPU indirect solver (#511). The diagonal scalings in each CG iteration now take linear rather than quadratic time: a random SOCP with n = 50,000 solved in 91 s instead of 311 s on a GB10.

Build fixes

  • CMake builds and installs the GPU indirect solver with -DUSE_GPU=ON as scs::scsgpuindir, with 32-bit integers (#445, #519).
  • Make: libscscudss now links libcudss and BLAS/LAPACK (#523); DLONG=1 no longer corrupts the heap in cuDSS builds (#487); CUCC defaults correctly when only CUDA_PATH is set (#427); the GPU indirect source includes string.h (#428).
  • make USING_R=1 now prints through R. CMake reports the OpenMP it found rather than the one requested, refuses USE_PARALLEL_PSD without OpenMP, and no longer picks up a parent project's OpenMP when USE_OPENMP is off (#518).

Python and MATLAB distributions

Python 3.3.2 adds Windows ARM64 wheels, the use_parallel_psd build option, fixes for GPU source builds, and a clear error for the solver-selection flags removed in 3.3.0. Install with:

python -m pip install --upgrade scs

MATLAB 3.3.2 provides the rebuilt SCS.mltbx with this core; the MATLAB interface is unchanged.

Validation and documentation

CI now tests single precision on Linux and macOS (#520), runs the GPU indirect and cuDSS suites on a simulated GPU (#486, #488, #504), tests MKL with OpenMP (#506), and reports every failing and skipped test (#438, #468). New regression tests cover #140, #220, #491, #499 and a non-PSD P (#444, #446, #493, #508, #523). The docs gained corrections from a read-through against the code (#517), GPU pages checked on a GPU (#519, #522), Python cuDSS install instructions (#524) and the benchmarks page (#476, #482, #526). The remaining changes are CI fixes and dependency updates.

Full core changelog