
    VpfV                    B   d Z ddlmZ ddlmZ ddlmZ ddlZddlm	c m
c mZ ddlm	c m
c 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 ZddZ	 ddZd ZddZd dZ G d de          Z eej         d          d             Z!dddddddZ"dS )!a  Symmetric (Hermitian) eigendecomposition using QDWH

References:
Nakatsukasa, Yuji, and Nicholas J. Higham.
"Stable and efficient spectral divide and conquer algorithms for the symmetric
eigenvalue decomposition and the SVD." SIAM Journal on Scientific Computing 35,
no. 3 (2013): A1325-A1349.
https://epubs.siam.org/doi/abs/10.1137/120876605

This implementation is primarily used on TPU, but it can in principle work on
CPU and GPU also.
    )annotations)partial)
NamedTupleN)
reductions)ufuncs)lax)qdwh)linalg)Stackc                    | |z   dz
  |z  |z  S N    )ins     Q/var/www/html/nettyfy-visnx/env/lib/python3.11/site-packages/jax/_src/lax/eigh.py	_round_upr   4   s    Q3q5Q,!	    c                   t          j        |           t          |          k    sJ d}t          |          D ]9\  }}|2t	          j        t           j        | j        |          |k     }||n||z  }:|| nt          j        || |          S )zMasks `x` up to the dynamic shape `dims`.

  Replaces values outside those dimensions with `alternative`. `alternative` is
  broadcast with `x`.
  N)	jnpndimlen	enumerater   broadcasted_iotaint32shapewhere)xdimsalternativemaskr   d
mask_dim_is          r   _maskr$   7   s     
!D			!	!	!	!	$oo A Ada}'	17A>>Bj<ZZdZ.?dl	$; ? ??r   c                    t          j        | t          j        d| j                  d |D                       }t          j        |t          d |D                       |          }t          |||          S )a  Similar to lax.dynamic_slice, but handles arrays with dynamic sizes.

  Returns fill_value instead of clamping start_indices for those elements that
  would overflow the side of the array.

  Args:
    operand: the array to slice
    start_indices: the offset of the start of the slice
    dynamic_slice_sizes: the true (unpadded) size of the slice
    static_slice_sizes: the padded size of the slice, which must be known at
      compile time. The static size must be larger than the dynamic size.
    fill_value: value with which to replace masked-out elements.
  Returns:
    An array with static shape `static_slice_sizes`, padded from its true
    (dynamic) size `dynamic_slice_sizes`.
  r   c                    g | ]}d |d fS r   r   .0r"   s     r   
<listcomp>z_slice.<locals>.<listcomp>[   s    :::!Q1I:::r   c              3  >   K   | ]}t          j        |          V  d S Nr   r   r)   r   s     r   	<genexpr>z_slice.<locals>.<genexpr>\   s*      'L'L	!'L'L'L'L'L'Lr   )r   padr   arraydtypedynamic_slicetupler$   )operandstart_indicesdynamic_slice_sizesstatic_slice_sizes
fill_valuepaddedouts          r   _slicer<   E   s    ( 779Q..::'9:::< <& 	&%'L'Lm'L'L'L"L"L,	. 	.#	s'	4	44r   c                ~   | j         }t          j        | t          j        d| j                  d |j         D                       } t          d |D                       }t          j        | ||j                   }t          |||          }t          j	        | ||          } t          j
        | dg| j        z  |          S )a  
  Similar to lax.dynamic_update_slice, but handles padded updates where padding
  values should not overwrite existing values in the array.

  Args:
  operand: the array to update
  update: the padded array to write
  start_indices: the offset at which to write `update`.
  update_dims: the true dimensions of the padded update `update`. Only values
    inside the rectangle given by `update_dims` will be overwritten.r   c                    g | ]}d |d fS r'   r   r(   s     r   r*   z!_update_slice.<locals>.<listcomp>n   s    5551aAY555r   c              3  >   K   | ]}t          j        |          V  d S r,   r-   r.   s     r   r/   z _update_slice.<locals>.<genexpr>o   s*      <<	!<<<<<<r   )r   r   r0   r   r1   r2   r4   r3   r$   dynamic_update_sliceslicer   )r5   updater6   update_dimsoperand_shapets         r   _update_slicerF   `   s     --GGIa//555557 7' <<m<<<<<-	==!FK##!$Wa??'	7QC',.	>	>>r      Fc                R     j         \  }t          j         d           }t          |ft          j                  }t	          j        |          } dd|f         }	t          |	f          }	t          j                  }
