class_docstr: Distribution class for the Incremental (Spline) Quantile Function in the
  paper ``Learning Quantile Functions without Quantile Crossing for
  Distribution-free Time Series Forecasting``
  by Park, Robinson, Aubet, Kan, Gasthaus, Wang
  Parameters
  ----------
  spline_knots, spline_heights
      Tensor parametrizing the x-positions (y-positions) of the spline knots
      Shape: (*batch_shape, (num_qk-1), num_pieces)
  qk_x, qk_y
      Tensor containing the increasing x-positions (y-positions) of the
      quantile knots, Shape: (*batch_shape, num_qk)
  beta_l, beta_r
      Tensor containing the non-negative learnable parameter of the
      left (right) tail, Shape: (*batch_shape,)
class_docstr_tok: ["Distribution","class","for","the","Incremental","(","Spline",")","Quantile","Function","in","the","paper","``","Learning","Quantile","Functions","without","Quantile","Crossing","for","Distribution-free","Time","Series","Forecasting","``","by","Park",",","Robinson",",","Aubet",",","Kan",",","Gasthaus",",","Wang","Parameters","--","--","--","--","--","spline_knots",",","spline_heights","Tensor","parametrizing","the","x-positions","(","y-positions",")","of","the","spline","knots","Shape",":","(","*","batch_shape",",","(","num_qk-1",")",",","num_pieces",")","qk_x",",","qk_y","Tensor","containing","the","increasing","x-positions","(","y-positions",")","of","the","quantile","knots",",","Shape",":","(","*","batch_shape",",","num_qk",")","beta_l",",","beta_r","Tensor","containing","the","non-negative","learnable","parameter","of","the","left","(","right",")","tail",",","Shape",":","(","*","batch_shape",",",")"]
docstr: For observations z and splines defined in [qk_x[k], qk_x[k+1]]
  Computes the quantile level alpha_tilde such that
  alpha_tilde
  = q^{-1}(z) if z is in-between qk_x[k] and qk_x[k+1]
  = qk_x[k] if z<qk_x[k]
  = qk_x[k+1] if z>qk_x[k+1]
  Parameters
  ----------
  z
      Observation, shape = (*batch_shape,)
  Returns
  -------
  alpha_tilde
      Corresponding quantile level, shape = (*batch_shape, num_qk-1)
docstr_tok: ["For","observations","z","and","splines","defined","in","[","qk_x","[","k","]",",","qk_x","[","k+1","]","]","Computes","the","quantile","level","alpha_tilde","such","that","alpha_tilde","=","q^","{","-1","}","(","z",")","if","z","is","in-between","qk_x","[","k","]","and","qk_x","[","k+1","]","=","qk_x","[","k","]","if","z","<","qk_x","[","k","]","=","qk_x","[","k+1","]","if","z",">","qk_x","[","k+1","]","Parameters","--","--","--","--","--","z","Observation",",","shape","=","(","*","batch_shape",",",")","Returns","--","--","--","-","alpha_tilde","Corresponding","quantile","level",",","shape","=","(","*","batch_shape",",","num_qk-1",")"]
code: def cdf_spline(self, z: torch.Tensor) -> torch.Tensor:
      r"""
      For observations z and splines defined in [qk_x[k], qk_x[k+1]]
      Computes the quantile level alpha_tilde such that
      alpha_tilde
      = q^{-1}(z) if z is in-between qk_x[k] and qk_x[k+1]
      = qk_x[k] if z<qk_x[k]
      = qk_x[k+1] if z>qk_x[k+1]
      Parameters
      ----------
      z
          Observation, shape = (*batch_shape,)
      Returns
      -------
      alpha_tilde
          Corresponding quantile level, shape = (*batch_shape, num_qk-1)
      """
  
      qk_y, qk_y_plus = self.qk_y, self.qk_y_plus
      qk_x, qk_x_plus = self.qk_x, self.qk_x_plus
      sk_x, delta_sk_x, delta_sk_y = (
          self.sk_x,
          self.delta_sk_x,
          self.delta_sk_y,
      )
  
      z_expand = z.unsqueeze(dim=-1)
  
      if self.num_pieces > 1:
          qk_y_expand = qk_y.unsqueeze(dim=-1)
          z_expand_twice = z_expand.unsqueeze(dim=-1)
  
          knots_eval = self.quantile_spline(sk_x, dim=-2)
  
          # Compute \sum_{s=0}^{s_0-1} \Delta sk_y[s],
          # where \Delta sk_y[s] = (sk_y[s+1]-sk_y[s])
          mask_sum_s0 = torch.lt(knots_eval, z_expand_twice)
          mask_sum_s0_minus = torch.cat(
              [
                  mask_sum_s0[..., 1:],
                  torch.zeros_like(qk_y_expand, dtype=torch.bool),
              ],
              dim=-1,
          )
          sum_delta_sk_y = torch.sum(
              mask_sum_s0_minus * delta_sk_y, dim=-1
          )
  
          mask_s0_only = torch.logical_and(
              mask_sum_s0, torch.logical_not(mask_sum_s0_minus)
          )
          # Compute (sk_x[s_0+1]-sk_x[s_0])/(sk_y[s_0+1]-sk_y[s_0])
          frac_s0 = torch.sum(
              (mask_s0_only * delta_sk_x) / delta_sk_y, dim=-1
          )
  
          # Compute sk_x_{s_0}
          sk_x_s0 = torch.sum(mask_s0_only * sk_x, dim=-1)
  
          # Compute alpha_tilde
          alpha_tilde = (
              sk_x_s0 + (z_expand - qk_y - sum_delta_sk_y) * frac_s0
          )
  
      else:
          # num_pieces=1, ISQF reduces to IQF
          alpha_tilde = qk_x + (z_expand - qk_y) / (
              qk_y_plus - qk_y
          ) * (qk_x_plus - qk_x)
  
      alpha_tilde = torch.minimum(
          torch.maximum(alpha_tilde, qk_x), qk_x_plus
      )
  
      return alpha_tilde
  
imports: from typing import Dict, List, Optional, Tuple
  import torch
  import torch.nn.functional
  from torch.distributions import AffineTransform, TransformedDistribution
  from gluonts.core.component import validated
  from .distribution_output import DistributionOutput
label_desc: Use image node_id 9 for calling the ISQF obj's underlying member method code with example usage: obj.cdf_spline(z) and returns: alpha_tilde