Generated by Cython 3.0.11

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

Raw output: cut_finder.c

+001: # distutils: language = c
  __pyx_t_7 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_7) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
 002: # cython: boundscheck = False
 003: # cython: wraparound = False
 004: # cython: profile = False
 005: 
+006: import numpy as np
  __pyx_t_7 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_7) < 0) __PYX_ERR(0, 6, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
 007: cimport numpy as np
 008: cimport cython
 009: from cython.parallel import prange
 010: from libc.stdlib cimport malloc, free
 011: 
+012: ctypedef np.int32_t NP_INT_t
typedef __pyx_t_5numpy_int32_t __pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t;
 013: ctypedef np.float64_t NP_FLOAT_t
 014: 
 015: cdef extern from "<math.h>" nogil:
 016:     const float INFINITY
 017: 
 018: cdef extern from "<limits.h>":
 019:     const int INT_MIN
 020:     const int INT_MAX
 021: 
+022: @cython.boundscheck(False)
/* Python wrapper */
static PyObject *__pyx_pw_5d_imm_9splitters_10cut_finder_1get_all_mistakes_histogram(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
PyDoc_STRVAR(__pyx_doc_5d_imm_9splitters_10cut_finder_get_all_mistakes_histogram, "\n    Main function to calculate mistakes for all features and thresholds.\n    Returns a list of Python dictionaries with 'feature', 'threshold', and 'mistakes'.\n    ");
static PyMethodDef __pyx_mdef_5d_imm_9splitters_10cut_finder_1get_all_mistakes_histogram = {"get_all_mistakes_histogram", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_5d_imm_9splitters_10cut_finder_1get_all_mistakes_histogram, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_5d_imm_9splitters_10cut_finder_get_all_mistakes_histogram};
static PyObject *__pyx_pw_5d_imm_9splitters_10cut_finder_1get_all_mistakes_histogram(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  __Pyx_memviewslice __pyx_v_X = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_y = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_centers = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_valid_centers = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_valid_cols = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyObject *__pyx_v_histogram = 0;
  int __pyx_v_njobs;
  #if !CYTHON_METH_FASTCALL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_all_mistakes_histogram (wrapper)", 0);
  #if !CYTHON_METH_FASTCALL
  #if CYTHON_ASSUME_SAFE_MACROS
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_X,&__pyx_n_s_y,&__pyx_n_s_centers,&__pyx_n_s_valid_centers,&__pyx_n_s_valid_cols,&__pyx_n_s_histogram,&__pyx_n_s_njobs,0};
  PyObject* values[7] = {0,0,0,0,0,0,0};
    if (__pyx_kwds) {
      Py_ssize_t kw_args;
      switch (__pyx_nargs) {
        case  7: values[6] = __Pyx_Arg_FASTCALL(__pyx_args, 6);
        CYTHON_FALLTHROUGH;
        case  6: values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5);
        CYTHON_FALLTHROUGH;
        case  5: values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4);
        CYTHON_FALLTHROUGH;
        case  4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);
        CYTHON_FALLTHROUGH;
        case  3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);
        CYTHON_FALLTHROUGH;
        case  2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
        CYTHON_FALLTHROUGH;
        case  1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds);
      switch (__pyx_nargs) {
        case  0:
        if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_X)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[0]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else goto __pyx_L5_argtuple_error;
        CYTHON_FALLTHROUGH;
        case  1:
        if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_y)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[1]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else {
          __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, 1); __PYX_ERR(0, 22, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  2:
        if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_centers)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[2]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else {
          __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, 2); __PYX_ERR(0, 22, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  3:
        if (likely((values[3] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_valid_centers)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[3]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else {
          __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, 3); __PYX_ERR(0, 22, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  4:
        if (likely((values[4] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_valid_cols)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[4]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else {
          __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, 4); __PYX_ERR(0, 22, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  5:
        if (likely((values[5] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_histogram)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[5]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else {
          __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, 5); __PYX_ERR(0, 22, __pyx_L3_error)
        }
        CYTHON_FALLTHROUGH;
        case  6:
        if (likely((values[6] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_njobs)) != 0)) {
          (void)__Pyx_Arg_NewRef_FASTCALL(values[6]);
          kw_args--;
        }
        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 22, __pyx_L3_error)
        else {
          __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, 6); __PYX_ERR(0, 22, __pyx_L3_error)
        }
      }
      if (unlikely(kw_args > 0)) {
        const Py_ssize_t kwd_pos_args = __pyx_nargs;
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, "get_all_mistakes_histogram") < 0)) __PYX_ERR(0, 22, __pyx_L3_error)
      }
    } else if (unlikely(__pyx_nargs != 7)) {
      goto __pyx_L5_argtuple_error;
    } else {
      values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
      values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
      values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);
      values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);
      values[4] = __Pyx_Arg_FASTCALL(__pyx_args, 4);
      values[5] = __Pyx_Arg_FASTCALL(__pyx_args, 5);
      values[6] = __Pyx_Arg_FASTCALL(__pyx_args, 6);
    }
    __pyx_v_X = __Pyx_PyObject_to_MemoryviewSlice_dsds_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t(values[0], PyBUF_WRITABLE); if (unlikely(!__pyx_v_X.memview)) __PYX_ERR(0, 25, __pyx_L3_error)
    __pyx_v_y = __Pyx_PyObject_to_MemoryviewSlice_ds_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t(values[1], PyBUF_WRITABLE); if (unlikely(!__pyx_v_y.memview)) __PYX_ERR(0, 25, __pyx_L3_error)
    __pyx_v_centers = __Pyx_PyObject_to_MemoryviewSlice_dsds_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t(values[2], PyBUF_WRITABLE); if (unlikely(!__pyx_v_centers.memview)) __PYX_ERR(0, 25, __pyx_L3_error)
    __pyx_v_valid_centers = __Pyx_PyObject_to_MemoryviewSlice_ds_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t(values[3], PyBUF_WRITABLE); if (unlikely(!__pyx_v_valid_centers.memview)) __PYX_ERR(0, 26, __pyx_L3_error)
    __pyx_v_valid_cols = __Pyx_PyObject_to_MemoryviewSlice_ds_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t(values[4], PyBUF_WRITABLE); if (unlikely(!__pyx_v_valid_cols.memview)) __PYX_ERR(0, 26, __pyx_L3_error)
    __pyx_v_histogram = ((PyObject*)values[5]);
    __pyx_v_njobs = __Pyx_PyInt_As_int(values[6]); if (unlikely((__pyx_v_njobs == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 26, __pyx_L3_error)
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("get_all_mistakes_histogram", 1, 7, 7, __pyx_nargs); __PYX_ERR(0, 22, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  {
    Py_ssize_t __pyx_temp;
    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
    }
  }
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_X, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_y, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_centers, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_valid_centers, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_valid_cols, 1);
  __Pyx_AddTraceback("d_imm.splitters.cut_finder.get_all_mistakes_histogram", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_histogram), (&PyList_Type), 1, "histogram", 1))) __PYX_ERR(0, 26, __pyx_L1_error)
  __pyx_r = __pyx_pf_5d_imm_9splitters_10cut_finder_get_all_mistakes_histogram(__pyx_self, __pyx_v_X, __pyx_v_y, __pyx_v_centers, __pyx_v_valid_centers, __pyx_v_valid_cols, __pyx_v_histogram, __pyx_v_njobs);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  goto __pyx_L0;
  __pyx_L1_error:;
  __pyx_r = NULL;
  __pyx_L0:;
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_X, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_y, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_centers, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_valid_centers, 1);
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_valid_cols, 1);
  {
    Py_ssize_t __pyx_temp;
    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
      __Pyx_Arg_XDECREF_FASTCALL(values[__pyx_temp]);
    }
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_5d_imm_9splitters_10cut_finder_get_all_mistakes_histogram(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_X, __Pyx_memviewslice __pyx_v_y, __Pyx_memviewslice __pyx_v_centers, __Pyx_memviewslice __pyx_v_valid_centers, __Pyx_memviewslice __pyx_v_valid_cols, PyObject *__pyx_v_histogram, int __pyx_v_njobs) {
  int __pyx_v_n;
  int __pyx_v_k;
  int __pyx_v_d;
  PyObject *__pyx_v_feature_results = 0;
  int __pyx_v_col;
  PyObject *__pyx_r = NULL;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_AddTraceback("d_imm.splitters.cut_finder.get_all_mistakes_histogram", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_feature_results);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__22 = PyTuple_Pack(12, __pyx_n_s_X, __pyx_n_s_y, __pyx_n_s_centers, __pyx_n_s_valid_centers, __pyx_n_s_valid_cols, __pyx_n_s_histogram, __pyx_n_s_njobs, __pyx_n_s_n, __pyx_n_s_k, __pyx_n_s_d, __pyx_n_s_feature_results, __pyx_n_s_col); if (unlikely(!__pyx_tuple__22)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__22);
  __Pyx_GIVEREF(__pyx_tuple__22);
/* … */
  __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_5d_imm_9splitters_10cut_finder_1get_all_mistakes_histogram, 0, __pyx_n_s_get_all_mistakes_histogram, NULL, __pyx_n_s_d_imm_splitters_cut_finder, __pyx_d, ((PyObject *)__pyx_codeobj__23)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_get_all_mistakes_histogram, __pyx_t_7) < 0) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
 023: @cython.wraparound(False)
 024: def get_all_mistakes_histogram(
 025:     NP_FLOAT_t[:,:] X, NP_INT_t[:] y, NP_FLOAT_t[:,:] centers,
 026:     NP_INT_t[:] valid_centers, NP_INT_t[:] valid_cols, list histogram, int njobs
 027: ):
 028:     """
 029:     Main function to calculate mistakes for all features and thresholds.
 030:     Returns a list of Python dictionaries with 'feature', 'threshold', and 'mistakes'.
 031:     """
