Help protect the Great Barrier Reef with TensorFlow on Kaggle

# tf.linalg.LinearOperatorBlockLowerTriangular

Combines `LinearOperators` into a blockwise lower-triangular matrix.

Inherits From: `LinearOperator`

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 `LinearOperator`s 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]`. `LinearOperator`s 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)

#### 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 `D` column-partitions, such that the total number of operators is `N = D * (D + 1) // 2`.

• `operator.matmul` has complexity equal to the sum of the `matmul` complexities of the individual operators.
• `operator.solve` has complexity equal to the sum of the `solve` complexities of the operators on the diagonal and the `matmul` complexities of the operators off the diagonal.
• `operator.determinant` has complexity equal to the sum of the `determinant` complexities of the operators on the diagonal.

#### Matrix property hints

This `LinearOperator` is initialized with boolean flags of the form `is_X`, for `X = non_singular, self_adjoint, positive_definite,`