
    AVh                        d Z ddlZddlZddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddlm
Z
 ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlm Z! ddl"m#Z# ddl$m%Z% ddl$m&Z& ddl$m'Z' ddl$m(Z( ddl)m*Z* dgZ+ G d  d!ejX                        Z- e*d"       G d# dej\                  ej^                  ej`                  $             Z1 G d% d&ejd                        Z3d3d'Z4d( Z5d) Z6 e&jn                  ejp                  e1      d4d*       Z9 e&jn                  ejt                  e1      d4d+       Z; e&jn                  ejx                  e1      	 	 	 	 d5d,       Z= e&jn                  ej|                  e1      d4d-       Z? e&jn                  ej                  e1      d6d.       ZA e&jn                  ej                  e1      d4d/       ZC e&jn                  ej                  e1      	 	 	 	 	 	 	 	 	 	 d7d0       ZE e&jn                  ej                  e1      	 	 d6d1       ZG e&jn                  ej                  e1      d4d2       ZIy)8z Base class for linear operators.    N)composite_tensor)composite_tensor_gradient)dtypes)ops)tensor_conversion)tensor_shape)tensor_spec)tensor_util)	type_spec)type_spec_registry)module)	array_ops)	check_ops)
linalg_ops)math_ops)resource_variable_ops)	variables)linalg_impl)linear_operator_util)property_hint_util)slicing)
tf_logging)data_structures)deprecation)dispatch)nest)variable_utils)	tf_exportLinearOperatorc                       e Zd ZdZd Zd Zy)_LinearOperatorGradientz/Composite tensor gradient for `LinearOperator`.c                 8    |j                   j                  |      S N)
_type_spec_to_components)selfvalues     \/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/linalg/linear_operator.pyget_gradient_componentsz/_LinearOperatorGradient.get_gradient_components<   s    **511    c                    t        j                  |      }t        d |D              ry j                  j	                        }g }t        |t        j                  |            D ]C  \  }}|+|j                  t        j                  fd|d             3|j                  |       E t        j                  ||      }j                  j                  |      S )Nc              3   $   K   | ]  }|d u  
 y wr#    ).0cs     r(   	<genexpr>zF_LinearOperatorGradient.replace_gradient_components.<locals>.<genexpr>C   s     
.19
.s   c                 F    t        j                  | j                        S )N)dtype)r   
zeros_liker2   )xr'   s    r(   <lambda>zE_LinearOperatorGradient.replace_gradient_components.<locals>.<lambda>O   s    )..qD r*   T)expand_composites)
r   flattenallr$   r%   zipappendmap_structurepack_sequence_as_from_components)	r&   r'   
componentsflat_componentsvalue_componentsflat_grad_componentsgcvcgrad_componentss	    `       r(   replace_gradient_componentsz3_LinearOperatorGradient.replace_gradient_components?   s    ll:.O 
.o
..
 ''66u=ot||4D'EF (B	##D"&(	) 	##B'( ++.0O,,_==r*   N)__name__
__module____qualname____doc__r)   rE   r-   r*   r(   r!   r!   8   s    72>r*   r!   zlinalg.LinearOperatorc                      e Zd ZdZ ej
                  ddd      	 	 	 	 	 	 	 dTd       Zej                  dUd       Z	e
d        Ze
d        Ze
d	        Ze
 ej                  dd
      d               Ze
d        Ze
d        Ze
d        Ze
d        Zej*                  d        Ze
d        Zd ZdVdZe
d        ZdWdZdUdZe
dXd       ZdYdZdUdZe
d        Z dZdZ!dUdZ"e
d        Z#d[dZ$dUdZ%d  Z&d! Z'd\d"Z(d# Z)d]d$Z*d% Z+d^d&Z,d' Z-ej*                  d_d(       Z.	 	 	 d`d)Z/	 	 	 	 	 	 dad+Z0d, Z1dbd-Z2dcd.Z3d/ Z4ddd0Z5d1 Z6ded2Z7d_d3Z8d_d4Z9dfd5Z:	 	 	 	 	 	 dad6Z;dbd7Z<dgd8Z=dhd9e>d*d fd:Z? e
e?d      Z@did;ZAdjd9e>d*d fd<ZBdid=ZCdkd9e>d*d fd>ZDdid?ZEd@ ZFdldAZGdB ZHdmdCZIdD ZJdndEZKdF ZLdodGZMdH ZNdpdIZOdJ ZPdqdKZQdL ZRdM ZSe
dN        ZTe
dO        ZUe
dP        ZVdQ ZWdR ZXe
dS        ZY eZ       Z[y)rr   a  Base class defining a [batch of] linear operator[s].

  Subclasses of `LinearOperator` provide access to common methods on a
  (batch) matrix, without the need to materialize the matrix.  This allows:

  * Matrix free computations
  * Operators that take advantage of special structure, while providing a
    consistent API to users.

  #### Subclassing

  To enable a public method, subclasses should implement the leading-underscore
  version of the method.  The argument signature should be identical except for
  the omission of `name="..."`.  For example, to enable
  `matmul(x, adjoint=False, name="matmul")` a subclass should implement
  `_matmul(x, adjoint=False)`.

  #### Performance contract

  Subclasses should only implement the assert methods
  (e.g. `assert_non_singular`) if they can be done in less than `O(N^3)`
  time.

  Class docstrings should contain an explanation of computational complexity.
  Since this is a high-performance library, attention should be paid to detail,
  and explanations can include constants as well as Big-O notation.

  #### Shape compatibility

  `LinearOperator` subclasses should operate on a [batch] matrix with
  compatible shape.  Class docstrings should define what is meant by compatible
  shape.  Some subclasses may not support batching.

  Examples:

  `x` is a batch matrix with compatible shape for `matmul` if

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

  `rhs` is a batch matrix with compatible shape for `solve` if

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

  #### Example docstring for subclasses.

  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.  Again, this matrix `A` may not be materialized, but for
  purposes of identifying and working with compatible arguments the shape is
  relevant.

  Examples:

  ```python
  some_tensor = ... shape = ????
  operator = MyLinOp(some_tensor)

  operator.shape()
  ==> [2, 4, 4]

  operator.log_abs_determinant()
  ==> Shape [2] Tensor

  x = ... Shape [2, 4, 5] Tensor

  operator.matmul(x)
  ==> Shape [2, 4, 5] Tensor
  ```

  #### Shape compatibility

  This operator acts on batch matrices with compatible shape.
  FILL IN WHAT IS MEANT BY COMPATIBLE SHAPE

  #### Performance

  FILL THIS IN

  #### 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.

  #### Initialization parameters

  All subclasses of `LinearOperator` are expected to pass a `parameters`
  argument to `super().__init__()`.  This should be a `dict` containing
  the unadulterated arguments passed to the subclass `__init__`.  For example,
  `MyLinearOperator` with an initializer should look like:

  ```python
  def __init__(self, operator, is_square=False, name=None):
     parameters = dict(
         operator=operator,
         is_square=is_square,
         name=name
     )
     ...
     super().__init__(..., parameters=parameters)
  ```

   Users can then access `my_linear_operator.parameters` to see all arguments
   passed to its initializer.
  Nz;Do not pass `graph_parents`.  They will  no longer be used.graph_parentsc	                    |r|du rt        d      d}|r|du rt        d      d}|r|du rt        d      d}|| _        || j                  |       ng | _        |rt	        j
                  |      j                  n|| _        || _        || _	        || _
        | j                  |      | _        d| _        |xs t        |       j                  | _        y)a  Initialize the `LinearOperator`.

    **This is a private method for subclass use.**
    **Subclasses should copy-paste this `__init__` documentation.**

    Args:
      dtype: The type of the this `LinearOperator`.  Arguments to `matmul` and
        `solve` will have to be this type.
      graph_parents: (Deprecated) Python list of graph prerequisites of this
        `LinearOperator` Typically tensors that are passed during initialization
      is_non_singular:  Expect that this operator is non-singular.
      is_self_adjoint:  Expect that this operator is equal to its hermitian
        transpose.  If `dtype` is real, this is equivalent to being symmetric.
      is_positive_definite:  Expect that this operator is positive definite,
        meaning the quadratic form `x^H A x` has positive real part for all
        nonzero `x`.  Note that we do not require the operator to be
        self-adjoint to be positive-definite.  See:
        https://en.wikipedia.org/wiki/Positive-definite_matrix#Extension_for_non-symmetric_matrices
      is_square:  Expect that this operator acts like square [batch] matrices.
      name: A name for this `LinearOperator`.
      parameters: Python `dict` of parameters used to instantiate this
        `LinearOperator`.

    Raises:
      ValueError:  If any member of graph_parents is `None` or not a `Tensor`.
      ValueError:  If hints are set incorrectly.
    Fz2A positive definite matrix is always non-singular.Tz'A non-singular matrix is always square.z'A self-adjoint matrix is always square.N)
