From b93c410b19a7ba3540e0c1b34a87758343eb2d7a Mon Sep 17 00:00:00 2001 From: JoeRenaud-Laptop Date: Tue, 3 Oct 2023 13:57:29 -0400 Subject: [PATCH] Changed expected size calculation --- CHANGES.md | 6 + CyRK/cy/common.pxd | 15 + CyRK/cy/common.pyx | 22 +- CyRK/cy/cyrk.pyx | 66 ++- CyRK/cy/cysolver.pxd | 2 +- CyRK/cy/cysolver.pyx | 86 ++-- Tests/Cython Experiments.ipynb | 856 ++++++--------------------------- pyproject.toml | 2 +- 8 files changed, 291 insertions(+), 764 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f3db5cc..5c67ed4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,12 @@ New Features: - `CySolver.change_y0_pointer` - Changes the y0 pointer without having to pass memoryviews. - `CySolver.change_t_eval_pointer` - Changes the t_eval pointer without having to pass memoryviews. +Performance: +- Improved how `CySolver` and `cyrk_ode` expected size is calculated and how much it grows with each concat. + +Other Changes: +- Moved some common constants for both `CySolver` and `cyrk_ode` out of their files and into `cy.common`. + #### v0.8.2 (2023-09-25) New Features: diff --git a/CyRK/cy/common.pxd b/CyRK/cy/common.pxd index 4729bdc..957d343 100644 --- a/CyRK/cy/common.pxd +++ b/CyRK/cy/common.pxd @@ -3,6 +3,21 @@ from libcpp cimport bool as bool_cpp_t from CyRK.rk.rk cimport double_numeric +cdef double SAFETY +cdef double MIN_FACTOR +cdef double MAX_FACTOR +cdef double MAX_STEP +cdef double INF +cdef double EPS +cdef double EPS_10 +cdef double EPS_100 +cdef Py_ssize_t MAX_INT_SIZE +cdef Py_ssize_t MAX_SIZET_SIZE +cdef double MIN_ARRAY_PREALLOCATE_SIZE +cdef double MAX_ARRAY_PREALLOCATE_SIZE +cdef double ARRAY_PREALLOC_TABS_SCALE +cdef double ARRAY_PREALLOC_RTOL_SCALE + cdef void interpolate( double* time_domain_full, double* time_domain_reduced, diff --git a/CyRK/cy/common.pyx b/CyRK/cy/common.pyx index 1b79f6e..b0bd608 100644 --- a/CyRK/cy/common.pyx +++ b/CyRK/cy/common.pyx @@ -2,10 +2,30 @@ # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False import cython +from libc.math cimport INFINITY as INF +from libc.float cimport DBL_EPSILON as EPS +from libc.stdint cimport SIZE_MAX, INT32_MAX from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free - from CyRK.array.interp cimport interp_array_ptr, interp_complex_array_ptr +# # Integration Constants +# Multiply steps computed from asymptotic behaviour of errors by this. +cdef double SAFETY = 0.9 +cdef double MIN_FACTOR = 0.2 # Minimum allowed decrease in a step size. +cdef double MAX_FACTOR = 10. # Maximum allowed increase in a step size. +cdef double MAX_STEP = INF +cdef double EPS_10 = EPS * 10. +cdef double EPS_100 = EPS * 100. +cdef Py_ssize_t MAX_SIZET_SIZE = (0.95 * SIZE_MAX) +cdef Py_ssize_t MAX_INT_SIZE = (0.95 * INT32_MAX) + +# # Memory management constants +cdef double MIN_ARRAY_PREALLOCATE_SIZE = 100. +cdef double MAX_ARRAY_PREALLOCATE_SIZE = 1_000_000. +cdef double ARRAY_PREALLOC_TABS_SCALE = 1000. # A delta_t_abs higher than this value will start to grow array size. +cdef double ARRAY_PREALLOC_RTOL_SCALE = 1.0e-6 # A rtol lower than this value will start to grow array size. + + cdef void interpolate( double* time_domain_full, double* time_domain_reduced, diff --git a/CyRK/cy/cyrk.pyx b/CyRK/cy/cyrk.pyx index e55e6b8..75c9fb5 100644 --- a/CyRK/cy/cyrk.pyx +++ b/CyRK/cy/cyrk.pyx @@ -13,19 +13,9 @@ from libcpp cimport bool as bool_cpp_t from libc.math cimport sqrt, fabs, nextafter, fmax, fmin, NAN from CyRK.rk.rk cimport double_numeric, find_rk_properties, populate_rk_arrays -from CyRK.cy.common cimport interpolate - -# # Integration Constants -# Multiply steps computed from asymptotic behaviour of errors by this. -cdef double SAFETY = 0.9 -cdef double MIN_FACTOR = 0.2 # Minimum allowed decrease in a step size. -cdef double MAX_FACTOR = 10. # Maximum allowed increase in a step size. -cdef double MAX_STEP = np.inf -cdef double INF = np.inf -cdef double EPS = np.finfo(np.float64).eps -cdef double EPS_10 = EPS * 10. -cdef double EPS_100 = EPS * 100. -cdef Py_ssize_t MAX_INT_SIZE = int(0.95 * sys.maxsize) +from CyRK.cy.common cimport interpolate, SAFETY, MIN_FACTOR, MAX_FACTOR, MAX_STEP, INF, EPS, EPS_10, EPS_100, \ + MAX_INT_SIZE, MIN_ARRAY_PREALLOCATE_SIZE, MAX_ARRAY_PREALLOCATE_SIZE, \ + ARRAY_PREALLOC_TABS_SCALE, ARRAY_PREALLOC_RTOL_SCALE cdef double cabs( @@ -288,20 +278,42 @@ def cyrk_ode( else: max_num_steps = min(max_num_steps, MAX_INT_SIZE) + # Expected size of output arrays. + + cdef Py_ssize_t expected_size_to_use, num_concats, current_size cdef double temp_expected_size - cdef Py_ssize_t expected_size_to_use, num_concats, new_size if expected_size == 0: - # CySolver will attempt to guess the best size for the output arrays. - temp_expected_size = t_delta_abs * fmax(1., (1.e-6 / rtol_min)) - temp_expected_size = fmax(temp_expected_size, 500.) - temp_expected_size = fmin(temp_expected_size, 1_000_000.) + # CySolver will attempt to guess on a best size for the arrays. + # Assume a safe bet on CPU cache size is 300KB. + temp_expected_size = 300_000. + # Doubles are (most likely) 8 bytes. + temp_expected_size = temp_expected_size / sizeof(double) + # Then there are going to be (y + num_extra) number of doubles + if capture_extra: + temp_expected_size = temp_expected_size / (y_size_dbl + num_extra) + else: + temp_expected_size = temp_expected_size / y_size_dbl + # If t_delta_abs is very large or rtol is very small, then we may need more. + temp_expected_size = \ + fmax( + temp_expected_size, + fmax( + fmax(1., t_delta_abs / ARRAY_PREALLOC_TABS_SCALE), + fmax(1., (ARRAY_PREALLOC_RTOL_SCALE / rtol_min)) + ) + ) + # Fix values that are very small/large + temp_expected_size = fmax(temp_expected_size, MIN_ARRAY_PREALLOCATE_SIZE) + temp_expected_size = fmin(temp_expected_size, MAX_ARRAY_PREALLOCATE_SIZE) + # Store result as int expected_size_to_use = temp_expected_size else: expected_size_to_use = expected_size - # This variable tracks how many times the storage arrays have been appended. - # It starts at 1 since there is at least one storage array present. - num_concats = 1 + # Set the current size to the expected size. + # `expected_size` should never change but current might grow if expected size is not large enough. + current_size = expected_size_to_use + num_concats = 1 # Initialize live variable arrays cdef double_numeric* y_old_ptr @@ -824,26 +836,28 @@ def cyrk_ode( dy_old_ptr[i] = dy_ptr[i] # Store data - if len_t >= (num_concats * expected_size_to_use): + if len_t >= current_size: # There is more data then we have room in our arrays. # Build new arrays with more space. # OPT: Note this is an expensive operation. num_concats += 1 - new_size = num_concats * expected_size_to_use + + # Grow the array by 50% its current value + current_size = (current_size * (1.5)) time_domain_array_ptr = PyMem_Realloc(time_domain_array_ptr, - new_size * sizeof(double)) + current_size * sizeof(double)) if not time_domain_array_ptr: raise MemoryError() y_results_array_ptr = PyMem_Realloc(y_results_array_ptr, - y_size * new_size * sizeof(double_numeric)) + y_size * current_size * sizeof(double_numeric)) if not y_results_array_ptr: raise MemoryError() if capture_extra: extra_array_ptr = PyMem_Realloc(extra_array_ptr, - num_extra * new_size * sizeof(double_numeric)) + num_extra * current_size * sizeof(double_numeric)) if not extra_array_ptr: raise MemoryError() diff --git a/CyRK/cy/cysolver.pxd b/CyRK/cy/cysolver.pxd index ce7d4c9..c040ec1 100644 --- a/CyRK/cy/cysolver.pxd +++ b/CyRK/cy/cysolver.pxd @@ -44,7 +44,7 @@ cdef class CySolver: cdef double* atols_ptr cdef double first_step, max_step cdef Py_ssize_t max_num_steps - cdef Py_ssize_t expected_size, num_concats, + cdef Py_ssize_t expected_size, current_size, num_concats cdef bool_cpp_t recalc_first_step # -- Interpolation info diff --git a/CyRK/cy/cysolver.pyx b/CyRK/cy/cysolver.pyx index cb2ce75..1d00817 100644 --- a/CyRK/cy/cysolver.pyx +++ b/CyRK/cy/cysolver.pyx @@ -13,19 +13,9 @@ cimport numpy as np np.import_array() from CyRK.rk.rk cimport find_rk_properties, populate_rk_arrays -from CyRK.cy.common cimport interpolate - -# # Integration Constants -# Multiply steps computed from asymptotic behaviour of errors by this. -cdef double SAFETY = 0.9 -cdef double MIN_FACTOR = 0.2 # Minimum allowed decrease in a step size. -cdef double MAX_FACTOR = 10. # Maximum allowed increase in a step size. -cdef double MAX_STEP = np.inf -cdef double INF = np.inf -cdef double EPS = np.finfo(np.float64).eps -cdef double EPS_10 = EPS * 10. -cdef double EPS_100 = EPS * 100. -cdef Py_ssize_t MAX_INT_SIZE = int(0.95 * sys.maxsize) +from CyRK.cy.common cimport interpolate, SAFETY, MIN_FACTOR, MAX_FACTOR, MAX_STEP, INF, EPS, EPS_10, EPS_100, \ + MAX_INT_SIZE, MIN_ARRAY_PREALLOCATE_SIZE, MAX_ARRAY_PREALLOCATE_SIZE, \ + ARRAY_PREALLOC_TABS_SCALE, ARRAY_PREALLOC_RTOL_SCALE cdef (double, double) EMPTY_T_SPAN = (NAN, NAN) @@ -405,17 +395,54 @@ cdef class CySolver: raise AttributeError('Negative number of max steps provided.') else: self.max_num_steps = min(max_num_steps, MAX_INT_SIZE) + + # Determine extra outputs + self.capture_extra = capture_extra + # To avoid memory access violations we need to set the extra output arrays no matter if they are used. + # If not used, just set them to size zero. + if self.capture_extra: + if num_extra <= 0: + self.status = -8 + raise AttributeError('Capture extra set to True, but number of extra set to 0 (or negative).') + self.num_extra = num_extra + else: + # Even though we are not capturing extra, we still want num_extra to be equal to 1 so that nan arrays + # are properly initialized + self.num_extra = 1 # Expected size of output arrays. cdef double temp_expected_size if expected_size == 0: # CySolver will attempt to guess on a best size for the arrays. - temp_expected_size = 100. * self.t_delta_abs * fmax(1., (1.e-6 / rtol_min)) - temp_expected_size = fmax(temp_expected_size, 100.) - temp_expected_size = fmin(temp_expected_size, 10_000_000.) + # Assume a safe bet on CPU cache size is 300KB. + temp_expected_size = 300_000. + # Doubles are (most likely) 8 bytes. + temp_expected_size = temp_expected_size / sizeof(double) + # Then there are going to be (y + num_extra) number of doubles + if self.capture_extra: + temp_expected_size = temp_expected_size / (self.y_size_dbl + self.num_extra) + else: + temp_expected_size = temp_expected_size / self.y_size_dbl + # If t_delta_abs is very large or rtol is very small, then we may need more. + temp_expected_size = \ + fmax( + temp_expected_size, + fmax( + fmax(1., self.t_delta_abs / ARRAY_PREALLOC_TABS_SCALE), + fmax(1., (ARRAY_PREALLOC_RTOL_SCALE / rtol_min)) + ) + ) + # Fix values that are very small/large + temp_expected_size = fmax(temp_expected_size, MIN_ARRAY_PREALLOCATE_SIZE) + temp_expected_size = fmin(temp_expected_size, MAX_ARRAY_PREALLOCATE_SIZE) + # Store result as int self.expected_size = temp_expected_size else: self.expected_size = expected_size + # Set the current size to the expected size. + # `expected_size` should never change but current might grow if expected size is not large enough. + self.current_size = self.expected_size + # This variable tracks how many times the storage arrays have been appended. # It starts at 1 since there is at least one storage array present. self.num_concats = 1 @@ -451,20 +478,6 @@ cdef class CySolver: if not self.dy_old_ptr: raise MemoryError() - # Determine extra outputs - self.capture_extra = capture_extra - # To avoid memory access violations we need to set the extra output arrays no matter if they are used. - # If not used, just set them to size zero. - if self.capture_extra: - if num_extra <= 0: - self.status = -8 - raise AttributeError('Capture extra set to True, but number of extra set to 0 (or negative).') - self.num_extra = num_extra - else: - # Even though we are not capturing extra, we still want num_extra to be equal to 1 so that nan arrays - # are properly initialized - self.num_extra = 1 - self.extra_output_init_ptr = PyMem_Malloc(self.num_extra * sizeof(double)) if not self.extra_output_init_ptr: raise MemoryError() @@ -650,6 +663,7 @@ cdef class CySolver: self.step_size = self.first_step # Reset output storage + self.current_size = self.expected_size self.num_concats = 1 # Reset storage variables to clear any old solutions and to avoid access violations if solve() is not called. @@ -1050,26 +1064,28 @@ cdef class CySolver: break # Store data - if self.len_t >= (self.num_concats * self.expected_size): + if self.len_t >= self.current_size: # There is more data then we have room in our arrays. # Build new arrays with more space. # OPT: Note this is an expensive operation. self.num_concats += 1 - new_size = self.num_concats * self.expected_size + + # Grow the array by 50% its current value + self.current_size = (self.current_size * (1.5)) time_domain_array_ptr = PyMem_Realloc(time_domain_array_ptr, - new_size * sizeof(double)) + self.current_size * sizeof(double)) if not time_domain_array_ptr: raise MemoryError() y_results_array_ptr = PyMem_Realloc(y_results_array_ptr, - self.y_size * new_size * sizeof(double)) + self.y_size * self.current_size * sizeof(double)) if not y_results_array_ptr: raise MemoryError() if self.capture_extra: extra_array_ptr = PyMem_Realloc(extra_array_ptr, - self.num_extra * new_size * sizeof(double)) + self.num_extra * self.current_size * sizeof(double)) if not extra_array_ptr: raise MemoryError() diff --git a/Tests/Cython Experiments.ipynb b/Tests/Cython Experiments.ipynb index fc88d1c..88e3054 100644 --- a/Tests/Cython Experiments.ipynb +++ b/Tests/Cython Experiments.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "id": "f79e8919", "metadata": {}, "outputs": [], @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "54f02ade", "metadata": {}, "outputs": [], @@ -23,40 +23,42 @@ }, { "cell_type": "code", - "execution_count": 4, - "id": "829e2f11", - "metadata": { - "scrolled": false - }, + "execution_count": 19, + "id": "ee511908", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Content of stdout:\n", - "_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.c\r\n", - "C:\\Users\\joepr\\.ipython\\cython\\_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.c(1541): warning C4005: '__pyx_nonatomic_int_type': macro redefinition\r\n", - "C:\\Users\\joepr\\.ipython\\cython\\_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.c(1492): note: see previous definition of '__pyx_nonatomic_int_type'\r\n", - " Creating library C:\\Users\\joepr\\.ipython\\cython\\Users\\joepr\\.ipython\\cython\\_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.cp311-win_amd64.lib and object C:\\Users\\joepr\\.ipython\\cython\\Users\\joepr\\.ipython\\cython\\_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.cp311-win_amd64.exp\r\n", - "Generating code\r\n", - "Finished generating code" + "8\n", + "2.220446049250313e-16\n", + "18446744073709551615\n", + "9223372036854775807\n", + "9223372036854775807\n", + "8\n", + "8\n", + "2\n", + "4\n", + "8\n", + "4\n" ] }, { "data": { "text/html": [ "\n", - "\n", + "\n", "\n", "\n", " \n", - " Cython: _cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.pyx\n", + " Cython: _cython_magic_059e990da63986b839f2cb7a88a34bb5.pyx\n", " \n", "\n", "\n", - "

