code: def compute_bootstrap_value(
      sample_batch: SampleBatch, policy: Policy
  ) -> SampleBatch:
      """Performs a value function computation at the end of a trajectory.
  
      If the trajectory is terminated (not truncated), will not use the value function,
      but assume that the value of the last timestep is 0.0.
      In all other cases, will use the given policy's value function to compute the
      "bootstrapped" value estimate at the end of the given trajectory. To do so, the
      very last observation (sample_batch[NEXT_OBS][-1]) and - if applicable -
      the very last state output (sample_batch[STATE_OUT][-1]) wil be used as inputs to
      the value function.
  
      The thus computed value estimate will be stored in a new column of the
      `sample_batch`: SampleBatch.VALUES_BOOTSTRAPPED. Thereby, values at all timesteps
      in this column are set to 0.0, except or the last timestep, which receives the
      computed bootstrapped value.
      This is done, such that in any loss function (which processes raw, intact
      trajectories, such as those of IMPALA and APPO) can use this new column as follows:
  
      Example: numbers=ts in episode, '|'=episode boundary (terminal),
      X=bootstrapped value (!= 0.0 b/c ts=12 is not a terminal).
      ts=5 is NOT a terminal.
      T:                     8   9  10  11  12 <- no terminal
      VF_PREDS:              .   .   .   .   .
      VALUES_BOOTSTRAPPED:   0   0   0   0   X
  
      Args:
          sample_batch: The SampleBatch (single trajectory) for which to compute the
              bootstrap value at the end. This SampleBatch will be altered in place
              (by adding a new column: SampleBatch.VALUES_BOOTSTRAPPED).
          policy: The Policy object, whose value function to use.
  
      Returns:
           The altered SampleBatch (with the extra SampleBatch.VALUES_BOOTSTRAPPED
           column).
      """
      # Trajectory is actually complete -> last r=0.0.
      if sample_batch[SampleBatch.TERMINATEDS][-1]:
          last_r = 0.0
      # Trajectory has been truncated -> last r=VF estimate of last obs.
      else:
          # Input dict is provided to us automatically via the Model's
          # requirements. It's a single-timestep (last one in trajectory)
          # input_dict.
          # Create an input dict according to the Policy's requirements.
          input_dict = sample_batch.get_single_step_input_dict(
              policy.view_requirements, index="last"
          )
          if policy.config.get("_enable_new_api_stack"):
              # Note: During sampling you are using the parameters at the beginning of
              # the sampling process. If I'll be using this advantages during training
              # should it not be the latest parameters during training for this to be
              # correct? Does this mean that I need to preserve the trajectory
              # information during training and compute the advantages inside the loss
              # function?
              # TODO (Kourosh): Another thing we need to figure out is which end point
              #  to call here (why forward_exploration)? What if this method is getting
              #  called inside the learner loop or via another abstraction like
              #  RLSampler.postprocess_trajectory() which is non-batched cpu/gpu task
              #  running across different processes for different trajectories?
              #  This implementation right now will compute even the action_dist which
              #  will not be needed but takes time to compute.
              if policy.framework == "torch":
                  input_dict = convert_to_torch_tensor(
                      input_dict, device=policy.device
                  )
  
              # For recurrent models, we need to add a time dimension.
              input_dict = policy.maybe_add_time_dimension(
                  input_dict, seq_lens=input_dict[SampleBatch.SEQ_LENS]
              )
              input_dict = NestedDict(input_dict)
              fwd_out = policy.model.forward_exploration(input_dict)
              # For recurrent models, we need to remove the time dimension.
              fwd_out = policy.maybe_remove_time_dimension(fwd_out)
              last_r = fwd_out[SampleBatch.VF_PREDS][-1]
          else:
              last_r = policy._value(**input_dict)
  
      vf_preds = np.array(sample_batch[SampleBatch.VF_PREDS])
      # We need to squeeze out the time dimension if there is one
      if len(vf_preds.shape) == 2:
          vf_preds = np.squeeze(vf_preds, axis=1)
          squeezed = True
      else:
          squeezed = False
  
      # Set the SampleBatch.VALUES_BOOTSTRAPPED field to VF_PREDS[1:] + the
      # very last timestep (where this bootstrapping value is actually needed), which
      # we set to the computed `last_r`.
      sample_batch[SampleBatch.VALUES_BOOTSTRAPPED] = np.concatenate(
          [
              convert_to_numpy(vf_preds[1:]),
              np.array([convert_to_numpy(last_r)], dtype=np.float32),
          ],
          axis=0,
      )
  
      if squeezed:
          sample_batch[SampleBatch.VF_PREDS] = np.expand_dims(
              vf_preds, axis=1
          )
          sample_batch[
              SampleBatch.VALUES_BOOTSTRAPPED
          ] = np.expand_dims(
              sample_batch[SampleBatch.VALUES_BOOTSTRAPPED], axis=1
          )
  
      return sample_batch
  
file_path: ray/rllib/evaluation/postprocessing.py
imports: import numpy
  import scipy.signal
  from typing import Dict, Optional
  from ray.rllib.evaluation.episode import Episode
  from ray.rllib.policy.policy import Policy
  from ray.rllib.policy.sample_batch import SampleBatch
  from ray.rllib.utils.annotations import DeveloperAPI
  from ray.rllib.utils.nested_dict import NestedDict
  from ray.rllib.utils.numpy import convert_to_numpy
  from ray.rllib.utils.torch_utils import convert_to_torch_tensor
  from ray.rllib.utils.typing import AgentID
  from ray.rllib.utils.typing import TensorType
label_desc: Use image node_id 4 for calling a global function with example usage: compute_bootstrap_value(sample_batch, policy) and returns: sample_batch