ValueError"_is_square_set_or_implied_by_hints_set_graph_parents_graph_parentsr   as_dtype
base_dtype_dtype_is_non_singular_is_self_adjoint_is_positive_definite_no_dependency_parameters_parameters_sanitizedtyperF   _name)	r&   r2   rK   is_non_singularis_self_adjointis_positive_definite	is_squarename
parameterss	            r(   __init__zLinearOperator.__init__   s    N 	E	!MNNo	e	BCCi	e	BCCi.7D+ 
m,d7<&//%(33%DK+D+D!5D**:6D!&D,d,,DJr*   c              #      K   | j                   }||d|z   z  }t        j                  |      5 }| ddd       y# 1 sw Y   yxY ww)z(Helper function to standardize op scope.N/)r`   r   
name_scope)r&   r`   	full_namescopes       r(   _name_scopezLinearOperator._name_scope  sL      		I3:i			" ek  s   ,A<	AAAc                 ,    t        | j                        S )zCDictionary of parameters used to instantiate this `LinearOperator`.)dictrX   r&   s    r(   ra   zLinearOperator.parameters%  s       !!r*   c                     | j                   S )z:The `DType` of `Tensor`s handled by this `LinearOperator`.)rS   rk   s    r(   r2   zLinearOperator.dtype*  s     ;;r*   c                     | j                   S )z;Name prepended to all ops created by this `LinearOperator`.)r[   rk   s    r(   r`   zLinearOperator.name/  s     ::r*   zDo not call `graph_parents`.c                     | j                   S )z4List of graph dependencies of this `LinearOperator`.)rP   rk   s    r(   rK   zLinearOperator.graph_parents4  s     r*   c                     | j                   S r#   )rT   rk   s    r(   r\   zLinearOperator.is_non_singular:         r*   c                     | j                   S r#   )rU   rk   s    r(   r]   zLinearOperator.is_self_adjoint>  rp   r*   c                     | j                   S r#   )rV   rk   s    r(   r^   z#LinearOperator.is_positive_definiteB  s    %%%r*   c                     | j                   | j                  k(  }| j                  du r|rt        d      | j                  |S | j                  S )z<Return `True/False` depending on if this operator is square.Fz>User set is_square hint to False, but the operator was square.)domain_dimensionrange_dimensionrN   rM   )r&   auto_square_checks     r(   r_   zLinearOperator.is_squareF  s\    
 --1E1EE..%7<M
JL L..6222r*   c                     t        d      )Nz_shape is not implemented.NotImplementedErrorrk   s    r(   _shapezLinearOperator._shapeT  s     :
;;r*   c                 "    | j                         S )a&  `TensorShape` of this `LinearOperator`.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns
    `TensorShape([B1,...,Bb, M, N])`, equivalent to `A.shape`.

    Returns:
      `TensorShape`, statically determined, may be undefined.
    )rz   rk   s    r(   shapezLinearOperator.shapeY  s     ;;=r*   c                     t        d      )Nz!_shape_tensor is not implemented.rx   rk   s    r(   _shape_tensorzLinearOperator._shape_tensorf  s     A
BBr*   c                    | j                  |      5  | j                  j                         r6t        j                  | j                  j                               cddd       S | j                         cddd       S # 1 sw Y   yxY w)aF  Shape of this `LinearOperator`, determined at runtime.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns a `Tensor` holding
    `[B1,...,Bb, M, N]`, equivalent to `tf.shape(A)`.

    Args:
      name:  A name for this `Op`.

    Returns:
      `int32` `Tensor`
    N)rh   r|   is_fully_definedr   shape_tensoras_listr~   r&   r`   s     r(   r   zLinearOperator.shape_tensorl  sj     
		$	 $		$	$	&#001C1C1EF$ $
 !!#$ $ $s   AA<#A<<Bc                      | j                   dd S )a8  `TensorShape` of batch dimensions of this `LinearOperator`.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns
    `TensorShape([B1,...,Bb])`, equivalent to `A.shape[:-2]`

    Returns:
      `TensorShape`, statically determined, may be undefined.
    N)r|   rk   s    r(   batch_shapezLinearOperator.batch_shape  s     ::cr?r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a/  Shape of batch dimensions of this operator, determined at runtime.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns a `Tensor` holding
    `[B1,...,Bb]`.

    Args:
      name:  A name for this `Op`.

    Returns:
      `int32` `Tensor`
    N)rh   _batch_shape_tensorr   s     r(   batch_shape_tensorz!LinearOperator.batch_shape_tensor  s3     
		$	 (%%'( ( (   ,5c                     | j                   j                         r/t        j                  | j                   j	                         d      S || j                         n|}|d d S )Nr   r`   r   )r   r   r   r   r   r&   r|   s     r(   r   z"LinearOperator._batch_shape_tensor  s_     ((*!..



"
"
$=: : &+]d!e3BZr*   c                 |    | j                  |      5  | j                  j                  cddd       S # 1 sw Y   yxY w)a@  Rank (in the sense of tensors) of matrix corresponding to this operator.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns `b + 2`.

    Args:
      name:  A name for this `Op`.

    Returns:
      Python integer, or None if the tensor rank is undefined.
    N)rh   r|   ndimsr   s     r(   tensor_rankzLinearOperator.tensor_rank  s4     
		$	 ZZ  s   2;c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a0  Rank (in the sense of tensors) of matrix corresponding to this operator.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns `b + 2`.

    Args:
      name:  A name for this `Op`.

    Returns:
      `int32` `Tensor`, determined at runtime.
    N)rh   _tensor_rank_tensorr   s     r(   tensor_rank_tensorz!LinearOperator.tensor_rank_tensor  s3     
		$	 (%%'( ( (r   c                     | j                   t        j                  | j                         S || j                         n|}t	        j
                  |      S r#   )r   r   "convert_to_tensor_v2_with_dispatchr   r   sizer   s     r(   r   z"LinearOperator._tensor_rank_tensor  sQ     #AA


  &+]d!e^^E""r*   c                     | j                   j                  t        j                  d      S | j                   j                  d   S )zDimension (in the sense of vector spaces) of the domain of this operator.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns `N`.

    Returns:
      `Dimension` object.
    N)r|   rankr   	Dimensiondimsrk   s    r(   rt   zLinearOperator.domain_dimension  s6     zz##D))ZZ__R  r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a1  Dimension (in the sense of vector spaces) of the domain of this operator.

    Determined at runtime.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns `N`.

    Args:
      name:  A name for this `Op`.

    Returns:
      `int32` `Tensor`
    N)rh   _domain_dimension_tensorr   s     r(   domain_dimension_tensorz&LinearOperator.domain_dimension_tensor  s3     
		$	 -**,- - -r   c                     t        j                  | j                        }|t        j                  |      S || j                         n|}|d   S )Nr   )r   dimension_valuert   r   r   r   r&   r|   	dim_values      r(   r   z'LinearOperator._domain_dimension_tensor  sO     ,,T-B-BCIAA)LL%*]d!e2Yr*   c                     | j                   j                  r| j                   j                  d   S t        j                  d      S )zDimension (in the sense of vector spaces) of the range of this operator.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns `M`.

    Returns:
      `Dimension` object.
    r   N)r|   r   r   r   rk   s    r(   ru   zLinearOperator.range_dimension  s3     zzZZ__R  ##D))r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a0  Dimension (in the sense of vector spaces) of the range of this operator.

    Determined at runtime.

    If this operator acts like the batch matrix `A` with
    `A.shape = [B1,...,Bb, M, N]`, then this returns `M`.

    Args:
      name:  A name for this `Op`.

    Returns:
      `int32` `Tensor`
    N)rh   _range_dimension_tensorr   s     r(   range_dimension_tensorz%LinearOperator.range_dimension_tensor  s3     
		$	 ,))+, , ,r   c                     t        j                  | j                        }|t        j                  |      S || j                         n|}|d   S )Nr   )r   r   ru   r   r   r   r   s      r(   r   z&LinearOperator._range_dimension_tensor#  sO     ,,T-A-ABIAA)LL%*]d!e2Yr*   c                 `   t        j                  d       | j                         r| j                         S t	        j
                  | j                         d      }t        j                  |d      t        j                  |d      z  }t        j                  || j                         d      S )z7Private default implementation of _assert_non_singular.zUsing (possibly slow) default implementation of assert_non_singular.  Requires conversion to a dense matrix and O(N^3) operations.F
