
    AVhW                        d 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 e	j4                  Zej8                  Zej:                  Zej<                  Zej@                  Z!  ed       ejD                  e!             e	jF                  Z$e	jJ                  Z&ejN                  Z(ejR                  Z*ejV                  Z+ejX                  Z,ejZ                  Z.ej^                  Z0ejb                  Z1  ed       ejD                  e0             ejd                  Z3ejh                  Z4ejj                  Z5e	jl                  Z7ejp                  Z9ejt                  Z;ejx                  Z<ejz                  Z=ej|                  Z>e	j~                  Z@ej                  ZB ed      ejD                  d9d              ZC ed      ejD                  d9d              ZDd ZEd ZFd ZGd ZHd ZI ed       ejD                  d9d!              ZJ ed"g #      	 	 	 d:d$       ZK ed%      ejD                  	 	 	 	 	 	 d;d&              ZLd' ZM ed(      ejD                  d<d)              ZNd* ZO ed+      ejD                  d=d,              ZP ed-      ejD                  d=d.              ZQ ed/      ejD                  d>d0              ZR ed1      ejD                  d>d2              ZS ed3      ejD                  d>d4              ZTd5 ZUd6 ZV ed7      ejD                  	 	 	 	 	 d?d8              ZWy)@zOperations for linear algebra.    N)constant_op)dtypes)ops)tensor_shape)	array_ops)array_ops_stack)	check_ops)cond)control_flow_ops)gen_linalg_ops)
linalg_ops)map_fn)math_ops)special_math_ops)stateless_random_ops
while_loop)dispatch)	tf_exportzlinalg.slogdetzlinalg.logmzlinalg.logdetc                 0   t        j                  |d| g      5  t        j                  |       }dt	        j
                  t	        j                  t	        j                  t        j                  |                  dg      z  cddd       S # 1 sw Y   yxY w)a  Computes log of the determinant of a hermitian positive definite matrix.

  ```python
  # Compute the determinant of a matrix while reducing the chance of over- or
  underflow:
  A = ... # shape 10 x 10
  det = tf.exp(tf.linalg.logdet(A))  # scalar
  ```

  Args:
    matrix:  A `Tensor`. Must be `float16`, `float32`, `float64`, `complex64`,
      or `complex128` with shape `[..., M, M]`.
    name:  A name to give this `Op`.  Defaults to `logdet`.

  Returns:
    The natural log of the determinant of `matrix`.

  @compatibility(numpy)
  Equivalent to numpy.linalg.slogdet, although no sign is returned since only
  hermitian positive definite matrices are supported.
  @end_compatibility
  logdet       @axisN)
r   
name_scoper   choleskyr   
reduce_sumlogrealr   matrix_diag_part)matrixnamechols      X/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/linalg/linalg_impl.pyr   r   D   su    6 ~~dHvh/ ""6*D$$X]]9#=#=d#CDET   s   A)BBzlinalg.adjointc                     t        j                  |d| g      5  t        j                  | d      } t        j                  | d      cddd       S # 1 sw Y   yxY w)ah  Transposes the last two dimensions of and conjugates tensor `matrix`.

  For example:

  ```python
  x = tf.constant([[1 + 1j, 2 + 2j, 3 + 3j],
                   [4 + 4j, 5 + 5j, 6 + 6j]])
  tf.linalg.adjoint(x)  # [[1 - 1j, 4 - 4j],
                        #  [2 - 2j, 5 - 5j],
                        #  [3 - 3j, 6 - 6j]]
  ```

  Args:
    matrix:  A `Tensor`. Must be `float16`, `float32`, `float64`, `complex64`,
      or `complex128` with shape `[..., M, M]`.
    name:  A name to give this `Op` (optional).

  Returns:
    The adjoint (a.k.a. Hermitian transpose a.k.a. conjugate transpose) of
    matrix.
  adjointr"   r#   T	conjugateN)r   r   convert_to_tensorr   matrix_transpose)r"   r#   s     r%   r'   r'   f   sM    0 ~~dIx0 >""69F%%f=> > >s   .AAc                    g d}|D cg c]"  }t        j                  || j                        $ }}t        j                  t        j                  |       d   t        j                  |       dd | j                        }t        j                  | |       }||d   |z  z   }t        j                  | |      }|d   |z  |d   |z  z   }||fS c c}w )z23rd-order Pade approximant for matrix exponential.)g      ^@g      N@g      (@Nbatch_shapedtype      r   	r   constantr1   r   eyer   shaper   matmul)r"   bxidentmatrix_2tmpmatrix_umatrix_vs           r%   _matrix_exp_pade3r@      s    !678{Av||,8!8
..oofb!//&)#2.LL% __VV,(1Q4%<#__VS)(qTH_qte|+(	8	 9s   'Cc                    g d}|D cg c]"  }t        j                  || j                        $ }}t        j                  t        j                  |       d   t        j                  |       dd | j                        }t        j                  | |       }t        j                  ||      }||d   |z  z   |d   |z  z   }t        j                  | |      }|d   |z  |d   |z  z   |d	   |z  z   }||fS c c}w )
z25th-order Pade approximant for matrix exponential.)g     @g     @g     @@g     @z@g      >@r.   Nr/      r2      r3   r   r4   )	r"   r9   r:   r;   r<   matrix_4r=   r>   r?   s	            r%   _matrix_exp_pade5rE      s    -!678{Av||,8!8
..oofb!//&)#2.LL% __VV,(__Xx0(1Q4(?"QqTE\1#__VS)(qTH_qth.1=(	8	 9s   'C4c                 B   g d}|D cg c]"  }t        j                  || j                        $ }}t        j                  t        j                  |       d   t        j                  |       dd | j                        }t        j                  | |       }t        j                  ||      }t        j                  ||      }||d   |z  z   |d   |z  z   |d   |z  z   }t        j                  | |      }|d   |z  |d	   |z  z   |d
   |z  z   |d   |z  z   }	||	fS c c}w )z27th-order Pade approximant for matrix exponential.)g    ~pAg    ~`Ag    @t>Ag    @Ag     @g     @g      L@r.   Nr/      rB   r2      rC   r3   r   r4   )
r"   r9   r:   r;   r<   rD   matrix_6r=   r>   r?   s
             r%   _matrix_exp_pade7rJ      s   I!678{Av||,8!8
..oofb!//&)#2.LL% __VV,(__Xx0(__Xx0(1Q4(?"QqTH_4qte|C#__VS)(qTH_qth.1@1Q4%<O(	8	 9s   'Dc                    g d}|D cg c]"  }t        j                  || j                        $ }}t        j                  t        j                  |       d   t        j                  |       dd | j                        }t        j                  | |       }t        j                  ||      }t        j                  ||      }t        j                  ||      }||d   |z  z   |d   |z  z   |d   |z  z   |d   |z  z   }t        j                  | |      }	|d	   |z  |d
   |z  z   |d   |z  z   |d   |z  z   |d   |z  z   }
|	|
fS c c}w )z29th-order Pade approximant for matrix exponential.)	g   ynBg   yn Bg    Ag   @
Ag    2|Ag    ~@Ag     @g     @g     V@r.   Nr/      rG   rB   r2      rH   rC   r3   r   r4   )r"   r9   r:   r;   r<   rD   rI   matrix_8r=   r>   r?   s              r%   _matrix_exp_pade9rO      sT   ! 788{Av||,8!8
..oofb!//&)#2.LL% __VV,(__Xx0(__Xx0(__Xx0(1 1Q4(?2QqTH_DdUl  __VS)(dXo!x'!A$/9AaD8OKdUl  
8	! 9s   'Ec                    g d}|D cg c]"  }t        j                  || j                        $ }}t        j                  t        j                  |       d   t        j                  |       dd | j                        }t        j                  | |       }t        j                  ||      }t        j                  ||      }t        j                  |||d   |z  z   |d   |z  z         |d   |z  z   |d   |z  z   |d	   |z  z   |d
   |z  z   }t        j                  | |      }|d   |z  |d   |z  z   |d   |z  z   }	t        j                  ||	      |d   |z  z   |d   |z  z   |d   |z  z   |d   |z  z   }
||
fS c c}w )z313th-order Pade approximant for matrix exponential.)g D`lCg D`\Cg `=Hb;Cg 	eCg JXBg  "5Bg  /cBg   \L8Bg   pķAg    syAg    S-Ag     @g     f@r.   Nr/      	   rL   rG   rB   r2      
   rM   rH   rC   r3   r   r4   )r"   r9   r:   r;   r<   rD   rI   tmp_ur>   tmp_vr?   s              r%   _matrix_exp_pade13rW      s   !
 788{Av||,8!8
..oofb!//&)#2.LL% __VV,(__Xx0(__Xx0(ooh1R58+; ;adXo MNdXo!x(*+A$/:<=aD5LI  __VU+(
B%(
QrUX-
-!x
?%ooh&181Q4(?JdXo!u%  
8	! 9s   'E<zlinalg.expmc                 p
   t        j                  |d| g      5  t        j                  | d      j                  dd ddgk(  rcddd       S j                  dd }|j	                         st        j                        dd }t        j                  t        j                  dgt        j                        dd fd            t        j                  t        j                  t        j                        t        j                  t        j                              d	z
        d      d
t
        j                  t
        j                  f   fdfdj                  t        j                   t        j"                  t        j$                  fv r d      }t        j&                  t        j(                  t        j*                  |z        t        j*                   d            z        d      t-              \  }}t/              \  }}t1        t        j2                  t        j4                   d            j                        z        \  }}	d}
 |
|||f       |
|||	f      nHj                  t        j6                  t        j8                  fv r d      }t        j&                  t        j(                  t        j*                  |z        t        j*                   d            z        d      t-              \  }}t/              \  }}t1              \  }}	t;              \  }}t=        t        j2                  t        j4                   d            j                        z        \  }}d}
 |
