Generated by Cython 3.0.10

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: ecc_sigmoid.c

    +001: cimport cython

      __pyx_t_4 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 1, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_4) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;

     002: from libc.stdlib cimport malloc, free

     003: from libc.math cimport ceil, exp

    +004: import gudhi as gd

      __pyx_t_7 = __Pyx_ImportDottedModule(__pyx_n_s_gudhi, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 4, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      if (PyDict_SetItem(__pyx_d, __pyx_n_s_gd, __pyx_t_7) < 0) __PYX_ERR(0, 4, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;

    +005: import numpy as np

      __pyx_t_7 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 5, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_7) < 0) __PYX_ERR(0, 5, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;

     006: cimport numpy as cnp

    +007: cnp.import_array()

      __pyx_t_9 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_9 == ((int)-1))) __PYX_ERR(0, 7, __pyx_L1_error)

     008:

     009:

    +010: dtype_float = np.float32

      __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 10, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_float32); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 10, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
      if (PyDict_SetItem(__pyx_d, __pyx_n_s_dtype_float, __pyx_t_4) < 0) __PYX_ERR(0, 10, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;

     011:

     012:

     013: @cython.cdivision(True)     # turn off checking for division by zero

    +014: cdef inline float sigmoid(float x, float lam) except -1:

    static CYTHON_INLINE float __pyx_f_11ecc_sigmoid_sigmoid(float __pyx_v_x, float __pyx_v_lam) {
      float __pyx_r;
    /* … */
      /* function exit code */
      __pyx_L0:;
      return __pyx_r;
    }

    +015:     return 1 / (1 + exp(-lam * x))

      __pyx_r = (1.0 / (1.0 + exp(((-__pyx_v_lam) * __pyx_v_x))));
      goto __pyx_L0;

     016:

    +017: cdef class SigEccBackbone:

    struct __pyx_obj_11ecc_sigmoid_SigEccBackbone {
      PyObject_HEAD
      struct __pyx_vtabstruct_11ecc_sigmoid_SigEccBackbone *__pyx_vtab;
      Py_ssize_t w;
      Py_ssize_t grid_h;
      Py_ssize_t grid_w;
      Py_ssize_t num_cells;
      Py_ssize_t steps;
      float t_min;
      float t_max;
      float resolution;
      float lower_bound;
      float lam;
      __Pyx_memviewslice tseq;
      __Pyx_memviewslice dimension;
    };
    /* … */
    struct __pyx_vtabstruct_11ecc_sigmoid_SigEccBackbone {
      Py_ssize_t (*_sq2pix)(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *, Py_ssize_t);
      Py_ssize_t *(*_find_neighbor_sq)(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *, Py_ssize_t, float, Py_ssize_t *);
      Py_ssize_t *(*_find_min_sq)(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *, float *, Py_ssize_t *, Py_ssize_t, Py_ssize_t *);
      PyObject *(*_set_dimension)(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *);
    };
    static struct __pyx_vtabstruct_11ecc_sigmoid_SigEccBackbone *__pyx_vtabptr_11ecc_sigmoid_SigEccBackbone;
    static CYTHON_INLINE Py_ssize_t __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *, Py_ssize_t);
    static CYTHON_INLINE Py_ssize_t *__pyx_f_11ecc_sigmoid_14SigEccBackbone__find_neighbor_sq(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *, Py_ssize_t, float, Py_ssize_t *);
    static CYTHON_INLINE Py_ssize_t *__pyx_f_11ecc_sigmoid_14SigEccBackbone__find_min_sq(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *, float *, Py_ssize_t *, Py_ssize_t, Py_ssize_t *);

     018:     cdef Py_ssize_t w, grid_h, grid_w, num_cells, steps

     019:     cdef float t_min, t_max, resolution, lower_bound, lam

     020:     cdef float[:] tseq

     021:     cdef const float[:] dimension

     022:

    +023:     def __init__(self, t_const=True, size=[28, 28], interval=[0.02, 0.28], steps=32, lam=200.):

    /* Python wrapper */
    static int __pyx_pw_11ecc_sigmoid_14SigEccBackbone_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
    PyDoc_STRVAR(__pyx_doc_11ecc_sigmoid_14SigEccBackbone___init__, "\n        Args:\n            t_const (bool, optional): Use T-construction. If False, V-construction will be used. Defaults to True.\n            size (list, optional): [Height, Width] of image. Defaults to [28, 28].\n            interval (list, optional): Minimum and maximum value of interval to consider. Defaults to [0.02, 0.28].\n            steps (int, optional):  Number of discretized points. Defaults to 32.\n            lamda (float, optional): Controls the tightness of sigmoid approximation. Defaults to 200.\n        ");
    #if CYTHON_UPDATE_DESCRIPTOR_DOC
    struct wrapperbase __pyx_wrapperbase_11ecc_sigmoid_14SigEccBackbone___init__;
    #endif
    static int __pyx_pw_11ecc_sigmoid_14SigEccBackbone_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
      PyObject *__pyx_v_t_const = 0;
      PyObject *__pyx_v_size = 0;
      PyObject *__pyx_v_interval = 0;
      PyObject *__pyx_v_steps = 0;
      PyObject *__pyx_v_lam = 0;
      CYTHON_UNUSED Py_ssize_t __pyx_nargs;
      CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
      int __pyx_r;
      __Pyx_RefNannyDeclarations
      __Pyx_RefNannySetupContext("__init__ (wrapper)", 0);
      #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 -1;
      #endif
      __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs);
      {
        PyObject **__pyx_pyargnames[] = {&__pyx_n_s_t_const,&__pyx_n_s_size,&__pyx_n_s_interval,&__pyx_n_s_steps,&__pyx_n_s_lam,0};
      PyObject* values[5] = {0,0,0,0,0};
        values[0] = __Pyx_Arg_NewRef_VARARGS(((PyObject *)Py_True));
        values[1] = __Pyx_Arg_NewRef_VARARGS(__pyx_k__11);
        values[2] = __Pyx_Arg_NewRef_VARARGS(__pyx_k__12);
        values[3] = __Pyx_Arg_NewRef_VARARGS(((PyObject *)__pyx_int_32));
        values[4] = __Pyx_Arg_NewRef_VARARGS(((PyObject *)__pyx_float_200_));
        if (__pyx_kwds) {
          Py_ssize_t kw_args;
          switch (__pyx_nargs) {
            case  5: values[4] = __Pyx_Arg_VARARGS(__pyx_args, 4);
            CYTHON_FALLTHROUGH;
            case  4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3);
            CYTHON_FALLTHROUGH;
            case  3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2);
            CYTHON_FALLTHROUGH;
            case  2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1);
            CYTHON_FALLTHROUGH;
            case  1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0);
            CYTHON_FALLTHROUGH;
            case  0: break;
            default: goto __pyx_L5_argtuple_error;
          }
          kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds);
          switch (__pyx_nargs) {
            case  0:
            if (kw_args > 0) {
              PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_t_const);
              if (value) { values[0] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; }
              else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 23, __pyx_L3_error)
            }
            CYTHON_FALLTHROUGH;
            case  1:
            if (kw_args > 0) {
              PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_size);
              if (value) { values[1] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; }
              else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 23, __pyx_L3_error)
            }
            CYTHON_FALLTHROUGH;
            case  2:
            if (kw_args > 0) {
              PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_interval);
              if (value) { values[2] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; }
              else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 23, __pyx_L3_error)
            }
            CYTHON_FALLTHROUGH;
            case  3:
            if (kw_args > 0) {
              PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_steps);
              if (value) { values[3] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; }
              else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 23, __pyx_L3_error)
            }
            CYTHON_FALLTHROUGH;
            case  4:
            if (kw_args > 0) {
              PyObject* value = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_lam);
              if (value) { values[4] = __Pyx_Arg_NewRef_VARARGS(value); kw_args--; }
              else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 23, __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, "__init__") < 0)) __PYX_ERR(0, 23, __pyx_L3_error)
          }
        } else {
          switch (__pyx_nargs) {
            case  5: values[4] = __Pyx_Arg_VARARGS(__pyx_args, 4);
            CYTHON_FALLTHROUGH;
            case  4: values[3] = __Pyx_Arg_VARARGS(__pyx_args, 3);
            CYTHON_FALLTHROUGH;
            case  3: values[2] = __Pyx_Arg_VARARGS(__pyx_args, 2);
            CYTHON_FALLTHROUGH;
            case  2: values[1] = __Pyx_Arg_VARARGS(__pyx_args, 1);
            CYTHON_FALLTHROUGH;
            case  1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0);
            CYTHON_FALLTHROUGH;
            case  0: break;
            default: goto __pyx_L5_argtuple_error;
          }
        }
        __pyx_v_t_const = values[0];
        __pyx_v_size = values[1];
        __pyx_v_interval = values[2];
        __pyx_v_steps = values[3];
        __pyx_v_lam = values[4];
      }
      goto __pyx_L6_skip;
      __pyx_L5_argtuple_error:;
      __Pyx_RaiseArgtupleInvalid("__init__", 0, 0, 5, __pyx_nargs); __PYX_ERR(0, 23, __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_VARARGS(values[__pyx_temp]);
        }
      }
      __Pyx_AddTraceback("ecc_sigmoid.SigEccBackbone.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
      __Pyx_RefNannyFinishContext();
      return -1;
      __pyx_L4_argument_unpacking_done:;
      __pyx_r = __pyx_pf_11ecc_sigmoid_14SigEccBackbone___init__(((struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *)__pyx_v_self), __pyx_v_t_const, __pyx_v_size, __pyx_v_interval, __pyx_v_steps, __pyx_v_lam);

      /* function exit code */
      {
        Py_ssize_t __pyx_temp;
        for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
          __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]);
        }
      }
      __Pyx_RefNannyFinishContext();
      return __pyx_r;
    }

    static int __pyx_pf_11ecc_sigmoid_14SigEccBackbone___init__(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *__pyx_v_self, PyObject *__pyx_v_t_const, PyObject *__pyx_v_size, PyObject *__pyx_v_interval, PyObject *__pyx_v_steps, PyObject *__pyx_v_lam) {
      PyObject *__pyx_7genexpr__pyx_v_i = NULL;
      int __pyx_r;
    /* … */
      /* function exit code */
      __pyx_r = 0;
      goto __pyx_L0;
      __pyx_L1_error:;
      __Pyx_XDECREF(__pyx_t_2);
      __Pyx_XDECREF(__pyx_t_3);
      __Pyx_XDECREF(__pyx_t_5);
      __Pyx_XDECREF(__pyx_t_8);
      __Pyx_XDECREF(__pyx_t_9);
      __PYX_XCLEAR_MEMVIEW(&__pyx_t_11, 1);
      __PYX_XCLEAR_MEMVIEW(&__pyx_t_15, 1);
      __Pyx_AddTraceback("ecc_sigmoid.SigEccBackbone.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename);
      __pyx_r = -1;
      __pyx_L0:;
      __Pyx_XDECREF(__pyx_7genexpr__pyx_v_i);
      __Pyx_RefNannyFinishContext();
      return __pyx_r;
    }
    /* … */
      __pyx_t_4 = PyList_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 23, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_INCREF(__pyx_int_28);
      __Pyx_GIVEREF(__pyx_int_28);
      if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_int_28)) __PYX_ERR(0, 23, __pyx_L1_error);
      __Pyx_INCREF(__pyx_int_28);
      __Pyx_GIVEREF(__pyx_int_28);
      if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 1, __pyx_int_28)) __PYX_ERR(0, 23, __pyx_L1_error);
      __pyx_k__11 = __pyx_t_4;
      __Pyx_GIVEREF(__pyx_t_4);
      __pyx_t_4 = 0;
      __pyx_t_4 = PyList_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 23, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_INCREF(__pyx_float_0_02);
      __Pyx_GIVEREF(__pyx_float_0_02);
      if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_float_0_02)) __PYX_ERR(0, 23, __pyx_L1_error);
      __Pyx_INCREF(__pyx_float_0_28);
      __Pyx_GIVEREF(__pyx_float_0_28);
      if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 1, __pyx_float_0_28)) __PYX_ERR(0, 23, __pyx_L1_error);
      __pyx_k__12 = __pyx_t_4;
      __Pyx_GIVEREF(__pyx_t_4);
      __pyx_t_4 = 0;

     024:         """

     025:         Args:

     026:             t_const (bool, optional): Use T-construction. If False, V-construction will be used. Defaults to True.

     027:             size (list, optional): [Height, Width] of image. Defaults to [28, 28].

     028:             interval (list, optional): Minimum and maximum value of interval to consider. Defaults to [0.02, 0.28].

     029:             steps (int, optional):  Number of discretized points. Defaults to 32.

     030:             lamda (float, optional): Controls the tightness of sigmoid approximation. Defaults to 200.

     031:         """

    +032:         assert size[0] > 1 and size[1] > 1, "Size of image should be larger than [1, 1]"

      #ifndef CYTHON_WITHOUT_ASSERTIONS
      if (unlikely(__pyx_assertions_enabled())) {
        __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_size, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 32, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        __pyx_t_3 = PyObject_RichCompare(__pyx_t_2, __pyx_int_1, Py_GT); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 32, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
        __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 32, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        if (__pyx_t_4) {
        } else {
          __pyx_t_1 = __pyx_t_4;
          goto __pyx_L3_bool_binop_done;
        }
        __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_size, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 32, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_3);
        __pyx_t_2 = PyObject_RichCompare(__pyx_t_3, __pyx_int_1, Py_GT); __Pyx_XGOTREF(__pyx_t_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 32, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        __pyx_t_4 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely((__pyx_t_4 < 0))) __PYX_ERR(0, 32, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
        __pyx_t_1 = __pyx_t_4;
        __pyx_L3_bool_binop_done:;
        if (unlikely(!__pyx_t_1)) {
          __Pyx_Raise(__pyx_builtin_AssertionError, __pyx_kp_s_Size_of_image_should_be_larger_t, 0, 0);
          __PYX_ERR(0, 32, __pyx_L1_error)
        }
      }
      #else
      if ((1)); else __PYX_ERR(0, 32, __pyx_L1_error)
      #endif

    +033:         assert interval[1] > interval[0], "End point of interval must be larger than starting point of interval"

      #ifndef CYTHON_WITHOUT_ASSERTIONS
      if (unlikely(__pyx_assertions_enabled())) {
        __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_interval, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 33, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        __pyx_t_3 = __Pyx_GetItemInt(__pyx_v_interval, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 33, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_3);
        __pyx_t_5 = PyObject_RichCompare(__pyx_t_2, __pyx_t_3, Py_GT); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 33, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 33, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
        if (unlikely(!__pyx_t_1)) {
          __Pyx_Raise(__pyx_builtin_AssertionError, __pyx_kp_s_End_point_of_interval_must_be_la, 0, 0);
          __PYX_ERR(0, 33, __pyx_L1_error)
        }
      }
      #else
      if ((1)); else __PYX_ERR(0, 33, __pyx_L1_error)
      #endif

    +034:         assert steps > 1, "Number of steps should be larger than 1"

      #ifndef CYTHON_WITHOUT_ASSERTIONS
      if (unlikely(__pyx_assertions_enabled())) {
        __pyx_t_5 = PyObject_RichCompare(__pyx_v_steps, __pyx_int_1, Py_GT); __Pyx_XGOTREF(__pyx_t_5); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 34, __pyx_L1_error)
        __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_5); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 34, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
        if (unlikely(!__pyx_t_1)) {
          __Pyx_Raise(__pyx_builtin_AssertionError, __pyx_kp_s_Number_of_steps_should_be_larger, 0, 0);
          __PYX_ERR(0, 34, __pyx_L1_error)
        }
      }
      #else
      if ((1)); else __PYX_ERR(0, 34, __pyx_L1_error)
      #endif

    +035:         self.w = size[1]

      __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_size, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 35, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_5);
      __pyx_t_6 = __Pyx_PyIndex_AsSsize_t(__pyx_t_5); if (unlikely((__pyx_t_6 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 35, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
      __pyx_v_self->w = __pyx_t_6;

    +036:         self.grid_h, self.grid_w = [2*i + 1 if t_const else 2*i - 1 for i in size]    # size of the cubical complex

      { /* enter inner scope */
        __pyx_t_5 = PyList_New(0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 36, __pyx_L7_error)
        __Pyx_GOTREF(__pyx_t_5);
        if (likely(PyList_CheckExact(__pyx_v_size)) || PyTuple_CheckExact(__pyx_v_size)) {
          __pyx_t_3 = __pyx_v_size; __Pyx_INCREF(__pyx_t_3);
          __pyx_t_6 = 0;
          __pyx_t_7 = NULL;
        } else {
          __pyx_t_6 = -1; __pyx_t_3 = PyObject_GetIter(__pyx_v_size); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 36, __pyx_L7_error)
          __Pyx_GOTREF(__pyx_t_3);
          __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_3); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 36, __pyx_L7_error)
        }
        for (;;) {
          if (likely(!__pyx_t_7)) {
            if (likely(PyList_CheckExact(__pyx_t_3))) {
              {
                Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_3);
                #if !CYTHON_ASSUME_SAFE_MACROS
                if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 36, __pyx_L7_error)
                #endif
                if (__pyx_t_6 >= __pyx_temp) break;
              }
              #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
              __pyx_t_2 = PyList_GET_ITEM(__pyx_t_3, __pyx_t_6); __Pyx_INCREF(__pyx_t_2); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(0, 36, __pyx_L7_error)
              #else
              __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L7_error)
              __Pyx_GOTREF(__pyx_t_2);
              #endif
            } else {
              {
                Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_3);
                #if !CYTHON_ASSUME_SAFE_MACROS
                if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 36, __pyx_L7_error)
                #endif
                if (__pyx_t_6 >= __pyx_temp) break;
              }
              #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
              __pyx_t_2 = PyTuple_GET_ITEM(__pyx_t_3, __pyx_t_6); __Pyx_INCREF(__pyx_t_2); __pyx_t_6++; if (unlikely((0 < 0))) __PYX_ERR(0, 36, __pyx_L7_error)
              #else
              __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_3, __pyx_t_6); __pyx_t_6++; if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L7_error)
              __Pyx_GOTREF(__pyx_t_2);
              #endif
            }
          } else {
            __pyx_t_2 = __pyx_t_7(__pyx_t_3);
            if (unlikely(!__pyx_t_2)) {
              PyObject* exc_type = PyErr_Occurred();
              if (exc_type) {
                if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear();
                else __PYX_ERR(0, 36, __pyx_L7_error)
              }
              break;
            }
            __Pyx_GOTREF(__pyx_t_2);
          }
          __Pyx_XDECREF_SET(__pyx_7genexpr__pyx_v_i, __pyx_t_2);
          __pyx_t_2 = 0;
          __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_t_const); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 36, __pyx_L7_error)
          if (__pyx_t_1) {
            __pyx_t_8 = __Pyx_PyInt_MultiplyCObj(__pyx_int_2, __pyx_7genexpr__pyx_v_i, 2, 0, 0); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 36, __pyx_L7_error)
            __Pyx_GOTREF(__pyx_t_8);
            __pyx_t_9 = __Pyx_PyInt_AddObjC(__pyx_t_8, __pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 36, __pyx_L7_error)
            __Pyx_GOTREF(__pyx_t_9);
            __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
            __pyx_t_2 = __pyx_t_9;
            __pyx_t_9 = 0;
          } else {
            __pyx_t_9 = __Pyx_PyInt_MultiplyCObj(__pyx_int_2, __pyx_7genexpr__pyx_v_i, 2, 0, 0); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 36, __pyx_L7_error)
            __Pyx_GOTREF(__pyx_t_9);
            __pyx_t_8 = __Pyx_PyInt_SubtractObjC(__pyx_t_9, __pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 36, __pyx_L7_error)
            __Pyx_GOTREF(__pyx_t_8);
            __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
            __pyx_t_2 = __pyx_t_8;
            __pyx_t_8 = 0;
          }
          if (unlikely(__Pyx_ListComp_Append(__pyx_t_5, (PyObject*)__pyx_t_2))) __PYX_ERR(0, 36, __pyx_L7_error)
          __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
        }
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        __Pyx_XDECREF(__pyx_7genexpr__pyx_v_i); __pyx_7genexpr__pyx_v_i = 0;
        goto __pyx_L11_exit_scope;
        __pyx_L7_error:;
        __Pyx_XDECREF(__pyx_7genexpr__pyx_v_i); __pyx_7genexpr__pyx_v_i = 0;
        goto __pyx_L1_error;
        __pyx_L11_exit_scope:;
      } /* exit inner scope */
      if (1) {
        PyObject* sequence = __pyx_t_5;
        Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
        if (unlikely(size != 2)) {
          if (size > 2) __Pyx_RaiseTooManyValuesError(2);
          else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
          __PYX_ERR(0, 36, __pyx_L1_error)
        }
        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
        __pyx_t_3 = PyList_GET_ITEM(sequence, 0);
        __pyx_t_2 = PyList_GET_ITEM(sequence, 1);
        __Pyx_INCREF(__pyx_t_3);
        __Pyx_INCREF(__pyx_t_2);
        #else
        __pyx_t_3 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 36, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_3);
        __pyx_t_2 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        #endif
        __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
      }
      __pyx_t_6 = __Pyx_PyIndex_AsSsize_t(__pyx_t_3); if (unlikely((__pyx_t_6 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 36, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_t_2); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 36, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_v_self->grid_h = __pyx_t_6;
      __pyx_v_self->grid_w = __pyx_t_10;

    +037:         self.num_cells = self.grid_h * self.grid_w

      __pyx_v_self->num_cells = (__pyx_v_self->grid_h * __pyx_v_self->grid_w);

    +038:         self.dimension = self._set_dimension()

      __pyx_t_5 = ((struct __pyx_vtabstruct_11ecc_sigmoid_SigEccBackbone *)__pyx_v_self->__pyx_vtab)->_set_dimension(__pyx_v_self); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 38, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_5);
      __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_ds_float__const__(__pyx_t_5, 0); if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 38, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
      __PYX_XCLEAR_MEMVIEW(&__pyx_v_self->dimension, 0);
      __pyx_v_self->dimension = __pyx_t_11;
      __pyx_t_11.memview = NULL;
      __pyx_t_11.data = NULL;

    +039:         self.t_min, self.t_max = interval

      if ((likely(PyTuple_CheckExact(__pyx_v_interval))) || (PyList_CheckExact(__pyx_v_interval))) {
        PyObject* sequence = __pyx_v_interval;
        Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
        if (unlikely(size != 2)) {
          if (size > 2) __Pyx_RaiseTooManyValuesError(2);
          else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
          __PYX_ERR(0, 39, __pyx_L1_error)
        }
        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
        if (likely(PyTuple_CheckExact(sequence))) {
          __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0);
          __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1);
        } else {
          __pyx_t_5 = PyList_GET_ITEM(sequence, 0);
          __pyx_t_2 = PyList_GET_ITEM(sequence, 1);
        }
        __Pyx_INCREF(__pyx_t_5);
        __Pyx_INCREF(__pyx_t_2);
        #else
        __pyx_t_5 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 39, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_5);
        __pyx_t_2 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 39, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        #endif
      } else {
        Py_ssize_t index = -1;
        __pyx_t_3 = PyObject_GetIter(__pyx_v_interval); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 39, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_3);
        __pyx_t_12 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_3);
        index = 0; __pyx_t_5 = __pyx_t_12(__pyx_t_3); if (unlikely(!__pyx_t_5)) goto __pyx_L12_unpacking_failed;
        __Pyx_GOTREF(__pyx_t_5);
        index = 1; __pyx_t_2 = __pyx_t_12(__pyx_t_3); if (unlikely(!__pyx_t_2)) goto __pyx_L12_unpacking_failed;
        __Pyx_GOTREF(__pyx_t_2);
        if (__Pyx_IternextUnpackEndCheck(__pyx_t_12(__pyx_t_3), 2) < 0) __PYX_ERR(0, 39, __pyx_L1_error)
        __pyx_t_12 = NULL;
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        goto __pyx_L13_unpacking_done;
        __pyx_L12_unpacking_failed:;
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        __pyx_t_12 = NULL;
        if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
        __PYX_ERR(0, 39, __pyx_L1_error)
        __pyx_L13_unpacking_done:;
      }
      __pyx_t_13 = __pyx_PyFloat_AsFloat(__pyx_t_5); if (unlikely((__pyx_t_13 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 39, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
      __pyx_t_14 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_14 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 39, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_v_self->t_min = __pyx_t_13;
      __pyx_v_self->t_max = __pyx_t_14;

    +040:         self.steps = steps

      __pyx_t_10 = __Pyx_PyIndex_AsSsize_t(__pyx_v_steps); if (unlikely((__pyx_t_10 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 40, __pyx_L1_error)
      __pyx_v_self->steps = __pyx_t_10;

    +041:         self.resolution = (self.t_max - self.t_min) / (self.steps - 1)

      __pyx_t_14 = (__pyx_v_self->t_max - __pyx_v_self->t_min);
      __pyx_t_10 = (__pyx_v_self->steps - 1);
      if (unlikely(__pyx_t_10 == 0)) {
        PyErr_SetString(PyExc_ZeroDivisionError, "float division");
        __PYX_ERR(0, 41, __pyx_L1_error)
      }
      __pyx_v_self->resolution = (__pyx_t_14 / ((float)__pyx_t_10));

    +042:         self.lower_bound = self.t_min - self.resolution    # lower bound for skipping gradient calculation in backpropagation step

      __pyx_v_self->lower_bound = (__pyx_v_self->t_min - __pyx_v_self->resolution);

    +043:         self.lam = lam

      __pyx_t_14 = __pyx_PyFloat_AsFloat(__pyx_v_lam); if (unlikely((__pyx_t_14 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 43, __pyx_L1_error)
      __pyx_v_self->lam = __pyx_t_14;

    +044:         self.tseq = np.linspace(*interval, steps, dtype=dtype_float)

      __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_linspace); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_5);
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_t_2 = __Pyx_PySequence_Tuple(__pyx_v_interval); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_INCREF(__pyx_v_steps);
      __Pyx_GIVEREF(__pyx_v_steps);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_steps)) __PYX_ERR(0, 44, __pyx_L1_error);
      __pyx_t_8 = PyNumber_Add(__pyx_t_2, __pyx_t_3); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_8);
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_dtype_float); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_dtype, __pyx_t_2) < 0) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_8, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
      __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __pyx_t_15 = __Pyx_PyObject_to_MemoryviewSlice_ds_float(__pyx_t_2, PyBUF_WRITABLE); if (unlikely(!__pyx_t_15.memview)) __PYX_ERR(0, 44, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __PYX_XCLEAR_MEMVIEW(&__pyx_v_self->tseq, 0);
      __pyx_v_self->tseq = __pyx_t_15;
      __pyx_t_15.memview = NULL;
      __pyx_t_15.data = NULL;

     045:

     046:

     047: # T-construction

    +048:     @cython.boundscheck(False)      # turn off bounds-checking for entire function

    /* Python wrapper */
    static PyObject *__pyx_pw_11ecc_sigmoid_14SigEccBackbone_3cal_ecc_topdim(PyObject *__pyx_v_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_11ecc_sigmoid_14SigEccBackbone_2cal_ecc_topdim, "_summary_\n\n        Args:\n            x (anything convertible to a numpy.ndarray): Array of shape [B, C, H, W].\n            backprop (bint): Whether or not the input requires gradient calculation\n\n        Returns:\n            _type_: _description_\n        ");
    static PyMethodDef __pyx_mdef_11ecc_sigmoid_14SigEccBackbone_3cal_ecc_topdim = {"cal_ecc_topdim", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_11ecc_sigmoid_14SigEccBackbone_3cal_ecc_topdim, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_11ecc_sigmoid_14SigEccBackbone_2cal_ecc_topdim};
    static PyObject *__pyx_pw_11ecc_sigmoid_14SigEccBackbone_3cal_ecc_topdim(PyObject *__pyx_v_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
    ) {
      PyObject *__pyx_v_x = 0;
      int __pyx_v_backprop;
      #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("cal_ecc_topdim (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_backprop,0};
      PyObject* values[2] = {0,0};
        if (__pyx_kwds) {
          Py_ssize_t kw_args;
          switch (__pyx_nargs) {
            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, 48, __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_backprop)) != 0)) {
              (void)__Pyx_Arg_NewRef_FASTCALL(values[1]);
              kw_args--;
            }
            else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 48, __pyx_L3_error)
            else {
              __Pyx_RaiseArgtupleInvalid("cal_ecc_topdim", 1, 2, 2, 1); __PYX_ERR(0, 48, __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, "cal_ecc_topdim") < 0)) __PYX_ERR(0, 48, __pyx_L3_error)
          }
        } else if (unlikely(__pyx_nargs != 2)) {
          goto __pyx_L5_argtuple_error;
        } else {
          values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);
          values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);
        }
        __pyx_v_x = values[0];
        __pyx_v_backprop = __Pyx_PyObject_IsTrue(values[1]); if (unlikely((__pyx_v_backprop == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 52, __pyx_L3_error)
      }
      goto __pyx_L6_skip;
      __pyx_L5_argtuple_error:;
      __Pyx_RaiseArgtupleInvalid("cal_ecc_topdim", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 48, __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_AddTraceback("ecc_sigmoid.SigEccBackbone.cal_ecc_topdim", __pyx_clineno, __pyx_lineno, __pyx_filename);
      __Pyx_RefNannyFinishContext();
      return NULL;
      __pyx_L4_argument_unpacking_done:;
      __pyx_r = __pyx_pf_11ecc_sigmoid_14SigEccBackbone_2cal_ecc_topdim(((struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *)__pyx_v_self), __pyx_v_x, __pyx_v_backprop);
      int __pyx_lineno = 0;
      const char *__pyx_filename = NULL;
      int __pyx_clineno = 0;

      /* function exit code */
      {
        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_11ecc_sigmoid_14SigEccBackbone_2cal_ecc_topdim(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *__pyx_v_self, PyObject *__pyx_v_x, int __pyx_v_backprop) {
      Py_ssize_t __pyx_v_batch_size;
      Py_ssize_t __pyx_v_num_channels;
      Py_ssize_t __pyx_v_b;
      Py_ssize_t __pyx_v_c;
      Py_ssize_t __pyx_v_cell;
      Py_ssize_t __pyx_v_pix;
      Py_ssize_t __pyx_v_i;
      Py_ssize_t __pyx_v_num_neighbors;
      Py_ssize_t __pyx_v_num_min;
      float __pyx_v_filt;
      float __pyx_v_dim;
      float __pyx_v_t;
      float __pyx_v_sig;
      Py_ssize_t *__pyx_v_neighbor_sq;
      Py_ssize_t *__pyx_v_sq;
      float __pyx_v_sq_filt[4];
      PyObject *__pyx_v_h = NULL;
      PyObject *__pyx_v_w = NULL;
      PyObject *__pyx_v_ecc = NULL;
      __Pyx_memviewslice __pyx_v_ecc_view = { 0, 0, { 0 }, { 0 }, { 0 } };
      PyObject *__pyx_v_grad_local = NULL;
      __Pyx_memviewslice __pyx_v_grad_local_view = { 0, 0, { 0 }, { 0 }, { 0 } };
      __Pyx_memviewslice __pyx_v_filtration = { 0, 0, { 0 }, { 0 }, { 0 } };
      PyObject *__pyx_v_cub_cpx = NULL;
      PyObject *__pyx_r = NULL;
    /* … */
      /* function exit code */
      __pyx_L1_error:;
      __Pyx_XDECREF(__pyx_t_1);
      __Pyx_XDECREF(__pyx_t_2);
      __Pyx_XDECREF(__pyx_t_3);
      __Pyx_XDECREF(__pyx_t_4);
      __Pyx_XDECREF(__pyx_t_5);
      __Pyx_XDECREF(__pyx_t_6);
      __PYX_XCLEAR_MEMVIEW(&__pyx_t_10, 1);
      __Pyx_XDECREF(__pyx_t_11);
      __PYX_XCLEAR_MEMVIEW(&__pyx_t_12, 1);
      __PYX_XCLEAR_MEMVIEW(&__pyx_t_18, 1);
      __Pyx_AddTraceback("ecc_sigmoid.SigEccBackbone.cal_ecc_topdim", __pyx_clineno, __pyx_lineno, __pyx_filename);
      __pyx_r = NULL;
      __pyx_L0:;
      __Pyx_XDECREF(__pyx_v_h);
      __Pyx_XDECREF(__pyx_v_w);
      __Pyx_XDECREF(__pyx_v_ecc);
      __PYX_XCLEAR_MEMVIEW(&__pyx_v_ecc_view, 1);
      __Pyx_XDECREF(__pyx_v_grad_local);
      __PYX_XCLEAR_MEMVIEW(&__pyx_v_grad_local_view, 1);
      __PYX_XCLEAR_MEMVIEW(&__pyx_v_filtration, 1);
      __Pyx_XDECREF(__pyx_v_cub_cpx);
      __Pyx_XGIVEREF(__pyx_r);
      __Pyx_RefNannyFinishContext();
      return __pyx_r;
    }
    /* … */
      __pyx_tuple__25 = PyTuple_Pack(27, __pyx_n_s_self, __pyx_n_s_x, __pyx_n_s_backprop, __pyx_n_s_batch_size, __pyx_n_s_num_channels, __pyx_n_s_b, __pyx_n_s_c, __pyx_n_s_cell, __pyx_n_s_pix, __pyx_n_s_i, __pyx_n_s_num_neighbors, __pyx_n_s_num_min, __pyx_n_s_filt, __pyx_n_s_dim, __pyx_n_s_t, __pyx_n_s_sig, __pyx_n_s_neighbor_sq, __pyx_n_s_sq, __pyx_n_s_sq_filt, __pyx_n_s_h, __pyx_n_s_w, __pyx_n_s_ecc, __pyx_n_s_ecc_view, __pyx_n_s_grad_local, __pyx_n_s_grad_local_view, __pyx_n_s_filtration, __pyx_n_s_cub_cpx); if (unlikely(!__pyx_tuple__25)) __PYX_ERR(0, 48, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_tuple__25);
      __Pyx_GIVEREF(__pyx_tuple__25);
    /* … */
      __pyx_t_4 = __Pyx_CyFunction_New(&__pyx_mdef_11ecc_sigmoid_14SigEccBackbone_3cal_ecc_topdim, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_SigEccBackbone_cal_ecc_topdim, NULL, __pyx_n_s_ecc_sigmoid, __pyx_d, ((PyObject *)__pyx_codeobj__26)); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 48, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_11ecc_sigmoid_SigEccBackbone, __pyx_n_s_cal_ecc_topdim, __pyx_t_4) < 0) __PYX_ERR(0, 48, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      PyType_Modified(__pyx_ptype_11ecc_sigmoid_SigEccBackbone);
      __pyx_codeobj__26 = (PyObject*)__Pyx_PyCode_New(3, 0, 0, 27, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__25, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_ecc_sigmoid_pyx, __pyx_n_s_cal_ecc_topdim, 48, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__26)) __PYX_ERR(0, 48, __pyx_L1_error)

     049:     @cython.wraparound(False)       # turn off negative index wrapping for entire function

     050:     @cython.cdivision(True)         # turn off checking for division by zero

     051:     @cython.initializedcheck(False) # turn off initialization check

     052:     def cal_ecc_topdim(self, object x, bint backprop):

     053:         """_summary_

     054:

     055:         Args:

     056:             x (anything convertible to a numpy.ndarray): Array of shape [B, C, H, W].

     057:             backprop (bint): Whether or not the input requires gradient calculation

     058:

     059:         Returns:

     060:             _type_: _description_

     061:         """

     062:         cdef Py_ssize_t batch_size, num_channels, b, c, cell, pix, i, num_neighbors, num_min

     063:         cdef float filt, dim, t, sig

     064:         cdef Py_ssize_t *neighbor_sq

     065:         cdef Py_ssize_t *sq

     066:         cdef float[4] sq_filt

     067:

    +068:         batch_size, num_channels, h, w = x.shape

      __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_x, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 68, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      if ((likely(PyTuple_CheckExact(__pyx_t_1))) || (PyList_CheckExact(__pyx_t_1))) {
        PyObject* sequence = __pyx_t_1;
        Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
        if (unlikely(size != 4)) {
          if (size > 4) __Pyx_RaiseTooManyValuesError(4);
          else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
          __PYX_ERR(0, 68, __pyx_L1_error)
        }
        #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
        if (likely(PyTuple_CheckExact(sequence))) {
          __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0);
          __pyx_t_3 = PyTuple_GET_ITEM(sequence, 1);
          __pyx_t_4 = PyTuple_GET_ITEM(sequence, 2);
          __pyx_t_5 = PyTuple_GET_ITEM(sequence, 3);
        } else {
          __pyx_t_2 = PyList_GET_ITEM(sequence, 0);
          __pyx_t_3 = PyList_GET_ITEM(sequence, 1);
          __pyx_t_4 = PyList_GET_ITEM(sequence, 2);
          __pyx_t_5 = PyList_GET_ITEM(sequence, 3);
        }
        __Pyx_INCREF(__pyx_t_2);
        __Pyx_INCREF(__pyx_t_3);
        __Pyx_INCREF(__pyx_t_4);
        __Pyx_INCREF(__pyx_t_5);
        #else
        {
          Py_ssize_t i;
          PyObject** temps[4] = {&__pyx_t_2,&__pyx_t_3,&__pyx_t_4,&__pyx_t_5};
          for (i=0; i < 4; i++) {
            PyObject* item = PySequence_ITEM(sequence, i); if (unlikely(!item)) __PYX_ERR(0, 68, __pyx_L1_error)
            __Pyx_GOTREF(item);
            *(temps[i]) = item;
          }
        }
        #endif
        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      } else {
        Py_ssize_t index = -1;
        PyObject** temps[4] = {&__pyx_t_2,&__pyx_t_3,&__pyx_t_4,&__pyx_t_5};
        __pyx_t_6 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 68, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_6);
        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
        __pyx_t_7 = __Pyx_PyObject_GetIterNextFunc(__pyx_t_6);
        for (index=0; index < 4; index++) {
          PyObject* item = __pyx_t_7(__pyx_t_6); if (unlikely(!item)) goto __pyx_L3_unpacking_failed;
          __Pyx_GOTREF(item);
          *(temps[index]) = item;
        }
        if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 4) < 0) __PYX_ERR(0, 68, __pyx_L1_error)
        __pyx_t_7 = NULL;
        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
        goto __pyx_L4_unpacking_done;
        __pyx_L3_unpacking_failed:;
        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
        __pyx_t_7 = NULL;
        if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
        __PYX_ERR(0, 68, __pyx_L1_error)
        __pyx_L4_unpacking_done:;
      }
      __pyx_t_8 = __Pyx_PyIndex_AsSsize_t(__pyx_t_2); if (unlikely((__pyx_t_8 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_t_9 = __Pyx_PyIndex_AsSsize_t(__pyx_t_3); if (unlikely((__pyx_t_9 == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __pyx_v_batch_size = __pyx_t_8;
      __pyx_v_num_channels = __pyx_t_9;
      __pyx_v_h = __pyx_t_4;
      __pyx_t_4 = 0;
      __pyx_v_w = __pyx_t_5;
      __pyx_t_5 = 0;

     069:

    +070:         ecc = np.zeros((batch_size, num_channels, self.steps), dtype=dtype_float)

      __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_zeros); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_5);
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __pyx_t_1 = PyInt_FromSsize_t(__pyx_v_batch_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __pyx_t_4 = PyInt_FromSsize_t(__pyx_v_num_channels); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __pyx_t_3 = PyInt_FromSsize_t(__pyx_v_self->steps); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_GIVEREF(__pyx_t_1);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1)) __PYX_ERR(0, 70, __pyx_L1_error);
      __Pyx_GIVEREF(__pyx_t_4);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_4)) __PYX_ERR(0, 70, __pyx_L1_error);
      __Pyx_GIVEREF(__pyx_t_3);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_t_3)) __PYX_ERR(0, 70, __pyx_L1_error);
      __pyx_t_1 = 0;
      __pyx_t_4 = 0;
      __pyx_t_3 = 0;
      __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GIVEREF(__pyx_t_2);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2)) __PYX_ERR(0, 70, __pyx_L1_error);
      __pyx_t_2 = 0;
      __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_dtype_float); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 70, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __pyx_v_ecc = __pyx_t_4;
      __pyx_t_4 = 0;

    +071:         cdef float[:, :, :] ecc_view = ecc

      __pyx_t_10 = __Pyx_PyObject_to_MemoryviewSlice_dsdsds_float(__pyx_v_ecc, PyBUF_WRITABLE); if (unlikely(!__pyx_t_10.memview)) __PYX_ERR(0, 71, __pyx_L1_error)
      __pyx_v_ecc_view = __pyx_t_10;
      __pyx_t_10.memview = NULL;
      __pyx_t_10.data = NULL;

     072:

    +073:         grad_local = np.zeros((batch_size, num_channels, h*w, self.steps), dtype=dtype_float) if backprop else None

      if (__pyx_v_backprop) {
        __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_zeros); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_3);
        __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
        __pyx_t_2 = PyInt_FromSsize_t(__pyx_v_batch_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        __pyx_t_5 = PyInt_FromSsize_t(__pyx_v_num_channels); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_5);
        __pyx_t_1 = PyNumber_Multiply(__pyx_v_h, __pyx_v_w); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_1);
        __pyx_t_6 = PyInt_FromSsize_t(__pyx_v_self->steps); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_6);
        __pyx_t_11 = PyTuple_New(4); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_11);
        __Pyx_GIVEREF(__pyx_t_2);
        if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 0, __pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error);
        __Pyx_GIVEREF(__pyx_t_5);
        if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 1, __pyx_t_5)) __PYX_ERR(0, 73, __pyx_L1_error);
        __Pyx_GIVEREF(__pyx_t_1);
        if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 2, __pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error);
        __Pyx_GIVEREF(__pyx_t_6);
        if (__Pyx_PyTuple_SET_ITEM(__pyx_t_11, 3, __pyx_t_6)) __PYX_ERR(0, 73, __pyx_L1_error);
        __pyx_t_2 = 0;
        __pyx_t_5 = 0;
        __pyx_t_1 = 0;
        __pyx_t_6 = 0;
        __pyx_t_6 = PyTuple_New(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_6);
        __Pyx_GIVEREF(__pyx_t_11);
        if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_11)) __PYX_ERR(0, 73, __pyx_L1_error);
        __pyx_t_11 = 0;
        __pyx_t_11 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_11);
        __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_dtype_float); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_1);
        if (PyDict_SetItem(__pyx_t_11, __pyx_n_s_dtype, __pyx_t_1) < 0) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
        __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_6, __pyx_t_11); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_1);
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
        __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
        __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0;
        __pyx_t_4 = __pyx_t_1;
        __pyx_t_1 = 0;
      } else {
        __Pyx_INCREF(Py_None);
        __pyx_t_4 = Py_None;
      }
      __pyx_v_grad_local = __pyx_t_4;
      __pyx_t_4 = 0;

    +074:         cdef float[:, :, :, :] grad_local_view = grad_local

      __pyx_t_12 = __Pyx_PyObject_to_MemoryviewSlice_dsdsdsds_float(__pyx_v_grad_local, PyBUF_WRITABLE); if (unlikely(!__pyx_t_12.memview)) __PYX_ERR(0, 74, __pyx_L1_error)
      __pyx_v_grad_local_view = __pyx_t_12;
      __pyx_t_12.memview = NULL;
      __pyx_t_12.data = NULL;

     075:

     076:         cdef float[:] filtration

     077:

    +078:         for b in range(batch_size):         # iterate over batch

      __pyx_t_9 = __pyx_v_batch_size;
      __pyx_t_8 = __pyx_t_9;
      for (__pyx_t_13 = 0; __pyx_t_13 < __pyx_t_8; __pyx_t_13+=1) {
        __pyx_v_b = __pyx_t_13;

    +079:             for c in range(num_channels):   # iterate over channel

        __pyx_t_14 = __pyx_v_num_channels;
        __pyx_t_15 = __pyx_t_14;
        for (__pyx_t_16 = 0; __pyx_t_16 < __pyx_t_15; __pyx_t_16+=1) {
          __pyx_v_c = __pyx_t_16;

    +080:                 cub_cpx = gd.CubicalComplex(top_dimensional_cells=x[b, c])  # T-construction

          __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_gd); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_4);
          __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_CubicalComplex); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_1);
          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
          __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_4);
          __pyx_t_11 = PyInt_FromSsize_t(__pyx_v_b); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_11);
          __pyx_t_6 = PyInt_FromSsize_t(__pyx_v_c); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_6);
          __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_3);
          __Pyx_GIVEREF(__pyx_t_11);
          if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_11)) __PYX_ERR(0, 80, __pyx_L1_error);
          __Pyx_GIVEREF(__pyx_t_6);
          if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_6)) __PYX_ERR(0, 80, __pyx_L1_error);
          __pyx_t_11 = 0;
          __pyx_t_6 = 0;
          __pyx_t_6 = __Pyx_PyObject_GetItem(__pyx_v_x, __pyx_t_3); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_6);
          __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
          if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_top_dimensional_cells, __pyx_t_6) < 0) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
          __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_empty_tuple, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 80, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_6);
          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
          __Pyx_XDECREF_SET(__pyx_v_cub_cpx, __pyx_t_6);
          __pyx_t_6 = 0;

    +081:                 filtration = cub_cpx.all_cells().astype(dtype_float).flatten()

          __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_cub_cpx, __pyx_n_s_all_cells); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 81, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_3);
          __pyx_t_11 = NULL;
          __pyx_t_17 = 0;
          #if CYTHON_UNPACK_METHODS
          if (likely(PyMethod_Check(__pyx_t_3))) {
            __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_3);
            if (likely(__pyx_t_11)) {
              PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
              __Pyx_INCREF(__pyx_t_11);
              __Pyx_INCREF(function);
              __Pyx_DECREF_SET(__pyx_t_3, function);
              __pyx_t_17 = 1;
            }
          }
          #endif
          {
            PyObject *__pyx_callargs[2] = {__pyx_t_11, NULL};
            __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_17, 0+__pyx_t_17);
            __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
            if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_1);
            __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
          }
          __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_astype); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 81, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_3);
          __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
          __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_dtype_float); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 81, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_1);
          __pyx_t_11 = NULL;
          __pyx_t_17 = 0;
          #if CYTHON_UNPACK_METHODS
          if (likely(PyMethod_Check(__pyx_t_3))) {
            __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_3);
            if (likely(__pyx_t_11)) {
              PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
              __Pyx_INCREF(__pyx_t_11);
              __Pyx_INCREF(function);
              __Pyx_DECREF_SET(__pyx_t_3, function);
              __pyx_t_17 = 1;
            }
          }
          #endif
          {
            PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_t_1};
            __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_17, 1+__pyx_t_17);
            __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0;
            __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
            if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 81, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_4);
            __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
          }
          __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_flatten); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 81, __pyx_L1_error)
          __Pyx_GOTREF(__pyx_t_3);
          __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
          __pyx_t_4 = NULL;
          __pyx_t_17 = 0;
          #if CYTHON_UNPACK_METHODS
          if (likely(PyMethod_Check(__pyx_t_3))) {
            __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);
            if (likely(__pyx_t_4)) {
              PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
              __Pyx_INCREF(__pyx_t_4);
              __Pyx_INCREF(function);
              __Pyx_DECREF_SET(__pyx_t_3, function);
              __pyx_t_17 = 1;
            }
          }
          #endif
          {
            PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL};
            __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_17, 0+__pyx_t_17);
            __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
            if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 81, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_6);
            __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
          }
          __pyx_t_18 = __Pyx_PyObject_to_MemoryviewSlice_ds_float(__pyx_t_6, PyBUF_WRITABLE); if (unlikely(!__pyx_t_18.memview)) __PYX_ERR(0, 81, __pyx_L1_error)
          __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
          __PYX_XCLEAR_MEMVIEW(&__pyx_v_filtration, 1);
          __pyx_v_filtration = __pyx_t_18;
          __pyx_t_18.memview = NULL;
          __pyx_t_18.data = NULL;

    +082:                 for cell in range(self.num_cells): # iterate over all cells in cubical complex

          __pyx_t_19 = __pyx_v_self->num_cells;
          __pyx_t_20 = __pyx_t_19;
          for (__pyx_t_21 = 0; __pyx_t_21 < __pyx_t_20; __pyx_t_21+=1) {
            __pyx_v_cell = __pyx_t_21;

    +083:                     filt = filtration[cell]

            __pyx_t_22 = __pyx_v_cell;
            __pyx_v_filt = (*((float *) ( /* dim=0 */ (__pyx_v_filtration.data + __pyx_t_22 * __pyx_v_filtration.strides[0]) )));

    +084:                     if filt > self.t_max:

            __pyx_t_23 = (__pyx_v_filt > __pyx_v_self->t_max);
            if (__pyx_t_23) {
    /* … */
            }

    +085:                         continue

              goto __pyx_L9_continue;

    +086:                     dim = self.dimension[cell]

            __pyx_t_22 = __pyx_v_cell;
            __pyx_v_dim = (*((float const  *) ( /* dim=0 */ (__pyx_v_self->dimension.data + __pyx_t_22 * __pyx_v_self->dimension.strides[0]) )));

     087:

    +088:                     for i in range(self.steps):

            __pyx_t_24 = __pyx_v_self->steps;
            __pyx_t_25 = __pyx_t_24;
            for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
              __pyx_v_i = __pyx_t_26;

    +089:                         t = self.tseq[i]

              __pyx_t_22 = __pyx_v_i;
              __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_22 * __pyx_v_self->tseq.strides[0]) )));

    +090:                         sig = (-1.)**dim

              __pyx_v_sig = pow(-1., ((double)__pyx_v_dim));

    +091:                         ecc_view[b, c, i] += sig * (sigmoid(t-filt, self.lam))

              __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 91, __pyx_L1_error)
              __pyx_t_22 = __pyx_v_b;
              __pyx_t_28 = __pyx_v_c;
              __pyx_t_29 = __pyx_v_i;
              *((float *) ( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_ecc_view.data + __pyx_t_22 * __pyx_v_ecc_view.strides[0]) ) + __pyx_t_28 * __pyx_v_ecc_view.strides[1]) ) + __pyx_t_29 * __pyx_v_ecc_view.strides[2]) )) += (__pyx_v_sig * __pyx_t_27);
            }

     092:

     093:                     # calculation of gradient only for inputs that require gradient

    +094:                     if backprop:

            if (__pyx_v_backprop) {
    /* … */
            }
            __pyx_L9_continue:;
          }
        }
      }

    +095:                         if filt < self.lower_bound:                         # skip bc. gradient is 0 for simplices with filtration value under lower bound

              __pyx_t_23 = (__pyx_v_filt < __pyx_v_self->lower_bound);
              if (__pyx_t_23) {
    /* … */
              }

    +096:                             continue

                goto __pyx_L9_continue;

     097:                         # square

    +098:                         if dim == 2:

              __pyx_t_23 = (__pyx_v_dim == 2.0);
              if (__pyx_t_23) {
    /* … */
                goto __pyx_L16;
              }

    +099:                             pix = self._sq2pix(cell)                        # index of the corresponding pixel in flattened original image

                __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, __pyx_v_cell); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 99, __pyx_L1_error)
                __pyx_v_pix = __pyx_t_24;

    +100:                             for i in range(self.steps):

                __pyx_t_24 = __pyx_v_self->steps;
                __pyx_t_25 = __pyx_t_24;
                for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                  __pyx_v_i = __pyx_t_26;

    +101:                                 t = self.tseq[i]

                  __pyx_t_29 = __pyx_v_i;
                  __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_29 * __pyx_v_self->tseq.strides[0]) )));

    +102:                                 grad_local_view[b, c, pix, i] -= self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                  __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 102, __pyx_L1_error)
                  __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 102, __pyx_L1_error)
                  __pyx_t_29 = __pyx_v_b;
                  __pyx_t_28 = __pyx_v_c;
                  __pyx_t_22 = __pyx_v_pix;
                  __pyx_t_31 = __pyx_v_i;
                  *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_29 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_31 * __pyx_v_grad_local_view.strides[3]) )) -= ((__pyx_v_self->lam * __pyx_t_27) * (1.0 - __pyx_t_30));
                }

     103:

     104:                         # edge

    +105:                         elif dim == 1:

              __pyx_t_23 = (__pyx_v_dim == 1.0);
              if (__pyx_t_23) {
    /* … */
                goto __pyx_L16;
              }

    +106:                             neighbor_sq = self._find_neighbor_sq(cell, dim, &num_neighbors) # neighbor_sq points at a C array containing index of neighbor squares

                __pyx_t_32 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__find_neighbor_sq(__pyx_v_self, __pyx_v_cell, __pyx_v_dim, (&__pyx_v_num_neighbors)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 106, __pyx_L1_error)
                __pyx_v_neighbor_sq = __pyx_t_32;

    +107:                             if num_neighbors == 1:                          # there is 1 neighbor square

                __pyx_t_23 = (__pyx_v_num_neighbors == 1);
                if (__pyx_t_23) {
    /* … */
                  goto __pyx_L19;
                }

    +108:                                 pix = self._sq2pix(neighbor_sq[0])

                  __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[0])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 108, __pyx_L1_error)
                  __pyx_v_pix = __pyx_t_24;

    +109:                                 for i in range(self.steps):

                  __pyx_t_24 = __pyx_v_self->steps;
                  __pyx_t_25 = __pyx_t_24;
                  for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                    __pyx_v_i = __pyx_t_26;

    +110:                                     t = self.tseq[i]

                    __pyx_t_31 = __pyx_v_i;
                    __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_31 * __pyx_v_self->tseq.strides[0]) )));

    +111:                                     grad_local_view[b, c, pix, i] += self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                    __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 111, __pyx_L1_error)
                    __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 111, __pyx_L1_error)
                    __pyx_t_31 = __pyx_v_b;
                    __pyx_t_22 = __pyx_v_c;
                    __pyx_t_28 = __pyx_v_pix;
                    __pyx_t_29 = __pyx_v_i;
                    *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_31 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_29 * __pyx_v_grad_local_view.strides[3]) )) += ((__pyx_v_self->lam * __pyx_t_30) * (1.0 - __pyx_t_27));
                  }

     112:                             else:                                           # there are 2 neighbor squares

    +113:                                 for i in range(2):

                /*else*/ {
                  for (__pyx_t_24 = 0; __pyx_t_24 < 2; __pyx_t_24+=1) {
                    __pyx_v_i = __pyx_t_24;

    +114:                                     sq_filt[i] = filtration[neighbor_sq[i]] # filtration value of neighbor squares

                    __pyx_t_29 = (__pyx_v_neighbor_sq[__pyx_v_i]);
                    (__pyx_v_sq_filt[__pyx_v_i]) = (*((float *) ( /* dim=0 */ (__pyx_v_filtration.data + __pyx_t_29 * __pyx_v_filtration.strides[0]) )));
                  }

     115:

    +116:                                 if sq_filt[0] > sq_filt[1]:

                  __pyx_t_23 = ((__pyx_v_sq_filt[0]) > (__pyx_v_sq_filt[1]));
                  if (__pyx_t_23) {
    /* … */
                    goto __pyx_L24;
                  }

    +117:                                     pix = self._sq2pix(neighbor_sq[1])

                    __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[1])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 117, __pyx_L1_error)
                    __pyx_v_pix = __pyx_t_24;

    +118:                                     for i in range(self.steps):

                    __pyx_t_24 = __pyx_v_self->steps;
                    __pyx_t_25 = __pyx_t_24;
                    for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                      __pyx_v_i = __pyx_t_26;

    +119:                                         t = self.tseq[i]

                      __pyx_t_29 = __pyx_v_i;
                      __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_29 * __pyx_v_self->tseq.strides[0]) )));

    +120:                                         grad_local_view[b, c, pix, i] += self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                      __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 120, __pyx_L1_error)
                      __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 120, __pyx_L1_error)
                      __pyx_t_29 = __pyx_v_b;
                      __pyx_t_28 = __pyx_v_c;
                      __pyx_t_22 = __pyx_v_pix;
                      __pyx_t_31 = __pyx_v_i;
                      *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_29 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_31 * __pyx_v_grad_local_view.strides[3]) )) += ((__pyx_v_self->lam * __pyx_t_27) * (1.0 - __pyx_t_30));
                    }

    +121:                                 elif sq_filt[0] < sq_filt[1]:

                  __pyx_t_23 = ((__pyx_v_sq_filt[0]) < (__pyx_v_sq_filt[1]));
                  if (__pyx_t_23) {
    /* … */
                    goto __pyx_L24;
                  }

    +122:                                     pix = self._sq2pix(neighbor_sq[0])

                    __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[0])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 122, __pyx_L1_error)
                    __pyx_v_pix = __pyx_t_24;

    +123:                                     for i in range(self.steps):

                    __pyx_t_24 = __pyx_v_self->steps;
                    __pyx_t_25 = __pyx_t_24;
                    for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                      __pyx_v_i = __pyx_t_26;

    +124:                                         t = self.tseq[i]

                      __pyx_t_31 = __pyx_v_i;
                      __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_31 * __pyx_v_self->tseq.strides[0]) )));

    +125:                                         grad_local_view[b, c, pix, i] += self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                      __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 125, __pyx_L1_error)
                      __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 125, __pyx_L1_error)
                      __pyx_t_31 = __pyx_v_b;
                      __pyx_t_22 = __pyx_v_c;
                      __pyx_t_28 = __pyx_v_pix;
                      __pyx_t_29 = __pyx_v_i;
                      *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_31 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_29 * __pyx_v_grad_local_view.strides[3]) )) += ((__pyx_v_self->lam * __pyx_t_30) * (1.0 - __pyx_t_27));
                    }

     126:                                 else:                                       # split gradient when the neighboring squares have the same filtration value

    +127:                                     for i in range(2):

                  /*else*/ {
                    for (__pyx_t_24 = 0; __pyx_t_24 < 2; __pyx_t_24+=1) {
                      __pyx_v_i = __pyx_t_24;

    +128:                                         pix = self._sq2pix(neighbor_sq[i])

                      __pyx_t_25 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[__pyx_v_i])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 128, __pyx_L1_error)
                      __pyx_v_pix = __pyx_t_25;

    +129:                                         for i in range(self.steps):

                      __pyx_t_25 = __pyx_v_self->steps;
                      __pyx_t_26 = __pyx_t_25;
                      for (__pyx_t_33 = 0; __pyx_t_33 < __pyx_t_26; __pyx_t_33+=1) {
                        __pyx_v_i = __pyx_t_33;

    +130:                                             t = self.tseq[i]

                        __pyx_t_29 = __pyx_v_i;
                        __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_29 * __pyx_v_self->tseq.strides[0]) )));

    +131:                                             grad_local_view[b, c, pix, i] += 0.5 * self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                        __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 131, __pyx_L1_error)
                        __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 131, __pyx_L1_error)
                        __pyx_t_29 = __pyx_v_b;
                        __pyx_t_28 = __pyx_v_c;
                        __pyx_t_22 = __pyx_v_pix;
                        __pyx_t_31 = __pyx_v_i;
                        *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_29 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_31 * __pyx_v_grad_local_view.strides[3]) )) += (((0.5 * __pyx_v_self->lam) * __pyx_t_27) * (1.0 - __pyx_t_30));
                      }
                    }
                  }
                  __pyx_L24:;
                }
                __pyx_L19:;

    +132:                             free(neighbor_sq)

                free(__pyx_v_neighbor_sq);

     133:                         # vertex

     134:                         else:

    +135:                             neighbor_sq = self._find_neighbor_sq(cell, dim, &num_neighbors) # neighbor_sq points at a C array containing index of neighbor squares

              /*else*/ {
                __pyx_t_32 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__find_neighbor_sq(__pyx_v_self, __pyx_v_cell, __pyx_v_dim, (&__pyx_v_num_neighbors)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L1_error)
                __pyx_v_neighbor_sq = __pyx_t_32;

    +136:                             if num_neighbors == 1:                          # there is 1 neighbor square

                switch (__pyx_v_num_neighbors) {
                  case 1:
    /* … */
                  break;
                  case 2:

    +137:                                 pix = self._sq2pix(neighbor_sq[0])

                  __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[0])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 137, __pyx_L1_error)
                  __pyx_v_pix = __pyx_t_24;

    +138:                                 for i in range(self.steps):

                  __pyx_t_24 = __pyx_v_self->steps;
                  __pyx_t_25 = __pyx_t_24;
                  for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                    __pyx_v_i = __pyx_t_26;

    +139:                                     t = self.tseq[i]

                    __pyx_t_31 = __pyx_v_i;
                    __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_31 * __pyx_v_self->tseq.strides[0]) )));

    +140:                                     grad_local_view[b, c, pix, i] -= self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                    __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 140, __pyx_L1_error)
                    __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 140, __pyx_L1_error)
                    __pyx_t_31 = __pyx_v_b;
                    __pyx_t_22 = __pyx_v_c;
                    __pyx_t_28 = __pyx_v_pix;
                    __pyx_t_29 = __pyx_v_i;
                    *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_31 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_29 * __pyx_v_grad_local_view.strides[3]) )) -= ((__pyx_v_self->lam * __pyx_t_30) * (1.0 - __pyx_t_27));
                  }

    +141:                             elif num_neighbors == 2:                        # there are 2 neighbor squares

                  break;
                  default:

    +142:                                 for i in range(2):

                  for (__pyx_t_24 = 0; __pyx_t_24 < 2; __pyx_t_24+=1) {
                    __pyx_v_i = __pyx_t_24;

    +143:                                     sq_filt[i] = filtration[neighbor_sq[i]] # filtration value of neighbor squares

                    __pyx_t_29 = (__pyx_v_neighbor_sq[__pyx_v_i]);
                    (__pyx_v_sq_filt[__pyx_v_i]) = (*((float *) ( /* dim=0 */ (__pyx_v_filtration.data + __pyx_t_29 * __pyx_v_filtration.strides[0]) )));
                  }

     144:

    +145:                                 if sq_filt[0] > sq_filt[1]:

                  __pyx_t_23 = ((__pyx_v_sq_filt[0]) > (__pyx_v_sq_filt[1]));
                  if (__pyx_t_23) {
    /* … */
                    goto __pyx_L37;
                  }

    +146:                                     pix = self._sq2pix(neighbor_sq[1])

                    __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[1])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 146, __pyx_L1_error)
                    __pyx_v_pix = __pyx_t_24;

    +147:                                     for i in range(self.steps):

                    __pyx_t_24 = __pyx_v_self->steps;
                    __pyx_t_25 = __pyx_t_24;
                    for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                      __pyx_v_i = __pyx_t_26;

    +148:                                         t = self.tseq[i]

                      __pyx_t_29 = __pyx_v_i;
                      __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_29 * __pyx_v_self->tseq.strides[0]) )));

    +149:                                         grad_local_view[b, c, pix, i] -= self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                      __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 149, __pyx_L1_error)
                      __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 149, __pyx_L1_error)
                      __pyx_t_29 = __pyx_v_b;
                      __pyx_t_28 = __pyx_v_c;
                      __pyx_t_22 = __pyx_v_pix;
                      __pyx_t_31 = __pyx_v_i;
                      *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_29 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_31 * __pyx_v_grad_local_view.strides[3]) )) -= ((__pyx_v_self->lam * __pyx_t_27) * (1.0 - __pyx_t_30));
                    }

    +150:                                 elif sq_filt[0] < sq_filt[1]:

                  __pyx_t_23 = ((__pyx_v_sq_filt[0]) < (__pyx_v_sq_filt[1]));
                  if (__pyx_t_23) {
    /* … */
                    goto __pyx_L37;
                  }

    +151:                                     pix = self._sq2pix(neighbor_sq[0])

                    __pyx_t_24 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[0])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 151, __pyx_L1_error)
                    __pyx_v_pix = __pyx_t_24;

    +152:                                     for i in range(self.steps):

                    __pyx_t_24 = __pyx_v_self->steps;
                    __pyx_t_25 = __pyx_t_24;
                    for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                      __pyx_v_i = __pyx_t_26;

    +153:                                         t = self.tseq[i]

                      __pyx_t_31 = __pyx_v_i;
                      __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_31 * __pyx_v_self->tseq.strides[0]) )));

    +154:                                         grad_local_view[b, c, pix, i] -= self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                      __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 154, __pyx_L1_error)
                      __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 154, __pyx_L1_error)
                      __pyx_t_31 = __pyx_v_b;
                      __pyx_t_22 = __pyx_v_c;
                      __pyx_t_28 = __pyx_v_pix;
                      __pyx_t_29 = __pyx_v_i;
                      *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_31 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_29 * __pyx_v_grad_local_view.strides[3]) )) -= ((__pyx_v_self->lam * __pyx_t_30) * (1.0 - __pyx_t_27));
                    }

     155:                                 else:                                       # split gradient when the neighboring squares have the same filtration value

    +156:                                     for i in range(2):

                  /*else*/ {
                    for (__pyx_t_24 = 0; __pyx_t_24 < 2; __pyx_t_24+=1) {
                      __pyx_v_i = __pyx_t_24;

    +157:                                         pix = self._sq2pix(neighbor_sq[i])

                      __pyx_t_25 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_neighbor_sq[__pyx_v_i])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 157, __pyx_L1_error)
                      __pyx_v_pix = __pyx_t_25;

    +158:                                         for i in range(self.steps):

                      __pyx_t_25 = __pyx_v_self->steps;
                      __pyx_t_26 = __pyx_t_25;
                      for (__pyx_t_33 = 0; __pyx_t_33 < __pyx_t_26; __pyx_t_33+=1) {
                        __pyx_v_i = __pyx_t_33;

    +159:                                             t = self.tseq[i]

                        __pyx_t_29 = __pyx_v_i;
                        __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_29 * __pyx_v_self->tseq.strides[0]) )));

    +160:                                             grad_local_view[b, c, pix, i] -= 0.5 * self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                        __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 160, __pyx_L1_error)
                        __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 160, __pyx_L1_error)
                        __pyx_t_29 = __pyx_v_b;
                        __pyx_t_28 = __pyx_v_c;
                        __pyx_t_22 = __pyx_v_pix;
                        __pyx_t_31 = __pyx_v_i;
                        *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_29 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_31 * __pyx_v_grad_local_view.strides[3]) )) -= (((0.5 * __pyx_v_self->lam) * __pyx_t_27) * (1.0 - __pyx_t_30));
                      }
                    }
                  }
                  __pyx_L37:;

     161:                             else:                                           # there are 4 neighbor squares

    +162:                                 for i in range(4):

                  for (__pyx_t_24 = 0; __pyx_t_24 < 4; __pyx_t_24+=1) {
                    __pyx_v_i = __pyx_t_24;

    +163:                                     sq_filt[i] = filtration[neighbor_sq[i]] # filtration value of neighbor squares

                    __pyx_t_31 = (__pyx_v_neighbor_sq[__pyx_v_i]);
                    (__pyx_v_sq_filt[__pyx_v_i]) = (*((float *) ( /* dim=0 */ (__pyx_v_filtration.data + __pyx_t_31 * __pyx_v_filtration.strides[0]) )));
                  }

     164:

    +165:                                 sq = self._find_min_sq(sq_filt, neighbor_sq, 4, &num_min)

                  __pyx_t_32 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__find_min_sq(__pyx_v_self, __pyx_v_sq_filt, __pyx_v_neighbor_sq, 4, (&__pyx_v_num_min)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 165, __pyx_L1_error)
                  __pyx_v_sq = __pyx_t_32;

    +166:                                 for i in range(num_min):

                  __pyx_t_24 = __pyx_v_num_min;
                  __pyx_t_25 = __pyx_t_24;
                  for (__pyx_t_26 = 0; __pyx_t_26 < __pyx_t_25; __pyx_t_26+=1) {
                    __pyx_v_i = __pyx_t_26;

    +167:                                     pix = self._sq2pix(sq[i])

                    __pyx_t_33 = __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(__pyx_v_self, (__pyx_v_sq[__pyx_v_i])); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 167, __pyx_L1_error)
                    __pyx_v_pix = __pyx_t_33;

    +168:                                     for i in range(self.steps):

                    __pyx_t_33 = __pyx_v_self->steps;
                    __pyx_t_34 = __pyx_t_33;
                    for (__pyx_t_35 = 0; __pyx_t_35 < __pyx_t_34; __pyx_t_35+=1) {
                      __pyx_v_i = __pyx_t_35;

    +169:                                         t = self.tseq[i]

                      __pyx_t_31 = __pyx_v_i;
                      __pyx_v_t = (*((float *) ( /* dim=0 */ (__pyx_v_self->tseq.data + __pyx_t_31 * __pyx_v_self->tseq.strides[0]) )));

    +170:                                         grad_local_view[b, c, pix, i] -= 1./num_min * self.lam * sigmoid(t-filt, self.lam) * (1 - sigmoid(t-filt, self.lam))

                      __pyx_t_30 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_30 == ((float)-1.0))) __PYX_ERR(0, 170, __pyx_L1_error)
                      __pyx_t_27 = __pyx_f_11ecc_sigmoid_sigmoid((__pyx_v_t - __pyx_v_filt), __pyx_v_self->lam); if (unlikely(__pyx_t_27 == ((float)-1.0))) __PYX_ERR(0, 170, __pyx_L1_error)
                      __pyx_t_31 = __pyx_v_b;
                      __pyx_t_22 = __pyx_v_c;
                      __pyx_t_28 = __pyx_v_pix;
                      __pyx_t_29 = __pyx_v_i;
                      *((float *) ( /* dim=3 */ (( /* dim=2 */ (( /* dim=1 */ (( /* dim=0 */ (__pyx_v_grad_local_view.data + __pyx_t_31 * __pyx_v_grad_local_view.strides[0]) ) + __pyx_t_22 * __pyx_v_grad_local_view.strides[1]) ) + __pyx_t_28 * __pyx_v_grad_local_view.strides[2]) ) + __pyx_t_29 * __pyx_v_grad_local_view.strides[3]) )) -= ((((1. / ((double)__pyx_v_num_min)) * __pyx_v_self->lam) * __pyx_t_30) * (1.0 - __pyx_t_27));
                    }
                  }

    +171:                                 free(sq)

                  free(__pyx_v_sq);
                  break;
                }

    +172:                             free(neighbor_sq)

                free(__pyx_v_neighbor_sq);
              }
              __pyx_L16:;

     173:                 # cumsum

     174:                 # for i in range(self.steps - 1):

     175:                 #     ecc_view[b, c, i+1] += ecc_view[b, c, i]

    +176:         return ecc, grad_local

      __Pyx_XDECREF(__pyx_r);
      __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 176, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_6);
      __Pyx_INCREF(__pyx_v_ecc);
      __Pyx_GIVEREF(__pyx_v_ecc);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_v_ecc)) __PYX_ERR(0, 176, __pyx_L1_error);
      __Pyx_INCREF(__pyx_v_grad_local);
      __Pyx_GIVEREF(__pyx_v_grad_local);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_v_grad_local)) __PYX_ERR(0, 176, __pyx_L1_error);
      __pyx_r = __pyx_t_6;
      __pyx_t_6 = 0;
      goto __pyx_L0;

     177:

     178:     @cython.cdivision(True)     # turn off checking for division by zero

    +179:     cdef inline Py_ssize_t _sq2pix(self, Py_ssize_t sq):

    static CYTHON_INLINE Py_ssize_t __pyx_f_11ecc_sigmoid_14SigEccBackbone__sq2pix(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *__pyx_v_self, Py_ssize_t __pyx_v_sq) {
      Py_ssize_t __pyx_r;
    /* … */
      /* function exit code */
      __pyx_L0:;
      return __pyx_r;
    }

     180:         """Given the index of a square, this function returns the index of the corresponding pixel.

     181:         Used for T-constructed cubical complexes.

     182:

     183:         Args:

     184:             vtx (Py_ssize_t): Index of square.

     185:

     186:         Returns:

     187:             Py_ssize_t: Index of corresponding pixel.

     188:         """

    +189:         return (sq // (2*self.grid_w))*self.w + (sq % self.grid_w)/2

      __pyx_r = (((__pyx_v_sq / (2 * __pyx_v_self->grid_w)) * __pyx_v_self->w) + ((__pyx_v_sq % __pyx_v_self->grid_w) / 2));
      goto __pyx_L0;

     190:

     191:     @cython.cdivision(True)     # turn off checking for division by zero

    +192:     cdef inline Py_ssize_t* _find_neighbor_sq(self, Py_ssize_t cell, float dim, Py_ssize_t* num_neighbors):

    static CYTHON_INLINE Py_ssize_t *__pyx_f_11ecc_sigmoid_14SigEccBackbone__find_neighbor_sq(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *__pyx_v_self, Py_ssize_t __pyx_v_cell, float __pyx_v_dim, Py_ssize_t *__pyx_v_num_neighbors) {
      Py_ssize_t __pyx_v_row_num;
      Py_ssize_t *__pyx_v_neighbor_sq;
      Py_ssize_t __pyx_v_col_num;
      Py_ssize_t *__pyx_r;
    /* … */
      /* function exit code */
      __pyx_L0:;
      return __pyx_r;
    }

     193:         """Returns the indices of a cell's neighboring squares.

     194:         Used for T-constructed cubical complexes.

     195:         Do not use for cells that are already squares.

     196:

     197:         Args:

     198:             cell (Py_ssize_t): Index of cell.

     199:             dim (float): Dimension of cell.

     200:             num_neighors(Py_ssize_t pointer): Number of neighboring squares of cell.

     201:

     202:         Returns:

     203:             Py_ssize_t pointer: C array containing index of neighboring squares.

     204:         """

     205:         cdef Py_ssize_t row_num

    +206:         cdef Py_ssize_t *neighbor_sq = <Py_ssize_t *> malloc(<Py_ssize_t>(dim -2) * -2 * sizeof(Py_ssize_t))    # assign size 2 array for edges and size 4 array for vertices

      __pyx_v_neighbor_sq = ((Py_ssize_t *)malloc(((((Py_ssize_t)(__pyx_v_dim - 2.0)) * -2L) * (sizeof(Py_ssize_t)))));

     207:         # edge

    +208:         if dim == 1:

      __pyx_t_1 = (__pyx_v_dim == 1.0);
      if (__pyx_t_1) {
    /* … */
        goto __pyx_L3;
      }

    +209:             row_num = cell // self.grid_w

        __pyx_v_row_num = (__pyx_v_cell / __pyx_v_self->grid_w);

     210:             # even row

    +211:             if row_num % 2 == 0:

        __pyx_t_1 = ((__pyx_v_row_num % 2) == 0);
        if (__pyx_t_1) {
    /* … */
          goto __pyx_L4;
        }

    +212:                 if row_num == 0:                        # top row

          __pyx_t_1 = (__pyx_v_row_num == 0);
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L5;
          }

    +213:                     neighbor_sq[0] = cell + self.grid_w

            (__pyx_v_neighbor_sq[0]) = (__pyx_v_cell + __pyx_v_self->grid_w);

    +214:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

    +215:                 elif row_num == self.grid_h - 1:        # bottom row

          __pyx_t_1 = (__pyx_v_row_num == (__pyx_v_self->grid_h - 1));
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L5;
          }

    +216:                     neighbor_sq[0] = cell - self.grid_w

            (__pyx_v_neighbor_sq[0]) = (__pyx_v_cell - __pyx_v_self->grid_w);

    +217:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

     218:                 else:

    +219:                     neighbor_sq[:] = [cell-self.grid_w, cell+self.grid_w]

          /*else*/ {
            __pyx_t_2[0] = (__pyx_v_cell - __pyx_v_self->grid_w);
            __pyx_t_2[1] = (__pyx_v_cell + __pyx_v_self->grid_w);
            memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_2, sizeof(__pyx_v_neighbor_sq[0]) * (2));

    +220:                     num_neighbors[0] = 2

            (__pyx_v_num_neighbors[0]) = 2;
          }
          __pyx_L5:;

     221:             # odd row

     222:             else:

    +223:                 col_num = cell % self.grid_w

        /*else*/ {
          __pyx_v_col_num = (__pyx_v_cell % __pyx_v_self->grid_w);

    +224:                 if col_num == 0:                        # left-most column

          __pyx_t_1 = (__pyx_v_col_num == 0);
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L6;
          }

    +225:                     neighbor_sq[0] = cell + 1

            (__pyx_v_neighbor_sq[0]) = (__pyx_v_cell + 1);

    +226:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

    +227:                 elif col_num == self.grid_w - 1:        # right-most column

          __pyx_t_1 = (__pyx_v_col_num == (__pyx_v_self->grid_w - 1));
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L6;
          }

    +228:                     neighbor_sq[0] = cell - 1

            (__pyx_v_neighbor_sq[0]) = (__pyx_v_cell - 1);

    +229:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

     230:                 else:

    +231:                     neighbor_sq[:] = [cell-1, cell+1]

          /*else*/ {
            __pyx_t_3[0] = (__pyx_v_cell - 1);
            __pyx_t_3[1] = (__pyx_v_cell + 1);
            memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_3, sizeof(__pyx_v_neighbor_sq[0]) * (2));

    +232:                     num_neighbors[0] = 2

            (__pyx_v_num_neighbors[0]) = 2;
          }
          __pyx_L6:;
        }
        __pyx_L4:;

     233:         # vertex

     234:         else:

    +235:             row_num = cell // self.grid_w

      /*else*/ {
        __pyx_v_row_num = (__pyx_v_cell / __pyx_v_self->grid_w);

    +236:             col_num = cell % self.grid_w

        __pyx_v_col_num = (__pyx_v_cell % __pyx_v_self->grid_w);

     237:             # top row

    +238:             if row_num == 0:

        __pyx_t_1 = (__pyx_v_row_num == 0);
        if (__pyx_t_1) {
    /* … */
          goto __pyx_L7;
        }

    +239:                 if cell == 0:                              # top left corner

          __pyx_t_1 = (__pyx_v_cell == 0);
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L8;
          }

    +240:                     neighbor_sq[0] = cell + self.grid_w + 1

            (__pyx_v_neighbor_sq[0]) = ((__pyx_v_cell + __pyx_v_self->grid_w) + 1);

    +241:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

    +242:                 elif cell == self.grid_w - 1:              # top right corner

          __pyx_t_1 = (__pyx_v_cell == (__pyx_v_self->grid_w - 1));
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L8;
          }

    +243:                     neighbor_sq[0] = cell + self.grid_w - 1

            (__pyx_v_neighbor_sq[0]) = ((__pyx_v_cell + __pyx_v_self->grid_w) - 1);

    +244:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

     245:                 else:

    +246:                     neighbor_sq[:2] = [cell+self.grid_w-1, cell+self.grid_w+1]

          /*else*/ {
            __pyx_t_4[0] = ((__pyx_v_cell + __pyx_v_self->grid_w) - 1);
            __pyx_t_4[1] = ((__pyx_v_cell + __pyx_v_self->grid_w) + 1);
            memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_4, sizeof(__pyx_v_neighbor_sq[0]) * (2));

    +247:                     num_neighbors[0] = 2

            (__pyx_v_num_neighbors[0]) = 2;
          }
          __pyx_L8:;

     248:             # bottom row

    +249:             elif row_num == self.grid_h - 1:

        __pyx_t_1 = (__pyx_v_row_num == (__pyx_v_self->grid_h - 1));
        if (__pyx_t_1) {
    /* … */
          goto __pyx_L7;
        }

    +250:                 if cell == self.grid_w * (self.grid_h-1):  # bottom left corner

          __pyx_t_1 = (__pyx_v_cell == (__pyx_v_self->grid_w * (__pyx_v_self->grid_h - 1)));
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L9;
          }

    +251:                     neighbor_sq[0] = cell - self.grid_w + 1

            (__pyx_v_neighbor_sq[0]) = ((__pyx_v_cell - __pyx_v_self->grid_w) + 1);

    +252:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

    +253:                 elif cell == self.grid_w*self.grid_h - 1:  # bottom right corner

          __pyx_t_1 = (__pyx_v_cell == ((__pyx_v_self->grid_w * __pyx_v_self->grid_h) - 1));
          if (__pyx_t_1) {
    /* … */
            goto __pyx_L9;
          }

    +254:                     neighbor_sq[0] = cell - self.grid_w - 1

            (__pyx_v_neighbor_sq[0]) = ((__pyx_v_cell - __pyx_v_self->grid_w) - 1);

    +255:                     num_neighbors[0] = 1

            (__pyx_v_num_neighbors[0]) = 1;

     256:                 else:

    +257:                     neighbor_sq[:2] = [cell-self.grid_w-1, cell-self.grid_w+1]

          /*else*/ {
            __pyx_t_5[0] = ((__pyx_v_cell - __pyx_v_self->grid_w) - 1);
            __pyx_t_5[1] = ((__pyx_v_cell - __pyx_v_self->grid_w) + 1);
            memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_5, sizeof(__pyx_v_neighbor_sq[0]) * (2));

    +258:                     num_neighbors[0] = 2

            (__pyx_v_num_neighbors[0]) = 2;
          }
          __pyx_L9:;

     259:             # left-most column

    +260:             elif col_num == 0:

        __pyx_t_1 = (__pyx_v_col_num == 0);
        if (__pyx_t_1) {
    /* … */
          goto __pyx_L7;
        }

    +261:                 neighbor_sq[:2] = [cell+1-self.grid_w, cell+1+self.grid_w]

          __pyx_t_6[0] = ((__pyx_v_cell + 1) - __pyx_v_self->grid_w);
          __pyx_t_6[1] = ((__pyx_v_cell + 1) + __pyx_v_self->grid_w);
          memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_6, sizeof(__pyx_v_neighbor_sq[0]) * (2));

    +262:                 num_neighbors[0] = 2

          (__pyx_v_num_neighbors[0]) = 2;

     263:             # right-most column

    +264:             elif col_num == self.grid_w - 1:

        __pyx_t_1 = (__pyx_v_col_num == (__pyx_v_self->grid_w - 1));
        if (__pyx_t_1) {
    /* … */
          goto __pyx_L7;
        }

    +265:                 neighbor_sq[:2] = [cell-1-self.grid_w, cell-1+self.grid_w]

          __pyx_t_7[0] = ((__pyx_v_cell - 1) - __pyx_v_self->grid_w);
          __pyx_t_7[1] = ((__pyx_v_cell - 1) + __pyx_v_self->grid_w);
          memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_7, sizeof(__pyx_v_neighbor_sq[0]) * (2));

    +266:                 num_neighbors[0] = 2

          (__pyx_v_num_neighbors[0]) = 2;

     267:             else:

    +268:                 neighbor_sq[:] = [cell-self.grid_w-1, cell-self.grid_w+1, cell+self.grid_w-1, cell+self.grid_w+1]

        /*else*/ {
          __pyx_t_8[0] = ((__pyx_v_cell - __pyx_v_self->grid_w) - 1);
          __pyx_t_8[1] = ((__pyx_v_cell - __pyx_v_self->grid_w) + 1);
          __pyx_t_8[2] = ((__pyx_v_cell + __pyx_v_self->grid_w) - 1);
          __pyx_t_8[3] = ((__pyx_v_cell + __pyx_v_self->grid_w) + 1);
          memcpy(&(__pyx_v_neighbor_sq[0]), __pyx_t_8, sizeof(__pyx_v_neighbor_sq[0]) * (4));

    +269:                 num_neighbors[0] = 4

          (__pyx_v_num_neighbors[0]) = 4;
        }
        __pyx_L7:;
      }
      __pyx_L3:;

    +270:         return neighbor_sq

      __pyx_r = __pyx_v_neighbor_sq;
      goto __pyx_L0;

     271:

    +272:     cdef inline Py_ssize_t* _find_min_sq(self, float *sq_filt, Py_ssize_t *neighbor_sq, Py_ssize_t arr_size, Py_ssize_t *num_min):

    static CYTHON_INLINE Py_ssize_t *__pyx_f_11ecc_sigmoid_14SigEccBackbone__find_min_sq(CYTHON_UNUSED struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *__pyx_v_self, float *__pyx_v_sq_filt, Py_ssize_t *__pyx_v_neighbor_sq, Py_ssize_t __pyx_v_arr_size, Py_ssize_t *__pyx_v_num_min) {
      float __pyx_v_min_val;
      Py_ssize_t __pyx_v_j;
      Py_ssize_t __pyx_v_count;
      Py_ssize_t __pyx_v_i;
      Py_ssize_t *__pyx_v_sq;
      Py_ssize_t *__pyx_r;
    /* … */
      /* function exit code */
      __pyx_L0:;
      return __pyx_r;
    }

     273:         """

     274:

     275:         """

    +276:         cdef float min_val = sq_filt[0]

      __pyx_v_min_val = (__pyx_v_sq_filt[0]);

    +277:         cdef Py_ssize_t j = 0, count = 0

      __pyx_v_j = 0;
      __pyx_v_count = 0;

     278:

     279:         # find minimum filtration value

    +280:         for i in range(1, arr_size):

      __pyx_t_1 = __pyx_v_arr_size;
      __pyx_t_2 = __pyx_t_1;
      for (__pyx_t_3 = 1; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {
        __pyx_v_i = __pyx_t_3;

    +281:             if sq_filt[i] < min_val:

        __pyx_t_4 = ((__pyx_v_sq_filt[__pyx_v_i]) < __pyx_v_min_val);
        if (__pyx_t_4) {
    /* … */
        }
      }

    +282:                 min_val = sq_filt[i]

          __pyx_v_min_val = (__pyx_v_sq_filt[__pyx_v_i]);

     283:

     284:         # count how many times min_val occurs

    +285:         for i in range(arr_size):

      __pyx_t_1 = __pyx_v_arr_size;
      __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;

    +286:             if sq_filt[i] == min_val:

        __pyx_t_4 = ((__pyx_v_sq_filt[__pyx_v_i]) == __pyx_v_min_val);
        if (__pyx_t_4) {
    /* … */
        }
      }

    +287:                 count += 1

          __pyx_v_count = (__pyx_v_count + 1);

     288:

    +289:         cdef Py_ssize_t *sq = <Py_ssize_t *> malloc(count * sizeof(Py_ssize_t))

      __pyx_v_sq = ((Py_ssize_t *)malloc((__pyx_v_count * (sizeof(Py_ssize_t)))));

     290:

     291:         # store the index of squares that have minimum filtration value

    +292:         for i in range(arr_size):

      __pyx_t_1 = __pyx_v_arr_size;
      __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;

    +293:             if sq_filt[i] == min_val:

        __pyx_t_4 = ((__pyx_v_sq_filt[__pyx_v_i]) == __pyx_v_min_val);
        if (__pyx_t_4) {
    /* … */
        }
      }

    +294:                 sq[j] = neighbor_sq[i]

          (__pyx_v_sq[__pyx_v_j]) = (__pyx_v_neighbor_sq[__pyx_v_i]);

    +295:                 j += 1

          __pyx_v_j = (__pyx_v_j + 1);

     296:

     297:         # number of min_val occurences

    +298:         num_min[0] = count

      (__pyx_v_num_min[0]) = __pyx_v_count;

    +299:         return sq

      __pyx_r = __pyx_v_sq;
      goto __pyx_L0;

     300:

    +301:     cdef _set_dimension(self):

    static PyObject *__pyx_f_11ecc_sigmoid_14SigEccBackbone__set_dimension(struct __pyx_obj_11ecc_sigmoid_SigEccBackbone *__pyx_v_self) {
      PyObject *__pyx_v_dimension = NULL;
      Py_ssize_t __pyx_8genexpr1__pyx_v_i;
      Py_ssize_t __pyx_8genexpr2__pyx_v_i;
      PyObject *__pyx_r = NULL;
    /* … */
      /* function exit code */
      __pyx_L1_error:;
      __Pyx_XDECREF(__pyx_t_1);
      __Pyx_XDECREF(__pyx_t_2);
      __Pyx_XDECREF(__pyx_t_3);
      __Pyx_XDECREF(__pyx_t_4);
      __Pyx_AddTraceback("ecc_sigmoid.SigEccBackbone._set_dimension", __pyx_clineno, __pyx_lineno, __pyx_filename);
      __pyx_r = 0;
      __pyx_L0:;
      __Pyx_XDECREF(__pyx_v_dimension);
      __Pyx_XGIVEREF(__pyx_r);
      __Pyx_RefNannyFinishContext();
      return __pyx_r;
    }

     302:         """

     303:         Sets dimension for all cubes in the cubical complex. Dimensions of vertice, edge, square are 0, 1, 2 respectively. Even rows consist of (vertice, edge, vertice, edge, ..., vertice, edge, vertice) and odd rows consist of (edge, square, edge, square, ..., edge, square, edge).

     304:

     305:         Returns:

     306:             _type_: _description_

     307:         """

    +308:         dimension = np.zeros([self.grid_h, self.grid_w], dtype=dtype_float)

      __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_zeros); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __pyx_t_1 = PyInt_FromSsize_t(__pyx_v_self->grid_h); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __pyx_t_3 = PyInt_FromSsize_t(__pyx_v_self->grid_w); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __pyx_t_4 = PyList_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_GIVEREF(__pyx_t_1);
      if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 0, __pyx_t_1)) __PYX_ERR(0, 308, __pyx_L1_error);
      __Pyx_GIVEREF(__pyx_t_3);
      if (__Pyx_PyList_SET_ITEM(__pyx_t_4, 1, __pyx_t_3)) __PYX_ERR(0, 308, __pyx_L1_error);
      __pyx_t_1 = 0;
      __pyx_t_3 = 0;
      __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GIVEREF(__pyx_t_4);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4)) __PYX_ERR(0, 308, __pyx_L1_error);
      __pyx_t_4 = 0;
      __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_dtype_float); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_dtype, __pyx_t_1) < 0) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_3, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 308, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      __pyx_v_dimension = __pyx_t_1;
      __pyx_t_1 = 0;

    +309:         dimension[[i for i in range(self.grid_h) if i % 2 == 1], :] += 1

      { /* enter inner scope */
        __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 309, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_1);
        __pyx_t_5 = __pyx_v_self->grid_h;
        __pyx_t_6 = __pyx_t_5;
        for (__pyx_t_7 = 0; __pyx_t_7 < __pyx_t_6; __pyx_t_7+=1) {
          __pyx_8genexpr1__pyx_v_i = __pyx_t_7;
          __pyx_t_8 = (__Pyx_mod_Py_ssize_t(__pyx_8genexpr1__pyx_v_i, 2) == 1);
          if (__pyx_t_8) {
            __pyx_t_4 = PyInt_FromSsize_t(__pyx_8genexpr1__pyx_v_i); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 309, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_4);
            if (unlikely(__Pyx_ListComp_Append(__pyx_t_1, (PyObject*)__pyx_t_4))) __PYX_ERR(0, 309, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
          }
        }
      } /* exit inner scope */
      __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 309, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_GIVEREF(__pyx_t_1);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_1)) __PYX_ERR(0, 309, __pyx_L1_error);
      __Pyx_INCREF(__pyx_slice__5);
      __Pyx_GIVEREF(__pyx_slice__5);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_slice__5)) __PYX_ERR(0, 309, __pyx_L1_error);
      __pyx_t_1 = 0;
      __pyx_t_1 = __Pyx_PyObject_GetItem(__pyx_v_dimension, __pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 309, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __pyx_t_3 = __Pyx_PyInt_AddObjC(__pyx_t_1, __pyx_int_1, 1, 1, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 309, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      if (unlikely((PyObject_SetItem(__pyx_v_dimension, __pyx_t_4, __pyx_t_3) < 0))) __PYX_ERR(0, 309, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;

    +310:         dimension[:, [i for i in range(self.grid_w) if i % 2 == 1]] += 1

      { /* enter inner scope */
        __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 310, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_4);
        __pyx_t_5 = __pyx_v_self->grid_w;
        __pyx_t_6 = __pyx_t_5;
        for (__pyx_t_7 = 0; __pyx_t_7 < __pyx_t_6; __pyx_t_7+=1) {
          __pyx_8genexpr2__pyx_v_i = __pyx_t_7;
          __pyx_t_8 = (__Pyx_mod_Py_ssize_t(__pyx_8genexpr2__pyx_v_i, 2) == 1);
          if (__pyx_t_8) {
            __pyx_t_3 = PyInt_FromSsize_t(__pyx_8genexpr2__pyx_v_i); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 310, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_3);
            if (unlikely(__Pyx_ListComp_Append(__pyx_t_4, (PyObject*)__pyx_t_3))) __PYX_ERR(0, 310, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
          }
        }
      } /* exit inner scope */
      __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 310, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_INCREF(__pyx_slice__5);
      __Pyx_GIVEREF(__pyx_slice__5);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_slice__5)) __PYX_ERR(0, 310, __pyx_L1_error);
      __Pyx_GIVEREF(__pyx_t_4);
      if (__Pyx_PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_4)) __PYX_ERR(0, 310, __pyx_L1_error);
      __pyx_t_4 = 0;
      __pyx_t_4 = __Pyx_PyObject_GetItem(__pyx_v_dimension, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 310, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __pyx_t_1 = __Pyx_PyInt_AddObjC(__pyx_t_4, __pyx_int_1, 1, 1, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 310, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      if (unlikely((PyObject_SetItem(__pyx_v_dimension, __pyx_t_3, __pyx_t_1) < 0))) __PYX_ERR(0, 310, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;

    +311:         dimension.setflags(write=False)

      __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_dimension, __pyx_n_s_setflags); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 311, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 311, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_write, Py_False) < 0) __PYX_ERR(0, 311, __pyx_L1_error)
      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_empty_tuple, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 311, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;

    +312:         return dimension.flatten()

      __Pyx_XDECREF(__pyx_r);
      __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_dimension, __pyx_n_s_flatten); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 312, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __pyx_t_3 = NULL;
      __pyx_t_9 = 0;
      #if CYTHON_UNPACK_METHODS
      if (likely(PyMethod_Check(__pyx_t_1))) {
        __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1);
        if (likely(__pyx_t_3)) {
          PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
          __Pyx_INCREF(__pyx_t_3);
          __Pyx_INCREF(function);
          __Pyx_DECREF_SET(__pyx_t_1, function);
          __pyx_t_9 = 1;
        }
      }
      #endif
      {
        PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL};
        __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+1-__pyx_t_9, 0+__pyx_t_9);
        __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
        if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 312, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_4);
        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      }
      __pyx_r = __pyx_t_4;
      __pyx_t_4 = 0;
      goto __pyx_L0;

     313:

     314:

     315:

     316:

     317:

     318:

     319:

     320:

     321:

     322:

     323:

     324:

     325:

     326:

     327:     # V-construction

     328:     # @cython.boundscheck(False)      # turn off bounds-checking for entire function

     329:     # @cython.wraparound(False)       # turn off negative index wrapping for entire function

     330:     # @cython.cdivision(True)         # turn off checking for division by zero

     331:     # @cython.initializedcheck(False) # turn off initialization check

     332:     # def cal_ecc_vtx(self, object x, bint backprop):

     333:     #     """_summary_

     334:

     335:     #     Args:

     336:     #         x (anything convertible to a numpy.ndarray): Array of shape [B, C, H, W].

     337:     #         backprop (bint): Whether or not the input requires gradient calculation.

     338:

     339:     #     Returns:

     340:     #         _type_: _description_

     341:     #     """

     342:     #     cdef Py_ssize_t batch_size, num_channels, b, c, cell, t, pix, i, num_max

     343:     #     cdef float filt, dim

     344:     #     cdef Py_ssize_t *neighbor_vtx

     345:     #     cdef Py_ssize_t *vtx

     346:     #     cdef float[4] vtx_filt

     347:

     348:     #     batch_size, num_channels, h, w = x.shape

     349:

     350:     #     ecc = np.zeros((batch_size, num_channels, self.steps), dtype=dtype_float)

     351:     #     cdef float[:, :, :] ecc_view = ecc

     352:

     353:     #     tseq = np.linspace(self.t_min, self.t_max, self.steps, dtype=dtype_float)

     354:     #     cdef float[:] tseq_view = tseq

     355:

     356:     #     grad_local = np.zeros((batch_size, num_channels, h*w, self.steps), dtype=dtype_float) if backprop else None

     357:     #     cdef float[:, :, :, :] grad_local_view = grad_local

     358:

     359:     #     cdef float[:] filtration

     360:

     361:     #     for b in range(batch_size):         # iterate over batch

     362:     #         for c in range(num_channels):   # iterate over channel

     363:     #             cub_cpx = gd.CubicalComplex(vertices=x[b, c])   # V-contruction

     364:     #             filtration = cub_cpx.all_cells().astype(dtype_float).flatten()

     365:     #             for cell in range(self.num_cells):  # iterate over all cells in cubical complex

     366:     #                 filt = filtration[cell]

     367:     #                 if filt > self.t_max:

     368:     #                     continue

     369:     #                 dim = self.dimension[cell]

     370:

     371:     #                 for i in range(self.steps):

     372:     #                     ecc_view[b, c, i] += (-1)**dim * sigmoid(tseq[i] - filt, self.lamda)

     373:

     374:     #                 # calculation of gradient only for inputs that require gradient

     375:     #                 if backprop:

     376:     #                     if filt < self.lower_bound:                             # skip bc. gradient is 0 for simplices with filtration value under lower bound

     377:     #                         continue

     378:     #                     # vertex

     379:     #                     if dim == 0:

     380:     #                         pix = self._vtx2pix(cell)                           # index of the corresponding pixel in flattened original image

     381:     #                         for i in range(self.steps):

     382:     #                             grad_local_view[b, c, pix, i] += sigmoid_grad(tseq[i] - filt, self.lamda)

     383:     #                     # edge

     384:     #                     elif dim == 1:

     385:     #                         neighbor_vtx = self._find_neighbor_vtx(cell, dim)   # neighbor_vtx points at a C array containing index of 2 neighbor vertices

     386:     #                         for i in range(2):

     387:     #                             vtx_filt[i] = filtration[neighbor_vtx[i]]       # filtration value of neighbor vertices

     388:

     389:     #                         if vtx_filt[0] > vtx_filt[1]:

     390:     #                             pix = self._vtx2pix(neighbor_vtx[0])

     391:     #                             grad_local_view[b, c, pix, t] -= 1.

     392:     #                         elif vtx_filt[0] < vtx_filt[1]:

     393:     #                             pix = self._vtx2pix(neighbor_vtx[1])

     394:     #                             grad_local_view[b, c, pix, t] -= 1.

     395:     #                         else:                                               # split gradient when the neighboring vertices have the same filtration value

     396:     #                             for i in range(2):

     397:     #                                 pix = self._vtx2pix(neighbor_vtx[i])

     398:     #                                 grad_local_view[b, c, pix, t] -= 0.5

     399:     #                         free(neighbor_vtx)

     400:     #                     # square

     401:     #                     else:

     402:     #                         neighbor_vtx = self._find_neighbor_vtx(cell, dim)   # neighbor_vtx points at a C array containing index of 4 neighbor vertices

     403:     #                         for i in range(4):

     404:     #                             vtx_filt[i] = filtration[neighbor_vtx[i]]       # filtration value of neighbor vertices

     405:

     406:     #                         vtx = self._find_max_vtx(vtx_filt, neighbor_vtx, 4, &num_max)   # vtx points at a C array containing index of vertices that contribute to constructing the cell

     407:     #                         for i in range(num_max):

     408:     #                             pix = self._vtx2pix(vtx[i])

     409:     #                             grad_local_view[b, c, pix, t] += 1./num_max

     410:     #                         free(vtx)

     411:     #                         free(neighbor_vtx)

     412:     #             # cumsum

     413:     #             for i in range(self.steps - 1):

     414:     #                 ecc_view[b, c, i+1] += ecc_view[b, c, i]

     415:     #     return ecc, grad_local

     416:

     417:     # @cython.cdivision(True)     # turn off checking for division by zero

     418:     # cdef inline Py_ssize_t _vtx2pix(self, Py_ssize_t vtx):

     419:     #     """Given the index of a vertex, this function returns the index of the corresponding pixel.

     420:     #     Used for V-constructed cubical complexes.

     421:

     422:     #     Args:

     423:     #         vtx (Py_ssize_t): Index of vertex.

     424:

     425:     #     Returns:

     426:     #         Py_ssize_t: Index of corresponding pixel.

     427:     #     """

     428:     #     return (vtx // (2*self.grid_w))*self.w + (vtx % self.grid_w)/2

     429:

     430:     # @cython.cdivision(True)     # turn off checking for division by zero

     431:     # cdef inline Py_ssize_t* _find_neighbor_vtx(self, Py_ssize_t cell, float dim):

     432:     #     """Returns the indices of a cell's neighboring vertices.

     433:     #     Used for V-constructed cubical complexes.

     434:     #     Do not use for cells that are already vertices.

     435:

     436:     #     Args:

     437:     #         cell (Py_ssize_t): Index of cell.

     438:     #         dim (float): Dimension of cell.

     439:

     440:     #     Returns:

     441:     #         Py_ssize_t pointer: C array containing index of neighboring squares.

     442:     #     """

     443:     #     cdef Py_ssize_t row_num

     444:     #     cdef Py_ssize_t *neighbor_vtx = <Py_ssize_t *> malloc(<Py_ssize_t>dim * 2 * sizeof(Py_ssize_t)) # assign size 2 array for edges and size 4 array for squares

     445:     #     # edge

     446:     #     if dim == 1:

     447:     #         row_num = cell // self.grid_w

     448:     #         if row_num % 2 == 0:    # even row

     449:     #             neighbor_vtx[:] = [cell-1, cell+1]

     450:     #         else:                   # odd row

     451:     #             neighbor_vtx[:] = [cell-self.grid_w, cell+self.grid_w]

     452:     #     # square

     453:     #     else:

     454:     #         neighbor_vtx[:] = [cell-self.grid_w-1, cell-self.grid_w+1, cell+self.grid_w-1, cell+self.grid_w+1]

     455:     #     return neighbor_vtx

     456:

     457:     # cdef inline Py_ssize_t* _find_max_vtx(self, float *vtx_filt, Py_ssize_t *neighbor_vtx, Py_ssize_t arr_size, Py_ssize_t *num_max):

     458:     #     """

     459:

     460:     #     """

     461:     #     cdef float max_val = vtx_filt[0]

     462:     #     cdef Py_ssize_t j = 0, count = 0

     463:

     464:     #     # find maximum filtration value

     465:     #     for i in range(1, arr_size):

     466:     #         if vtx_filt[i] > max_val:

     467:     #             max_val = vtx_filt[i]

     468:

     469:     #     # count how many times max_val occurs

     470:     #     for i in range(arr_size):

     471:     #         if vtx_filt[i] == max_val:

     472:     #             count += 1

     473:

     474:     #     cdef Py_ssize_t *vtx = <Py_ssize_t *> malloc(count * sizeof(Py_ssize_t))

     475:

     476:     #     # store the index of vertices that have maximum filtration value

     477:     #     for i in range(arr_size):

     478:     #         if vtx_filt[i] == max_val:

     479:     #             vtx[j] = neighbor_vtx[i]

     480:     #             j += 1

     481:

     482:     #     # number of max_val occurences

     483:     #     num_max[0] = count

     484:     #     return vtx