docs: def lapmod(n, cc, ii, kk, fast=True, return_cost=True,
             fp_version=FP_DYNAMIC):
      """Solve sparse linear assignment problem using Jonker-Volgenant algorithm.
  
      n: number of rows of the assignment cost matrix
      cc: 1D array of all finite elements of the assignement cost matrix
      ii: 1D array of indices of the row starts in cc. The following must hold:
              ii[0] = 0 and ii[n+1] = len(cc).
      kk: 1D array of the column indices so that:
              cost[i, kk[ii[i] + k]] == cc[ii[i] + k].
          Indices within one row must be sorted.
      extend_cost: whether or not extend a non-square matrix [default: False]
      cost_limit: an upper limit for a cost of a single assignment
                  [default: np.inf]
      return_cost: whether or not to return the assignment cost
  
      Returns (opt, x, y) where:
        opt: cost of the assignment
        x: vector of columns assigned to rows
        y: vector of rows assigned to columns
      or (x, y) if return_cost is not True.
  
      When extend_cost and/or cost_limit is set, all unmatched entries will be
      marked by -1 in x/y.
      """
      # log = logging.getLogger('lapmod')
  
      check_cost(n, cc, ii, kk)
  
      if fast is True:
          # log.debug('[----CR & RT & ARR & augmentation ----]')
          x, y = _lapmod(n, cc, ii, kk, fp_version=fp_version)
      else:
          cc = np.ascontiguousarray(cc, dtype=np.float64)
          ii = np.ascontiguousarray(ii, dtype=np.int32)
          kk = np.ascontiguousarray(kk, dtype=np.int32)
          x = np.empty((n,), dtype=np.int32)
          y = np.empty((n,), dtype=np.int32)
          v = np.empty((n,), dtype=np.float64)
          free_rows = np.empty((n,), dtype=np.int32)
          # log.debug('[----Column reduction & reduction transfer----]')
          n_free_rows = _pycrrt(n, cc, ii, kk, free_rows, x, y, v)
          # log.debug(
          #     'free, x, y, v: %s %s %s %s', free_rows[:n_free_rows], x, y, v)
          if n_free_rows == 0:
              # log.info('Reduction solved it.')
              if return_cost is True:
                  return get_cost(n, cc, ii, kk, x), x, y
              else:
                  return x, y
          for it in range(2):
              # log.debug('[---Augmenting row reduction (iteration: %d)---]', it)
              n_free_rows = _pyarr(
                      n, cc, ii, kk, n_free_rows, free_rows, x, y, v)
              # log.debug(
              #   'free, x, y, v: %s %s %s %s', free_rows[:n_free_rows], x, y, v)
              if n_free_rows == 0:
                  # log.info('Augmenting row reduction solved it.')
                  if return_cost is True:
                      return get_cost(n, cc, ii, kk, x), x, y
                  else:
                      return x, y
          # log.info('[----Augmentation----]')
          _pya(n, cc, ii, kk, n_free_rows, free_rows, x, y, v)
          # log.debug('x, y, v: %s %s %s', x, y, v)
      if return_cost is True:
          return get_cost(n, cc, ii, kk, x), x, y
      else:
          return x, y