dt          t	          j        |	j	                  j
                  z  |
z  fdfd} fd} |	          \  }}}t	          j        dt          j                  }t          j        ||||||f          \  }}}}|r||fS ||fS )	a}  Decomposes the `n x n` rank `rank` Hermitian projector `P` into

  an `n x rank` isometry `V_minus` such that `P = V_minus @ V_minus.conj().T`
  and an `n x (n - rank)` isometry `V_minus` such that
  -(I - P) = V_plus @ V_plus.conj().T`.

  The subspaces are computed using the naiive QR eigendecomposition
  algorithm, which converges very quickly due to the sharp separation
  between the relevant eigenvalues of the projector.

  Args:
    P: A rank-`rank` Hermitian projector into the space of `H`'s first `rank`
      eigenpairs. `P` is padded to NxN.
    H: The aforementioned Hermitian matrix, which is used to track convergence.
    n: the true (dynamic) shape of `P`.
    rank: Rank of `P`.
    maxiter: Maximum number of iterations.
    swap: If true, the two outputs spaces are swapped.

  Returns:
    V_minus, V_plus: Isometries into the eigenspaces described in the docstring.
  r   )axisNg      $@c                D   t          j        | d          \  }}t          |	
f          }t          |d
f		
z
  ff          }t	          j        |                                j                  }t	          j        ||          }t          j        |          }|||fS )Ncomplete)moder   )	
jnp_linalgqrr$   r<   r   dotconjTnorm)XQ_V1V2error_matrixerrorHNr   ranks          r   body_f_after_matmulz0_projector_subspace.<locals>.body_f_after_matmul   s    =,,,DAq 
q1d)		B	At9q!d(maV	4	4B 727799;**L7<,,LOL))Er5=r   c                `    | \  }}}}|k     }|k    }t          j        ||          d         S )Nr   )r   logical_and)argsrU   jrY   still_countingunconvergedmaxiterthreshs         r   cond_fz#_projector_subspace.<locals>.cond_f   s:    NAq!U[N&.Knk::1==r   c                l    | \  }}}}t          j        |          } |          \  }}}|||dz   |fS r   )r   rO   )	r`   rV   rU   ra   rS   rW   rY   Pr]   s	          r   body_fz#_projector_subspace.<locals>.body_f   sH    KB1a2A''**MBEr1q5%r   r2   )r   rM   rR   r$   r   nanargsortfloatfinfor2   epsonesr   r   
while_loop)rh   rZ   r   r\   rd   swaprU   negative_column_norms	sort_idxsrS   H_normrf   ri   rV   rW   rY   oner[   r]   re   s   `````            @@@r   _projector_subspacerw   v   s   0 
$!Q%?115555 5tSWEEk/00)9o!A4y!?1&%	!'**.///&8&       > > > > > >            &%a((-"b%#)$$$#^FFRS%4HII"b!U	 r6Mr6Mr   c                2     j         \  }} |t          j        ||j                  z                       j                  z
  }t          j        |df          \  }}}}t          t          j        | j                  f          }d||z
  z  t          j        t          j        t          j
                                                          t          j                  d||z   z  z
  k     }	t          j        |	 fd fd          \  }
}|
                                j         z  |
z  }|                                j         z  |z  }|*t          j        ||
          }
t          j        ||          }||
||fS )a   The Hermitian matrix `H` is split into two matrices `H_minus`
  `H_plus`, respectively sharing its eigenspaces beneath and above
  its `split_point`th eigenvalue.

  Returns, in addition, `V_minus` and `V_plus`, isometries such that
  `Hi = Vi.conj().T @ H @ Vi`. If `V0` is not None, `V0 @ Vi` are
  returned instead; this allows the overall isometries mapping from
  an initial input matrix to progressively smaller blocks to be formed.

  Args:
    H: The Hermitian matrix to split.
    split_point: The eigenvalue to split along.
    V0: Matrix of isometries to be updated.
  Returns:
    H_minus: A Hermitian matrix sharing the eigenvalues of `H` beneath
      `split_point`.
    V_minus: An isometry from the input space of `V0` to `H_minus`.
    H_plus: A Hermitian matrix sharing the eigenvalues of `H` above
      `split_point`.
    V_plus: An isometry from the input space of `V0` to `H_plus`.
    rank: The dynamic size of the m subblock.
  rj   T)is_hermitiandynamic_shapeg      g      ?c                 ,    t           d          S )NTrr   rw   )rZ   P_plusr   	rank_pluss   r   <lambda>z split_spectrum.<locals>.<lambda>   s    !&!Q	EEE r   c                 ,    t           d          S )NFr|   r}   )rZ   P_minusr   
rank_minuss   r   r   z split_spectrum.<locals>.<lambda>   s    !'1a%HHH r   )r   r   eyer2   astyper	   r$   roundtracer   realr   r   condrP   rQ   rO   )rZ   r   split_pointV0r[   rU   H_shiftUIrr   V_minusV_plusH_minusH_plusr   r~   r   r   s   ``            @@@@r   split_spectrumr      s   . 
$!Qswq0ABBBBJJ17SSS'ytAq6JJJ*!Q1CGAQW%%%1v..!AEN'y6;w#7#78899@@KK*!a%=&*n) 
Z	$H
EEEEEEEHHHHHHH /'6
 \\^^!W,'KKMMOa6)&^gb'""GWR  F	'66:	55r   c                  (    e Zd ZU dZded<   ded<   dS )_SubproblemzDescribes a subproblem of _eigh_work.

  Each subproblem is a `size` x `size` Hermitian matrix, starting at `offset`
  in the workspace.
  z	jax.ArrayoffsetsizeN)__name__
__module____qualname____doc____annotations__r   r   r   r   r     s3            /////r   r   termination_sizesubset_by_index)static_argnamesc           
     `   | j         \  }t          j        t          j                  t	          j        dz   t          t          j        dt          j                  t          j        dt          j                                      }|                    t          t          j        d                              }t          j	        | j
                  }t          j        t          | f                    | }fd}fd}	d }