Generated by Cython 3.0.0

\n", + "

Generated by Cython 0.29.35

\n", "

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

\n", - "
+001: # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False
\n", - "
  __pyx_t_7 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 1, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_7);\n",
-       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_7) < 0) __PYX_ERR(1, 1, __pyx_L1_error)\n",
-       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
-       "
 002: 
\n", - "
 003: from libcpp cimport bool as bool_cpp_t
\n", - "
 004: 
\n", - "
+005: import numpy as np
\n", - "
  __pyx_t_7 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 5, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_7);\n",
-       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_7) < 0) __PYX_ERR(1, 5, __pyx_L1_error)\n",
-       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
-       "
 006: 
\n", - "
 007: 
\n", - "
 008: import cython
\n", - "
 009: cimport cython
\n", - "
 010: 
\n", - "
 011: cdef extern from *:
\n", - "
 012:     """
\n", - "
 013:     /* This is C code which will be put
\n", - "
 014:      * in the .c file output by Cython */
\n", - "
 015:     #include "Python.h"
\n", - "
 016:     
\n", - "
 017:     Py_ssize_t LIKELY_IN_CACHE_SIZE = 8;
\n", - "
 018: 
\n", - "
 019:     Py_ssize_t binary_search_with_guess(double key, double* array, Py_ssize_t length, Py_ssize_t guess){
\n", - "
 020:         Py_ssize_t imin = 0;
\n", - "
 021:         Py_ssize_t imax = length;
\n", - "
 022:         Py_ssize_t imid = 0;
\n", - "
 023: 
\n", - "
 024:         if (key > array[length - 1]){
\n", - "
 025:             return length;
\n", - "
 026:         }
\n", - "
 027:         else if (key < array[0]){
\n", - "
 028:             return -1;
\n", - "
 029:         }
\n", - "
 030: 
\n", - "
 031:         if (guess > (length - 3)){
\n", - "
 032:             guess = length - 3;
\n", - "
 033:         }
\n", - "
 034:         if (guess < 1) {
\n", - "
 035:             guess = 1;
\n", - "
 036:         }
\n", - "
 037: 
\n", - "
 038:         /* Check most likely values: guess - 1, guess, guess + 1 */
\n", - "
 039:         if (key < array[guess]){
\n", - "
 040:             if (key < array[guess - 1]){
\n", - "
 041:                 imax = guess - 1;
\n", - "
 042:                 /* last attempt to restrict search to items in cache */
\n", - "
 043:                 if ((guess > LIKELY_IN_CACHE_SIZE) && (key >= array[guess - LIKELY_IN_CACHE_SIZE])){
\n", - "
 044:                     imin = guess - LIKELY_IN_CACHE_SIZE;
\n", - "
 045:                 }
\n", - "
 046:             }
\n", - "
 047:             else {
\n", - "
 048:                 return guess - 1;
\n", - "
 049:             }
\n", - "
 050:         }
\n", - "
 051:         else{
\n", - "
 052:             if (key < array[guess + 1]){
\n", - "
 053:                 return guess;
\n", - "
 054:             }
\n", - "
 055:             else{
\n", - "
 056:                 if (key < array[guess + 2]){
\n", - "
 057:                     return guess + 1;
\n", - "
 058:                 }
\n", - "
 059:                 else {
\n", - "
 060:                     imin = guess + 2;
\n", - "
 061:                     /* last attempt to restrict search to items in cache */
\n", - "
 062:                     if ((guess < (length - LIKELY_IN_CACHE_SIZE - 1)) && (key < array[guess + LIKELY_IN_CACHE_SIZE])){
\n", - "
 063:                         imax = guess + LIKELY_IN_CACHE_SIZE;
\n", - "
 064:                     }
\n", - "
 065:                 }
\n", - "
 066:             }
\n", - "
 067:         }
\n", - "
 068:         /* Finally, find index by bisection */
\n", - "
 069:         while (imin < imax){
\n", - "
 070:             imid = imin + ((imax - imin) >> 1);
\n", - "
 071:             if (key >= array[imid]){
\n", - "
 072:                 imin = imid + 1;
\n", - "
 073:             }
\n", - "
 074:             else{
\n", - "
 075:                 imax = imid;
\n", - "
 076:             }
\n", - "
 077:         }
\n", - "
 078: 
\n", - "
 079:         return imin - 1;
\n", - "
 080:     
\n", - "
 081:     }
\n", - "
 082:     """