compute_uvr   axisz(Singular matrix up to precision epsilon.message)loggingwarn_can_use_choleskyassert_positive_definiter   svdto_denser   
reduce_max
reduce_minr   assert_less(_max_condition_number_to_be_non_singular)r&   singular_valuesconds      r(   _assert_non_singularz#LinearOperator._assert_non_singular-  s    LL	IJ **,,"t}}5Io!!/;!!/;<d""


7
7
9<> >r*   c                    t        j                  d      5  t        j                  | j                  j
                        j                  }t        j                  t        j                  dt        j                  | j                         | j                        t        j                  | j                         | j                        g      | j                        |z  }d|z  cddd       S # 1 sw Y   yxY w)zAReturn the maximum condition number that we consider nonsingular. max_nonsingular_condition_numberg      Y@g      ?N)r   re   npfinfor2   as_numpy_dtypeepsr   castr   r   r   )r&   	dtype_epsr   s      r(   r   z7LinearOperator._max_condition_number_to_be_non_singular>  s    	:	; ((4::44599iMM


mmD7794::FmmD88:DJJG  jj
 &&c #X  s   C	C))C2c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a  Returns an `Op` that asserts this operator is non singular.

    This operator is considered non-singular if

    ```
    ConditionNumber < max{100, range_dimension, domain_dimension} * eps,
    eps := np.finfo(self.dtype.as_numpy_dtype).eps
    ```

    Args:
      name:  A string name to prepend to created ops.

    Returns:
      An `Assert` `Op`, that, when run, will raise an `InvalidArgumentError` if
        the operator is singular.
    N)rh   r   r   s     r(   assert_non_singularz"LinearOperator.assert_non_singularJ  s3    " 
		$	 )&&() ) )r   c                     t        j                  d       | j                  rKt        j                  t        j                  t        j                  | j                                     d      S t        d      )z4Default implementation of _assert_positive_definite.zUsing (possibly slow) default implementation of assert_positive_definite.  Requires conversion to a dense matrix and O(N^3) operations.z!Matrix was not positive definite.r   z,assert_positive_definite is not implemented.)r   r   r]   r   assert_positiver   matrix_diag_partr   choleskyr   ry   rk   s    r(   _assert_positive_definitez(LinearOperator._assert_positive_definite^  sc    LL	IJ &&

$
$Z%8%8%I
J57 7 L
MMr*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a  Returns an `Op` that asserts this operator is positive definite.

    Here, positive definite means that the quadratic form `x^H A x` has positive
    real part for all nonzero `x`.  Note that we do not require the operator to
    be self-adjoint to be positive definite.

    Args:
      name:  A name to give this `Op`.

    Returns:
      An `Assert` `Op`, that, when run, will raise an `InvalidArgumentError` if
        the operator is not positive definite.
    N)rh   r   r   s     r(   r   z'LinearOperator.assert_positive_definiten  s3     
		$	 .++-. . .r   c                     | j                         }t        j                  d       t        j                  |t        j                  |      d      S )NzlUsing (possibly slow) default implementation of assert_self_adjoint.  Requires conversion to a dense matrix.z$Matrix was not equal to its adjoint.r   )r   r   r   r   assert_equallinalgadjoint)r&   denses     r(   _assert_self_adjointz#LinearOperator._assert_self_adjoint  sE    MMOELL	34 !!u68 8r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)ab  Returns an `Op` that asserts this operator is self-adjoint.

    Here we check that this operator is *exactly* equal to its hermitian
    transpose.

    Args:
      name:  A string name to prepend to created ops.

    Returns:
      An `Assert` `Op`, that, when run, will raise an `InvalidArgumentError` if
        the operator is not self-adjoint.
    N)rh   r   r   s     r(   assert_self_adjointz"LinearOperator.assert_self_adjoint  s3     
		$	 )&&() ) )r   c                     |j                   j                  | j                   k7  r(t        d| j                   d|j                   d|      y)z#Check that arg.dtype == self.dtype.z Expected argument to have dtype z
