Generated by Cython 0.29.21
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: find_cutpoints.c
+001: # -*- coding: utf-8 -*-
__pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_t_1, __pyx_kp_u_find_cutpoints_line_52, __pyx_kp_u_Compute_the_cutpoints_from_a_giv) < 0) __PYX_ERR(0, 1, __pyx_L1_error) if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
002:
003:
004: # pept is a Python library that unifies Positron Emission Particle
005: # Tracking (PEPT) research, including tracking, simulation, data analysis
006: # and visualisation tools.
007: #
008: # If you used this codebase or any software making use of it in a scientific
009: # publication, you must cite the following paper:
010: # Nicuşan AL, Windows-Yule CR. Positron emission particle tracking
011: # using machine learning. Review of Scientific Instruments.
012: # 2020 Jan 1;91(1):013329.
013: # https://doi.org/10.1063/1.5129251
014: #
015: # Copyright (C) 2019-2021 the pept developers
016: #
017: # This program is free software: you can redistribute it and/or modify
018: # it under the terms of the GNU General Public License as published by
019: # the Free Software Foundation, either version 3 of the License, or
020: # (at your option) any later version.
021: #
022: # This program is distributed in the hope that it will be useful,
023: # but WITHOUT ANY WARRANTY; without even the implied warranty of
024: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025: # GNU General Public License for more details.
026: #
027: # You should have received a copy of the GNU General Public License
028: # along with this program. If not, see <https://www.gnu.org/licenses/>.
029: # pept is a Python library that unifies Positron Emission Particle
030: # Tracking (PEPT) research, including tracking, simulation, data analysis
031: # and visualisation tools
032:
033:
034: # File : find_cutpoints.pyx
035: # License : GNU v3.0
036: # Author : Andrei Leonard Nicusan <a.l.nicusan@bham.ac.uk>
037: # Date : 03.02.2019
038:
039:
040: # cython: language_level=3
041: # cython: boundscheck=False
042: # cython: wraparound=False
043: # cython: initializedcheck=False
044: # cython: nonecheck=False
045: # cython: embedsignature=True
046: # cython: cdivision=True
047:
048:
+049: import numpy as np
__pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 49, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 49, __pyx_L1_error) __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
050:
051:
+052: cpdef find_cutpoints(
static PyObject *__pyx_pw_4pept_9utilities_9cutpoints_14find_cutpoints_1find_cutpoints(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static PyObject *__pyx_f_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints(__Pyx_memviewslice __pyx_v_sample_lines, double __pyx_v_max_distance, __Pyx_memviewslice __pyx_v_cutoffs, CYTHON_UNUSED int __pyx_skip_dispatch, struct __pyx_opt_args_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints *__pyx_optional_args) { int __pyx_v_append_indices = ((int)0); Py_ssize_t __pyx_v_n; PyObject *__pyx_v_cutpoints = NULL; __Pyx_memviewslice __pyx_v_cutpoints_mv = { 0, 0, { 0 }, { 0 }, { 0 } }; Py_ssize_t __pyx_v_i; Py_ssize_t __pyx_v_j; Py_ssize_t __pyx_v_k; Py_ssize_t __pyx_v_ic; double __pyx_v_P[3]; double __pyx_v_U[3]; double __pyx_v_Q[3]; double __pyx_v_R[3]; double __pyx_v_QP[3]; double __pyx_v_a; double __pyx_v_b; double __pyx_v_c; double __pyx_v_d; double __pyx_v_e; double __pyx_v_denom; double __pyx_v_s0; double __pyx_v_t0; double __pyx_v_A0[3]; double __pyx_v_C0[3]; double __pyx_v_AC0[3]; double __pyx_v_mx; double __pyx_v_my; double __pyx_v_mz; PyObject *__pyx_v_cutpoints_truncated = NULL; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("find_cutpoints", 0); if (__pyx_optional_args) { if (__pyx_optional_args->__pyx_n > 0) { __pyx_v_append_indices = __pyx_optional_args->append_indices; } } /* … */ /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_XDECREF(__pyx_t_4); __Pyx_XDECREF(__pyx_t_5); __PYX_XDEC_MEMVIEW(&__pyx_t_6, 1); __Pyx_XDECREF(__pyx_t_22); __Pyx_AddTraceback("pept.utilities.cutpoints.find_cutpoints.find_cutpoints", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = 0; __pyx_L0:; __Pyx_XDECREF(__pyx_v_cutpoints); __PYX_XDEC_MEMVIEW(&__pyx_v_cutpoints_mv, 1); __Pyx_XDECREF(__pyx_v_cutpoints_truncated); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; } /* Python wrapper */ static PyObject *__pyx_pw_4pept_9utilities_9cutpoints_14find_cutpoints_1find_cutpoints(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ static char __pyx_doc_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints[] = "find_cutpoints(double[:, :] sample_lines, double max_distance, double[:] cutoffs, bool append_indices=0)\nCompute the cutpoints from a given array of lines.\n\n ::\n\n Function signature:\n find_cutpoints(\n double[:, :] sample_lines, # LoRs in sample\n double max_distance, # Max distance between two LoRs\n double[:] cutoffs, # Spatial cutoff for cutpoints\n bint append_indices = False # Append LoR indices used\n )\n\n This is a low-level Cython function that does not do any checks on the\n input data - it is meant to be used in other modules / libraries. For a\n normal user, the `pept.tracking.peptml` function `find_cutpoints` and\n class `Cutpoints` are recommended as higher-level APIs. They do check the\n input data and are easier to use (for example, they automatically compute\n the cutoffs).\n\n A cutpoint is the point in 3D space that minimises the distance between any\n two lines. For any two non-parallel 3D lines, this point corresponds to the\n midpoint of the unique segment that is perpendicular to both lines.\n\n This function considers every pair of lines in `sample_lines` and returns\n all the cutpoints that satisfy the following conditions:\n\n 1. The distance between the two lines is smaller than `max_distance`.\n 2. The cutpoints are within the `cutoffs`.\n\n Parameters\n ----------\n sample_lines : (N, M >= 7) numpy.ndarray\n The sample of lines, where each row is [time, x1, y1, z1, x2, y2, z2],\n containing two points [x1, y1, z1] and [x2, y2, z2] defining an LoR.\n max_distance : float\n The maximum distance between two LoRs for their cutpoint to be\n considered.\n cutoffs : (6,) numpy.ndarray\n Only consider the cutpoints that fall within the cutoffs. `cutoffs` has\n the format [min_x, max_x, min_y, max_y, min_z, max_z].\n append_indices : bo""ol, optional\n If set to `True`, the indices of the individual LoRs that were used\n to compute each cutpoint is also appended to the returned array.\n Default is `False`.\n\n Returns\n -------\n cutpoints : (M, 4) or (M, 6) numpy.ndarray\n A numpy array of the calculated weighted cutpoints. If `append_indices`\n is `False`, then the columns are [time, x, y, z]. If `append_indices`\n is `True`, then the columns are [time, x, y, z, i, j], where `i` and\n `j` are the LoR indices from `sample_lines` that were used to compute\n the cutpoints. The time is the average between the timestamps of the\n two LoRs that were used to compute the cutpoint. The first column (for\n time) is sorted.\n\n Examples\n --------\n\n >>> import numpy as np\n >>> from pept.utilities import find_cutpoints\n >>>\n >>> lines = np.random.random((500, 7)) * 500\n >>> max_distance = 0.1\n >>> cutoffs = np.array([0, 500, 0, 500, 0, 500], dtype = float)\n >>>\n >>> cutpoints = find_cutpoints(lines, max_distance, cutoffs)\n\n "; static PyObject *__pyx_pw_4pept_9utilities_9cutpoints_14find_cutpoints_1find_cutpoints(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { __Pyx_memviewslice __pyx_v_sample_lines = { 0, 0, { 0 }, { 0 }, { 0 } }; double __pyx_v_max_distance; __Pyx_memviewslice __pyx_v_cutoffs = { 0, 0, { 0 }, { 0 }, { 0 } }; int __pyx_v_append_indices; PyObject *__pyx_r = 0; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("find_cutpoints (wrapper)", 0); { static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_sample_lines,&__pyx_n_s_max_distance,&__pyx_n_s_cutoffs,&__pyx_n_s_append_indices,0}; PyObject* values[4] = {0,0,0,0}; if (unlikely(__pyx_kwds)) { Py_ssize_t kw_args; const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); switch (pos_args) { case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); CYTHON_FALLTHROUGH; case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); CYTHON_FALLTHROUGH; case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); CYTHON_FALLTHROUGH; case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); CYTHON_FALLTHROUGH; case 0: break; default: goto __pyx_L5_argtuple_error; } kw_args = PyDict_Size(__pyx_kwds); switch (pos_args) { case 0: if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_sample_lines)) != 0)) kw_args--; else goto __pyx_L5_argtuple_error; CYTHON_FALLTHROUGH; case 1: if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_max_distance)) != 0)) kw_args--; else { __Pyx_RaiseArgtupleInvalid("find_cutpoints", 0, 3, 4, 1); __PYX_ERR(0, 52, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 2: if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_cutoffs)) != 0)) kw_args--; else { __Pyx_RaiseArgtupleInvalid("find_cutpoints", 0, 3, 4, 2); __PYX_ERR(0, 52, __pyx_L3_error) } CYTHON_FALLTHROUGH; case 3: if (kw_args > 0) { PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_append_indices); if (value) { values[3] = value; kw_args--; } } } if (unlikely(kw_args > 0)) { if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "find_cutpoints") < 0)) __PYX_ERR(0, 52, __pyx_L3_error) } } else { switch (PyTuple_GET_SIZE(__pyx_args)) { case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); CYTHON_FALLTHROUGH; case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); values[1] = PyTuple_GET_ITEM(__pyx_args, 1); values[0] = PyTuple_GET_ITEM(__pyx_args, 0); break; default: goto __pyx_L5_argtuple_error; } } __pyx_v_sample_lines = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(values[0], PyBUF_WRITABLE); if (unlikely(!__pyx_v_sample_lines.memview)) __PYX_ERR(0, 53, __pyx_L3_error) __pyx_v_max_distance = __pyx_PyFloat_AsDouble(values[1]); if (unlikely((__pyx_v_max_distance == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 54, __pyx_L3_error) __pyx_v_cutoffs = __Pyx_PyObject_to_MemoryviewSlice_ds_double(values[2], PyBUF_WRITABLE); if (unlikely(!__pyx_v_cutoffs.memview)) __PYX_ERR(0, 55, __pyx_L3_error) if (values[3]) { __pyx_v_append_indices = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_append_indices == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 56, __pyx_L3_error) } else { __pyx_v_append_indices = ((int)0); } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; __Pyx_RaiseArgtupleInvalid("find_cutpoints", 0, 3, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 52, __pyx_L3_error) __pyx_L3_error:; __Pyx_AddTraceback("pept.utilities.cutpoints.find_cutpoints.find_cutpoints", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; __pyx_r = __pyx_pf_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints(__pyx_self, __pyx_v_sample_lines, __pyx_v_max_distance, __pyx_v_cutoffs, __pyx_v_append_indices); int __pyx_lineno = 0; const char *__pyx_filename = NULL; int __pyx_clineno = 0; /* function exit code */ __Pyx_RefNannyFinishContext(); return __pyx_r; } static PyObject *__pyx_pf_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_sample_lines, double __pyx_v_max_distance, __Pyx_memviewslice __pyx_v_cutoffs, int __pyx_v_append_indices) { PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("find_cutpoints", 0); __Pyx_XDECREF(__pyx_r); __pyx_t_2.__pyx_n = 1; __pyx_t_2.append_indices = __pyx_v_append_indices; __pyx_t_1 = __pyx_f_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints(__pyx_v_sample_lines, __pyx_v_max_distance, __pyx_v_cutoffs, 0, &__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 52, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; /* function exit code */ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); __Pyx_AddTraceback("pept.utilities.cutpoints.find_cutpoints.find_cutpoints", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __PYX_XDEC_MEMVIEW(&__pyx_v_sample_lines, 1); __PYX_XDEC_MEMVIEW(&__pyx_v_cutoffs, 1); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; }
+053: double[:, :] sample_lines, # LoRs in sample
struct __pyx_opt_args_4pept_9utilities_9cutpoints_14find_cutpoints_find_cutpoints { int __pyx_n; int append_indices; };
054: double max_distance, # Max allowed distance between two LoRs
055: double[:] cutoffs, # Spatial cutoff for cutpoints
056: bint append_indices = 0 # Append LoR indices used for each cutpoint
057: ):
058: '''Compute the cutpoints from a given array of lines.
059:
060: ::
061:
062: Function signature:
063: find_cutpoints(
064: double[:, :] sample_lines, # LoRs in sample
065: double max_distance, # Max distance between two LoRs
066: double[:] cutoffs, # Spatial cutoff for cutpoints
067: bint append_indices = False # Append LoR indices used
068: )
069:
070: This is a low-level Cython function that does not do any checks on the
071: input data - it is meant to be used in other modules / libraries. For a
072: normal user, the `pept.tracking.peptml` function `find_cutpoints` and
073: class `Cutpoints` are recommended as higher-level APIs. They do check the
074: input data and are easier to use (for example, they automatically compute
075: the cutoffs).
076:
077: A cutpoint is the point in 3D space that minimises the distance between any
078: two lines. For any two non-parallel 3D lines, this point corresponds to the
079: midpoint of the unique segment that is perpendicular to both lines.
080:
081: This function considers every pair of lines in `sample_lines` and returns
082: all the cutpoints that satisfy the following conditions:
083:
084: 1. The distance between the two lines is smaller than `max_distance`.
085: 2. The cutpoints are within the `cutoffs`.
086:
087: Parameters
088: ----------
089: sample_lines : (N, M >= 7) numpy.ndarray
090: The sample of lines, where each row is [time, x1, y1, z1, x2, y2, z2],
091: containing two points [x1, y1, z1] and [x2, y2, z2] defining an LoR.
092: max_distance : float
093: The maximum distance between two LoRs for their cutpoint to be
094: considered.
095: cutoffs : (6,) numpy.ndarray
096: Only consider the cutpoints that fall within the cutoffs. `cutoffs` has
097: the format [min_x, max_x, min_y, max_y, min_z, max_z].
098: append_indices : bool, optional
099: If set to `True`, the indices of the individual LoRs that were used
100: to compute each cutpoint is also appended to the returned array.
101: Default is `False`.
102:
103: Returns
104: -------
105: cutpoints : (M, 4) or (M, 6) numpy.ndarray
106: A numpy array of the calculated weighted cutpoints. If `append_indices`
107: is `False`, then the columns are [time, x, y, z]. If `append_indices`
108: is `True`, then the columns are [time, x, y, z, i, j], where `i` and
109: `j` are the LoR indices from `sample_lines` that were used to compute
110: the cutpoints. The time is the average between the timestamps of the
111: two LoRs that were used to compute the cutpoint. The first column (for
112: time) is sorted.
113:
114: Examples
115: --------
116:
117: >>> import numpy as np
118: >>> from pept.utilities import find_cutpoints
119: >>>
120: >>> lines = np.random.random((500, 7)) * 500
121: >>> max_distance = 0.1
122: >>> cutoffs = np.array([0, 500, 0, 500, 0, 500], dtype = float)
123: >>>
124: >>> cutpoints = find_cutpoints(lines, max_distance, cutoffs)
125:
126: '''
127:
128: # Lines for a single sample => n x 7 array
129: # sample_lines row: [time X1 Y1 Z1 X2 Y2 Z2]
+130: cdef Py_ssize_t n = sample_lines.shape[0]
__pyx_v_n = (__pyx_v_sample_lines.shape[0]);
131:
132: # Pre-allocate enough memory
133: # weighted_cutpoints cols: [time, x, y, z, [LoR1_index, LoR2_index]]
+134: if append_indices:
__pyx_t_1 = (__pyx_v_append_indices != 0); if (__pyx_t_1) { /* … */ goto __pyx_L3; }
+135: cutpoints = np.zeros((n * (n - 1) // 2, 6), order = 'C')
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __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, 135, __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_n * (__pyx_v_n - 1)) / 2)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 135, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __Pyx_INCREF(__pyx_int_6); __Pyx_GIVEREF(__pyx_int_6); PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_int_6); __pyx_t_2 = 0; __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 135, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_4); __pyx_t_4 = 0; __pyx_t_4 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 135, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); if (PyDict_SetItem(__pyx_t_4, __pyx_n_s_order, __pyx_n_u_C) < 0) __PYX_ERR(0, 135, __pyx_L1_error) __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_2, __pyx_t_4); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 135, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __pyx_v_cutpoints = __pyx_t_5; __pyx_t_5 = 0;
136: else:
+137: cutpoints = np.zeros((n * (n - 1) // 2, 4), order = 'C')
/*else*/ { __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_zeros); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __pyx_t_5 = PyInt_FromSsize_t(((__pyx_v_n * (__pyx_v_n - 1)) / 2)); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_5); __Pyx_INCREF(__pyx_int_4); __Pyx_GIVEREF(__pyx_int_4); PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_int_4); __pyx_t_5 = 0; __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_order, __pyx_n_u_C) < 0) __PYX_ERR(0, 137, __pyx_L1_error) __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 137, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_v_cutpoints = __pyx_t_3; __pyx_t_3 = 0; } __pyx_L3:;
138:
139:
+140: cdef double[:, :] cutpoints_mv = cutpoints # memoryview of cutpoints
__pyx_t_6 = __Pyx_PyObject_to_MemoryviewSlice_dsds_double(__pyx_v_cutpoints, PyBUF_WRITABLE); if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 140, __pyx_L1_error) __pyx_v_cutpoints_mv = __pyx_t_6; __pyx_t_6.memview = NULL; __pyx_t_6.data = NULL;
141: cdef Py_ssize_t i, j, k # iterators
142: cdef Py_ssize_t ic # cutpoint index
143: cdef double[3] P, U, Q, R, QP # position, direction vectors
144: cdef double a, b, c, d, e # collected terms
145: cdef double denom, s0, t0 # parameters for lines
146: cdef double[3] A0, C0, AC0 # perpendicular points
147: cdef double mx, my, mz # cutpoint coordinates
148:
+149: with nogil:
{ #ifdef WITH_THREAD PyThreadState *_save; Py_UNBLOCK_THREADS __Pyx_FastGIL_Remember(); #endif /*try:*/ { /* … */ /*finally:*/ { /*normal exit:*/{ #ifdef WITH_THREAD __Pyx_FastGIL_Forget(); Py_BLOCK_THREADS #endif goto __pyx_L6; } __pyx_L6:; } }
+150: ic = 0
__pyx_v_ic = 0;
+151: for i in range(n - 1):
__pyx_t_7 = (__pyx_v_n - 1); __pyx_t_8 = __pyx_t_7; for (__pyx_t_9 = 0; __pyx_t_9 < __pyx_t_8; __pyx_t_9+=1) { __pyx_v_i = __pyx_t_9;
+152: for j in range(i + 1, n):
__pyx_t_10 = __pyx_v_n; __pyx_t_11 = __pyx_t_10; for (__pyx_t_12 = (__pyx_v_i + 1); __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) { __pyx_v_j = __pyx_t_12;
153:
154: # Write each pair of lines in terms of a position vector and a
155: # direction vector:
156: # L1 : A(s) = P + s U
157: # L2 : C(t) = Q + t R
+158: for k in range(3):
for (__pyx_t_13 = 0; __pyx_t_13 < 3; __pyx_t_13+=1) { __pyx_v_k = __pyx_t_13;
+159: P[k] = sample_lines[i, 1 + k]
__pyx_t_14 = __pyx_v_i; __pyx_t_15 = (1 + __pyx_v_k); (__pyx_v_P[__pyx_v_k]) = (*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_14 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_15 * __pyx_v_sample_lines.strides[1]) )));
+160: U[k] = sample_lines[i, 4 + k] - P[k]
__pyx_t_15 = __pyx_v_i; __pyx_t_14 = (4 + __pyx_v_k); (__pyx_v_U[__pyx_v_k]) = ((*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_15 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_14 * __pyx_v_sample_lines.strides[1]) ))) - (__pyx_v_P[__pyx_v_k]));
+161: Q[k] = sample_lines[j, 1 + k]
__pyx_t_14 = __pyx_v_j; __pyx_t_15 = (1 + __pyx_v_k); (__pyx_v_Q[__pyx_v_k]) = (*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_14 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_15 * __pyx_v_sample_lines.strides[1]) )));
+162: R[k] = sample_lines[j, 4 + k] - Q[k]
__pyx_t_15 = __pyx_v_j; __pyx_t_14 = (4 + __pyx_v_k); (__pyx_v_R[__pyx_v_k]) = ((*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_15 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_14 * __pyx_v_sample_lines.strides[1]) ))) - (__pyx_v_Q[__pyx_v_k]));
+163: QP[k] = Q[k] - P[k]
(__pyx_v_QP[__pyx_v_k]) = ((__pyx_v_Q[__pyx_v_k]) - (__pyx_v_P[__pyx_v_k])); }
164:
+165: a = U[0] * U[0] + U[1] * U[1] + U[2] * U[2]
__pyx_v_a = ((((__pyx_v_U[0]) * (__pyx_v_U[0])) + ((__pyx_v_U[1]) * (__pyx_v_U[1]))) + ((__pyx_v_U[2]) * (__pyx_v_U[2])));
+166: b = U[0] * R[0] + U[1] * R[1] + U[2] * R[2]
__pyx_v_b = ((((__pyx_v_U[0]) * (__pyx_v_R[0])) + ((__pyx_v_U[1]) * (__pyx_v_R[1]))) + ((__pyx_v_U[2]) * (__pyx_v_R[2])));
+167: c = R[0] * R[0] + R[1] * R[1] + R[2] * R[2]
__pyx_v_c = ((((__pyx_v_R[0]) * (__pyx_v_R[0])) + ((__pyx_v_R[1]) * (__pyx_v_R[1]))) + ((__pyx_v_R[2]) * (__pyx_v_R[2])));
+168: d = U[0] * QP[0] + U[1] * QP[1] + U[2] * QP[2]
__pyx_v_d = ((((__pyx_v_U[0]) * (__pyx_v_QP[0])) + ((__pyx_v_U[1]) * (__pyx_v_QP[1]))) + ((__pyx_v_U[2]) * (__pyx_v_QP[2])));
+169: e = QP[0] * R[0] + QP[1] * R[1] + QP[2] * R[2]
__pyx_v_e = ((((__pyx_v_QP[0]) * (__pyx_v_R[0])) + ((__pyx_v_QP[1]) * (__pyx_v_R[1]))) + ((__pyx_v_QP[2]) * (__pyx_v_R[2])));
170:
+171: denom = b * b - a * c
__pyx_v_denom = ((__pyx_v_b * __pyx_v_b) - (__pyx_v_a * __pyx_v_c));
+172: if denom:
__pyx_t_1 = (__pyx_v_denom != 0); if (__pyx_t_1) { /* … */ } } } }
+173: s0 = (b * e - c * d) / denom
__pyx_v_s0 = (((__pyx_v_b * __pyx_v_e) - (__pyx_v_c * __pyx_v_d)) / __pyx_v_denom);
+174: t0 = (a * e - b * d) / denom
__pyx_v_t0 = (((__pyx_v_a * __pyx_v_e) - (__pyx_v_b * __pyx_v_d)) / __pyx_v_denom);
175:
+176: for k in range(3):
for (__pyx_t_13 = 0; __pyx_t_13 < 3; __pyx_t_13+=1) { __pyx_v_k = __pyx_t_13;
+177: A0[k] = P[k] + s0 * U[k]
(__pyx_v_A0[__pyx_v_k]) = ((__pyx_v_P[__pyx_v_k]) + (__pyx_v_s0 * (__pyx_v_U[__pyx_v_k])));
+178: C0[k] = Q[k] + t0 * R[k]
(__pyx_v_C0[__pyx_v_k]) = ((__pyx_v_Q[__pyx_v_k]) + (__pyx_v_t0 * (__pyx_v_R[__pyx_v_k])));
+179: AC0[k] = A0[k] - C0[k]
(__pyx_v_AC0[__pyx_v_k]) = ((__pyx_v_A0[__pyx_v_k]) - (__pyx_v_C0[__pyx_v_k])); }
180:
181: # Check the distance is smaller than max_distance
+182: if (AC0[0] * AC0[0] + AC0[1] * AC0[1] +
if (__pyx_t_1) { /* … */ }
+183: AC0[2] * AC0[2] < max_distance * max_distance):
__pyx_t_1 = ((((((__pyx_v_AC0[0]) * (__pyx_v_AC0[0])) + ((__pyx_v_AC0[1]) * (__pyx_v_AC0[1]))) + ((__pyx_v_AC0[2]) * (__pyx_v_AC0[2]))) < (__pyx_v_max_distance * __pyx_v_max_distance)) != 0);
+184: mx = (A0[0] + C0[0]) / 2
__pyx_v_mx = (((__pyx_v_A0[0]) + (__pyx_v_C0[0])) / 2.0);
+185: my = (A0[1] + C0[1]) / 2
__pyx_v_my = (((__pyx_v_A0[1]) + (__pyx_v_C0[1])) / 2.0);
+186: mz = (A0[2] + C0[2]) / 2
__pyx_v_mz = (((__pyx_v_A0[2]) + (__pyx_v_C0[2])) / 2.0);
187:
188: # Check the cutpoint falls within the cutoffs
+189: if (mx > cutoffs[0] and mx < cutoffs[1] and
__pyx_t_14 = 0; __pyx_t_16 = ((__pyx_v_mx > (*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_14 * __pyx_v_cutoffs.strides[0]) )))) != 0); if (__pyx_t_16) { } else { __pyx_t_1 = __pyx_t_16; goto __pyx_L18_bool_binop_done; } __pyx_t_14 = 1; __pyx_t_16 = ((__pyx_v_mx < (*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_14 * __pyx_v_cutoffs.strides[0]) )))) != 0); if (__pyx_t_16) { } else { __pyx_t_1 = __pyx_t_16; goto __pyx_L18_bool_binop_done; } /* … */ if (__pyx_t_1) { /* … */ }
+190: my > cutoffs[2] and my < cutoffs[3] and
__pyx_t_14 = 2; __pyx_t_16 = ((__pyx_v_my > (*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_14 * __pyx_v_cutoffs.strides[0]) )))) != 0); if (__pyx_t_16) { } else { __pyx_t_1 = __pyx_t_16; goto __pyx_L18_bool_binop_done; } __pyx_t_14 = 3; __pyx_t_16 = ((__pyx_v_my < (*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_14 * __pyx_v_cutoffs.strides[0]) )))) != 0); if (__pyx_t_16) { } else { __pyx_t_1 = __pyx_t_16; goto __pyx_L18_bool_binop_done; }
+191: mz > cutoffs[4] and mz < cutoffs[5]):
__pyx_t_14 = 4; __pyx_t_16 = ((__pyx_v_mz > (*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_14 * __pyx_v_cutoffs.strides[0]) )))) != 0); if (__pyx_t_16) { } else { __pyx_t_1 = __pyx_t_16; goto __pyx_L18_bool_binop_done; } __pyx_t_14 = 5; __pyx_t_16 = ((__pyx_v_mz < (*((double *) ( /* dim=0 */ (__pyx_v_cutoffs.data + __pyx_t_14 * __pyx_v_cutoffs.strides[0]) )))) != 0); __pyx_t_1 = __pyx_t_16; __pyx_L18_bool_binop_done:;
192: # Average the times of the two lines
+193: cutpoints_mv[ic, 0] = (sample_lines[i, 0] + \
__pyx_t_14 = __pyx_v_i; __pyx_t_15 = 0; /* … */ __pyx_t_19 = __pyx_v_ic; __pyx_t_20 = 0; *((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_cutpoints_mv.data + __pyx_t_19 * __pyx_v_cutpoints_mv.strides[0]) ) + __pyx_t_20 * __pyx_v_cutpoints_mv.strides[1]) )) = (((*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_14 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_15 * __pyx_v_sample_lines.strides[1]) ))) + (*((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_sample_lines.data + __pyx_t_17 * __pyx_v_sample_lines.strides[0]) ) + __pyx_t_18 * __pyx_v_sample_lines.strides[1]) )))) / 2.0);
+194: sample_lines[j, 0]) / 2
__pyx_t_17 = __pyx_v_j; __pyx_t_18 = 0;
+195: cutpoints_mv[ic, 1] = mx
__pyx_t_18 = __pyx_v_ic; __pyx_t_17 = 1; *((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_cutpoints_mv.data + __pyx_t_18 * __pyx_v_cutpoints_mv.strides[0]) ) + __pyx_t_17 * __pyx_v_cutpoints_mv.strides[1]) )) = __pyx_v_mx;
+196: cutpoints_mv[ic, 2] = my
__pyx_t_17 = __pyx_v_ic; __pyx_t_18 = 2; *((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_cutpoints_mv.data + __pyx_t_17 * __pyx_v_cutpoints_mv.strides[0]) ) + __pyx_t_18 * __pyx_v_cutpoints_mv.strides[1]) )) = __pyx_v_my;
+197: cutpoints_mv[ic, 3] = mz
__pyx_t_18 = __pyx_v_ic; __pyx_t_17 = 3; *((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_cutpoints_mv.data + __pyx_t_18 * __pyx_v_cutpoints_mv.strides[0]) ) + __pyx_t_17 * __pyx_v_cutpoints_mv.strides[1]) )) = __pyx_v_mz;
198:
+199: if append_indices:
__pyx_t_1 = (__pyx_v_append_indices != 0); if (__pyx_t_1) { /* … */ }
+200: cutpoints_mv[ic, 4] = <double>i
__pyx_t_17 = __pyx_v_ic; __pyx_t_18 = 4; *((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_cutpoints_mv.data + __pyx_t_17 * __pyx_v_cutpoints_mv.strides[0]) ) + __pyx_t_18 * __pyx_v_cutpoints_mv.strides[1]) )) = ((double)__pyx_v_i);
+201: cutpoints_mv[ic, 5] = <double>j
__pyx_t_18 = __pyx_v_ic; __pyx_t_17 = 5; *((double *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_cutpoints_mv.data + __pyx_t_18 * __pyx_v_cutpoints_mv.strides[0]) ) + __pyx_t_17 * __pyx_v_cutpoints_mv.strides[1]) )) = ((double)__pyx_v_j);
202:
+203: ic = ic + 1
__pyx_v_ic = (__pyx_v_ic + 1);
204:
205:
206: # Truncate the cutpoints which were not written
+207: cutpoints_truncated = np.delete(cutpoints, slice(ic, None, None), 0)
__Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_delete); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = PyInt_FromSsize_t(__pyx_v_ic); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_2); __pyx_t_4 = PySlice_New(__pyx_t_2, Py_None, Py_None); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_4); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_t_2 = NULL; __pyx_t_21 = 0; if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) { __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_5); if (likely(__pyx_t_2)) { PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5); __Pyx_INCREF(__pyx_t_2); __Pyx_INCREF(function); __Pyx_DECREF_SET(__pyx_t_5, function); __pyx_t_21 = 1; } } #if CYTHON_FAST_PYCALL if (PyFunction_Check(__pyx_t_5)) { PyObject *__pyx_temp[4] = {__pyx_t_2, __pyx_v_cutpoints, __pyx_t_4, __pyx_int_0}; __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_21, 3+__pyx_t_21); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; } else #endif #if CYTHON_FAST_PYCCALL if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) { PyObject *__pyx_temp[4] = {__pyx_t_2, __pyx_v_cutpoints, __pyx_t_4, __pyx_int_0}; __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_21, 3+__pyx_t_21); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; } else #endif { __pyx_t_22 = PyTuple_New(3+__pyx_t_21); if (unlikely(!__pyx_t_22)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_22); if (__pyx_t_2) { __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_22, 0, __pyx_t_2); __pyx_t_2 = NULL; } __Pyx_INCREF(__pyx_v_cutpoints); __Pyx_GIVEREF(__pyx_v_cutpoints); PyTuple_SET_ITEM(__pyx_t_22, 0+__pyx_t_21, __pyx_v_cutpoints); __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_22, 1+__pyx_t_21, __pyx_t_4); __Pyx_INCREF(__pyx_int_0); __Pyx_GIVEREF(__pyx_int_0); PyTuple_SET_ITEM(__pyx_t_22, 2+__pyx_t_21, __pyx_int_0); __pyx_t_4 = 0; __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_22, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 207, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_22); __pyx_t_22 = 0; } __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __pyx_v_cutpoints_truncated = __pyx_t_3; __pyx_t_3 = 0;
+208: del(cutpoints)
__Pyx_DECREF(__pyx_v_cutpoints);
__pyx_v_cutpoints = NULL;
209:
210: # Sort rows based on time (column 0)
+211: cutpoints_truncated = cutpoints_truncated[cutpoints_truncated[:, 0].argsort()]
__pyx_slice_ = PySlice_New(Py_None, Py_None, Py_None); if (unlikely(!__pyx_slice_)) __PYX_ERR(0, 211, __pyx_L1_error) __Pyx_GOTREF(__pyx_slice_); __Pyx_GIVEREF(__pyx_slice_); /* … */ __pyx_t_5 = __Pyx_PyObject_GetItem(__pyx_v_cutpoints_truncated, __pyx_tuple__2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 211, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_5); __pyx_t_22 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_argsort); if (unlikely(!__pyx_t_22)) __PYX_ERR(0, 211, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_22); __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; __pyx_t_5 = NULL; if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_22))) { __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_22); if (likely(__pyx_t_5)) { PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_22); __Pyx_INCREF(__pyx_t_5); __Pyx_INCREF(function); __Pyx_DECREF_SET(__pyx_t_22, function); } } __pyx_t_3 = (__pyx_t_5) ? __Pyx_PyObject_CallOneArg(__pyx_t_22, __pyx_t_5) : __Pyx_PyObject_CallNoArg(__pyx_t_22); __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 211, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_22); __pyx_t_22 = 0; __pyx_t_22 = __Pyx_PyObject_GetItem(__pyx_v_cutpoints_truncated, __pyx_t_3); if (unlikely(!__pyx_t_22)) __PYX_ERR(0, 211, __pyx_L1_error) __Pyx_GOTREF(__pyx_t_22); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __Pyx_DECREF_SET(__pyx_v_cutpoints_truncated, __pyx_t_22); __pyx_t_22 = 0; __pyx_tuple__2 = PyTuple_Pack(2, __pyx_slice_, __pyx_int_0); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 211, __pyx_L1_error) __Pyx_GOTREF(__pyx_tuple__2); __Pyx_GIVEREF(__pyx_tuple__2);
212:
+213: return cutpoints_truncated
__Pyx_XDECREF(__pyx_r); __Pyx_INCREF(__pyx_v_cutpoints_truncated); __pyx_r = __pyx_v_cutpoints_truncated; goto __pyx_L0;