\n", - "
 083:     Py_ssize_t binary_search_with_guess(double key, double* array, Py_ssize_t length, Py_ssize_t guess) noexcept nogil
\n", - "
 084: 
\n", - "
 085: from libc.math cimport isnan
\n", - "
 086: 
\n", - "
 087: # Get machine precision.
\n", - "
 088: cdef double EPS
\n", - "
+089: EPS = np.finfo(dtype=np.float64).eps
\n", - "
  __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_np); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_7);\n",
-       "  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_finfo); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_4);\n",
-       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
-       "  __pyx_t_7 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_7);\n",
-       "  __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_np); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_5);\n",
-       "  __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_float64); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_9);\n",
-       "  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;\n",
-       "  if (PyDict_SetItem(__pyx_t_7, __pyx_n_s_dtype, __pyx_t_9) < 0) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;\n",
-       "  __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_empty_tuple, __pyx_t_7); if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_9);\n",
-       "  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;\n",
-       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
-       "  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_n_s_eps); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_7);\n",
-       "  __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;\n",
-       "  __pyx_t_10 = __pyx_PyFloat_AsDouble(__pyx_t_7); if (unlikely((__pyx_t_10 == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 89, __pyx_L1_error)\n",
-       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
-       "  __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_EPS = __pyx_t_10;\n",
-       "
 090: 
