code: def scrimp_plus_plus(
      ts, m, step_size=0.25, runtime=None, random_state=None
  ):
      """SCRIMP++ is an anytime algorithm that computes the matrix profile for a
      given time series (ts) over a given window size (m). Essentially, it allows
      for an approximate solution to be provided for quicker analysis. In the
      case of this implementation, the runtime is measured based on the wall
      clock. If the number of seconds exceeds the runtime, then the approximate
      solution is returned. If the runtime is None, the exact solution is
      returned.
  
      This algorithm was created at the University of California Riverside. For
      further academic understanding, please review this paper:
  
      Matrix Proﬁle XI: SCRIMP++: Time Series Motif Discovery at Interactive
      Speed. Yan Zhu, Chin-Chia Michael Yeh, Zachary Zimmerman, Kaveh Kamgar
      Eamonn Keogh, ICDM 2018.
  
      https://www.cs.ucr.edu/~eamonn/SCRIMP_ICDM_camera_ready_updated.pdf
  
          Parameters
          ----------
          ts : np.ndarray
              The time series to compute the matrix profile for.
          m : int
              The window size.
          step_size : float, default 0.25
              The sampling interval for the window. The paper suggest 0.25 is the
              most practical. It should be a float value between 0 and 1.
          runtime : int, default None
              The maximum number of seconds based on wall clock time for this
              algorithm to run. It computes the exact solution when it is set to
              None.
          random_state : int, default None
              Set the random seed generator for reproducible results.
  
          Returns
          -------
          (np.array, np.array)
              The matrix profile and the matrix profile index respectively.
      """
      # start the timer here
      start_time = time.time()
  
      # validate step_size
      if (
          not isinstance(step_size, float)
          or step_size > 1
          or step_size < 0
      ):
          raise ValueError(
              "step_size should be a float between 0 and 1."
          )
  
      # validate runtime
      if runtime is not None and (
          not isinstance(runtime, int) or runtime < 1
      ):
          raise ValueError(
              "runtime should be a valid positive integer."
          )
  
      # validate random_state
      if random_state is not None:
          try:
              np.random.seed(random_state)
          except:
              raise ValueError("Invalid random_state value given.")
  
      ts_len = len(ts)
  
      # set the trivial match range
      exclusion_zone = calc_exclusion_zone(m)
  
      # value checking
      if m > ts_len / 2:
          raise ValueError(
              "Time series is too short relative to desired \
              subsequence length"
          )
  
      if m < 4:
          raise ValueError("Window size must be at least 4")
  
      # initialization
      step_size = calc_step_size(m, step_size)
      profile_len = calc_profile_len(ts_len, m)
  
      matrix_profile = np.zeros(profile_len)
      mp_index = np.zeros(profile_len, dtype="int32")
  
      X, n, sumx2, sumx, meanx, sigmax2, sigmax = fast_find_nn_pre(
          ts, m
      )
  
      ###########################
      # PreSCRIMP
      #
      # compute distance profile
      dotproduct = np.zeros(profile_len)
      refine_distance = np.full(profile_len, np.inf)
      orig_index = np.arange(profile_len)
  
      compute_order = list(range(0, profile_len, step_size))
      np.random.shuffle(compute_order)
  
      for iteration, idx in enumerate(compute_order):
          # compute distance profile
          subsequence = next_subsequence(ts, idx, m)
  
          distance_profile = calc_distance_profile(
              X, subsequence, n, m, meanx, sigmax
          )
  
          # apply exclusion zone
          distance_profile = apply_exclusion_zone(
              idx, exclusion_zone, profile_len, distance_profile
          )
  
          # find and store nearest neighbor
          matrix_profile, mp_index, idx_nn = find_and_store_nn(
              iteration, idx, matrix_profile, mp_index, distance_profile
          )
  
          idx_diff = calc_idx_diff(idx, idx_nn)
          dotproduct = calc_dotproduct_idx(
              dotproduct, m, matrix_profile, idx, sigmax, idx_nn, meanx
          )
  
          endidx = calc_end_idx(profile_len, idx, step_size, idx_diff)
  
          dotproduct = calc_dotproduct_end_idx(
              ts, dotproduct, idx, m, endidx, idx_nn, idx_diff
          )
  
          refine_distance = calc_refine_distance_end_idx(
              refine_distance,
              dotproduct,
              idx,
              endidx,
              meanx,
              sigmax,
              idx_nn,
              idx_diff,
              m,
          )
  
          beginidx = calc_begin_idx(idx, step_size, idx_diff)
  
          dotproduct = calc_dotproduct_begin_idx(
              ts, dotproduct, beginidx, idx, idx_diff, m, idx_nn
          )
  
          refine_distance = calc_refine_distance_begin_idx(
              refine_distance,
              dotproduct,
              beginidx,
              idx,
              idx_diff,
              idx_nn,
              sigmax,
              meanx,
              m,
          )
  
          matrix_profile, mp_index = apply_update_positions(
              matrix_profile,
              mp_index,
              refine_distance,
              beginidx,
              endidx,
              orig_index,
              idx_diff,
          )
  
          # check if time is up
          if time_is_exceeded(start_time, runtime):
              break
  
      if not time_is_exceeded(start_time, runtime):
          ###########################
          # SCRIMP
          #
          compute_order = orig_index[orig_index > exclusion_zone]
          np.random.shuffle(compute_order)
  
          curlastz = np.zeros(profile_len)
          curdistance = np.zeros(profile_len)
          dist1 = np.full(profile_len, np.inf)
          dist2 = np.full(profile_len, np.inf)
  
          for idx in compute_order:
              curlastz = calc_curlastz(
                  ts, m, n, idx, profile_len, curlastz
              )
              curdistance = calc_curdistance(
                  curlastz,
                  meanx,
                  sigmax,
                  idx,
                  profile_len,
                  m,
                  curdistance,
              )
  
              dist1[0 : idx - 1] = np.inf
              dist1[idx:profile_len] = curdistance[idx:profile_len]
  
              dist2[0 : profile_len - idx] = curdistance[
                  idx:profile_len
              ]
              dist2[profile_len - idx + 2 : profile_len] = np.inf
  
              loc1 = dist1 < matrix_profile
              if loc1.any():
                  matrix_profile[loc1] = dist1[loc1]
                  mp_index[loc1] = orig_index[loc1] - idx + 1
  
              loc2 = dist2 < matrix_profile
              if loc2.any():
                  matrix_profile[loc2] = dist2[loc2]
                  mp_index[loc2] = orig_index[loc2] + idx - 1
  
              # check if time is up
              if time_is_exceeded(start_time, runtime):
                  break
  
      return (matrix_profile, mp_index)
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  import math
  import time
  import warnings
  import numpy
label_desc: Use image node_id 23 for calling a global function with example usage: scrimp_plus_plus(ts, m, step_size, runtime, random_state) and returns: matrix_profile,  mp_index