class_docstr: A mix-in class for storing tensors as properties with helper methods.
docstr: This is an in place operation to reformat all tensor class attributes
  based on a set of given indices using torch.gather. This is useful when
  attributes which are batched tensors e.g. shape (N, 3) need to be
  multiplied with another tensor which has a different first dimension
  e.g. packed vertices of shape (V, 3).
  
  Example
  
  .. code-block:: python
  
      self.specular_color = (N, 3) tensor of specular colors for each mesh
  
  A lighting calculation may use
  
  .. code-block:: python
  
      verts_packed = meshes.verts_packed()  # (V, 3)
  
  To multiply these two tensors the batch dimension needs to be the same.
  To achieve this we can do
  
  .. code-block:: python
  
      batch_idx = meshes.verts_packed_to_mesh_idx()  # (V)
  
  This gives index of the mesh for each vertex in verts_packed.
  
  .. code-block:: python
  
      self.gather_props(batch_idx)
      self.specular_color = (V, 3) tensor with the specular color for
                               each packed vertex.
  
  torch.gather requires the index tensor to have the same shape as the
  input tensor so this method takes care of the reshaping of the index
  tensor to use with class attributes with arbitrary dimensions.
  
  Args:
      batch_idx: shape (B, ...) where `...` represents an arbitrary
          number of dimensions
  
  Returns:
      self with all properties reshaped. e.g. a property with shape (N, 3)
      is transformed to shape (B, 3).
docstr_tok: ["This","is","an","in","place","operation","to","reformat","all","tensor","class","attributes","based","on","a","set","of","given","indices","using","torch.gather",".","This","is","useful","when","attributes","which","are","batched","tensors","e.g",".","shape","(","N",",","3",")","need","to","be","multiplied","with","another","tensor","which","has","a","different","first","dimension","e.g",".","packed","vertices","of","shape","(","V",",","3",")",".","Example","..","code-block",":",":","python","self.specular_color","=","(","N",",","3",")","tensor","of","specular","colors","for","each","mesh","A","lighting","calculation","may","use","..","code-block",":",":","python","verts_packed","=","meshes.verts_packed","(",")","#","(","V",",","3",")","To","multiply","these","two","tensors","the","batch","dimension","needs","to","be","the","same",".","To","achieve","this","we","can","do","..","code-block",":",":","python","batch_idx","=","meshes.verts_packed_to_mesh_idx","(",")","#","(","V",")","This","gives","index","of","the","mesh","for","each","vertex","in","verts_packed",".","..","code-block",":",":","python","self.gather_props","(","batch_idx",")","self.specular_color","=","(","V",",","3",")","tensor","with","the","specular","color","for","each","packed","vertex",".","torch.gather","requires","the","index","tensor","to","have","the","same","shape","as","the","input","tensor","so","this","method","takes","care","of","the","reshaping","of","the","index","tensor","to","use","with","class","attributes","with","arbitrary","dimensions",".","Args",":","batch_idx",":","shape","(","B",",","...",")","where","`","...","`","represents","an","arbitrary","number","of","dimensions","Returns",":","self","with","all","properties","reshaped",".","e.g",".","a","property","with","shape","(","N",",","3",")","is","transformed","to","shape","(","B",",","3",")","."]
code: def gather_props(self, batch_idx) -> "TensorProperties":
      """
      This is an in place operation to reformat all tensor class attributes
      based on a set of given indices using torch.gather. This is useful when
      attributes which are batched tensors e.g. shape (N, 3) need to be
      multiplied with another tensor which has a different first dimension
      e.g. packed vertices of shape (V, 3).
  
      Example
  
      .. code-block:: python
  
          self.specular_color = (N, 3) tensor of specular colors for each mesh
  
      A lighting calculation may use
  
      .. code-block:: python
  
          verts_packed = meshes.verts_packed()  # (V, 3)
  
      To multiply these two tensors the batch dimension needs to be the same.
      To achieve this we can do
  
      .. code-block:: python
  
          batch_idx = meshes.verts_packed_to_mesh_idx()  # (V)
  
      This gives index of the mesh for each vertex in verts_packed.
  
      .. code-block:: python
  
          self.gather_props(batch_idx)
          self.specular_color = (V, 3) tensor with the specular color for
                                   each packed vertex.
  
      torch.gather requires the index tensor to have the same shape as the
      input tensor so this method takes care of the reshaping of the index
      tensor to use with class attributes with arbitrary dimensions.
  
      Args:
          batch_idx: shape (B, ...) where `...` represents an arbitrary
              number of dimensions
  
      Returns:
          self with all properties reshaped. e.g. a property with shape (N, 3)
          is transformed to shape (B, 3).
      """
      # Iterate through the attributes of the class which are tensors.
      for k in dir(self):
          v = getattr(self, k)
          if torch.is_tensor(v):
              if v.shape[0] > 1:
                  # There are different values for each batch element
                  # so gather these using the batch_idx.
                  # First clone the input batch_idx tensor before
                  # modifying it.
                  _batch_idx = batch_idx.clone()
                  idx_dims = _batch_idx.shape
                  tensor_dims = v.shape
                  if len(idx_dims) > len(tensor_dims):
                      msg = "batch_idx cannot have more dimensions than %s. "
                      msg += "got shape %r and %s has shape %r"
                      raise ValueError(
                          msg % (k, idx_dims, k, tensor_dims)
                      )
                  if idx_dims != tensor_dims:
                      # To use torch.gather the index tensor (_batch_idx) has
                      # to have the same shape as the input tensor.
                      new_dims = len(tensor_dims) - len(idx_dims)
                      new_shape = idx_dims + (1,) * new_dims
                      expand_dims = (-1,) + tensor_dims[1:]
                      _batch_idx = _batch_idx.view(*new_shape)
                      _batch_idx = _batch_idx.expand(*expand_dims)
  
                  v = v.gather(0, _batch_idx)
                  setattr(self, k, v)
      return self
  
imports: import copy
  import inspect
  import warnings
  from typing import Any, List, Optional, Tuple, TypeVar, Union
  import numpy
  import torch
  import torch.nn
  from ..common.datatypes import Device, make_device
label_desc: Use image node_id 9 for calling the TensorProperties obj's underlying member method code with example usage: obj.gather_props(batch_idx) and returns: self