diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 154d168e..a5641ae5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -13,13 +13,12 @@ jobs: uses: actions/setup-python@v2 - name: Install Python dependencies run: | - # pin docutils here due to bullets not appearing - pip install sphinx sphinx-rtd-theme breathe docutils==0.16 + pip install sphinx sphinx-rtd-theme breathe docutils - name: Build docs run: | cd docs/src && make docs && touch ../.nojekyll - name: Deploy - uses: JamesIves/github-pages-deploy-action@4.1.4 + uses: JamesIves/github-pages-deploy-action@4.2.1 with: branch: gh-pages # The branch the action should deploy to. folder: docs # The folder the action should deploy. diff --git a/docs/src/_static/css/scs_theme.css b/docs/src/_static/css/scs_theme.css index 5cac262f..e4406240 100644 --- a/docs/src/_static/css/scs_theme.css +++ b/docs/src/_static/css/scs_theme.css @@ -76,11 +76,11 @@ body { /* Link Styling */ a,a:visited, a:focus { - color: rgb(46, 118, 176); /* Light blue*/ + color: rgb(46, 118, 176); /* Light blue */ text-decoration: none; } a:hover, a:active { - color: rgb(0, 32, 72); /* blue*/ + color: rgb(0, 32, 72); /* blue */ text-decoration: none; } diff --git a/docs/src/conf.py b/docs/src/conf.py index 305f112a..cecda385 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -43,7 +43,10 @@ # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] -pygments_style = 'sphinx' + +# sphinx pygments style uses ugly green boxes for code blocks +#pygments_style = 'sphinx' +pygments_style = 'default' #html_sidebars = { # '**': [ @@ -63,7 +66,7 @@ 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, @@ -71,10 +74,10 @@ def setup(app): #'github_banner': True, #'github_user': 'cvxgrp', #'github_repo': 'scs', + #'logo': 'scs_logo_transparent.png', + #'logo_name': False, #'github_button': False, - #'html_show_sourcelink' = 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..43288d53 --- /dev/null +++ b/docs/src/examples/.gitignore @@ -0,0 +1 @@ +qp.out diff --git a/docs/src/examples/c.rst b/docs/src/examples/c.rst index ed290c51..4ec5d0c8 100644 --- a/docs/src/examples/c.rst +++ b/docs/src/examples/c.rst @@ -1,5 +1,26 @@ .. _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 running the code yields output + +.. literalinclude:: qp.c.out + :language: none + diff --git a/docs/src/examples/matlab.rst b/docs/src/examples/matlab.rst index 966cbc1e..b4c8971b 100644 --- a/docs/src/examples/matlab.rst +++ b/docs/src/examples/matlab.rst @@ -2,4 +2,19 @@ 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 + :language: none + diff --git a/docs/src/examples/python.rst b/docs/src/examples/python.rst index 29c32c45..57e375dc 100644 --- a/docs/src/examples/python.rst +++ b/docs/src/examples/python.rst @@ -2,4 +2,19 @@ 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 + :language: none + diff --git a/docs/src/examples/qp.c b/docs/src/examples/qp.c new file mode 100644 index 00000000..e30b985a --- /dev/null +++ b/docs/src/examples/qp.c @@ -0,0 +1,77 @@ +#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.c.out b/docs/src/examples/qp.c.out new file mode 100644 index 00000000..6ad869dc --- /dev/null +++ b/docs/src/examples/qp.c.out @@ -0,0 +1,33 @@ +------------------------------------------------------------------ + SCS v3.0.0 - Splitting Conic Solver + (c) Brendan O'Donoghue, Stanford University, 2012 +------------------------------------------------------------------ +problem: variables n: 2, constraints m: 3 +cones: l: linear vars: 3 +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, warm_start: 0 + acceleration_lookback: 10, acceleration_interval: 10 +lin-sys: sparse-direct + nnz(A): 4, nnz(P): 3 +------------------------------------------------------------------ + iter | pri res | dua res | gap | obj | scale | time (s) +------------------------------------------------------------------ + 0| 1.78e+00 1.00e+00 1.42e+00 -1.04e+00 1.00e-01 2.28e-05 + 175| 3.34e-11 4.17e-10 4.07e-10 1.24e+00 2.08e+01 4.26e-04 +------------------------------------------------------------------ +status: solved +timings: total: 1.17e-03s = setup: 7.40e-04s + solve: 4.28e-04s + lin-sys: 3.06e-05s, cones: 1.57e-05s, accel: 2.42e-05s +------------------------------------------------------------------ +objective = 1.235000 +------------------------------------------------------------------ +SCS solved successfully: 1 +SCS took 175 iters +Optimal solution vector x*: +x[0] = 0.300000 +x[1] = -0.700000 +Optimal dual vector y*: +y[0] = 2.700000 +y[1] = 2.100000 +y[2] = 0.000000 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.m.out b/docs/src/examples/qp.m.out new file mode 100644 index 00000000..65dd5b6b --- /dev/null +++ b/docs/src/examples/qp.m.out @@ -0,0 +1,44 @@ + < M A T L A B (R) > + Copyright 1984-2021 The MathWorks, Inc. + R2021a Update 3 (9.10.0.1684407) 64-bit (maci64) + May 27, 2021 + + +For online documentation, see https://www.mathworks.com/support +For product information, visit www.mathworks.com. + + +------------------------------------------------------------------ + SCS v3.0.0 - Splitting Conic Solver + (c) Brendan O'Donoghue, Stanford University, 2012 +------------------------------------------------------------------ +problem: variables n: 2, constraints m: 3 +cones: l: linear vars: 3 +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, warm_start: 0 + acceleration_lookback: 10, acceleration_interval: 10 +lin-sys: sparse-direct + nnz(A): 4, nnz(P): 3 +------------------------------------------------------------------ + iter | pri res | dua res | gap | obj | scale | time (s) +------------------------------------------------------------------ + 0| 1.78e+00 1.00e+00 1.42e+00 -1.04e+00 1.00e-01 2.37e-04 + 175| 3.34e-11 4.17e-10 4.07e-10 1.24e+00 2.08e+01 6.45e-03 +------------------------------------------------------------------ +status: solved +timings: total: 2.51e-02s = setup: 1.86e-02s + solve: 6.52e-03s + lin-sys: 2.94e-05s, cones: 1.52e-05s, accel: 6.04e-03s +------------------------------------------------------------------ +objective = 1.235000 +------------------------------------------------------------------ +SCS took 175 iters +Optimal solution vector x*: + 0.3000 + -0.7000 + +Optimal dual vector y*: + 2.7000 + 2.1000 + 0 + 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..a5117b6f --- /dev/null +++ b/docs/src/examples/qp.py @@ -0,0 +1,23 @@ +import scipy +import scs +import numpy as np + +# Set up the problem data +P = scipy.sparse.csc_matrix([[3., -1.], [-1., 2.]]) +A = scipy.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/examples/qp.py.out b/docs/src/examples/qp.py.out new file mode 100644 index 00000000..15f9b601 --- /dev/null +++ b/docs/src/examples/qp.py.out @@ -0,0 +1,29 @@ +------------------------------------------------------------------ + SCS v3.0.0 - Splitting Conic Solver + (c) Brendan O'Donoghue, Stanford University, 2012 +------------------------------------------------------------------ +problem: variables n: 2, constraints m: 3 +cones: l: linear vars: 3 +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, warm_start: 0 + acceleration_lookback: 10, acceleration_interval: 10 +lin-sys: sparse-direct + nnz(A): 4, nnz(P): 3 +------------------------------------------------------------------ + iter | pri res | dua res | gap | obj | scale | time (s) +------------------------------------------------------------------ + 0| 1.78e+00 1.00e+00 1.42e+00 -1.04e+00 1.00e-01 6.11e-05 + 175| 3.34e-11 4.17e-10 4.07e-10 1.24e+00 2.08e+01 1.59e-04 +------------------------------------------------------------------ +status: solved +timings: total: 1.09e-03s = setup: 9.31e-04s + solve: 1.60e-04s + lin-sys: 2.49e-05s, cones: 1.16e-05s, accel: 2.14e-05s +------------------------------------------------------------------ +objective = 1.235000 +------------------------------------------------------------------ +SCS took 175 iters +Optimal solution vector x*: +[ 0.3 -0.7] +Optimal dual vector y*: +[2.7 2.1 0. ] 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). */