+032:     cdef int n = X.shape[0]
  __pyx_v_n = (__pyx_v_X.shape[0]);
+033:     cdef int k = centers.shape[0]
  __pyx_v_k = (__pyx_v_centers.shape[0]);
+034:     cdef int d = valid_cols.shape[0]
  __pyx_v_d = (__pyx_v_valid_cols.shape[0]);
+035:     cdef list feature_results = []
  __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 35, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_v_feature_results = ((PyObject*)__pyx_t_1);
  __pyx_t_1 = 0;
 036:     cdef int col
 037: 
+038:     if njobs is None or njobs <= 1:
  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_njobs); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 38, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = (__pyx_t_1 == Py_None);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (!__pyx_t_3) {
  } else {
    __pyx_t_2 = __pyx_t_3;
    goto __pyx_L4_bool_binop_done;
  }
  __pyx_t_3 = (__pyx_v_njobs <= 1);
  __pyx_t_2 = __pyx_t_3;
  __pyx_L4_bool_binop_done:;
  if (__pyx_t_2) {
/* … */
    goto __pyx_L3;
  }
 039:         # Iterate over valid columns
+040:         for col in range(d):
    __pyx_t_4 = __pyx_v_d;
    __pyx_t_5 = __pyx_t_4;
    for (__pyx_t_6 = 0; __pyx_t_6 < __pyx_t_5; __pyx_t_6+=1) {
      __pyx_v_col = __pyx_t_6;
+041:             if valid_cols[col] == 1:
      __pyx_t_7 = __pyx_v_col;
      __pyx_t_2 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t *) ( /* dim=0 */ (__pyx_v_valid_cols.data + __pyx_t_7 * __pyx_v_valid_cols.strides[0]) ))) == 1);
      if (__pyx_t_2) {
/* … */
      }
    }
