# C/C++

In this example we shall solve the following small quadratic program:

$\begin{split}\begin{array}{ll} \mbox{minimize} & (1/2) x^T \begin{bmatrix}3 & -1\\ -1 & 2 \end{bmatrix} x + \begin{bmatrix}-1 \\ -1\end{bmatrix}^T x \\ \mbox{subject to} & \begin{bmatrix} -1 \\ 1 \end{bmatrix}^T x = -1 \\ & \begin{bmatrix} 1 & 0\\ 0 & 1\end{bmatrix} x \leq \begin{bmatrix}0.3 \\ -0.5\end{bmatrix} \end{array}\end{split}$

over variable $$x \in \mathbf{R}^2$$. This problem corresponds to data:

$\begin{split}\begin{array}{cccc} P = \begin{bmatrix}3 & -1\\ -1 & 2 \end{bmatrix}, & A = \begin{bmatrix}-1 & 1\\ 1 & 0\\ 0 & 1\end{bmatrix}, & b = \begin{bmatrix}-1 \\ 0.3 \\ -0.5\end{bmatrix}, & c = \begin{bmatrix}-1 \\ -1\end{bmatrix}. \end{array}\end{split}$

And the cone $$\mathcal{K}$$ consists of a zero cone (z) of length 1 and a positive cone (l) of dimension 2. Note that the order of the rows in $$A$$ and $$b$$ corresponds to the order in Cones, so the row corresponding to the zero cone comes first, followed by the rows for the positive cone.

C code to solve this is below.

#include "scs.h"    /* SCS API */
#include <stdio.h>  /* printf */
#include <stdlib.h> /* memory allocation */

/* Set up and solve basic qp */
int main(int argc, char **argv) {
/* Set up the problem data */
/* A and P must be in compressed sparse column format */
double P_x = {3., -1., 2.}; /* Upper triangular of P only */
int P_i = {0, 0, 1};
int P_p = {0, 1, 3};
double A_x = {-1., 1., 1., 1.};
int A_i = {0, 1, 0, 2};
int A_p = {0, 2, 4};
double b = {-1., 0.3, -0.5};
double c = {-1., -1.};
/* data shapes */
int n = 2; /* number of variables */
int m = 3; /* number of constraints */

/* Allocate SCS structs */
ScsCone *k = (ScsCone *)calloc(1, sizeof(ScsCone));
ScsData *d = (ScsData *)calloc(1, sizeof(ScsData));
ScsSettings *stgs = (ScsSettings *)calloc(1, sizeof(ScsSettings));
ScsSolution *sol = (ScsSolution *)calloc(1, sizeof(ScsSolution));
ScsInfo *info = (ScsInfo *)calloc(1, sizeof(ScsInfo));

/* Fill in data struct */
d->m = m;
d->n = n;
d->b = b;
d->c = c;
d->A = &(ScsMatrix){A_x, A_i, A_p, m, n};
d->P = &(ScsMatrix){P_x, P_i, P_p, n, n};

/* Cone */
k->z = 1;
k->l = 2;

/* Utility to set default settings */
scs_set_default_settings(stgs);

/* Modify tolerances */
stgs->eps_abs = 1e-9;
stgs->eps_rel = 1e-9;

/* Initialize SCS workspace */
ScsWork *scs_work = scs_init(d, k, stgs);

/* Solve! */
int exitflag = scs_solve(scs_work, sol, info, 0);

/*
* If we wanted to solve many related problems with different
* b / c vectors we could update the SCS workspace as follows:
*
* int success = scs_update(scs_work, new_b, new_c)
* int new_exitflag = scs_solve(scs_work, sol, info, 1);
*
*/

/* Free SCS workspace */
scs_finish(scs_work);

/* Verify that SCS solved the problem */
printf("SCS solved successfully: %i\n", exitflag == SCS_SOLVED);

/* Print some info about the solve */
printf("SCS took %i iters, using the %s linear solver.\n", info->iter,
info->lin_sys_solver);

/* Print solution x */
printf("Optimal solution vector x*:\n");
for (int i = 0; i < n; ++i) {
printf("x[%i] = %4f\n", i, sol->x[i]);
}

/* Print dual solution y */
printf("Optimal dual vector y*:\n");
for (int i = 0; i < m; ++i) {
printf("y[%i] = %4f\n", i, sol->y[i]);
}

/* Free allocated memory */
free(k);
free(d);
free(stgs);
free(info);
/* SCS allocates sol->x,y,s if NULL on entry, need to be freed */
free(sol->x);
free(sol->y);
free(sol->s);
free(sol);
return 0; /* returning exitflag will set bash exit code to 1 */
}


After following the CMake install instructions, we can compile the code (assuming the library was installed in /usr/local/ and the gcc compiler is available) using:

gcc -I/usr/local/include/scs -L/usr/local/lib/ qp.c -o qp.out -lscsdir


Then running the binary yields output:

------------------------------------------------------------------
SCS v3.2.1 - Splitting Conic Solver
(c) Brendan O'Donoghue, Stanford University, 2012
------------------------------------------------------------------
problem:  variables n: 2, constraints m: 3
cones: 	  z: primal zero / dual free vars: 1
l: linear vars: 2
settings: eps_abs: 1.0e-09, eps_rel: 1.0e-09, eps_infeas: 1.0e-07
alpha: 1.50, scale: 1.00e-01, adaptive_scale: 1
max_iters: 100000, normalize: 1, rho_x: 1.00e-06
acceleration_lookback: 10, acceleration_interval: 10
lin-sys:  sparse-direct-amd-qdldl
nnz(A): 4, nnz(P): 3
------------------------------------------------------------------
iter | pri res | dua res |   gap   |   obj   |  scale  | time (s)
------------------------------------------------------------------
0| 1.51e+00  1.00e+00  4.91e+00  1.14e+00  1.00e-01  1.19e-04
75| 4.09e-10  7.93e-10  1.07e-09  1.24e+00  1.00e-01  2.10e-04
------------------------------------------------------------------
status:  solved
timings: total: 2.11e-04s = setup: 9.88e-05s + solve: 1.13e-04s
lin-sys: 1.48e-05s, cones: 3.92e-06s, accel: 5.06e-05s
------------------------------------------------------------------
objective = 1.235000
------------------------------------------------------------------
SCS solved successfully: 1
SCS took 75 iters, using the sparse-direct-amd-qdldl linear solver.
Optimal solution vector x*:
x = 0.300000
x = -0.700000
Optimal dual vector y*:
y = 2.700000
y = 2.100000
y = 0.000000