.  Found: z in tensor N)r2   rR   	TypeError)r&   args     r(   _check_input_dtypez!LinearOperator._check_input_dtype  s>    
yytzz)::syy#'( ( *r*   c                     t        d      )Nz_matmul is not implemented.rx   )r&   r4   r   adjoint_args       r(   _matmulzLinearOperator._matmul  s    
;
<<r*   c                    t        |t              r|r| j                         n| }|r|j                         n|}|j                  T|j                  H|j                  |j                  k7  r/t        dj                  |j                  |j                              | j                  |      5  | j                  ||      cddd       S | j                  |      5  t        j                  |d      }| j                  |       |rdnd}|rdnd}t        j                  | j                  |      j                  |j                  |          | j!                  |||      cddd       S # 1 sw Y   xY w# 1 sw Y   yxY w)a  Transform [batch] matrix `x` with left multiplication:  `x --> Ax`.

    ```python
    # Make an operator acting like batch matrix A.  Assume A.shape = [..., M, N]
    operator = LinearOperator(...)
    operator.shape = [..., M, N]

    X = ... # shape [..., N, R], batch matrix, R > 0.

    Y = operator.matmul(X)
    Y.shape
    ==> [..., M, R]

    Y[..., :, r] = sum_j A[..., :, j] X[j, r]
    ```

    Args:
      x: `LinearOperator` or `Tensor` with compatible shape and same `dtype` as
        `self`. See class docstring for definition of compatibility.
      adjoint: Python `bool`.  If `True`, left multiply by the adjoint: `A^H x`.
      adjoint_arg:  Python `bool`.  If `True`, compute `A x^H` where `x^H` is
        the hermitian transpose (transposition and complex conjugation).
      name:  A name for this `Op`.

    Returns:
      A `LinearOperator` or `Tensor` with shape `[..., M, R]` and same `dtype`
        as `self`.
    NzIOperators are incompatible. Expected `x` to have dimension {} but got {}.r4   r   r   r   r   r   )
isinstancer   r   ru   rt   rM   formatrh   _linop_matmulr   r   r   r   dimension_at_indexr|   assert_is_compatible_withr   )	r&   r4   r   r   r`   left_operatorright_operatorself_dimarg_dims	            r(   matmulzLinearOperator.matmul  sk   F !^$(/dllnTm&1qyy{qn

(
(
4

(
(
4

(
(M,J,J
J$f..0N0NPQ 	Q
 D! A!!-@A A 
		$	 
G

>
>qs
Ka
a Bh!rg%%
**h  9 9ggg!  \\!W+\F
G 
GA A
G 
Gs   *E%BE1%E.1E:returnc                 R   t        |d      rt        |d      s|S t        |d      r%|j                  r|j                  st        d      |S t        j                  ||      }d }d }d }|rt        j                  ||      }n
|du rd}d}d}ddlm} |j                  ||g||||      S )	N
_ones_diag
multiplier_zeros_diagzhMatmul with non-square `LinearOperator`s or non-square `LinearOperatorZeros` not supported at this time.Fr   linear_operator_composition	operatorsr\   r]   r^   r_   )hasattrr_   rM   r   combined_non_singular_hinttensorflow.python.ops.linalgr   LinearOperatorComposition)r&   r   r   r_   r\   r]   r^   r   s           r(   r   zLinearOperator._linop_matmul  s     ~|,W6  
	/%%]-D-DK
 	
  %..}nMioo!	,GG>
 $
 K(BB"N3))3 C  r*   c                 $    | j                  |      S r#   )r   )r&   others     r(   
__matmul__zLinearOperator.__matmul__  s    ;;ur*   c                     t        j                  |d      }| j                  ||      }t        j                  |d      S )Nr   r   r   )r   expand_dimsr   squeeze)r&   r4   r   x_maty_mats        r(   _matveczLinearOperator._matvec  s9    !!!"-EKKwK/EU,,r*   c                 J   | j                  |      5  t        j                  |d      }| j                  |       |rdnd}t	        j
                  | j                  |      j                  |j                  d          | j                  ||      cddd       S # 1 sw Y   yxY w)a<  Transform [batch] vector `x` with left multiplication:  `x --> Ax`.

    ```python
    # Make an operator acting like batch matrix A.  Assume A.shape = [..., M, N]
    operator = LinearOperator(...)

    X = ... # shape [..., N], batch vector

    Y = operator.matvec(X)
    Y.shape
    ==> [..., M]

    Y[..., :] = sum_j A[..., :, j] X[..., j]
    ```

    Args:
      x: `Tensor` with compatible shape and same `dtype` as `self`.
        `x` is treated as a [batch] vector meaning for every set of leading
        dimensions, the last dimension defines a vector.
        See class docstring for definition of compatibility.
      adjoint: Python `bool`.  If `True`, left multiply by the adjoint: `A^H x`.
      name:  A name for this `Op`.

    Returns:
      A `Tensor` with shape `[..., M]` and same `dtype` as `self`.
    r4   r   r   r   r   N)	rh   r   r   r   r   r   r|   r   r   )r&   r4   r   r`   r   s        r(   matveczLinearOperator.matvec  s    6 
		$	 .

>
>qs
Ka
a Bh%%
**h  9 9!''"+ F\\!W\-. . .   A=BB"c                     t        j                  d       | j                         r#t        j                  | j                               S t        j                  | j                               S )NzUsing (possibly slow) default implementation of determinant.  Requires conversion to a dense matrix and O(N^3) operations.)	r   r   r   r   explog_abs_determinantr   matrix_determinantr   rk   s    r(   _determinantzLinearOperator._determinant=  sR    LL	IJ \\$22455((99r*   c                     | j                   du rt        d      | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)zDeterminant for every batch member.

    Args:
      name:  A name for this `Op`.

    Returns:
      `Tensor` with shape `self.batch_shape` and same `dtype` as `self`.

    Raises:
      NotImplementedError:  If `self.is_square` is `False`.
    FNDeterminant not implemented for an operator that is expected to not be square.N)r_   ry   rh   r  r   s     r(   determinantzLinearOperator.determinantE  sS     ~~  
		$	 ! ! ! !   AAc                 d   t        j                  d       | j                         rdt        j                  t        j                  | j                                     }dt        j                  t        j                  |      dg      z  S t        j                  | j                               \  }}|S )Nr     r   r   )r   r   r   r   r   r   r   r   r   
