picos.expressions.exp_biaffine¶
Implements BiaffineExpression
.
Classes
- class picos.expressions.exp_biaffine.BiaffineExpression(string, shape=(1, 1), coefficients={})[source]¶
Bases:
picos.expressions.expression.Expression
,abc.ABC
A multidimensional (complex) biaffine expression.
Abstract base class for the affine
ComplexAffineExpression
and its real subclassAffineExpression
. Quadratic expressions are stored inQuadraticExpression
instead.In general this expression has the form
where and are variable vectors, is a bilinear function, and are linear functions, and is a constant.
If no coefficient matrices defining and are provided on subclass instanciation, then this acts as an affine function of .
In a more technical sense, the notational variables and each represent a stack of vectorizations of a number of actual scalar, vector, or matrix variables or parameters and with and this class stores the nonzero (bi)linear functions , and in the form of separate sparse coefficient matrices.
- Htranspose()[source]¶
Return the conjugate (or Hermitian) transpose.
Deprecated since version 2.0: Use
H
instead.
- __init__(string, shape=(1, 1), coefficients={})[source]¶
Initialize a (complex) biaffine expression.
- Parameters
Warning
If the given coefficients are already of the desired (numeric) type and shape, they are stored by reference. Modifying such data can lead to unexpected results as PICOS expressions are supposed to be immutable (to allow caching of results).
If you create biaffine expressions by any other means than this constructor, PICOS makes a copy of your data to prevent future modifications to it from causing inconsistencies.
- broadcasted(shape)[source]¶
Return the expression broadcasted to the given shape.
- Example
>>> from picos import Constant >>> C = Constant("C", range(6), (2, 3)) >>> print(C) [ 0.00e+00 2.00e+00 4.00e+00] [ 1.00e+00 3.00e+00 5.00e+00] >>> print(C.broadcasted((6, 6))) [ 0.00e+00 2.00e+00 4.00e+00 0.00e+00 2.00e+00 4.00e+00] [ 1.00e+00 3.00e+00 5.00e+00 1.00e+00 3.00e+00 5.00e+00] [ 0.00e+00 2.00e+00 4.00e+00 0.00e+00 2.00e+00 4.00e+00] [ 1.00e+00 3.00e+00 5.00e+00 1.00e+00 3.00e+00 5.00e+00] [ 0.00e+00 2.00e+00 4.00e+00 0.00e+00 2.00e+00 4.00e+00] [ 1.00e+00 3.00e+00 5.00e+00 1.00e+00 3.00e+00 5.00e+00]
- copy()[source]¶
Return a deep copy of the expression.
Deprecated since version 2.0: PICOS expressions are now immutable.
- dupdiag(n)[source]¶
Return a matrix with the (repeated) expression on the diagonal.
Vectorization is performed in column-major order.
- Parameters
n (int) – Number of times to duplicate the vectorization.
- dupvec(n)[source]¶
Return a (repeated) column-major vectorization of the expression.
- Parameters
n (int) – Number of times to duplicate the vectorization.
- Returns
A column vector.
- Example
>>> from picos import Constant >>> A = Constant("A", [[1, 2], [3, 4]]) >>> A.dupvec(1) is A.vec True >>> A.dupvec(3).equals(A.vec // A.vec // A.vec) True
- equals(other, absTol=None, relTol=None)[source]¶
Check mathematical equality with another (bi)affine expression.
The precise type of both (bi)affine expressions may differ. In particular, a
ComplexAffineExpression
with real coefficients and constant term can be equal to anAffineExpression
.If the operand is not already a PICOS expression, an attempt is made to load it as a constant affine expression. In this case, no reshaping or broadcasting is used to bring the constant term to the same shape as this expression. In particular,
- Parameters
other – Another PICOS expression or a constant numeric data value supported by
load_data
.absTol – As long as all absolute differences between scalar entries of the coefficient matrices and the constant terms being compared does not exceed this bound, consider the expressions equal.
relTol – As long as all absolute differences between scalar entries of the coefficient matrices and the constant terms being compared divided by the maximum absolute value found in either term does not exceed this bound, consider the expressions equal.
- Example
>>> from picos import Constant >>> A = Constant("A", 0, (5,5)) >>> repr(A) '<5×5 Real Constant: A>' >>> A.is0 True >>> A.equals(0) False >>> A.equals("|0|(5,5)") True >>> repr(A*1j) '<5×5 Complex Constant: A·1j>' >>> A.equals(A*1j) True
- factor_out(mutable)[source]¶
Factor out a single mutable from a vector expression.
If this expression is a column vector that depends on some mutable with a trivial internal vectorization format (i.e.
FullVectorization
), then this method, called with as its argument, returns a pair of expressions such that .- Returns
Two refined
BiaffineExpression
instances that do not depend onmutable
.- Raises
TypeError – If the expression is not a column vector or if
mutable
is not aMutable
or does not have a trivial vectorization format.LookupError – If the expression does not depend on
mutable
.
- Example
>>> from picos import RealVariable >>> from picos.uncertain import UnitBallPerturbationSet >>> x = RealVariable("x", 3) >>> z = UnitBallPerturbationSet("z", 3).parameter >>> a = ((2*x + 3)^z) + 4*x + 5; a <3×1 Uncertain Affine Expression: (2·x + [3])⊙z + 4·x + [5]> >>> sorted(a.mutables, key=lambda mtb: mtb.name) [<3×1 Real Variable: x>, <3×1 Perturbation: z>] >>> az, a0 = a.factor_out(z) >>> az <3×3 Real Affine Expression: ((2·x + [3])⊙z + 4·x + [5])_z> >>> a0 <3×1 Real Affine Expression: ((2·x + [3])⊙z + 4·x + [5])_0> >>> sorted(az.mutables.union(a0.mutables), key=lambda mtb: mtb.name) [<3×1 Real Variable: x>] >>> (az*z + a0).equals(a) True
- classmethod fromMatrix(matrix, size=None)[source]¶
Create a class instance from a numeric matrix.
Deprecated since version 2.0: Use
from_constant
instead.
- classmethod fromScalar(scalar)[source]¶
Create a class instance from a numeric scalar.
Deprecated since version 2.0: Use
from_constant
instead.
- classmethod from_constant(constant, shape=None, name=None)[source]¶
Create a class instance from the given numeric constant.
Loads the given constant as a PICOS expression, optionally broadcasted or reshaped to the given shape and named as specified.
See
load_data
for supported data formats and broadcasting and reshaping rules.Unlike
Constant
, this class method always creates an instance of the class that it is called on, instead of tailoring towards the numeric type of the data.Note
When an operation involves both a PICOS expression and a constant value of another type, PICOS converts the constant on the fly so that you rarely need to use this method.
- hadamard(fact)[source]¶
Denote the elementwise (or Hadamard) product.
Deprecated since version 2.0: Use
object.__xor__
instead.
- isconstant()[source]¶
Whether the expression involves no mutables.
Deprecated since version 2.0: Use
constant
instead.
- kron(other)[source]¶
Denote the Kronecker product from the right hand side.
Deprecated since version 2.2: Use infix @ instead.
- leftkron(other)[source]¶
Denote the Kronecker product from the left hand side.
Deprecated since version 2.2: Reverse operands and use infix @ instead.
- partial_trace(subsystems, dimensions=2)[source]¶
Return the partial trace over selected subsystems.
If the expression can be written as for matrices with shapes given in
dimensions
, then this returns with , ifi in subsystems
(with read as ), and , otherwise.- Parameters
subsystems (int or tuple or list) – A collection of or a single subystem number, indexed from zero, corresponding to subsystems that shall be traced over. The value refers to the last subsystem.
dimensions (int or tuple or list) – Either an integer so that the subsystems are assumed to be all of shape , or a sequence of subsystem shapes where an integer within the sequence is read as . In any case, the elementwise product over all subsystem shapes must equal the expression’s shape.
- Raises
TypeError – If the subsystems do not match the expression or if a non-square subsystem is to be traced over.
IndexError – If the subsystem selection is invalid in any other way.
- Example
>>> from picos import Constant >>> A = Constant("A", range(16), (4, 4)) >>> print(A) [ 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] >>> A0 = A.partial_trace(0); A0 <2×2 Real Constant: A.{tr([2×2])⊗[2×2]}> >>> print(A0) [ 1.00e+01 1.80e+01] [ 1.20e+01 2.00e+01] >>> A1 = A.partial_trace(1); A1 <2×2 Real Constant: A.{[2×2]⊗tr([2×2])}> >>> print(A1) [ 5.00e+00 2.10e+01] [ 9.00e+00 2.50e+01]
- partial_transpose(subsystems, dimensions=2)[source]¶
Return the expression with selected subsystems transposed.
If the expression can be written as for matrices with shapes given in
dimensions
, then this returns with , ifi in subsystems
(with read as ), and , otherwise.- Parameters
subsystems (int or tuple or list) – A collection of or a single subystem number, indexed from zero, corresponding to subsystems that shall be transposed. The value refers to the last subsystem.
dimensions (int or tuple or list) – Either an integer so that the subsystems are assumed to be all of shape , or a sequence of subsystem shapes where an integer within the sequence is read as . In any case, the elementwise product over all subsystem shapes must equal the expression’s shape.
- Raises
TypeError – If the subsystems do not match the expression.
IndexError – If the subsystem selection is invalid.
- Example
>>> from picos import Constant >>> A = Constant("A", range(16), (4, 4)) >>> print(A) [ 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] >>> A0 = A.partial_transpose(0); A0 <4×4 Real Constant: A.{[2×2]ᵀ⊗[2×2]}> >>> print(A0) [ 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] >>> A1 = A.partial_transpose(1); A1 <4×4 Real Constant: A.{[2×2]⊗[2×2]ᵀ}> >>> print(A1) [ 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]
- reshaped(shape, order='F')[source]¶
Return the expression reshaped in the given order.
The default indexing order is column-major. Given an matrix, reshaping in the default order is a constant time operation while reshaping in row-major order requires time. However, the latter allows you to be consistent with NumPy, which uses C-order (a generalization of row-major) by default.
- Parameters
order (str) – The indexing order to use when reshaping. Must be either
"F"
for Fortran-order (column-major) or"C"
for C-order (row-major).- Example
>>> from picos import Constant >>> C = Constant("C", range(6), (2, 3)) >>> print(C) [ 0.00e+00 2.00e+00 4.00e+00] [ 1.00e+00 3.00e+00 5.00e+00] >>> print(C.reshaped((3, 2))) [ 0.00e+00 3.00e+00] [ 1.00e+00 4.00e+00] [ 2.00e+00 5.00e+00] >>> print(C.reshaped((3, 2), order="C")) [ 0.00e+00 2.00e+00] [ 4.00e+00 1.00e+00] [ 3.00e+00 5.00e+00]
- reshaped_or_broadcasted(shape)[source]¶
Return the expression
reshaped
orbroadcasted
.Unlike with
reshaped
andbroadcasted
, the target shape may not contain a wildcard character.If the wildcard-free target shape has the same number of elements as the current shape, then this is the same as
reshaped
, otherwise it is the same asbroadcasted
.
- reshuffled(permutation='ikjl', dimensions=None, order='C')[source]¶
Return the reshuffled or realigned expression.
This operation works directly on matrices. However, it is equivalent to the following sequence of operations:
The matrix is reshaped to a tensor with the given
dimensions
and according toorder
.The tensor’s axes are permuted according to
permutation
.The tensor is reshaped back to the shape of the original matrix according to
order
.
For comparison, the following function applies the same operation to a 2D NumPy
ndarray
:def reshuffle_numpy(matrix, permutation, dimensions, order): P = "{} -> {}".format("".join(sorted(permutation)), permutation) reshuffled = numpy.reshape(matrix, dimensions, order) reshuffled = numpy.einsum(P, reshuffled) return numpy.reshape(reshuffled, matrix.shape, order)
- Parameters
permutation (str or tuple or list) – A sequence of comparable elements with length equal to the number of tensor dimensions. The sequence is compared to its ordered version and the resulting permutation pattern is used to permute the tensor indices. For instance, the string
"ikjl"
is compared to its sorted version"ijkl"
and denotes that the second and third axis should be swapped.dimensions (None or tuple or list) – If this is an integer sequence, then it defines the dimensions of the tensor. If this is
None
, then the tensor is assumed to be hypercubic and the number of dimensions is inferred from thepermutation
argument.order (str) – The indexing order to use for the virtual reshaping. Must be either
"F"
for Fortran-order (generalization of column-major) or"C"
for C-order (generalization of row-major). Note that PICOS usually reshapes in Fortran-order while NumPy defaults to C-order.
- Example
>>> from picos import Constant >>> A = Constant("A", range(16), (4, 4)) >>> print(A) [ 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] >>> R = A.reshuffled(); R <4×4 Real Constant: shuffled(A,ikjl,C)> >>> print(R) [ 0.00e+00 4.00e+00 1.00e+00 5.00e+00] [ 8.00e+00 1.20e+01 9.00e+00 1.30e+01] [ 2.00e+00 6.00e+00 3.00e+00 7.00e+00] [ 1.00e+01 1.40e+01 1.10e+01 1.50e+01] >>> A.reshuffled("ji").equals(A.T) # Regular transposition. True >>> A.reshuffled("3214").equals(A.T0) # Partial transposition (1). True >>> A.reshuffled("1432").equals(A.T1) # Partial transposition (2). True
- same_as(other)[source]¶
Check mathematical equality with another affine expression.
Deprecated since version 2.0: Use
equals
instead.
- soft_copy()[source]¶
Return a shallow copy of the expression.
Deprecated since version 2.0: PICOS expressions are now immutable.
- property T0[source]¶
Expression with the first subsystem transposed.
Only available for a matrix with all subsystems of shape . Use
partial_transpose
otherwise.
- property T1[source]¶
Expression with the second subsystem transposed.
Only available for a matrix with all subsystems of shape . Use
partial_transpose
otherwise.
- property T2[source]¶
Expression with the third subsystem transposed.
Only available for a matrix with all subsystems of shape . Use
partial_transpose
otherwise.
- property T3[source]¶
Expression with the fourth subsystem transposed.
Only available for a matrix with all subsystems of shape . Use
partial_transpose
otherwise.
- property Tl[source]¶
Expression with the last subsystem transposed.
Only available for a matrix with all subsystems of shape . Use
partial_transpose
otherwise.
- property Tx[source]¶
Auto-detect few subsystems of same shape and transpose the last.
Deprecated since version 2.0: Use
partial_transpose
instead.
- property desvec[source]¶
The reverse operation of
svec
.- Raises
If the expression is not a vector or has a dimension outside the permissible set
ValueError – In the case of a complex vector, If the vector is not in the image of
svec
.
- property diag[source]¶
Diagonal matrix with the expression on the main diagonal.
Vectorization is performed in column-major order.
- property hermitian[source]¶
Whether the expression is a hermitian (or symmetric) matrix.
Uses
RELATIVE_HERMITIANNESS_TOLERANCE
.If PICOS rejects your near-hermitian (near-symmetric) expression as not hermitian (not symmetric), you can use
hermitianized
to correct larger numeric errors or the effects of noisy data.
- property hermitianized[source]¶
The expression projected onto the subspace of hermitian matrices.
For a square (complex) affine expression , this is .
If the expression is not complex, then this is a projection onto the subspace of symmetric matrices.
- property is0¶
Whether this is a constant scalar, vector or matrix of all zeros.
- property isreal¶
Whether the expression is always real-valued.
- property svec[source]¶
An isometric vectorization of a symmetric or hermitian expression.
In the real symmetric case
the vectorization format is precisely the one define in [svec],
the vectorization is isometric and isomorphic, and
this is the same vectorization as used internally by the
SymmetricVariable
class.
In the complex hermitian case
the same format is used, now resulting in a complex vector,
the vectorization is isometric but not isomorphic as there are guaranteed zeros in the imaginary part of the vector, and
this is not the same vectorization as the isomorphic, real-valued one used by
HermitianVariable
.
The reverse operation is denoted by
desvec
in either case.- Raises
TypeError – If the expression is not square.
ValueError – If the expression is not hermitian.
- property tr0[source]¶
Expression with the first subsystem traced out.
Only available for a matrix with all subsystems of shape . Use
partial_trace
otherwise.
- property tr1[source]¶
Expression with the second subsystem traced out.
Only available for a matrix with all subsystems of shape . Use
partial_trace
otherwise.
- property tr2[source]¶
Expression with the third subsystem traced out.
Only available for a matrix with all subsystems of shape . Use
partial_trace
otherwise.
- property tr3[source]¶
Expression with the fourth subsystem traced out.
Only available for a matrix with all subsystems of shape . Use
partial_trace
otherwise.
- property trilvec[source]¶
Column-major vectorization of the lower triangular part.
- Returns
A column vector of all elements that satisfy .
Note
If you want a row-major vectorization instead, write
A.T.triuvec
instead ofA.trilvec
.- Example
>>> from picos import Constant >>> A = Constant("A", [[1, 2], [3, 4], [5, 6]]) >>> print(A) [ 1.00e+00 2.00e+00] [ 3.00e+00 4.00e+00] [ 5.00e+00 6.00e+00] >>> print(A.trilvec) [ 1.00e+00] [ 3.00e+00] [ 5.00e+00] [ 4.00e+00] [ 6.00e+00]
- property triuvec[source]¶
Column-major vectorization of the upper triangular part.
- Returns
A column vector of all elements that satisfy .
Note
If you want a row-major vectorization instead, write
A.T.trilvec
instead ofA.triuvec
.- Example
>>> from picos import Constant >>> A = Constant("A", [[1, 2, 3], [4, 5, 6]]) >>> print(A) [ 1.00e+00 2.00e+00 3.00e+00] [ 4.00e+00 5.00e+00 6.00e+00] >>> print(A.triuvec) [ 1.00e+00] [ 2.00e+00] [ 5.00e+00] [ 3.00e+00] [ 6.00e+00]
- property trl[source]¶
Expression with the last subsystem traced out.
Only available for a matrix with all subsystems of shape . Use
partial_trace
otherwise.
- property vec[source]¶
Column-major vectorization of the expression as a column vector.
Note
Given an expression
A
,A.vec
andA[:]
produce the same result (up to its string description) butA.vec
is faster and its result is cached.- Example
>>> from picos import Constant >>> A = Constant("A", [[1, 2], [3, 4]]) >>> A.vec.equals(A[:]) True >>> A[:] is A[:] False >>> A.vec is A.vec True