A Gentle Start

SDPA for Python solves Conic-form Linear Optimization Problems (CLPs). A CLP is of the form:

\[\begin{aligned} (\mathcal{P}) \min_{x}. \quad & c^T x\\ \textrm{s.t.} \quad & x \succeq_K 0\\ & A x - b \succeq_J 0, \end{aligned}\]

where \(\mathcal{ J }\) and \(\mathcal{ K }\) represents cones, that will be defined in the next subsection.

As an example, we will solve the following specific CLP in this section as a gentle begin, the problems is defined as \((\mathcal{P})\) with

\[\begin{aligned} &\boldsymbol{A}=\left(\begin{array}{cccc} 10 & 4 & 4 & 0 \\ 0 & 0 & 0 & -8 \\ 0 & -8 & -8 & -2 \end{array}\right), \quad \boldsymbol{b}=\left(\begin{array}{c} 48 \\ -8 \\ 20 \end{array}\right), \quad \boldsymbol{c}=\left(\begin{array}{c} -11 \\ 0 \\ 0 \\ 23 \end{array}\right) \\ &\text { J.f }=3, \quad \mathrm{~K} . \mathrm{s}=2, \end{aligned}\]

where J.f and K.s represents the data format of the corresponding cones \(\mathcal{ J }\) and \(\mathcal{ K }\).

Data Format in SDPAP

As seen above, the problem data is read into Python variables A, b, c, K and J.

A, b and c may be defined as numpy.ndarray or one of the sparse array formats (e.g. csr_array or csc_array) in scipy.sparse.

K and J are SymCone objects, a data structure provided in sdpa-python. They can be initialized using K = sdpap.SymCone() and J = sdpap.SymCone() respectively. We need to set their parameters according to the problem.

In the CLP problem form shown above, the generalized inequality \(x \succeq_{\mathcal{ K }} 0\) means \(x\in \mathcal{ K }\) for cone \(\mathcal{ K}\). The cones \(\mathcal{ J }\) and \(\mathcal{ K }\) are each defined as Cartesian product of three different type of cones:

\(\mathcal{ K } = \mathcal{ K }_{f}\times\mathcal{ K }_{l}\times\mathcal{ K }_{s}\) and \(\mathcal{ J } = \mathcal{ J }_{f}\times\mathcal{ J }_{l}\times\mathcal{ J }_{s}\)

Corresponding to each type, we will specify for cone \(\mathcal{ K }\), the parameters K.f, K.l, K.s and similarly for cone \(\mathcal{ J }\), the parameters J.f, J.l, J.s

These parameters specify the type of constraints, which will be discussed in the following.

\(f \colon\) Equality Constraints

​ The cone with subscript \(f\) represents \(x\) that satisfies the equality constraint. In code, we use J.f or K.f to represent the number of equality constraint. For example, for

\[\left(\begin{array}{cccc} 10 & 4 & 4 & 0 \\ 0 & 0 & 0 & -8 \\ 0 & -8 & -8 & -2 \end{array}\right) x-\left(\begin{array}{c} 48 \\ -8 \\ 20 \end{array}\right)=0,\]

We have three equality constraints. Hence, J.f = 3. ​

\(l \colon\) LP Cones

The cone with subscript \(l\) represents the LP cone, i.e., \(x\) such that \(\left\{x\colon x \succeq_{\mathbb{ R }_{+}^{n}} 0\right\}\) In code, we use J.l or K.l to represent the size of variables in the LP cone constraints.

For example, for

\[\left(\begin{array}{cccc} 10 & 4 & 4 & 0 \\ 0 & 0 & 0 & -8 \\ 0 & -8 & -8 & -2 \end{array}\right) x-\left(\begin{array}{c} 48 \\ -8 \\ 20 \end{array}\right)\succeq_{\mathbb{ R }_{+}^{n}} 0,\]

We have three inequality constraints. Thus, J.l = 3. ​

\(s\colon\) SDP Cones

The cone with subscript \(s\) represents the SDP cones. One SDP cone is defined as the set

\[\left\{\boldsymbol{x}_{s}: \text{vec}^{-1}(\boldsymbol{x}_{s})\succeq_{S_{+}} \mathbf{0}\right\}\]

where \(S_{+}\) represents positive-semidefinite cone. The size of \(\boldsymbol{x}_{s}\) must be a square of an integer, i.e., \(\boldsymbol{x}_{s} \in \mathbb{ R }^{n^2}\) and \(\text{vec}^{-1}(\boldsymbol{x}_{s}) \in \mathbb{ R }^{n\times n}\) ​ The symbol \(\text{vec}^{-1}(x)\) means the matrix formed by the vector \(x\). That is, if

\[\boldsymbol{x}_{s}=\left[\begin{array}{l} x_{1} \\ x_{2} \\ x_{3} \\ x_{4} \end{array}\right]\]

then

\[\text{vec}^{-1}\left(\boldsymbol{x}_{s}\right)=\left(\begin{array}{ll} x_{1} & x_{3} \\ x_{2} & x_{4} \end{array}\right)\]

