
    AVh                     4   d 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j                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d      dej                  fd       Z ej                  d       dej                  fd!       Zd2d"Z ej                  d#      dej                  fd$       Z ej                  d%      dej                  fd&       Z ej                  d'      dej                  fd(       Zd) Zd* Z  ej                  d+      dej                  fd,       Z! ej                  d-      dej                  fd.       Z"d/ Z#d0 Z$y1)3a*  Gradients for operators defined in linalg_ops.py.

Useful reference for derivative formulas is (Mike Giles, 2008).

Ionescu et al. (2015) provide a detailed derivation of formulas for
backpropagating through spectral layers (SVD and Eig).

References:
  An extended collection of matrix derivative results for
  forward and reverse mode automatic differentiation:
    [Mike Giles, 2008]
    (https://ora.ox.ac.uk/objects/uuid:8d0c0a29-c92b-4153-a1d2-38b276e93124)
    ([pdf](http://eprints.maths.ox.ac.uk/1079/1/NA-08-01.pdf))
  Matrix Backpropagation for Deep Networks with Structured Layers
    [Ionescu et al., 2015]
    (https://www.cv-foundation.org/openaccess/content_iccv_2015/html/Ionescu_Matrix_Backpropagation_for_ICCV_2015_paper.html)
    ([pdf](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/Ionescu_Matrix_Backpropagation_for_ICCV_2015_paper.pdf))
  Training Deep Networks with Structured Layers by Matrix Backpropagation:
    [Ionescu et al., 2015](https://arxiv.org/abs/1509.07838)
    ([pdf](https://arxiv.org/pdf/1509.07838.pdf))
    )dtypes)ops)	array_ops)array_ops_stack)cond)gen_linalg_ops)
linalg_ops)math_ops)linalg_implMatrixInverseopc           	          | j                   d   }| j                  d      }t        j                  |t        j                  ||||       |        S )zGradient for MatrixInverse.r   adjoint)	adjoint_a	adjoint_br   )outputsget_attrr
   matmul)r   gradainv
