class_docstr: Perturb a `LinearOperator` with a rank `K` update.
  
  This operator acts like a [batch] matrix `A` with shape
  `[B1,...,Bb, M, N]` for some `b >= 0`.  The first `b` indices index a
  batch member.  For every batch index `(i1,...,ib)`, `A[i1,...,ib, : :]` is
  an `M x N` matrix.
  
  `LinearOperatorLowRankUpdate` represents `A = L + U D V^H`, where
  
  ```
  L, is a LinearOperator representing [batch] M x N matrices
  U, is a [batch] M x K matrix.  Typically K << M.
  D, is a [batch] K x K matrix.
  V, is a [batch] N x K matrix.  Typically K << N.
  V^H is the Hermitian transpose (adjoint) of V.
  ```
  
  If `M = N`, determinants and solves are done using the matrix determinant
  lemma and Woodbury identities, and thus require L and D to be non-singular.
  
  Solves and determinants will be attempted unless the "is_non_singular"
  property of L and D is False.
  
  In the event that L and D are positive-definite, and U = V, solves and
  determinants can be done using a Cholesky factorization.
  
  ```python
  # Create a 3 x 3 diagonal linear operator.
  diag_operator = LinearOperatorDiag(
      diag_update=[1., 2., 3.], is_non_singular=True, is_self_adjoint=True,
      is_positive_definite=True)
  
  # Perturb with a rank 2 perturbation
  operator = LinearOperatorLowRankUpdate(
      operator=diag_operator,
      u=[[1., 2.], [-1., 3.], [0., 0.]],
      diag_update=[11., 12.],
      v=[[1., 2.], [-1., 3.], [10., 10.]])
  
  operator.shape
  ==> [3, 3]
  
  operator.log_abs_determinant()
  ==> scalar Tensor
  
  x = ... Shape [3, 4] Tensor
  operator.matmul(x)
  ==> Shape [3, 4] Tensor
  ```
  
  ### 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.
  ```
  
  ### Performance
  
  Suppose `operator` is a `LinearOperatorLowRankUpdate` of shape `[M, N]`,
  made from a rank `K` update of `base_operator` which performs `.matmul(x)` on
  `x` having `x.shape = [N, R]` with `O(L_matmul*N*R)` complexity (and similarly
  for `solve`, `determinant`.  Then, if `x.shape = [N, R]`,
  
  * `operator.matmul(x)` is `O(L_matmul*N*R + K*N*R)`
  
  and if `M = N`,
  
  * `operator.solve(x)` is `O(L_matmul*N*R + N*K*R + K^2*R + K^3)`
  * `operator.determinant()` is `O(L_determinant + L_solve*N*K + K^2*N + K^3)`
  
  If instead `operator` and `x` have shape `[B1,...,Bb, M, N]` and
  `[B1,...,Bb, N, R]`, every operation increases in complexity by `B1*...*Bb`.
  
  #### Matrix property hints
  
  This `LinearOperator` is initialized with boolean flags of the form `is_X`,
  for `X = non_singular`, `self_adjoint`, `positive_definite`,
  `diag_update_positive` and `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: ["Perturb","a","`","LinearOperator","`","with","a","rank","`","K","`","update",".","This","operator","acts","like","a","[","batch","]","matrix","`","A","`","with","shape","`","[","B1",",","...",",","Bb",",","M",",","N","]","`","for","some","`","b",">","=","0","`",".","The","first","`","b","`","indices","index","a","batch","member",".","For","every","batch","index","`","(","i1",",","...",",","ib",")","`",",","`","A","[","i1",",","...",",","ib",",",":",":","]","`","is","an","`","M","x","N","`","matrix",".","`","LinearOperatorLowRankUpdate","`","represents","`","A","=","L","+","U","D","V^H","`",",","where","``","`","L",",","is","a","LinearOperator","representing","[","batch","]","M","x","N","matrices","U",",","is","a","[","batch","]","M","x","K","matrix",".","Typically","K","<","<","M.","D",",","is","a","[","batch","]","K","x","K","matrix",".","V",",","is","a","[","batch","]","N","x","K","matrix",".","Typically","K","<","<","N.","V^H","is","the","Hermitian","transpose","(","adjoint",")","of","V.","``","`","If","`","M","=","N","`",",","determinants","and","solves","are","done","using","the","matrix","determinant","lemma","and","Woodbury","identities",",","and","thus","require","L","and","D","to","be","non-singular",".","Solves","and","determinants","will","be","attempted","unless","the","``","is_non_singular","''","property","of","L","and","D","is","False",".","In","the","event","that","L","and","D","are","positive-definite",",","and","U","=","V",",","solves","and","determinants","can","be","done","using","a","Cholesky","factorization",".","``","`","python","#","Create","a","3","x","3","diagonal","linear","operator",".","diag_operator","=","LinearOperatorDiag","(","diag_update=","[","1.",",","2.",",","3",".","]",",","is_non_singular=True",",","is_self_adjoint=True",",","is_positive_definite=True",")","#","Perturb","with","a","rank","2","perturbation","operator","=","LinearOperatorLowRankUpdate","(","operator=diag_operator",",","u=","[","[","1.",",","2",".","]",",","[","-1.",",","3",".","]",",","[","0.",",","0",".","]","]",",","diag_update=","[","11.",",","12",".","]",",","v=","[","[","1.",",","2",".","]",",","[","-1.",",","3",".","]",",","[","10.",",","10",".","]","]",")","operator.shape","==",">","[","3",",","3","]","operator.log_abs_determinant","(",")","==",">","scalar","Tensor","x","=","...","Shape","[","3",",","4","]","Tensor","operator.matmul","(","x",")","==",">","Shape","[","3",",","4","]","Tensor","``","`","#","#","#","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",".","``","`","#","#","#","Performance","Suppose","`","operator","`","is","a","`","LinearOperatorLowRankUpdate","`","of","shape","`","[","M",",","N","]","`",",","made","from","a","rank","`","K","`","update","of","`","base_operator","`","which","performs","`",".matmul","(","x",")","`","on","`","x","`","having","`","x.shape","=","[","N",",","R","]","`","with","`","O","(","L_matmul","*","N","*","R",")","`","complexity","(","and","similarly","for","`","solve","`",",","`","determinant","`",".","Then",",","if","`","x.shape","=","[","N",",","R","]","`",",","*","`","operator.matmul","(","x",")","`","is","`","O","(","L_matmul","*","N","*","R","+","K","*","N","*","R",")","`","and","if","`","M","=","N","`",",","*","`","operator.solve","(","x",")","`","is","`","O","(","L_matmul","*","N","*","R","+","N","*","K","*","R","+","K^2","*","R","+","K^3",")","`","*","`","operator.determinant","(",")","`","is","`","O","(","L_determinant","+","L_solve","*","N","*","K","+","K^2","*","N","+","K^3",")","`","If","instead","`","operator","`","and","`","x","`","have","shape","`","[","B1",",","...",",","Bb",",","M",",","N","]","`","and","`","[","B1",",","...",",","Bb",",","N",",","R","]","`",",","every","operation","increases","in","complexity","by","`","B1","*","...","*","Bb","`",".","#","#","#","#","Matrix","property","hints","This","`","LinearOperator","`","is","initialized","with","boolean","flags","of","the","form","`","is_X","`",",","for","`","X","=","non_singular","`",",","`","self_adjoint","`",",","`","positive_definite","`",",","`","diag_update_positive","`","and","`","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","."]
