Help protect the Great Barrier Reef with TensorFlow on Kaggle Join Challenge

tf.linalg.LinearOperatorBlockLowerTriangular

Combines LinearOperators into a blockwise lower-triangular matrix.

Inherits From: LinearOperator, Module

This operator is initialized with a nested list of linear operators, which are combined into a new LinearOperator whose underlying matrix representation is square and has each operator on or below the main diagonal, and zero's elsewhere. Each element of the outer list is a list of LinearOperators corresponding to a row-partition of the blockwise structure. The number of LinearOperators in row-partion i must be equal to i.

For example, a blockwise 3 x 3 LinearOperatorBlockLowerTriangular is initialized with the list [[op_00], [op_10, op_11], [op_20, op_21, op_22]], where the op_ij, i < 3, j <= i, are LinearOperator instances. The LinearOperatorBlockLowerTriangular behaves as the following blockwise matrix, where 0 represents appropriately-sized [batch] matrices of zeros:

[[op_00,     0,     0],
 [op_10, op_11,     0],
 [op_20, op_21, op_22]]

Each op_jj on the diagonal is required to represent a square matrix, and hence will have shape batch_shape_j + [M_j, M_j]. LinearOperators in row j of the blockwise structure must have range_dimension equal to that of op_jj, and LinearOperators in column j must have domain_dimension equal to that of op_jj.

If each op_jj on the diagonal has shape batch_shape_j + [M_j, M_j], then the combined operator has shape broadcast_batch_shape + [sum M_j, sum M_j], where broadcast_batch_shape is the mutual broadcast of batch_shape_j, j = 0, 1, ..., J, assuming the intermediate batch shapes broadcast. Even if the combined shape is well defined, the combined operator's methods may fail due to lack of broadcasting ability in the defining operators' methods.

For example, to create a 4 x 4 linear operator combined of three 2 x 2 operators:

>>> operator_0 = tf.linalg.LinearOperatorFullMatrix([[1., 2.], [3., 4.]])
>>> operator_1 = tf.linalg.LinearOperatorFullMatrix([[1., 0.], [0., 1.]])
>>> operator_2 = tf.linalg.LinearOperatorLowerTriangular([[5., 6.], [7., 8]])
>>> operator = LinearOperatorBlockLowerTriangular(
...   [[operator_0], [operator_1, operator_2]])
operator.to_dense()
<tf.Tensor: shape=(4, 4), dtype=float32, numpy=
array([[1., 2., 0., 0.],
       [3., 4., 0., 0.],
       [1., 0., 5., 0.],
       [0., 1., 7., 8.]], dtype=float32)>
operator.shape
TensorShape([4, 4])
operator.log_abs_determinant()
<tf.Tensor: shape=(), dtype=float32, numpy=4.3820267>
x0 = [[1., 6.], [-3., 4.]]
x1 = [[0., 2.], [4., 0.]]
x = tf.concat([x0, x1], 0)  # Shape [2, 4] Tensor
operator.matmul(x)
<tf.Tensor: shape=(4, 2), dtype=float32, numpy=
array([[-5., 14.],
       [-9., 34.],
       [ 1., 16.],
       [29., 18.]], dtype=float32)>

The above matmul is equivalent to:

>>> tf.concat([operator_0.matmul(x0),
...   operator_1.matmul(x0) + operator_2.matmul(x1)], axis=0)
<tf.Tensor: shape=(4, 2), dtype=float32, numpy=
array([[-5., 14.],
       [-9., 34.],
       [ 1., 16.],
       [29., 18.]], dtype=float32)>

Shape compatibility

This operator acts on [batch] matrix with compatible shape. x is a batch matrix with compatible shape for matmul and solve if

operator.shape = [B1,...,Bb] + [M, N],  with b >= 0
x.shape =        [B1,...,Bb] + [N, R],  with R >= 0.

For example:

Create a [2, 3] batch of 4 x 4 linear operators:

>>> matrix_44 = tf.random.normal(shape=[2, 3, 4, 4])
>>> operator_44 = tf.linalg.LinearOperatorFullMatrix(matrix_44)

Create a [1, 3] batch of 5 x 4 linear operators:

>>> matrix_54 = tf.random.normal(shape=[1, 3, 5, 4])
>>> operator_54 = tf.linalg.LinearOperatorFullMatrix(matrix_54)

Create a [1, 3] batch of 5 x 5 linear operators:

>>> matrix_55 = tf.random.normal(shape=[1, 3, 5, 5])
>>> operator_55 = tf.linalg.LinearOperatorFullMatrix(matrix_55)

Combine to create a [2, 3] batch of 9 x 9 operators:

>>> operator_99 = LinearOperatorBlockLowerTriangular(
...   [[operator_44], [operator_54, operator_55]])
>>> operator_99.shape
TensorShape([2, 3, 9, 9])

Create a shape [2, 1, 9] batch of vectors and apply the operator to it.

>>> x = tf.random.normal(shape=[2, 1, 9])
>>> y = operator_99.matvec(x)
>>> y.shape
TensorShape([2, 3, 9])

Create a blockwise list of vectors and apply the operator to it. A blockwise list is returned.

>>> x4 = tf.random.normal(shape=[2, 1, 4])
>>> x5 = tf.random.normal(shape=[2, 3, 5])
>>> y_blockwise = operator_99.matvec([x4, x5])
>>> y_blockwise[0].shape
TensorShape([2, 3, 4])
>>> y_blockwise[1].shape
TensorShape([2, 3, 5])

Performance

Suppose operator is a LinearOperatorBlockLowerTriangular consisting of D row-partitions and