op_adjoints       Q/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/linalg_grad.py_MatrixInverseGradr   /   sT     
A${{9%*
//
oodDJ$.0	  
       Einsumc                 `   dfdfd}fdfdfd}| j                  d      }t        |t              r|j                         }|j	                  d      \  }}t        | j                        d	k(  r}t        j                  | j                  d
         }t        |      j                  t        |z               }|s't        j                  |gdj                  ||            S  |||||      S |j	                  d      \  }	}
|v r|	vr|	z  }	|
vr|
z  }
| j                  d
   | j                  d	   }}|j                  j                  r*t!        j"                  |      }t!        j"                  |      }t        j                  |      }t        j                  |      } |||||	|
|      } |||||
|	|      }|vr||fS  ||	      \  }} ||
      \  }}|j%                         }|j%                         }|j'                         r|j'                         r||| ||| k(  r||fS t        j(                  ||| |||       \  }}t        j*                  t!        j,                  |||z         |      }t        j*                  t!        j,                  |||z         |      }||fS )zGradient for Einsum.z...c                     | j                        }|d   j                  |      }|dk7  r|S t        |      dk  ry|d   j                  |      }|dk7  r|t        |d         z
  S y)a  Returns the axis (possibly negative) corresponding to a label.

    Returns the axis index of the axis label if it is before an ellipsis (or if
    the ellipsis is not present), and the negative index if it occurs after the
    ellipsis. E.g. index of `b` in `ab...cd`, is `1`, but that of `c` is `-2`.

    For multiple occurrences, returns the leftmost one. If not found, returns
    None.

    Args:
      subscripts: A string denoting the einsum subscript (e.g. `ab...cd`)
      label: The single character axis label.
    r      N   )splitfindlen)
subscriptslabelsplitsindexellipsiss       r   _GetAxisFromLabelz&_EinsumGrad.<locals>._GetAxisFromLabel@   sp     h'F1INN5!E{l
6{Q1INN5!E{S^##r   c                     | j                        }|dk(  ryt        |       |t              z   z
  }|dkD  r| nd}||fS )a  Returns a tuple denoting the slice mapping to ellipsis.

    For a given subscript, returns a tuple (start, end) denoting the start
    axis index and the (negative) end axis index respectively. For any input
    Tensor `x` described by the subscript, `x[start:end]` would be the slice
    represented by the ellipsis. E.g. For `ab...cd` returns `[1, -2]`.

    If ellipsis is not present in `subscripts`, returns `(0, 0)`.

    Args:
      subscripts: A string denoting the einsum subscript.
    r   )r   r   r   N)r#   r$   )r%   start	remainingendr)   s       r   _GetBcastSubshapez&_EinsumGrad.<locals>._GetBcastSubshapeY   sM     OOH%E{J53x=#89I!A9*4C#:r   c                     dj                  t        |             }|D cg c]  } ||       }}t        j                  |D cg c]  }||   	 c}      }|||fS c c}w c c}w )a  Returns reduced subscripts and their corresponding dimensions and axes.

    Given a set of axis labels, returns their concatenated subscript, their
    corresponding dimensions from input_shape, and their corresponding axes.
    Note that the concatenated subscript `reduced_subs` may have axis labels
    from `reduced_label_set` in any order. For example, for the reduced label
    set `{b, d}`, subscripts `aabbcd` and input shape `[2,2,5,5,3,4]`, returns
    subscripts `bd`, dimensions `[5,4]` and axes `[2,5]`.

    Args:
      reduced_label_set: Set of axis labels which appear in `subscripts`.
      input_shape: A `Tensor` representing the shape of the einsum operand
        corresponding to `subscripts`.
      subscripts: A string denoting the einsum subscript.

    Returns:
      reduced_subs: Subscripts formed by a concatenation of labels in
        `reduced_label_set`.
      reduced_dims: Dimensions from `input_shape` corresponding to each label
        in `reduced_subs`.
      reduced_axes: Axes described by `subscripts` corresponding to each label
        in `reduced_subs`. If there are multiple occurrences in `subscripts`,
        we consider only the leftmost one.

     )joinlistr   stack)	reduced_label_setinput_shaper%   reduced_subssreduced_axesaxreduced_dimsr*   s	           r   _GetReducedSubscriptsz*_EinsumGrad.<locals>._GetReducedSubscriptsm   sq    6 774 123L ?KK%j!4KLK"((#/0RR02L|33	 L 	1s   AA"c                 X    |||      \  }}}t        t        |            t        t        |            z   t        |      t        |      z   k  }dj                  |D 	cg c]	  }	|	|vs|	 c}	      }
|sX|
|k(  rSt        j                  |t        j                  |            }t        j                  t        j                  | |      |      S t        j                  |t        j                  |       gd      }t        j                  t        j                  t        |      t        j                        t        j                  |       gd      }t        j                  t        j                  | |      |      }t        j                   |gdj#                  ||z   |            S c c}	w )a  Returns the gradient wrt input for a unary einsum with reductions.

    Args:
      output_grad: The gradient wrt the output of a unary einsum operation.
      output_subs: The output subscript. (E.g. `ac` for equation `abc->ac`).
      input_subs: The input subscript. (E.g. `abc` for equation `abc->ac`).
      input_shape: A `Tensor` representing the shape of the input operand.
      reduced_label_set: The set of axis labels appearing in `input_subs` but
        not in `output_subs`.
    r1   r   axisdtype{}->{})r$   setr2   r
   reduced_shaper   convert_to_tensorr   broadcast_toreshapeconcatshapeonesr   int32r   einsumformat)output_gradoutput_subs
input_subsr6   r5   r7   r;   r9   has_repeated_labelsr8   !input_subs_without_reduced_labelsrD   grad_shape_with_reduced_labelsbroadcasted_gradr<   s                 r   _GetGradReducedz$_EinsumGrad.<locals>._GetGradReduced   s    0E;
04,L,
 	C
Os3{#344J#k**	+ 
 )+=q!+<"<=)?%  )[8 ,,
s,,\:<m ##


K
7F F &/%5%5	y{341&>" 	NN301FOOK(
  		!  !--+}5&(   "2!3!)1K1;"=> >a 	>s    	F'*F'c                     t        |      j                  t        ||z   dz               dj                  fd|D              }t        j                  | |gdj                  |||            }s|S  	||||      S )aW  Returns the gradient wrt an input operand for a binary einsum.

    This function does not handle (un)broadcasting. This must be done separately
    on the returned gradient.

    Args:
      output_grad: The gradient wrt the output of a binary einsum operation.
      other_operand: The complementary `Tensor` operand i.e. which is not the
        input operand.
      input_shape: A `Tensor` representing the shape of input operand.
      input_subs: The subscripts of the input operand.
      other_subs: The subscripts of the complementary operand.
      output_subs: The output subscripts.
    .r1   c              3   ,   K   | ]  }|vs|  y wN ).0r8   r5   s     r   	<genexpr>z3_EinsumGrad.<locals>._GetGradWrt.<locals>.<genexpr>  s     La:K1KLs   	z	{},{}->{})rC   
differencer2   r   rL   rM   )
rN   other_operandr6   rP   
other_subsrO   	left_subsgrad_reducedr5   rU   s
           @r   _GetGradWrtz _EinsumGrad.<locals>._GetGradWrt   s    l J22K*$s*+- L:LLI "((+})E)4););-8*-6*89L  <J,. .r   equationz->r!   r   rB   ,)r   
isinstancebytesdecoder"   r$   inputsr   rI   rC   r]   r   rL   rM   rA   
is_complexr
   conj	get_shapeis_fully_definedbroadcast_gradient_argsrG   
reduce_sum)r   r   r/   rb   rc   rP   rO   r6   r5   x_subsy_subsxyx_shapey_shapegrad_xgrad_ybx_startbx_endby_startby_endx_shape_staticy_shape_staticrxryr*   rU   r<   r)   s                            @@@@r   _EinsumGradr   ;   s    (2("4HK>ZJ.X [[$(%  H$NN40*k^q //"))A,/KJ223{X7M3NO ""D6#+??;
#KM M 4j+,. . ##C(.&&
 vfvf 
1ryy|Q!	ZZaAaAOOA'OOA'tQE&tQE&[ 6> 'v.(F&v.(F;;=.;;=.%%'%%'Xf%)HH6> ,,WXf-E-4Xf-EG&"b&(R-0';&&(R-0';&	r   MatrixDeterminantc                     | j                   d   }| j                  d   }t        j                  |d      }t	        j
                  ||z  t	        j                  t	        j                  |      ddggd            }||z  S )zGradient for MatrixDeterminant.r   Tr   r!   rh   r   r	   matrix_inverser   rG   rH   rI   )r   r   ac	a_adj_invmultiplierss         r   _MatrixDeterminantGradr   w  sx     	iil!jjm!''48)!!$("+"2"2IOOA4FA3O34#67+ 
y	  r   MatrixSquareRootc                 b   d }| j                   d   }t        j                  |      }|d   }t        j                  |dd       }t        j                  ||j                        }t        j                  |dg      }t        j                  ||g      }	t        j                  |	|      }
t        j                  |      } ||
|      } |||
      }t        j                  ||      }t        j                  t        j                  |      d      g}t        j                  |dg|      }t        j                  |||z  gdggd      }t        j                  t        j                  |      |      }t        j                   ||      }t        j                  ||      }t        j                  |      S )zGradient for MatrixSquareRoot.c                 4   t        j                  |       }t        j                  |      }|d   }|d   }t        j                  t        j                  |      d      g}t        j
                  |dg|      }t        j                  ||gdg|gdggd      }t        j                  |dg|gdg|ggd      }	t        j                  | |      }
t        j                  ||	      }||z  }t        j                  ||g|ggd      }t        j                  |
|z  |      S )zAComputes the Kronecker product of two batches of square matrices.r   r    r   r!   )r   rI   r
   subtractsizeslicerH   rG   )b1b2b1_shapeb2_shapeb1_orderb2_ordershape_slice_sizeshape_sliceb1_reshape_shapeb2_reshape_shape
b1_reshape
b2_reshape
order_prodkprod_shapes                 r   _KroneckerProductz0_MatrixSquareRootGrad.<locals>._KroneckerProduct  s   r"Hr"H|H|H )))..*BAFG//(QC"24K ''	xj1#zA37< ''	qcH:sXJ7< ""2'78J""2'78JH$J""K*
|#LaPKZ*4kBBr   r   r   r@   r    r!   )r   r   rI   r
   reduce_prodr	   eyerA   rG   tilematrix_transposeaddr   r   r   rH   matrix_solve)r   r   r   sqrtmrI   ordermatrix_countr   eye_flat	eye_tiled	eye_batchsqrtm_transposek1k2ksumr   r   shape_vec_davec_da
vec_dsqrtmdsqrtm_transposes                        r   _MatrixSquareRootGradr     s{   C, **Q-%
//%
 %
)%%%eAbk2, 	uEKK0#sRD)(nnX~6)	51) ..u5/O4"	*"	b"	$ ''	u(=qABs,<=+!!;!"EqI,Y77=|L& &&tV4* &&z59		#	#$4	55r   LogMatrixDeterminantc                     | j                   d   }| j                  d   }t        j                  |d      }t	        j
                  |t	        j                  t	        j                  |      ddggd            }||z  S )z"Gradient for LogMatrixDeterminant.r   r!   Tr   r   )r   _grad_br   r   r   r   s          r   _LogMatrixDeterminantGradr     sp     	iil!jjm!''48)!!i	 2QF;Q?A+	y	  r   Choleskyc                 4   | j                   d   }t        j                  |      d   }t        j                  |      dd }t        j                  |t        j
                  |||j                              }t        j                  ||d      }t        j                  |dt        j                  |      z        }t        j                  |dd      }t        j                  t        j                  ||d      |      }|t        j                  |      z  }|dz  S )	zGradient for Cholesky.r   r   Nr   batch_shaperA   Tr         ?)r   r   rI   r	   matrix_triangular_solver   rA   r
   r   matrix_set_diagmatrix_diag_partmatrix_band_part_linalgr   )r   r   lnum_rowsr   	l_inversemiddlegrad_as           r   _CholeskyGradr     s    
 	jjm!__Q#("3B'+001;5=AL;<772DE) ??1dd3&$$V%(9+E+Ef+M%MO&%%fb!4&??ooi48)E& 	GOOF##&	#r   Qrc           
      t   | j                   \  }}|j                  j                  :|j                  j                         d   |j                  j                         d   t	        d|j                         |j                  j
                  d   j                  |j                  j
                  d   j                  kD  r|j                  j
                  d   j                  |j                  j
                  d   j                  k(  rMt	        d|j                   d|j                  j
                  d    d|j                  j
                  d    d      d	 fd
}|j                  j
                  d   j                  |j                  j
                  d   }}||k\  r |||||      S | j                  d   }|ddd|df   }	|dddd|f   }
|ddd|df   }|dddd|f   }t        j                  ||      } |||
|t        j                  |	|d      z   |      }t        j                  ||gd      S )zGradient for Qr.Nr   r   z>QrGrad not implemented with dynamic shapes. Received r.shape: zVQrGrad not implemented when nrows > ncols and full_matrices is true. Received r.shape=z with nrows=z
and ncols=rW   c                     t        j                  t        j                  |t        j                  |       dd            S )zAEquiv to matmul(x, adjoint(matrix_inverse(r))) if r is upper-tri.Flowerr   )r   r   r	   r   )rq   rs     r   _TriangularSolvez!_QrGrad.<locals>._TriangularSolve  s5    ??**wq!	?@ @r   c           	      ,   t        j                  | |d      }|t        j                  |      z
  }t        j                  ||d      }|t        j                  |      z
  }t	        j
                  ||z   dd      }t        j                  | | ||      z         }	 |t        j                  | |      z
  |      }
|	|
z   }| j                  j                  r|t        j                  |      z
  }t        j                  t	        j                  |      t        j                  |            }|t        j                  t        j                  |      | j                        z
  }| t        j                  | t        j                  |            |      z   }|S )zTGradient for matrix orders num_rows >= num_cols
    and full_matrices is false.
    Tr   r   r   r   )r
   r   r   r   r   r   rA   ri   set_diag
zeros_like	diag_partcastreal)qr   dqdrqdqqdq_rdrrdr_trilr   r   retmeyem
correctionr   s                  r   _QrGradSquareAndDeepMatricesz-_QrGrad.<locals>._QrGradSquareAndDeepMatrices  sE    //!R4
0C%%D
//!R4
0C%%D%%dTk2q9D__Q%5dA%> >?Fb8??1c#::A>F
6/Cww
$
$ai2215w7H7H7KLd(--d(;QWWEEj"
//!W__Z8
91> >c Jr   r   .Tr   r>   )r   rI   ndimsas_listNotImplementedErrordimsvaluerh   r
   r   r   rH   )r   r   r   r   r   r   r   num_colsr   rr   udvdudydxr   s                  @r   _QrGradr     s    
$!Qggmmqww04<ggoo#
 33477)= > >ggll2qww||B/555ggll2R 0 6 66
 M!"	aggll26F5G *177<<+;*<A? @ @
@0 ww||B'--qww||B/?H('1b"55 	iil!Q	!Q		!	#q()
"	#q)8)
"q""#Aq$&B$)O$O$&(" 
		2r(	,,r   MatrixSolvec                 
   | j                   d   }| j                  d      }| j                  d   }t        j                  |||       }|rt        j                  ||d       }||fS t        j                  ||d       }||fS )zGradient for MatrixSolve.r   r   r   Tr   )rh   r   r   r	   r   r
   r   )r   r   r   r   r   r   r   s          r   _MatrixSolveGradr   -  s     	iil!kk)$)jjm!""1d	MB&ooa488F &	 oofa488F
&	r   MatrixSolveLsc                     dt         j                  fddt         j                  fd j                  d      }|du rt        d       j                  d   j                         dd	 }|j                         r|d   |d
   k\  r	        S         S t        j                   j                  d         dd	 }t        j                  |d   |d
   k\   fd fd      S )zGradients for MatrixSolveLs.r   c                    | j                   d   }| j                   d   }| j                  d   }t        j                  | j                   d   |j                  j
                        }t        j                  ||d      }t        j                  ||      }t        j                  ||d      }|t        j                  |      z   }	t        j                  ||	       t        j                  ||d      z   }
t        j                  ||      }|
|dfS )a,  Gradients for the overdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the first
    kind:
       X = F(A, B) = (A^T * A + lambda * I)^{-1} * A^T * B
    which solve the least squares problem
       min ||A * X - B||_F^2 + lambda ||X||_F^2.
    r   r!   r    Tl2_regularizer
first_kindr   N)rh   r   r
   r   rA   
base_dtyper	   _RegularizedGramianCholeskycholesky_solver   r   r   )r   r   r   brq   r   cholzxztzx_symr   r   s               r   _Overdeterminedz+_MatrixSolveLsGrad.<locals>._OverdeterminedE  s     			!A
		!A


1A]]299Q<1C1CDN11	.T;D 	!!$-A
//!Q$
/C9--c22Fooa((8??1a4+PPF__Q"FFD!!r   c                 4   | j                   d   }| j                   d   }t        j                  | j                   d   |j                  j                        }t        j                  ||d      }t        j                  |t        j                  ||            }t        j                  ||      }t        j                  ||d      }t        j                  ||       }|t        j                  ||d      z
  }	t        j                  ||	d      }	||	z   }
|
|d	fS )
a*  Gradients for the underdetermined case of MatrixSolveLs.

    This is the backprop for the solution to the normal equations of the second
    kind:
      X = F(A, B) = A * (A*A^T + lambda*I)^{-1} * B
    that (for lambda=0) solve the least squares problem
      min ||X||_F subject to A*X = B.
    r   r!   r    Fr   Tr   r   N)	rh   r
   r   rA   r   r	   r   r   r   )r   r   r   r   r   r   r   tmpa1a2r   s              r   _Underdeterminedz,_MatrixSolveLsGrad.<locals>._Underdetermined_  s     			!A
		!A]]299Q<1C1CDN11	.U<D &&tX__Q-EFF

#
#D!
,C	a4	0B
//&"
%	%B	6T:	:B	bD	1B"WFFD!!r   fastFz#Gradient not defined for fast=Falser   r   Nr   c                              S rY   rZ   )r  r   r   s   r   <lambda>z$_MatrixSolveLsGrad.<locals>.<lambda>  s    _R6 r   c                              S rY   rZ   )r  r   r   s   r   r
  z$_MatrixSolveLsGrad.<locals>.<lambda>  s    -b$7 r   )
r   	Operationr   
ValueErrorrh   rk   rl   r   rI   r   )r   r   r  matrix_shaper  r  s   ``  @@r   _MatrixSolveLsGradr  ;  s    "#-- "4"3== "4 
V	$	U]
:
;;1'')"#.,""$B<++R&&b$'' ??299Q<05L99\"%b)99679 9r   BandedTriangularSolvec                    | j                   d   }| j                   d   }t        j                  |      d   }| j                  d      }| j                  d      }| j                  d   }t        j                  ||||       }|rt        j                  ||d       }	nt        j                  ||d       }	|rt        j                  |	|dz
   dfd	
      }	nt        j                  |	d|dz
  fd	
      }	|j                  j                         r=|j                  j                         r#|j                  dd |j                  dd k(  r|	|fS t        j                  |      }
t        j                  |      }t        j                  |
dd |dd       \  }}t        j                  t        j                  |	|      |
      }	t        j                  t        j                  ||      |      }|	|fS )z#Gradient for BandedTriangularSolve.r   r!   r   r   r   r   Tr   
LEFT_RIGHT)kalignNr>   )rh   r   rI   r   r   r	   banded_triangular_solver
   r   r   rl   rm   rG   rn   )r   r   r   r   	num_bandsr   lower_ar   r   r   a_shapeb_shaperarbs                 r   _BandedTriangularSolveGradr    s    	iil!iil!ooa $)kk)$)KK 'jjm!--W)m5&ooa488Foofa488F''Y]#Q'|=F ''1i!m$L:F gg QWW%=%=%?ggcrlaggcrl"6>OOA'OOA',,WSb\73B<H&"bX00bA7K&X00bA7K&	r   MatrixTriangularSolvec                    | j                   d   }| j                   d   }| j                  d      }| j                  d      }| j                  d   }t        j                  ||||       }|rt        j                  ||d       }nt        j                  ||d       }|rt        j                  |dd      }nt        j                  |dd      }|j                  j                         r=|j                  j                         r#|j                  d	d
 |j                  d	d
 k(  r||fS t        j                  |      }	t        j                  |      }
t        j                  |	d	d
 |
d	d
       \  }}t        j                  t        j                  ||      |	      }t        j                  t        j                  ||      |
      }||fS )z#Gradient for MatrixTriangularSolve.r   r!   r   r   r   Tr   r   Nr   r>   )rh   r   r   r	   r   r
   r   r   r   rI   rl   rm   rG   rn   )r   r   r   r   r   r  r   r   r   r  r  r  r  s                r   _MatrixTriangularSolveGradr    s    	iil!iil!kk)$)KK 'jjm!--W)m5&ooa488Foofa488F''A6F''26Fgg QWW%=%=%?ggcrlaggcrl"6>OOA'OOA',,WSb\73B<H&"bX00bA7K&X00bA7K&	r   c                 >    | t        j                  | | z  |z         z  S rY   )r
   
reciprocal)rq   epsilons     r   _SafeReciprocalr#    s     	
X  Q1	11r   Eigc           
         | j                   d   }| j                  d      }t        j                  ||g      5  |rx| j                   d   }t	        j
                  |      }t        j                  t        t        j                  |d      t        j                  |d      z
        t        j                  |            }t        j                  |      }t        j                  ||      }t        j                  |      }	t        j                  t        j                  t        j                   t        j"                  |      |j$                                    }
|	||t        j                  t        j                  ||      |
      z
  z  z  }	t'        j(                  |t        j                  |	|            }nwt'        j*                  | j,                  d         \  }}t	        j
                  |      }t'        j(                  |t        j                  t        j                  |      |            }t        j                   || j,                  d   j$                        cddd       S # 1 sw Y   yxY w)a5  Gradient for Eig.

  Based on eq. 4.77 from paper by
  Christoph Boeddeker et al.
  https://arxiv.org/abs/1701.00392
  See also
  "Computation of eigenvalue and eigenvector derivatives
  for a general complex-valued eigensystem" by Nico van der Aa.
  As for now only distinct eigenvalue case is considered.
  r   	compute_vr!   r   r   N)r   r   r   control_dependenciesr   r   r   r   r#  expand_dimsr   r
   rj   r   matrix_diagr   r   r   rA   r	   r   eigrh   )r   grad_egrad_ver&  vvtfvgvmiddiag_grad_partr   r   s                r   _EigGradr4    s    	jjm!kk+&)  01 #5
**Q-a??1b 
#
#
##Ar*Y-B-B1b-IIK


q
!#a --
aOOB'c!!&)c ,,

$
$mmHMM#.		:<=n 
Q#A(>OOPPc
 &&r8??3+CDf^^BIIaL)da??1b
 &&
hooi33F;R@Bf==1!3!34G#5 #5 #5s   HI!!I*SelfAdjointEigV2c                    | j                   d   }| j                  d      }t        j                  ||g      5  |r| j                   d   }t	        j
                  t        t	        j                  |d      t	        j                  |d      z
        t	        j                  |            }t        j                  |t        j                  t	        j                  |      |t        j                  ||d      z  z   |d            }ndt        j                  | j                  d         \  }}t        j                  |t        j                  t	        j                  |      |d            }t	        j                  |t!        j"                  |      z   dd      }t	        j
                  |d	t	        j$                  |      z        }|cd
d
d
       S # 1 sw Y   y
xY w)zGradient for SelfAdjointEigV2.r   r&  r!   r   r   Tr   r   r   N)r   r   r   r'  r   r   r#  r(  r   r
   r   r)  r	   self_adjoint_eigrh   r   r   r   r   )	r   r+  r,  r-  r&  r.  r0  r   r   s	            r   _SelfAdjointEigV2Gradr8    s    	jjm!kk+&)  01  
**Q-a 
#
#
##Ar*Y-B-B1b-IIK


q
!#a 

//##F+(//!Vt<<=	f ((16daq'#,#8#8#@#$-1 34f ''1H(H"aPF&&v'*Y-G-G-O'OQFA     s   F	GGSvdc                    | j                   d   }|j                         j                  d      }t        j                  ||j
                        }t        j                  |      }| j                  d      sZt        j                  |d      \  }}}	t        j                  |t        j                  ||	d            }
|
j                  |       |
S | j                  d      }|j                         j                  d      }|j                         j                  d      }|j                  d   j                  |d         }|j                  d	   j                  |d         }|d
d j                  |d
d       j                  |d
d       }|j                  ||g      }|j                  d   j                   }|j                  d	   j                   }||t#        d      | j$                  d   }| j$                  d   }| j$                  d   }	t        j                  ||j
                        }d}||kD  rd}||}}|	|}	}||}}t'        j(                  |||g      5  |r)t+        ||z
        dkD  rt#        d| d| d| d| d	      t        j                  |      }t        j,                  |      }t        j.                  |      }t        j0                  t3        t        j4                  |d      t        j4                  |d	      z
        t        j6                  |            }t        j                  t3        |            }|	dd
d
d
|f   }|dd
d
d
|f   }t        j                  ||d      }t        j                  ||d      }||z  }||z  }|t        j                  |t9        j:                  |      z   |      z   t        j                  ||t9        j:                  |      z         z   }t        j                  |t        j                  ||d            }||k(  r|}nt        j<                  |d      } t        j                  | |      }!| t        j                  |!|d      z
  }"|rK|	dd
d
||f   }#|dd
d
||f   }$t        j                  ||$d      }%|"t        j                  |%|#d      z  }"t        j                  ||      }&t        j                  |&|"      }'||'z   }|j
                  j>                  rt9        j@                  |d	   |d
d	 |j
                        }(|(|z  })t        j                  |t9        j:                  |)      |)z
        }*dt        j                  |t        j                  |*|d            z  }+||+z  }|rt        j<                  |d      }
n|}
|
j                  |       |
cd
d
d
       S # 1 sw Y   y
xY w)z.Gradient for the singular value decomposition.r   r    
compute_uvT)r;  r   full_matricesr   r   NzPSVD gradient has not been implemented for input with unknown inner matrix shape.r!   Fz[svd gradient is not implemented for abs(m - n) > 1 when full_matrices is True. Received: m=z and n=z from op input=z with shape=rW   .r   	conjugater   r   )!rh   rk   with_rank_at_leastr
   r   rA   r   r)  r   r	   svdr   	set_shaper   
merge_withconcatenater   r   r   r   r'  abssquarerI   r   r#  r(  r   r   r   r   ri   r   ),r   grad_sgrad_ur,  r   r  
grad_s_matr8   r   r.  r   r<  grad_u_shapegrad_v_shaper   nr   use_adjoints_mats2s_shaper0  	s_inv_matv1grad_v1u_guv_gvf_uf_v
term1_nouvterm1grad_a_before_transposegv1tgv1t_v1
term2_nousv2grad_v2v1t_gv2u_s_invterm2r   r   
term3_nouvterm3s,                                               r   _SvdGradrd  2  sR    	iil!KKM,,Q/'==)&$$V,*	\	"nnQ40GAq!__Q
A NOF
WM++o.-!!#66q9,!!#66q9,ll2!!,r"23!ll2!!,r"23!''Sb(9:EE3B+##QF+'ll2!ll2!Y!)
	  	jjm!jjm!jjm!mmAqww!+U KaqAaqAVFF
 89 JQUa556Cwqc BSWIQ01 1 !!!$E		B ooa G!!!!"b)I,A,A"b,II	KQ	!A %%oa&89I	
32A2:BS!RaRZ G??1f5D??2w$7D
d(C
d(C 	X__S7??3+?%?GGsW__S%99:	;  OOAxz2NOEAv %''4@db)g(//'2FFj	sAqs{^a1%//"g>hoogrTBB
9-googz2e %wwKK"QWWMc
*a??9gooa.@1.DEjx
X__Zt<> >e &))
!T3f 'f
WUJ J Js   MW  W	c                 $   t        j                  |       }t        j                  |dz
  dft        j                        }t        j
                  |t        j                  ddgddgg      gd      }t        j                  | dddddf   |      S )zDShifts next-to-last dimension to the left, adding zero on the right.r    r@   r   r!   r>   .Nr   rankzerosr   rK   rH   constantpadrq   rg  rh  rj  s       r   
_LeftShiftrl    sx    		$
//4!8Q-v||
<%%!3!3aVaV4D!EFQO#	qab!}c	**r   c                 $   t        j                  |       }t        j                  |dz
  dft        j                        }t        j
                  |t        j                  ddgddgg      gd      }t        j                  | dddddf   |      S )	zDShifts next-to-last dimension to the right, adding zero on the left.r    r@   r!   r   r>   .Nr   rf  rk  s       r   _RightShiftrn    sz    		$
//4!8Q-v||
<%%!3!3aVaV4D!EFQO#	qcrc1~s	++r   TridiagonalMatMulc                    t        j                  | j                  d   d      }t        j                  | j                  d   d      }t        j                  | j                  d   d      }t        j                  | j                  d         }t        j
                  t        |      |z  d      }t        j
                  ||z  d      }t        j
                  t        |      |z  d      }t        ||z        ||z  z   t        ||z        z   }	t        j                  |d	      }t        j                  |d	      }t        j                  |d	      }||||	fS )
zGradient for TridiagonalMatMul.r   Tr=  r!   r       r   r>   r   )	r   r   rh   r
   rj   rn   rl  rn  r(  )
r   r   superdiag_conjmaindiag_conjsubdiag_conjrhs_conjsuperdiag_gradmaindiag_gradsubdiag_gradrhs_grads
             r   _TridiagonalMatMulGradrz    s+    --biildK.,,RYYq\TJ-++BIIaLDI,]]299Q<((&&z(';d'BL.%%hoB?-$$[%:T%AK,$./d't(;<=( ((<.''r:-&&|R8,	h	>>r   TridiagonalSolvec                     | j                   d   }| j                  d   }| j                  d      }| j                  d      }t        |      }t	        j
                  ||||      }t        ||       }||fS )z"Gradient for TridiagonalSolveGrad.r   partial_pivotingperturb_singular)r}  r~  )rh   r   r   _TransposeTridiagonalMatrixr	   tridiagonal_solve_MatmulExtractingThreeDiagonals)	r   r   diagsrq   r}  r~  diags_transposedgrad_rhs
grad_diagss	            r   _TridiagonalSolveGradr    s     ))A,%jjm![[!34[[!34 17))
''	)(
 0!<<*	X	r   c                 ,   | ddddf   }| j                   j                         r~t        j                  t	        | j                   dd       dgz   | j
                        }t        j                  | ddddf   |fd      }t        j                  || dd	ddf   fd      }nt        j                  |       }t        j                  |dz
  dft        j                        }t        j                  |t        j                  d	dgg      fd	      }t        j                  | ddddf   |      }t        j                  |t        j                  dd	gg      fd	      }t        j                  | dd	ddf   |      }t        j                  |||gd      S )
zTransposes a tridiagonal matrix.

  Args:
    diags: the diagonals of the input matrix in the compact form (see
      linalg_ops.tridiagonal_solve).

  Returns:
    Diagonals of the transposed matrix in the compact form.
  .r!   Nr   r@   r    r   r>   r   )rI   rl   r   rh  r3   rA   rH   rg  r   rK   ri  rj  r   r4   )r  diagrh  	superdiagsubdiagrg  superdiag_padsubdiag_pads           r   r  r    sq    
sAqy	$
[[!!# OODSb!12aS8LE  %Q
"3U!;"EIuS!SbS['9:DG>>% DOOTAXqM>E$$eY-?-?!Q-I%J*+-MeCABJ/?I""E9+=+=1vh+G#H()+KmmE#q#2#+.<G				49	CCr   c                 F   t        j                  | |z  d      }|j                  j                         rt	        j
                  t        | j                  dd       d| j                  d   gz   | j                        }t        j                  | t	        j                  |dddddf   |fd      z  d      }t        j                  | t	        j                  ||dddddf   fd      z  d      }nt	        j                  |      }t	        j
                  |dz
  dft        j                        }t	        j                  |t	        j                  d	dgd	d	gg      fd	      }t        j                  | t	        j                  |dddddf   |      z  d      }t	        j                  |t	        j                  dd	gd	d	gg      fd	      }t        j                  | t	        j                  |dddddf   |      z  d      }t        j                  |||gd      S )
a  Multiplies matrices and extracts three diagonals from the product.

  With sizes M x K and K x M, this function takes O(MK) time and O(M) space,
  while using math_ops.matmul, and then extracting the diagonals would take
  O(M^2 K) time and O(M^2) space.

  Args:
    x: first matrix
    y_tr: second matrix transposed

  Returns:
    Diagonals of the product in compact format (see
    linalg_ops.tridiagonal_solve)

  r   r>   Nr   r!   r@   .r    r   )r
   rn   rI   rl   r   rh  r3   rA   rH   rg  r   rK   ri  rj  r   r4   )	rq   y_trr  rh  r  r  rg  r  r  s	            r   r  r    s     
		QXB	/$	ZZ  "OOQWWSb\a--QWW>E##	Id3A:.6R@@rKI!!	IeT#ssA+%67bAALG >>$DOOTAXqM>E$$		""QFQF#345A?M##	IMM$sABz*M::EI""		""QFQF#345A?K!!	IMM$sCRC{+[99DG				49	CCr   N)g#B;)%__doc__tensorflow.python.frameworkr   r   tensorflow.python.opsr   r   r   r   r	   r
   tensorflow.python.ops.linalgr   r   RegisterGradientr  r   r   r   r   r   r   r   r   r  r  r  r#  r4  r8  rd  rl  rn  rz  r  r  r  rZ   r   r   <module>r     s  * / + + 1 & 0 , * ? o& 3==   '  hxCMM x  xv	 )*!s}} ! +! ()=6cmm =6 *=6@ ,-!#-- ! .! j!cmm  "2 d@- @- @-F m$
 
 %
 o&L93== L9 'L9^ -.3==  /@ -.3==  /@2
 e25 25 25j ()&cmm & *&R e@ @ @F+, )*?s}} ? +?( ()cmm  *,D>$Dr   