|||||f       |
|||	||f      nt?        dj                  z        t        j@                  t        j                              tC        jD                  tF        jH                  j                        tK        jL                  fdfd      }t        j                         d      }fd}fd}tO        jN                  ||||g      \  }}j                  j	                         sLt        j                  |t        j                  |t        j                  |      dd fd            cddd       S t        j                  ||jQ                  |j                  dd             cddd       S # 1 sw Y   yxY w)a  Computes the matrix exponential of one or more square matrices.

  $$exp(A) = \sum_{n=0}^\infty A^n/n!$$

  The exponential is computed using a combination of the scaling and squaring
  method and the Pade approximation. Details can be found in:
  Nicholas J. Higham, "The scaling and squaring method for the matrix
  exponential revisited," SIAM J. Matrix Anal. Applic., 26:1179-1193, 2005.

  The input is a tensor of shape `[..., M, M]` whose inner-most 2 dimensions
  form square matrices. The output is a tensor of the same shape as the input
  containing the exponential for all input submatrices `[..., :, :]`.

  Args:
    input: A `Tensor`. Must be `float16`, `float32`, `float64`, `complex64`, or
      `complex128` with shape `[..., M, M]`.
    name:  A name to give this `Op` (optional).

  Returns:
    the matrix exponential of the input.

  Raises:
    ValueError: An unsupported type is provided as input.

  @compatibility(scipy)
  Equivalent to scipy.linalg.expm
  @end_compatibility
  matrix_exponentialinputr(   r.   Nr   r   r   r3   .c                 D    t        j                  | j                        S N)r   r5   r1   )r:   l1_norms    r%   <lambda>z$matrix_exponential.<locals>.<lambda>  s    k**1gmm<     c           
      T   t        |       t        |      dz
  k(  sJ t        |       dk(  r:t        j                  t        j                   | d               |d   |d         S t        j                  t        j                   | d               |d    | dd  |dd              S )Nr2   r   )lenr   where_v2r   less)valscases_nest_whereconstr]   s     r%   rf   z'matrix_exponential.<locals>._nest_where  s    Y#e*q.(((	Ta!!MM'5a>2E!HeAhH 	H !!MM'5a>2E!HQR%),. 	.r_   gj%eg@r   )g#"ՀA?gNj?gC|@)g ,?g|zی@?gQi?gd @z3tf.linalg.expm does not support matrices of type %sc                  >    t        j                    z    z         S r\   )r   matrix_solve)uvs   r%   r^   z$matrix_exponential.<locals>.<lambda>H  s    :22A261q5A r_   c                  V    t        j                  t        j                               S r\   )r   fillr7   )r"   nans   r%   r^   z$matrix_exponential.<locals>.<lambda>I  s    	yv6< r_           c                 >     t        j                   fdd       S )Nc                  0    t        j                         S r\   r   rc   )imax_squaringss   r%   r^   z/matrix_exponential.<locals>.c.<locals>.<lambda>O  s    (--="A r_   c                  ,    t        j                  d      S )NF)r   r5    r_   r%   r^   z/matrix_exponential.<locals>.c.<locals>.<lambda>P  s    +"6"6u"= r_   )tf_condr
   )rs   _	is_finitert   s   ` r%   czmatrix_exponential.<locals>.cM  s    \\)A=? ?r_   c                     | dz   t        j                  t        j                  |       t        j                  ||      |      fS Nr2   )r   rb   r   rc   r8   )rs   r	squaringss     r%   r9   zmatrix_exponential.<locals>.bR  sA    UI&&
--9
%xq!'<aA A Ar_   ))r   r   r+   r7   is_fully_definedr   reshapeconcatr   
reduce_maxr   abssizenewaxisr1   r   float16float32	complex64maximumfloorr   r@   rE   rJ   castpowfloat64
complex128rO   rW   
ValueErrorry   r   r5   nprn   rw   r
   r   concatenate)rZ   r#   r0   maxnormu3v3u5v5u7v7condsu9v9u13v13resultrs   rz   r9   rx   rf   rg   ry   r]   r"   rt   rn   r~   rj   rk   s                       @@@@@@@@@@r%   rY   rY      s   > ~~d05': TQ""5w7F||BCQF"TQ TQ ,,s#K'')OOF+CR0k 	  2$	(?(D!EANPF!!LL 	 781<	> 	 i''):)::	<G =E. ||8H8HII'(g""
..ll7W,-U3Z0HHJKLNi !(fb" (fb" 

--U3Z;V\\
JKLfb" ?e
eb"b\
*a
eb"b\
*a	&..&*;*;<	<'(g""
..ll7W,-U3Z0HHJKLNi !(fb" (fb" (fb" (fb"#

--U3Z;V\\
JKLhc3?e
eb"b"c2
3a
eb"b"c2
3aL||$ % % ""8#6#6w#?@I


rvvv||
4C\\A<>F ''	2Mc
A?
A %%aQK8IAv<<((*



K)@)EFQ
OQcTQ TQh V[%<%<V\\"#=N%OPiTQ TQ TQs   -T,RT,11T,,T5zlinalg.banded_triangular_solve)v1c                     t        j                  |d| |g      5  t        j                  | |||      cddd       S # 1 sw Y   yxY w)aJ  Solve triangular systems of equations with a banded solver.

  `bands` is a tensor of shape `[..., K, M]`, where `K` represents the number
  of bands stored. This corresponds to a batch of `M` by `M` matrices, whose
  `K` subdiagonals (when `lower` is `True`) are stored.

  This operator broadcasts the batch dimensions of `bands` and the batch
  dimensions of `rhs`.


  Examples:

  Storing 2 bands of a 3x3 matrix.
  Note that first element in the second row is ignored due to
  the 'LEFT_RIGHT' padding.

  >>> x = [[2., 3., 4.], [1., 2., 3.]]
  >>> x2 = [[2., 3., 4.], [10000., 2., 3.]]
  >>> y = tf.zeros([3, 3])
  >>> z = tf.linalg.set_diag(y, x, align='LEFT_RIGHT', k=(-1, 0))
  >>> z
  <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
  array([[2., 0., 0.],
         [2., 3., 0.],
         [0., 3., 4.]], dtype=float32)>
  >>> soln = tf.linalg.banded_triangular_solve(x, tf.ones([3, 1]))
  >>> soln
  <tf.Tensor: shape=(3, 1), dtype=float32, numpy=
  array([[0.5 ],
         [0.  ],
         [0.25]], dtype=float32)>
  >>> are_equal = soln == tf.linalg.banded_triangular_solve(x2, tf.ones([3, 1]))
  >>> print(tf.reduce_all(are_equal).numpy())
  True
  >>> are_equal = soln == tf.linalg.triangular_solve(z, tf.ones([3, 1]))
  >>> print(tf.reduce_all(are_equal).numpy())
  True

  Storing 2 superdiagonals of a 4x4 matrix. Because of the 'LEFT_RIGHT' padding
  the last element of the first row is ignored.

  >>> x = [[2., 3., 4., 5.], [-1., -2., -3., -4.]]
  >>> y = tf.zeros([4, 4])
  >>> z = tf.linalg.set_diag(y, x, align='LEFT_RIGHT', k=(0, 1))
  >>> z
  <tf.Tensor: shape=(4, 4), dtype=float32, numpy=
  array([[-1.,  2.,  0.,  0.],
         [ 0., -2.,  3.,  0.],
         [ 0.,  0., -3.,  4.],
         [ 0.,  0., -0., -4.]], dtype=float32)>
  >>> soln = tf.linalg.banded_triangular_solve(x, tf.ones([4, 1]), lower=False)
  >>> soln
  <tf.Tensor: shape=(4, 1), dtype=float32, numpy=
  array([[-4.       ],
         [-1.5      ],
         [-0.6666667],
         [-0.25     ]], dtype=float32)>
  >>> are_equal = (soln == tf.linalg.triangular_solve(
  ...   z, tf.ones([4, 1]), lower=False))
  >>> print(tf.reduce_all(are_equal).numpy())
  True


  Args:
    bands: A `Tensor` describing the bands of the left hand side, with shape
      `[..., K, M]`. The `K` rows correspond to the diagonal to the `K - 1`-th
      diagonal (the diagonal is the top row) when `lower` is `True` and
      otherwise the `K - 1`-th superdiagonal to the diagonal (the diagonal is
      the bottom row) when `lower` is `False`. The bands are stored with
      'LEFT_RIGHT' alignment, where the superdiagonals are padded on the right
      and subdiagonals are padded on the left. This is the alignment cuSPARSE
      uses.  See  `tf.linalg.set_diag` for more details.
    rhs: A `Tensor` of shape [..., M] or [..., M, N] and with the same dtype as
      `diagonals`. Note that if the shape of `rhs` and/or `diags` isn't known
      statically, `rhs` will be treated as a matrix rather than a vector.
    lower: An optional `bool`. Defaults to `True`. Boolean indicating whether
      `bands` represents a lower or upper triangular matrix.
    adjoint: An optional `bool`. Defaults to `False`. Boolean indicating whether
      to solve with the matrix's block-wise adjoint.
    name:  A name to give this `Op` (optional).

  Returns:
    A `Tensor` of shape [..., M] or [..., M, N] containing the solutions.
  banded_triangular_solve)lowerr'   N)r   r   r   r   )bandsrhsr   r'   r#   s        r%   r   r   ^  sF    v ~~d5s|D 211s%22 2 2s	   =Azlinalg.tridiagonal_solvec           	      &   |r|st        d      |dk(  rt        | ||||||      S |dk(  r/t        | t        t        f      rt        |       dk7  rt        d      | \  }}	}
|
j                  dd j                  |	j                  dd       r+|j                  dd j                  |	j                  dd       s:t        dj                  |
j                  |	j                  |j                              t        j                  |	j                  d         fd	} ||
d
ddg      }
 ||dddg      }t        j                  ||	|
fd      } t        | ||||||      S |dk(  rt        j                  | j                  d         }t        j                  | j                  d         }|r"|r ||k7  rt        dj                  ||            |xs |t        j                  | ddd      } t        | ||||||      S t        dj                  |            )a/  Solves tridiagonal systems of equations.

  The input can be supplied in various formats: `matrix`, `sequence` and
  `compact`, specified by the `diagonals_format` arg.

  In `matrix` format, `diagonals` must be a tensor of shape `[..., M, M]`, with
  two inner-most dimensions representing the square tridiagonal matrices.
  Elements outside of the three diagonals will be ignored.

  In `sequence` format, `diagonals` are supplied as a tuple or list of three
  tensors of shapes `[..., N]`, `[..., M]`, `[..., N]` representing
  superdiagonals, diagonals, and subdiagonals, respectively. `N` can be either
  `M-1` or `M`; in the latter case, the last element of superdiagonal and the
  first element of subdiagonal will be ignored.

  In `compact` format the three diagonals are brought together into one tensor
  of shape `[..., 3, M]`, with last two dimensions containing superdiagonals,
  diagonals, and subdiagonals, in order. Similarly to `sequence` format,
  elements `diagonals[..., 0, M-1]` and `diagonals[..., 2, 0]` are ignored.

  The `compact` format is recommended as the one with best performance. In case
  you need to cast a tensor into a compact format manually, use `tf.gather_nd`.
  An example for a tensor of shape [m, m]:

  ```python
  rhs = tf.constant([...])
  matrix = tf.constant([[...]])
  m = matrix.shape[0]
  dummy_idx = [0, 0]  # An arbitrary element to use as a dummy
  indices = [[[i, i + 1] for i in range(m - 1)] + [dummy_idx],  # Superdiagonal
           [[i, i] for i in range(m)],                          # Diagonal
           [dummy_idx] + [[i + 1, i] for i in range(m - 1)]]    # Subdiagonal
  diagonals=tf.gather_nd(matrix, indices)
  x = tf.linalg.tridiagonal_solve(diagonals, rhs)
  ```

  Regardless of the `diagonals_format`, `rhs` is a tensor of shape `[..., M]` or
  `[..., M, K]`. The latter allows to simultaneously solve K systems with the
  same left-hand sides and K different right-hand sides. If `transpose_rhs`
  is set to `True` the expected shape is `[..., M]` or `[..., K, M]`.

  The batch dimensions, denoted as `...`, must be the same in `diagonals` and
  `rhs`.

  The output is a tensor of the same shape as `rhs`: either `[..., M]` or
  `[..., M, K]`.

  The op isn't guaranteed to raise an error if the input matrix is not
  invertible. `tf.debugging.check_numerics` can be applied to the output to
  detect invertibility problems.

  **Note**: with large batch sizes, the computation on the GPU may be slow, if
  either `partial_pivoting=True` or there are multiple right-hand sides
  (`K > 1`). If this issue arises, consider if it's possible to disable pivoting
  and have `K = 1`, or, alternatively, consider using CPU.

  On CPU, solution is computed via Gaussian elimination with or without partial
  pivoting, depending on `partial_pivoting` parameter. On GPU, Nvidia's cuSPARSE
  library is used: https://docs.nvidia.com/cuda/cusparse/index.html#gtsv

  Args:
    diagonals: A `Tensor` or tuple of `Tensor`s describing left-hand sides. The
      shape depends of `diagonals_format`, see description above. Must be
      `float32`, `float64`, `complex64`, or `complex128`.
    rhs: A `Tensor` of shape [..., M] or [..., M, K] and with the same dtype as
      `diagonals`. Note that if the shape of `rhs` and/or `diags` isn't known
      statically, `rhs` will be treated as a matrix rather than a vector.
    diagonals_format: one of `matrix`, `sequence`, or `compact`. Default is
      `compact`.
    transpose_rhs: If `True`, `rhs` is transposed before solving (has no effect
      if the shape of rhs is [..., M]).
    conjugate_rhs: If `True`, `rhs` is conjugated before solving.
    name:  A name to give this `Op` (optional).
    partial_pivoting: whether to perform partial pivoting. `True` by default.
      Partial pivoting makes the procedure more stable, but slower. Partial
      pivoting is unnecessary in some cases, including diagonally dominant and
      symmetric positive definite matrices (see e.g. theorem 9.12 in [1]).
    perturb_singular: whether to perturb singular matrices to return a finite
      result. `False` by default. If true, solutions to systems involving
      a singular matrix will be computed by perturbing near-zero pivots in
      the partially pivoted LU decomposition. Specifically, tiny pivots are
      perturbed by an amount of order `eps * max_{ij} |U(i,j)|` to avoid
      overflow. Here `U` is the upper triangular part of the LU decomposition,
      and `eps` is the machine precision. This is useful for solving
      numerically singular systems when computing eigenvectors by inverse
      iteration.
      If `partial_pivoting` is `False`, `perturb_singular` must be `False` as
      well.

  Returns:
    A `Tensor` of shape [..., M] or [..., M, K] containing the solutions.
    If the input matrix is singular, the result is undefined.

  Raises:
    ValueError: Is raised if any of the following conditions hold:
      1. An unsupported type is provided as input,
      2. the input tensors have incorrect shapes,
      3. `perturb_singular` is `True` but `partial_pivoting` is not.
    UnimplementedError: Whenever `partial_pivoting` is true and the backend is
      XLA, or whenever `perturb_singular` is true and the backend is
      XLA or GPU.

  [1] Nicholas J. Higham (2002). Accuracy and Stability of Numerical Algorithms:
  Second Edition. SIAM. p. 175. ISBN 978-0-89871-802-7.

  z5partial_pivoting must be True if perturb_singular is.compactsequencerB   z0Expected diagonals to be a sequence of length 3.Nr   zoTensors representing the three diagonals must have the same shape,except for the last dimension, got {}, {}, {}c                 J   t        j                  | j                  d         }|r|k(  r| S |dz
  k(  rKt        t	        | j                        dz
        D cg c]  }ddg c}|gz   }t        j                  | |      S t        dj                  |dz
  |            c c}w )Nr   r2   r   z/Expected {} to be have length {} or {}, got {}.)	r   dimension_valuer7   rangera   r   padr   format)tr#   last_dim_paddingnrx   paddingsms         r%   pad_if_necessaryz+tridiagonal_solve.<locals>.pad_if_necessaryH  s    

&
&qwwr{
3a!q&	
a!e%*3qww<!+;%<=aV=%&'}}Q))HOO
1q5!   >s   B subdiagonalr2   r   superdiagonalr.   r   r"   CExpected last two dimensions of diagonals to be same, got {} and {}r   r2   ro   
LEFT_RIGHTkpadding_valuealignz!Unrecognized diagonals_format: {})r   !_tridiagonal_solve_compact_format
isinstancetuplelistra   r7   is_compatible_withr   r   r   r   stackr   r!   )	diagonalsr   diagonals_formattranspose_rhsconjugate_rhsr#   partial_pivotingperturb_singular	superdiagmaindiagsubdiagr   m1m2r   s                 @r%   tridiagonal_solver     s2   h .
L
MM",Y]-:<L-=tE E #i%/3y>Q3FIJJ#, IxMM#211(.."2EFOOCR 33HNN3B4GH::@&mmX^^Y__;>? ?
 	$$X^^B%78A	 w1v>G OaVDI%%y(G&D2NI,Y]-:<L-=tE E !		%	%ioob&9	:B		%	%ioob&9	:B	bR2X
O6"b>  	bA**WBlDI,Y]-:<L-=tE E 	6==>NOPPr_   c           	           j                   j                  j                   j                  }}|r|dk  rt        dj                  |            |r,||k7  r'||dz
  k7  rt        dj                  |dz
  ||            |rf j                   dd j	                  j                   d|dz
         s8t        dj                   j                   dd j                   d|dz
                j                   d   r9 j                   d   dk7  r't        d	j                   j                   d                fd
}	|rk|ri||dz
  k(  ra|rt        j                        t        j                  d       |	        t        j                  t        j                   |||      d      S |rt        j                  |      n|rt        j                         |	        t        j                   |||      S )zCHelper function used after the input has been cast to compact form.r3   z2Expected diagonals to have rank at least 2, got {}r2   z/Expected the rank of rhs to be {} or {}, got {}Nr.   z'Batch shapes {} and {} are incompatiblerB   zExpected 3 diagonals got {}c                       j                   d   rej                   d   rU j                   d   j                   d   k7  r5t        dj                   j                   d   j                   d               y y y )Nr   r.   zRExpected number of left-hand sided and right-hand sides to be equal, got {} and {})r7   r   r   )r   r   s   r%   check_num_lhs_matches_num_rhszH_tridiagonal_solve_compact_format.<locals>.check_num_lhs_matches_num_rhs  ss    		"syy}, ::@&$??2.		";?@ @ 	- !.r_   r   r)   )r7   rankr   r   r   r   conjr   expand_dimssqueezer   r   r,   )
r   r   r   r   r   r   r#   
diags_rankrhs_rankr   s
   ``        r%   r   r   l  s    #--syy~~h* A~
>
E
E  H
*x:>/IHOO
q.*h0 1 1"-@@		/:>"$@GG
//#2
		/:> :< = = __RY__R0A5
299)//":MN
OO@ *Z!^!;MM#c


R
(C!#$$Y5E%5t	=>@B B 

$
$SM
BC
--
C!		%	%i6F&6
> >r_   zlinalg.tridiagonal_matmulc                 ~   |dk(  r| ddddf   }| ddddf   }| ddddf   }n|dk(  r| \  }}}n|dk(  rt        j                  | j                  d	         }t        j                  | j                  d
         }|r"|r ||k7  rt        dj	                  ||            t        j                  | ddd      }	|	ddddf   }|	ddddf   }|	ddddf   }nt        d|z        t        j                  |d
      }t        j                  |d
      }t        j                  |d
      }t        j                  |||||      S )a  Multiplies tridiagonal matrix by matrix.

  `diagonals` is representation of 3-diagonal NxN matrix, which depends on
  `diagonals_format`.

  In `matrix` format, `diagonals` must be a tensor of shape `[..., M, M]`, with
  two inner-most dimensions representing the square tridiagonal matrices.
  Elements outside of the three diagonals will be ignored.

  If `sequence` format, `diagonals` is list or tuple of three tensors:
  `[superdiag, maindiag, subdiag]`, each having shape [..., M]. Last element
  of `superdiag` first element of `subdiag` are ignored.

  In `compact` format the three diagonals are brought together into one tensor
  of shape `[..., 3, M]`, with last two dimensions containing superdiagonals,
  diagonals, and subdiagonals, in order. Similarly to `sequence` format,
  elements `diagonals[..., 0, M-1]` and `diagonals[..., 2, 0]` are ignored.

  The `sequence` format is recommended as the one with the best performance.

  `rhs` is matrix to the right of multiplication. It has shape `[..., M, N]`.

  Example:

  ```python
  superdiag = tf.constant([-1, -1, 0], dtype=tf.float64)
  maindiag = tf.constant([2, 2, 2], dtype=tf.float64)
  subdiag = tf.constant([0, -1, -1], dtype=tf.float64)
  diagonals = [superdiag, maindiag, subdiag]
  rhs = tf.constant([[1, 1], [1, 1], [1, 1]], dtype=tf.float64)
  x = tf.linalg.tridiagonal_matmul(diagonals, rhs, diagonals_format='sequence')
  ```

  Args:
    diagonals: A `Tensor` or tuple of `Tensor`s describing left-hand sides. The
      shape depends of `diagonals_format`, see description above. Must be
      `float32`, `float64`, `complex64`, or `complex128`.
    rhs: A `Tensor` of shape [..., M, N] and with the same dtype as `diagonals`.
    diagonals_format: one of `sequence`, or `compact`. Default is `compact`.
    name:  A name to give this `Op` (optional).

  Returns:
    A `Tensor` of shape [..., M, N] containing the result of multiplication.

  Raises:
    ValueError: An unsupported type is provided as input, or when the input
    tensors have incorrect shapes.
  r   .r   Nr2   r3   r   r"   r   r.   r   r   ro   r   r   z!Unrecognized diagonals_format: %s)
r   r   r7   r   r   r   r!   r   r   tridiagonal_mat_mul)
r   r   r   r#   r   r   r   r   r   diagss
             r%   tridiagonal_matmulr     s`   f "#q!)$Ia#HQ	"G:%#, Ix8#		%	%ioob&9	:B		%	%ioob&9	:B	bR2X
