%load_ext cython
%%cython
import numpy as np
from scipy.optimize.cython_optimize cimport brentq
# import math from Cython
from libc cimport math
CNT = 1e5
C0_ARG = 1.0 + np.linspace(-0.05, 0.05, int(CNT), dtype=np.dtype("f8"))
C1_ARG = 0.7
XLO, XHI = 0.0, 1.0 # lower and upper search boundaries
XTOL, RTOL = 1e-3, 1e-3
MITR = 10 # other solver parameters
# user defined struct for extra parameters
ctypedef struct test_params:
double C0
double C1
# user defined callback
cdef double f(double x, void *args):
cdef test_params *myargs = <test_params *> args
return myargs.C0 - math.exp(-(x - myargs.C1))
# Cython wrapper function
cdef int brentq_wrapper_loop_example(double[:] c0, double c1, double xa, double xb,
double xtol, double rtol, int mitr, double[:] result):
cdef Py_ssize_t i = 0
cdef test_params myargs
myargs.C1 = c1
while i < CNT:
myargs.C0 = c0[i]
result[i] = brentq(
f, xa, xb, <test_params *> &myargs, xtol, rtol, mitr, NULL)
i += 1
return 0
# Python function
def brentq_loop_example(c0=C0_ARG, c1=C1_ARG, xa=XLO, xb=XHI, xtol=XTOL, rtol=RTOL,
mitr=MITR):
'''Calls Cython wrapper from Python.'''
cdef double[:] result = np.empty_like(c0)
if not brentq_wrapper_loop_example(c0, c1, xa, xb, xtol, rtol, mitr, result):
return result
%timeit brentq_loop_example()
26.4 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
x_loop = brentq_loop_example()
np.asarray(x_loop)[:10]
array([0.75149248, 0.75149143, 0.75149038, 0.75148933, 0.75148828, 0.75148723, 0.75148618, 0.75148513, 0.75148408, 0.75148303])
%%cython
from scipy.optimize.cython_optimize cimport brentq
import numpy as np
# import math from Cython
from libc cimport math
CNT = 1e5
C0_ARG = 1.0 + np.linspace(-0.05, 0.05, int(CNT), dtype=np.dtype("f8"))
C1_ARG = 0.7
XLO, XHI = 0., 1.0 # lower and upper search boundaries
XTOL, RTOL, MITR = 1e-3, 1e-3, 10 # other solver parameters
# user defined struct for extra parameters
ctypedef struct test_params:
double C0
double C1
# user defined callback
cdef double f(double x, void *args):
cdef test_params *myargs = <test_params *> args
return myargs.C0 - math.exp(-(x - myargs.C1))
# Cython wrapper function
cdef double brentq_wrapper_map_example(dict args, double xa, double xb,
double xtol, double rtol, int mitr):
# Cython automatically casts dictionary to struct
cdef test_params myargs = args
return brentq(
f, xa, xb, <test_params *> &myargs, xtol, rtol, mitr, NULL)
# Python function
def brentq_map_example(c0=C0_ARG, c1=C1_ARG, xa=XLO, xb=XHI, xtol=XTOL, rtol=RTOL,
mitr=MITR):
'''Calls Cython wrapper from Python.'''
args = [{'C0': c0_, 'C1': c1} for c0_ in c0]
return map(lambda a: brentq_wrapper_map_example(a, xa, xb, xtol, rtol, mitr), args)
%timeit list(brentq_map_example())
64.7 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
x_map = list(brentq_map_example())
assert np.allclose(np.asarray(x_map), np.asarray(x_loop))
from scipy.optimize import brentq
import numpy as np
CNT = 1e5
C0_ARG = 1.0 + np.linspace(-0.05, 0.05, int(CNT), np.float64)
C1_ARG = 0.7
XLO, XHI = 0., 1.0 # lower and upper search boundaries
XTOL, RTOL, MITR = 1e-3, 1e-3, 10 # other solver parameters
# user defined callback
def f(x, args):
return args['C0'] - np.exp(-(x - args['C1']))
# Python function
def brentq_np_example(c0=C0_ARG, c1=C1_ARG, xa=XLO, xb=XHI, xtol=XTOL, rtol=RTOL,
mitr=MITR):
'''Calls Cython wrapper from Python.'''
args = [{'C0': c0_, 'C1': c1} for c0_ in c0]
return map(lambda a: brentq(f, xa, xb, a, xtol, rtol, mitr), args)
%timeit list(brentq_np_example())
682 ms ± 17.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
x_np = list(brentq_np_example())
assert np.allclose(np.asarray(x_map), np.asarray(x_np))
%%cython
cimport cython
from cython.parallel import prange
import numpy as np
from scipy.optimize.cython_optimize cimport brentq
# import math from Cython
from libc cimport math
CNT = 1e5
C0_ARG = 1.0 + np.linspace(-0.05, 0.05, int(CNT), dtype=np.dtype("f8"))
C1_ARG = 0.7
XLO, XHI = 0.0, 1.0 # lower and upper search boundaries
XTOL, RTOL = 1e-3, 1e-3
MITR = 10 # other solver parameters
# user defined struct for extra parameters
ctypedef struct test_params:
double C0
double C1
# user defined callback
@cython.initializedcheck(False)
@cython.boundscheck(False) # turn off boundscheck for this function
@cython.wraparound(False)
@cython.cdivision(True)
cdef double f(double x, void *args) nogil:
# nogil doesn't seem to matter here
# works w/ or w/o, same benchmark time
cdef test_params *myargs = <test_params *> args
return myargs.C0 - math.exp(-(x - myargs.C1))
# Cython wrapper function
@cython.initializedcheck(False)
@cython.boundscheck(False) # turn off boundscheck for this function
@cython.wraparound(False)
@cython.cdivision(True)
cdef int brentq_wrapper_prange_example(double[:] c0, double c1, double xa, double xb,
double xtol, double rtol, int mitr, double[:] result):
cdef Py_ssize_t i
cdef test_params myargs
myargs.C1 = c1
for i in prange(c0.shape[0], nogil=True):
myargs.C0 = c0[i]
result[i] = brentq(
f, xa, xb, <test_params *> &myargs, xtol, rtol, mitr, NULL)
return 0
# Python function
def brentq_prange_example(c0=C0_ARG, c1=C1_ARG, xa=XLO, xb=XHI, xtol=XTOL, rtol=RTOL,
mitr=MITR):
'''Calls Cython wrapper from Python.'''
cdef double[:] result = np.empty_like(c0)
if not brentq_wrapper_prange_example(c0, c1, xa, xb, xtol, rtol, mitr, result):
return result
%timeit brentq_prange_example()
17.9 ms ± 111 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
x_prange = brentq_prange_example()
assert np.allclose(np.asarray(x_map), np.asarray(x_prange))