+042:                 update_col_all_mistakes_histogram_unsorted(
        __pyx_f_5d_imm_9splitters_10cut_finder_update_col_all_mistakes_histogram_unsorted(__pyx_v_X, __pyx_v_y, __pyx_v_centers, __pyx_v_valid_centers, __pyx_v_col, __pyx_v_n, __pyx_v_k, __pyx_v_feature_results, ((PyObject*)__pyx_t_1)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 42, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 043:                     X, y, centers, valid_centers,
+044:                     col, n, k, feature_results, histogram[col]
        if (unlikely(__pyx_v_histogram == Py_None)) {
          PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
          __PYX_ERR(0, 44, __pyx_L1_error)
        }
        if (!(likely(PyList_CheckExact(PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col)))||((PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col)) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col)))) __PYX_ERR(0, 44, __pyx_L1_error)
        __pyx_t_1 = PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col);
        __Pyx_INCREF(__pyx_t_1);
 045:                 )
 046:     else:
 047:         # Parallelize the process
+048:         for col in prange(d, num_threads=njobs, schedule='dynamic', nogil=True):  # Removed nogil=True
  /*else*/ {
    {
        #ifdef WITH_THREAD
        PyThreadState *_save;
        _save = NULL;
        Py_UNBLOCK_THREADS
        __Pyx_FastGIL_Remember();
        #endif
        /*try:*/ {
          __pyx_t_4 = __pyx_v_d;
          {
              #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))))
                  #undef likely
                  #undef unlikely
                  #define likely(x)   (x)
                  #define unlikely(x) (x)
              #endif
              __pyx_t_6 = (__pyx_t_4 - 0 + 1 - 1/abs(1)) / 1;
              if (__pyx_t_6 > 0)
              {
                  #ifdef _OPENMP
                  #pragma omp parallel
                  #endif /* _OPENMP */
                  {
                      #ifdef _OPENMP
                      #pragma omp for firstprivate(__pyx_v_col) lastprivate(__pyx_v_col) schedule(dynamic)          __pyx_t_4 = __pyx_v_d;
          {
              #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))))
                  #undef likely
                  #undef unlikely
                  #define likely(x)   (x)
                  #define unlikely(x) (x)
              #endif
              __pyx_t_6 = (__pyx_t_4 - 0 + 1 - 1/abs(1)) / 1;
              if (__pyx_t_6 > 0)
              {
                  #ifdef _OPENMP
                  #pragma omp parallel
                  #endif /* _OPENMP */
                  {
                      #ifdef _OPENMP
                      #pragma omp for firstprivate(__pyx_v_col) lastprivate(__pyx_v_col) schedule(dynamic) num_threads(__pyx_v_njobs)
                      #endif /* _OPENMP */
                      for (__pyx_t_5 = 0; __pyx_t_5 < __pyx_t_6; __pyx_t_5++){
                          {
                              __pyx_v_col = (int)(0 + 1 * __pyx_t_5);
/* … */
        /*finally:*/ {
          /*normal exit:*/{
            #ifdef WITH_THREAD
            __Pyx_FastGIL_Forget();
            Py_BLOCK_THREADS
            #endif
            goto __pyx_L11;
          }
          __pyx_L10_error: {
            #ifdef WITH_THREAD
            __Pyx_FastGIL_Forget();
            Py_BLOCK_THREADS
            #endif
            goto __pyx_L1_error;
          }
          __pyx_L11:;
        }
    }
  }
  __pyx_L3:;
+049:             if valid_cols[col] == 1:
                              __pyx_t_7 = __pyx_v_col;
                              __pyx_t_2 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t *) ( /* dim=0 */ (__pyx_v_valid_cols.data + __pyx_t_7 * __pyx_v_valid_cols.strides[0]) ))) == 1);
                              if (__pyx_t_2) {
/* … */
                              }
                              goto __pyx_L23;
                              __pyx_L14_error:;
                              {
                                  #ifdef WITH_THREAD
                                  PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
                                  #endif
                                  #ifdef _OPENMP
                                  #pragma omp flush(__pyx_parallel_exc_type)
                                  #endif /* _OPENMP */
                                  if (!__pyx_parallel_exc_type) {
                                    __Pyx_ErrFetchWithState(&__pyx_parallel_exc_type, &__pyx_parallel_exc_value, &__pyx_parallel_exc_tb);
                                    __pyx_parallel_filename = __pyx_filename; __pyx_parallel_lineno = __pyx_lineno; __pyx_parallel_clineno = __pyx_clineno;
                                    __Pyx_GOTREF(__pyx_parallel_exc_type);
                                  }
                                  #ifdef WITH_THREAD
                                  __Pyx_PyGILState_Release(__pyx_gilstate_save);
                                  #endif
                              }
                              __pyx_parallel_why = 4;
                              goto __pyx_L22;
                              __pyx_L22:;
                              #ifdef _OPENMP
                              #pragma omp critical(__pyx_parallel_lastprivates0)
                              #endif /* _OPENMP */
                              {
                                  __pyx_parallel_temp0 = __pyx_v_col;
                              }
                              __pyx_L23:;
                              #ifdef _OPENMP
                              #pragma omp flush(__pyx_parallel_why)
                              #endif /* _OPENMP */
                          }
                      }
                      #ifdef _OPENMP
                      Py_END_ALLOW_THREADS
                      #else
{
#ifdef WITH_THREAD
                      PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
                      #endif
                      #endif /* _OPENMP */
                      /* Clean up any temporaries */
                      __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
                      #ifdef WITH_THREAD
                      __Pyx_PyGILState_Release(__pyx_gilstate_save);
                      #endif
                      #ifndef _OPENMP
}
#endif /* _OPENMP */
                  }
              }
              if (__pyx_parallel_exc_type) {
                /* This may have been overridden by a continue, break or return in another thread. Prefer the error. */
                __pyx_parallel_why = 4;
              }
              if (__pyx_parallel_why) {
                __pyx_v_col = __pyx_parallel_temp0;
                switch (__pyx_parallel_why) {
                      case 4:
                  {
                      #ifdef WITH_THREAD
                      PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
                      #endif
                      __Pyx_GIVEREF(__pyx_parallel_exc_type);
                      __Pyx_ErrRestoreWithState(__pyx_parallel_exc_type, __pyx_parallel_exc_value, __pyx_parallel_exc_tb);
                      __pyx_filename = __pyx_parallel_filename; __pyx_lineno = __pyx_parallel_lineno; __pyx_clineno = __pyx_parallel_clineno;
                      #ifdef WITH_THREAD
                      __Pyx_PyGILState_Release(__pyx_gilstate_save);
                      #endif
                  }
                  goto __pyx_L10_error;
                }
              }
          }
          #if ((defined(__APPLE__) || defined(__OSX__)) && (defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))))
              #undef likely
              #undef unlikely
              #define likely(x)   __builtin_expect(!!(x), 1)
              #define unlikely(x) __builtin_expect(!!(x), 0)
          #endif
        }
