...
 
Commits (573)
......@@ -3,16 +3,19 @@
# Working files
patch
fix_*.py
fix_*/
test_*.py
test_*/
/fix_*.py
/fix_*/
/test_*.py
/test_*/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*.so
# profiling
*.cprof
# setuptools
build/
dist/
......@@ -26,8 +29,6 @@ pip-delete-this-directory.txt
target/
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
image: base/archlinux
# NOTE: python-setuptools is a missing dependency of python-coverage.
# NOTE: gcc, swig, which are build dependencies of swiglpk (via pip).
image: archlinux/base
stages:
- test
- coverage
- deploy
# ------------------------------------------------------------------------------
# Tests necessary for pipeline completion.
# ------------------------------------------------------------------------------
# Run production tests with Python 3.
testbench (py3):
stage: test
before_script:
# Install PICOS dependencies.
- pacman -Sy --noconfirm python-numpy python-cvxopt
# Install additional solvers.
- pacman -S --noconfirm python-pip glpk gcc
- pip install swiglpk smcp
- >
pacman -Syu --noconfirm
gcc glpk python-coverage python-cvxopt python-numpy python-pip
python-setuptools swig which
- pip install swiglpk
script:
- python ./test.py -vv -s cvxopt glpk smcp
- >
coverage run -p --source picos
./test.py -p -vv -s cvxopt glpk
artifacts:
expire_in: 1 day
paths:
- .coverage.*
# Run production tests with Python 2.
testbench (py2):
stage: test
before_script:
# Install PICOS dependencies.
- pacman -Sy --noconfirm python2-numpy python2-cvxopt
# Install additional solvers.
- pacman -S --noconfirm python2-pip glpk gcc
- pip2 install swiglpk smcp
- >
pacman -Syu --noconfirm
gcc glpk python2-coverage python2-numpy python2-pip python2-setuptools
swig which
- pip2 install cvxopt swiglpk
script:
- >
coverage2 run -p --source picos
./test.py -p -vv -s cvxopt glpk
artifacts:
expire_in: 1 day
paths:
- .coverage.*
# Run doctests via PICOS' test runner.
doctests (py3):
stage: test
before_script:
- >
pacman -Syu --noconfirm
python-coverage python-cvxopt python-networkx python-numpy
python-setuptools
script:
- python2 ./test.py -vv -s cvxopt glpk smcp
- >
coverage run -p --source picos
./test.py -u -vv
artifacts:
expire_in: 1 day
paths:
- .coverage.*
doctest:
# Test-build the documentations.
# NOTE: "doctest" is built because there are still some leftover
# testcode/testoutput blocks that are not handled by test.py.
# NOTE: There is a bug that would require us to build "doctest" twice to also
# include documentation from the auto-generated API documentation but all
# these additional tests are already handled by "doctests (py3)".
documentation:
stage: test
before_script:
- pacman -Sy --noconfirm python-pip python-numpy python-cvxopt
- pacman -S --noconfirm m2r python-sphinx python-matplotlib python-networkx
- pip install sphinx-automodapi
- >
pacman -Syu --noconfirm
gcc git glpk graphviz make python-cvxopt python-matplotlib
python-networkx python-numpy python-pip python-scipy python-sphinx
python-sphinx_rtd_theme texlive-most swig which
- pip install autoapi swiglpk
script:
- sphinx-build -b doctest doc doctest
- sphinx-build -W -b html doc html
- sphinx-build -W -b latex doc latex
- make -C latex
# Check if upload to PyPI would succeed.
twinecheck:
stage: test
before_script:
- pacman -Syu --noconfirm git twine
script:
- ./setup.py sdist
- twine check dist/*
# Detect do-not-commit-this comments left in the code.
leftovers:
stage: test
before_script:
- pacman -Sy --noconfirm grep
script:
- (! grep -qr XXX picos)
# ------------------------------------------------------------------------------
# Compliance tests that are allowed to fail.
# ------------------------------------------------------------------------------
# Check (limited) PEP 8 and PEP 257 compliance.
style:
stage: test
before_script:
- pacman -Syu --noconfirm pylama
script:
- >
pylama
--linters pep8,pep257
--ignore D105,D203,D213,D401,E122,E128,E221,E271,E272,E501,E702,E741
picos tests
allow_failure: true
# Check line lengths.
linelength:
stage: test
before_script:
- pacman -Sy --noconfirm findutils grep
script:
- (! find picos tests -name '*.py' -print0|xargs -0 grep '^.\{81,\}$')
allow_failure: true
# ------------------------------------------------------------------------------
# Compute test coverage.
# ------------------------------------------------------------------------------
# Merge and report test coverage.
coverage:
stage: coverage
needs: [ # Run job early when all coverage results are available.
"testbench (py3)",
"testbench (py2)",
"doctests (py3)"]
dependencies: [ # Download exactly the coverage results.
"testbench (py3)",
"testbench (py2)",
"doctests (py3)"]
before_script:
- pacman -Syu --noconfirm python-coverage python-setuptools
script:
- coverage combine
- coverage report
artifacts:
expire_in: 1 year
name: coverage
paths:
- .coverage
# ------------------------------------------------------------------------------
# Deploy a release.
# ------------------------------------------------------------------------------
# Upload package to PyPI.
pypi:
stage: deploy
dependencies: [] # Don't download coverage reports.
before_script:
- pacman -Sy --noconfirm git twine
- pacman -Syu --noconfirm git twine
script:
- ./setup.py sdist
- twine upload --skip-existing dist/*
......@@ -46,11 +172,13 @@ pypi:
- master
- pypi
# Upload package to Anaconda.
anaconda:
stage: deploy
dependencies: [] # Don't download coverage reports.
before_script:
# Install Miniconda from the AUR.
- pacman -Sy --noconfirm wget fakeroot audit
- pacman -Syu --noconfirm audit fakeroot grep tar wget
- wget https://aur.archlinux.org/cgit/aur.git/snapshot/miniconda3.tar.gz
- tar xf miniconda3.tar.gz
- cd miniconda3
......@@ -66,16 +194,17 @@ anaconda:
- master
- conda
# Generate and publish the online documentation.
pages:
stage: deploy
dependencies: [] # Don't download coverage reports.
before_script:
# Install PICOS dependencies.
- pacman -Sy --noconfirm python-numpy python-cvxopt
# Install documentation built dependencies.
- pacman -S --noconfirm m2r python-sphinx python-matplotlib python-networkx
- pacman -S --noconfirm texlive-most python-sphinx_rtd_theme python-scipy
- pacman -S --noconfirm git python-pip glpk graphviz
- pip install sphinx-automodapi swiglpk
- >
pacman -Syu --noconfirm
gcc git glpk graphviz python-cvxopt python-matplotlib python-networkx
python-numpy python-pip python-scipy python-sphinx
python-sphinx_rtd_theme texlive-most swig which
- pip install autoapi swiglpk
script:
- sphinx-build -b html doc html
- mkdir public
......@@ -87,4 +216,26 @@ pages:
- master
- doc
# Generate PDF versions of the documentation.
pdfdoc:
stage: deploy
dependencies: [] # Don't download coverage reports.
before_script:
- >
pacman -Syu --noconfirm
gcc git glpk graphviz make python-cvxopt python-matplotlib
python-networkx python-numpy python-pip python-scipy python-sphinx
python-sphinx_rtd_theme texlive-most swig which
- pip install autoapi swiglpk
script:
- make -C doc latexpdf
- mv doc/build/latex/picos*.pdf .
artifacts:
name: picos-doc
paths:
- picos*.pdf
only:
- master
- pdfdoc
# vi:ts=2:et:ai
This diff is collapsed.
......@@ -4,23 +4,26 @@ Contribution Guide
Filing a bug report or feature request
--------------------------------------
### Via GitLab
Via GitLab
~~~~~~~~~~
If you have a GitLab account, just head to PICOS' official
[issue tracker](https://gitlab.com/picos-api/picos/issues).
`issue tracker <https://gitlab.com/picos-api/picos/issues>`_.
### Via mail
Via mail
~~~~~~~~
If you don't have a GitLab account you can still create an issue by writing a
mail to `incoming+picos-api/[email protected]`. Unlike issues created
directly on GitLab, issues created by mail are *not* publicly visible.
If you don't have a GitLab account you can still create an issue by writing to
`incoming+picos-api/[email protected] <incoming+picos-api/[email protected]>`_.
Unlike issues created directly on GitLab, issues created by mail are *not*
publicly visible.
Submitting a code change
------------------------
The canoncial way to submit a code change is to
1. [fork the PICOS repository on GitLab](https://gitlab.com/picos-api/picos/forks/new),
1. `fork the PICOS repository on GitLab <https://gitlab.com/picos-api/picos/forks/new>`_,
2. clone your fork and make your application use it instead of your system's
PICOS installation,
3. optionally create a local topic branch to work with,
......@@ -28,41 +31,56 @@ The canoncial way to submit a code change is to
5. make a pull request on GitLab so that we can test and merge your changes.
If you don't want to create a GitLab account, we are also happy to receive your
changes via mail as a patch created by `git patch`.
changes via mail as a patch created by :command:`git patch`.
Implementing your solver
------------------------
If you want to implement support for a new solver, all you have to do is update
[solvers.py](picos/solvers.py) where applicable, and add a file called
`solver_<name>.py` in the same directory with your implementation. We recommend
that you read two or three of the existing solver implementations to get an
idea how things are done. If you want to know exactly how PICOS communicates
with your implementation, refer to the solver base class in
[solver.py](picos/solver.py).
:file:`solvers/__init__.py` where applicable, and add a file coined
:file:`solver_<name>.py` in the same directory with your implementation.
We recommend that you read two or three of the existing solver implementations
to get an idea how things are done.
If you want to know exactly how PICOS communicates with your implementation,
refer to the solver base class in :file:`solver.py`.
Implementing a test case
------------------------
Production and unit test sets are implemented in the files in the
[tests](picos/tests) folder that start with `ptest_` and `utest_`, respectively.
Production and test sets are implemented in the files in the :file:`tests`
folder that start with :file:`ptest_`.
If you want to add to our test pool, feel free to either extend these files or
create a new set, whatever is appropriate. Make sure that the tests you add are
not too computationally expensive since they are also run as part of our
continuous integration pipeline whenever a commit is pushed to GitLab.
create a new set, whatever is appropriate.
Make sure that the tests you add are not too computationally expensive since
they are also run as part of our continuous integration pipeline whenever a
commit is pushed to GitLab.
Coding guidelines
-----------------
### Cleanup in progress
Code style
~~~~~~~~~~
Set your linter to enforce :pep:`8` and :pep:`257` except for the following
codes:
.. code::
D105,D203,D213,D401,E122,E128,E221,E271,E272,E501,E702,E741
Our line width limit is ``80`` characters.
Cleanup in progress
~~~~~~~~~~~~~~~~~~~
We are aiming to tidy up PICOS' codebase in the future to make it more robust
and easier to maintain and extend. That means that the cost of adding a new
feature often is to also refactor around the neighboring features. That being
said, you are encouraged to just rewrite a function that you feel does not look
so good, even if you initially just planned to add some text to it! :wink:
so good, even if you initially just planned to add some text to it!
### Test coverage
Test coverage
~~~~~~~~~~~~~
Refactoring means stability in the long run, but can break features in the
short term. To prevent this from happening, we're happy to grow our set of
......
......@@ -2,8 +2,8 @@ A Python Interface to Conic Optimization Solvers
================================================
PICOS is a user friendly Python API to several conic and integer programming
solvers, very much like [YALMIP](http://users.isy.liu.se/johanl/yalmip/) or
[CVX](http://cvxr.com/cvx/) under [MATLAB](http://www.mathworks.com/).
solvers, very much like `YALMIP <https://yalmip.github.io/>`_ or
`CVX <http://cvxr.com/cvx/>`_ under `MATLAB <http://www.mathworks.com/>`_.
PICOS allows you to enter a mathematical optimization problem as a **high level
model**, with painless support for **(complex) vector and matrix variables** and
......@@ -19,103 +19,178 @@ PICOS runs under both **Python 2** and **Python 3** and supports the following
solvers and problem types. To use a solver, you need to seperately install it
along with the Python interface listed here.
| Solver | Interface | [LP](https://en.wikipedia.org/wiki/Linear_programming) | [SOCP](https://en.wikipedia.org/wiki/Second-order_cone_programming) | [SDP](https://en.wikipedia.org/wiki/Semidefinite_programming) | [QCQP](https://en.wikipedia.org/wiki/Quadratically_constrained_quadratic_program) | [EXP](https://docs.mosek.com/modeling-cookbook/expo.html) | [MIP](https://en.wikipedia.org/wiki/Integer_programming) | License |
| --------------------------------------------------------- | ---------------------------------------------------------- | --- | --- | --- | --- | --- | --- | -------- |
| [CPLEX](https://www.ibm.com/analytics/cplex-optimizer) | included | Yes | Yes | | Yes | | Yes | non-free |
| [CVXOPT](https://cvxopt.org/) | native | Yes | Yes | Yes | Yes | Yes¹| | [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) |
| [ECOS](https://www.embotech.com/ECOS) | [ecos-python](https://github.com/embotech/ecos-python) | Yes | Yes | | Yes | Yes | Yes | [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) |
| [GLPK](https://www.gnu.org/software/glpk/) | [swiglpk](https://github.com/biosustain/swiglpk) | Yes | | | | | Yes | [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) |
| [Gurobi](http://www.gurobi.com/products/gurobi-optimizer) | included | Yes | Yes | | Yes | | Yes | non-free |
| [MOSEK](https://www.mosek.com/) | included | Yes | Yes | Yes | Yes | | Yes | non-free |
| [SMCP](http://smcp.readthedocs.io/en/latest/) | native | Yes²| Yes²| Yes | Yes²| | | [GPL-3](https://www.gnu.org/licenses/gpl-3.0.html) |
| [SCIP](http://scip.zib.de/) | [PySCIPOpt](https://github.com/SCIP-Interfaces/PySCIPOpt/) | Yes | Yes | | Yes | | Yes | [ZIB](https://scip.zib.de/academic.txt)/[MIT](https://github.com/SCIP-Interfaces/PySCIPOpt/blob/master/LICENSE) |
¹ only [geometric programming](https://en.wikipedia.org/wiki/Geometric_programming),
² experimental
### Example
.. _GPL-3: https://www.gnu.org/licenses/gpl-3.0.html
.. _MIT: https://opensource.org/licenses/MIT
.. _ZIB: https://scip.zib.de/academic.txt
.. list-table::
:header-rows: 1
* - | Solver
|
- | Python
| interface
- | `LP <https://en.wikipedia.org/wiki/Linear_programming>`_
|
- | `SOCP <https://en.wikipedia.org/wiki/Second-order_cone_programming>`_,
| `QCQP <https://en.wikipedia.org/wiki/Quadratically_constrained_quadratic_program>`_
- | `SDP <https://en.wikipedia.org/wiki/Semidefinite_programming>`_
|
- | `EXP <https://docs.mosek.com/modeling-cookbook/expo.html>`_
|
- | `MIP <https://en.wikipedia.org/wiki/Integer_programming>`_
|
- | License
|
* - `CPLEX <https://www.ibm.com/analytics/cplex-optimizer>`_
- included
- Yes
- Yes
-
-
- Yes
- non-free
* - `CVXOPT <https://cvxopt.org/>`_
- native
- Yes
- Yes
- Yes
- `GP <https://en.wikipedia.org/wiki/Geometric_programming>`_
-
- `GPL-3`_
* - `ECOS <https://github.com/embotech/ecos>`_
- `ecos-python <https://github.com/embotech/ecos-python>`_
- Yes
- Yes
-
- Yes
- Yes
- `GPL-3`_
* - `GLPK <https://www.gnu.org/software/glpk/>`_
- `swiglpk <https://github.com/biosustain/swiglpk>`_
- Yes
-
-
-
- Yes
- `GPL-3`_
* - `Gurobi <http://www.gurobi.com/products/gurobi-optimizer>`_
- included
- Yes
- Yes
-
-
- Yes
- non-free
* - `MOSEK <https://www.mosek.com/>`_
- included
- Yes
- Yes
- Yes
- WIP
- Yes
- non-free
* - `SCIP <http://scip.zib.de/>`_
- `PySCIPOpt <https://github.com/SCIP-Interfaces/PySCIPOpt/>`_
- Yes
- Yes
-
-
- Yes
- `ZIB`_/`MIT`_
* - `SMCP <http://smcp.readthedocs.io/en/latest/>`_
- native
-
-
- Yes
-
-
- `GPL-3`_
Example
~~~~~~~
This is what it looks like to solve a multidimensional mixed integer program
with PICOS:
with PICOS (the solver GLPK is chosen explicitly for reproducibility):
```python
>>> import picos
>>> P = picos.Problem()
>>> x = P.add_variable("x", 2, vtype="integer")
>>> C = P.add_constraint(x <= 5.5)
>>> P.set_objective("max", 1|x) # 1|x is the sum over x
>>> solution = P.solve(verbose = 0)
>>> print(solution["status"])
'integer optimal solution'
>>> print(P.obj_value())
>>> x = picos.IntegerVariable("x", 2)
>>> P.add_constraint(x <= 5.5)
<2×1 Affine Constraint: x ≤ [5.5]>
>>> P.set_objective("max", picos.sum(x))
>>> P.solve(solver="glpk")
<feasible primal solution (claimed optimal) from glpk>
>>> P.value
10.0
>>> print(x)
[ 5.00e+00]
[ 5.00e+00]
>>> print(C.slack)
[ 5.00e-01]
[ 5.00e-01]
```
### Documentation & Source
Documentation & Source
~~~~~~~~~~~~~~~~~~~~~~
The full documentation can be found [here](https://picos-api.gitlab.io/picos/).
The source code lives on [GitLab](https://gitlab.com/picos-api/picos).
The page you are reading is featured in both places.
- The full documentation can be browsed
`online <https://picos-api.gitlab.io/picos/>`_
or downloaded
`in PDF form <https://gitlab.com/picos-api/picos/-/jobs/artifacts/master/raw/picos.pdf?job=pdfdoc>`_.
- The API documentation without the tutorial and examples is also available as a
`separate PDF <https://gitlab.com/picos-api/picos/-/jobs/artifacts/master/raw/picos-api.pdf?job=pdfdoc>`_.
- The source code lives on `GitLab <https://gitlab.com/picos-api/picos>`_.
Installation
------------
### Via pip
.. rubric:: Via pip
If you are using [pip](https://pypi.org/project/pip/) you can run
If you are using `pip <https://pypi.org/project/pip/>`_ you can run
``pip install picos`` to get the latest version.
### Via Anaconda
.. rubric:: Via Anaconda
If you are using [Anaconda](https://anaconda.org/) you can run
If you are using `Anaconda <https://anaconda.org/>`_ you can run
``conda install -c picos picos`` to get the latest version.
### Via your system's package manager
.. rubric:: Via your system's package manager
On **Arch Linux**, there are seperate packages in the AUR for the
[latest version](https://aur.archlinux.org/packages/python-picos-git/) and the
[latest release](https://aur.archlinux.org/packages/python-picos/). Both are
`latest version <https://aur.archlinux.org/packages/python-picos-git/>`_ and the
`latest release <https://aur.archlinux.org/packages/python-picos/>`_. Both are
split packages that ship both Python 2 and Python 3 versions of PICOS.
If you are packaging PICOS for additional systems, please tell us so we can list
your package here!
### From source
.. rubric:: From source
If you are installing PICOS manually, you can choose between a number of
[development versions](https://gitlab.com/picos-api/picos/branches) and
[source releases](https://gitlab.com/picos-api/picos/tags).
`development versions <https://gitlab.com/picos-api/picos/branches>`_ and
`source releases <https://gitlab.com/picos-api/picos/tags>`_.
You will need to have at least the following Python packages installed:
- [NumPy](http://www.numpy.org/)
- [CVXOPT](https://cvxopt.org/)
- `NumPy <http://www.numpy.org/>`_
- `CVXOPT <https://cvxopt.org/>`_
Credits
-------
### Developers
.. rubric:: Developers
- [Guillaume Sagnol](http://page.math.tu-berlin.de/~sagnol/) is PICOS' initial
author and primary developer since 2012.
- [Maximilian Stahlberg](about:blank) is extending and maintaining PICOS since
2017.
- `Guillaume Sagnol <http://page.math.tu-berlin.de/~sagnol/>`_ has started work
on PICOS in 2012.
- `Maximilian Stahlberg <about:blank>`_ is extending and co-maintaining PICOS
since 2017.
### Contributors
.. rubric:: Contributors
For an up-to-date list of all code contributors, please refer to the
[contributors page](https://gitlab.com/picos-api/picos/graphs/master).
`contributors page <https://gitlab.com/picos-api/picos/graphs/master>`_.
Should a reference from before 2019 be unclear, you can refer to the
[old contributors page](https://github.com/gsagnol/picos/graphs/contributors)
`old contributors page <https://github.com/gsagnol/picos/graphs/contributors>`_
on GitHub as well.
License
-------
PICOS is free and open source software and available to you under the terms of
the [GNU GPL v3](https://gitlab.com/picos-api/picos/raw/master/LICENSE.txt).
the `GNU GPL v3 <https://gitlab.com/picos-api/picos/raw/master/LICENSE.txt>`_.
python:
- 2.7
- 3.6
- 3.7
- 3.8
# vi:ts=2:et:ai
about:
description: "A python interface to conic optimization solvers."
home: https://gitlab.com/picos-api/picos
license: GPL-3.0
package:
name: picos
version: {{ load_setup_py_data().version }}
......@@ -28,4 +23,9 @@ test:
imports:
- picos
about:
description: "A python interface to conic optimization solvers."
home: https://gitlab.com/picos-api/picos
license: GPL-3.0
# vi:ts=2:et:ai
build/
automodapi/
api/
*.xcf
......@@ -6,6 +6,7 @@ SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
AUTOGENDIR = api
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
......@@ -47,7 +48,8 @@ help:
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
rm -rf $(BUILDDIR)
rm -rf $(AUTOGENDIR)
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
......
.wy-table-responsive table td {
white-space: normal !important;
}
{# THEMODULE #}
{{ node.name }}
{{ '=' * node.name|length }}
.. automodule:: {{ node.name }}
:no-special-members:
{# SET CURRENT MODULE #}
.. currentmodule:: {{ node.name }}
{# CONTENT #}
{%- block content -%}
{%- if node.exceptions or node.classes or node.functions or node.variables %}
Outline
-------
{%- if node.classes %}
Classes
^^^^^^^
.. list-table::
:widths: 25 75
{% for item, obj in node.classes.items() %}
* - :py:class:`{{ item }}`
- {{ obj|summary }}
{%- endfor -%}
{%- endif -%}
{%- if node.functions %}
Functions
^^^^^^^^^
.. list-table::
:widths: 25 75
{% for item, obj in node.functions.items() %}
* - :py:func:`{{ item }}`
- {{ obj|summary }}
{%- endfor -%}
{%- endif -%}
{% if node.exceptions %}
Exceptions
^^^^^^^^^^
.. list-table::
:widths: 25 75
{% for item, obj in node.exceptions.items() %}
* - :py:exc:`{{ item }}`
- {{ obj|summary }}
{%- endfor -%}
{%- endif -%}
{%- if node.variables %}
Data
^^^^
.. hlist::
:columns: 4
{% for item, obj in node.variables.items() %}
- :py:data:`{{ item }}`
{%- endfor -%}
{%- endif -%}
{%- endif %}
{%- if subnodes %}
Submodules
^^^^^^^^^^
.. list-table::
:widths: 25 75
{% for subnode in subnodes %}
* - :py:mod:`{{ subnode.name }}`
- {{ subnode.module|summary }}
{%- endfor %}
{%- endif -%}
{%- endblock -%}
{# CLASSES #}
{%- block classes -%}
{%- if node.classes %}
Classes
-------
{% for item in node.classes %}
{{ item }}
{{ '^' * item|length }}
.. autoclass:: {{ item }}
:members:
:undoc-members:
{% endfor -%}
{%- endif -%}
{%- endblock -%}
{# FUNCTIONS #}
{%- block functions -%}
{%- if node.functions %}
Functions
---------
{% for item in node.functions %}
{{ item }}
{{ '^' * item|length }}
.. autofunction:: {{ item }}
{% endfor -%}
{%- endif -%}
{%- endblock -%}
{# EXCEPTIONS #}
{%- block exceptions -%}
{%- if node.exceptions %}
Exceptions
----------
{% for item in node.exceptions %}
{{ item }}
{{ '^' * item|length }}
.. autoexception:: {{ item }}
{% endfor -%}
{%- endif -%}
{%- endblock -%}
{# DATA #}
{%- block variables -%}
{%- if node.variables %}
Data
----
{% for item, obj in node.variables.items() %}
.. autodata:: {{ item }}
:annotation:
{% endfor -%}
{%- endif -%}
{%- endblock -%}
......@@ -3,45 +3,38 @@
API Reference
=============
.. rubric:: Basic interface
To use PICOS to its full extend you just need to know about the two components
below.
.. toctree::
:maxdepth: 3
api/problem.rst
api/tools.rst
.. rubric:: Generated expressions and constraints
When you use the basic interface above, PICOS creates mathematical expressions
and constraints involving your variables and data. The following sections
describe these objects.
.. toctree::
:maxdepth: 3
api/expressions.rst
api/constraints.rst
.. rubric:: Customizing PICOS
The following components allow you to fine-tune the behavior of PICOS.
PICOS is organized in a number of submodules and subpackages, most of which you
do not need to access directly when solving optimization problems. It is usually
sufficient to ``import picos`` and use the functions and classes provided in the
:mod:`picos` namespace.
.. toctree::
:maxdepth: 3
api/glyphs.rst
.. rubric:: Internal Gears
You don't usually come in direct contact with the classes and functions below,
but if you like to poke around or :ref:`contribute to PICOS <contributing>` we
got you covered!
:maxdepth: 1
api/picos
api/picos.apidoc
api/picos.caching
api/picos.compat
api/picos.constraints
api/picos.containers
api/picos.expressions
api/picos.formatting
api/picos.glyphs
api/picos.legacy
api/picos.modeling
api/picos.reforms
api/picos.solvers
api/picos.tools
More
----
Modules below the second level are not listed here but can be found in the
sidebar to your left. Often these modules define a single class which is also
mirrored in one of the namespaces above.
.. toctree::
:maxdepth: 3
:hidden:
:glob:
api/solvers.rst
api/picos.*.*
.. _constraints:
The Constraints package
=======================
.. automodapi:: picos.constraints
:no-heading:
:headings: =-
.. _expression:
The Expressions module
======================
.. automodule:: picos.expressions
.. _glyphs:
The Glyphs module
=================
.. automodule:: picos.glyphs
.. _problem:
The Problem class
=================
The :class:`Problem <picos.Problem>` class represents your optimization problem
and is your main way of interfacing PICOS. After you create a problem instance,
you can add variables to it via :meth:`add_variable
<picos.Problem.add_variable>` and use standard Python algebraic operators
(:ref:`cheatsheet`) and algebraic functions (:ref:`tools`) to create expressions
and constraints involving these variables.
.. autoclass:: picos.Problem
.. _solvers:
The Solvers package
===================
.. automodapi:: picos.solvers
:no-heading:
:headings: =-
.. _tools:
The Tools module
================
Many of the tools, in particular the algebraic functions, are also available
in the ``picos`` namespace. For example, you can write :func:`picos.sum
<picos.tools.sum>` instead of :func:`picos.tools.sum <picos.tools.sum>`.
In the future, we are looking to split the toolbox into mutltiple modules, so
that it is clear which of the functions are imported into the ``picos``
namespace.
.. automodule:: picos.tools
.. _changelog:
.. mdinclude:: ../CHANGELOG.md
.. include:: ../CHANGELOG.rst
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
.. _contributing:
.. mdinclude:: ../CONTRIBUTING.md
.. include:: ../CONTRIBUTING.rst
.. _duals:
Dual Values
===========
Picos typically reformulates optimization problems as
conic programs of the form
.. math::
:nowrap:
\begin{center}
$\begin{array}{cclc}
\underset{\mathbf{x} \in \mathbb{R}^n}{\mbox{minimize}}
& \mathbf{c}^T \mathbf{x} + \gamma & &\\
\mbox{subject to} & A_i(\mathbf{x}) & \succeq_{K_i} \mathbf{b}_i,\ \forall i \in I,
\end{array}$
\end{center}
where each :math:`A_i` is a linear map
from :math:`\mathbb{R}^n` to a linear space containing the cone :math:`K_i`,
and the generalized conic inequality :math:`\mathbf{x} \succeq_K \mathbf{y}`
means :math:`\mathbf{x}-\mathbf{y}\in K` for a cone :math:`K`.
For the sake of compactness, we allow generalized inequalities over the trivial cone
:math:`K_{eq} = \{\mathbf{0}\}`, such that
:math:`A \mathbf{x} \succeq_{K_{eq}} \mathbf{b}` represents an equality constraint
:math:`A \mathbf{x} = \mathbf{b}`.
The dual conic problem can be written as follows:
.. math::
:nowrap:
\begin{center}
$\begin{array}{cll}
\mbox{maximize} & \sum_{i\in I} \mathbf{b}_i^T \mathbf{y}_i + \gamma \\
\mbox{subject to} & \sum_{i\in I} A_i^*(\mathbf{y}_i) = \mathbf{c}, \\
& \mathbf{y}_i \succeq_{K_i^*} 0,\ \forall i \in I,
\end{array}$
\end{center}
where :math:`A^*` denotes the adjoint operator of :math:`A` and
:math:`K^*` denotes the the dual cone of :math:`K` (see the note below for a list
of cones that are supported in PICOS, together with their dual).
After an optimization problem has been solved, we can query the optimal dual variable :math:`y_i \in K_i^*`
of a conic constraint ``con`` over the cone :math:`K_i` with its
:func:`~picos.constraints.Constraint.dual` attribute, i.e., ``con.dual``.
When an optimization problem ``P`` can be reformulated to a conic program ``C``
of the above form by PICOS,
we can use its :func:`~picos.Problem.dual` attribute to
return a :class:`~picos.Problem` object ``D=P.dual`` which contains the
dual conic program of ``C``. It is also possible to solve ``P`` via its dual
by using the :ref:`dualize <option_dualize>` option:
This passes problem ``D`` to the solver,
and the optimal primal and dual variables of ``P`` will be retrieved from the
optimal solution of ``D``.
Supported cones and their dual
------------------------------
PICOS can provide dual information for problems involving the following cones:
Trivial cone
^^^^^^^^^^^^
The trivial cone :math:`K_{eq} = \{\mathbf{0}\}\subset \mathbb{R}^n`,
whose dual cone is the entire space :math:`K_{eq}^* = \mathbb{R}^n`.
This means that the dual variable :math:`\mathbf{y}` for an equality constraint
is unconstrained.
Nonnegative Orthant
^^^^^^^^^^^^^^^^^^^
The nonnegative orthant :math:`\mathbb{R}_+^n` is self dual: :math:`(\mathbb{R}_+^n)^* = \mathbb{R}_+^n`.
Therefore the dual variable for a set of linear inequalities is a vector :math:`\mathbf{y}\geq\mathbf{0}`.
Lorentz Cone
^^^^^^^^^^^^
The :ref:`Lorentz cone <lorentz>` :math:`\mathcal{Q}^n=`
:math:`\{(t,\mathbf{x}) \in \mathbb{R}\times \mathbb{R}^{n-1}: \|\mathbf{x}\| \leq t \}`,
which is used to model second-order cone inequalities, is self-dual:
:math:`(\mathcal{Q}^n)^* = \mathcal{Q}^n`. This means that the dual variable for a second order cone
inequality of the form
.. math::
:nowrap:
$\| A \mathbf{x} - \mathbf{b} \| \leq \mathbf{h}^T \mathbf{x} - g
\iff
\left[
\begin{array}{c} \mathbf{h}^T\\ A \end{array}
\right] \mathbf{x}
\succeq_{\mathcal{Q}^n}
\left[
\begin{array}{c} g\\ \mathbf{b} \end{array}
\right]$
is a vector of the form :math:`[\lambda, \mathbf{z}^T]^T` such that
:math:`\|\mathbf{z}\| \leq \lambda`.
Rotated Second-order Cone
^^^^^^^^^^^^^^^^^^^^^^^^^
The (widened or narrowed) :ref:`rotated second order cone <rotatedcone>` is
.. math::
:nowrap:
$\mathcal{R}_p^n =\{(u,v,\mathbf{x})\in\mathbb{R}\times\mathbb{R}\times\mathbb{R}^{n-2}:
\|\mathbf{x}\|^2 \leq p\cdot u \cdot v,\ u,v\geq 0 \}$
for some :math:`p>0`, and its dual cone is
:math:`(\mathcal{R}_{p}^n)^* = \mathcal{R}_{4/p}^n`. In particular, :math:`\mathcal{R}_p^n` is self-dual for :math:`p=2`.
For example, the dual variable for the constraint
:math:`\| A \mathbf{x} - \mathbf{b} \|^2 \leq (\mathbf{h}^T \mathbf{x} - g)(\mathbf{e}^T \mathbf{x} - f)`
with
:math:`(\mathbf{h}^T \mathbf{x} - g)\geq 0` and :math:`(\mathbf{e}^T \mathbf{x} - f)\geq 0`,
i.e.,
.. math::
:nowrap:
$
\left[
\begin{array}{c} \mathbf{h}^T\\ \mathbf{e}^T\\ A \end{array}
\right] \mathbf{x}
\succeq_{\mathcal{R}_1^n}
\left[
\begin{array}{c} g\\ f\\ \mathbf{b} \end{array}
\right]$
is a vector of the form :math:`[\alpha, \beta, \mathbf{z}^T]^T` such that
:math:`\|\mathbf{z}\|^2 \leq 4 \alpha \beta`;
Positive Semi-definite Cone
^^^^^^^^^^^^^^^^^^^^^^^^^^^
The positive semidefinite cone :math:`\mathbb{S}_+^n` is
self dual: :math:`(\mathbb{S}_+^n)^* = \mathbb{S}_+^n`. This means that the dual
variable for a linear matrix inequality :math:`\sum_i x_i M_i \succeq M_0` is a
positive semidefinite matrix :math:`Y \succeq 0`;
Exponential Cone
^^^^^^^^^^^^^^^^
PICOS can also reformulate several constraints using the *exponential cone*
:class:`~picos.expressions.ExponentialCone`, as it is the case for example
for :class:`~picos.constraints.KullbackLeiblerConstraint`.
PICOS provides dual values for :class:`~picos.constraints.ExpConeConstraint`,
as computed by the solver, but dualization of those constraints
is not yet supported.
This diff is collapsed.
.. figure:: picos_trans.gif
.. figure:: picos_trans.png
.. _welcome:
......@@ -9,6 +9,12 @@ Welcome to the documentation of PICOS, a user friendly Python API to several
conic and integer programming solvers, whose open source code lives on
`GitLab <https://gitlab.com/picos-api/picos>`_.
PDF versions of the
`full documentation <https://gitlab.com/picos-api/picos/-/jobs/artifacts/master/raw/picos.pdf?job=pdfdoc>`_
and only the
`API reference <https://gitlab.com/picos-api/picos/-/jobs/artifacts/master/raw/picos-api.pdf?job=pdfdoc>`_
are available for offline use.
.. _quickstart:
......@@ -35,7 +41,8 @@ Documentation outline
.. toctree::
:maxdepth: 2
Introduction<introduction>
Introduction <introduction>
userguide
api
contributing
changelog
.. _introduction:
.. mdinclude:: ../README.md
.. include:: ../README.rst
This diff is collapsed.
.. _slicing:
Matrix Slicing
==============
Affine matrix expressions form the core of PICOS' modeling toolbox: All
:class:`constant <picos.Constant>` and
:class:`variable <picos.expressions.variables>` expressions that you enter,
including integral variables, and any linear combination of these objects, are
stored as instances of the multidimensional
:class:`~picos.expressions.ComplexAffineExpression` class.
This base class implements plenty of algebraic operations to combine and modify
your initial expressions to yield the desired statements.
One of these operations is slicing, denoted by ``A[·]`` for an affine expression
``A``.
.. rubric:: Preliminaries
Unlike in NumPy, all multidimensional expressions are strictly matrices.
In particular, there are no flat arrays but only row and column vectors, and any
scalar expression is also a :math:`1 \times 1` matrix.
PICOS does not support tensors or higher order expressions, but it does support
the
`Kronecker product <https://en.wikipedia.org/wiki/Kronecker_product>`_ as well
as
:meth:`partial trace <picos.expressions.ComplexAffineExpression.partial_trace>`
and
:meth:`partial transposition <picos.expressions.ComplexAffineExpression.partial_transpose>`
operations to enable some of the optimization problems naturally defined on
tensors.
If you enter data in the form of a flat array (e.g. a Python :class:`list` or
a NumPy :class:`~numpy:numpy.ndarray` with one axis), it will be read as a
column vector.
In PICOS, all indices start from zero.
.. rubric:: Slicing modes
PICOS has two modes for slicing: :ref:`arbitrary_access` and
:ref:`proper_slicing`.
Arbitrary Access lets you select individual elements from a vector or matrix
expression and put them in a column vector in the desired order.
:meth:`Transposition <picos.expressions.ComplexAffineExpression.T>`,
:meth:`reshaping <picos.expressions.ComplexAffineExpression.reshaped>` and
:meth:`broadcasting <picos.expressions.ComplexAffineExpression.broadcasted>` can
then be used to put the selection into the desired shape.
Arbitrary Access has the form ``A[·]`` where ``·`` stands for an integer, a
Python :class:`slice`, a flat collection of integers such as a :class:`list`,
or a dictionary storing sparse index pairs.
Proper Slicing refers to selecting certain rows and columns of a matrix, and
forming a new matrix where all elements that are not selected are removed.
It has the form ``A[·,·]`` where each ``·`` stands for an integer, a
:class:`slice`, or a flat collection of integers.
To demonstrate the different possibilities, we use a constant :math:`5 \times 5`
expression:
>>> from picos import Constant
>>> A = Constant("A", range(25), (5,5))
>>> A
<5×5 Real Constant: A>
>>> print(A)
[ 0.00e+00 5.00e+00 1.00e+01 1.50e+01 2.00e+01]
[ 1.00e+00 6.00e+00 1.10e+01 1.60e+01 2.10e+01]
[ 2.00e+00 7.00e+00 1.20e+01 1.70e+01 2.20e+01]
[ 3.00e+00 8.00e+00 1.30e+01 1.80e+01 2.30e+01]
[ 4.00e+00 9.00e+00 1.40e+01 1.90e+01 2.40e+01]
.. _arbitrary_access:
Arbitrary Access
----------------
.. rubric:: By integer
If a single integer or a single flat collection of integers is given, then these
indices refer to the column-major vectorization of the matrix, represented by
the order of the numbers in the demonstration matrix ``A``.
The most common case is selecting a single element via an integer index:
>>> A[0] # Select the first element as a scalar expression.
<1×1 Real Constant: A[0]>
>>> print(A[0]) # Print its value.
0.0
>>> print(A[7]) # The value of the eighth element.
7.0
>>> # Negative indices are counted from the rear; -1 refers to the last element:
>>> print(A[-1])
24.0
.. rubric:: By slice
Python slices allow you to compactly specify a structured sequence of elements
to extract.
A Python slice has the form ``a:b`` or ``a:b:s`` with :math:`a` the inclusive
start index, :math:`b` the exclusive stop index and :math:`s` a step size.
Negative :math:`a` and :math:`b`, as in the integer index case, are counted from
the rear, while a negative step size reverses the order.
All of :math:`a`, :math:`b` and :math:`s` may be omitted. Then, the defaults are
.. math::
s &= 1, \\
a &= \begin{cases}
0,~&\text{if}~s > 0, \\
\text{len}(A) - 1,~&\text{if}~s < 0,
\end{cases} \\
b &= \begin{cases}
\text{len}(A),~&\text{if}~s > 0, \\
\textbf{None},~&\text{if}~s < 0.
\end{cases}
Note the :obj:`None` in the statement above: When going backwards, this special
token is the only way to stop at the first element with index :math:`0` as
:math:`-1` refers to the last element. For example, the first two elements in
reverse order are selected via the slice ``1:None:-1`` or just ``1::-1``.
>>> A[:2] # The first two elements as a column vector.
<2×1 Real Constant: A[:2]>
>>> print(A[:2])
[ 0.00e+00]
[ 1.00e+00]
>>> print(A[1::-1]) # The first two elements reversed (indices 1 and 0).
[ 1.00e+00]
[ 0.00e+00]
>>> print(A[-2:]) # The last two elements.
[ 2.30e+01]
[ 2.40e+01]
>>> print(A[2:7].T) # The third to seventh element (transposed).
[ 2.00e+00 3.00e+00 4.00e+00 5.00e+00 6.00e+00]
>>> print(A[2:7:2].T) # As before, but with a step size of 2.
[ 2.00e+00 4.00e+00 6.00e+00]
You could use this to vectorize :math:`A` in column-major order, but ``A.vec``
is both individually faster and has its result cached:
>>> A[:].equals(A.vec)
True
>>> A.vec is A.vec # Cached.
True
>>> A[:] is A[:] # Computed again as new expression.
False
.. rubric:: By integer sequence
By providing a :class:`list` or a similar vector of integers, you can select
arbitrary elements in any order, including duplicates:
>>> print(A[[0,1,0,1,-1]])
[ 0.00e+00]
[ 1.00e+00]
[ 0.00e+00]
[ 1.00e+00]
[ 2.40e+01]
Note that you cannot provide a :class:`tuple` instead of a list, as ``A[(·,·)]``
is understood by Python as ``A[·,·]`` (see :ref:`proper_slicing`).
Any other object that the function :func:`~picos.expressions.data.load_data`
with ``typecode="i"`` loads as an integer row or column vector works, including
integral NumPy arrays.
.. _sparse_index_dict:
.. rubric:: By sparse index pair dictionary
If you provide a dictionary with exactly two keys that can be compared via
``<`` and whose values are integer sequences of same length (anything recognized
by :func:`~picos.expressions.data.load_data` as an integer vector), PICOS
interprets the sequence corresponding to the smaller key as row indices and the
sequence corresponding to the greater key as the corresponding column indices:
>>> print(A[{"x": range(3), "y": [1]*3}]) # Select (0,1), (1,1) and (2,1).
[ 5.00e+00]
[ 6.00e+00]
[ 7.00e+00]
>>> print(A[{"y": range(3), "x": [1]*3}]) # Transposed selection, as "x" < "y".
[ 1.00e+00]
[ 6.00e+00]
[ 1.10e+01]
You could use this to extract the main diagonal of :math:`A`, but ``A.maindiag``
is both individually faster and has its result cached:
>>> indices = dict(enumerate([range(min(A.shape))]*2))
>>> indices
{0: range(0, 5), 1: range(0, 5)}
>>> A[indices].equals(A.maindiag)
True
>>> A.maindiag is A.maindiag # Cached.
True
>>> A[indices] is A[indices] # Computed again as new expression.
False
.. _proper_slicing:
Proper Slicing
--------------
If you provide not one but two integers, slices, or integer sequences separated
by a comma or given as a :obj:`tuple`, then they are understood as row and
column indices, respectively.
Unlike when providing a sparse index pair by dictionary, these indices select
*entire* rows and columns and PICOS returns the matrix of all elements that are
selected twice (both by row and by column):
>>> print(A[1,2]) # The single element at (1,2) (second row, third column).
11.0
>>> print(A[0,:]) # The first row of the matrix.
[ 0.00e+00 5.00e+00 1.00e+01 1.50e+01 2.00e+01]
>>> print(A[range(3),-1]) # The first three elements of the last column.
[ 2.00e+01]
[ 2.10e+01]
[ 2.20e+01]
>>> print(A[[0,1],[0,1]]) # The first second-order principal submatrix.
[ 0.00e+00 5.00e+00]
[ 1.00e+00 6.00e+00]
>>> print(A[1:-1,1:-1]) # Cut away the outermost pixels of an image.
[ 6.00e+00 1.10e+01 1.60e+01]
[ 7.00e+00 1.20e+01 1.70e+01]
[ 8.00e+00 1.30e+01 1.80e+01]
>>> print(A[::2,::2]) # Sample every second element.
[ 0.00e+00 1.00e+01 2.00e+01]
[ 2.00e+00 1.20e+01 2.20e+01]
[ 4.00e+00 1.40e+01 2.40e+01]
You can even select the entire matrix to effectively create a copy of it, though
this is discouraged as expressions are supposed to be immutable so that reusing
an expression in multiple places is always safe.
>>> A[:,:].equals(A)
True
>>> A[:,:] is A
False
We refer to this as proper slicing because you cut out the rows that you want,
throwing away the rest, then cut the desired columns out from the remainder.
It's like cutting a square cake except that you can also duplicate the pieces!
.. note::
In NumPy, ``A[[0,1],[0,1]]`` would create a flat array with the elements
``A[0,0]`` and ``A[1,1]`` while PICOS creates a submatrix from the first two
rows and columns as in the example above. If you want to mirror NumPy's
behavior in PICOS, see :ref:`sparse_index_dict`.
This diff is collapsed.
This diff is collapsed.
......@@ -12,6 +12,9 @@ to the :ref:`function cheat sheet <cheatsheet>` or go directly to the
:maxdepth: 2
tutorial.rst
constraints.rst
examples.rst
cheatsheet.rst
api.rst
slicing.rst
duals.rst
tolerances.rst
# coding: utf-8
#-------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
# Copyright (C) 2012-2017 Guillaume Sagnol
# Copyright (C) 2018 Maximilian Stahlberg
# Copyright (C) 2018-2019 Maximilian Stahlberg
#
# This file is part of PICOS.
#
......@@ -18,39 +18,79 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#-------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
"""A Python Interface to Conic Optimization Solvers.
The :mod:`picos` namespace gives you quick access to the most important classes
and functions for optimizing with PICOS, so that ``import picos`` is often
sufficient for implementing your model.
"""
import os
# The Problem class is the user's main way of interfacing PICOS.