code: def __rqa_dp(
      sim: np.ndarray, gap_onset: float, gap_extend: float, knight: bool
  ) -> Tuple[np.ndarray, np.ndarray]:  # pragma: no cover
      """RQA dynamic programming implementation"""
      # The output array
      score = np.zeros(sim.shape, dtype=sim.dtype)
  
      # The backtracking array
      backtrack = np.zeros(sim.shape, dtype=np.int8)
  
      # These are place-holder arrays to limit the points being considered
      # at each step of the DP
      #
      # If knight moves are enabled, values are indexed according to
      # [(-1,-1), (-1, -2), (-2, -1)]
      #
      # If knight moves are disabled, then only the first entry is used.
      #
      # Using placeholder vectors here makes the code a bit cleaner down below.
      sim_values = np.zeros(3)
      score_values = np.zeros(3)
      vec = np.zeros(3)
  
      if knight:
          # Initial limit is for the base case: diagonal + one knight
          init_limit = 2
  
          # Otherwise, we have 3 positions
          limit = 3
      else:
          init_limit = 1
          limit = 1
  
      # backtracking rubric:
      #   0 ==> diagonal move
      #   1 ==> knight move up
      #   2 ==> knight move left
      #  -1 ==> reset without inclusion
      #  -2 ==> reset with inclusion (ie positive value at init)
  
      # Initialize the first row and column with the data
      score[0, :] = sim[0, :]
      score[:, 0] = sim[:, 0]
  
      # backtracking initialization: the first row and column are all resets
      # if there's a positive link here, it's an inclusive reset
      for i in range(sim.shape[0]):
          if sim[i, 0]:
              backtrack[i, 0] = -2
          else:
              backtrack[i, 0] = -1
  
      for j in range(sim.shape[1]):
          if sim[0, j]:
              backtrack[0, j] = -2
          else:
              backtrack[0, j] = -1
  
      # Initialize the 1-1 case using only the diagonal
      if sim[1, 1] > 0:
          score[1, 1] = score[0, 0] + sim[1, 1]
          backtrack[1, 1] = 0
      else:
          link = sim[0, 0] > 0
          score[1, 1] = max(
              0, score[0, 0] - (link) * gap_onset - (~link) * gap_extend
          )
          if score[1, 1] > 0:
              backtrack[1, 1] = 0
          else:
              backtrack[1, 1] = -1
  
      # Initialize the second row with diagonal and left-knight moves
      i = 1
      for j in range(2, sim.shape[1]):
          score_values[:-1] = (score[i - 1, j - 1], score[i - 1, j - 2])
          sim_values[:-1] = (sim[i - 1, j - 1], sim[i - 1, j - 2])
          t_values = sim_values > 0
          if sim[i, j] > 0:
              backtrack[i, j] = np.argmax(score_values[:init_limit])
              score[i, j] = (
                  score_values[backtrack[i, j]] + sim[i, j]
              )  # or + 1 for binary
          else:
              vec[:init_limit] = (
                  score_values[:init_limit]
                  - t_values[:init_limit] * gap_onset
                  - (~t_values[:init_limit]) * gap_extend
              )
  
              backtrack[i, j] = np.argmax(vec[:init_limit])
              score[i, j] = max(0, vec[backtrack[i, j]])
              # Is it a reset?
              if score[i, j] == 0:
                  backtrack[i, j] = -1
  
      # Initialize the second column with diagonal and up-knight moves
      j = 1
      for i in range(2, sim.shape[0]):
          score_values[:-1] = (score[i - 1, j - 1], score[i - 2, j - 1])
          sim_values[:-1] = (sim[i - 1, j - 1], sim[i - 2, j - 1])
          t_values = sim_values > 0
          if sim[i, j] > 0:
              backtrack[i, j] = np.argmax(score_values[:init_limit])
              score[i, j] = (
                  score_values[backtrack[i, j]] + sim[i, j]
              )  # or + 1 for binary
  
          else:
              vec[:init_limit] = (
                  score_values[:init_limit]
                  - t_values[:init_limit] * gap_onset
                  - (~t_values[:init_limit]) * gap_extend
              )
  
              backtrack[i, j] = np.argmax(vec[:init_limit])
              score[i, j] = max(0, vec[backtrack[i, j]])
              # Is it a reset?
              if score[i, j] == 0:
                  backtrack[i, j] = -1
  
      # Now fill in the rest of the table
      for i in range(2, sim.shape[0]):
          for j in range(2, sim.shape[1]):
              score_values[:] = (
                  score[i - 1, j - 1],
                  score[i - 1, j - 2],
                  score[i - 2, j - 1],
              )
              sim_values[:] = (
                  sim[i - 1, j - 1],
                  sim[i - 1, j - 2],
                  sim[i - 2, j - 1],
              )
              t_values = sim_values > 0
              if sim[i, j] > 0:
                  # if knight is true, it's max of (-1,-1), (-1, -2), (-2, -1)
                  # otherwise, it's just the diagonal move (-1, -1)
                  # for backtracking purposes, if the max is 0 then it's the start of a new sequence
                  # if the max is non-zero, then we extend the existing sequence
                  backtrack[i, j] = np.argmax(score_values[:limit])
                  score[i, j] = (
                      score_values[backtrack[i, j]] + sim[i, j]
                  )  # or + 1 for binary
  
              else:
                  # if the max of our options is negative, then it's a hard reset
                  # otherwise, it's a skip move
                  vec[:limit] = (
                      score_values[:limit]
                      - t_values[:limit] * gap_onset
                      - (~t_values[:limit]) * gap_extend
                  )
  
                  backtrack[i, j] = np.argmax(vec[:limit])
                  score[i, j] = max(0, vec[backtrack[i, j]])
                  # Is it a reset?
                  if score[i, j] == 0:
                      backtrack[i, j] = -1
  
      return score, backtrack
  
imports: from __future__ import annotations
  import numpy
  from scipy.spatial.distance import cdist
  from numba import jit
  from .util import pad_center, fill_off_diagonal, is_positive_int, tiny, expand_to
  from .util.exceptions import ParameterError
  from .filters import get_window
  from typing import Any, Iterable, List, Optional, Tuple, Union, overload
  from typing_extensions import Literal
  from ._typing import _WindowSpec, _IntLike_co
label_desc: Use image node_id 17 for calling a global function with example usage: __rqa_dp(sim, gap_onset, gap_extend, knight) and returns: score,  backtrack