text: import numpy as np
  # Sampler class is written by referring to https://github.com/pytorch/pytorch/blob/master/torch/utils/data/sampler.py.
  class Sampler(object):
      r"""Base class for all Samplers.
  
      Every Sampler subclass has to provide an :meth:`__iter__` method, providing a
      way to iterate over indices of dataset elements, and a :meth:`__len__` method
      that returns the length of the returned iterators.
      """
  
      def __init__(self, data_source):
          pass
  
      def __iter__(self):
          raise NotImplementedError
  
      def __len__(self):
          return len(self.data_source)
  
  class SequentialSampler(Sampler):
      r"""Samples elements sequentially, always in the same order.
  
      Arguments:
          data_source (Dataset): dataset to sample from
      """
  
      def __init__(self, data_source):
          self.data_source = data_source
  
      def __iter__(self):
          return iter(range(len(self.data_source)))
  
      def __len__(self) -> int:
          return len(self.data_source)
  
  
  class RandomSampler(Sampler):
      r"""Samples elements randomly. If without replacement, then sample from a shuffled dataset.
      If with replacement, then user can specify :attr:`num_samples` to draw.
  
      Arguments:
          data_source (Dataset): dataset to sample from
          replacement (bool): samples are drawn on-demand with replacement if ``True``, default=``False``
          num_samples (int): number of samples to draw, default=`len(dataset)`. This argument
              is supposed to be specified only when `replacement` is ``True``.
      """
  
      def __init__(self, data_source, replacement=False,
                   num_samples=None):
          self.data_source = data_source
          self.replacement = replacement
          self._num_samples = num_samples
  
          if not isinstance(self.replacement, bool):
              raise TypeError(">> replacement should be a boolean value, but got "
                              "replacement={}".format(self.replacement))
  
          if self._num_samples is not None and not replacement:
              raise ValueError(">> With replacement=False, num_samples should not be specified, "
                               "since a random permute will be performed.")
  
          if not isinstance(self.num_samples, int) or self.num_samples <= 0:
              raise ValueError(">> num_samples should be a positive integer "
                               "value, but got num_samples={}".format(self.num_samples))
  
      @property
      def num_samples(self):
          # dataset size might change at runtime
          if self._num_samples is None:
              return len(self.data_source)
          return self._num_samples
  
      def __iter__(self):
          n = len(self.data_source)
          if self.replacement:
              for _ in range(self.num_samples // 32):
                  yield from np.random.randint(high=n, size=(32,)).tolist()
              yield from np.random.randint(high=n, size=(self.num_samples % 32,)).tolist()
          else:
              yield from np.random.permutation(np.arange(n)).tolist()
  
      def __len__(self):
          return self.num_samples
  
  class BatchSampler(Sampler):
      r"""Wraps another sampler to yield a mini-batch of indices.
  
      Args:
          sampler (Sampler or Iterable): Base sampler. Can be any iterable object
          batch_size (int): Size of mini-batch.
          drop_last (bool): If ``True``, the sampler will drop the last batch if
              its size would be less than ``batch_size``
  
      Example:
          >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=False))
          [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
          >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=True))
          [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
      """
  
      def __init__(self, sampler, batch_size, drop_last):
          # Since collections.abc.Iterable does not check for `__getitem__`, which
          # is one way for an object to be an iterable, we don't do an `isinstance`
          # check here.
          if not isinstance(sampler, Sampler):
              raise ValueError("sampler should be an instance of "
                               "torch.utils.data.Sampler, but got sampler={}"
                               .format(sampler))
          if not isinstance(batch_size, int) or isinstance(batch_size, bool) or \
                  batch_size <= 0:
              raise ValueError("batch_size should be a positive integer value, "
                               "but got batch_size={}".format(batch_size))
          if not isinstance(drop_last, bool):
              raise ValueError("drop_last should be a boolean value, but got "
                               "drop_last={}".format(drop_last))
          self.sampler = sampler
          self.batch_size = batch_size
          self.drop_last = drop_last
  
      def __iter__(self):
          batch = []
          for idx in self.sampler:
              batch.append(idx)
              if len(batch) == self.batch_size:
                  yield batch
                  batch = []
          if len(batch) > 0 and not self.drop_last:
              yield batch
  
      def __len__(self):
          if self.drop_last:
              return len(self.sampler) // self.batch_size  # type: ignore
          else:
              return (len(self.sampler) + self.batch_size - 1) // self.batch_size  # type: ignore
  