O6"b>  &&WBlDEc1ai IS!QYHCAIG
8;KK
LL ##Ir2)""8R0(!!'2.'		'	'	8Wc4	PPr_   c                    g }| j                   j                  s.t        dj                  | j                   j                              | j
                  _| j
                  j                  I| j
                  j                  dk  r.t        dj                  | j
                  j                              |S |r'|j                  t        j                  | dd             |S )z&Checks that input is a `float` matrix.z2Input `a` must have `float`-like `dtype` (saw {}).r3   z4Input `a` must have at least 2 dimensions (saw: {}).z*Input `a` must have at least 2 dimensions.r   message)r1   is_floating	TypeErrorr   r#   r7   r   r   appendr	   assert_rank_at_least)avalidate_args
assertionss      r%   _maybe_validate_matrixr     s    *	
		
   &qww|| 46 6WWQWW\\5ww||a $$*F177<<$8: : 
	 &&AK	MN 
r_   zlinalg.matrix_rankc                    t        j                  |xs d      5  t        j                  | t        j                  d      } t        | |      }|r3t        j                  |      5  t        j                  |       } ddd       t        | d      }|| j                  dd j                         r1t        j                  | j                  dd j                               }n+t        j                   t        j                  |       dd       }t        j"                  | j$                  j&                        j(                  }|t        j*                  || j$                        z  t        j                   |dd	
      z  }t        j,                  t        j*                  ||kD  t        j.                        d      cddd       S # 1 sw Y   FxY w# 1 sw Y   yxY w)a  Compute the matrix rank of one or more matrices.

  Args:
    a: (Batch of) `float`-like matrix-shaped `Tensor`(s) which are to be
      pseudo-inverted.
    tol: Threshold below which the singular value is counted as 'zero'.
      Default value: `None` (i.e., `eps * max(rows, cols) * max(singular_val)`).
    validate_args: When `True`, additional assertions might be embedded in the
      graph.
      Default value: `False` (i.e., no graph assertions are added).
    name: Python `str` prefixed to ops created by this function.
      Default value: 'matrix_rank'.

  Returns:
    matrix_rank: (Batch of) `int32` scalars representing the number of non-zero
      singular values.
  matrix_rankr   
