class_docstr: This is the proportional sampling variant of the prioritized experience replay as described
  in https://arxiv.org/pdf/1511.05952.pdf.
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 self.num_transitions() >= size:
          # split the tree leaves to equal segments and sample one transition from each segment
          batch = []
          segment_size = self.sum_tree.total_value() / size
  
          # get the maximum weight in the memory
          min_probability = (
              self.min_tree.total_value() / self.sum_tree.total_value()
          )  # min P(j) = min p^a / sum(p^a)
          max_weight = (
              min_probability * self.num_transitions()
          ) ** -self.beta.current_value  # max wi
  
          # sample a batch
          for i in range(size):
              segment_start = segment_size * i
              segment_end = segment_size * (i + 1)
  
              # sample leaf and calculate its weight
              val = random.uniform(segment_start, segment_end)
              (
                  leaf_idx,
                  priority,
                  transition,
              ) = self.sum_tree.get_element_by_partial_sum(val)
              priority /= (
                  self.sum_tree.total_value()
              )  # P(j) = p^a / sum(p^a)
              weight = (
                  self.num_transitions() * priority
              ) ** -self.beta.current_value  # (N * P(j)) ^ -beta
              normalized_weight = (
                  weight / max_weight
              )  # wj = ((N * P(j)) ^ -beta) / max wi
  
              transition.info["idx"] = leaf_idx
              transition.info["weight"] = normalized_weight
  
              batch.append(transition)
  
          self.beta.step()
  
      else:
          raise ValueError(
              "The replay buffer cannot be sampled since there are not enough transitions yet. "
              "There are currently {} transitions".format(
                  self.num_transitions()
              )
          )
  
      self.reader_writer_lock.release_writing()
      return batch
  
imports: import operator
  import random
  from enum import Enum
  from typing import List, Tuple, Any
  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 4 for calling the PrioritizedExperienceReplay obj's underlying member method code with example usage: obj.sample(size) and returns: batch