In code, we use J.s or K.s as a tuple to represents the number of SDP cone constraints and the number of the rows or columns of the matrix in each SDP cone. For example, if we have three SDP cone constraints \(\boldsymbol{x}_{1}\succeq_{S_{+}} 0,\boldsymbol{x}_{2}\succeq_{S_{+}} 0\) and \(\boldsymbol{x}_{3} \succeq_{S_{+}} 0\) and \(\boldsymbol{x}_{i}\in \mathbb{ R }^{i^2}\) for any \(i = 1,2,3\). Then K.s = (1,2,3).

Solving the Sample CLP

Now, we can define and solve the sample CLP given in the beginning of this section by the following code:

import sdpap
import numpy as np

A = np.array([
    [10, 4, 4, 0],
    [0, 0, 0, -8],
    [0, -8, -8, -2]    
])

b = np.array([
    [48],
    [-8],
    [20]
])

c = np.array([
    [-11],
    [0],
    [0],
    [23]
])

K = sdpap.SymCone(s=(2,))
J = sdpap.SymCone(f=3)

x, y, sdpapinfo , timeinfo , sdpainfo = sdpap.solve(A,b,c,K,J)

The output will be as below:

---------- SDPAP Start ----------
SDPA start at [Sun Jun  5 10:43:05 2022]
NumThreads  is set as 12
Schur computation : DENSE 
Entering DMUMPS driver with JOB, N, NZ =  -2           0              0
Converted to SDPA internal data / Starting SDPA main loop
   mu      thetaP  thetaD  objP      objD      alphaP  alphaD  beta 
 0 1.0e+04 1.0e+00 1.0e+00 -0.00e+00 -1.20e+03 1.0e+00 9.1e-01 2.00e-01
 1 1.6e+03 0.0e+00 9.4e-02 +9.23e+02 -7.51e+01 2.3e+00 9.6e-01 2.00e-01
 2 1.7e+02 6.4e-17 3.6e-03 +2.80e+02 +3.74e+01 1.3e+00 1.0e+00 2.00e-01
 3 1.8e+01 6.4e-17 1.5e-17 +7.70e+01 +4.19e+01 9.9e-01 9.9e-01 1.00e-01
 4 1.9e+00 7.2e-17 7.5e-18 +4.57e+01 +4.19e+01 1.0e+00 9.0e+01 1.00e-01
 5 1.9e-01 7.3e-17 1.1e-15 +4.23e+01 +4.19e+01 1.0e+00 1.0e+00 1.00e-01
 6 1.9e-02 6.4e-17 2.2e-17 +4.19e+01 +4.19e+01 1.0e+00 9.0e+01 1.00e-01
 7 1.9e-03 6.3e-17 2.1e-15 +4.19e+01 +4.19e+01 1.0e+00 1.0e+00 1.00e-01
 8 1.9e-04 8.3e-17 3.0e-17 +4.19e+01 +4.19e+01 1.0e+00 1.0e+00 1.00e-01
 9 1.9e-05 7.9e-17 1.5e-17 +4.19e+01 +4.19e+01 1.0e+00 9.0e+01 1.00e-01
10 1.9e-06 6.5e-17 1.6e-15 +4.19e+01 +4.19e+01 1.0e+00 9.0e+01 1.00e-01

phase.value  = pdOPT     
   Iteration = 10
          mu = +1.9180668442023463e-06
relative gap = +9.1554458700816248e-08
        gap  = +3.8361319951718542e-06
     digits  = +7.0383205007122669e+00
objValPrimal = +4.1900003836133735e+01
objValDual   = +4.1900000000001739e+01
p.feas.error = +7.2685417628031834e-15
d.feas.error = +1.5063505998114124e-12
total time   = 0.016597
  main loop time = 0.016594
      total time = 0.016597
file  check time = 0.000000
file change time = 0.000003
file   read time = 0.000000
Converting optimal solution to CLP format
SDPA end at [Sun Jun  5 10:43:05 2022]
Start: getCLPresult
Making result infomation...
/opt/anaconda3/envs/py310/lib/python3.10/site-packages/scipy/sparse/linalg/_eigen/arpack/arpack.py:1265: RuntimeWarning: k >= N - 1 for N * N square matrix. Attempting to use scipy.linalg.eig instead.
  warnings.warn("k >= N - 1 for N * N square matrix. "
========================================
 SDPAP: Result
========================================
    SDPA.phase = pdOPT
     iteration = 10
    convMethod = LMI
     frvMethod = split
  domainMethod = none
   rangeMethod = none
     primalObj = -4.1900000000001739e+01
       dualObj = -4.1900003836133735e+01
    dualityGap = +9.1554458700816248e-08
   primalError = +1.5063505998114124e-12
     dualError = +0.0000000000000000e+00
   convertTime = 0.000262
     solveTime = 0.018632
retrievingTime = 0.000003
     totalTime = 0.020157
---------- SDPAP End ----------

The information printed in the Result section of the output log will be returned in the dictionary sdpainfo. The dictionary sdpapinfo will contain a subset of this information.


Table of contents