class_docstr: Diffusion with node sampling on the given graph for node-level datasets, used in 
  `MVGRL <https://arxiv.org/pdf/2006.05582v1.pdf>`_.  Class objects callable via method 
  :meth:`views_fn`.
  
  Args:
      sample_size (int, optional): Number of nodes in the sampled subgraoh from a large graph.
          (default: :obj:`2000`)
      batch_size (int, optional): Number of subgraphs to sample. (default: :obj:`4`)
      mode (string, optional): Diffusion instantiation mode with two options:
          :obj:`"ppr"`: Personalized PageRank; :obj:`"heat"`: heat kernel; 
          (default: :obj:`"ppr"`)
      alpha (float, optinal): Teleport probability in a random walk. (default: :obj:`0.2`)
      t (float, optinal): Diffusion time. (default: :obj:`5`)
      add_self_loop (bool, optional): Set True to add self-loop to edge_index.
          (default: :obj:`True`)
docstr: Method to be called when :class:`DiffusionWithSample` object is called.
  
  Args:
      data (:class:`torch_geometric.data.Data`): The input graph or batched graphs.
      
  :rtype: :class:`torch_geometric.data.Data`.  
docstr_tok: ["Method","to","be","called","when",":","class",":","`","DiffusionWithSample","`","object","is","called",".","Args",":","data","(",":","class",":","`","torch_geometric.data.Data","`",")",":","The","input","graph","or","batched","graphs",".",":","rtype",":",":","class",":","`","torch_geometric.data.Data","`","."]
code: def views_fn(self, data):
      r"""Method to be called when :class:`DiffusionWithSample` object is called.
  
      Args:
          data (:class:`torch_geometric.data.Data`): The input graph or batched graphs.
  
      :rtype: :class:`torch_geometric.data.Data`.
      """
      node_num, _ = data.x.size()
      if self.add_self_loop:
          sl = torch.tensor(
              [[n, n] for n in range(node_num)], device=data.x.device
          ).t()
          edge_index = torch.cat((data.edge_index, sl), dim=1)
      else:
          edge_index = data.edge_index.detach().clone()
  
      orig_adj = to_dense_adj(edge_index)[0]
      orig_adj = torch.where(
          orig_adj > 1, torch.ones_like(orig_adj), orig_adj
      )
      d = torch.diag(torch.sum(orig_adj, 1))
  
      if self.mode == "ppr":
          dinv = torch.inverse(torch.sqrt(d))
          at = torch.matmul(torch.matmul(dinv, orig_adj), dinv)
          diff_adj = self.alpha * torch.inverse(
              (torch.eye(orig_adj.shape[0]) - (1 - self.alpha) * at)
          )
  
      elif self.mode == "heat":
          diff_adj = torch.exp(
              self.t * (torch.matmul(orig_adj, torch.inverse(d)) - 1)
          )
  
      else:
          raise Exception(
              "Must choose one diffusion instantiation mode from 'ppr' and 'heat'!"
          )
  
      if self.epsilon:
          epsilons = [1e-5, 1e-4, 1e-3, 1e-2]
          avg_degree = torch.sum(orig_adj) / orig_adj.shape[0]
          ep = epsilons[
              torch.argmin(
                  [
                      abs(
                          avg_degree
                          - torch.sum(diff_adj >= e) / diff_adj.shape[0]
                      )
                      for e in epsilons
                  ]
              )
          ]
  
          diff_adj[diff_adj < ep] = 0.0
          scaler = MinMaxScaler()
          scaler.fit(diff_adj)
          diff_adj = torch.tensor(
              scaler.transform(diff_adj), device=data.x.device
          )
  
      dlist_orig_x = []
      dlist_diff_x = []
      drop_num = node_num - self.sample_size
      for b in range(self.batch_size):
          idx_drop = torch.randperm(node_num, device=data.x.device)[
              :drop_num
          ]
          idx_nondrop = [
              n for n in range(node_num) if not n in idx_drop
          ]
  
          sample_orig_adj = orig_adj.clone()
          sample_orig_adj = sample_orig_adj[idx_nondrop, :][
              :, idx_nondrop
          ]
  
          sample_diff_adj = diff_adj.clone()
          sample_diff_adj = sample_diff_adj[idx_nondrop, :][
              :, idx_nondrop
          ]
  
          sample_orig_x = data.x[idx_nondrop]
  
          edge_ind, edge_attr = dense_to_sparse(sample_diff_adj)
  
          dlist_orig_x.append(
              Data(
                  x=sample_orig_x,
                  edge_index=dense_to_sparse(sample_orig_adj)[0],
              )
          )
          dlist_diff_x.append(
              Data(
                  x=sample_orig_x,
                  edge_index=edge_ind,
                  edge_attr=edge_attr,
              )
          )
  
      return Batch.from_data_list(dlist_orig_x), Batch.from_data_list(
          dlist_diff_x
      )
  
imports: import torch
  from torch_geometric.utils import to_dense_adj, dense_to_sparse, dropout_adj, degree, add_remaining_self_loops
  from sklearn.preprocessing import MinMaxScaler
  from torch_geometric.data import Batch, Data
  from dig.sslgraph.utils.adaptive import degree_drop_weights, pr_drop_weights, evc_drop_weights, drop_edge_weighted
label_desc: Use image node_id 3 for calling the DiffusionWithSample obj's underlying member method code with example usage: obj.views_fn(data) and returns: Batch,  Batch