t          |          }|gt          ||          g|k    r                                                   t          |	                     d}d	}t#          |z            }||k    rSt%          ||          }                    |                               t          |	|                     |d
z  }||k    St          j        d          fd}t'          j        |
||||f          \  }}}|dddf         |fS )a   The main work loop performing the symmetric eigendecomposition of H.
  Each step recursively computes a projector into the space of eigenvalues
  above jnp.mean(jnp.diag(H)). The result of the projections into and out of
  that space, along with the isometries accomplishing these, are then computed.
  This is performed recursively until the projections have size 1, and thus
  store an eigenvalue of the original input; the corresponding isometry is
  the related eigenvector. The results are then composed.

  This function cannot be Jitted because the internal split_spectrum cannot
  be.

  Args:
    H: The Hermitian input.
    n: The true (dynamic) shape of H.

  Returns:
    H, V: The result of the projection.
  r   r   )r   r   rj   c                   t          ||df||f| | f          }t          |d|f|f
| f          }t          |||f          }t          j                            |d          \  }}	t          |||f          }t          |	|f          }	t          j        ||          }|	                    |j                  }	t          ||	d d d f         |df|df          }t          ||d|f|f          }|||fS )Nr   Fsort_eigenvaluesr   )
r<   r$   r   r
   eighr   rO   r   r2   rF   )Br   bagendablockseigenvectorsrZ   Veig_vecseig_valsr[   r   s             r   	base_casez_eigh_work.<locals>.base_case^  s   
 	v{QFQF33A|a[1a&1a&99A 	a!QAUCCHhX1v&&HXt$$Hwq(##Hx~..H68AAAtG#4vqkAq6JJF x!Vq!fMML6<''r   c           
     ,    t          |dff  f          fd}d  fd}t          j                  }t          j        t          j        j                  j        |j                  }	t          j        t          j        t          j        t          j
                                                j                            z
            }
