docstr: Computes sample paths by unrolling the RNN starting with a initial
  input and state.
  
  Parameters
  ----------
  static_feat : Tensor
      static features. Shape: (batch_size, num_static_features).
  past_target : Tensor
      target history. Shape: (batch_size, history_length).
  time_feat : Tensor
      time features. Shape: (batch_size, prediction_length, num_time_features).
  scale : Tensor
      tensor containing the scale of each element in the batch. Shape: (batch_size, 1, 1).
  begin_states : List or Tensor
      list of initial states for the LSTM layers or tensor for GRU.
      the shape of each tensor of the list should be (num_layers, batch_size, num_cells)
  Returns
  --------
  Tensor
      A tensor containing sampled paths.
      Shape: (batch_size, num_sample_paths, prediction_length).
docstr_tok: ["Computes","sample","paths","by","unrolling","the","RNN","starting","with","a","initial","input","and","state",".","Parameters","--","--","--","--","--","static_feat",":","Tensor","static","features",".","Shape",":","(","batch_size",",","num_static_features",")",".","past_target",":","Tensor","target","history",".","Shape",":","(","batch_size",",","history_length",")",".","time_feat",":","Tensor","time","features",".","Shape",":","(","batch_size",",","prediction_length",",","num_time_features",")",".","scale",":","Tensor","tensor","containing","the","scale","of","each","element","in","the","batch",".","Shape",":","(","batch_size",",","1",",","1",")",".","begin_states",":","List","or","Tensor","list","of","initial","states","for","the","LSTM","layers","or","tensor","for","GRU",".","the","shape","of","each","tensor","of","the","list","should","be","(","num_layers",",","batch_size",",","num_cells",")","Returns","--","--","--","--","Tensor","A","tensor","containing","sampled","paths",".","Shape",":","(","batch_size",",","num_sample_paths",",","prediction_length",")","."]
code: def sampling_decoder(
      self,
      static_feat: torch.Tensor,
      past_target: torch.Tensor,
      past_control: torch.Tensor,
      time_feat: torch.Tensor,
      scale: torch.Tensor,
      control_scale: torch.Tensor,
      future_control: torch.Tensor,
      begin_states: Union[torch.Tensor, List[torch.Tensor]],
  ) -> torch.Tensor:
      """
      Computes sample paths by unrolling the RNN starting with a initial
      input and state.
  
      Parameters
      ----------
      static_feat : Tensor
          static features. Shape: (batch_size, num_static_features).
      past_target : Tensor
          target history. Shape: (batch_size, history_length).
      time_feat : Tensor
          time features. Shape: (batch_size, prediction_length, num_time_features).
      scale : Tensor
          tensor containing the scale of each element in the batch. Shape: (batch_size, 1, 1).
      begin_states : List or Tensor
          list of initial states for the LSTM layers or tensor for GRU.
          the shape of each tensor of the list should be (num_layers, batch_size, num_cells)
      Returns
      --------
      Tensor
          A tensor containing sampled paths.
          Shape: (batch_size, num_sample_paths, prediction_length).
      """
  
      # blows-up the dimension of each tensor to batch_size * self.num_parallel_samples for increasing parallelism
      repeated_past_target = past_target.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      )
      repeated_time_feat = time_feat.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      )
      repeated_past_control = past_control.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      )
      repeated_static_feat = static_feat.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      ).unsqueeze(1)
      repeated_future_control = future_control.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      )
      repeated_scale = scale.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      )
      repeated_control_scale = control_scale.repeat_interleave(
          repeats=self.num_parallel_samples, dim=0
      )
  
      if self.cell_type == "LSTM":
          repeated_states = [
              s.repeat_interleave(
                  repeats=self.num_parallel_samples, dim=1
              )
              for s in begin_states
          ]
      else:
          repeated_states = begin_states.repeat_interleave(
              repeats=self.num_parallel_samples, dim=1
          )
  
      future_samples = []
  
      # for each future time-units we draw new samples for this time-unit and update the state
      for k in range(self.prediction_length):
          # (batch_size * num_samples, 1, *target_shape, num_lags)
          lags = self.get_lagged_subsequences(
              sequence=repeated_past_target,
              sequence_length=self.history_length + k,
              indices=self.shifted_lags,
              subsequences_length=1,
          )
          control_lags = self.get_lagged_subsequences(
              sequence=repeated_past_control,
              sequence_length=self.history_length + k,
              indices=self.shifted_lags,
              subsequences_length=1,
          )
  
          # (batch_size * num_samples, 1, *target_shape, num_lags)
          lags_scaled = lags / repeated_scale.unsqueeze(-1)
  
          control_lags_scaled = (
              control_lags / repeated_control_scale.unsqueeze(-1)
          )
  
          # from (batch_size * num_samples, 1, *target_shape, num_lags)
          # to (batch_size * num_samples, 1, prod(target_shape) * num_lags)
          input_lags = lags_scaled.reshape(
              (-1, 1, prod(self.target_shape) * len(self.lags_seq))
          )
  
          input_control_lags = control_lags_scaled.reshape(
              (-1, 1, len(self.lags_seq) * prod(self.target_shape))
          )
  
          # (batch_size * num_samples, 1, prod(target_shape) * num_lags + num_time_features + num_static_features)
          decoder_input = torch.cat(
              (
                  input_lags,
                  input_control_lags,
                  repeated_time_feat[:, k : k + 1, :],
                  repeated_static_feat,
              ),
              dim=-1,
          )
  
          # output shape: (batch_size * num_samples, 1, num_cells)
          # state shape: (batch_size * num_samples, num_cells)
          rnn_outputs, repeated_states = self.rnn(
              decoder_input, repeated_states
          )
  
          control_dist_args = self.proj_control_args(rnn_outputs)
          control_distr = self.control_output.distribution(
              control_dist_args, repeated_control_scale
          )
  
          new_control_sample = control_distr.sample()
          control = repeated_future_control[:, k : k + 1]
          control[control != control] = new_control_sample[
              control != control
          ]
          repeated_past_control = torch.cat(
              (repeated_past_control, control), dim=1
          )
  
          distr_args = self.proj_distr_args(
              torch.cat((rnn_outputs, control.unsqueeze(-1)), dim=-1)
          )
  
          # compute likelihood of target given the predicted parameters
          distr = self.distr_output.distribution(
              distr_args, scale=repeated_scale
          )
  
          # (batch_size * num_samples, 1, *target_shape)
          new_samples = distr.sample()
  
          # (batch_size * num_samples, seq_len, *target_shape)
          repeated_past_target = torch.cat(
              (repeated_past_target, new_samples), dim=1
          )
          future_samples.append(new_samples)
  
      # (batch_size * num_samples, prediction_length, *target_shape)
      samples = torch.cat(future_samples, dim=1)
  
      # (batch_size, num_samples, prediction_length, *target_shape)
      return samples.reshape(
          (
              (-1, self.num_parallel_samples)
              + (self.prediction_length,)
              + self.target_shape
          )
      )
  
imports: from typing import List, Optional, Tuple, Union
  import numpy
  import torch
  import torch.nn
  from torch.distributions import Distribution
  from gluonts.core.component import validated
  from gluonts.torch.modules.distribution_output import DistributionOutput
  from pts.model import weighted_average
  from pts.modules import MeanScaler, NOPScaler, FeatureEmbedder
label_desc: Use image node_id 2 for calling the CausalDeepARPredictionNetwork obj's underlying member method code with example usage: obj.sampling_decoder(static_feat, past_target, past_control, time_feat, scale, control_scale, future_control, begin_states) and returns: samples