dtype_hintr#   NF)
compute_uvr.   r   T)r   keepdimsr   )r   r   r+   r   r   r   control_dependenciesr   identitysvdr7   r   r   maxas_listr   r   finfor1   as_numpy_dtypeepsr   r   int32)r   tolr   r#   r   sr   r   s           r%   r   r      sl   ( ~~d+m, NaFNNEA'=9J##J/ "q!"A% A
{
''"#,	(	(	*FF17723<'')*	 223 78HHQWW++,00c
a)
)


ab4
89 
 x}}QWfllC"M!N N" "	N Ns%   A
G$F>:D:G>G	GGzlinalg.pinvc           	          t        j                  |xs d      5  t        j                   d       t         |      }|r3t        j                  |      5  t        j                          ddd        j                  j                  }| fd} |d      } |d      }t        |t              r&t        |t              rt        t        ||            }	n*t        j                  t        j                  ||      |      }	d|	z  t!        j"                  |      j$                  z  }t        j                  ||d	
      }t'         dd      \  }
}}|t        j(                  |
d      z  }t        j*                  |
t        j,                  |d      kD  |
t!        j.                  t         j0                  |            }
t        j2                  |t        j,                  |
d      z  |d      } j4                  _ j4                  j6                  I|j9                   j4                  dd j;                   j4                  d    j4                  d   g             |cddd       S # 1 sw Y   xY w# 1 sw Y   yxY w)a
  Compute the Moore-Penrose pseudo-inverse of one or more matrices.

  Calculate the [generalized inverse of a matrix](
  https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse) using its
  singular-value decomposition (SVD) and including all large singular values.

  The pseudo-inverse of a matrix `A`, is defined as: 'the matrix that 'solves'
  [the least-squares problem] `A @ x = b`,' i.e., if `x_hat` is a solution, then
  `A_pinv` is the matrix such that `x_hat = A_pinv @ b`. It can be shown that if
  `U @ Sigma @ V.T = A` is the singular value decomposition of `A`, then
  `A_pinv = V @ inv(Sigma) U^T`. [(Strang, 1980)][1]

  This function is analogous to [`numpy.linalg.pinv`](
  https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.pinv.html).
  It differs only in default value of `rcond`. In `numpy.linalg.pinv`, the
  default `rcond` is `1e-15`. Here the default is
  `10. * max(num_rows, num_cols) * np.finfo(dtype).eps`.

  Args:
    a: (Batch of) `float`-like matrix-shaped `Tensor`(s) which are to be
      pseudo-inverted.
    rcond: `Tensor` of small singular value cutoffs.  Singular values smaller
      (in modulus) than `rcond` * largest_singular_value (again, in modulus) are
      set to zero. Must broadcast against `tf.shape(a)[:-2]`.
      Default value: `10. * max(num_rows, num_cols) * np.finfo(a.dtype).eps`.
    validate_args: When `True`, additional assertions might be embedded in the
      graph.
      Default value: `False` (i.e., no graph assertions are added).
    name: Python `str` prefixed to ops created by this function.
      Default value: 'pinv'.

  Returns:
    a_pinv: (Batch of) pseudo-inverse of input `a`. Has same shape as `a` except
      rightmost two dimensions are transposed.

  Raises:
    TypeError: if input `a` does not have `float`-like `dtype`.
    ValueError: if input `a` has fewer than 2 dimensions.

  #### Examples

  ```python
  import tensorflow as tf
  import tensorflow_probability as tfp

  a = tf.constant([[1.,  0.4,  0.5],
                   [0.4, 0.2,  0.25],
                   [0.5, 0.25, 0.35]])
  tf.matmul(tf.linalg.pinv(a), a)
  # ==> array([[1., 0., 0.],
               [0., 1., 0.],
               [0., 0., 1.]], dtype=float32)

  a = tf.constant([[1.,  0.4,  0.5,  1.],
                   [0.4, 0.2,  0.25, 2.],
                   [0.5, 0.25, 0.35, 3.]])
  tf.matmul(tf.linalg.pinv(a), a)
  # ==> array([[ 0.76,  0.37,  0.21, -0.02],
               [ 0.37,  0.43, -0.33,  0.02],
               [ 0.21, -0.33,  0.81,  0.01],
               [-0.02,  0.02,  0.01,  1.  ]], dtype=float32)
  ```

  #### References

  [1]: G. Strang. 'Linear Algebra and Its Applications, 2nd Ed.' Academic Press,
       Inc., 1980, pp. 139-142.
  pinvr   r(   Nc                     t        j                  j                  |          }||S t        j                        |    S r\   )r   r   r7   r   )dimdim_valr   s     r%   get_dim_sizezpinv.<locals>.get_dim_sizez  s:    ..qwws|<.q!#&&r_   r.   r   g      $@rcond)r1   r#   FT)full_matricesr   r   )	adjoint_b)r   r   r+   r   r   r   r   r1   r   r   intfloatr   r   r   r   r   r   r   r   r   rb   expand_dims_v2arrayinfr8   r7   r   	set_shaper   )r   r   r   r#   r   r1   r   num_rowsnum_colsmax_rows_colssingular_valuesleft_singular_vectorsright_singular_vectorscutoffa_pinvs   `              r%   r   r   '  s   N ~~dnf% 8ac*A'=9J##J/ "q!" GG""E}' b!hb!h	Hc	"z(C'@c(H56 Xx0%9M!BHHUO$7$77e!!%u7CE 		4	1	 X((rBBF(()2262>>
