...
 
Commits (565)
......@@ -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
- >
pacman -Syu --noconfirm
gcc glpk python-coverage python-cvxopt python-numpy python-pip
python-setuptools swig which
- pip install swiglpk smcp
script:
- python ./test.py -vv -s cvxopt glpk smcp
- >
coverage run -p --source picos
./test.py -p -vv -s cvxopt glpk smcp
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 smcp
script:
- >
coverage2 run -p --source picos
./test.py -p -vv -s cvxopt glpk smcp
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 m2r 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
# 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 +163,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 +185,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 m2r 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 +207,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 m2r 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.
......@@ -44,7 +44,7 @@ with PICOS:
>>> 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)
>>> solution = P.solve()
>>> print(solution["status"])
'integer optimal solution'
>>> print(P.obj_value())
......@@ -59,9 +59,13 @@ with PICOS:
### 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
------------
......
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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
.. _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
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.
from .problem import Problem
new_problem = Problem
from .apidoc import api_start, api_end
_API_START = api_start(globals())
# -------------------------------
# Character set changes.
from .glyphs import ascii, latin1, unicode, default as default_charset # noqa
# Model setup.
from .modeling import (find_assignment, maximize, minimize, Objective, # noqa
Options, Problem, Solution)
# Constants.
from .expressions import Constant # noqa
# Make character set changes available.
from .glyphs import ascii, latin1, unicode, default as default_charset
# Variables.
from .expressions.variables import ( # noqa
BinaryVariable, ComplexVariable, HermitianVariable, IntegerVariable,
LowerTriangularVariable, RealVariable, SkewSymmetricVariable,
SymmetricVariable, UpperTriangularVariable)
# Basic tools.
from .tools import import_cbf, new_param
# Sets.
from .expressions import ( # noqa
Ball, ExponentialCone, SecondOrderCone, Simplex, RotatedSecondOrderCone)
# Constraints and expressions that cannot be created algebraically.
from .tools import ball, expcone, flow_Constraint, simplex, truncated_simplex
# Algebraic function-like classes.
from .constraints import FlowConstraint # noqa
from .expressions import ( # noqa
DetRootN, Entropy, GeometricMean, Logarithm, LogSumExp,
NegativeEntropy, Norm, SpectralNorm, NuclearNorm, PowerTrace,
SumExtremes, SumExponentials)
# Algebraic functions. (TODO: Give them a module of their own.)
from .tools import detrootn, diag, diag_vect, exp, geomean, kron, \
kullback_leibler, lambda_max, lambda_min, log, logsumexp, lse, norm, \
partial_trace, partial_transpose, sum, sumexp, sum_k_largest, \
sum_k_largest_lambda, sum_k_smallest, sum_k_smallest_lambda, trace, tracepow
# Algebraic functions, including legacy ones.
from .expressions.algebra import * # noqa
# Exceptions that the user might want to catch.
from .tools import DualizationError, NonConvexError, NotAppropriateSolverError,\
QuadAsSocpError
# Utilities.
from .expressions.data import value # noqa
from .solvers import available_solvers # noqa
LOCATION = os.path.realpath(os.path.join(os.getcwd(),os.path.dirname(__file__)))
VERSION_FILE = os.path.join(LOCATION, ".version")
# Non-algebraic legacy imports.
from .modeling.file_in import import_cbf # noqa
def get_version_info():
with open(VERSION_FILE, "r") as versionFile:
# Exceptions.
from .modeling import SolutionFailure # noqa
from .expressions import NotValued # noqa
_LOCATION = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
_VERSION_FILE = os.path.join(_LOCATION, ".version")
def _get_version_info():
with open(_VERSION_FILE, "r") as versionFile:
return tuple(versionFile.read().strip().split("."))
__version_info__ = get_version_info()
__version_info__ = _get_version_info()
__version__ = '.'.join(__version_info__)
# --------------------------------------
__all__ = api_end(_API_START, globals())
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# coding: utf-8
# ------------------------------------------------------------------------------
# Copyright (C) 2019 Maximilian Stahlberg
#
# This file is part of PICOS.
#
# PICOS is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PICOS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ------------------------------------------------------------------------------