Matrix/Vector-Valued Linear Functions: Parents#

In Sage, matrices assume that the base is a ring. Hence, we cannot construct matrices whose entries are linear functions in Sage. Really, they should be thought of as the tensor product of the \(R\)-module of linear functions and the \(R\)-vector/matrix space, with the latter viewed as an \(R\)-module (\(R\) is usually QQ or RDF for our purposes).

You should not construct any tensor products by calling the parent directly. This is also why none of the classes are imported in the global namespace. The come into play whenever you have vector or matrix MIP linear expressions/constraints. The intended way to construct them is implicitly by acting with vectors or matrices on linear functions. For example:

sage: mip.<x> = MixedIntegerLinearProgram('ppl')   # base ring is QQ
sage: 3 + x[0] + 2*x[1]            # a linear function
3 + x_0 + 2*x_1
sage: x[0] * vector([3,4]) + 1     # vector linear function
(1, 1) + (3, 4)*x_0
sage: x[0] * matrix([[3,1],[4,0]]) + 1   # matrix linear function
[1 + 3*x_0 x_0]
[4*x_0     1  ]
>>> from sage.all import *
>>> mip = MixedIntegerLinearProgram('ppl', names=('x',)); (x,) = mip._first_ngens(1)# base ring is QQ
>>> Integer(3) + x[Integer(0)] + Integer(2)*x[Integer(1)]            # a linear function
3 + x_0 + 2*x_1
>>> x[Integer(0)] * vector([Integer(3),Integer(4)]) + Integer(1)     # vector linear function
(1, 1) + (3, 4)*x_0
>>> x[Integer(0)] * matrix([[Integer(3),Integer(1)],[Integer(4),Integer(0)]]) + Integer(1)   # matrix linear function
[1 + 3*x_0 x_0]
[4*x_0     1  ]

Internally, all linear functions are stored as a dictionary whose

  • keys are the index of the linear variable (and -1 for the constant term)

  • values are the coefficient of that variable. That is, a number for linear functions, a vector for vector-valued functions, etc.

The entire dictionary can be accessed with the dict() method. For convenience, you can also retrieve a single coefficient with coefficient(). For example:

sage: mip.<b> = MixedIntegerLinearProgram()
sage: f_scalar = (3 + b[7] + 2*b[9]);  f_scalar
3 + x_0 + 2*x_1
sage: f_scalar.dict()
{-1: 3.0, 0: 1.0, 1: 2.0}
sage: f_scalar.dict()[1]
2.0
sage: f_scalar.coefficient(b[9])
2.0
sage: f_scalar.coefficient(1)
2.0

sage: f_vector = b[7] * vector([3,4]) + 1;  f_vector
(1.0, 1.0) + (3.0, 4.0)*x_0
sage: f_vector.coefficient(-1)
(1.0, 1.0)
sage: f_vector.coefficient(b[7])
(3.0, 4.0)
sage: f_vector.coefficient(0)
(3.0, 4.0)
sage: f_vector.coefficient(1)
(0.0, 0.0)

sage: f_matrix = b[7] * matrix([[0,1], [2,0]]) + b[9] - 3;  f_matrix
[-3 + x_1 x_0     ]
[2*x_0    -3 + x_1]
sage: f_matrix.coefficient(-1)
[-3.0  0.0]
[ 0.0 -3.0]
sage: f_matrix.coefficient(0)
[0.0 1.0]
[2.0 0.0]
sage: f_matrix.coefficient(1)
[1.0 0.0]
[0.0 1.0]
>>> from sage.all import *
>>> mip = MixedIntegerLinearProgram(names=('b',)); (b,) = mip._first_ngens(1)
>>> f_scalar = (Integer(3) + b[Integer(7)] + Integer(2)*b[Integer(9)]);  f_scalar
3 + x_0 + 2*x_1
>>> f_scalar.dict()
{-1: 3.0, 0: 1.0, 1: 2.0}
>>> f_scalar.dict()[Integer(1)]
2.0
>>> f_scalar.coefficient(b[Integer(9)])
2.0
>>> f_scalar.coefficient(Integer(1))
2.0