reduce_sumlogr   slogdet)r&   diag_log_abs_dets       r(   _log_abs_determinantz#LinearOperator._log_abs_determinantX  s    LL	IJ ''
(;(;DMMO(LMd$$X\\$%7rdCCC^^DMMO4NA{r*   c                     | j                   du rt        d      | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a  Log absolute value of determinant for every batch member.

    Args:
      name:  A name for this `Op`.

    Returns:
      `Tensor` with shape `self.batch_shape` and same `dtype` as `self`.

    Raises:
      NotImplementedError:  If `self.is_square` is `False`.
    Fr  N)r_   ry   rh   r  r   s     r(   r  z"LinearOperator.log_abs_determinantb  sS     ~~  
		$	 )&&() ) )r
  c                 @   | j                   du rt        d      |rt        j                  |      n|}| j	                         r7t        j                  t        j                  | j                               |      S t        j                  | j                         ||      S )z&Solve by conversion to a dense matrix.Fz6Solve is not yet implemented for non-square operators.r   )r_   ry   r   r   r   r   cholesky_solver   r   r   matrix_solve_with_broadcastr&   rhsr   r   s       r(   _dense_solvezLinearOperator._dense_solveu  s    ~~
BD D!,&..
#C&&


dmmo
.5 5;;g/ /r*   c                 T    t        j                  d       | j                  |||      S )z!Default implementation of _solve.ztUsing (possibly slow) default implementation of solve.  Requires conversion to a dense matrix and O(N^3) operations.r   )r   r   r  r  s       r(   _solvezLinearOperator._solve  s/    LL	IJ S'{KKr*   c                 ^   | j                   du rt        d      | j                  du rt        d      t        |t              r|r| j                         n| }|r|j                         n|}|j                  T|j                  H|j                  |j                  k7  r/t        dj                  |j                  |j                              | j                  |      5  | j                  ||      cddd       S | j                  |      5  t        j                  |d      }| j                  |       |rdnd	}|rdnd	}t        j                   | j"                  |      j%                  |j"                  |          | j'                  |||
      cddd       S # 1 sw Y   xY w# 1 sw Y   yxY w)a  Solve (exact or approx) `R` (batch) systems of equations: `A X = rhs`.

    The returned `Tensor` will be close to an exact solution if `A` is well
    conditioned. Otherwise closeness will vary. See class docstring for details.

    Examples:

    ```python
    # Make an operator acting like batch matrix A.  Assume A.shape = [..., M, N]
    operator = LinearOperator(...)
    operator.shape = [..., M, N]

    # Solve R > 0 linear systems for every member of the batch.
    RHS = ... # shape [..., M, R]

    X = operator.solve(RHS)
    # X[..., :, r] is the solution to the r'th linear system
    # sum_j A[..., :, j] X[..., j, r] = RHS[..., :, r]

    operator.matmul(X)
    ==> RHS
    ```

    Args:
      rhs: `Tensor` with same `dtype` as this operator and compatible shape.
        `rhs` is treated like a [batch] matrix meaning for every set of leading
        dimensions, the last two dimensions defines a matrix.
        See class docstring for definition of compatibility.
      adjoint: Python `bool`.  If `True`, solve the system involving the adjoint
        of this `LinearOperator`:  `A^H X = rhs`.
      adjoint_arg:  Python `bool`.  If `True`, solve `A X = rhs^H` where `rhs^H`
        is the hermitian transpose (transposition and complex conjugation).
      name:  A name scope to use for ops added by this method.

    Returns:
      `Tensor` with shape `[...,N, R]` and same `dtype` as `rhs`.

    Raises:
      NotImplementedError:  If `self.is_non_singular` or `is_square` is False.
    FzLExact solve not implemented for an operator that is expected to be singular.zNExact solve not implemented for an operator that is expected to not be square.NzKOperators are incompatible. Expected `rhs` to have dimension {} but got {}.r  r   r   r   r   )r\   ry   r_   r   r   r   ru   rt   rM   r   rh   _linop_solver   r   r   r   r   r|   r   r  )	r&   r  r   r   r`   r   r   r   r   s	            r(   solvezLinearOperator.solve  s   R u$  ~~  #~&(/dllnTm(3s{{}n

(
(
4

(
(
4

(
(M,J,J
J$f..0N0NPQ 	Q D! @  ?@ @ 
		$	 H@@
Ec c"Bh!rg%%
**h  9 9ii !" [[g;[GH H@ @H Hs   F	BF#F #F,c                 6   t        |d      rt        |d      s|j                         S t        j                  ||      }d }d }d }|rt        j                  ||      }n
|du rd}d}d}ddlm} ddlm} |j                  |j                  |      |g||||      S )Nr   r   Fr   r   linear_operator_inversionr   )
r   inverser   r_   r   r   r   r"  r   LinearOperatorInversion)	r&   r   r   r_   r\   r]   r^   r   r"  s	            r(   r  zLinearOperator._linop_solve  s     ~|,W6 ""$$ #,,]NKIOO*EE
o 
e	oo" IF&@@%==mL
 ('1 A 	 	r*   c                     t        j                  |d      }| j                  ||      }t        j                  |d      S )z$Default implementation of _solvevec.r   r   r   )r   r   r  r   )r&   r  r   rhs_matsolution_mats        r(   	_solveveczLinearOperator._solvevec  s9    ##Cb1G::gw:7L\33r*   c                 J   | j                  |      5  t        j                  |d      }| j                  |       |rdnd}t	        j
                  | j                  |      j                  |j                  d          | j                  ||      cddd       S # 1 sw Y   yxY w)a!  Solve single equation with best effort: `A X = rhs`.

    The returned `Tensor` will be close to an exact solution if `A` is well
    conditioned. Otherwise closeness will vary. See class docstring for details.

    Examples:

    ```python
    # Make an operator acting like batch matrix A.  Assume A.shape = [..., M, N]
    operator = LinearOperator(...)
    operator.shape = [..., M, N]

    # Solve one linear system for every member of the batch.
    RHS = ... # shape [..., M]

    X = operator.solvevec(RHS)
    # X is the solution to the linear system
    # sum_j A[..., :, j] X[..., j] = RHS[..., :]

    operator.matvec(X)
    ==> RHS
    ```

    Args:
      rhs: `Tensor` with same `dtype` as this operator.
        `rhs` is treated like a [batch] vector meaning for every set of leading
        dimensions, the last dimension defines a vector.  See class docstring
        for definition of compatibility regarding batch dimensions.
      adjoint: Python `bool`.  If `True`, solve the system involving the adjoint
        of this `LinearOperator`:  `A^H X = rhs`.
      name:  A name scope to use for ops added by this method.

    Returns:
      `Tensor` with shape `[...,N]` and same `dtype` as `rhs`.

    Raises:
      NotImplementedError:  If `self.is_non_singular` or `is_square` is False.
    r  r   r   r   r   N)	rh   r   r   r   r   r   r|   r   r(  )r&   r  r   r`   r   s        r(   solveveczLinearOperator.solvevec  s    N 
		$	 	2@@
Ec c"Bh%%
**h  9 9#))B- H^^C^1	2 	2 	2r   r`   c                     | j                   du r| S | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)aG  Returns the adjoint of the current `LinearOperator`.

    Given `A` representing this `LinearOperator`, return `A*`.
    Note that calling `self.adjoint()` and `self.H` are equivalent.

    Args:
      name:  A name for this `Op`.

    Returns:
      `LinearOperator` which represents the adjoint of this `LinearOperator`.
    TN)r]   rh   _linop_adjointr   s     r(   r   zLinearOperator.adjoint7  sF     t#k			$	 #  "# # #s	   <Ac                     ddl m} |j                  | | j                  | j                  | j
                  | j                        S )Nr   )linear_operator_adjointr\   r]   r^   r_   )r   r.  LinearOperatorAdjointr\   r]   r^   r_   )r&   r.  s     r(   r,  zLinearOperator._linop_adjointK  sB    D"88,,,,!66.. 9 " "r*   c                     | j                   du rt        d      | j                  du rt        d      | j                  |      5  | j	                         cddd       S # 1 sw Y   yxY w)a  Returns the Inverse of this `LinearOperator`.

    Given `A` representing this `LinearOperator`, return a `LinearOperator`
    representing `A^-1`.

    Args:
      name: A name scope to use for ops added by this method.

    Returns:
      `LinearOperator` representing inverse of this matrix.

    Raises:
      ValueError: When the `LinearOperator` is not hinted to be `non_singular`.
    FzFCannot take the Inverse: This operator represents a non square matrix.zDCannot take the Inverse: This operator represents a singular matrix.N)r_   rM   r\   rh   _linop_inverser   s     r(   r#  zLinearOperator.inverseT  ss     ~~ . / /u$ , - - 
		$	 #  "# # #s   AA'c                     ddl m} |j                  | | j                  | j                  | j
                  | j                        S )Nr   r!  r/  )r   r"  r$  r\   r]   r^   r_   )r&   r"  s     r(   r2  zLinearOperator._linop_inversem  sE     G$<<,,,,!66.. = " "r*   c                     | j                         st        d      | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a  Returns a Cholesky factor as a `LinearOperator`.

    Given `A` representing this `LinearOperator`, if `A` is positive definite
    self-adjoint, return `L`, where `A = L L^T`, i.e. the cholesky
    decomposition.

    Args:
      name:  A name for this `Op`.

    Returns:
      `LinearOperator` which represents the lower triangular matrix
      in the Cholesky decomposition.

    Raises:
      ValueError: When the `LinearOperator` is not hinted to be positive
        definite and self adjoint.
    zTCannot take the Cholesky decomposition: Not a positive definite self adjoint matrix.N)r   rM   rh   _linop_choleskyr   s     r(   r   zLinearOperator.cholesky{  sT    & !!# F G G			$	 $!!#$ $ $s   AAc                 z    ddl m} |j                  t        j                  | j                               ddd      S )Nr   ) linear_operator_lower_triangularTF)r\   r]   r_   )r   r7  LinearOperatorLowerTriangularr   r   r   )r&   r7  s     r(   r5  zLinearOperator._linop_cholesky  s;    M+IIDMMO,	 J  r*   c                 >   | j                   j                         r| j                   }n| j                         }t        j                  | j
                        }||}n| j                         }t        j                  ||| j                        }| j                  |      S )>Generic and often inefficient implementation.  Override often.)num_rowsr   r2   )r   r   r   r   r   rt   r   r   eyer2   r   )r&   r   r   nr<  s        r(   	_to_densezLinearOperator._to_dense  s    ((*$$k++-k,,T-B-BCI
a

&
&
(a
..!DJJ
OC;;sr*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)z9Return a dense (batch) matrix representing this operator.N)rh   r>  r   s     r(   r   zLinearOperator.to_dense  s/    			$	 ^^  r   c                 H    t        j                  | j                               S )r:  )r   r   r   rk   s    r(   
_diag_partzLinearOperator._diag_part  s    %%dmmo66r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)au  Efficiently get the [batch] diagonal part of this operator.

    If this operator has shape `[B1,...,Bb, M, N]`, this returns a
    `Tensor` `diagonal`, of shape `[B1,...,Bb, min(M, N)]`, where
    `diagonal[b1,...,bb, i] = self.to_dense()[b1,...,bb, i, i]`.

    ```
    my_operator = LinearOperatorDiag([1., 2.])

    # Efficiently get the diagonal
    my_operator.diag_part()
    ==> [1., 2.]

    # Equivalent, but inefficient method
    tf.linalg.diag_part(my_operator.to_dense())
    ==> [1., 2.]
    ```

    Args:
      name:  A name for this `Op`.

    Returns:
      diag_part:  A `Tensor` of same `dtype` as self.
    N)rh   rA  r   s     r(   	diag_partzLinearOperator.diag_part  s1    2 
		$	 __  r   c                 L    t        j                  | j                         d      S )Nr   r   )r   r  rC  rk   s    r(   _tracezLinearOperator._trace  s    t~~/b99r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)a	  Trace of the linear operator, equal to sum of `self.diag_part()`.

    If the operator is square, this is also the sum of the eigenvalues.

    Args:
      name:  A name for this `Op`.

    Returns:
      Shape `[B1,...,Bb]` `Tensor` of same `dtype` as `self`.
    N)rh   rE  r   s     r(   tracezLinearOperator.trace  s0     
		$	 [[]  r   c                 (    | j                         |z   S r#   r   )r&   r4   s     r(   _add_to_tensorzLinearOperator._add_to_tensor  s    ==?Qr*   c                     | j                  |      5  t        j                  |d      }| j                  |       | j	                  |      cddd       S # 1 sw Y   yxY w)a  Add matrix represented by this operator to `x`.  Equivalent to `A + x`.

    Args:
      x:  `Tensor` with same `dtype` and shape broadcastable to `self.shape`.
      name:  A name to give this `Op`.

    Returns:
      A `Tensor` with broadcast shape and same `dtype` as `self`.
    r4   r   N)rh   r   r   r   rJ  )r&   r4   r`   s      r(   add_to_tensorzLinearOperator.add_to_tensor  sU     
		$	 $

>
>qs
Ka
a   #$ $ $s   9AAc                 H    t        j                  | j                               S r#   )r   self_adjoint_eigvalsr   rk   s    r(   _eigvalszLinearOperator._eigvals  s    **4==?;;r*   c                     | j                   st        d      | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)ae  Returns the eigenvalues of this linear operator.

    If the operator is marked as self-adjoint (via `is_self_adjoint`)
    this computation can be more efficient.

    Note: This currently only supports self-adjoint operators.

    Args:
      name:  A name for this `Op`.

    Returns:
      Shape `[B1,...,Bb, N]` `Tensor` of same `dtype` as `self`.
    z)Only self-adjoint matrices are supported.N)r]   ry   rh   rO  r   s     r(   eigvalszLinearOperator.eigvals  sE      KLL			$	 ]]_  s   AAc                 
   | j                   s&t        j                  | j                         d      }n#t	        j
                  | j                               }t	        j                  |d      t	        j                  |d      z  S )NFr   r   r   )	r]   r   r   r   r   absrO  r   r   )r&   valss     r(   _condzLinearOperator._cond  sc     ^^DMMO>d \\$--/*d2.2./ 0r*   c                 p    | j                  |      5  | j                         cddd       S # 1 sw Y   yxY w)zReturns the condition number of this linear operator.

    Args:
      name:  A name for this `Op`.

    Returns:
      Shape `[B1,...,Bb]` `Tensor` of same `dtype` as `self`.
    N)rh   rU  r   s     r(   r   zLinearOperator.cond  s0     
		$	 ZZ\  r   c                 6    | j                   xr | j                  S r#   )r]   r^   rk   s    r(   r   z LinearOperator._can_use_cholesky$  s    =D$=$==r*   c                     |g n|}t        |      D ]B  \  }}|,t        j                  |      rt        j                  |      r4t        d||fz         || _        y)a(  Set self._graph_parents.  Called during derived class init.

    This method allows derived classes to set graph_parents, without triggering
    a deprecation warning (which is invoked if `graph_parents` is passed during
    `__init__`.

    Args:
      graph_parents: Iterable over Tensors.
    Nz)Graph parent item %d is not a Tensor; %s.)	enumerater   is_refr
   
is_tf_typerM   rP   )r&   rK   its       r(   rO   z!LinearOperator._set_graph_parents'  sj     (/B]M-( O1	
/66q9&11!4D1vMNNO (Dr*   c                      y)aw  A tuple of parameter names to rebuild the `LinearOperator`.

    The tuple contains the names of kwargs to the `LinearOperator`'s constructor
    that the `TypeSpec` needs to rebuild the `LinearOperator` instance.

    "is_non_singular", "is_self_adjoint", "is_positive_definite", and
    "is_square" are common to all `LinearOperator` subclasses and may be
    omitted.
    r-   r-   rk   s    r(   _composite_tensor_fieldsz'LinearOperator._composite_tensor_fields9  s     r*   c                      y)aQ  A tuple of names referring to parameters that may be treated statically.

    This is a subset of `_composite_tensor_fields`, and contains the names of
    of `Tensor`-like args to the `LinearOperator`s constructor that may be
    stored as static values, if they are statically known. These are typically
    shapes or axis values.
    r-   r-   rk   s    r(   &_composite_tensor_prefer_static_fieldsz5LinearOperator._composite_tensor_prefer_static_fieldsF  s     r*   c                      y r#   r-   rk   s    r(   r$   zLinearOperator._type_specQ  s     	r*   c                     | j                   j                  |       }t        j                  |      }| j                   j	                  |      S )a  Recursively converts ResourceVariables in the LinearOperator to Tensors.

    The usage of `self._type_spec._from_components` violates the contract of
    `CompositeTensor`, since it is called on a different nested structure
    (one containing only `Tensor`s) than `self.type_spec` specifies (one that
    may contain `ResourceVariable`s). Since `LinearOperator`'s
    `_from_components` method just passes the contents of the nested structure
    to `__init__` to rebuild the operator, and any `LinearOperator` that may be
    instantiated with `ResourceVariables` may also be instantiated with
    `Tensor`s, this usage is valid.

    Returns:
      tensor_operator: `self` with all internal Variables converted to Tensors.
    )r$   r%   r   convert_variables_to_tensorsr=   )r&   r>   tensor_componentss      r(   _convert_variables_to_tensorsz,LinearOperator._convert_variables_to_tensorsY  sB      //5J&CC??++,=>>r*   c                 2    t        j                  | i |      S )N)params_overridesslices)r   batch_slice)r&   ri  s     r(   __getitem__zLinearOperator.__getitem__o  s    tbHHr*   c                      y)a;  A dict of names to number of dimensions contributing to an operator.

    This is a dictionary of parameter names to `int`s specifying the
    number of right-most dimensions contributing to the **matrix** shape of the
    densified operator.
    If the parameter is a `Tensor`, this is mapped to an `int`.
    If the parameter is a `LinearOperator` (called `A`), this specifies the
    number of batch dimensions of `A` contributing to this `LinearOperator`s
    matrix shape.
    If the parameter is a structure, this is a structure of the same type of
    `int`s.
    r-   r-   rk   s    r(   -_experimental_parameter_ndims_to_matrix_ndimsz<LinearOperator._experimental_parameter_ndims_to_matrix_ndimsr  s     r*   )NNNNNNNr#   )r   )r   )r   )r   )r   )r   )r   )r   )r   )FF)FFr   )r   r   r   r   r   r   )F)Fr   )det)r  )FFr  )Fr  r   )r   r   )r#  r   rI  rC  rG  )rL  )rQ  )r   )\rF   rG   rH   rI   r   deprecated_argsrb   
contextlibcontextmanagerrh   propertyra   r2   r`   
deprecatedrK   r\   r]   r^   r_   abcabstractmethodrz   r|   r~   r   r   r   r   r   r   r   rt   r   r   ru   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r	  r  r  r  r  r  r  r(  r*  strr   Hr,  r#  r2  r   r5  r>  r   rA  rC  rE  rG  rJ  rL  rO  rQ  rU  r   r   rO   r_  ra  r$   rf  rk  rm  r!   __composite_gradient__r-   r*   r(   r   r   [   s   wt ;t &56EG "##$(@-G@-D   " "     ;$ >? @  ! ! ! ! & & 3 3 < < 
 
C$(  ("   ( 	# ! !-$ * *,$>"
)(N ."8) ( = = <G|.+.=M..`-
!.F:!&)&
/LKHZ(+(=M(	(T402d## #.> #$ w!"## #.> #2"$3 $0@ $2 
78:$<&0
>($ 
 
   	 	?,I   34r*   )	metaclassc                   ^    e Zd ZdZdZd Zed        Zd Zd Z	e
d        Zd Zd	 Zd
 Zd Zy)_LinearOperatorSpecz+A tf.TypeSpec for `LinearOperator` objects._param_specs_non_tensor_params_prefer_static_fieldsc                 .    || _         || _        || _        y)a  Initializes a new `_LinearOperatorSpec`.

    Args:
      param_specs: Python `dict` of `tf.TypeSpec` instances that describe
        kwargs to the `LinearOperator`'s constructor that are `Tensor`-like or
        `CompositeTensor` subclasses.
      non_tensor_params: Python `dict` containing non-`Tensor` and non-
        `CompositeTensor` kwargs to the `LinearOperator`'s constructor.
      prefer_static_fields: Python `tuple` of strings corresponding to the names
        of `Tensor`-like args to the `LinearOperator`s constructor that may be
        stored as static values, if known. These are typically shapes, indices,
        or axis values.
    Nr  )r&   param_specsnon_tensor_paramsprefer_static_fieldss       r(   rb   z_LinearOperatorSpec.__init__  s     $D/D!5Dr*   c                    d}t        |t        |j                  |z               }i }i }t        |j	                               D ]z  \  }}t        |      }t        j                  |      D 	cg c]  }	t        |	t        j                         }
}	t        |
      r|||<   \t        |
      s|||<   mt        d| d        | |||j                        S c c}	w )a  Builds a `_LinearOperatorSpec` from a `LinearOperator` instance.

    Args:
      operator: An instance of `LinearOperator`.

    Returns:
      linear_operator_spec: An instance of `_LinearOperatorSpec` to be used as
        the `TypeSpec` of `operator`.
    r/  keyszField z5 contains a mix of `Tensor` and  non-`Tensor` values.r  r  r  )_extract_attrssetr_  listitems_extract_type_spec_recursivelyr   r7   r   r   TypeSpecr8   anyry   ra  )clsoperatorvalidation_fieldskwargsr  r  kvtype_spec_or_vr4   	is_tensors              r(   from_operatorz!_LinearOperatorSpec.from_operator  s    >225FFGIF KV\\^$ 
<15a8n LL8: a!3!34 :i :	Y'A9~ !!F1# .: #; < 	<
< +%LLN N:s   +!Cc                 B    t        |t        | j                              S )Nr  )r  r  r  )r&   objs     r(   r%   z"_LinearOperatorSpec._to_components  s    #D):):$;<<r*   c                 R    t        | j                  fi |} | j                  di |S )Nr-   )rj   r  
value_type)r&   r>   r  s      r(   r=   z$_LinearOperatorSpec._from_components  s+    $))8Z8F4??$V$$r*   c                     | j                   S r#   )r  rk   s    r(   _component_specsz$_LinearOperatorSpec._component_specs  s    r*   c                 H    | j                   | j                  | j                  fS r#   r  rk   s    r(   
_serializez_LinearOperatorSpec._serialize  s'    ##&&( (r*   c                     | j                   | j                  | j                  d}|j                  |        t	        |       di |S )Nr  r-   )r  r  r  updaterZ   )r&   	overridesr  s      r(   _copyz_LinearOperatorSpec._copy  sF    ((!44 $ : :F
 MM)4:r*   c                 j    | j                  t        j                  fd| j                              S )zFReturns a TypeSpec representing a batch of objects with this TypeSpec.c                 &    | j                        S r#   )_batch)spec