+050:                 with gil:
                                {
                                    #ifdef WITH_THREAD
                                    PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
                                    #endif
                                    /*try:*/ {
/* … */
                                    /*finally:*/ {
                                      /*normal exit:*/{
                                        #ifdef WITH_THREAD
                                        __Pyx_PyGILState_Release(__pyx_gilstate_save);
                                        #endif
                                        goto __pyx_L21;
                                      }
                                      __pyx_L20_error: {
                                        #ifdef WITH_THREAD
                                        __Pyx_PyGILState_Release(__pyx_gilstate_save);
                                        #endif
                                        goto __pyx_L14_error;
                                      }
                                      __pyx_L21:;
                                    }
                                }
+051:                     update_col_all_mistakes_histogram_unsorted(
                                      __pyx_f_5d_imm_9splitters_10cut_finder_update_col_all_mistakes_histogram_unsorted(__pyx_v_X, __pyx_v_y, __pyx_v_centers, __pyx_v_valid_centers, __pyx_v_col, __pyx_v_n, __pyx_v_k, __pyx_v_feature_results, ((PyObject*)__pyx_t_1)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 51, __pyx_L20_error)
                                      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
                                    }
 052:                         X, y, centers, valid_centers,
+053:                         col, n, k, feature_results, histogram[col]
                                      if (unlikely(__pyx_v_histogram == Py_None)) {
                                        PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
                                        __PYX_ERR(0, 53, __pyx_L20_error)
                                      }
                                      if (!(likely(PyList_CheckExact(PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col)))||((PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col)) == Py_None) || __Pyx_RaiseUnexpectedTypeError("list", PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col)))) __PYX_ERR(0, 53, __pyx_L20_error)
                                      __pyx_t_1 = PyList_GET_ITEM(__pyx_v_histogram, __pyx_v_col);
                                      __Pyx_INCREF(__pyx_t_1);
 054:                     )
 055: 
+056:     return feature_results
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(__pyx_v_feature_results);
  __pyx_r = __pyx_v_feature_results;
  goto __pyx_L0;
 057: 
 058: 
 059: @cython.boundscheck(False)
 060: @cython.wraparound(False)