|
d|	z  |z  k    }||	z  k     }t          j        ||z  |||||          S )Nr   c                r    t          |t          j                  d d d f         dfdf          }| ||fS )Nr   r   )rF   r   diag)r   r   r   rZ   r   r   s      r   nearly_diagonal_casez@_eigh_work.<locals>.recursive_case.<locals>.nearly_diagonal_case  s@    VSXa[[D%9FA;AOOfV\))r   c                <    |dn| |d         k     ||d         k    z  S )NTr   r   r   )startendr   s      r   should_update_rangez?_eigh_work.<locals>.recursive_case.<locals>.should_update_range  s2     $ $++oa6H0HIr   c           	     N    t          dfff          }t          j        t          t	          j        t          j                            ft          j                            }t          ||          \  }}}}}	t          |df|	|	f          t          |df|	f                               t          |	                    f |	z             }
t          j        |
fd fd          \   t          ||	z   df|	z
  |	z
  f          t          |d|	z   f|	z
  f                               t          |	z   |	z
                      f |	z   z             }t          j        |fd fd          \    fS )Nr   )r   c                      S r,   r   )updated_minus_states   r   r   zJ_eigh_work.<locals>.recursive_case.<locals>.default_case.<locals>.<lambda>  s    % r   c                      fS r,   r   r   r   r   s   r   r   zJ_eigh_work.<locals>.recursive_case.<locals>.default_case.<locals>.<lambda>      6<0 r   c                      S r,   r   )updated_plus_states   r   r   zJ_eigh_work.<locals>.recursive_case.<locals>.default_case.<locals>.<lambda>  s    $ r   c                      fS r,   r   r   s   r   r   zJ_eigh_work.<locals>.recursive_case.<locals>.default_case.<locals>.<lambda>  r   r   )r<   r   	nanmedianr$   r   r   r   r   rk   r   rF   pushr   r   r   )r   r   r   r   r   r   r   r   r   r\   should_update_minusshould_update_plusr   r   r   rZ   r[   r   r   r   r   r   s   ```         @@r   default_casez8_eigh_work.<locals>.recursive_case.<locals>.default_case  s!   
6{QFQF
;
;a(sxA/G/G!sw)W)WXXk/=
Q0# 0# 0#,gw
 &!tTl
C
C
g6{QI
F
F
++k&$//
0
0
 0/
&4-  &)X

%
%
%
%
0
0
0
0
0
0& &"flF fv}a01t8QX2F  FQ$6AH  ++k&4-!d(<<
=
= /.
4-!_  &)X

$
$
$
$
0
0
0
0
0
0& &"flF V\))r   rj      )r<   rM   rR   r   asarrayrn   r2   ro   r   r   r   r   r   r   )r   r   r   r   r   r   r   r   rR   ro   off_diag_normnearly_diagonaltinyrZ   r   H0_normr[   r   r   s   ```          @@r   recursive_casez"_eigh_work.<locals>.recursive_casez  s`    	v{QFQF33A* * * * * * *  ** ** ** ** ** ** ** ** ** ** ** **` ?1D
+ci((,DJ
?
?
?CO	CHSXfk!nn--44QW==>>>@ @M#q3w~5O#-D8$  r   c                8    | \  }}}|                                  S r,   )empty)stater   rU   s      r   	loop_condz_eigh_work.<locals>.loop_cond  s    LFAqLLNN?r   gGz?    rG   r   c           	        | \  }}}|                                 \  \  }}}t          j        	|k     t          j        t          j                  j        	          }t          j        |          }t          j        ||||||          S r,   )	popr   r   iinfor   maxargminr   switch)
r   r   r   r   r   r   whichchoicebranchesbucketss
           r   	loop_bodyz_eigh_work.<locals>.loop_body  sv    #( FFL **,,KVQIgk39SY#7#7#;WEEEZF:fh66<PPPr   N)r   r   r   r   r   creater   r1   r   r   r2   rM   rR   r$   minr   appendintr   r   rq   )rZ   r   r   r   rU   r   r   r   r   r   r   cutoff
multipliergranularityr   bucket_sizer   r   r[   r   r   s    ` `             @@@@r   
_eigh_workr      s   , 
$!Q	k!SY!<E;syCI..	!SY0G0GHHJ J&;;{#)A,,Q???@@&
 !'***,
 OE!aV,,--'0 &( ( ( ( ( (8M M M M M M M M^   q"##&H'i(()(	 NN1OOGNA..///JKA
NA
f**a--knn[!!!oognk::;;;
q&a	 f**
 IgW---'Q Q Q Q Q Q  NVV\:< <!V\	1|	##r   float32   T)	precisionr   r   r   r   c                  | j         \  }}||k    rt          d| j          d          |||k    rt          d          d}||d|fk    }t          |          dk    rt          d          |d         |d	         k    rt          d
          |d         dk     rt          d          ||n|}	|d	         |	k    rt          d          ||k    re|t	          | ||f          } t          j        | |p|          \  }
}|r0|
|d         |d	                  }
|dd|d         |d	         f         }|
|fS ||n|}t          j        |          5  t          | |||          \  }
}ddd           n# 1 swxY w Y   t	          t          j        |
          |ft          j                  }