batch_sizes    r(   r5   z,_LinearOperatorSpec._batch.<locals>.<lambda>  s    Z0 r*   r  r  r   r;   r  r&   r  s    `r(   r  z_LinearOperatorSpec._batch  s3    ::&&0     r*   c                 d    | j                  t        j                  d | j                              S )zBReturns a TypeSpec representing a single element of this TypeSpec.c                 "    | j                         S r#   )_unbatch)r  s    r(   r5   z._LinearOperatorSpec._unbatch.<locals>.<lambda>  s     r*   r  r  r  s     r(   r  z_LinearOperatorSpec._unbatch  s2    ::&&(     r*   N)rF   rG   rH   rI   	__slots__rb   classmethodr  r%   r=   ru  r  r  r  r  r  r-   r*   r(   r~  r~    sX    3M)6$ !N !NF=%  (
   r*   r~  c                     dj                  | j                        }t        |t        fd| i      } t	        j
                  dj                  ||            |       t        |j                        | _        | S )zBClass decorator to convert `LinearOperator`s to `CompositeTensor`.z{}Specr  z{}.{})	r   rF   rZ   r~  r   registerru  r  r$   )r  module_name	spec_name	spec_types       r(   make_composite_tensorr    se     oocll+)924|S6IJ)Egnn[)DEiPI334#.	*r*   c                 b   i }t               |D ]  }t        | |      t        | d|z         t        | di       j                  |      g}t        fd|D              r|D cg c]	  }|us| c}d   ||<   nt	        d| d|  d| d| d	| d
      || j
                  v r<||   7t        j                  ||         rt        j                  ||         }||||<   t        ||   t        j                  t        j                  f      s||   j                         ||<    |S c c}w )a+  Extract constructor kwargs to reconstruct `op`.

  Args:
    op: A `LinearOperator` instance.
    keys: A Python `tuple` of strings indicating the names of the constructor
      kwargs to extract from `op`.

  Returns:
    kwargs: A Python `dict` of kwargs to `op`'s constructor, keyed by `keys`.
  r  ra   c              3   &   K   | ]  }|u 
 y wr#   r-   )r.   r  	not_founds     r(   r0   z!_extract_attrs.<locals>.<genexpr>  s     
,!1I
,s   r   z4Could not determine an appropriate value for field `z` in object  `z#`. Looked for 
 1. an attr called `z`,
 2. an attr called `_z-`,
 3. an entry in `op.parameters` with key 'z'.)objectgetattrgetr  rM   ra  r
   r  constant_valuer   r   ndarraygenerictolist)opr  r  r  srcsr  
