Semidefinite Programming (SDP) in Julia

We will show how to solve the Basic QP example problem both natively in Clarabel.jl and also by solving with Clarabel.jl within either JuMP or Convex.jl.

Clarabel.jl native interface

using Clarabel, SparseArrays, LinearAlgebra

n    = 3
nvec = Int(n*(n+1)/2)

P = spzeros(nvec,nvec)

q = [1.,0.,1.,0.,0.,1.]

A1 = -Diagonal([                         #<-- LHS of SDP constraint
     1., sqrt(2), 1., sqrt(2), sqrt(2), 1.
])
A2 = [1. 2(2.) 3. 2(4.) 2(5.) 6.]        #<-- LHS of equality constraint
A  = sparse([A1;A2]);

b = [zeros(nvec);                       #<-- RHS of SDP constraint
     1.]                                #<-- RHS of equality constraint

cones =
    [Clarabel.PSDTriangleConeT(n),      #<--- for the SDP constraint
     Clarabel.ZeroConeT(1)]             #<--- for the equality constraints

settings = Clarabel.Settings()

solver   = Clarabel.Solver()

Clarabel.setup!(solver, P, q, A, b, cones, settings)

result = Clarabel.solve!(solver)
-------------------------------------------------------------
           Clarabel.jl v0.8.1  -  Clever Acronym
                   (c) Paul Goulart
                University of Oxford, 2022
-------------------------------------------------------------

problem:
  variables     = 6
  constraints   = 7
  nnz(P)        = 0
  nnz(A)        = 12
  cones (total) = 2
    : Zero        = 1,  numel = 1
    : PSDTriangle = 1,  numel = 6

settings:
  linear algebra: direct / qdldl, precision: Float64
  max iter = 200, time limit = Inf,  max step = 0.990
  tol_feas = 1.0e-08, tol_gap_abs = 1.0e-08, tol_gap_rel = 1.0e-08,
  static reg : on, ϵ1 = 1.0e-08, ϵ2 = 4.9e-32
  dynamic reg: on, ϵ = 1.0e-13, δ = 2.0e-07
  iter refine: on, reltol = 1.0e-13, abstol = 1.0e-12,
               max iter = 10, stop ratio = 5.0
  equilibrate: on, min_scale = 1.0e-04, max_scale = 1.0e+04
               max iter = 10

iter    pcost        dcost       gap       pres      dres      k/t        μ       step
---------------------------------------------------------------------------------------------
  0   7.3529e-02   7.3529e-02  2.78e-17  4.30e-01  7.71e-01  1.00e+00  1.33e+00   ------
  1   1.3789e-01   4.0894e-02  9.70e-02  7.31e-02  1.14e-01  5.93e-03  2.32e-01  8.70e-01
  2   8.3910e-02   8.1077e-02  2.83e-03  2.57e-03  3.46e-03  6.34e-04  9.67e-03  9.64e-01
  3   8.6450e-02   8.6422e-02  2.79e-05  2.55e-05  3.38e-05  6.39e-06  9.73e-05  9.90e-01
  4   8.6475e-02   8.6475e-02  2.79e-07  2.55e-07  3.38e-07  6.39e-08  9.73e-07  9.90e-01
  5   8.6475e-02   8.6475e-02  2.79e-09  2.55e-09  3.38e-09  6.39e-10  9.73e-09  9.90e-01
---------------------------------------------------------------------------------------------
Terminated with status = solved
solve time =  806μs

Recover the symmetric matrix X

X = zeros(n,n)
X[triu(ones(Bool,3,3))] .= result.x
X = Symmetric(X)
3×3 Symmetric{Float64, Matrix{Float64}}:
 0.0128947  0.0177209  0.0251946
 0.0177209  0.0243534  0.0346243
 0.0251946  0.0346243  0.0492269

Using JuMP

We can solve the same problem a little more easily by using Clarabel.jl as the backend solver within JuMP. Here is the same problem again. Note that we are not required to model our SDP constraint in triangular form if we are using JuMP.

using Clarabel, JuMP

n = 3
A = [1 2 4;
     2 3 5;
     4 5 6]

model = JuMP.Model(Clarabel.Optimizer)
set_optimizer_attribute(model, "verbose", true)
set_optimizer_attribute(model, "equilibrate_enable",false)

@variable(model, X[1:n,1:n],PSD)
@constraint(model, tr(A*X) == 1)
@objective(model, Min, tr(X))

optimize!(model)
-------------------------------------------------------------
           Clarabel.jl v0.8.1  -  Clever Acronym
                   (c) Paul Goulart
                University of Oxford, 2022
-------------------------------------------------------------

problem:
  variables     = 6
  constraints   = 7
  nnz(P)        = 0
  nnz(A)        = 12
  cones (total) = 2
    : Zero        = 1,  numel = 1
    : PSDTriangle = 1,  numel = 6

settings:
  linear algebra: direct / qdldl, precision: Float64
  max iter = 200, time limit = Inf,  max step = 0.990
  tol_feas = 1.0e-08, tol_gap_abs = 1.0e-08, tol_gap_rel = 1.0e-08,
  static reg : on, ϵ1 = 1.0e-08, ϵ2 = 4.9e-32
  dynamic reg: on, ϵ = 1.0e-13, δ = 2.0e-07
  iter refine: on, reltol = 1.0e-13, abstol = 1.0e-12,
               max iter = 10, stop ratio = 5.0
  equilibrate: off, min_scale = 1.0e-04, max_scale = 1.0e+04
               max iter = 10

iter    pcost        dcost       gap       pres      dres      k/t        μ       step
---------------------------------------------------------------------------------------------
  0   7.3529e-02   7.3529e-02  4.16e-17  6.11e-01  3.73e-01  1.00e+00  1.48e+00   ------
  1   9.5000e-02   4.5267e-02  4.97e-02  7.92e-02  3.07e-02  6.41e-03  1.30e-01  9.46e-01
  2   8.3793e-02   8.2081e-02  1.71e-03  2.90e-03  1.09e-03  2.10e-04  5.15e-03  9.62e-01
  3   8.6449e-02   8.6432e-02  1.69e-05  2.88e-05  1.08e-05  2.12e-06  5.18e-05  9.90e-01
  4   8.6475e-02   8.6475e-02  1.69e-07  2.88e-07  1.08e-07  2.12e-08  5.18e-07  9.90e-01
  5   8.6475e-02   8.6475e-02  1.69e-09  2.88e-09  1.08e-09  2.12e-10  5.18e-09  9.90e-01
---------------------------------------------------------------------------------------------
Terminated with status = solved
solve time =  781μs

Here is the solution again

JuMP.value.(X)
3×3 Matrix{Float64}:
 0.0128947  0.0177209  0.0251946
 0.0177209  0.0243534  0.0346243
 0.0251946  0.0346243  0.0492269

This page was generated using Literate.jl.