1 Guide
1.1 The problem SCS solves
SCS solves the convex quadratic cone program
minimize (/ 1 2) xᵀPx + cᵀx
subject to Ax + s = b, s ∈ K
over the variable x ∈ ℝⁿ and slack s ∈ ℝᵐ, where P is symmetric positive semidefinite, A is m×n, and K is a closed convex cone. SCS simultaneously produces a solution to the dual problem; the dual variable is returned as scs-result-y. See the upstream algorithm notes for the precise primal/dual pair.
In Racket you supply A and the optional P as compressed-sparse-column matrices (scs:matrix / scs:sparse-matrix), b and c as vectors or lists, and K as a make-cone value, then call solve.
1.2 Cones
The cone K is a Cartesian product of primitive cones. The rows of A (and the entries of b and s) must appear in this exact order, which is also the order of the make-cone keywords:
zero cone —
#:zero equality rows (s = 0). positive orthant —
#:positive inequality rows (s ≥ 0). box cone —
#:box-lower / #:box-upper; see Box cones. second-order (Lorentz) cones —
#:soc, a list of block sizes; each block (t, u) satisfies ‖u‖₂ ≤ t. positive semidefinite cones —
#:psd, a list of matrix dimensions; see Semidefinite cones. exponential cones —
#:exp-primal / #:exp-dual counts of triples; the primal cone is the closure of {(x,y,z) : y·e^(x/y) ≤ z, y > 0}. power cones —
#:power, a list of parameters in [-1, 1] (negative values select the dual power cone).
This mirrors the cone ordering documented in the SCS cones reference.
1.2.1 Box cones
The box cone is {(t, r) : t·l ≤ r ≤ t·u} with a leading scale variable t. To impose plain bounds l ≤ y ≤ u, arrange A and b so the first box row’s slack is a constant 1 (a row of zeros in A with the matching b entry equal to 1) and the remaining rows carry y. make-cone takes the bounds with #:box-lower and #:box-upper; their length is the number of box-constrained entries, and SCS’s bsize is that length plus one. Model predictive control is a worked example.
1.2.2 Semidefinite cones
For a k×k symmetric matrix, the PSD cone slack is the lower triangle stacked column-wise with the off-diagonal entries scaled by √2; the block length is k(k+1)/2. So a 2×2 matrix [[a b] [b c]] is represented by (a, √2·b, c). #:psd takes the list of k values. See the cones reference and Semidefinite program.
1.3 Building matrices and vectors
scs:matrix builds a matrix from a dense, row-major sequence of values:
(scs:matrix 3 2 ; 3 rows, 2 columns -1 1 1 0 0 1)
scs:sparse-matrix builds one from explicit (row col value) triples, which is convenient for a quadratic P (supply only the upper triangle):
(scs:sparse-matrix 2 2 '(0 0 3) '(0 1 -1) '(1 1 2))
Both return a CSC matrix suitable for #:A or #:P. The right-hand side b and objective c are passed to solve as plain vectors or lists.
1.4 Settings
make-settings produces a settings value populated with SCS’s defaults, overridden by the keywords you pass. Unlike the C library, verbose? defaults to #f (libraries should be quiet). The most common knobs are the convergence tolerances #:eps-abs and #:eps-rel (SCS default 0.0001) and #:max-iters. See the upstream settings reference for the full list and defaults. Passing no #:settings to solve uses the defaults.
1.5 Solving and reading results
solve returns an scs-result. Check solved? (true when the exit flag is 1, SCS_SOLVED); scs-result-status is the human-readable status string and scs-result-status-val the integer exit flag. The exit flags follow the SCS exit-flag reference: 1 solved, 2 solved-inaccurate, -1 unbounded, -2 infeasible, and -3 through -7 for the indeterminate/failed/interrupted and inaccurate-certificate cases.
The primal solution is scs-result-x, the dual is scs-result-y, and the slack is scs-result-s; scs-result-pobj and scs-result-dobj are the primal and dual objectives.
1.5.1 Direct vs. indirect solver
By default solve uses the direct linear-system solver. Pass #:indirect? #t to use the indirect (conjugate-gradient) solver, which can scale better on very large sparse problems.
1.5.2 Warm starting and re-solving
When a sequence of problems differs only in b or c, you can keep one solver workspace and update it instead of rebuilding from scratch. This is done through the scs/foreign layer with scs-init, scs-update, and scs-solve (passing a warm flag of 1 to the re-solve). Lasso with warm starting and Model predictive control show the pattern.