+061: cdef void update_col_all_mistakes_histogram_unsorted(
static void __pyx_f_5d_imm_9splitters_10cut_finder_update_col_all_mistakes_histogram_unsorted(__Pyx_memviewslice __pyx_v_X, __Pyx_memviewslice __pyx_v_y, __Pyx_memviewslice __pyx_v_centers, __Pyx_memviewslice __pyx_v_valid_centers, int __pyx_v_col, int __pyx_v_n, int __pyx_v_k, PyObject *__pyx_v_feature_results, PyObject *__pyx_v_histogram) {
  int __pyx_v_i;
  int __pyx_v_ix;
  CYTHON_UNUSED int __pyx_v_ic;
  int __pyx_v_mistakes;
  __pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t __pyx_v_threshold;
  CYTHON_UNUSED __Pyx_memviewslice __pyx_v_centers_order = { 0, 0, { 0 }, { 0 }, { 0 } };
  int __pyx_v_num_thresholds;
  __pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *__pyx_v_combined_thresholds;
  __pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t __pyx_v_max_val;
  __pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t __pyx_v_min_val;
  PyObject *__pyx_v_unique_thresholds = NULL;
  PyObject *__pyx_v_split = NULL;
  PyObject *__pyx_v_sorted_thresholds = NULL;
/* … */
  /* function exit code */
  goto __pyx_L0;
  __pyx_L1_error:;
  #ifdef WITH_THREAD
  __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
  #endif
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_XDECREF(__pyx_t_10);
  __PYX_XCLEAR_MEMVIEW(&__pyx_t_11, 1);
  __Pyx_XDECREF(__pyx_t_12);
  __PYX_XCLEAR_MEMVIEW(&__pyx_t_14, 1);
  __Pyx_AddTraceback("d_imm.splitters.cut_finder.update_col_all_mistakes_histogram_unsorted", __pyx_clineno, __pyx_lineno, __pyx_filename);
  #ifdef WITH_THREAD
  __Pyx_PyGILState_Release(__pyx_gilstate_save);
  #endif
  __pyx_L0:;
  __PYX_XCLEAR_MEMVIEW(&__pyx_v_centers_order, 0);
  #ifdef WITH_THREAD
  __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
  #endif
  __Pyx_XDECREF(__pyx_v_unique_thresholds);
  __Pyx_XDECREF(__pyx_v_split);
  __Pyx_XDECREF(__pyx_v_sorted_thresholds);
  __Pyx_RefNannyFinishContext();
  #ifdef WITH_THREAD
  __Pyx_PyGILState_Release(__pyx_gilstate_save);
  #endif
}
 062:     NP_FLOAT_t[:,:] X, NP_INT_t[:] y, NP_FLOAT_t[:,:] centers,
 063:     NP_INT_t[:] valid_centers,
 064:     int col, int n, int k,
 065:     list feature_results, list histogram) nogil:  # Marked as noexcept
 066:     """
 067:     Helper function to calculate mistakes for a single column using histogram-based and center-based thresholds.
 068:     Appends the results as Python dictionaries to feature_results.
 069:     """
 070:     cdef int i
+071:     cdef int ix = 0
  __pyx_v_ix = 0;
+072:     cdef int ic = 0
  __pyx_v_ic = 0;
+073:     cdef int mistakes = 0
  __pyx_v_mistakes = 0;
 074:     cdef NP_FLOAT_t threshold
 075:     cdef np.int64_t[:] centers_order
 076:     cdef int num_thresholds
 077:     cdef NP_FLOAT_t *combined_thresholds
 078:     cdef NP_FLOAT_t max_val
 079:     cdef NP_FLOAT_t min_val
 080: 
 081:     # Find the maximum and minimum valid center values
+082:     max_val = -INFINITY
  __pyx_v_max_val = (-INFINITY);
+083:     min_val = INFINITY
  __pyx_v_min_val = INFINITY;
 084: 
+085:     for i in range(k):
  __pyx_t_1 = __pyx_v_k;
  __pyx_t_2 = __pyx_t_1;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
    __pyx_v_i = __pyx_t_3;
+086:         if valid_centers[i] == 1:
    __pyx_t_4 = __pyx_v_i;
    __pyx_t_5 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t *) ( /* dim=0 */ (__pyx_v_valid_centers.data + __pyx_t_4 * __pyx_v_valid_centers.strides[0]) ))) == 1);
    if (__pyx_t_5) {
/* … */
    }
  }
+087:             if centers[i, col] > max_val:
      __pyx_t_4 = __pyx_v_i;
      __pyx_t_6 = __pyx_v_col;
      __pyx_t_5 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_4 * __pyx_v_centers.strides[0]) ) + __pyx_t_6 * __pyx_v_centers.strides[1]) ))) > __pyx_v_max_val);
      if (__pyx_t_5) {
/* … */
      }
+088:                 max_val = centers[i, col]
        __pyx_t_6 = __pyx_v_i;
        __pyx_t_4 = __pyx_v_col;
        __pyx_v_max_val = (*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_6 * __pyx_v_centers.strides[0]) ) + __pyx_t_4 * __pyx_v_centers.strides[1]) )));
+089:             if centers[i, col] < min_val:
      __pyx_t_4 = __pyx_v_i;
      __pyx_t_6 = __pyx_v_col;
      __pyx_t_5 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_4 * __pyx_v_centers.strides[0]) ) + __pyx_t_6 * __pyx_v_centers.strides[1]) ))) < __pyx_v_min_val);
      if (__pyx_t_5) {
/* … */
      }
+090:                 min_val = centers[i, col]
        __pyx_t_6 = __pyx_v_i;
        __pyx_t_4 = __pyx_v_col;
        __pyx_v_min_val = (*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_6 * __pyx_v_centers.strides[0]) ) + __pyx_t_4 * __pyx_v_centers.strides[1]) )));
 091: 
 092:     # Sorting and threshold combination
