import numpy as np
import numba
import cython
%load_ext cython
Generating some data:
def random_Gaussian(sig2=0.25):
return sig2 * np.random.randn()
%timeit (random_Gaussian(), random_Gaussian())
In pure Python:
def klGauss(x: float, y: float, sig2=0.25) -> float:
return (x - y)**2 / (2 * sig2**x)
%timeit klGauss(random_Gaussian(), random_Gaussian())
With numba:
@numba.jit(nopython=True)
def klGauss_numba(x: float, y: float, sig2=0.25) -> float:
return (x - y)**2 / (2 * sig2**x)
help(klGauss_numba)
%timeit klGauss_numba(random_Gaussian(), random_Gaussian())
%timeit klGauss_numba(random_Gaussian(), random_Gaussian())
print(f"Speed up using Numba for klGauss was: {(1290-993)/(20300-993):.2g} faster!")
With Cython
%%cython --annotate
def klGauss_cython(double x, double y, double sig2=0.25) -> double:
return (x - y)**2 / (2 * sig2**x)
help(klGauss_cython)
%timeit klGauss_cython(random_Gaussian(), random_Gaussian())
print(f"Speed up using Cython for klGauss was: {(1290-993)/(1100-993):.2g} faster!")
Generating some data:
def random_Bern():
return np.random.random()
%timeit (random_Bern(), random_Bern())
In pure Python:
from math import log
def klBern(x: float, y: float) -> float:
x = max(1e-7, min(1 - 1e-7, x))
x = max(1e-7, min(1 - 1e-7, x))
return x * log(x/y) + (1-x) * log((1-x)/(1-y))
%timeit klBern(random_Bern(), random_Bern())
With numba:
from math import log
@numba.jit(nopython=True)
def klBern_numba(x: float, y: float) -> float:
x = max(1e-7, min(1 - 1e-7, x))
x = max(1e-7, min(1 - 1e-7, x))
return x * log(x/y) + (1-x) * log((1-x)/(1-y))
help(klBern_numba)
%timeit klBern_numba(random_Bern(), random_Bern())
%timeit klBern_numba(random_Bern(), random_Bern())
print(f"Speed up using Numba for klBern was: {(1740-753)/(996-753):.2g} faster!")
With Cython
%load_ext cython
%%cython --annotate
from libc.math cimport log
def klBern_cython(double x, double y) -> double:
x = max(1e-7, min(1 - 1e-7, x))
x = max(1e-7, min(1 - 1e-7, x))
return x * log(x/y) + (1-x) * log((1-x)/(1-y))
help(klBern_cython)
%timeit klBern_cython(random_Bern(), random_Bern())
print(f"Speed up using Cython for klBern was: {(1740-753)/(861-753):.2g} faster!")
Generating some data:
def random_t0_s_t_delta(min_t: int=100, max_t: int=1000) -> (int, int, int, float):
t0 = 0
t = np.random.randint(min_t, max_t + 1)
s = np.random.randint(t0, t)
delta = np.random.choice([0.1, 0.05, 0.01, 0.005, 0.001, max(0.0005, 1/t)])
return (t0, s, t, delta)
%timeit random_t0_s_t_delta()
In pure Python:
def threshold(t0: int, s: int, t: int, delta: float) -> float:
return np.log((s - t0 + 1) * (t - s) / delta)
%timeit threshold(*random_t0_s_t_delta())
It's way faster to use math.log
instead of numpy.log
(of course)!
from math import log
def threshold2(t0: int, s: int, t: int, delta: float) -> float:
return log((s - t0 + 1) * (t - s) / delta)
%timeit threshold2(*random_t0_s_t_delta())
In numba:
from math import log
@numba.jit(nopython=True)
def threshold_numba(t0: int, s: int, t: int, delta: float) -> float:
return log((s - t0 + 1) * (t - s) / delta)
help(threshold_numba)
%timeit threshold_numba(*random_t0_s_t_delta())
print(f"Speed up using Cython for thresold was: {(7510-7200)/(7750-7200):.2g} faster!")
In Cython:
%%cython --annotate
from libc.math cimport log
cpdef double threshold_cython(int t0, int s, int t, double delta):
return log((s - t0 + 1) * (t - s) / delta)
%%cython --annotate
from libc.math cimport log
def threshold_cython2(int t0, int s, int t, double delta) -> double:
return log((s - t0 + 1) * (t - s) / delta)
help(threshold_cython)
%timeit threshold_cython(*random_t0_s_t_delta())
%timeit threshold_cython2(*random_t0_s_t_delta())
print(f"Speed up using Cython for thresold was: {abs(7510-7200)/abs(7070-7200):.2g} faster!")