class_docstr: Combines `LinearOperators` into a blockwise lower-triangular matrix.
  
  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:
  
  ```none
  [[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)
  <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 `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, square`.
  These have the following meaning:
  
  * If `is_X == True`, callers should expect the operator to have the
    property `X`.  This is a promise that should be fulfilled, but is *not* a
    runtime assert.  For example, finite floating point precision may result
    in these promises being violated.
  * If `is_X == False`, callers should expect the operator to not have `X`.
  * If `is_X == None` (the default), callers should have no expectation either
    way.
class_docstr_tok: ["Combines","`","LinearOperators","`","into","a","blockwise","lower-triangular","matrix",".","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",":","``","`","none","[","[","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",")","<","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","`","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",",","square","`",".","These","have","the","following","meaning",":","*","If","`","is_X","==","True","`",",","callers","should","expect","the","operator","to","have","the","property","`","X","`",".","This","is","a","promise","that","should","be","fulfilled",",","but","is","*","not","*","a","runtime","assert",".","For","example",",","finite","floating","point","precision","may","result","in","these","promises","being","violated",".","*","If","`","is_X","==","False","`",",","callers","should","expect","the","operator","to","not","have","`","X","`",".","*","If","`","is_X","==","None","`","(","the","default",")",",","callers","should","have","no","expectation","either","way","."]
code: def _validate_dtype(self, dtype):
      for i, row in enumerate(self.operators):
          for operator in row:
              if operator.dtype != dtype:
                  name_type = (str((o.name, o.dtype)) for o in row)
                  raise TypeError(
                      "Expected all operators to have the same dtype.  Found {} in row "
                      "{} and {} in row 0.".format(
                          name_type, i, str(dtype)
                      )
                  )
  
imports: from tensorflow.python.framework import common_shapes
  from tensorflow.python.framework import dtypes
  from tensorflow.python.framework import ops
  from tensorflow.python.framework import tensor_conversion
  from tensorflow.python.framework import tensor_shape
  from tensorflow.python.ops import array_ops
  from tensorflow.python.ops import array_ops_stack
  from tensorflow.python.ops import check_ops
  from tensorflow.python.ops import control_flow_ops
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops.linalg import linalg_impl
  from tensorflow.python.ops.linalg import linear_operator
  from tensorflow.python.ops.linalg import linear_operator_addition
  from tensorflow.python.ops.linalg import linear_operator_full_matrix
  from tensorflow.python.ops.linalg import linear_operator_identity
  from tensorflow.python.ops.linalg import linear_operator_util
  from tensorflow.python.util import nest
  from tensorflow.python.util.tf_export import tf_export
label_desc: Use image node_id 6 for calling the LinearOperatorBlockLowerTriangular obj's underlying member method code with example usage: obj._validate_dtype(dtype) without return types