Commits (8)
......@@ -13,6 +13,9 @@ __pycache__/
# profiling
# setuptools
......@@ -26,8 +29,6 @@ pip-delete-this-directory.txt
# 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.
......@@ -87,4 +87,23 @@ pages:
- master
- doc
stage: deploy
- >
pacman -Sy --noconfirm
git glpk graphviz make m2r python-cvxopt python-matplotlib python-networkx
python-numpy python-pip python-scipy python-sphinx texlive-most
- pip install sphinx-automodapi swiglpk
- make -C doc latexpdf
- mv doc/build/latex/picos*.pdf .
name: picos-doc
- picos*.pdf
- master
- pdfdoc
# vi:ts=2:et:ai
......@@ -3,6 +3,7 @@
This file documents major changes to PICOS.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[Unreleased]: https://gitlab.com/picos-api/picos/compare/v1.2.0...master
[1.2.0]: https://gitlab.com/picos-api/picos/compare/v1.1.3...v1.2.0
[1.1.3]: https://gitlab.com/picos-api/picos/compare/v1.1.2...v1.1.3
[1.1.2]: https://gitlab.com/picos-api/picos/compare/v1.1.1...v1.1.2
......@@ -17,6 +18,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[0.1.0]: about:blank
## [Unreleased]
### Added
- Support for ECOS 2.0.7.
## [1.2.0] - 2019-01-11
### Important
......@@ -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
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).
description: "A python interface to conic optimization solvers."
home: https://gitlab.com/picos-api/picos
license: GPL-3.0
name: picos
version: {{ load_setup_py_data().version }}
......@@ -28,4 +23,9 @@ test:
- picos
description: "A python interface to conic optimization solvers."
home: https://gitlab.com/picos-api/picos
license: GPL-3.0
# vi:ts=2:et:ai
......@@ -6,6 +6,7 @@ SPHINXOPTS =
SPHINXBUILD = sphinx-build
BUILDDIR = build
AUTOGENDIR = api/autogen
# 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)"
rm -rf $(BUILDDIR)/*
rm -rf $(BUILDDIR)
rm -rf $(AUTOGENDIR)
.wy-table-responsive table td {
white-space: normal !important;
.wy-table-responsive {
overflow: visible !important;
......@@ -3,45 +3,14 @@
API Reference
.. rubric:: Basic interface
To use PICOS to its full extend you just need to know about the two components
.. toctree::
:maxdepth: 3
.. 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
.. rubric:: Customizing PICOS
The following components allow you to fine-tune the behavior of PICOS.
.. toctree::
:maxdepth: 3
.. 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!
PICOS is organized in a number of submodules, 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. Additional utilities can be found in :mod:`picos.tools`.
.. toctree::
:maxdepth: 3
:maxdepth: 1
.. _constraints:
The Constraints package
This package contains the constraint types that are used to express optimization
You do not need to instanciate these constraints directly; it is more convenient
to create them by applying Python's comparison operators to algebraic
expressions (see the :ref:`cheatsheet`).
.. module:: picos.constraints
.. automodapi:: picos.constraints
:headings: =-
.. _expression:
The Expressions module
This module contains the expression types created by PICOS when you perform
algebraic operations on variables and parameters. You do not need to create
expressions directly; it is more convenient to use standard Python operators
(see the :ref:`cheatsheet`) and additional algebraic functions (see the
:mod:`picos` and :mod:`picos.tools` namespaces) on the basic affine expressions
created by :func:`add_variable <picos.Problem.add_variable>` and
:func:`new_param <picos.new_param>`.
.. automodule:: picos.expressions
.. _glyphs:
The Glyphs module
PICOS internally uses this module to produce string representations for the
algebraic expressions that you create.
The function-like objects that are used to build such strings are called
"glyphs" and are instanciated by this module following the
`singleton pattern <https://en.wikipedia.org/wiki/Singleton_pattern>`_.
As a result, you can modify the glyph objects listed below to influence how
PICOS will format future strings, for example to disable use of unicode symbols
that your console does not suppport or to adapt PICOS' output to the rest of
your application.
Here's an example of first swapping the entire character set to display
expressions using only `Latin-1 <https://en.wikipedia.org/wiki/ISO/IEC_8859-1>`_
characters, and then modifying a single glyph to our liking:
>>> import picos
>>> X = picos.new_problem().add_variable("X", (2,2), "symmetric")
>>> print(X >> 0)
X ≽ 0
>>> picos.glyphs.latin1()
>>> print(X >> 0)
X » 0
>>> picos.glyphs.psdge.template = "{} - {} is psd"
>>> print(X >> 0)
X - 0 is psd
Note that glyphs understand some algebraic rules such as operator precedence
and associativity. This is possible because strings produced by glyphs remember
how they were created.
>>> one_plus_two = picos.glyphs.add(1, 2)
>>> one_plus_two
'1 + 2'
>>> one_plus_two.glyph.template, one_plus_two.operands
('{} + {}', (1, 2))
>>> picos.glyphs.add(one_plus_two, 3)
'1 + 2 + 3'
>>> picos.glyphs.sub(0, one_plus_two)
'0 - (1 + 2)'
The positive semidefinite glyph above does not yet know how to properly handle
arguments with respect to the ``-`` symbol involved, but we can modify it
>>> print(X + X >> X + X)
X + X - X + X is psd
>>> # Use the same operator binding strength as regular substraction.
>>> picos.glyphs.psdge.order = picos.glyphs.sub.order
>>> print(X + X >> X + X)
X + X - (X + X) is psd
You can reset all glyphs to their initial state as follows:
>>> picos.glyphs.default()
.. automodule:: picos.glyphs
.. module:: picos
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.
You can find additional utilities in the :mod:`picos.tools` namespace.
.. automodapi:: picos
:headings: =-
.. _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.
(:ref:`cheatsheet`) and algebraic functions (:mod:`picos.tools`) to create
expressions and constraints involving these variables.
.. autoclass:: picos.Problem
.. automodule:: picos.problem
.. _solvers:
The Solvers package
This package contains the interfaces to the optimization solvers that PICOS uses
as its backend.
You do not need to instanciate any of the solver classes directly; if you want
to select a particular solver, it is most convenient to supply it to
:func:`Problem.solve <picos.Problem.solve>` via the ``solver`` keyword argument.
.. module:: picos.solvers
.. automodapi:: picos.solvers
: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 :mod:`picos` namespace. For example, you can write :func:`picos.sum
<picos.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``
that it is clear which of the functions are imported into the :mod:`picos`
.. automodule:: picos.tools
# coding: utf-8
# PICOS documentation build configuration file.
# This file is execfile()d with the current directory set to its containing dir.
import sys, os, subprocess
# Use the PICOS source directory for autodoc.
import sys, os
sys.path.insert(0, os.path.abspath(".."))
# -- General configuration -----------------------------------------------------
# Use the PICOS source directory for autodoc.
sys.path.insert(0, os.path.abspath(".."))
# Add Sphinx extensions.
extensions = [
......@@ -29,10 +25,6 @@ extensions = [
autoclass_content = 'both'
autodoc_member_order = 'groupwise'
autodoc_default_options = {
'members': None,
'undoc-members': None,
# TODO: Uncomment once autodoc_inherit_docstrings works.
#'inherited-members': None,
'show-inheritance': True
......@@ -41,15 +33,15 @@ autodoc_default_options = {
autodoc_inherit_docstrings = False
# Configure automodapi.
automodapi_toctreedirnm = 'automodapi'
automodapi_toctreedirnm = 'api/autogen'
automodsumm_inherited_members = True
# Configure intersphinx.
intersphinx_cache_limit = 10
intersphinx_mapping = {
'python': ('http://docs.python.org/3', None),
'numpy': ('http://docs.scipy.org/doc/numpy', None),
'cvxopt': ('http://cvxopt.org/userguide', None)
'python': ('https://docs.python.org/3', None),
'numpy': ('https://docs.scipy.org/doc/numpy', None),
'cvxopt': ('https://cvxopt.org/userguide', None)
# Configure matplotlib.
......@@ -57,12 +49,6 @@ plot_html_show_source_link = False
plot_formats = ['png']
plot_html_show_formats = False
# Configure todo.
todo_include_todos = True
# Add template directories.
templates_path = []
# Warn about all invalid references.
nitpicky = True
......@@ -72,13 +58,10 @@ nitpick_ignore = [
("py:class", "RSOCC")
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
# Set the master toctree document.
master_doc = 'index'
# General information about the project.
# Specify general information about the project.
projectname = u'PICOS'
project = u'PICOS'
copyright = u'2012–2018 G. Sagnol, 2017–2019 M. Stahlberg'
......@@ -88,39 +71,18 @@ from version import get_version, SHORT
version = get_version()
release = get_version(SHORT)
# The language for content autogenerated by Sphinx.
# Set the language for content autogenerated by Sphinx.
language = 'en'
# Set the date format to the only one that is both human readable and sortable.
today_fmt = '%Y-%m-%d'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# Disable function parentheses.
add_function_parentheses = False
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
......@@ -130,6 +92,10 @@ html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_theme_options = {"logo_only": True}
# Fix line breaks in tables not working in the "read the doc" theme.
html_static_path = ['_static']
html_context = {'css_files': ['_static/theme_override.css']}
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = '{} {} Documentation'.format(project, release)
......@@ -146,11 +112,6 @@ html_logo = "logo_text.png"
# pixels large.
html_favicon = "favicon.ico"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%Y-%m-%d'
......@@ -159,22 +120,12 @@ html_last_updated_fmt = '%Y-%m-%d'
# typographically correct entities.
html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
html_domain_indices = False
# If false, no index is generated.
html_use_index = False
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
......@@ -184,99 +135,51 @@ html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'picosdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
'papersize': 'a4paper',
'pointsize': '10pt',
'preamble': '',
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
_authors = 'Guillaume Sagnol \\and Maximilian Stahlberg'
latex_documents = [
('index', 'picos.tex', u'picos Documentation',
u'Guillaume Sagnol', 'manual'),
('index', 'picos.tex', 'Full Documentation', _authors, 'manual', True),
('api', 'picos-api.tex', 'API Documentation', _authors, 'manual', True)
# The name of an image file (relative to this directory) to place at the top of
# the title page.
latex_logo = './picos_white.png'
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'pymathprog', u'picos Documentation',
[u'Guillaume Sagnol'], 1)
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'picos', u'picos Documentation',
u'Guillaume Sagnol', 'picos', 'python interface to conic optimization solvers.',
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# Do not generate the Python module index as it's redundant in the API
# documentation.
latex_domain_indices = False
# -- Miscellaneous -------------------------------------------------------------
def setup(app):
from sphinx.util.texescape import tex_replacements
from sphinx.util.texescape import tex_replacements
def em(text):
return '\\ensuremath{{{}}}'.format(text)
tex_replacements += [
(u'‖', em('\\Vert{}')),
(u'≽', em('\\succeq{}')),
(u'≼', em('\\preceq{}')),
(u'≤', em('\\leq{}')),
(u'≥', em('\\geq{}')),
(u'ᵀ', '\\textsuperscript{T}'),
(u'ᴴ', '\\textsuperscript{H}'),
(u'⟨', em('\\langle{}')),
(u'⟩', em('\\rangle{}')),
(u'⊙', em('\\odot{}')),
(u'∘', em('\\circ{}')),
(u'·', em('\\cdot{}')),
(u'∑', em('\\sum{}')),
(u'∈', em('\\in{}')),
(u'…', '\\ldots{}'),
(u'∀', em('\\forall{}'))
.. 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,7 @@ Documentation outline
.. toctree::
:maxdepth: 2
Introduction <introduction>
......@@ -118,7 +118,8 @@ def available_solvers(problem = None):
:returns: A list of names of available solvers.
:param Problem problem: Return only solvers that also support this problem.
:param picos.Problem problem: Return only solvers that also support this
return [name for name, solver in _solvers.items()
if solver.available() and (problem is None
......@@ -59,44 +59,57 @@ class ECOSSolver(Solver):
(scalar) constraint indices. Note that equality constraints use a
different index space."""
self._ecosModuleCache = None
"""Different versions of ECOS have a different path to the ecos.py
module, this is a cache of that module to allow for quick access."""
def reset_problem(self):
self.int = None
self._objectiveOffset = 0.0
def _array(self):
import ecos
return ecos.np.array
def ecos(self):
Returns the ECOS core module (found in ecos.py), which is obtained by
``import ecos`` up to ECOS 2.0.6 and by ``import ecos.ecos`` starting
with ECOS 2.0.7.
if self._ecosModuleCache is None:
import ecos
if hasattr(ecos, "ecos"):
self._ecosModuleCache = ecos.ecos
self._ecosModuleCache = ecos
return self._ecosModuleCache
def _matrix(self):
import ecos
return ecos.sparse.csc_matrix
def array(self):
return self.ecos.np.array
array = property(_array)
matrix = property(_matrix)
def matrix(self):
return self.ecos.sparse.csc_matrix
def zeros(self, shape):
"""Creates a zero array or a zero matrix, depending on ``shape``."""
if isinstance(shape, int) or len(shape) == 1:
import ecos
return ecos.np.zeros(shape)
return self.ecos.np.zeros(shape)
return self.matrix(shape)
def stack(self, *args):
"""Stacks vectors or matrices, the latter vertically."""
import ecos
# In the case of matrices, stack vertically.
if isinstance(args[0], ecos.sparse.base.spmatrix):
if isinstance(args[0], self.ecos.sparse.base.spmatrix):
for i in range(1, len(args)):
assert isinstance(args[i], ecos.sparse.base.spmatrix)
return ecos.sparse.vstack(args, format = "csc")
assert isinstance(args[i], self.ecos.sparse.base.spmatrix)
return self.ecos.sparse.vstack(args, format = "csc")
# In the case of arrays, append them.
for i in range(len(args)):
assert isinstance(args[i], ecos.np.ndarray)
return ecos.np.hstack(args)
assert isinstance(args[i], self.ecos.np.ndarray)
return self.ecos.np.hstack(args)
def _affineExpressionToGAndH(self, expression):
assert isinstance(expression, AffinExp)
......@@ -133,8 +146,6 @@ class ECOSSolver(Solver):
return self._affineExpressionToGAndH(expression)
def _import_problem(self):
import ecos
numVars = self.ext.numberOfVars
# ECOS' internal problem representation is stateless; a number of
......@@ -339,8 +350,6 @@ class ECOSSolver(Solver):
raise NotImplementedError()
def _solve(self):
import ecos
# An alias to the internal problem instance.
p = self.int
......@@ -391,7 +400,7 @@ class ECOSSolver(Solver):
# Attempt to solve the problem.
with self._header(), self._stopwatch():
solution = ecos.solve(**arguments)
solution = self.ecos.solve(**arguments)
# Debug print the solver output.
if self._debug():
......@@ -1712,6 +1712,7 @@ def new_param(name, value):
>>> import picos as pic
>>> import cvxopt as cvx
>>> prob=pic.Problem()
>>> x=prob.add_variable('x',3)