docstr: Static check that shapes are compatible.
docstr_tok: ["Static","check","that","shapes","are","compatible","."]
code: def _check_shapes(self):
      """Static check that shapes are compatible."""
      # Broadcast shape also checks that u and v are compatible.
      uv_shape = array_ops.broadcast_static_shape(
          self.u.shape, self.v.shape
      )
  
      batch_shape = array_ops.broadcast_static_shape(
          self.base_operator.batch_shape, uv_shape[:-2]
      )
  
      tensor_shape.Dimension(
          self.base_operator.domain_dimension
      ).assert_is_compatible_with(uv_shape[-2])
  
      if self._diag_update is not None:
          tensor_shape.dimension_at_index(
              uv_shape, -1
          ).assert_is_compatible_with(self._diag_update.shape[-1])
          array_ops.broadcast_static_shape(
              batch_shape, self._diag_update.shape[:-1]
          )
  
imports: 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 linalg_ops
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops.linalg import linear_operator
  from tensorflow.python.ops.linalg import linear_operator_diag
  from tensorflow.python.ops.linalg import linear_operator_identity
  from tensorflow.python.ops.linalg import linear_operator_util
  from tensorflow.python.platform import tf_logging
  from tensorflow.python.util.tf_export import tf_export
label_desc: Use image node_id 2 for calling the LinearOperatorLowRankUpdate obj's underlying member method code with example usage: obj._check_shapes() without return types