+093:     with gil:
  {
      #ifdef WITH_THREAD
      PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
      #endif
      /*try:*/ {
/* … */
      /*finally:*/ {
        /*normal exit:*/{
          #ifdef WITH_THREAD
          __Pyx_PyGILState_Release(__pyx_gilstate_save);
          #endif
          goto __pyx_L10;
        }
        __pyx_L9_error: {
          #ifdef WITH_THREAD
          __Pyx_PyGILState_Release(__pyx_gilstate_save);
          #endif
          goto __pyx_L1_error;
        }
        __pyx_L10:;
      }
  }
+094:         centers_order = np.asarray(centers[:, col]).argsort()
        __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_n_s_np); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 94, __pyx_L9_error)
        __Pyx_GOTREF(__pyx_t_9);
        __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_asarray); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 94, __pyx_L9_error)
        __Pyx_GOTREF(__pyx_t_10);
        __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
        __pyx_t_11.data = __pyx_v_centers.data;
        __pyx_t_11.memview = __pyx_v_centers.memview;
        __PYX_INC_MEMVIEW(&__pyx_t_11, 1);
        __pyx_t_11.shape[0] = __pyx_v_centers.shape[0];
__pyx_t_11.strides[0] = __pyx_v_centers.strides[0];
    __pyx_t_11.suboffsets[0] = -1;

{
    Py_ssize_t __pyx_tmp_idx = __pyx_v_col;
    Py_ssize_t __pyx_tmp_stride = __pyx_v_centers.strides[1];
        __pyx_t_11.data += __pyx_tmp_idx * __pyx_tmp_stride;
}

__pyx_t_9 = __pyx_memoryview_fromslice(__pyx_t_11, 1, (PyObject *(*)(char *)) __pyx_memview_get_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t, (int (*)(char *, PyObject *)) __pyx_memview_set_nn___pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t, 0);; if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 94, __pyx_L9_error)
        __Pyx_GOTREF(__pyx_t_9);
        __PYX_XCLEAR_MEMVIEW(&__pyx_t_11, 1);
        __pyx_t_11.memview = NULL; __pyx_t_11.data = NULL;
        __pyx_t_12 = NULL;
        __pyx_t_13 = 0;
        #if CYTHON_UNPACK_METHODS
        if (unlikely(PyMethod_Check(__pyx_t_10))) {
          __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_10);
          if (likely(__pyx_t_12)) {
            PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
            __Pyx_INCREF(__pyx_t_12);
            __Pyx_INCREF(function);
            __Pyx_DECREF_SET(__pyx_t_10, function);
            __pyx_t_13 = 1;
          }
        }
        #endif
        {
          PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_t_9};
          __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+1-__pyx_t_13, 1+__pyx_t_13);
          __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0;
          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
          if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 94, __pyx_L9_error)
          __Pyx_GOTREF(__pyx_t_8);
          __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
        }
        __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_n_s_argsort); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 94, __pyx_L9_error)
        __Pyx_GOTREF(__pyx_t_10);
        __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
        __pyx_t_8 = NULL;
        __pyx_t_13 = 0;
        #if CYTHON_UNPACK_METHODS
        if (likely(PyMethod_Check(__pyx_t_10))) {
          __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_10);
          if (likely(__pyx_t_8)) {
            PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_10);
            __Pyx_INCREF(__pyx_t_8);
            __Pyx_INCREF(function);
            __Pyx_DECREF_SET(__pyx_t_10, function);
            __pyx_t_13 = 1;
          }
        }
        #endif
        {
          PyObject *__pyx_callargs[2] = {__pyx_t_8, NULL};
          __pyx_t_7 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+1-__pyx_t_13, 0+__pyx_t_13);
          __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0;
          if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 94, __pyx_L9_error)
          __Pyx_GOTREF(__pyx_t_7);
          __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
        }
        __pyx_t_14 = __Pyx_PyObject_to_MemoryviewSlice_ds_nn___pyx_t_5numpy_int64_t(__pyx_t_7, PyBUF_WRITABLE); if (unlikely(!__pyx_t_14.memview)) __PYX_ERR(0, 94, __pyx_L9_error)
        __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
        __pyx_v_centers_order = __pyx_t_14;
        __pyx_t_14.memview = NULL;
        __pyx_t_14.data = NULL;
 095: 
 096:         # Combine histogram-based and center-based thresholds
+097:         unique_thresholds = set()
        __pyx_t_7 = PySet_New(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 97, __pyx_L9_error)
        __Pyx_GOTREF(__pyx_t_7);
        __pyx_v_unique_thresholds = ((PyObject*)__pyx_t_7);
        __pyx_t_7 = 0;
+098:         for split in histogram:
        if (unlikely(__pyx_v_histogram == Py_None)) {
          PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable");
          __PYX_ERR(0, 98, __pyx_L9_error)
        }
        __pyx_t_7 = __pyx_v_histogram; __Pyx_INCREF(__pyx_t_7);
        __pyx_t_15 = 0;
        for (;;) {
          {
            Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_7);
            #if !CYTHON_ASSUME_SAFE_MACROS
            if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 98, __pyx_L9_error)
            #endif
            if (__pyx_t_15 >= __pyx_temp) break;
          }
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_10 = PyList_GET_ITEM(__pyx_t_7, __pyx_t_15); __Pyx_INCREF(__pyx_t_10); __pyx_t_15++; if (unlikely((0 < 0))) __PYX_ERR(0, 98, __pyx_L9_error)
          #else
          __pyx_t_10 = __Pyx_PySequence_ITEM(__pyx_t_7, __pyx_t_15); __pyx_t_15++; if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 98, __pyx_L9_error)
          __Pyx_GOTREF(__pyx_t_10);
          #endif
          __Pyx_XDECREF_SET(__pyx_v_split, __pyx_t_10);
          __pyx_t_10 = 0;
