From ea27ba2895e84510192603585d2c1eef1dc2fa82 Mon Sep 17 00:00:00 2001 From: Brendan O'Donoghue Date: Sun, 9 Jan 2022 15:54:52 +0000 Subject: [PATCH] add examples to docs --- docs/src/conf.py | 20 +++++---- docs/src/examples/.gitignore | 1 + docs/src/examples/c.rst | 23 ++++++++++- docs/src/examples/matlab.rst | 16 +++++++- docs/src/examples/python.rst | 15 ++++++- docs/src/examples/qp.c | 78 ++++++++++++++++++++++++++++++++++++ docs/src/examples/qp.m | 21 ++++++++++ docs/src/examples/qp.prob | 22 ++++++++++ docs/src/examples/qp.py | 23 +++++++++++ docs/src/index.rst | 2 +- include/scs.h | 7 ++-- 11 files changed, 209 insertions(+), 19 deletions(-) create mode 100644 docs/src/examples/.gitignore create mode 100644 docs/src/examples/qp.c create mode 100644 docs/src/examples/qp.m create mode 100644 docs/src/examples/qp.prob create mode 100644 docs/src/examples/qp.py diff --git a/docs/src/conf.py b/docs/src/conf.py index 305f112a..e23be4d6 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -56,25 +56,23 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -# html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' +html_theme = 'alabaster' +# html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] def setup(app): app.add_css_file('css/scs_theme.css') -html_logo = '_static/scs_logo.png' +#html_logo = '_static/scs_logo_transparent.png' html_favicon = '_static/favicon.ico' html_theme_options = { - 'logo_only': True, - 'display_version': True, - #'github_banner': True, - #'github_user': 'cvxgrp', - #'github_repo': 'scs', - #'github_button': False, - #'html_show_sourcelink' = False, + 'github_banner': True, + 'github_user': 'cvxgrp', + 'github_repo': 'scs', + 'logo': 'scs_logo_transparent.png', + 'logo_name': False, + 'github_button': False, #'github_type': 'star', - #'travis_button': False, 'analytics_id': 'UA-203326834-1', } diff --git a/docs/src/examples/.gitignore b/docs/src/examples/.gitignore new file mode 100644 index 00000000..f47cb204 --- /dev/null +++ b/docs/src/examples/.gitignore @@ -0,0 +1 @@ +*.out diff --git a/docs/src/examples/c.rst b/docs/src/examples/c.rst index ed290c51..ae5fb8da 100644 --- a/docs/src/examples/c.rst +++ b/docs/src/examples/c.rst @@ -1,5 +1,24 @@ .. _c_example: C/C++ -====== -TODO +===== + +.. include:: qp.prob + +C code to solve this is below. + +.. literalinclude:: qp.c + :language: c + +After following the CMake :ref:`install instructions `, we can +compile the code using: + +.. code:: + + gcc -I/usr/local/include/scs -L/usr/local/lib/ -lscsdir qp.c -o qp.out + +.. ./qp.out > qp.c.out + +Then run the code yielding output + +.. literalinclude:: qp.c.out diff --git a/docs/src/examples/matlab.rst b/docs/src/examples/matlab.rst index 966cbc1e..2c1d1d75 100644 --- a/docs/src/examples/matlab.rst +++ b/docs/src/examples/matlab.rst @@ -2,4 +2,18 @@ MATLAB ====== -TODO + +.. include:: qp.prob + +Python code to solve this is below. + +.. literalinclude:: qp.m + :language: matlab + +After following the matlab :ref:`install instructions `, we can +run the code yielding output + +.. matlab -r "run ~/git/scs/docs/src/examples/qp.m;exit" + +.. literalinclude:: qp.m.out + diff --git a/docs/src/examples/python.rst b/docs/src/examples/python.rst index 29c32c45..47896f64 100644 --- a/docs/src/examples/python.rst +++ b/docs/src/examples/python.rst @@ -2,4 +2,17 @@ Python ====== -TODO + +.. include:: qp.prob + +Python code to solve this is below. + +.. literalinclude:: qp.py + :language: python + +After following the python :ref:`install instructions `, we can +run the code yielding output + +.. python qp.py > qp.py.out + +.. literalinclude:: qp.py.out diff --git a/docs/src/examples/qp.c b/docs/src/examples/qp.c new file mode 100644 index 00000000..e1991e9a --- /dev/null +++ b/docs/src/examples/qp.c @@ -0,0 +1,78 @@ +#include "scs.h" /* SCS API */ + +/* 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] = {3., -1., 2.}; /* Upper triangular of P only */ + int P_i[3] = {0, 0, 1}; + int P_p[3] = {0, 1, 3}; + double A_x[4] = {-1., 1., 1., 1.}; + int A_i[4] = {0, 1, 0, 2}; + int A_p[3] = {0, 2, 4}; + double b[3] = {-1., 0.3, -0.5,}; + double c[2] = {-1., -1.}; + /* data shape */ + int n = 2; + int m = 3; + + /* 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 structs */ + 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->l = m; + + /* Utility to set some default settings */ + scs_set_default_settings(stgs); + + /* Modify tolerances */ + stgs->eps_abs=1e-9; + stgs->eps_rel=1e-9; + + /* Solve! */ + int exitflag = scs(d, k, stgs, sol, info); + + /* Verify that SCS solved the problem */ + printf("SCS solved successfully: %i\n", exitflag == SCS_SOLVED); + + /* Print iterations taken */ + printf("SCS took %i iters\n", info->iter); + + /* 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 exitflag; +} diff --git a/docs/src/examples/qp.m b/docs/src/examples/qp.m new file mode 100644 index 00000000..2a5042fb --- /dev/null +++ b/docs/src/examples/qp.m @@ -0,0 +1,21 @@ +% First, make sure SCS is in the path so MATLAB can call it +addpath("/Users/bodonoghue/git/scs-matlab") + +% Set up data +data.P = sparse([3., -1.; -1., 2.]); +data.A = sparse([-1., 1.; 1., 0.; 0., 1.]); +data.b = [-1; 0.3; -0.5]; +data.c = [-1.; -1.]; +cone.l = size(data.b, 1); + +% Optional solver settings +settings = struct('eps_abs', 1e-9, 'eps_rel', 1e-9); + +% Solve! +[x, y, s, info] = scs(data, cone, settings); + +disp(sprintf("SCS took %i iters", info.iter)) +disp("Optimal solution vector x*:"); +disp(x) +disp("Optimal dual vector y*:"); +disp(y) diff --git a/docs/src/examples/qp.prob b/docs/src/examples/qp.prob new file mode 100644 index 00000000..5344ac6b --- /dev/null +++ b/docs/src/examples/qp.prob @@ -0,0 +1,22 @@ + +In this example we shall solve the following small quadratic program: + +.. math:: + \begin{array}{ll} + \mbox{minimize} & \frac{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\\ 1 & 0\\ 0 & 1\end{bmatrix} x \leq \begin{bmatrix}-1 \\ 0.3 \\ -0.5\end{bmatrix} + \end{array} + +over variable :math:`x \in \mathbf{R}^2`. This problem corresponds to data: + +.. math:: + \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} + +The cone :math:`\mathcal{K}` is simply the positive orthant :code:`l` of +dimension 3. diff --git a/docs/src/examples/qp.py b/docs/src/examples/qp.py new file mode 100644 index 00000000..a22073c4 --- /dev/null +++ b/docs/src/examples/qp.py @@ -0,0 +1,23 @@ +import scs +import numpy as np +from scipy import sparse + +# Set up the problem data +P = sparse.csc_matrix([[3., -1.], [-1., 2.]]) +A = sparse.csc_matrix([[-1., 1.], [1., 0.], [0., 1.]]) +b = np.array([-1, 0.3, -0.5]) +c = np.array([-1., -1.]) + +# Populate dicts with data to pass into SCS +data = dict(P=P, A=A, b=b, c=c) +cone = dict(l=len(b)); + +# Solve! +sol = scs.solve(data, cone, eps_abs=1e-9, eps_rel=1e-9) + +print(f"SCS took {sol['info']['iter']} iters") +print("Optimal solution vector x*:"); +print(sol['x']) + +print("Optimal dual vector y*:"); +print(sol['y']) diff --git a/docs/src/index.rst b/docs/src/index.rst index 3d178ba6..fb4ab9e1 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -3,7 +3,7 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -.. image:: _static/scs_logo.png +.. image:: _static/scs_logo_transparent.png :width: 400 :alt: SCS :align: center diff --git a/include/scs.h b/include/scs.h index be525289..89c46b3d 100644 --- a/include/scs.h +++ b/include/scs.h @@ -17,8 +17,8 @@ typedef struct SCS_CONE_WORK ScsConeWork; /** Struct containing linear system workspace. Implemented by linear solver. */ typedef struct SCS_LIN_SYS_WORK ScsLinSysWork; -/** This defines the data matrices which should be supplied in column compressed - * format with zero based indexing. +/** This defines the data matrices which should be supplied in compressed + * sparse column format with zero based indexing. */ typedef struct { /** Matrix values, size: number of non-zeros. */ @@ -297,7 +297,8 @@ void SCS(finish)(ScsWork *w); * @param d Problem data. * @param k Cone data. * @param stgs SCS solver settings. - * @param sol Solution will be stored here. + * @param sol Solution will be stored here. If members `x`, `y`, `s` are + * NULL then SCS will allocate memory for them. * @param info Information about the solve will be stored here. * @return Flag that determines solve type (see \a glbopts.h). */