class_docstr: A wrapper for torch.linalg.eigh to avoid complex eigenvalues for degenerate case.
  
  Examples
  --------
  >>> import torch
  >>> import numpy as np
  >>> from deepchem.utils.differentiation_utils import LinearOperator
  >>> A = LinearOperator.m(torch.rand(2, 2))
  >>> evals, evecs = degen_symeig.apply(A.fullmatrix())
  >>> evals.shape
  torch.Size([2])
  >>> evecs.shape
  torch.Size([2, 2])
docstr: Calculate the gradient of the eigenvalues and eigenvectors of a symmetric matrix.
  
  Parameters
  ----------
  grad_eival: torch.Tensor
      The gradient of the eigenvalues. Shape: ``(*BA, q)``.
  grad_eivec: torch.Tensor
      The gradient of the eigenvectors. Shape: ``(*BA, q, q)``.
  
  Returns
  -------
  result: torch.Tensor
      The gradient of the symmetric matrix. Shape: ``(*BA, q, q)``.
docstr_tok: ["Calculate","the","gradient","of","the","eigenvalues","and","eigenvectors","of","a","symmetric","matrix",".","Parameters","--","--","--","--","--","grad_eival",":","torch.Tensor","The","gradient","of","the","eigenvalues",".","Shape",":","``","(","*","BA",",","q",")","``",".","grad_eivec",":","torch.Tensor","The","gradient","of","the","eigenvectors",".","Shape",":","``","(","*","BA",",","q",",","q",")","``",".","Returns","--","--","--","-","result",":","torch.Tensor","The","gradient","of","the","symmetric","matrix",".","Shape",":","``","(","*","BA",",","q",",","q",")","``","."]
code: def backward(ctx, grad_eival, grad_eivec):
      """Calculate the gradient of the eigenvalues and eigenvectors of a symmetric matrix.
  
      Parameters
      ----------
      grad_eival: torch.Tensor
          The gradient of the eigenvalues. Shape: ``(*BA, q)``.
      grad_eivec: torch.Tensor
          The gradient of the eigenvectors. Shape: ``(*BA, q, q)``.
  
      Returns
      -------
      result: torch.Tensor
          The gradient of the symmetric matrix. Shape: ``(*BA, q, q)``.
  
      """
      eival, eivec = ctx.saved_tensors
      min_threshold = torch.finfo(eival.dtype).eps ** 0.6
      eivect = eivec.transpose(-2, -1).conj()
  
      # remove the degenerate part
      # see https://arxiv.org/pdf/2011.04366.pdf
      if grad_eivec is not None:
          # take the contribution from the eivec
          F = eival.unsqueeze(-2) - eival.unsqueeze(-1)
          idx = torch.abs(F) <= min_threshold
          F[idx] = float("inf")
  
          F = F.pow(-1)
          F = F * torch.matmul(eivect, grad_eivec)
          result = torch.matmul(eivec, torch.matmul(F, eivect))
      else:
          result = torch.zeros_like(eivec)
  
      # calculate the contribution from the eival
      if grad_eival is not None:
          result += torch.matmul(
              eivec, grad_eival.unsqueeze(-1) * eivect
          )
  
      # symmetrize to reduce numerical instability
      result = (result + result.transpose(-2, -1).conj()) * 0.5
      return result
  
file_path: deepchem/deepchem/utils/differentiation_utils/symeig.py
imports: import torch
  from typing import Optional, Sequence, Tuple, Union
  from deepchem.utils.differentiation_utils import LinearOperator
  import functools
  from deepchem.utils.pytorch_utils import tallqr, to_fortran_order
  from deepchem.utils.differentiation_utils import get_bcasted_dims
label_desc: Use image node_id 2 for calling the degen_symeig obj's underlying member method code with example usage: obj.backward(ctx, grad_eival, grad_eivec) and returns: result