docstr: Sample a batch of transitions form the replay buffer. If the requested size is larger than the number
  of samples available in the replay buffer then the batch will return empty.
  :param size: the size of the batch to sample
  :return: a batch (list) of selected transitions from the replay buffer
docstr_tok: ["Sample","a","batch","of","transitions","form","the","replay","buffer",".","If","the","requested","size","is","larger","than","the","number","of","samples","available","in","the","replay","buffer","then","the","batch","will","return","empty",".",":","param","size",":","the","size","of","the","batch","to","sample",":","return",":","a","batch","(","list",")","of","selected","transitions","from","the","replay","buffer"]
code: def sample(self, size: int) -> List[Transition]:
      """
      Sample a batch of transitions form the replay buffer. If the requested size is larger than the number
      of samples available in the replay buffer then the batch will return empty.
      :param size: the size of the batch to sample
      :return: a batch (list) of selected transitions from the replay buffer
      """
      self.reader_writer_lock.lock_writing()
  
      if size % self.num_classes != 0:
          raise ValueError(
              "Sampling batches from a balanced replay buffer should be done only using batch sizes "
              "which are a multiple of the number of classes. The number of classes defined is: {} "
              "and the batch size requested is: {}".format(
                  self.num_classes, size
              )
          )
  
      batch_size_from_each_class = size // self.num_classes
  
      if self.allow_duplicates_in_batch_sampling:
          transitions_idx = [
              np.random.randint(
                  len(class_transitions),
                  size=batch_size_from_each_class,
              )
              for class_transitions in self.transitions
          ]
  
      else:
          for class_idx, class_transitions in enumerate(
              self.transitions
          ):
              if self.num_transitions() < batch_size_from_each_class:
                  raise ValueError(
                      "The replay buffer cannot be sampled since there are not enough transitions yet. "
                      "There are currently {} transitions for class {}".format(
                          len(class_transitions), class_idx
                      )
                  )
  
          transitions_idx = [
              np.random.choice(
                  len(class_transitions),
                  size=batch_size_from_each_class,
                  replace=False,
              )
              for class_transitions in self.transitions
          ]
  
      batch = []
      for class_idx, class_transitions_idx in enumerate(
          transitions_idx
      ):
          batch += [
              self.transitions[class_idx][i]
              for i in class_transitions_idx
          ]
  
      self.reader_writer_lock.release_writing()
  
      return batch
  
imports: import operator
  import random
  from enum import Enum
  from typing import List, Tuple, Any, Union
  import numpy
  from rl_coach.core_types import Transition
  from rl_coach.memories.memory import MemoryGranularity
  from rl_coach.memories.non_episodic.experience_replay import ExperienceReplayParameters, ExperienceReplay
  from rl_coach.schedules import Schedule, ConstantSchedule
label_desc: Use image node_id 3 for calling the BalancedExperienceReplay obj's underlying member method code with example usage: obj.sample(size) and returns: batch