!O __!9!9/2!NNF
 	wwqww||7qwws|//aggbk0JKLq8 8
" "8 8s$   ;I,I,G)I,I)	$I,,I5zlinalg.lu_solvec           	      X   t        j                  |xs d      5  t        j                  | t        j                  d      } t        j                  |t        j
                  d      }t        j                  || j                  d      }t        | |||      }|r]t        j                  |      5  t        j                  |       } t        j                  |      }t        j                  |      }ddd       |j                  j                  dk(  r3|j                  j                  dk(  rt        j                  ||d	
      }nct        j                  |      }t        j                  |dd	 t        j                  |      dd       }|d	   |d   }
}	t        j                  ||	|
ggd
      }t        j                   ||      }t        j"                  |d|	|
g      }t        j                   ||dd       }t        j"                  |d|	g      }t%        j&                  |      }t        j                   t%        j(                  |      ddt        j*                  f   ||	g      }t-        j.                  ||gd
      }t        j0                  ||      }t        j"                  ||      }t3        t5        | dd      t        j6                  t        j                  |       dd | j                              }t9        | t9        ||      d      cddd       S # 1 sw Y   'xY w# 1 sw Y   yxY w)a  Solves systems of linear eqns `A X = RHS`, given LU factorizations.

  Note: this function does not verify the implied matrix is actually invertible
  nor is this condition checked even when `validate_args=True`.

  Args:
    lower_upper: `lu` as returned by `tf.linalg.lu`, i.e., if `matmul(P,
      matmul(L, U)) = X` then `lower_upper = L + U - eye`.
    perm: `p` as returned by `tf.linag.lu`, i.e., if `matmul(P, matmul(L, U)) =
      X` then `perm = argmax(P)`.
    rhs: Matrix-shaped float `Tensor` representing targets for which to solve;
      `A X = RHS`. To handle vector cases, use: `lu_solve(..., rhs[...,
        tf.newaxis])[..., 0]`.
    validate_args: Python `bool` indicating whether arguments should be checked
      for correctness. Note: this function does not verify the implied matrix is
        actually invertible, even when `validate_args=True`.
      Default value: `False` (i.e., don't validate arguments).
    name: Python `str` name given to ops managed by this object.
      Default value: `None` (i.e., 'lu_solve').

  Returns:
    x: The `X` in `A @ X = RHS`.

  #### Examples

  ```python
  import numpy as np
  import tensorflow as tf
  import tensorflow_probability as tfp

  x = [[[1., 2],
        [3, 4]],
       [[7, 8],
        [3, 4]]]
  inv_x = tf.linalg.lu_solve(*tf.linalg.lu(x), rhs=tf.eye(2))
  tf.assert_near(tf.matrix_inverse(x), inv_x)
  # ==> True
  ```

  lu_solvelower_upperr   permr   Nr3   r2   r.   r   r   r   	num_lower	num_upperr1   F)r   )r   r   r+   r   r   r   r1   _lu_solve_assertionsr   r   r   r7   r   gatherbroadcast_dynamic_shaper   broadcast_tor   r   reduce_prodr   r   r   r   	gather_ndset_diag	band_partonestriangular_solve)r  r  r   r   r#   r   permuted_rhs	rhs_shapebroadcast_batch_shapedr   rhs_broadcast_shapebroadcast_rhsbroadcast_permbroadcast_batch_sizebroadcast_batch_indicesr   s                    r%   r  r    s   X ~~d(j) 3'']DK  &,,VLD


