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