static_valr  s          @r(   r  r    sZ    &h) %aAy!72sQw	#BL"%))!Y7D 
,t
,,"9ay&819!<fQi@ Dd !!" $""# %778c	=> > 	B555&):O			vay	) //q	:
! &)&)bjj"**56)""$fQi)%* 
- :s   %	D,/D,c                    t        | t        j                        r| j                  S t        | t        j
                        r6t        j                  | j                  | j                  | j                        S t        j                  |       r*t        j                  | j                  | j                        S t        | t              rt        d | D              S t        | t         j"                        rt%        | j&                        S t        | t(              r t+        |       d | D              S t        | t,              r& t+        |       d | j/                         D              S | S )aX  Return (collection of) `TypeSpec`(s) for `value` if it includes `Tensor`s.

  If `value` is a `Tensor` or `CompositeTensor`, return its `TypeSpec`. If
  `value` is a collection containing `Tensor` values, recursively supplant them
  with their respective `TypeSpec`s in a collection of parallel stucture.

  If `value` is none of the above, return it unchanged.

  Args:
    value: a Python `object` to (possibly) turn into a (collection of)
    `tf.TypeSpec`(s).

  Returns:
    spec: the `TypeSpec` or collection of `TypeSpec`s corresponding to `value`
    or `value`, if no `Tensor`s are found.
  )r2   	trainablec              3   2   K   | ]  }t        |        y wr#   r  )r.   r  s     r(   r0   z1_extract_type_spec_recursively.<locals>.<genexpr>4  s     Aa.q1A   c              3   2   K   | ]  }t        |        y wr#   r  )r.   r4   s     r(   r0   z1_extract_type_spec_recursively.<locals>.<genexpr>8  s     HQ5a8Hr  c              3   <   K   | ]  \  }}|t        |      f  y wr#   r  )r.   r  r  s      r(   r0   z1_extract_type_spec_recursively.<locals>.<genexpr>:  s'      21a 9!<= 2s   )r   r   CompositeTensorr$   r   Variabler   VariableSpecr|   r2   r  r
   r  r	   