0A0A
NC%k4mLJ##J/ &((5!!$'  %&
 			!

1 4%%c4b9l //#&i'??
CR.
//$

$& r]IbMa%,,.CaV-L235  ,,S2EFm''AqzBm !--d4G4LMn (("aAn%112GH ) 6 6
..-
.q)2C2C/C
D
#!% ',,"N
3">n ((Gl&&|5HIl+q9OOK("-[5F5F	HIE -a3 3& &3 3s&   BL .A L.HL L	L  L)zlinalg.lu_matrix_inversec                 >   t        j                  |xs d      5  t        j                  | t        j                  d      } t        j                  |t        j
                  d      }t        | ||      }|rHt        j                  |      5  t        j                  |       } t        j                  |      }ddd       t        j                  |       }t        | |t        |d   |dd | j                        d	
      cddd       S # 1 sw Y   RxY w# 1 sw Y   yxY w)a  Computes the inverse given the LU decomposition(s) of one or more matrices.

  This op is conceptually identical to,

  ```python
  inv_X = tf.lu_matrix_inverse(*tf.linalg.lu(X))
  tf.assert_near(tf.matrix_inverse(X), inv_X)
  # ==> True
  ```

  Note: this function does not verify the implied matrix is actually invertible
  nor is this condition checked even when `validate_args=True`.

  Args:
    lower_upper: `lu` as returned by `tf.linalg.lu`, i.e., if `matmul(P,
      matmul(L, U)) = X` then `lower_upper = L + U - eye`.
    perm: `p` as returned by `tf.linag.lu`, i.e., if `matmul(P, matmul(L, U)) =
      X` then `perm = argmax(P)`.
    validate_args: Python `bool` indicating whether arguments should be checked
      for correctness. Note: this function does not verify the implied matrix is
        actually invertible, even when `validate_args=True`.
      Default value: `False` (i.e., don't validate arguments).
    name: Python `str` name given to ops managed by this object.
      Default value: `None` (i.e., 'lu_matrix_inverse').

  Returns:
    inv_x: The matrix_inv, i.e.,
      `tf.matrix_inverse(tf.linalg.lu_reconstruct(lu, perm))`.

  #### Examples

  ```python
  import numpy as np
  import tensorflow as tf
  import tensorflow_probability as tfp

  x = [[[3., 4], [1, 2]],
       [[7., 8], [3, 4]]]
  inv_x = tf.linalg.lu_matrix_inverse(*tf.linalg.lu(x))
  tf.assert_near(tf.matrix_inverse(x), inv_x)
  # ==> True
  ```

  lu_matrix_inverser  r   r  Nr   r.   r/   F)r   r   )r   r   r+   r   r   r   lu_reconstruct_assertionsr   r   r   r7   r  r6   r1   )r  r  r   r#   r   r7   s         r%   r*  r*    s    ` ~~d112 '']DK  &,,VLD*;mLJ##J/ (((5!!$'( OOK(Eb	uSbz9J9JK	 ( ( s%   A1D+D6ADD	DDzlinalg.lu_reconstructc           	         t        j                  |xs d      5  t        j                  | t        j                  d      } t        j                  |t        j
                  d      }t        | ||      }|rHt        j                  |      5  t        j                  |       } t        j                  |      }ddd       t        j                  |       }t        t        | dd      t        j                  |dd | j                  	            }t        | dd      }t        j                   ||      }| j                  /| j                  j"                  | j                  j"                  d
k7  rt        j$                  |dd       }	|d   }
t        j&                  ||	|
|
g      }t        j&                  ||	|
g      }t)        j(                  t        j*                  |      }t        j,                  t        j.                  |	      ddt        j0                  f   |	|
g      }t        j2                  |t5        j6                  ||gd            }t        j&                  ||      }n)t        j8                  |t        j*                  |            }|j;                  | j                         |cddd       S # 1 sw Y   xY w# 1 sw Y   yxY w)a  The reconstruct one or more matrices from their LU decomposition(s).

  Args:
    lower_upper: `lu` as returned by `tf.linalg.lu`, i.e., if `matmul(P,
      matmul(L, U)) = X` then `lower_upper = L + U - eye`.
    perm: `p` as returned by `tf.linag.lu`, i.e., if `matmul(P, matmul(L, U)) =
      X` then `perm = argmax(P)`.
    validate_args: Python `bool` indicating whether arguments should be checked
      for correctness.
      Default value: `False` (i.e., don't validate arguments).
    name: Python `str` name given to ops managed by this object.
      Default value: `None` (i.e., 'lu_reconstruct').

  Returns:
    x: The original input to `tf.linalg.lu`, i.e., `x` as in,
      `lu_reconstruct(*tf.linalg.lu(x))`.

  #### Examples

  ```python
  import numpy as np
  import tensorflow as tf
  import tensorflow_probability as tfp

  x = [[[3., 4], [1, 2]],
       [[7., 8], [3, 4]]]
  x_reconstructed = tf.linalg.lu_reconstruct(*tf.linalg.lu(x))
  tf.assert_near(x, x_reconstructed)
  # ==> True
  ```

  lu_reconstructr  r   r  Nr   r   r  r  r3   r.   r   )r   r   r+   r   r   r   r+  r   r   r   r7   r  r  r  r1   r   r8   r   r  r   r   invert_permutationr  r   r   r  r   r   r  r  )r  r  r   r#   r   r7   r   upperr:   
batch_sizer#  batch_indicess               r%   r-  r-  L  sN   F ~~d../ $'']DK  &,,VLD*;mLJ##J/ (((5!!$'( OOK(E+q9uSbz):):;=E kQ"=Eu%A![%6%6%;%;%C!#''cr
3j
)a


A
Aq1
2atj!_5d]]977>d,,
..
$Q	(9(9%9
:ZOMm



_""M4#8rBDa


Au
%a


1i::4@
AaKK!!"I$ $( ($ $s%   A1J>+J16G1J>1J;	6J>>Kc                 l   g }d}| j                   j                  $| j                   j                  dk  rt        |      |r'|j                  t	        j
                  | d|             d}| j                   j                  Q|j                   j                  ;| j                   j                  |j                   j                  dz   k7  rJt        |      |r=|j                  t	        j                  | t        j                  |      dz   |             d}| j                   dd j                         r,| j                   d   | j                   d	   k7  rt        |      |S |rWt        j                  t        j                   |       dd d
      \  }}|j                  t	        j                  |||             |S )zCReturns list of assertions related to `lu_reconstruct` assumptions.z4Input `lower_upper` must have at least 2 dimensions.Nr3   r   z/`rank(lower_upper)` must equal `rank(perm) + 1`r2   z`lower_upper` must be square.r.   r   )num_or_size_splitsr   )r7   r   r   r   r	   assert_rank_at_least_v2assert_rankr   r   splitassert_equal)r  r  r   r   r   r   r   s          r%   r+  r+    s   *B''K,=,=,B,BQ,F
