code: def _compute_PI(
      T_A,
      T_B,
      m,
      μ_Q,
      σ_Q,
      M_T,
      Σ_T,
      Q_subseq_isconstant,
      T_subseq_isconstant,
      indices,
      start,
      stop,
      thread_idx,
      s,
      P_squared,
      I,
      excl_zone=None,
      k=1,
  ):
      """
      Compute (Numba JIT-compiled) and update the squared (top-k) matrix profile
      distance and matrix profile indces according to the preSCRIMP algorithm.
  
      Parameters
      ----------
      T_A : numpy.ndarray
          The time series or sequence for which to compute the matrix profile
  
      T_B : numpy.ndarray
          The time series or sequence that will be used to annotate T_A. For every
          subsequence in T_A, its nearest neighbor in T_B will be recorded.
  
      m : int
          Window size
  
      μ_Q : numpy.ndarray
          Sliding window mean for `T_A`
  
      σ_Q : numpy.ndarray
          Sliding window standard deviation for `T_A`
  
      M_T : numpy.ndarray
          Sliding window mean for `T_B`
  
      Σ_T : numpy.ndarray
          Sliding window standard deviation for `T_B`
  
      Q_subseq_isconstant : numpy.ndarray
          A boolean array that indicates whether a subsequence in `T_A` is constant (True)
  
      T_subseq_isconstant : numpy.ndarray
          A boolean array that indicates whether a subsequence in `T_B` is constant (True)
  
      indices : numpy.ndarray
          The subsequence indices to compute `prescrump` for
  
      start : int
          The (inclusive) start index for `indices`
  
      stop : int
          The (exclusive) stop index for `indices`
  
      thread_idx : int
          The thread index
  
      s : int
          The sampling interval that defaults to
          `int(np.ceil(m / config.STUMPY_EXCL_ZONE_DENOM))`
  
      P_squared : numpy.ndarray
          The squared (top-k) matrix profile
  
      I : numpy.ndarray
          The (top-k) matrix profile indices
  
      excl_zone : int
          The half width for the exclusion zone relative to the `i`.
  
      k : int, default 1
          The number of top `k` smallest distances used to construct the matrix profile.
          Note that this will increase the total computational time and memory usage
          when k > 1.
  
      Returns
      -------
      None
  
      Notes
      -----
      `DOI: 10.1109/ICDM.2018.00099 \
      <https://www.cs.ucr.edu/~eamonn/SCRIMP_ICDM_camera_ready_updated.pdf>`__
  
      See Algorithm 2
      """
      l = T_A.shape[0] - m + 1  # length of matrix profile
      w = T_B.shape[0] - m + 1  # length of distance profile
      squared_distance_profile = np.empty(w)
      QT = np.empty(w, dtype=np.float64)
      for i in indices[start:stop]:
          Q = T_A[i : i + m]
          QT[:] = core._sliding_dot_product(Q, T_B)
          squared_distance_profile[
              :
          ] = core._calculate_squared_distance_profile(
              m,
              QT,
              μ_Q[i],
              σ_Q[i],
              M_T,
              Σ_T,
              Q_subseq_isconstant[i],
              T_subseq_isconstant,
          )
  
          if excl_zone is not None:
              core._apply_exclusion_zone(
                  squared_distance_profile, i, excl_zone, np.inf
              )
  
          nn_i = np.argmin(squared_distance_profile)
          if squared_distance_profile[nn_i] == np.inf:
              continue
  
          if (
              squared_distance_profile[nn_i]
              < P_squared[thread_idx, i, -1]
              and nn_i not in I[thread_idx, i]
          ):
              idx = np.searchsorted(
                  P_squared[thread_idx, i],
                  squared_distance_profile[nn_i],
                  side="right",
              )
              core._shift_insert_at_index(
                  P_squared[thread_idx, i],
                  idx,
                  squared_distance_profile[nn_i],
              )
              core._shift_insert_at_index(I[thread_idx, i], idx, nn_i)
  
          j = nn_i
          QT_j = QT[j]
          QT_j_prime = QT_j
          # Update top-k for both subsequences `S[i+g] = T[i+g:i+g+m]`` and
          # `S[j+g] = T[j+g:j+g+m]` (i.e., the right neighbors of `T[i : i+m]` and
          # `T[j:j+m]`) by using the distance between `S[i+g]` and `S[j+g]`
          for g in range(1, min(s, l - i, w - j)):
              QT_j = (
                  QT_j
                  - T_B[j + g - 1] * T_A[i + g - 1]
                  + T_B[j + g + m - 1] * T_A[i + g + m - 1]
              )
              D_squared = core._calculate_squared_distance(
                  m,
                  QT_j,
                  M_T[j + g],
                  Σ_T[j + g],
                  μ_Q[i + g],
                  σ_Q[i + g],
                  T_subseq_isconstant[j + g],
                  Q_subseq_isconstant[i + g],
              )
              if (
                  D_squared < P_squared[thread_idx, i + g, -1]
                  and (j + g) not in I[thread_idx, i + g]
              ):
                  idx = np.searchsorted(
                      P_squared[thread_idx, i + g],
                      D_squared,
                      side="right",
                  )
                  core._shift_insert_at_index(
                      P_squared[thread_idx, i + g], idx, D_squared
                  )
                  core._shift_insert_at_index(
                      I[thread_idx, i + g], idx, j + g
                  )
  
              if (
                  excl_zone is not None
                  and D_squared < P_squared[thread_idx, j + g, -1]
                  and (i + g) not in I[thread_idx, j + g]
              ):
                  idx = np.searchsorted(
                      P_squared[thread_idx, j + g],
                      D_squared,
                      side="right",
                  )
                  core._shift_insert_at_index(
                      P_squared[thread_idx, j + g], idx, D_squared
                  )
                  core._shift_insert_at_index(
                      I[thread_idx, j + g], idx, i + g
                  )
  
          QT_j = QT_j_prime
          # Update top-k for both subsequences `S[i-g] = T[i-g:i-g+m]` and
          # `S[j-g] = T[j-g:j-g+m]` (i.e., the left neighbors of `T[i : i+m]` and
          # `T[j:j+m]`) by using the distance between `S[i-g]` and `S[j-g]`
          for g in range(1, min(s, i + 1, j + 1)):
              QT_j = (
                  QT_j
                  - T_B[j - g + m] * T_A[i - g + m]
                  + T_B[j - g] * T_A[i - g]
              )
              D_squared = core._calculate_squared_distance(
                  m,
                  QT_j,
                  M_T[j - g],
                  Σ_T[j - g],
                  μ_Q[i - g],
                  σ_Q[i - g],
                  T_subseq_isconstant[j - g],
                  Q_subseq_isconstant[i - g],
              )
              if (
                  D_squared < P_squared[thread_idx, i - g, -1]
                  and (j - g) not in I[thread_idx, i - g]
              ):
                  idx = np.searchsorted(
                      P_squared[thread_idx, i - g],
                      D_squared,
                      side="right",
                  )
                  core._shift_insert_at_index(
                      P_squared[thread_idx, i - g], idx, D_squared
                  )
                  core._shift_insert_at_index(
                      I[thread_idx, i - g], idx, j - g
                  )
  
              if (
                  excl_zone is not None
                  and D_squared < P_squared[thread_idx, j - g, -1]
                  and (i - g) not in I[thread_idx, j - g]
              ):
                  idx = np.searchsorted(
                      P_squared[thread_idx, j - g],
                      D_squared,
                      side="right",
                  )
                  core._shift_insert_at_index(
                      P_squared[thread_idx, j - g], idx, D_squared
                  )
                  core._shift_insert_at_index(
                      I[thread_idx, j - g], idx, i - g
                  )
  
          # In the case of a self-join, the calculated distance profile can also be
          # used to refine the top-k for all non-trivial subsequences
          if excl_zone is not None:
              # Note that the squared distance, `squared_distance_profile[j]`,
              # between subsequences `S_i = T[i : i + m]` and `S_j = T[j : j + m]`
              # can be used to update the top-k for BOTH subsequence `i` and
              # subsequence `j`. We update the latter here.
  
              indices = np.flatnonzero(
                  squared_distance_profile
                  < P_squared[thread_idx, :, -1]
              )
              for j in indices:
                  if i not in I[thread_idx, j]:
                      idx = np.searchsorted(
                          P_squared[thread_idx, j],
                          squared_distance_profile[j],
                          side="right",
                      )
                      core._shift_insert_at_index(
                          P_squared[thread_idx, j],
                          idx,
                          squared_distance_profile[j],
                      )
                      core._shift_insert_at_index(
                          I[thread_idx, j], idx, i
                      )
  
file_path: stumpy/stumpy/scrump.py
imports: import numba
  import numpy
  from numba import njit, prange
  from .None import config, core
  from .scraamp import prescraamp, scraamp
  from .stump import _stump
label_desc: Use image node_id 2 for calling a global function with example usage: _compute_PI(T_A, T_B, m, μ_Q, σ_Q, M_T, Σ_T, Q_subseq_isconstant, T_subseq_isconstant, indices, start, stop, thread_idx, s, P_squared, I, excl_zone, k) without return types