TensorSpecr  r   TrackableDataStructurer  __wrapped__tuplerZ   rj   r  )r'   s    r(   r  r    s   " '778y))* --5;;%//C C5!!!%++u{{;; tA5AAA==>)%*;*;<<u4;H%HHHt4; 2#(;;=2 2 2	,r*   c                 $    | j                  |      S r#   r   matrixr`   s     r(   _adjointr  D  s    		r*   c                 $    | j                  |      S r#   ro  inputr`   s     r(   	_choleskyr  I  s    		r*   c                 $    | j                  |      S r#   rp  )r  r`   r  padding_valuealigns        r(   rA  rA  Q  s     
	r*   c                 $    | j                  |      S r#   )r	  r  s     r(   _detr  \  s    			4	  r*   c                 L    | j                  |      }|r|j                         }|S r#   )r#  r   )r  r   r`   invs       r(   _inverser  a  s#    d#
++-C	*r*   c                 j    | j                   r| j                  r| j                  |      S t        d      )Nz5Expected matrix to be self-adjoint positive definite.)r^   r]   r  rM   r  s     r(   _logdetr  i  s0      V%;%;%%d++JKKr*   c                     |s|rt        d      |s|rt        d      t        | t              s,|j                  | | | |      }t	        j
                  |      S | j                  ||||      S )Nz'Transposing not supported at this time.z*Sparse methods not supported at this time.)r   r   r`   )rM   r   r   r   r   r   )abtranspose_atranspose_b	adjoint_a	adjoint_ba_is_sparseb_is_sparseoutput_typegrad_agrad_br`   adjoint_matmuls                r(   r   r   p  s     K
>
??K
A
BB	A~	&XX	"]	  N
 >>.))	
	 
 
> >r*   c                 `    t        | t              st        d      | j                  |||      S )NzOPassing in `matrix` as a Tensor and `rhs` as a LinearOperator is not supported.)r   r`   )r   r   rM   r  )r  r  r   r`   s       r(   r  r    s5     
FN	+
 8 9 9	c7	66r*   c                 $    | j                  |      S r#   rq  )r4   r`   s     r(   rE  rE    s    	
r*   )z	tf.linalgr#   )rC  r   r   
RIGHT_LEFT)FN)
FFFFFFNFFN)JrI   rw  rs  numpyr   tensorflow.python.frameworkr   r   r   r   r   r   r	   r
   r   r   tensorflow.python.moduler   tensorflow.python.opsr   r   r   r   r   r   r   r   r   r   r   r   tensorflow.python.platformr   r   tensorflow.python.trackabler   tensorflow.python.utilr   r   r   r    tensorflow.python.util.tf_exportr   __all__CompositeTensorGradientr!   Moduler  ABCMetar   BatchableTypeSpecr~  r  r  r  dispatch_for_typesr   r  r   r  rC  rA  rn  r  r  r  logdetr  r   r   r  r  rG  rE  r-   r*   r(   <module>r     s}   ' 
   8 A . + 9 4 3 3 1 : + + + , * 7 + > = ; 0 < 7 . + ' 1 6 
>55>F "#f5
MM#33s{{f5 $f5R)` )55 ` F#L$X V^^^< = V__n= > V--~> 

 ? VZZ8! 9! VZZ8 9 V]]N;L <L X__n= 	> >>< V\\>: 		7 ;7 V\\>: ;r*   