W
))+AwOQ >''DJJOO,G1!44winnT2Q6	IJ ,'s,,. 1 1" 55w 
 ??$RS)aADAqi,,Q7CD	r_   c                 ,   t        | ||      }d}|j                  j                  $|j                  j                  dk  r4t        |      |r'|j	                  t        j                  |d|             d}| j                  d   ;|j                  d   ,| j                  d   |j                  d   k7  rt        |      |S |rS|j	                  t        j                  t        j                  |       d   t        j                  |      d   |             |S )z=Returns list of assertions related to `lu_solve` assumptions.z,Input `rhs` must have at least 2 dimensions.r3   r   z3`lower_upper.shape[-1]` must equal `rhs.shape[-1]`.r   r.   r4  )	r+  r7   ndimsr   r   r	   r   r8  r   )r  r  r   r   r   r   s         r%   r  r    s   (dMJ*:'YY__ 
yyw&&sGDF B''CIIbM,E		"-w 
 OOK(,OOC $	 
r_   zlinalg.eigh_tridiagonalc                    t        j                  |xs d      5  fd}d }t        j                  | d      } | j                  d   dk  rt	        j
                  |       cddd       S t        j                  |d	      }| j                  |j                  k7  rt        d
       || |      }	|r|	cddd       S  || ||	      }
|	|
fcddd       S # 1 sw Y   yxY w)u	  Computes the eigenvalues of a Hermitian tridiagonal matrix.

  Args:
    alpha: A real or complex tensor of shape (n), the diagonal elements of the
      matrix. NOTE: If alpha is complex, the imaginary part is ignored (assumed
        zero) to satisfy the requirement that the matrix be Hermitian.
    beta: A real or complex tensor of shape (n-1), containing the elements of
      the first super-diagonal of the matrix. If beta is complex, the first
      sub-diagonal of the matrix is assumed to be the conjugate of beta to
      satisfy the requirement that the matrix be Hermitian
    eigvals_only: If False, both eigenvalues and corresponding eigenvectors are
      computed. If True, only eigenvalues are computed. Default is True.
    select: Optional string with values in {‘a’, ‘v’, ‘i’} (default is 'a') that
      determines which eigenvalues to calculate:
        'a': all eigenvalues.
        ‘v’: eigenvalues in the interval (min, max] given by `select_range`.
        'i’: eigenvalues with indices min <= i <= max.
    select_range: Size 2 tuple or list or tensor specifying the range of
      eigenvalues to compute together with select. If select is 'a',
      select_range is ignored.
    tol: Optional scalar. The absolute tolerance to which each eigenvalue is
      required. An eigenvalue (or cluster) is considered to have converged if it
      lies in an interval of this width. If tol is None (default), the value
      eps*|T|_2 is used where eps is the machine precision, and |T|_2 is the
      2-norm of the matrix T.
    name: Optional name of the op.

  Returns:
    eig_vals: The eigenvalues of the matrix in non-decreasing order.
    eig_vectors: If `eigvals_only` is False the eigenvectors are returned in
      the second output argument.

  Raises:
     ValueError: If input values are invalid.
     NotImplemented: Computing eigenvectors for `eigvals_only` = False is
       not implemented yet.

  This op implements a subset of the functionality of
  scipy.linalg.eigh_tridiagonal.

  Note: The result is undefined if the input contains +/-inf or NaN, or if
  any value in beta has a magnitude greater than
  `numpy.sqrt(numpy.finfo(beta.dtype.as_numpy_dtype).max)`.


  TODO(b/187527398):
    Add support for outer batch dimensions.

  #### Examples

  ```python
  import numpy
  eigvals = tf.linalg.eigh_tridiagonal([0.0, 0.0, 0.0], [1.0, 1.0])
  eigvals_expected = [-numpy.sqrt(2.0), 0.0, numpy.sqrt(2.0)]
  tf.assert_near(eigvals_expected, eigvals)
  # ==> True
  ```

  eigh_tridiagonalc                 (
    d t        j                  d      5   j                  j                  rVt	        j
                          t	        j
                  t	        j                  |      |z        t	        j                        }n*t	        j                  |      t	        j                  |      }t        j                   j                  j                        }t        j                  |dd |dd |dd z   |dd gd      }t	        j                  |j                   t	        j"                   |z               }t	        j$                  |j&                  t	        j(                   |z
              }t	        j$                  t	        j                  |      t	        j                  |            }t        j*                  g  j                  j                        }t        j$                  ||j                   z  ||j,                  z   |j.                  z        }	|	t	        j$                  |t	        j"                              z  t	        j                  |j,                  |d   z        |j,                  |z   rt	        j$                         |j0                  dz   d}
d	k(  rt	        j2                        nrd
k(  r>t5        j6                  d   d   d      }
t	        j2                  d   d   dz         n/dk(  rt5        j8                  d   d   d      }
nt;        d      |
r4t        j<                  |
g      5  t        j>                          ddd       d}t	        j@                   j                        |z  |j,                  z  |z  }dv r||z
  d|z  z  z
  }||z   |z  z   }nMd   |z
  d|z  z  z
  }d   |z   |z  z   }  |      }  |      }t	        j2                  ||      t	        j                  ||j                         }t	        j$                  ||j&                        }t        jB                        }t        jD                  ||      }t        jD                  ||      }t        jD                  |      t        jD                  |      d fd} fd}tG        jF                  ||d||g      \  }}} ||      cddd       S # 1 sw Y   xY w# 1 sw Y   yxY w)z;Computes all eigenvalues of a Hermitian tridiagonal matrix.c                 6    t        j                  d      5   j                  d   t        j                  t        j                        t
        j                        t        j                  t        j                        t
        j                         fd} fd |       \  }}d}d}	dz
  |z  }
|
fd} ||	||      \  }	}}|fd	}t        j                  |||	||gd
      \  }}}|cddd       S # 1 sw Y   yxY w)z)Implements the Sturm sequence recurrence.sturmr   r  c                      d   z
  } t        j                  | dk        }t        j                  t        j                  d         |       } | |fS )Nr   )r   wherer   equal)qcountalphaalpha0_perturbationr  r:   zeross     r%   sturm_step0zSeigh_tridiagonal.<locals>._compute_eigenvalues.<locals>._sturm.<locals>.sturm_step0"  sU    a1AOOAE47EuQx+-@!EAe8Or_   c                     |    | dz
     |z  z
  z
  }t        j                  |k  |dz   |      }t        j                  |k  t        j                  |       |      }||fS r|   )r   rA  r   minimum)rs   rC  rD  rE  beta_sqpivminr:   s      r%   
sturm_stepzReigh_tridiagonal.<locals>._compute_eigenvalues.<locals>._sturm.<locals>.sturm_step*  sk    a71q5>A--1AOOAKEBEVX-=-=a&-I1MAe8Or_      r2   c                 T    t              D ]  } | |z   ||      \  }} | z   ||fS r\   )r   )startrC  rD  jrM  
unroll_cnts       r%   unrolled_stepszVeigh_tridiagonal.<locals>._compute_eigenvalues.<locals>._sturm.<locals>.unrolled_steps:  s?    :& 9#EAIq%8ha9:%q%//r_   c                 0    t        j                  |       S r\   rr   )rs   rC  rD  r   s      r%   r^   zPeigh_tridiagonal.<locals>._compute_eigenvalues.<locals>._sturm.<locals>.<lambda>D  s    X]]1a%8 r_   F)	back_propN)	r   r   r7   r   rG  r   r   r  r   )rE  rK  rL  rF  r:   rH  rC  rD  	blocksizers   peelrS  r
   rx   r   r  rM  rR  rG  s   `````         @@@@@r%   _sturmz>eigh_tridiagonal.<locals>._compute_eigenvalues.<locals>._sturm  s    ^^G$ ,	kk!n!//)//!"4FLLI%	 2&,,G$  !](!U )!a%9$$*0
 'q!U3+!Q !*8$"--NQ5MUD+!QY,	 ,	 ,	s   C%DDcompute_eigenvaluesNr2   r   r   r   r  r   rs   z&Got empty index range in select_range.r4  rk   z#Got empty interval in select_range.z-'select must have a value in {'a', 'i', 'v'}.g @>   r   rs   r3   )r7   c                     d| z  d|z  z   S )Ng      ?rv   )r   r/  s     r%   midpointz@eigh_tridiagonal.<locals>._compute_eigenvalues.<locals>.midpoint  s    +#+.
.r_   c           
          t        j                  t        j                  |       t        j                  t        j                  ||z
                    S r\   )r   logical_andrc   r   )rs   r   r/  abs_tolmax_its      r%   continue_binary_searchzNeigh_tridiagonal.<locals>._compute_eigenvalues.<locals>.continue_binary_search  sC    %%mmAv&mmGX%8%8%GHJ Jr_   c                      	||      } 
|      }t        j                  |k  ||      }t        j                  |kD  ||      }| dz   ||fS r|   )r   rA  )rs   r   r/  midcountsrX  rE  rF  rK  r[  rL  target_countss        r%   binary_search_stepzJeigh_tridiagonal.<locals>._compute_eigenvalues.<locals>.binary_search_step  sa    &#%&2EsK&//&M"93F%//&="8#uE%Qu$
$r_   )$r   r   r1   
is_complexr   r    r   sqrtsquarer   r   r   r   r   r   rJ  r   r   r   min
reduce_minr  r   tinynmantr   r	   assert_less_equalassert_lessr   r   r   r   r7   r  r   )!rE  betabeta_absr   off_diag_abs_row_sumlambda_est_maxlambda_est_mint_normonesafeminassertsfudge
norm_slackr   r/  firstlasttarget_shaper`  re  rx   rX  r^  rF  rK  r_  r[  rL  rd  r   selectselect_ranger   s!   `                    @@@@@@@@r%   _compute_eigenvaluesz.eigh_tridiagonal.<locals>._compute_eigenvalues  s   .` >>/0 l&;;!!--&%MM(--"5"<=']]7+(OOD)'\\$'( 334(//bq\8CR=8AB<7"#Ga Q!))IIx**53G+GHJ!))IIx**53G+GHJ !!LL((,,~*FH
 ggb : :;**S599_sUYY%**.LM8++C1D1DW1MNN&ooeii(1+.EF))f$$$S'2' q S="..+-s]//1o1o>@' #..a,q/A:MN-s]))1o1o;='
 JK
K''	2 .&&u-E. ]]1ekk2U:UYYFO
Z :-E	F0BB% :->% q/J.UV1CC%q/J.?%1DeL%w0CUK$"..5-   		2  		2 }5&&uLA&&uLA''='445H5AC	/	J
	% 	% %//0F0B12E50AC5% u%Yl& l&p. .ql& l&s%   L'T
