tools.py

picos.tools.eval_dict(dict_of_variables)

if dict_of_variables is a dictionary mapping variable names (strings) to variables, this function returns the dictionary names -> variable values.

picos.tools.svec(mat, ignore_sym=False)

returns the svec representation of the cvx matrix mat. (see Dattorro, ch.2.2.2.1)

If ignore_sym = False (default), the function raises an Exception if mat is not symmetric. Otherwise, elements in the lower triangle of mat are simply ignored.

picos.tools.ltrim1(vec, uptri=True, offdiag_fact=1.0)

If vec is a vector or an affine expression of size n(n+1)/2, ltrim1(vec) returns a (n,n) matrix with the elements of vec in the lower triangle. If uptri == False, the upper triangle is 0, otherwise the upper triangle is the symmetric of the lower one.

picos.tools.lowtri(exp)

if exp is a square affine expression of size (n,n), lowtri(exp) returns the (n(n+1)/2)-vector of the lower triangular elements of exp.

Example

>>> import picos as pic
>>> import cvxopt as cvx
>>> prob=pic.Problem()
>>> X=prob.add_variable('X',(4,4),'symmetric')
>>> pic.tools.lowtri(X)
# (10 x 1)-affine expression: lowtri(X) #
>>> X0 = cvx.matrix(range(16),(4,4))
>>> X.value = X0 * X0.T
>>> print(X) #doctest: +NORMALIZE_WHITESPACE
[ 2.24e+02  2.48e+02  2.72e+02  2.96e+02]
[ 2.48e+02  2.76e+02  3.04e+02  3.32e+02]
[ 2.72e+02  3.04e+02  3.36e+02  3.68e+02]
[ 2.96e+02  3.32e+02  3.68e+02  4.04e+02]
>>> print(pic.tools.lowtri(X)) #doctest: +NORMALIZE_WHITESPACE
[ 2.24e+02]
[ 2.48e+02]
[ 2.72e+02]
[ 2.96e+02]
[ 2.76e+02]
[ 3.04e+02]
[ 3.32e+02]
[ 3.36e+02]
[ 3.68e+02]
[ 4.04e+02]
picos.tools.sum(lst, it=None, indices=None)

sum of a list of affine expressions. This fonction can be used with python list comprehensions (see the example below).

Parameters:
  • lst – list of AffinExp.
  • it (None or str or list.) – Description of the letters which should be used to replace the dummy indices. The function tries to find a template for the string representations of the affine expressions in the list. If several indices change in the list, their letters should be given as a list of strings, in their order of appearance in the resulting string. For example, if three indices change in the summands, and you want them to be named 'i', 'j' and 'k', set it = ['i','j','k']. You can also group two indices which always appear together, e.g. if 'i' always appear next to 'j' you could set it = [('ij',2),'k']. Here, the number 2 indicates that 'ij' replaces 2 indices. If it is set to None, or if the function is not able to find a template, the string of the first summand will be used for the string representation of the sum.
  • indices (str.) – a string to denote the set where the indices belong to.

Example:

>>> import picos as pic
>>> prob=pic.Problem()
>>> x={}
>>> names=['foo','bar','baz']
>>> for n in names:
...   x[n]=prob.add_variable( 'x[{0}]'.format(n),(3,5) )
>>> for n in names:
...   print("{}: {}".format(n, x[n])) #doctest: +NORMALIZE_WHITESPACE
foo: # variable x[foo]:(3 x 5),continuous #
bar: # variable x[bar]:(3 x 5),continuous #
baz: # variable x[baz]:(3 x 5),continuous #
>>> pic.sum([x[n] for n in names],'n','names')
# (3 x 5)-affine expression: Σ_{n in names} x[n] #
>>> pic.sum([(i+1) * x[n] for i,n in enumerate(names)],['i','n'],'[3] x names') #two indices
# (3 x 5)-affine expression: Σ_{i,n in [3] x names} i*x[n] #
>>> IJ = [(1,2),(2,4),(0,1),(1,3)]
>>> pic.sum([x['foo'][ij] for ij in IJ],[('ij',2)],'IJ') #double index
# (1 x 1)-affine expression: Σ_{ij in IJ} x[foo][ij] #
picos.tools.diag(exp, dim=1)