\n", - "
 091: # Determine cache limits.
\n", - "
+092: cdef Py_ssize_t LIKELY_IN_CACHE_SIZE = 8
\n", - "
  __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE = 8;\n",
-       "
 093: 
\n", - "
 094: 
\n", - "
+095: cdef Py_ssize_t binary_search_with_guess_2(double key, double[:] array, Py_ssize_t length, Py_ssize_t guess) noexcept nogil:
\n", - "
static Py_ssize_t __pyx_f_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_binary_search_with_guess_2(double __pyx_v_key, __Pyx_memviewslice __pyx_v_array, Py_ssize_t __pyx_v_length, Py_ssize_t __pyx_v_guess) {\n",
-       "  Py_ssize_t __pyx_v_imin;\n",
-       "  Py_ssize_t __pyx_v_imax;\n",
-       "  Py_ssize_t __pyx_v_imid;\n",
-       "  Py_ssize_t __pyx_r;\n",
-       "/* … */\n",
-       "  /* function exit code */\n",
-       "  __pyx_L0:;\n",
-       "  return __pyx_r;\n",
-       "}\n",
-       "
 096:     """ Binary search with guess.
\n", - "
 097: 
\n", - "
 098:     Based on `numpy`'s `binary_search_with_guess` function.
\n", - "
 099: 
\n", - "
 100:     Parameters
\n", - "
 101:     ----------
\n", - "
 102:     key : float
\n", - "
 103:         Key index to search for.
\n", - "
 104:     array : np.ndarray
\n", - "
 105:         Array to search in.
\n", - "
 106:     length : int (unsigned)
\n", - "
 107:         Length of array.
\n", - "
 108:     guess : int (unsigned)
\n", - "
 109:         Initial guess of where key might be.
\n", - "
 110: 
\n", - "
 111:     Returns
\n", - "
 112:     -------
\n", - "
 113:     guess : int (unsigned)
\n", - "
 114:         Corrected guess after search.
\n", - "
 115:     """
\n", - "
 116: 
\n", - "
+117:     cdef Py_ssize_t imin = 0
\n", - "
  __pyx_v_imin = 0;\n",
-       "
+118:     cdef Py_ssize_t imax = length
\n", - "
  __pyx_v_imax = __pyx_v_length;\n",
-       "
 119: 
\n", - "
+120:     if key > array[length - 1]:
\n", - "
  __pyx_t_1 = (__pyx_v_length - 1);\n",
-       "  __pyx_t_2 = (__pyx_v_key > (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "  if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "  }\n",
-       "
+121:         return length
\n", - "
    __pyx_r = __pyx_v_length;\n",
-       "    goto __pyx_L0;\n",
-       "
+122:     elif key < array[0]:
\n", - "
  __pyx_t_1 = 0;\n",
-       "  __pyx_t_2 = (__pyx_v_key < (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "  if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "  }\n",
-       "
+123:         return -1
\n", - "
    __pyx_r = -1L;\n",
-       "    goto __pyx_L0;\n",
-       "
 124: 
\n", - "
 125:     # If len <= 4 use linear search.
\n", - "
 126:     # if length <= 4:
\n", - "
 127:     #     raise NotImplemented
\n", - "
 128: 
\n", - "
+129:     if guess > (length - 3):
\n", - "
  __pyx_t_2 = (__pyx_v_guess > (__pyx_v_length - 3));\n",
-       "  if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "  }\n",
-       "
+130:         guess = length - 3
\n", - "
    __pyx_v_guess = (__pyx_v_length - 3);\n",
-       "
+131:     if guess < 1:
\n", - "
  __pyx_t_2 = (__pyx_v_guess < 1);\n",
-       "  if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "  }\n",
-       "
+132:         guess = 1
\n", - "
    __pyx_v_guess = 1;\n",
-       "
 133: 
\n", - "
 134:     # Check most likely values: guess - 1, guess, guess + 1
\n", - "
+135:     if key < array[guess]:
\n", - "
  __pyx_t_1 = __pyx_v_guess;\n",
-       "  __pyx_t_2 = (__pyx_v_key < (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "  if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "    goto __pyx_L6;\n",
-       "  }\n",
-       "
+136:         if key < array[guess - 1]:
\n", - "
    __pyx_t_1 = (__pyx_v_guess - 1);\n",
-       "    __pyx_t_2 = (__pyx_v_key < (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "    if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "      goto __pyx_L7;\n",
-       "    }\n",
-       "
+137:             imax = guess - 1
\n", - "
      __pyx_v_imax = (__pyx_v_guess - 1);\n",
-       "
 138:             # last attempt to restrict search to items in cache
\n", - "
+139:             if guess > LIKELY_IN_CACHE_SIZE and key >= array[guess - LIKELY_IN_CACHE_SIZE]:
\n", - "
      __pyx_t_3 = (__pyx_v_guess > __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE);\n",
-       "      if (__pyx_t_3) {\n",
-       "      } else {\n",
-       "        __pyx_t_2 = __pyx_t_3;\n",
-       "        goto __pyx_L9_bool_binop_done;\n",
-       "      }\n",
-       "      __pyx_t_1 = (__pyx_v_guess - __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE);\n",
-       "      __pyx_t_3 = (__pyx_v_key >= (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "      __pyx_t_2 = __pyx_t_3;\n",
-       "      __pyx_L9_bool_binop_done:;\n",
-       "      if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "      }\n",
-       "
+140:                 imin = guess - LIKELY_IN_CACHE_SIZE
\n", - "
        __pyx_v_imin = (__pyx_v_guess - __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE);\n",
-       "
 141: 
\n", - "
 142:         else:
\n", - "
+143:             return guess - 1
\n", - "
    /*else*/ {\n",
-       "      __pyx_r = (__pyx_v_guess - 1);\n",
-       "      goto __pyx_L0;\n",
-       "    }\n",
-       "    __pyx_L7:;\n",
-       "
 144:     else:
\n", - "
+145:         if key < array[guess + 1]:
\n", - "
  /*else*/ {\n",
-       "    __pyx_t_1 = (__pyx_v_guess + 1);\n",
-       "    __pyx_t_2 = (__pyx_v_key < (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "    if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "    }\n",
-       "
+146:             return guess
\n", - "
      __pyx_r = __pyx_v_guess;\n",
-       "      goto __pyx_L0;\n",
-       "
 147:         else:
\n", - "
+148:             if key < array[guess + 2]:
\n", - "
    /*else*/ {\n",
-       "      __pyx_t_1 = (__pyx_v_guess + 2);\n",
-       "      __pyx_t_2 = (__pyx_v_key < (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "      if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "      }\n",
-       "
+149:                 return guess + 1
\n", - "
        __pyx_r = (__pyx_v_guess + 1);\n",
-       "        goto __pyx_L0;\n",
-       "
 150:             else:
\n", - "
+151:                 imin = guess + 2
\n", - "
      /*else*/ {\n",
-       "        __pyx_v_imin = (__pyx_v_guess + 2);\n",
-       "
 152:                 # last attempt to restrict search to items in cache
\n", - "
+153:                 if guess < (length - LIKELY_IN_CACHE_SIZE - 1) and key < array[guess + LIKELY_IN_CACHE_SIZE]:
\n", - "
        __pyx_t_3 = (__pyx_v_guess < ((__pyx_v_length - __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE) - 1));\n",
-       "        if (__pyx_t_3) {\n",
-       "        } else {\n",
-       "          __pyx_t_2 = __pyx_t_3;\n",
-       "          goto __pyx_L14_bool_binop_done;\n",
-       "        }\n",
-       "        __pyx_t_1 = (__pyx_v_guess + __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE);\n",
-       "        __pyx_t_3 = (__pyx_v_key < (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "        __pyx_t_2 = __pyx_t_3;\n",
-       "        __pyx_L14_bool_binop_done:;\n",
-       "        if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "        }\n",
-       "      }\n",
-       "    }\n",
-       "  }\n",
-       "  __pyx_L6:;\n",
-       "
+154:                     imax = guess + LIKELY_IN_CACHE_SIZE
\n", - "
          __pyx_v_imax = (__pyx_v_guess + __pyx_v_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_LIKELY_IN_CACHE_SIZE);\n",
-       "
 155: 
\n", - "
 156:     # Finally, find index by bisection
\n", - "
 157:     cdef Py_ssize_t imid
\n", - "
+158:     while imin < imax:
\n", - "
  while (1) {\n",
-       "    __pyx_t_2 = (__pyx_v_imin < __pyx_v_imax);\n",
-       "    if (!__pyx_t_2) break;\n",
-       "
+159:         imid = imin + ((imax - imin) >> 1)
\n", - "
    __pyx_v_imid = (__pyx_v_imin + ((__pyx_v_imax - __pyx_v_imin) >> 1));\n",
-       "
+160:         if key >= array[imid]:
\n", - "
    __pyx_t_1 = __pyx_v_imid;\n",
-       "    __pyx_t_2 = (__pyx_v_key >= (*((double *) ( /* dim=0 */ (__pyx_v_array.data + __pyx_t_1 * __pyx_v_array.strides[0]) ))));\n",
-       "    if (__pyx_t_2) {\n",
-       "/* … */\n",
-       "      goto __pyx_L18;\n",
-       "    }\n",
-       "
+161:             imin = imid + 1
\n", - "
      __pyx_v_imin = (__pyx_v_imid + 1);\n",
-       "
 162:         else:
\n", - "
+163:             imax = imid
\n", - "
    /*else*/ {\n",
-       "      __pyx_v_imax = __pyx_v_imid;\n",
-       "    }\n",
-       "    __pyx_L18:;\n",
-       "  }\n",
-       "
 164: 
\n", - "
+165:     return imin - 1
\n", - "
  __pyx_r = (__pyx_v_imin - 1);\n",
-       "  goto __pyx_L0;\n",
-       "
 166: 
\n", - "
 167: 
\n", - "
+168: cpdef double interp(double desired_x, double[:] x_domain, double[:] dependent_values, Py_ssize_t provided_j = -2) noexcept nogil:
\n", - "
static PyObject *__pyx_pw_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_1interp(PyObject *__pyx_self, \n",
-       "#if CYTHON_METH_FASTCALL\n",
-       "PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds\n",
-       "#else\n",
-       "PyObject *__pyx_args, PyObject *__pyx_kwds\n",
-       "#endif\n",
-       "); /*proto*/\n",
-       "static double __pyx_f_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp(double __pyx_v_desired_x, __Pyx_memviewslice __pyx_v_x_domain, __Pyx_memviewslice __pyx_v_dependent_values, CYTHON_UNUSED int __pyx_skip_dispatch, struct __pyx_opt_args_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp *__pyx_optional_args) {\n",
-       "  Py_ssize_t __pyx_v_provided_j = ((Py_ssize_t)-2L);\n",
-       "  Py_ssize_t __pyx_v_len_x;\n",
-       "  double __pyx_v_left_value;\n",
-       "  double __pyx_v_right_value;\n",
-       "  Py_ssize_t __pyx_v_j;\n",
-       "  double __pyx_v_slope;\n",
-       "  double __pyx_v_result;\n",
-       "  double __pyx_v_fp_at_j;\n",
-       "  double __pyx_v_xp_at_j;\n",
-       "  double __pyx_v_fp_at_jp1;\n",
-       "  double __pyx_v_xp_at_jp1;\n",
-       "  double __pyx_r;\n",
-       "  if (__pyx_optional_args) {\n",
-       "    if (__pyx_optional_args->__pyx_n > 0) {\n",
-       "      __pyx_v_provided_j = __pyx_optional_args->provided_j;\n",
-       "    }\n",
-       "  }\n",
-       "/* … */\n",
-       "  /* function exit code */\n",
-       "  __pyx_L0:;\n",
-       "  return __pyx_r;\n",
-       "}\n",
-       "\n",
-       "/* Python wrapper */\n",
-       "static PyObject *__pyx_pw_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_1interp(PyObject *__pyx_self, \n",
-       "#if CYTHON_METH_FASTCALL\n",
-       "PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds\n",
-       "#else\n",
-       "PyObject *__pyx_args, PyObject *__pyx_kwds\n",
-       "#endif\n",
-       "); /*proto*/\n",
-       "PyDoc_STRVAR(__pyx_doc_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp, \" Interpolation function for floats.\\n\\n    Provided a domain, `x_domain` and a dependent array `dependent_values` search domain for value closest to \\n    `desired_x` and return the value of `dependent_values` at that location if it is defined. Otherwise, use local \\n    slopes of `x_domain` and `dependent_values` to interpolate a value of `dependent_values` at `desired_x`.\\n\\n    Based on `numpy`'s `interp` function.\\n\\n    Parameters\\n    ----------\\n    desired_x : float\\n        Location where `dependent_variables` is desired.\\n    x_domain : np.ndarray[float]\\n        Domain to search for the correct location.\\n    dependent_values : np.ndarray[float]\\n        Dependent values that are to be returned after search and interpolation.\\n    provided_j : int\\n        Give a j index from a previous interpolation to improve performance.\\n\\n    Returns\\n    -------\\n    result : float\\n        Desired value of `dependent_values`.\\n\\n    \");\n",
-       "static PyMethodDef __pyx_mdef_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_1interp = {\"interp\", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_1interp, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp};\n",
-       "static PyObject *__pyx_pw_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_1interp(PyObject *__pyx_self, \n",
-       "#if CYTHON_METH_FASTCALL\n",
-       "PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds\n",
-       "#else\n",
-       "PyObject *__pyx_args, PyObject *__pyx_kwds\n",
-       "#endif\n",
-       ") {\n",
-       "  double __pyx_v_desired_x;\n",
-       "  __Pyx_memviewslice __pyx_v_x_domain = { 0, 0, { 0 }, { 0 }, { 0 } };\n",
-       "  __Pyx_memviewslice __pyx_v_dependent_values = { 0, 0, { 0 }, { 0 }, { 0 } };\n",
-       "  Py_ssize_t __pyx_v_provided_j;\n",
-       "  #if !CYTHON_METH_FASTCALL\n",
-       "  CYTHON_UNUSED const Py_ssize_t __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);\n",
-       "  #endif\n",
-       "  CYTHON_UNUSED PyObject *const *__pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);\n",
-       "  PyObject *__pyx_r = 0;\n",
-       "  __Pyx_RefNannyDeclarations\n",
-       "  __Pyx_RefNannySetupContext(\"interp (wrapper)\", 0);\n",
-       "  {\n",
-       "    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_desired_x,&__pyx_n_s_x_domain,&__pyx_n_s_dependent_values,&__pyx_n_s_provided_j,0};\n",
-       "    PyObject* values[4] = {0,0,0,0};\n",
-       "    if (__pyx_kwds) {\n",
-       "      Py_ssize_t kw_args;\n",
-       "      switch (__pyx_nargs) {\n",
-       "        case  4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  2: values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  1: values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  0: break;\n",
-       "        default: goto __pyx_L5_argtuple_error;\n",
-       "      }\n",
-       "      kw_args = __Pyx_NumKwargs_FASTCALL(__pyx_kwds);\n",
-       "      switch (__pyx_nargs) {\n",
-       "        case  0:\n",
-       "        if (likely((values[0] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_desired_x)) != 0)) kw_args--;\n",
-       "        else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "        else goto __pyx_L5_argtuple_error;\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  1:\n",
-       "        if (likely((values[1] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_x_domain)) != 0)) kw_args--;\n",
-       "        else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "        else {\n",
-       "          __Pyx_RaiseArgtupleInvalid(\"interp\", 0, 3, 4, 1); __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "        }\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  2:\n",
-       "        if (likely((values[2] = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_dependent_values)) != 0)) kw_args--;\n",
-       "        else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "        else {\n",
-       "          __Pyx_RaiseArgtupleInvalid(\"interp\", 0, 3, 4, 2); __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "        }\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  3:\n",
-       "        if (kw_args > 0) {\n",
-       "          PyObject* value = __Pyx_GetKwValue_FASTCALL(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_provided_j);\n",
-       "          if (value) { values[3] = value; kw_args--; }\n",
-       "          else if (unlikely(PyErr_Occurred())) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "        }\n",
-       "      }\n",
-       "      if (unlikely(kw_args > 0)) {\n",
-       "        const Py_ssize_t kwd_pos_args = __pyx_nargs;\n",
-       "        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, \"interp\") < 0)) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "      }\n",
-       "    } else {\n",
-       "      switch (__pyx_nargs) {\n",
-       "        case  4: values[3] = __Pyx_Arg_FASTCALL(__pyx_args, 3);\n",
-       "        CYTHON_FALLTHROUGH;\n",
-       "        case  3: values[2] = __Pyx_Arg_FASTCALL(__pyx_args, 2);\n",
-       "        values[1] = __Pyx_Arg_FASTCALL(__pyx_args, 1);\n",
-       "        values[0] = __Pyx_Arg_FASTCALL(__pyx_args, 0);\n",
-       "        break;\n",
-       "        default: goto __pyx_L5_argtuple_error;\n",
-       "      }\n",
-       "    }\n",
-       "    __pyx_v_desired_x = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_desired_x == (double)-1) && PyErr_Occurred())) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "    __pyx_v_x_domain = __Pyx_PyObject_to_MemoryviewSlice_ds_double(values[1], PyBUF_WRITABLE); if (unlikely(!__pyx_v_x_domain.memview)) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "    __pyx_v_dependent_values = __Pyx_PyObject_to_MemoryviewSlice_ds_double(values[2], PyBUF_WRITABLE); if (unlikely(!__pyx_v_dependent_values.memview)) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "    if (values[3]) {\n",
-       "      __pyx_v_provided_j = __Pyx_PyIndex_AsSsize_t(values[3]); if (unlikely((__pyx_v_provided_j == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "    } else {\n",
-       "      __pyx_v_provided_j = ((Py_ssize_t)-2L);\n",
-       "    }\n",
-       "  }\n",
-       "  goto __pyx_L4_argument_unpacking_done;\n",
-       "  __pyx_L5_argtuple_error:;\n",
-       "  __Pyx_RaiseArgtupleInvalid(\"interp\", 0, 3, 4, __pyx_nargs); __PYX_ERR(1, 168, __pyx_L3_error)\n",
-       "  __pyx_L3_error:;\n",
-       "  __PYX_XCLEAR_MEMVIEW(&__pyx_v_x_domain, 1);\n",
-       "  __PYX_XCLEAR_MEMVIEW(&__pyx_v_dependent_values, 1);\n",
-       "  __Pyx_AddTraceback(\"_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.interp\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
-       "  __Pyx_RefNannyFinishContext();\n",
-       "  return NULL;\n",
-       "  __pyx_L4_argument_unpacking_done:;\n",
-       "  __pyx_r = __pyx_pf_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp(__pyx_self, __pyx_v_desired_x, __pyx_v_x_domain, __pyx_v_dependent_values, __pyx_v_provided_j);\n",
-       "  int __pyx_lineno = 0;\n",
-       "  const char *__pyx_filename = NULL;\n",
-       "  int __pyx_clineno = 0;\n",
-       "\n",
-       "  /* function exit code */\n",
-       "  __PYX_XCLEAR_MEMVIEW(&__pyx_v_x_domain, 1);\n",
-       "  __PYX_XCLEAR_MEMVIEW(&__pyx_v_dependent_values, 1);\n",
-       "  __Pyx_RefNannyFinishContext();\n",
-       "  return __pyx_r;\n",
-       "}\n",
-       "\n",
-       "static PyObject *__pyx_pf_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp(CYTHON_UNUSED PyObject *__pyx_self, double __pyx_v_desired_x, __Pyx_memviewslice __pyx_v_x_domain, __Pyx_memviewslice __pyx_v_dependent_values, Py_ssize_t __pyx_v_provided_j) {\n",
-       "  PyObject *__pyx_r = NULL;\n",
-       "  __Pyx_RefNannyDeclarations\n",
-       "  __Pyx_RefNannySetupContext(\"interp\", 0);\n",
-       "  __Pyx_XDECREF(__pyx_r);\n",
-       "  __pyx_t_2.__pyx_n = 1;\n",
-       "  __pyx_t_2.provided_j = __pyx_v_provided_j;\n",
-       "  __pyx_t_1 = __pyx_f_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp(__pyx_v_desired_x, __pyx_v_x_domain, __pyx_v_dependent_values, 0, &__pyx_t_2); \n",
-       "  __pyx_t_3 = PyFloat_FromDouble(__pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 168, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_3);\n",
-       "  __pyx_r = __pyx_t_3;\n",
-       "  __pyx_t_3 = 0;\n",
-       "  goto __pyx_L0;\n",
-       "\n",
-       "  /* function exit code */\n",
-       "  __pyx_L1_error:;\n",
-       "  __Pyx_XDECREF(__pyx_t_3);\n",
-       "  __Pyx_AddTraceback(\"_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e.interp\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
-       "  __pyx_r = NULL;\n",
-       "  __pyx_L0:;\n",
-       "  __Pyx_XGIVEREF(__pyx_r);\n",
-       "  __Pyx_RefNannyFinishContext();\n",
-       "  return __pyx_r;\n",
-       "}\n",
-       "/* … */\n",
-       "  __pyx_tuple__20 = PyTuple_Pack(4, __pyx_n_s_desired_x, __pyx_n_s_x_domain, __pyx_n_s_dependent_values, __pyx_n_s_provided_j); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(1, 168, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_tuple__20);\n",
-       "  __Pyx_GIVEREF(__pyx_tuple__20);\n",
-       "  __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(4, 0, 0, 4, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_C_Users_joepr_ipython_cython__cy, __pyx_n_s_interp, 168, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(1, 168, __pyx_L1_error)\n",
-       "/* … */\n",
-       "  __pyx_t_7 = __Pyx_CyFunction_New(&__pyx_mdef_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_1interp, 0, __pyx_n_s_interp, NULL, __pyx_n_s_cython_magic_d4222b7144831091f5, __pyx_d, ((PyObject *)__pyx_codeobj__21)); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 168, __pyx_L1_error)\n",
-       "  __Pyx_GOTREF(__pyx_t_7);\n",
-       "  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_7, __pyx_tuple__22);\n",
-       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_interp, __pyx_t_7) < 0) __PYX_ERR(1, 168, __pyx_L1_error)\n",
-       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
-       "/* … */\n",
-       "struct __pyx_opt_args_54_cython_magic_d4222b7144831091f56850783d13a87f2d82b30e_interp {\n",
-       "  int __pyx_n;\n",
-       "  Py_ssize_t provided_j;\n",
-       "};\n",
-       "
 169:     """ Interpolation function for floats.
\n", - "
 170: 
\n", - "
 171:     Provided a domain, `x_domain` and a dependent array `dependent_values` search domain for value closest to 
\n", - "
 172:     `desired_x` and return the value of `dependent_values` at that location if it is defined. Otherwise, use local 
\n", - "
 173:     slopes of `x_domain` and `dependent_values` to interpolate a value of `dependent_values` at `desired_x`.
\n", - "
 174: 
\n", - "
 175:     Based on `numpy`'s `interp` function.
\n", - "
 176: 
\n", - "
 177:     Parameters
\n", - "
 178:     ----------
\n", - "
 179:     desired_x : float
\n", - "
 180:         Location where `dependent_variables` is desired.
\n", - "
 181:     x_domain : np.ndarray[float]
\n", - "
 182:         Domain to search for the correct location.
\n", - "
 183:     dependent_values : np.ndarray[float]
\n", - "
 184:         Dependent values that are to be returned after search and interpolation.
\n", - "
 185:     provided_j : int
\n", - "
 186:         Give a j index from a previous interpolation to improve performance.
\n", - "
 187: 
\n", - "
 188:     Returns
\n", - "
 189:     -------
\n", - "
 190:     result : float
\n", - "
 191:         Desired value of `dependent_values`.
\n", - "
 192: 
\n", - "
 193:     """
\n", - "
 194: 
\n", - "
 195:     cdef Py_ssize_t len_x
\n", - "
+196:     len_x = len(x_domain)
\n", - "
  __pyx_t_1 = __Pyx_MemoryView_Len(__pyx_v_x_domain); \n",
-       "  __pyx_v_len_x = __pyx_t_1;\n",
-       "
 197:     # TODO: Needs to be at least 3 item long array. Add exception here?
\n", - "
 198: 
\n", - "
 199:     cdef double left_value
\n", - "
+200:     left_value = dependent_values[0]
\n", - "
  __pyx_t_2 = 0;\n",
-       "  __pyx_v_left_value = (*((double *) ( /* dim=0 */ (__pyx_v_dependent_values.data + __pyx_t_2 * __pyx_v_dependent_values.strides[0]) )));\n",
-       "
 201:     cdef double right_value
\n", - "
+202:     right_value = dependent_values[len_x - 1]
\n", - "
  __pyx_t_2 = (__pyx_v_len_x - 1);\n",
-       "  __pyx_v_right_value = (*((double *) ( /* dim=0 */ (__pyx_v_dependent_values.data + __pyx_t_2 * __pyx_v_dependent_values.strides[0]) )));\n",
-       "
 203: 
\n", - "
 204:     # Binary Search with Guess
\n", - "
 205:     cdef Py_ssize_t j
\n", - "
+206:     j = 0
\n", - "
  __pyx_v_j = 0;\n",
-       "
 207:     cdef double slope
\n", - "
 208: 
\n", - "
 209:     cdef double result
\n", - "
 210:     cdef double fp_at_j
\n", - "
 211:     cdef double xp_at_j
\n", - "
 212:     cdef double fp_at_jp1
\n", - "
 213:     cdef double xp_at_jp1
\n", - "
 214: 
\n", - "
 215:     # Perform binary search with guess
\n", - "
+216:     if provided_j == -2:
\n", - "
  __pyx_t_3 = (__pyx_v_provided_j == -2L);\n",
-       "  if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "    goto __pyx_L3;\n",
-       "  }\n",
-       "
 217:         # No j provided; search for it instead.
\n", - "
+218:         j = binary_search_with_guess(desired_x, &x_domain[0], len_x, j)
\n", - "
    __pyx_t_2 = 0;\n",
-       "    __pyx_v_j = binary_search_with_guess(__pyx_v_desired_x, (&(*((double *) ( /* dim=0 */ (__pyx_v_x_domain.data + __pyx_t_2 * __pyx_v_x_domain.strides[0]) )))), __pyx_v_len_x, __pyx_v_j);\n",
-       "
+219:     elif provided_j < -2:
\n", - "
  __pyx_t_3 = (__pyx_v_provided_j < -2L);\n",
-       "  if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "    goto __pyx_L3;\n",
-       "  }\n",
-       "
 220:         # Error
\n", - "
 221:         # TODO: How to handle exception handling in a cdef function... For now just repeat the search.
\n", - "
+222:         j = binary_search_with_guess(desired_x, &x_domain[0], len_x, j)
\n", - "
    __pyx_t_2 = 0;\n",
-       "    __pyx_v_j = binary_search_with_guess(__pyx_v_desired_x, (&(*((double *) ( /* dim=0 */ (__pyx_v_x_domain.data + __pyx_t_2 * __pyx_v_x_domain.strides[0]) )))), __pyx_v_len_x, __pyx_v_j);\n",
-       "
 223:     else:
\n", - "
+224:         j = provided_j
\n", - "
  /*else*/ {\n",
-       "    __pyx_v_j = __pyx_v_provided_j;\n",
-       "  }\n",
-       "  __pyx_L3:;\n",
-       "
 225: 
\n", - "
+226:     if j <= -1:
\n", - "
  __pyx_t_3 = (__pyx_v_j <= -1L);\n",
-       "  if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "    goto __pyx_L4;\n",
-       "  }\n",
-       "
+227:         result = left_value
\n", - "
    __pyx_v_result = __pyx_v_left_value;\n",
-       "
+228:     elif j >= len_x:
\n", - "
  __pyx_t_3 = (__pyx_v_j >= __pyx_v_len_x);\n",
-       "  if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "    goto __pyx_L4;\n",
-       "  }\n",
-       "
+229:         result = right_value
\n", - "
    __pyx_v_result = __pyx_v_right_value;\n",
-       "
 230:     else:
\n", - "
+231:         fp_at_j = dependent_values[j]
\n", - "
  /*else*/ {\n",
-       "    __pyx_t_2 = __pyx_v_j;\n",
-       "    __pyx_v_fp_at_j = (*((double *) ( /* dim=0 */ (__pyx_v_dependent_values.data + __pyx_t_2 * __pyx_v_dependent_values.strides[0]) )));\n",
-       "
+232:         xp_at_j = x_domain[j]
\n", - "
    __pyx_t_2 = __pyx_v_j;\n",
-       "    __pyx_v_xp_at_j = (*((double *) ( /* dim=0 */ (__pyx_v_x_domain.data + __pyx_t_2 * __pyx_v_x_domain.strides[0]) )));\n",
-       "
+233:         if j == len_x - 1:
\n", - "
    __pyx_t_3 = (__pyx_v_j == (__pyx_v_len_x - 1));\n",
-       "    if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "      goto __pyx_L5;\n",
-       "    }\n",
-       "
+234:             result = fp_at_j
\n", - "
      __pyx_v_result = __pyx_v_fp_at_j;\n",
-       "
+235:         elif xp_at_j == desired_x:
\n", - "
    __pyx_t_3 = (__pyx_v_xp_at_j == __pyx_v_desired_x);\n",
-       "    if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "      goto __pyx_L5;\n",
-       "    }\n",
-       "
+236:             result = fp_at_j
\n", - "
      __pyx_v_result = __pyx_v_fp_at_j;\n",
-       "
 237:         else:
\n", - "
+238:             fp_at_jp1 = dependent_values[j + 1]
\n", - "
    /*else*/ {\n",
-       "      __pyx_t_2 = (__pyx_v_j + 1);\n",
-       "      __pyx_v_fp_at_jp1 = (*((double *) ( /* dim=0 */ (__pyx_v_dependent_values.data + __pyx_t_2 * __pyx_v_dependent_values.strides[0]) )));\n",
-       "
+239:             xp_at_jp1 = x_domain[j + 1]
\n", - "
      __pyx_t_2 = (__pyx_v_j + 1);\n",
-       "      __pyx_v_xp_at_jp1 = (*((double *) ( /* dim=0 */ (__pyx_v_x_domain.data + __pyx_t_2 * __pyx_v_x_domain.strides[0]) )));\n",
-       "
+240:             slope = (fp_at_jp1 - fp_at_j) / (xp_at_jp1 - xp_at_j)
\n", - "
      __pyx_v_slope = ((__pyx_v_fp_at_jp1 - __pyx_v_fp_at_j) / (__pyx_v_xp_at_jp1 - __pyx_v_xp_at_j));\n",
-       "
 241: 
\n", - "
 242:             # If we get nan in one direction, try the other
\n", - "
+243:             result = slope * (desired_x - xp_at_j) + fp_at_j
\n", - "
      __pyx_v_result = ((__pyx_v_slope * (__pyx_v_desired_x - __pyx_v_xp_at_j)) + __pyx_v_fp_at_j);\n",
-       "
+244:             if isnan(result):
\n", - "
      __pyx_t_3 = isnan(__pyx_v_result);\n",
-       "      if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "      }\n",
-       "    }\n",
-       "    __pyx_L5:;\n",
-       "  }\n",
-       "  __pyx_L4:;\n",
-       "
+245:                 result = slope * (desired_x - xp_at_jp1) + fp_at_jp1
\n", - "
        __pyx_v_result = ((__pyx_v_slope * (__pyx_v_desired_x - __pyx_v_xp_at_jp1)) + __pyx_v_fp_at_jp1);\n",
-       "
+246:                 if isnan(result) and (fp_at_jp1 == fp_at_j):
\n", - "
        __pyx_t_4 = isnan(__pyx_v_result);\n",
-       "        if (__pyx_t_4) {\n",
-       "        } else {\n",
-       "          __pyx_t_3 = __pyx_t_4;\n",
-       "          goto __pyx_L8_bool_binop_done;\n",
-       "        }\n",
-       "        __pyx_t_4 = (__pyx_v_fp_at_jp1 == __pyx_v_fp_at_j);\n",
-       "        __pyx_t_3 = __pyx_t_4;\n",
-       "        __pyx_L8_bool_binop_done:;\n",
-       "        if (__pyx_t_3) {\n",
-       "/* … */\n",
-       "        }\n",
-       "
+247:                     result = fp_at_j
\n", - "
          __pyx_v_result = __pyx_v_fp_at_j;\n",
-       "
 248: 
\n", - "
+249:     return result
\n", - "
  __pyx_r = __pyx_v_result;\n",
-       "  goto __pyx_L0;\n",
-       "
" + "
 01: # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False
\n", + "
 02: 
\n", + "
 03: from libc.float cimport DBL_EPSILON
\n", + "
 04: from libc.stdint cimport SIZE_MAX, INT64_MAX, int16_t, int32_t, int64_t
\n", + "
+05: print(sizeof(double))
\n", + "
  __pyx_t_1 = __Pyx_PyInt_FromSize_t((sizeof(double))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 5, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
 06: 
\n", + "
+07: print(DBL_EPSILON)
\n", + "
  __pyx_t_2 = PyFloat_FromDouble(DBL_EPSILON); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 7, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 7, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
+08: print(SIZE_MAX)
\n", + "
  __pyx_t_1 = __Pyx_PyInt_FromSize_t(SIZE_MAX); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 8, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
+09: print(INT64_MAX)
\n", + "
  __pyx_t_2 = __Pyx_PyInt_From_int64_t(INT64_MAX); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 9, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
 10: 
\n", + "
+11: import sys
\n", + "
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_sys, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 11, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_sys, __pyx_t_1) < 0) __PYX_ERR(0, 11, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
+12: print(sys.maxsize)
\n", + "
  __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_sys); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 12, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_maxsize); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 12, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
+13: print(sizeof(size_t))
\n", + "
  __pyx_t_1 = __Pyx_PyInt_FromSize_t((sizeof(size_t))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 13, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 13, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
+14: print(sizeof(ssize_t))
\n", + "
  __pyx_t_2 = __Pyx_PyInt_FromSize_t((sizeof(Py_ssize_t))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 14, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
 15: 
\n", + "
+16: print(sizeof(int16_t))
\n", + "
  __pyx_t_1 = __Pyx_PyInt_FromSize_t((sizeof(int16_t))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 16, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
+17: print(sizeof(int32_t))
\n", + "
  __pyx_t_2 = __Pyx_PyInt_FromSize_t((sizeof(int32_t))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 17, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 17, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
+18: print(sizeof(int64_t))
\n", + "
  __pyx_t_1 = __Pyx_PyInt_FromSize_t((sizeof(int64_t))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 18, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 18, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
+19: print(sizeof(int))
\n", + "
  __pyx_t_2 = __Pyx_PyInt_FromSize_t((sizeof(int))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 19, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 19, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
 20: 
\n", + "
" ], "text/plain": [ "" ] }, - "execution_count": 4, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], + "source": [ + "%%cython --annotate --force\n", + "# cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False\n", + "\n", + "from libc.float cimport DBL_EPSILON\n", + "from libc.stdint cimport SIZE_MAX, INT64_MAX, int16_t, int32_t, int64_t\n", + "print(sizeof(double))\n", + "\n", + "print(DBL_EPSILON)\n", + "print(SIZE_MAX)\n", + "print(INT64_MAX)\n", + "\n", + "import sys\n", + "print(sys.maxsize)\n", + "print(sizeof(size_t))\n", + "print(sizeof(ssize_t))\n", + "\n", + "print(sizeof(int16_t))\n", + "print(sizeof(int32_t))\n", + "print(sizeof(int64_t))\n", + "print(sizeof(int))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "829e2f11", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "UsageError: Cell magic `%%cython` not found.\n" + ] + } + ], "source": [ "%%cython --annotate --force\n", "# cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False\n", @@ -12364,7 +11820,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.9.16" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index caa91e7..7c7da70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name='CyRK' -version = '0.8.3a0.dev1' +version = '0.8.3a0.dev2' description='Runge-Kutta ODE Integrator Implemented in Cython and Numba.' authors= [ {name = 'Joe P. Renaud', email = 'joe.p.renaud@gmail.com'}