S; FT;T	 TTc           	         t        j                  d      5  t        j                  |      }t        j                  |       }t	        j
                  | |j                        } |dd |dd z
  }t        j                  |j                  j                        j                  }t	        j                  t	        j                  |d         t	        j                  |d               }t        j                  |      |z  }t	        j                  ||      }	t        j                  dg|	gd      }
t        j                  |	dggd      }t	        j                   t	        j"                  |
      |      t        j$                  t        j&                        d      t	        j                   |
t	        j"                  |            t        j$                  t        j&                        d      dz   t        j                        t	        j
                  t)        j*                  ||fd	d
g      |j                        }t-        |d      }||ddt        j.                  f   z  }t1        j2                  d|j4                  |j                        }t	        j
                  ||j                        }| t        j.                  ddf   |ddt        j.                  f   z
  }t        j6                  |t        j.                  ddf   |dg      }||t	        j8                  |      gfdd }fd}t;        j:                  ||d|||g      \  }}}}t=        |      cddd       S # 1 sw Y   yxY w)z5Implements inverse iteration to compute eigenvectors.compute_eigenvectorsr  r2   Nr   r   Fr   rL   *   )r7   seed)r7   r1   c                 R    fd}t        j                   fd|d| g      \  }} | S )Nc                    
|    }	|    }t        j                  t        j                  ||      d      }|||d d f   }t	        t        |            \  }}t        |      }t        j                  |||      }| dz   |fS )Nr   r2   )r   r   r   r   qr	transposetensor_scatter_nd_update)cluster_idxeigenvectorsrP  endupdate_indicesvectors_in_clusterrC  rx   vectors_to_updateortho_interval_endortho_interval_starts            r%   orthogonalize_clusterzxeigh_tridiagonal.<locals>._compute_eigenvectors.<locals>.orthogonalize_close_eigenvectors.<locals>.orthogonalize_cluster  s    (5E$[1C&22uc*B0N!-eCil!; i 234DAq )!$==n.?AL?L00r_   c                 0    t        j                  |       S r\   rr   )rs   evnum_clusterss     r%   r^   zkeigh_tridiagonal.<locals>._compute_eigenvectors.<locals>.orthogonalize_close_eigenvectors.<locals>.<lambda>  s    HMM!\: r_   r   r   )r  r  rx   r  r  r  s      r%    orthogonalize_close_eigenvectorszYeigh_tridiagonal.<locals>._compute_eigenvectors.<locals>.orthogonalize_close_eigenvectors  s3    1 '11:#a%68/!\ 
r_   c                 F   d}d}t        j                  d|z   |j                        }t        j                  t        j
                  | |      t        j                  t        j                  t        j                  |      t        j                  ||z                          S )NrG   g?r2   r  )	r   r5   r1   r   r]  rc   
reduce_anygreater_equalr    )rs   rx   nrm_v	nrm_v_oldr_  min_norm_growthnorm_growth_factors          r%   continue_iterationzKeigh_tridiagonal.<locals>._compute_eigenvectors.<locals>.continue_iteration  s    &/*33/! 6
 %%mmAv&!!((mmE*mm$6$BCEFG Gr_   c                     t        |ddd      }|}t        |d      }||d d t        j                  f   z  } |      }| dz   |||fS )Nr   T)r   r   r   r2   r   )r   normr   r   )rs   rk   r  r  r   r  s       r%   inverse_iteration_stepzOeigh_tridiagonal.<locals>._compute_eigenvectors.<locals>.inverse_iteration_step  se    )##%! )qq/%%9,,,--!.q1!Q5)+
+r_   )r   r   r   r   r   r   r1   r   r   r   r   r   r   rg  rc   r   r]  logical_notr   rb   r   stateless_random_normalr  r   r   r5   r7   tiler   r   r  )rE  ro  eigvalsr   r   gapr   rt  gaptolcloseleft_neighbor_closeright_neighbor_closev0r  zero_nrmeigvals_castalpha_shiftedr  r  rx   rk   r   r  r  r  r  s                        @@@@@r%   _compute_eigenvectorsz/eigh_tridiagonal.<locals>._compute_eigenvectors  s   >>01 kNN7#NN5!e4::6 abkGCRL(hhw}}33488!!LL$hll72;&?A& c6*'../?aH(//0@qI'33  !457K M(00342 ?%11!5!56J!KM&..12=?@A ~~&89 ]] 88!fAr7,** Ra %9,,,--''EKKP  }}WDJJ?)##Q&',q):K:K7K*LL 	~~d9#4#4a#781a&A}hmmD&9:	6	G	, $../A/E012uh/GI1eQ |Wk k ks   MM--M6rE  r(   r   r2   Nro  z+'alpha' and 'beta' must have the same type.)r   r   r+   r7   r   r    r1   r   )rE  ro  eigvals_onlyr}  r~  r   r#   r  r  r  
eigvectorsr   s      ```     @r%   r<  r<    s    H ~~d001 `_&Bm^ !!%g6EAAAv]]5!k` `l   F3D{{djj DEE"5$/G{` `~ 'udG<JJA	` ` `s   AC3ACCC$r\   )TFN)r   FFNTF)r   N)NFN)FN)Tr   NNN)X__doc__numpyr   tensorflow.python.frameworkr   r   r   r   tensorflow.python.opsr   r   r	   r
   rw   r   r   r   r   r   r   r   r   tensorflow.python.utilr    tensorflow.python.util.tf_exportr   matrix_band_partr  r   cholesky_solvematrix_determinantdetlog_matrix_determinantslogdetadd_dispatch_supportmatrix_diagdiagr!   	diag_partself_adjoint_eigeighself_adjoint_eigvalseigvalsheinsumr6   matrix_inverseinvmatrix_logarithmlogmlumatrix_solve_lslstsqr  r  matrix_set_diagr  ri   solvematrix_square_rootsqrtmr   	tensordottracer,   r  matrix_triangular_solver  r   r'   r@   rE   rJ   rO   rW   rY   r   r   r   r   r   r   r   r  r*  r-  r+  r  r<  rv   r_   r%   <module>r     s   %  3 . + 4 + 1 + 1 2 0 , ( * 2 6 , + 6 &&	**##

/
/ 	
 9H99'B C&&	""**		 	 nn&& 	- 666t< =""]]$$%%nn	&&	55  ?	  @ 	>  >: "24 =	qQ  qQh +3 	\2 4\2~ %&	 (1$)$)'+',iQ  'iQX/>d &'	LQ  (LQ^"  	"N  !"NJ =	}  }@ 	]  ]@ %&	<  '<~ "#	E  $EP@4 $%	 #'"&b  &br_   