if exp is an affine expression of size (n,m), diag(exp,dim) returns a diagonal matrix of size dim*n*m \times dim*n*m, with dim copies of the vectorized expression exp[:] on the diagonal.

In particular:

  • when exp is scalar, diag(exp,n) returns a diagonal matrix of size n \times n, with all diagonal elements equal to exp.
  • when exp is a vector of size n, diag(exp) returns the diagonal matrix of size n \times n with the vector exp on the diagonal

Example

>>> import picos as pic
>>> prob=pic.Problem()
>>> x=prob.add_variable('x',1)
>>> y=prob.add_variable('y',1)
>>> pic.tools.diag(x-y,4)
# (4 x 4)-affine expression: Diag(x -y) #
>>> pic.tools.diag(x//y)
# (2 x 2)-affine expression: Diag([x;y]) #
picos.tools.new_param(name, value)

Declare a parameter for the problem, that will be stored as a cvxopt sparse matrix. It is possible to give a list or a dictionary of parameters. The function returns a constant AffinExp (or a list or a dict of AffinExp) representing this parameter.

Note

Declaring parameters is optional, since the expression can as well be given by using normal variables. (see Example below). However, if you use this function to declare your parameters, the names of the parameters will be displayed when you print an Expression or a Constraint

Parameters:
  • name (str.) – The name given to this parameter.
  • value – The value (resp list of values, dict of values) of the parameter. The type of value (resp. the elements of the list value, the values of the dict value) should be understandable by the function _retrieve_matrix().
Returns:

A constant affine expression (AffinExp) (resp. a list of AffinExp of the same length as value, a dict of AffinExp indexed by the keys of value)

Example:

>>> import cvxopt as cvx
>>> prob=pic.Problem()
>>> x=prob.add_variable('x',3)
>>> B={'foo':17.4,'matrix':cvx.matrix([[1,2],[3,4],[5,6]]),'ones':'|1|(4,1)'}
>>> B['matrix']*x+B['foo']
# (2 x 1)-affine expression: [ 2 x 3 MAT ]*x + |17.4| #
>>> #(in the string above, |17.4| represents the 2-dim vector [17.4,17.4])
>>> B=pic.new_param('B',B)
>>> #now that B is a param, we have a nicer display:
>>> B['matrix']*x+B['foo']
# (2 x 1)-affine expression: B[matrix]*x + |B[foo]| #
picos.tools.available_solvers()

Lists all available solvers

picos.tools.offset_in_lil(lil, offset, lower)

substract the offset from all elements of the (recursive) list of lists lil which are larger than lower.

picos.tools.import_cbf(filename)

Imports the data from a CBF file, and creates a Problem object.

The created problem contains one (multidimmensional) variable for each cone specified in the section VAR of the .cbf file, and one (multidimmensional) constraint for each cone specified in the sections CON and PSDCON.

Semidefinite variables defined in the section PSDVAR of the .cbf file are represented by a matrix picos variable X with X.vtype='symmetric'.

This function returns a tuple (P,x,X,data), where:

  • P is the imported picos Problem object.
  • x is a list of Variable objects, representing the (multidimmensional) scalar variables.
  • X is a list of Variable objects, representing the symmetric semidefinite positive variables.
  • data is a dictionary containing picos parameters (AffinExp objects) used to define the problem. Indexing is with respect to the blocks of variables as defined in thes sections VAR and CON of the .cbf file.
picos.tools.diag_vect(exp)

Returns the vector with the diagonal elements of the matrix expression exp

Example

>>> import picos as pic
>>> prob=pic.Problem()
>>> X=prob.add_variable('X',(3,3))
>>> pic.tools.diag_vect(X)
# (3 x 1)-affine expression: diag(X) #
exception picos.tools.QuadAsSocpError(msg)

Exception raised when the problem can not be solved in the current form, because quad constraints are not handled. User should try to convert the quads as socp.

exception picos.tools.NotAppropriateSolverError(msg)

Exception raised when trying to solve a problem with a solver which cannot handle it

exception picos.tools.NonConvexError(msg)

Exception raised when non-convex quadratic constraints are passed to a solver which cannot handle them.

exception picos.tools.DualizationError(msg)

Exception raised when a non-standard conic problem is being dualized.

picos.tools.geomean(exp)

returns a GeoMeanExp object representing the geometric mean of the entries of exp[:]. This can be used to enter inequalities of the form t <= geomean(x). Note that geometric mean inequalities are internally reformulated as a set of SOC inequalities.

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> x = prob.add_variable('x',1)
>>> y = prob.add_variable('y',3)
>>> # the following line adds the constraint x <= (y0*y1*y2)**(1./3) in the problem:
>>> prob.add_constraint(x<pic.geomean(y))
picos.tools.norm(exp, num=2, denom=1)

returns a NormP_Exp object representing the (generalized-) p-norm of the entries of exp[:]. This can be used to enter constraints of the form \Vert x \Vert_p \leq t with p\geq1. Generalized norms are also defined for p<1, by using the usual formula \operatorname{norm}(x,p) := \Big(\sum_i x_i^p\Big)^{1/p}. Note that this function is concave (for p<1) over the set of vectors with nonnegative coordinates. When a constraint of the form \operatorname{norm}(x,p) > t with p\leq1 is entered, PICOS implicitely assumes that x is a nonnegative vector.

This function can also be used to represent the Lp,q- norm of a matrix (for p,q \geq 1): \operatorname{norm}(X,(p,q)) := \Big(\sum_i (\sum_j x_{ij}^q )^{p/q}\Big)^{1/p}, that is, the p-norm of the vector formed with the q-norms of the rows of X.

The exponent p of the norm must be specified either by a couple numerator (2d argument) / denominator (3d arguments), or directly by a float p given as second argument. In the latter case a rational approximation of p will be used. It is also possible to pass 'inf' as second argument for the infinity-norm (aka max-norm).

For the case of (p,q)-norms, p and q must be specified by a tuple of floats in the second argument (rational approximations will be used), and the third argument will be ignored.

Example:

>>> import picos as pic
>>> P = pic.Problem()
>>> x = P.add_variable('x',1)
>>> y = P.add_variable('y',3)
>>> pic.norm(y,7,3) < x
# p-norm ineq : norm_7/3( y)<x#
>>> pic.norm(y,-0.4) > x
# generalized p-norm ineq : norm_-2/5( y)>x#
>>> X = P.add_variable('X',(3,2))
>>> pic.norm(X,(1,2)) < 1
# pq-norm ineq : norm_1,2( X)<1.0#
>>> pic.norm(X,('inf',1)) < 1
# pq-norm ineq : norm_inf,1( X)<1.0#
picos.tools.tracepow(exp, num=1, denom=1, coef=None)

Returns a TracePow_Exp object representing the trace of the pth-power of the symmetric matrix exp, where exp is an AffinExp which we denote by X. This can be used to enter constraints of the form \operatorname{trace} X^p \leq t with p\geq1 or p < 0, or \operatorname{trace} X^p \geq t with 0 \leq p \leq 1. Note that X is forced to be positive semidefinite when a constraint of this form is entered in PICOS.

It is also possible to specify a coef matrix (M) of the same size as exp, in order to represent the expression \operatorname{trace} (M X^p). The constraint \operatorname{trace} (M X^p)\geq t can be reformulated with SDP constraints if M is positive semidefinite and 0<p<1.

Trace of power inequalities are internally reformulated as a set of Linear Matrix Inequalities (SDP), or second order cone inequalities if exp is a scalar.

The exponent p of the norm must be specified either by a couple numerator (2d argument) / denominator (3d arguments), or directly by a float p given as second argument. In the latter case a rational approximation of p will be used.

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> X = prob.add_variable('X',(3,3),'symmetric')
>>> t = prob.add_variable('t',1)
>>> pic.tracepow(X,7,3) < t
# trace of pth power ineq : trace( X)**7/3<t#
>>> pic.tracepow(X,0.6) > t
# trace of pth power ineq : trace( X)**3/5>t#
>>> A = cvx.normal(3,3);A=A*A.T #A random semidefinite positive matrix
>>> A = pic.new_param('A',A)
>>> pic.tracepow(X,0.25,coef=A) > t
# trace of pth power ineq : trace[ A *(X)**1/4]>t#
picos.tools.trace(exp)

trace of a square AffinExp

picos.tools.partial_transpose(exp, dims_1=None, subsystems=None, dims_2=None)

Partial transpose of an Affine Expression, with respect to given subsystems. If X is a matrix AffinExp that can be written as X = A_0 \otimes \cdots \otimes A_{n-1} for some matrices A_0,\ldots,A_{n-1} of respective sizes dims_1[0] x dims_2[0], … , dims_1[n-1] x dims_2[n-1], this function returns the matrix Y = B_0 \otimes \cdots \otimes B_{n-1}, where B_i=A_i^T if i in subsystems, and B_i=A_i otherwise.

The optional parameters dims_1 and dims_2 are tuples specifying the dimension of each subsystem A_i. The argument subsystems must be a tuple (or an int) with the index of all subsystems to be transposed.

The default value dims_1=None automatically computes the size of the subblocks, assuming that exp is a n^k \times n^k-square matrix, for the smallest appropriate value of k \in [2,6], that is dims_1=(n,)*k.

If dims_2 is not specified, it is assumed that the subsystems A_i are square, i.e., dims_2=dims_1. If subsystems is not specified, the default assumes that only the last system must be transposed, i.e., subsystems = (len(dims_1)-1,)

Example:

>>> import picos as pic
>>> import cvxopt as cvx
>>> P = pic.Problem()
>>> X = P.add_variable('X',(4,4))
>>> X.value = cvx.matrix(range(16),(4,4))
>>> print(X) #doctest: +NORMALIZE_WHITESPACE
[ 0.00e+00  4.00e+00  8.00e+00  1.20e+01]
[ 1.00e+00  5.00e+00  9.00e+00  1.30e+01]
[ 2.00e+00  6.00e+00  1.00e+01  1.40e+01]
[ 3.00e+00  7.00e+00  1.10e+01  1.50e+01]
>>> print(X.Tx) #standard partial transpose (with respect to the 2x2 blocks and 2d subsystem) #doctest: +NORMALIZE_WHITESPACE
[ 0.00e+00  1.00e+00  8.00e+00  9.00e+00]
[ 4.00e+00  5.00e+00  1.20e+01  1.30e+01]
[ 2.00e+00  3.00e+00  1.00e+01  1.10e+01]
[ 6.00e+00  7.00e+00  1.40e+01  1.50e+01]
>>> print(pic.partial_transpose(X,(2,2),0)) #(now with respect to the first subsystem) #doctest: +NORMALIZE_WHITESPACE
[ 0.00e+00  4.00e+00  2.00e+00  6.00e+00]
[ 1.00e+00  5.00e+00  3.00e+00  7.00e+00]
[ 8.00e+00  1.20e+01  1.00e+01  1.40e+01]
[ 9.00e+00  1.30e+01  1.10e+01  1.50e+01]
picos.tools.partial_trace(X, k=1, dim=None)

Partial trace of an Affine Expression, with respect to the k th subsystem for a tensor product of dimensions dim. If X is a matrix AffinExp that can be written as X = A_0 \otimes \cdots \otimes A_{n-1} for some matrices A_0,\ldots,A_{n-1} of respective sizes dim[0] x dim[0], … , dim[n-1] x dim[n-1] (dim is a list of ints if all matrices are square), or dim[0][0] x dim[0][1], …,``dim[n-1][0] x dim[n-1][1]`` (dim is a list of 2-tuples if any of them except the k th one is rectangular), this function returns the matrix Y = \operatorname{trace}(A_k)\quad A_0 \otimes \cdots A_{k-1} \otimes A_{k+1} \otimes \cdots \otimes A_{n-1}.

The default value dim=None automatically computes the size of the subblocks, assuming that X is a n^2 \times n^2-square matrix with blocks of size n \times n.

Example:

>>> import picos as pic
>>> import cvxopt as cvx
>>> P = pic.Problem()
>>> X = P.add_variable('X',(4,4))
>>> X.value = cvx.matrix(range(16),(4,4))
>>> print(X) #doctest: +NORMALIZE_WHITESPACE
[ 0.00e+00  4.00e+00  8.00e+00  1.20e+01]
[ 1.00e+00  5.00e+00  9.00e+00  1.30e+01]
[ 2.00e+00  6.00e+00  1.00e+01  1.40e+01]
[ 3.00e+00  7.00e+00  1.10e+01  1.50e+01]
>>> print(pic.partial_trace(X)) #partial trace with respect to second subsystem (k=1) #doctest: +NORMALIZE_WHITESPACE
[ 5.00e+00  2.10e+01]
[ 9.00e+00  2.50e+01]
>>> print(pic.partial_trace(X,0)) #and now with respect to first subsystem (k=0) #doctest: +NORMALIZE_WHITESPACE
[ 1.00e+01  1.80e+01]
[ 1.20e+01  2.00e+01]
picos.tools.detrootn(exp)

returns a DetRootN_Exp object representing the determinant of the n th-root of the symmetric matrix exp, where n is the dimension of the matrix. This can be used to enter constraints of the form (\operatorname{det} X)^{1/n} \geq t. Note that X is forced to be positive semidefinite when a constraint of this form is entered in PICOS. Determinant inequalities are internally reformulated as a set of Linear Matrix Inequalities (SDP).

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> X = prob.add_variable('X',(3,3),'symmetric')
>>> t = prob.add_variable('t',1)
>>> t < pic.detrootn(X)
# nth root of det ineq : det( X)**1/3>t#
picos.tools.ball(r, p=2)

returns a Ball object representing:

  • a L_p Ball of radius r (\{x: \Vert x \Vert_p \geq r \}) if p \geq 1
  • the convex set \{x\geq 0: \Vert x \Vert_p \geq r \} p < 1.

Example

>>> import picos as pic
>>> P = pic.Problem()
>>> x = P.add_variable('x', 3)
>>> x << pic.ball(2,3)  #doctest: +NORMALIZE_WHITESPACE
# p-norm ineq : norm_3( x)<2.0#
>>> x << pic.ball(1,0.5)
# generalized p-norm ineq : norm_1/2( x)>1.0#
picos.tools.sum_k_largest(exp, k)

returns a Sum_k_Largest_Exp object representing the sum of the k largest elements of an affine expression exp. This can be used to enter constraints of the form \sum_{i=1}^k x_{i}^{\downarrow} \leq t. This kind of constraints is reformulated internally as a set of linear inequalities.

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> x = prob.add_variable('x',3)
>>> t = prob.add_variable('t',1)
>>> pic.sum_k_largest(x,2) < 1
# sum_k_largest constraint : sum_2_largest(x)<1.0#
>>> pic.sum_k_largest(x,1) < t
# (3x1)-affine constraint: max(x)<=t #
picos.tools.sum_k_largest_lambda(exp, k)

returns a Sum_k_Largest_Exp object representing the sum of the k largest eigenvalues of a square matrix affine expression exp. This can be used to enter constraints of the form \sum_{i=1}^k \lambda_{i}^{\downarrow}(X) \leq t. This kind of constraints is reformulated internally as a set of linear matrix inequalities (SDP). Note that exp is assumed to be symmetric (picos does not check).

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> X = prob.add_variable('X',(3,3),'symmetric')
>>> t = prob.add_variable('t',1)
>>> pic.sum_k_largest_lambda(X,3) < 1 #this is simply the trace of X
# (1x1)-affine constraint: 〈 I | X 〉 < 1.0 #
>>> pic.sum_k_largest_lambda(X,2) < t
# sum_k_largest constraint : sum_2_largest_lambda(X)<t#
picos.tools.lambda_max(exp)

largest eigenvalue of a square matrix expression (cf. pic.sum_k_largest(exp,1))

>>> import picos as pic
>>> prob = pic.Problem()
>>> x = prob.add_variable('X',(3,3),'symmetric')
>>> pic.lambda_max(X) < 2
# (3x3)-LMI constraint lambda_max(X)<=2.0 #
picos.tools.sum_k_smallest(exp, k)

returns a Sum_k_Smallest_Exp object representing the sum of the k smallest elements of an affine expression exp. This can be used to enter constraints of the form \sum_{i=1}^k x_{i}^{\uparrow} \geq t. This kind of constraints is reformulated internally as a set of linear inequalities.

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> x = prob.add_variable('x',3)
>>> t = prob.add_variable('t',1)
>>> pic.sum_k_smallest(x,2) > t
# sum_k_smallest constraint : sum_2_smallest(x)>t#
>>> pic.sum_k_smallest(x,1) > 3
# (3x1)-affine constraint: min(x)>=3.0 #
picos.tools.sum_k_smallest_lambda(exp, k)

returns a Sum_k_Smallest_Exp object representing the sum of the k smallest eigenvalues of a square matrix affine expression exp. This can be used to enter constraints of the form \sum_{i=1}^k \lambda_{i}^{\uparrow}(X) \geq t. This kind of constraints is reformulated internally as a set of linear matrix inequalities (SDP). Note that exp is assumed to be symmetric (picos does not check).

Example:

>>> import picos as pic
>>> prob = pic.Problem()
>>> X = prob.add_variable('X',(3,3),'symmetric')
>>> t = prob.add_variable('t',1)
>>> pic.sum_k_smallest_lambda(X,1) > 1
# (3x3)-LMI constraint lambda_min(X)>=1.0 #
>>> pic.sum_k_smallest_lambda(X,2) > t
# sum_k_smallest constraint : sum_2_smallest_lambda(X)>t#
picos.tools.lambda_min(exp)

smallest eigenvalue of a square matrix expression (cf. pic.sum_k_smallest(exp,1))

>>> import picos as pic
>>> prob = pic.Problem()
>>> x = prob.add_variable('X',(3,3),'symmetric')
>>> pic.lambda_min(X) > -1
# (3x3)-LMI constraint lambda_min(X)>=-1.0 #
picos.tools.simplex(gamma=1)

returns a Truncated_Simplex object representing the set \{x\geq 0: ||x||_1 \leq \gamma \}.

Example

>>> import picos as pic
>>> P = pic.Problem()
>>> x = P.add_variable('x', 3)
>>> x << pic.simplex(1)
# (4x1)-affine constraint: x in standard simplex #
>>> x << pic.simplex(2)
# (4x1)-affine constraint: x in simplex of radius 2 #
picos.tools.truncated_simplex(gamma=1, sym=False)

returns a Truncated_Simplex object representing object representing the set:

  • \{x \geq  0: ||x||_\infty \leq 1,\ ||x||_1 \leq \gamma \} if sym=False (default)
  • \{x: ||x||_\infty \leq 1,\ ||x||_1 \leq \gamma \} if sym=True.

Example

>>> import picos as pic
>>> P = pic.Problem()
>>> x = P.add_variable('x', 3)
>>> x << pic.truncated_simplex(2)
# (7x1)-affine constraint: x in truncated simplex of radius 2 #
>>> x << pic.truncated_simplex(2,sym=True)
# symmetrized truncated simplex constraint : ||x||_{infty;1} <= {1;2}#
picos.tools.kron(A, B)

Kronecker product of 2 expression, at least one of which must be constant

Example:

>>> import picos as pic
>>> import cvxopt as cvx
>>> import numpy as np
>>> P = pic.Problem()
>>> X = P.add_variable('X',(4,3))
>>> X.value = cvx.matrix(range(12),(4,3))
>>> I = pic.new_param('I',np.eye(2))
>>> print(pic.kron(I,X)) #doctest: +NORMALIZE_WHITESPACE
[ 0.00e+00  4.00e+00  8.00e+00  0.00e+00  0.00e+00  0.00e+00]
[ 1.00e+00  5.00e+00  9.00e+00  0.00e+00  0.00e+00  0.00e+00]
[ 2.00e+00  6.00e+00  1.00e+01  0.00e+00  0.00e+00  0.00e+00]
[ 3.00e+00  7.00e+00  1.10e+01  0.00e+00  0.00e+00  0.00e+00]
[ 0.00e+00  0.00e+00  0.00e+00  0.00e+00  4.00e+00  8.00e+00]
[ 0.00e+00  0.00e+00  0.00e+00  1.00e+00  5.00e+00  9.00e+00]
[ 0.00e+00  0.00e+00  0.00e+00  2.00e+00  6.00e+00  1.00e+01]
[ 0.00e+00  0.00e+00  0.00e+00  3.00e+00  7.00e+00  1.10e+01]