/* … */
        }
        __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+099:             if min_val <= split.threshold < max_val:
          __pyx_t_10 = PyFloat_FromDouble(__pyx_v_min_val); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 99, __pyx_L9_error)
          __Pyx_GOTREF(__pyx_t_10);
          __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_split, __pyx_n_s_threshold); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 99, __pyx_L9_error)
          __Pyx_GOTREF(__pyx_t_8);
          __pyx_t_9 = PyObject_RichCompare(__pyx_t_10, __pyx_t_8, Py_LE); __Pyx_XGOTREF(__pyx_t_9); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 99, __pyx_L9_error)
          if (__Pyx_PyObject_IsTrue(__pyx_t_9)) {
            __Pyx_DECREF(__pyx_t_9);
            __pyx_t_12 = PyFloat_FromDouble(__pyx_v_max_val); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 99, __pyx_L9_error)
            __Pyx_GOTREF(__pyx_t_12);
            __pyx_t_9 = PyObject_RichCompare(__pyx_t_8, __pyx_t_12, Py_LT); __Pyx_XGOTREF(__pyx_t_9); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 99, __pyx_L9_error)
            __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
          }
          __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
          __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
          __pyx_t_5 = __Pyx_PyObject_IsTrue(__pyx_t_9); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 99, __pyx_L9_error)
          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
          if (__pyx_t_5) {
/* … */
          }
+100:                 unique_thresholds.add(split.threshold)
            __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_v_split, __pyx_n_s_threshold); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 100, __pyx_L9_error)
            __Pyx_GOTREF(__pyx_t_9);
            __pyx_t_16 = PySet_Add(__pyx_v_unique_thresholds, __pyx_t_9); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 100, __pyx_L9_error)
            __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
 101: 
+102:         for i in range(k):
        __pyx_t_1 = __pyx_v_k;
        __pyx_t_2 = __pyx_t_1;
        for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
          __pyx_v_i = __pyx_t_3;
+103:             if valid_centers[i] == 1 and centers[i, col]!=max_val:
          __pyx_t_4 = __pyx_v_i;
          __pyx_t_17 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t *) ( /* dim=0 */ (__pyx_v_valid_centers.data + __pyx_t_4 * __pyx_v_valid_centers.strides[0]) ))) == 1);
          if (__pyx_t_17) {
          } else {
            __pyx_t_5 = __pyx_t_17;
            goto __pyx_L18_bool_binop_done;
          }
          __pyx_t_4 = __pyx_v_i;
          __pyx_t_6 = __pyx_v_col;
          __pyx_t_17 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_4 * __pyx_v_centers.strides[0]) ) + __pyx_t_6 * __pyx_v_centers.strides[1]) ))) != __pyx_v_max_val);
          __pyx_t_5 = __pyx_t_17;
          __pyx_L18_bool_binop_done:;
          if (__pyx_t_5) {
/* … */
          }
        }
+104:                 unique_thresholds.add(centers[i, col])
            __pyx_t_6 = __pyx_v_i;
            __pyx_t_4 = __pyx_v_col;
            __pyx_t_7 = PyFloat_FromDouble((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_6 * __pyx_v_centers.strides[0]) ) + __pyx_t_4 * __pyx_v_centers.strides[1]) )))); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 104, __pyx_L9_error)
            __Pyx_GOTREF(__pyx_t_7);
            __pyx_t_16 = PySet_Add(__pyx_v_unique_thresholds, __pyx_t_7); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 104, __pyx_L9_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
 105: 
+106:         sorted_thresholds = sorted(unique_thresholds)
        __pyx_t_9 = PySequence_List(__pyx_v_unique_thresholds); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 106, __pyx_L9_error)
        __Pyx_GOTREF(__pyx_t_9);
        __pyx_t_7 = ((PyObject*)__pyx_t_9);
        __pyx_t_9 = 0;
        __pyx_t_16 = PyList_Sort(__pyx_t_7); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 106, __pyx_L9_error)
        __pyx_v_sorted_thresholds = ((PyObject*)__pyx_t_7);
        __pyx_t_7 = 0;
 107: 
+108:         num_thresholds = len(sorted_thresholds)
        __pyx_t_15 = __Pyx_PyList_GET_SIZE(__pyx_v_sorted_thresholds); if (unlikely(__pyx_t_15 == ((Py_ssize_t)-1))) __PYX_ERR(0, 108, __pyx_L9_error)
        __pyx_v_num_thresholds = __pyx_t_15;
+109:         combined_thresholds = <NP_FLOAT_t *> malloc(num_thresholds * sizeof(NP_FLOAT_t))
        __pyx_v_combined_thresholds = ((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *)malloc((__pyx_v_num_thresholds * (sizeof(__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t)))));
 110: 
+111:         for i in range(num_thresholds):
        __pyx_t_1 = __pyx_v_num_thresholds;
        __pyx_t_2 = __pyx_t_1;
        for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
          __pyx_v_i = __pyx_t_3;
