Python API - MLinExpr#

class MLinExpr#

Gurobi linear matrix expression object. A linear matrix expression results from an arithmetic operation with an MVar object. A common example is a matrix-vector product, where the matrix is a NumPy ndarray or a SciPy sparse matrix and the vector is a Gurobi MVar object. Linear matrix expressions are used to build linear objectives and constraints. They are temporary objects that typically have short lifespans.

You generally build linear matrix expressions using overloaded operators, typically by multiplying a 2-D matrix (dense or sparse) by a 1-D MVar object using the Python matrix multiply (@) operator (e.g., expr = A @ x). You can also promote an MVar object to an MLinExpr using arithmetic expressions (e.g., expr = x + 1). Most arithmetic operations are supported on MLinExpr objects, including addition and subtraction (e.g., expr = A @ x - B @ y), multiplication by a constant (e.g. expr = 2 * A @ x), and point-wise multiplication with an ndarray or a sparse matrix. An MLinExpr object containing empty expressions can be created using the zeros method.

An MLinExpr object has a shape representing its dimensions, a size that counts the total number of elements, and an ndim that gives the number of dimensions. These properties lean on their counterparts in NumPy’s ndarray class.

When working with MLinExpr objects, you need to make sure that the operands’ shapes are compatible. For matrix multiplication, we follow the rules of Python’s matrix multiplication operator: both operands need to have at least one dimension, and their inner dimensions must agree. For more information we refer you to Python’s documentation. Other binary operations such as addition and multiplication are straightforward to understand if both operands have the same shape: the operation is applied point wise on the matching indices. For operands that have different shapes, the arithmetic follows NumPy’s broadcasting rules. We refer you to the NumPy documentation for more information.

The full list of overloaded operators on MLinExpr objects is as follows: +, +=, -, -=, *, *=, and @. In Python parlance, we’ve defined the following MLinExpr functions: __add__, __radd__, __iadd__, __sub__, __rsub__, __isub__, __neg__, __mul__, __rmul__, __imul__, __matmul__, and __rmatmul__.

We’ve also overloaded the comparison operators (==, <=, and >=), to make it easier to build constraints from linear matrix expressions.

clear()#

Reset this expression to all zeros.

Example:
expr = 2 * model.addMVar(3) + 1
expr.clear()  # All three entries are reset to constant 0.0
copy()#

Create a copy of a linear matrix expression.

Returns:

Copy of expression object.

Example:
orig = 2 * model.addMVar(3) + 1.0
copy = orig.copy()
copy += 2.0  # Leaves 'orig' untouched
getValue()#

Compute the value of a linear matrix expression using the current solution.

Returns:

Value of expression as an ndarray.

Example:
expr = A @ x + b
model.addConstr(expr == 0)
model.optimize()
val = expr.getValue()
item()#

For an MLinExpr that contains a single element, returns a copy of that element as a LinExpr object. Calling this method on an MLinExpr with more than one element will raise a ValueError.

Returns:

An LinExpr object

Example:
mle = 2 * model.addMVar((2, 2)) + 1
mle_sub = mle[0, 1]  # A 0-D MLinExpr encapsulating one LinExpr object
mle_le = mle[0, 1].item()  # A copy of the resident LinExpr object
property ndim#

The number of dimensions in this expression.

Returns:

An int

Example:
expr1 = 2 * model.addMVar((3,)) + 1
print(expr1.ndim)  #  "1"
expr2 =  2 * model.addMVar((1, 3)) + 1
print(expr2.ndim)  #  "2"
property shape#

The shape of this expression.

Returns:

A tuple of int

Example:
expr1 = 2 * model.addMVar((3,)) + 1
print(expr1.shape)  #  "(3,)"
expr2 = 2 * model.addMVar((1, 3)) + 1
print(expr2.shape)  #  "(1, 3)"
property size#

The total number of elements in this expression.

Returns:

An int

Example:
expr1 = 2 * model.addMVar((3,)) + 1
print(expr1.size)  #  "3"
expr2 = 2 * model.addMVar((2, 3)) + 1
print(expr2.size)  #  "6"
sum(axis=None)#

Sum the elements of this MLinExpr; returns an MLinExpr object.

Parameters:

axis – An int, or None. Sum along the specified axis. If set to None, summation takes place along all axes of this MLinExpr.

Returns:

An MLinExpr representing the sum.

Example:
expr = 2 * model.addMVar((2, 2)) - 1
sum_row = expr.sum(axis=0)  # Sum along the rows
sum_col = expr.sum(axis=1)  # Sum along the columns
sum_all = expr.sum()  # Sum all elements, result is 0-D
zeros(shape)#

Construct an all-zero MLinExpr object of the given shape.

Parameters:

shape – An int, or tuple of int. The requested shape.

Returns:

An MLinExpr, initialized to zero.

Example:
mle = gp.MLinExpr.zeros(3)
x = model.addMVar(3)
mle += 2 * x
__eq__()#

Overloads the == operator, creating a TempConstr object that captures an array of equality constraints. The result is typically immediately passed to Model.addConstr.

Returns:

A TempConstr object.

Example:
m.addConstr(A @ x == 1)
__ge__(arg)#

Overloads the >= operator, creating a TempConstr object that captures an array of inequality constraints. The result is typically immediately passed to Model.addConstr.

Returns:

A TempConstr object.

Example:
m.addConstr(A @ x >= 1)
__getitem__()#

Index or slice this MLinExpr.

Returns:

An MLinExpr object.

Example:
mle = 2 * m.addMVar((2,2))
col0 = mle[:, 0]  # The first column of mle, 1-D result
elmt = mle[1, 0]  # The element at position (1, 0), 0-D result

You can index and slice MLinExpr objects like you would index NumPy’s ndarray, and indexing behavior is straightforward to understand if you only read from the returned object. When you write to the returned object, be aware that some kinds of indexing return NumPy views on the indexed expression (e.g., slices), while others result in copies being returned (e.g., fancy indexing). Here is an example:

Example:
mle = 2 * m.addMVar(4)
leading_part_1 = mle[:2]
leading_part_2 = mle[[0,1]]
leading_part_1 += 99  # This modifies mle, too
leading_part_2 += 1  # This doesn't modify mle

If you are unsure about any of these concepts and want to avoid any risk of accidentally writing back to the indexed object, you should always combine indexing with the copy method.

Example:
expr = 2 * model.addMVar((2,2)) + 1
first_col = expr[:, 0].copy()
first_col =+ 1  # Leaves expr untouched
__le__()#

Overloads the <= operator, creating a TempConstr object that captures an array of inequality constraints. The result is typically immediately passed to Model.addConstr.

Returns:

A TempConstr object.

Example:
m.addConstr(A @ x <= 1)
__setitem__()#

Assign into this MLinExpr.

Example:
mle = 2 * model.addMVar((2,2))
v = model.addVar()
w = model.addVar()
mle[:] = v + 1  # Overwrite mle with four independent copies of 'v+1'
mle[1, 1] = w  # Overwrite the entry at position (1, 1) of mle with 'w'

Note that assignment into an existing MLinExpr always entails multiple data copies and is less efficient than building matrix expressions through operations with MVar objects.