class_docstr: EditableModule is a base class to enable classes that it inherits be
  converted to pure functions for higher order derivatives purpose.
  
  Usage
  -----
  To use this class, the user must implement the ``getparamnames`` method
  which returns a list of tensor names that affect the output of the method
  with name indicated in ``methodname``.
  
  Used in:
  
  - Classes of Density Functional Theory (DFT).
  
  - It can also be used in other classes that need to be converted to pure
    functions for higher order derivatives purpose.
  
  Examples
  --------
  >>> import torch
  >>> from deepchem.utils.differentiation_utils import EditableModule
  >>> class A(EditableModule):
  ...     def __init__(self, a):
  ...         self.b = a*a
  ...
  ...     def mult(self, x):
  ...         return self.b * x
  ...
  ...     def getparamnames(self, methodname, prefix=""):
  ...         if methodname == "mult":
  ...             return [prefix+"b"]
  ...         else:
  ...             raise KeyError()
  >>> a = torch.tensor(2.0).requires_grad_()
  >>> x = torch.tensor(0.4).requires_grad_()
  >>> alpha = A(a)
  >>> alpha.mult(x)
  tensor(1.6000, grad_fn=<MulBackward0>)
  >>> alpha.getparamnames("mult")
  ['b']
  >>> alpha.assertparams(alpha.mult, x)
  "mult" method check done
docstr: Sequence the tensors used in executing the method by calling the method
  and see which parameters are connected in the backward graph
docstr_tok: ["Sequence","the","tensors","used","in","executing","the","method","by","calling","the","method","and","see","which","parameters","are","connected","in","the","backward","graph"]
code: def __list_operating_params(self, method, *args, **kwargs):
      """Sequence the tensors used in executing the method by calling the method
      and see which parameters are connected in the backward graph"""
  
      # get all the tensors recursively
      all_tensors, all_names = _get_tensors(self)
  
      # copy the tensors and require them to be differentiable
      copy_tensors0 = [
          tensor.clone().detach().requires_grad_()
          for tensor in all_tensors
      ]
      copy_tensors = copy.copy(copy_tensors0)
      _set_tensors(self, copy_tensors)
  
      # run the method and see which one has the gradients
      output = method(*args, **kwargs)
      if not isinstance(output, torch.Tensor):
          raise RuntimeError(
              "The method to be asserted must have a tensor output"
          )
      output = output.sum()
      grad_tensors = torch.autograd.grad(
          output, copy_tensors0, retain_graph=True, allow_unused=True
      )
  
      # return the original tensor
      all_tensors_copy = copy.copy(all_tensors)
      _set_tensors(self, all_tensors_copy)
  
      names = []
      params = []
      for i, grad in enumerate(grad_tensors):
          if grad is None:
              continue
          names.append(all_names[i])
          params.append(all_tensors[i])
  
      return names, params
  
imports: import inspect
  import warnings
  from abc import abstractmethod
  import copy
  import torch
  from typing import Sequence, Union, Dict, List, Callable, Any
  from deepchem.utils.attribute_utils import get_attr, set_attr, del_attr
label_desc: Use image node_id 11 for calling the EditableModule obj's underlying member method code with example usage: obj.__list_operating_params(method) and returns: names,  params