+112:             combined_thresholds[i] = sorted_thresholds[i]
          __pyx_t_18 = __pyx_PyFloat_AsDouble(PyList_GET_ITEM(__pyx_v_sorted_thresholds, __pyx_v_i)); if (unlikely((__pyx_t_18 == ((npy_float64)-1)) && PyErr_Occurred())) __PYX_ERR(0, 112, __pyx_L9_error)
          (__pyx_v_combined_thresholds[__pyx_v_i]) = __pyx_t_18;
        }
      }
 113: 
 114:     # Process each threshold
+115:     for i in range(num_thresholds):
  __pyx_t_1 = __pyx_v_num_thresholds;
  __pyx_t_2 = __pyx_t_1;
  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
    __pyx_v_i = __pyx_t_3;
+116:         mistakes = 0
    __pyx_v_mistakes = 0;
+117:         ix = 0
    __pyx_v_ix = 0;
+118:         threshold = combined_thresholds[i]
    __pyx_v_threshold = (__pyx_v_combined_thresholds[__pyx_v_i]);
 119: 
 120:         # Count mistakes
+121:         while ix < n:
    while (1) {
      __pyx_t_5 = (__pyx_v_ix < __pyx_v_n);
      if (!__pyx_t_5) break;
+122:             if X[ix, col] <= threshold:
      __pyx_t_4 = __pyx_v_ix;
      __pyx_t_6 = __pyx_v_col;
      __pyx_t_5 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_X.data + __pyx_t_4 * __pyx_v_X.strides[0]) ) + __pyx_t_6 * __pyx_v_X.strides[1]) ))) <= __pyx_v_threshold);
      if (__pyx_t_5) {
/* … */
        goto __pyx_L26;
      }
+123:                 if centers[y[ix], col] > threshold:
        __pyx_t_6 = __pyx_v_ix;
        __pyx_t_4 = (*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t *) ( /* dim=0 */ (__pyx_v_y.data + __pyx_t_6 * __pyx_v_y.strides[0]) )));
        __pyx_t_19 = __pyx_v_col;
        __pyx_t_5 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_4 * __pyx_v_centers.strides[0]) ) + __pyx_t_19 * __pyx_v_centers.strides[1]) ))) > __pyx_v_threshold);
        if (__pyx_t_5) {
/* … */
        }
+124:                     mistakes += 1
          __pyx_v_mistakes = (__pyx_v_mistakes + 1);
 125:             else:
+126:                 if centers[y[ix], col] <= threshold:
      /*else*/ {
        __pyx_t_6 = __pyx_v_ix;
        __pyx_t_19 = (*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_INT_t *) ( /* dim=0 */ (__pyx_v_y.data + __pyx_t_6 * __pyx_v_y.strides[0]) )));
        __pyx_t_4 = __pyx_v_col;
        __pyx_t_5 = ((*((__pyx_t_5d_imm_9splitters_10cut_finder_NP_FLOAT_t *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_centers.data + __pyx_t_19 * __pyx_v_centers.strides[0]) ) + __pyx_t_4 * __pyx_v_centers.strides[1]) ))) <= __pyx_v_threshold);
        if (__pyx_t_5) {
/* … */
        }
      }
      __pyx_L26:;
+127:                     mistakes += 1
          __pyx_v_mistakes = (__pyx_v_mistakes + 1);
+128:             ix += 1
      __pyx_v_ix = (__pyx_v_ix + 1);
    }
 129: 
 130:         # Store result
+131:         with gil:
    {
        #ifdef WITH_THREAD
        PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
        #endif
        /*try:*/ {
/* … */
        /*finally:*/ {
          /*normal exit:*/{
            #ifdef WITH_THREAD
            __Pyx_PyGILState_Release(__pyx_gilstate_save);
            #endif
            goto __pyx_L33;
          }
          __pyx_L32_error: {
            #ifdef WITH_THREAD
            __Pyx_PyGILState_Release(__pyx_gilstate_save);
            #endif
            goto __pyx_L1_error;
          }
          __pyx_L33:;
        }
    }
  }
+132:             feature_results.append({
          if (unlikely(__pyx_v_feature_results == Py_None)) {
            PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "append");
            __PYX_ERR(0, 132, __pyx_L32_error)
          }
/* … */
          __pyx_t_16 = __Pyx_PyList_Append(__pyx_v_feature_results, __pyx_t_7); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 132, __pyx_L32_error)
          __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
        }
+133:                 'feature': col,
          __pyx_t_7 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 133, __pyx_L32_error)
          __Pyx_GOTREF(__pyx_t_7);
          __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_col); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 133, __pyx_L32_error)
          __Pyx_GOTREF(__pyx_t_9);
          if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_feature, __pyx_t_9) < 0) __PYX_ERR(0, 133, __pyx_L32_error)
          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+134:                 'threshold': threshold,
          __pyx_t_9 = PyFloat_FromDouble(__pyx_v_threshold); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 134, __pyx_L32_error)
          __Pyx_GOTREF(__pyx_t_9);
          if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_threshold, __pyx_t_9) < 0) __PYX_ERR(0, 133, __pyx_L32_error)
          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
+135:                 'mistakes': mistakes
          __pyx_t_9 = __Pyx_PyInt_From_int(__pyx_v_mistakes); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 135, __pyx_L32_error)
          __Pyx_GOTREF(__pyx_t_9);
          if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_mistakes, __pyx_t_9) < 0) __PYX_ERR(0, 133, __pyx_L32_error)
          __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
 136:             })
 137: 
+138:     free(combined_thresholds)
  free(__pyx_v_combined_thresholds);