>>> f_vector = b[Integer(7)] * vector([Integer(3),Integer(4)]) + Integer(1);  f_vector
(1.0, 1.0) + (3.0, 4.0)*x_0
>>> f_vector.coefficient(-Integer(1))
(1.0, 1.0)
>>> f_vector.coefficient(b[Integer(7)])
(3.0, 4.0)
>>> f_vector.coefficient(Integer(0))
(3.0, 4.0)
>>> f_vector.coefficient(Integer(1))
(0.0, 0.0)

>>> f_matrix = b[Integer(7)] * matrix([[Integer(0),Integer(1)], [Integer(2),Integer(0)]]) + b[Integer(9)] - Integer(3);  f_matrix
[-3 + x_1 x_0     ]
[2*x_0    -3 + x_1]
>>> f_matrix.coefficient(-Integer(1))
[-3.0  0.0]
[ 0.0 -3.0]
>>> f_matrix.coefficient(Integer(0))
[0.0 1.0]
[2.0 0.0]
>>> f_matrix.coefficient(Integer(1))
[1.0 0.0]
[0.0 1.0]

Just like sage.numerical.linear_functions, (in)equalities become symbolic inequalities. See linear_tensor_constraints for details.

Note

For brevity, we just use LinearTensor in class names. It is understood that this refers to the above tensor product construction.

sage.numerical.linear_tensor.LinearTensorParent(linear_functions_parent)[source]#

Return the parent for the tensor product over the common base_ring.

The output is cached, so only a single parent is ever constructed for a given base ring.

INPUT:

  • free_module_parent – module. A free module, like vector or matrix space.

  • linear_functions_parent – linear functions. The linear functions parent.

OUTPUT:

The parent of the tensor product of a free module and linear functions over a common base ring.

EXAMPLES:

sage: from sage.numerical.linear_functions import LinearFunctionsParent
sage: from sage.numerical.linear_tensor import LinearTensorParent
sage: LinearTensorParent(QQ^3, LinearFunctionsParent(QQ))
Tensor product of Vector space of dimension 3 over Rational Field and Linear functions over Rational Field

sage: LinearTensorParent(ZZ^3, LinearFunctionsParent(QQ))
Traceback (most recent call last):
...
ValueError: base rings must match
>>> from sage.all import *
>>> from sage.numerical.linear_functions import LinearFunctionsParent
>>> from sage.numerical.linear_tensor import LinearTensorParent
>>> LinearTensorParent(QQ**Integer(3), LinearFunctionsParent(QQ))
Tensor product of Vector space of dimension 3 over Rational Field and Linear functions over Rational Field

>>> LinearTensorParent(ZZ**Integer(3), LinearFunctionsParent(QQ))
Traceback (most recent call last):
...
ValueError: base rings must match
class sage.numerical.linear_tensor.LinearTensorParent_class(free_module, linear_functions)[source]#

Bases: Parent

The parent for all linear functions over a fixed base ring.

Warning

You should use LinearTensorParent() to construct instances of this class.

INPUT/OUTPUT:

See LinearTensorParent()

EXAMPLES:

sage: from sage.numerical.linear_tensor import LinearTensorParent_class
sage: LinearTensorParent_class
<class 'sage.numerical.linear_tensor.LinearTensorParent_class'>
>>> from sage.all import *
>>> from sage.numerical.linear_tensor import LinearTensorParent_class
>>> LinearTensorParent_class
<class 'sage.numerical.linear_tensor.LinearTensorParent_class'>
Element[source]#

alias of LinearTensor

free_module()[source]#

Return the linear functions.

See also free_module().

OUTPUT:

Parent of the linear functions, one of the factors in the tensor product construction.

EXAMPLES:

sage: mip.<x> = MixedIntegerLinearProgram()
sage: lt = x[0] * vector(RDF, [1,2])
sage: lt.parent().free_module()
Vector space of dimension 2 over Real Double Field
sage: lt.parent().free_module() is vector(RDF, [1,2]).parent()
True
>>> from sage.all import *
>>> mip = MixedIntegerLinearProgram(names=('x',)); (x,) = mip._first_ngens(1)
>>> lt = x[Integer(0)] * vector(RDF, [Integer(1),Integer(2)])
>>> lt.parent().free_module()
Vector space of dimension 2 over Real Double Field
>>> lt.parent().free_module() is vector(RDF, [Integer(1),Integer(2)]).parent()
True
is_matrix_space()[source]#

Return whether the free module is a matrix space.

OUTPUT:

Boolean. Whether the free_module() factor in the tensor product is a matrix space.

EXAMPLES:

sage: mip = MixedIntegerLinearProgram()
sage: LF = mip.linear_functions_parent()
sage: LF.tensor(RDF^2).is_matrix_space()
False
sage: LF.tensor(RDF^(2,2)).is_matrix_space()
True
>>> from sage.all import *
>>> mip = MixedIntegerLinearProgram()
>>> LF = mip.linear_functions_parent()
>>> LF.tensor(RDF**Integer(2)).is_matrix_space()
False
>>> LF.tensor(RDF**(Integer(2),Integer(2))).is_matrix_space()
True
is_vector_space()[source]#

Return whether the free module is a vector space.

OUTPUT:

Boolean. Whether the free_module() factor in the tensor product is a vector space.

EXAMPLES:

sage: mip = MixedIntegerLinearProgram()
sage: LF = mip.linear_functions_parent()
sage: LF.tensor(RDF^2).is_vector_space()
True
sage: LF.tensor(RDF^(2,2)).is_vector_space()
False
>>> from sage.all import *
>>> mip = MixedIntegerLinearProgram()
>>> LF = mip.linear_functions_parent()
>>> LF.tensor(RDF**Integer(2)).is_vector_space()
True
>>> LF.tensor(RDF**(Integer(2),Integer(2))).is_vector_space()
False
linear_functions()[source]#

Return the linear functions.

See also free_module().

OUTPUT:

Parent of the linear functions, one of the factors in the tensor product construction.

EXAMPLES:

sage: mip.<x> = MixedIntegerLinearProgram()
sage: lt = x[0] * vector([1,2])
sage: lt.parent().linear_functions()
Linear functions over Real Double Field
sage: lt.parent().linear_functions() is mip.linear_functions_parent()
True
>>> from sage.all import *
>>> mip = MixedIntegerLinearProgram(names=('x',)); (x,) = mip._first_ngens(1)
>>> lt = x[Integer(0)] * vector([Integer(1),Integer(2)])
>>> lt.parent().linear_functions()
Linear functions over Real Double Field
>>> lt.parent().linear_functions() is mip.linear_functions_parent()
True
sage.numerical.linear_tensor.is_LinearTensor(x)[source]#

Test whether x is a tensor product of linear functions with a free module.

INPUT:

  • x – anything.

OUTPUT:

Boolean.

EXAMPLES:

sage: p = MixedIntegerLinearProgram()
sage: x = p.new_variable(nonnegative=False)
sage: from sage.numerical.linear_tensor import is_LinearTensor
sage: is_LinearTensor(x[0] - 2*x[2])
doctest:warning...
DeprecationWarning: The function is_LinearTensor is deprecated;
use 'isinstance(..., LinearTensor)' instead.
See https://github.com/sagemath/sage/issues/38184 for details.
False
sage: is_LinearTensor('a string')
False
>>> from sage.all import *
>>> p = MixedIntegerLinearProgram()
>>> x = p.new_variable(nonnegative=False)
>>> from sage.numerical.linear_tensor import is_LinearTensor
>>> is_LinearTensor(x[Integer(0)] - Integer(2)*x[Integer(2)])
doctest:warning...
DeprecationWarning: The function is_LinearTensor is deprecated;
use 'isinstance(..., LinearTensor)' instead.
See https://github.com/sagemath/sage/issues/38184 for details.
False
>>> is_LinearTensor('a string')
False