|s|r@t          j        |
          }|r||d         |d	                  }|
|         }
|dd|f         }|
|fS )a  Computes the eigendecomposition of the symmetric/Hermitian matrix H.

  Args:
    H: The `n x n` Hermitian input, padded to `N x N`.
    precision: :class:`~jax.lax.Precision` object specifying the matmul
      precision.
    termination_size: Recursion ends once the blocks reach this linear size.
    n: the true (dynamic) size of the matrix.
    sort_eigenvalues: If `True`, the eigenvalues will be sorted from lowest to
      highest.
    subset_by_index: Optional 2-tuple [start, end] indicating the range of
      indices of eigenvalues to compute. For example, is ``range_select`` =
      [n-2,n], then ``eigh`` computes the two largest eigenvalues and their
      eigenvectors.

  Returns:
    vals: The `n` eigenvalues of `H`.
    vecs: A unitary matrix such that `vecs[:, i]` is a normalized eigenvector
      of `H` corresponding to `vals[i]`. We have `H @ vecs = vals * vecs` up
      to numerical error.
  zInput H of shape z must be square.Nz5Static size must be greater or equal to dynamic size.Fr   rG   z*subset_by_index must be a tuple of size 2.r   z)Got empty index range in subset_by_index.z0Indices in subset_by_index must be non-negative.z0Index in subset_by_index[1] exceeds matrix size.r   r   )r   	TypeError
ValueErrorr   r$   
lax_linalgeigh_jacobijaxdefault_matmul_precisionr   r   r   r   rk   rl   )rZ   r   r   r   r   r   Mr[   compute_slice	range_maxr   r   rt   s                r   r   r     s   < 
$!Q!VV
AAAA
B
BB]q1uu
L
M
MM-		 #1v-M
?q  CDDDq_Q///BCCCqAIJJJYAIqI%%IJJJ
}
Aq6

a#/	->  Hh  F/!,q/AABh!!!_Q//!2DDDEhX9aa!!
#I..  #	1/  Hh               6;x((1$88( & &H%%I EOA.1CCDi	"H9%H	8	s   E33E7:E7r'   )rG   Fr,   )#r   
__future__r   	functoolsr   typingr   r   jax._src.numpy.lax_numpy_srcnumpy	lax_numpyr   jax._src.numpy.linalgr
   rM   jax._src.numpyr   r   r   jax._src.laxr	   r   jax._src.lax.stackr   r   r$   r<   rF   rw   r   r   jitr   r   r   r   r   <module>r      s    # " " " " "             



 & & & & & & & & & & & & * * * * * * * * * * * * % % % % % % ! ! ! ! ! !             - - - - - - $ $ $ $ $ $  @ @ @ @ 5 5 5 56? ? ?,D D D DN06 06 06 06l
 
 
 
 
* 
 
 
 	"IJJJO$ O$ KJO$j 
I I I I I I Ir   