parameters: (self,
                 base_operator,
                 u,
                 diag_update=None,
                 v=None,
                 is_diag_update_positive=None,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorLowRankUpdate")
docstring: Initialize a `LinearOperatorLowRankUpdate`.
  
      This creates a `LinearOperator` of the form `A = L + U D V^H`, with
      `L` a `LinearOperator`, `U, V` both [batch] matrices, and `D` a [batch]
      diagonal matrix.
  
      If `L` is non-singular, solves and determinants are available.
      Solves/determinants both involve a solve/determinant of a `K x K` system.
      In the event that L and D are self-adjoint positive-definite, and U = V,
      this can be done using a Cholesky factorization.  The user should set the
      `is_X` matrix property hints, which will trigger the appropriate code path.
  
      Args:
        base_operator:  Shape `[B1,...,Bb, M, N]` real `float32` or `float64`
          `LinearOperator`.  This is `L` above.
        u:  Shape `[B1,...,Bb, M, K]` `Tensor` of same `dtype` as `base_operator`.
          This is `U` above.
        diag_update:  Optional shape `[B1,...,Bb, K]` `Tensor` with same `dtype`
          as `base_operator`.  This is the diagonal of `D` above.
           Defaults to `D` being the identity operator.
        v:  Optional `Tensor` of same `dtype` as `u` and shape `[B1,...,Bb, N, K]`
           Defaults to `v = u`, in which case the perturbation is symmetric.
           If `M != N`, then `v` must be set since the perturbation is not square.
        is_diag_update_positive:  Python `bool`.
          If `True`, expect `diag_update > 0`.
        is_non_singular:  Expect that this operator is non-singular.
          Default is `None`, unless `is_positive_definite` is auto-set to be
          `True` (see below).
        is_self_adjoint:  Expect that this operator is equal to its hermitian
          transpose.  Default is `None`, unless `base_operator` is self-adjoint
          and `v = None` (meaning `u=v`), in which case this defaults to `True`.
        is_positive_definite:  Expect that this operator is positive definite.
          Default is `None`, unless `base_operator` is positive-definite
          `v = None` (meaning `u=v`), and `is_diag_update_positive`, in which case
          this defaults to `True`.
          Note that we say an operator is positive definite when the quadratic
          form `x^H A x` has positive real part for all nonzero `x`.
        is_square:  Expect that this operator acts like square [batch] matrices.
        name: A name for this `LinearOperator`.
  
      Raises:
        ValueError:  If `is_X` flags are set in an inconsistent way.
docstring_summary: Initialize a `LinearOperatorLowRankUpdate`.
docstring_tokens: Initialize a LinearOperatorLowRankUpdate .
function: def __init__(self,
                 base_operator,
                 u,
                 diag_update=None,
                 v=None,
                 is_diag_update_positive=None,
                 is_non_singular=None,
                 is_self_adjoint=None,
                 is_positive_definite=None,
                 is_square=None,
                 name="LinearOperatorLowRankUpdate"):
      """Initialize a `LinearOperatorLowRankUpdate`.
  
      This creates a `LinearOperator` of the form `A = L + U D V^H`, with
      `L` a `LinearOperator`, `U, V` both [batch] matrices, and `D` a [batch]
      diagonal matrix.
  
      If `L` is non-singular, solves and determinants are available.
      Solves/determinants both involve a solve/determinant of a `K x K` system.
      In the event that L and D are self-adjoint positive-definite, and U = V,
      this can be done using a Cholesky factorization.  The user should set the
      `is_X` matrix property hints, which will trigger the appropriate code path.
  
      Args:
        base_operator:  Shape `[B1,...,Bb, M, N]` real `float32` or `float64`
          `LinearOperator`.  This is `L` above.
        u:  Shape `[B1,...,Bb, M, K]` `Tensor` of same `dtype` as `base_operator`.
          This is `U` above.
        diag_update:  Optional shape `[B1,...,Bb, K]` `Tensor` with same `dtype`
          as `base_operator`.  This is the diagonal of `D` above.
           Defaults to `D` being the identity operator.
        v:  Optional `Tensor` of same `dtype` as `u` and shape `[B1,...,Bb, N, K]`
           Defaults to `v = u`, in which case the perturbation is symmetric.
           If `M != N`, then `v` must be set since the perturbation is not square.
        is_diag_update_positive:  Python `bool`.
          If `True`, expect `diag_update > 0`.
        is_non_singular:  Expect that this operator is non-singular.
          Default is `None`, unless `is_positive_definite` is auto-set to be
          `True` (see below).
        is_self_adjoint:  Expect that this operator is equal to its hermitian
          transpose.  Default is `None`, unless `base_operator` is self-adjoint
          and `v = None` (meaning `u=v`), in which case this defaults to `True`.
        is_positive_definite:  Expect that this operator is positive definite.
          Default is `None`, unless `base_operator` is positive-definite
          `v = None` (meaning `u=v`), and `is_diag_update_positive`, in which case
          this defaults to `True`.
          Note that we say an operator is positive definite when the quadratic
          form `x^H A x` has positive real part for all nonzero `x`.
        is_square:  Expect that this operator acts like square [batch] matrices.
        name: A name for this `LinearOperator`.
  
      Raises:
        ValueError:  If `is_X` flags are set in an inconsistent way.
      """
      # TODO(langmore) support complex types.
      # Complex types are not allowed due to tf.cholesky() requiring float.
      # If complex dtypes are allowed, we update the following
      # 1. is_diag_update_positive should still imply that `diag > 0`, but we need
      #    to remind the user that this implies diag is real.  This is needed
      #    because if diag has non-zero imaginary part, it will not be
      #    self-adjoint positive definite.
      dtype = base_operator.dtype
      allowed_dtypes = [dtypes.float32, dtypes.float64]
      if dtype not in allowed_dtypes:
        raise TypeError(
            "Argument matrix must have dtype in %s.  Found: %s"
            % (allowed_dtypes, dtype))
  
      if diag_update is None:
        if is_diag_update_positive is False:
          raise ValueError(
              "Default diagonal is the identity, which is positive.  However, "
              "user set 'is_diag_update_positive' to False.")
        is_diag_update_positive = True
  
      # In this case, we can use a Cholesky decomposition to help us solve/det.
      self._use_cholesky = (
          base_operator.is_positive_definite and base_operator.is_self_adjoint
          and is_diag_update_positive
          and v is None)
  
      # Possibly auto-set some characteristic flags from None to True.
      # If the Flags were set (by the user) incorrectly to False, then raise.
      if base_operator.is_self_adjoint and v is None and not dtype.is_complex:
        if is_self_adjoint is False:
          raise ValueError(
              "A = L + UDU^H, with L self-adjoint and D real diagonal.  Since"
              " UDU^H is self-adjoint, this must be a self-adjoint operator.")
        is_self_adjoint = True
  
      # The condition for using a cholesky is sufficient for SPD, and
      # we no weaker choice of these hints leads to SPD.  Therefore,
      # the following line reads "if hints indicate SPD..."
      if self._use_cholesky:
        if (
            is_positive_definite is False
            or is_self_adjoint is False
            or is_non_singular is False):
          raise ValueError(
              "Arguments imply this is self-adjoint positive-definite operator.")
        is_positive_definite = True
        is_self_adjoint = True
  
      values = base_operator.graph_parents + [u, diag_update, v]
      with ops.name_scope(name, values=values):
  
        # Create U and V.
        self._u = ops.convert_to_tensor(u, name="u")
        if v is None:
          self._v = self._u
        else:
          self._v = ops.convert_to_tensor(v, name="v")
  
        if diag_update is None:
          self._diag_update = None
        else:
          self._diag_update = ops.convert_to_tensor(
              diag_update, name="diag_update")
  
        # Create base_operator L.
        self._base_operator = base_operator
        graph_parents = base_operator.graph_parents + [
            self.u, self._diag_update, self.v]
        graph_parents = [p for p in graph_parents if p is not None]
  
        super(LinearOperatorLowRankUpdate, self).__init__(
            dtype=self._base_operator.dtype,
            graph_parents=graph_parents,
            is_non_singular=is_non_singular,
            is_self_adjoint=is_self_adjoint,
            is_positive_definite=is_positive_definite,
            is_square=is_square,
            name=name)
  
        # Create the diagonal operator D.
        self._set_diag_operators(diag_update, is_diag_update_positive)
        self._is_diag_update_positive = is_diag_update_positive
  
        check_ops.assert_same_float_dtype((base_operator, self.u, self.v,
                                           self._diag_update))
        self._check_shapes()
  
        # Pre-compute the so-called "capacitance" matrix
        #   C := D^{-1} + V^H L^{-1} U
        self._capacitance = self._make_capacitance()
        if self._use_cholesky:
          self._chol_capacitance = linalg_ops.cholesky(self._capacitance)
function_tokens: def __init__ ( self , base_operator , u , diag_update = None , v = None , is_diag_update_positive = None , is_non_singular = None , is_self_adjoint = None , is_positive_definite = None , is_square = None , name = "LinearOperatorLowRankUpdate" ) : # TODO(langmore) support complex types. # Complex types are not allowed due to tf.cholesky() requiring float. # If complex dtypes are allowed, we update the following # 1. is_diag_update_positive should still imply that `diag > 0`, but we need #    to remind the user that this implies diag is real.  This is needed #    because if diag has non-zero imaginary part, it will not be #    self-adjoint positive definite. dtype = base_operator . dtype allowed_dtypes = [ dtypes . float32 , dtypes . float64 ] if dtype not in allowed_dtypes : raise TypeError ( "Argument matrix must have dtype in %s.  Found: %s" % ( allowed_dtypes , dtype ) ) if diag_update is None : if is_diag_update_positive is False : raise ValueError ( "Default diagonal is the identity, which is positive.  However, " "user set 'is_diag_update_positive' to False." ) is_diag_update_positive = True # In this case, we can use a Cholesky decomposition to help us solve/det. self . _use_cholesky = ( base_operator . is_positive_definite and base_operator . is_self_adjoint and is_diag_update_positive and v is None ) # Possibly auto-set some characteristic flags from None to True. # If the Flags were set (by the user) incorrectly to False, then raise. if base_operator . is_self_adjoint and v is None and not dtype . is_complex : if is_self_adjoint is False : raise ValueError ( "A = L + UDU^H, with L self-adjoint and D real diagonal.  Since" " UDU^H is self-adjoint, this must be a self-adjoint operator." ) is_self_adjoint = True # The condition for using a cholesky is sufficient for SPD, and # we no weaker choice of these hints leads to SPD.  Therefore, # the following line reads "if hints indicate SPD..." if self . _use_cholesky : if ( is_positive_definite is False or is_self_adjoint is False or is_non_singular is False ) : raise ValueError ( "Arguments imply this is self-adjoint positive-definite operator." ) is_positive_definite = True is_self_adjoint = True values = base_operator . graph_parents + [ u , diag_update , v ] with ops . name_scope ( name , values = values ) : # Create U and V. self . _u = ops . convert_to_tensor ( u , name = "u" ) if v is None : self . _v = self . _u else : self . _v = ops . convert_to_tensor ( v , name = "v" ) if diag_update is None : self . _diag_update = None else : self . _diag_update = ops . convert_to_tensor ( diag_update , name = "diag_update" ) # Create base_operator L. self . _base_operator = base_operator graph_parents = base_operator . graph_parents + [ self . u , self . _diag_update , self . v ] graph_parents = [ p for p in graph_parents if p is not None ] super ( LinearOperatorLowRankUpdate , self ) . __init__ ( dtype = self . _base_operator . dtype , graph_parents = graph_parents , is_non_singular = is_non_singular , is_self_adjoint = is_self_adjoint , is_positive_definite = is_positive_definite , is_square = is_square , name = name ) # Create the diagonal operator D. self . _set_diag_operators ( diag_update , is_diag_update_positive ) self . _is_diag_update_positive = is_diag_update_positive check_ops . assert_same_float_dtype ( ( base_operator , self . u , self . v , self . _diag_update ) ) self . _check_shapes ( ) # Pre-compute the so-called "capacitance" matrix #   C := D^{-1} + V^H L^{-1} U self . _capacitance = self . _make_capacitance ( ) if self . _use_cholesky : self . _chol_capacitance = linalg_ops . cholesky ( self . _capacitance )