602 lines
21 KiB
Python
602 lines
21 KiB
Python
# Contents in this file are referenced from the sphinx-generated docs.
|
|
# "magictoken" is used for markers as beginning and ending of example text.
|
|
|
|
import sys
|
|
import unittest
|
|
from numba.tests.support import captured_stdout
|
|
from numba.core.config import IS_WIN32
|
|
|
|
|
|
class MatplotlibBlocker:
|
|
'''Blocks the import of matplotlib, so that doc examples that attempt to
|
|
plot the output don't result in plots popping up and blocking testing.'''
|
|
|
|
def find_spec(self, fullname, path, target=None):
|
|
if fullname == 'matplotlib':
|
|
msg = 'Blocked import of matplotlib for test suite run'
|
|
raise ImportError(msg)
|
|
|
|
|
|
class DocsExamplesTest(unittest.TestCase):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self._mpl_blocker = MatplotlibBlocker()
|
|
|
|
def setUp(self):
|
|
sys.meta_path.insert(0, self._mpl_blocker)
|
|
|
|
def tearDown(self):
|
|
sys.meta_path.remove(self._mpl_blocker)
|
|
|
|
def test_mandelbrot(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_mandelbrot.begin
|
|
from timeit import default_timer as timer
|
|
try:
|
|
from matplotlib.pylab import imshow, show
|
|
have_mpl = True
|
|
except ImportError:
|
|
have_mpl = False
|
|
import numpy as np
|
|
from numba import jit
|
|
|
|
@jit(nopython=True)
|
|
def mandel(x, y, max_iters):
|
|
"""
|
|
Given the real and imaginary parts of a complex number,
|
|
determine if it is a candidate for membership in the Mandelbrot
|
|
set given a fixed number of iterations.
|
|
"""
|
|
i = 0
|
|
c = complex(x,y)
|
|
z = 0.0j
|
|
for i in range(max_iters):
|
|
z = z * z + c
|
|
if (z.real * z.real + z.imag * z.imag) >= 4:
|
|
return i
|
|
|
|
return 255
|
|
|
|
@jit(nopython=True)
|
|
def create_fractal(min_x, max_x, min_y, max_y, image, iters):
|
|
height = image.shape[0]
|
|
width = image.shape[1]
|
|
|
|
pixel_size_x = (max_x - min_x) / width
|
|
pixel_size_y = (max_y - min_y) / height
|
|
for x in range(width):
|
|
real = min_x + x * pixel_size_x
|
|
for y in range(height):
|
|
imag = min_y + y * pixel_size_y
|
|
color = mandel(real, imag, iters)
|
|
image[y, x] = color
|
|
|
|
return image
|
|
|
|
image = np.zeros((500 * 2, 750 * 2), dtype=np.uint8)
|
|
s = timer()
|
|
create_fractal(-2.0, 1.0, -1.0, 1.0, image, 20)
|
|
e = timer()
|
|
print(e - s)
|
|
if have_mpl:
|
|
imshow(image)
|
|
show()
|
|
# magictoken.ex_mandelbrot.end
|
|
|
|
def test_moving_average(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_moving_average.begin
|
|
import numpy as np
|
|
|
|
from numba import guvectorize
|
|
|
|
@guvectorize(['void(float64[:], intp[:], float64[:])'],
|
|
'(n),()->(n)')
|
|
def move_mean(a, window_arr, out):
|
|
window_width = window_arr[0]
|
|
asum = 0.0
|
|
count = 0
|
|
for i in range(window_width):
|
|
asum += a[i]
|
|
count += 1
|
|
out[i] = asum / count
|
|
for i in range(window_width, len(a)):
|
|
asum += a[i] - a[i - window_width]
|
|
out[i] = asum / count
|
|
|
|
arr = np.arange(20, dtype=np.float64).reshape(2, 10)
|
|
print(arr)
|
|
print(move_mean(arr, 3))
|
|
# magictoken.ex_moving_average.end
|
|
|
|
def test_nogil(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_no_gil.begin
|
|
import math
|
|
import threading
|
|
from timeit import repeat
|
|
|
|
import numpy as np
|
|
from numba import jit
|
|
|
|
nthreads = 4
|
|
size = 10**6
|
|
|
|
def func_np(a, b):
|
|
"""
|
|
Control function using Numpy.
|
|
"""
|
|
return np.exp(2.1 * a + 3.2 * b)
|
|
|
|
@jit('void(double[:], double[:], double[:])', nopython=True,
|
|
nogil=True)
|
|
def inner_func_nb(result, a, b):
|
|
"""
|
|
Function under test.
|
|
"""
|
|
for i in range(len(result)):
|
|
result[i] = math.exp(2.1 * a[i] + 3.2 * b[i])
|
|
|
|
def timefunc(correct, s, func, *args, **kwargs):
|
|
"""
|
|
Benchmark *func* and print out its runtime.
|
|
"""
|
|
print(s.ljust(20), end=" ")
|
|
# Make sure the function is compiled before the benchmark is
|
|
# started
|
|
res = func(*args, **kwargs)
|
|
if correct is not None:
|
|
assert np.allclose(res, correct), (res, correct)
|
|
# time it
|
|
print('{:>5.0f} ms'.format(min(repeat(
|
|
lambda: func(*args, **kwargs), number=5, repeat=2)) * 1000))
|
|
return res
|
|
|
|
def make_singlethread(inner_func):
|
|
"""
|
|
Run the given function inside a single thread.
|
|
"""
|
|
def func(*args):
|
|
length = len(args[0])
|
|
result = np.empty(length, dtype=np.float64)
|
|
inner_func(result, *args)
|
|
return result
|
|
return func
|
|
|
|
def make_multithread(inner_func, numthreads):
|
|
"""
|
|
Run the given function inside *numthreads* threads, splitting
|
|
its arguments into equal-sized chunks.
|
|
"""
|
|
def func_mt(*args):
|
|
length = len(args[0])
|
|
result = np.empty(length, dtype=np.float64)
|
|
args = (result,) + args
|
|
chunklen = (length + numthreads - 1) // numthreads
|
|
# Create argument tuples for each input chunk
|
|
chunks = [[arg[i * chunklen:(i + 1) * chunklen] for arg in
|
|
args] for i in range(numthreads)]
|
|
# Spawn one thread per chunk
|
|
threads = [threading.Thread(target=inner_func, args=chunk)
|
|
for chunk in chunks]
|
|
for thread in threads:
|
|
thread.start()
|
|
for thread in threads:
|
|
thread.join()
|
|
return result
|
|
return func_mt
|
|
|
|
func_nb = make_singlethread(inner_func_nb)
|
|
func_nb_mt = make_multithread(inner_func_nb, nthreads)
|
|
|
|
a = np.random.rand(size)
|
|
b = np.random.rand(size)
|
|
|
|
correct = timefunc(None, "numpy (1 thread)", func_np, a, b)
|
|
timefunc(correct, "numba (1 thread)", func_nb, a, b)
|
|
timefunc(correct, "numba (%d threads)" % nthreads, func_nb_mt, a, b)
|
|
# magictoken.ex_no_gil.end
|
|
|
|
def test_vectorize_one_signature(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_vectorize_one_signature.begin
|
|
from numba import vectorize, float64
|
|
|
|
@vectorize([float64(float64, float64)])
|
|
def f(x, y):
|
|
return x + y
|
|
# magictoken.ex_vectorize_one_signature.end
|
|
|
|
def test_vectorize_multiple_signatures(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_vectorize_multiple_signatures.begin
|
|
from numba import vectorize, int32, int64, float32, float64
|
|
import numpy as np
|
|
|
|
@vectorize([int32(int32, int32),
|
|
int64(int64, int64),
|
|
float32(float32, float32),
|
|
float64(float64, float64)])
|
|
def f(x, y):
|
|
return x + y
|
|
# magictoken.ex_vectorize_multiple_signatures.end
|
|
|
|
# magictoken.ex_vectorize_return_call_one.begin
|
|
a = np.arange(6)
|
|
result = f(a, a)
|
|
# result == array([ 0, 2, 4, 6, 8, 10])
|
|
# magictoken.ex_vectorize_return_call_one.end
|
|
|
|
self.assertIsInstance(result, np.ndarray)
|
|
correct = np.array([0, 2, 4, 6, 8, 10])
|
|
np.testing.assert_array_equal(result, correct)
|
|
|
|
# magictoken.ex_vectorize_return_call_two.begin
|
|
a = np.linspace(0, 1, 6)
|
|
result = f(a, a)
|
|
# Now, result == array([0. , 0.4, 0.8, 1.2, 1.6, 2. ])
|
|
# magictoken.ex_vectorize_return_call_two.end
|
|
|
|
self.assertIsInstance(result, np.ndarray)
|
|
correct = np.array([0., 0.4, 0.8, 1.2, 1.6, 2. ])
|
|
np.testing.assert_allclose(result, correct)
|
|
|
|
# magictoken.ex_vectorize_return_call_three.begin
|
|
a = np.arange(12).reshape(3, 4)
|
|
# a == array([[ 0, 1, 2, 3],
|
|
# [ 4, 5, 6, 7],
|
|
# [ 8, 9, 10, 11]])
|
|
|
|
result1 = f.reduce(a, axis=0)
|
|
# result1 == array([12, 15, 18, 21])
|
|
|
|
result2 = f.reduce(a, axis=1)
|
|
# result2 == array([ 6, 22, 38])
|
|
|
|
result3 = f.accumulate(a)
|
|
# result3 == array([[ 0, 1, 2, 3],
|
|
# [ 4, 6, 8, 10],
|
|
# [12, 15, 18, 21]])
|
|
|
|
result4 = f.accumulate(a, axis=1)
|
|
# result3 == array([[ 0, 1, 3, 6],
|
|
# [ 4, 9, 15, 22],
|
|
# [ 8, 17, 27, 38]])
|
|
# magictoken.ex_vectorize_return_call_three.end
|
|
|
|
self.assertIsInstance(result1, np.ndarray)
|
|
correct = np.array([12, 15, 18, 21])
|
|
np.testing.assert_array_equal(result1, correct)
|
|
|
|
self.assertIsInstance(result2, np.ndarray)
|
|
correct = np.array([6, 22, 38])
|
|
np.testing.assert_array_equal(result2, correct)
|
|
|
|
self.assertIsInstance(result3, np.ndarray)
|
|
correct = np.array([
|
|
[0, 1, 2, 3],
|
|
[4, 6, 8, 10],
|
|
[12, 15, 18, 21]
|
|
])
|
|
np.testing.assert_array_equal(result3, correct)
|
|
|
|
self.assertIsInstance(result4, np.ndarray)
|
|
correct = np.array([
|
|
[0, 1, 3, 6],
|
|
[4, 9, 15, 22],
|
|
[8, 17, 27, 38]
|
|
])
|
|
np.testing.assert_array_equal(result4, correct)
|
|
|
|
def test_guvectorize(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_guvectorize.begin
|
|
from numba import guvectorize, int64
|
|
import numpy as np
|
|
|
|
@guvectorize([(int64[:], int64, int64[:])], '(n),()->(n)')
|
|
def g(x, y, res):
|
|
for i in range(x.shape[0]):
|
|
res[i] = x[i] + y
|
|
# magictoken.ex_guvectorize.end
|
|
|
|
# magictoken.ex_guvectorize_call_one.begin
|
|
a = np.arange(5)
|
|
result = g(a, 2)
|
|
# result == array([2, 3, 4, 5, 6])
|
|
# magictoken.ex_guvectorize_call_one.end
|
|
|
|
self.assertIsInstance(result, np.ndarray)
|
|
correct = np.array([2, 3, 4, 5, 6])
|
|
np.testing.assert_array_equal(result, correct)
|
|
|
|
# magictoken.ex_guvectorize_call_two.begin
|
|
a = np.arange(6).reshape(2, 3)
|
|
# a == array([[0, 1, 2],
|
|
# [3, 4, 5]])
|
|
|
|
result1 = g(a, 10)
|
|
# result1 == array([[10, 11, 12],
|
|
# [13, 14, 15]])
|
|
|
|
result2 = g(a, np.array([10, 20]))
|
|
g(a, np.array([10, 20]))
|
|
# result2 == array([[10, 11, 12],
|
|
# [23, 24, 25]])
|
|
# magictoken.ex_guvectorize_call_two.end
|
|
|
|
self.assertIsInstance(result1, np.ndarray)
|
|
correct = np.array([[10, 11, 12], [13, 14, 15]])
|
|
np.testing.assert_array_equal(result1, correct)
|
|
|
|
self.assertIsInstance(result2, np.ndarray)
|
|
correct = np.array([[10, 11, 12], [23, 24, 25]])
|
|
np.testing.assert_array_equal(result2, correct)
|
|
|
|
def test_guvectorize_scalar_return(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_guvectorize_scalar_return.begin
|
|
from numba import guvectorize, int64
|
|
import numpy as np
|
|
|
|
@guvectorize([(int64[:], int64, int64[:])], '(n),()->()')
|
|
def g(x, y, res):
|
|
acc = 0
|
|
for i in range(x.shape[0]):
|
|
acc += x[i] + y
|
|
res[0] = acc
|
|
# magictoken.ex_guvectorize_scalar_return.end
|
|
|
|
# magictoken.ex_guvectorize_scalar_return_call.begin
|
|
a = np.arange(5)
|
|
result = g(a, 2)
|
|
# At this point, result == 20.
|
|
# magictoken.ex_guvectorize_scalar_return_call.end
|
|
|
|
self.assertIsInstance(result, np.integer)
|
|
self.assertEqual(result, 20)
|
|
|
|
def test_guvectorize_overwrite(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_guvectorize_overwrite.begin
|
|
from numba import guvectorize, float64
|
|
import numpy as np
|
|
|
|
@guvectorize([(float64[:], float64[:])], '()->()')
|
|
def init_values(invals, outvals):
|
|
invals[0] = 6.5
|
|
outvals[0] = 4.2
|
|
# magictoken.ex_guvectorize_overwrite.end
|
|
|
|
# magictoken.ex_guvectorize_overwrite_call_one.begin
|
|
invals = np.zeros(shape=(3, 3), dtype=np.float64)
|
|
# invals == array([[6.5, 6.5, 6.5],
|
|
# [6.5, 6.5, 6.5],
|
|
# [6.5, 6.5, 6.5]])
|
|
|
|
outvals = init_values(invals)
|
|
# outvals == array([[4.2, 4.2, 4.2],
|
|
# [4.2, 4.2, 4.2],
|
|
# [4.2, 4.2, 4.2]])
|
|
# magictoken.ex_guvectorize_overwrite_call_one.end
|
|
|
|
self.assertIsInstance(invals, np.ndarray)
|
|
correct = np.array([
|
|
[6.5, 6.5, 6.5],
|
|
[6.5, 6.5, 6.5],
|
|
[6.5, 6.5, 6.5]])
|
|
np.testing.assert_array_equal(invals, correct)
|
|
|
|
self.assertIsInstance(outvals, np.ndarray)
|
|
correct = np.array([
|
|
[4.2, 4.2, 4.2],
|
|
[4.2, 4.2, 4.2],
|
|
[4.2, 4.2, 4.2]])
|
|
np.testing.assert_array_equal(outvals, correct)
|
|
|
|
# magictoken.ex_guvectorize_overwrite_call_two.begin
|
|
invals = np.zeros(shape=(3, 3), dtype=np.float32)
|
|
# invals == array([[0., 0., 0.],
|
|
# [0., 0., 0.],
|
|
# [0., 0., 0.]], dtype=float32)
|
|
outvals = init_values(invals)
|
|
# outvals == array([[4.2, 4.2, 4.2],
|
|
# [4.2, 4.2, 4.2],
|
|
# [4.2, 4.2, 4.2]])
|
|
print(invals)
|
|
# invals == array([[0., 0., 0.],
|
|
# [0., 0., 0.],
|
|
# [0., 0., 0.]], dtype=float32)
|
|
# magictoken.ex_guvectorize_overwrite_call_two.end
|
|
|
|
self.assertIsInstance(invals, np.ndarray)
|
|
correct = np.array([
|
|
[0., 0., 0.],
|
|
[0., 0., 0.],
|
|
[0., 0., 0.]], dtype=np.float32)
|
|
np.testing.assert_array_equal(invals, correct)
|
|
|
|
self.assertIsInstance(outvals, np.ndarray)
|
|
correct = np.array([
|
|
[4.2, 4.2, 4.2],
|
|
[4.2, 4.2, 4.2],
|
|
[4.2, 4.2, 4.2]])
|
|
np.testing.assert_array_equal(outvals, correct)
|
|
|
|
# magictoken.ex_guvectorize_overwrite_call_three.begin
|
|
@guvectorize(
|
|
[(float64[:], float64[:])],
|
|
'()->()',
|
|
writable_args=('invals',)
|
|
)
|
|
def init_values(invals, outvals):
|
|
invals[0] = 6.5
|
|
outvals[0] = 4.2
|
|
|
|
invals = np.zeros(shape=(3, 3), dtype=np.float32)
|
|
# invals == array([[0., 0., 0.],
|
|
# [0., 0., 0.],
|
|
# [0., 0., 0.]], dtype=float32)
|
|
outvals = init_values(invals)
|
|
# outvals == array([[4.2, 4.2, 4.2],
|
|
# [4.2, 4.2, 4.2],
|
|
# [4.2, 4.2, 4.2]])
|
|
print(invals)
|
|
# invals == array([[6.5, 6.5, 6.5],
|
|
# [6.5, 6.5, 6.5],
|
|
# [6.5, 6.5, 6.5]], dtype=float32)
|
|
# magictoken.ex_guvectorize_overwrite_call_three.end
|
|
|
|
self.assertIsInstance(invals, np.ndarray)
|
|
correct = np.array([
|
|
[6.5, 6.5, 6.5],
|
|
[6.5, 6.5, 6.5],
|
|
[6.5, 6.5, 6.5]])
|
|
np.testing.assert_array_equal(invals, correct)
|
|
|
|
self.assertIsInstance(outvals, np.ndarray)
|
|
correct = np.array([
|
|
[4.2, 4.2, 4.2],
|
|
[4.2, 4.2, 4.2],
|
|
[4.2, 4.2, 4.2]])
|
|
np.testing.assert_array_equal(outvals, correct)
|
|
|
|
def test_vectorize_dynamic(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_vectorize_dynamic.begin
|
|
from numba import vectorize
|
|
|
|
@vectorize
|
|
def f(x, y):
|
|
return x * y
|
|
# magictoken.ex_vectorize_dynamic.end
|
|
|
|
# magictoken.ex_vectorize_dynamic_call_one.begin
|
|
result = f(3,4)
|
|
# result == 12
|
|
|
|
print(f.types)
|
|
# ['ll->l']
|
|
# magictoken.ex_vectorize_dynamic_call_one.end
|
|
|
|
self.assertEqual(result, 12)
|
|
if IS_WIN32:
|
|
correct = ['ll->q']
|
|
else:
|
|
correct = ['ll->l']
|
|
self.assertEqual(f.types, correct)
|
|
|
|
# magictoken.ex_vectorize_dynamic_call_two.begin
|
|
result = f(1.,2.)
|
|
# result == 2.0
|
|
|
|
print(f.types)
|
|
# ['ll->l', 'dd->d']
|
|
# magictoken.ex_vectorize_dynamic_call_two.end
|
|
|
|
self.assertEqual(result, 2.0)
|
|
if IS_WIN32:
|
|
correct = ['ll->q', 'dd->d']
|
|
else:
|
|
correct = ['ll->l', 'dd->d']
|
|
self.assertEqual(f.types, correct)
|
|
|
|
# magictoken.ex_vectorize_dynamic_call_three.begin
|
|
result = f(1,2.)
|
|
# result == 2.0
|
|
|
|
print(f.types)
|
|
# ['ll->l', 'dd->d']
|
|
# magictoken.ex_vectorize_dynamic_call_three.end
|
|
|
|
self.assertEqual(result, 2.0)
|
|
if IS_WIN32:
|
|
correct = ['ll->q', 'dd->d']
|
|
else:
|
|
correct = ['ll->l', 'dd->d']
|
|
self.assertEqual(f.types, correct)
|
|
|
|
# magictoken.ex_vectorize_dynamic_call_four.begin
|
|
@vectorize
|
|
def g(a, b):
|
|
return a / b
|
|
|
|
print(g(2.,3.))
|
|
# 0.66666666666666663
|
|
|
|
print(g(2,3))
|
|
# 0.66666666666666663
|
|
|
|
print(g.types)
|
|
# ['dd->d']
|
|
# magictoken.ex_vectorize_dynamic_call_four.end
|
|
|
|
correct = ['dd->d']
|
|
self.assertEqual(g.types, correct)
|
|
|
|
def test_guvectorize_dynamic(self):
|
|
with captured_stdout():
|
|
# magictoken.ex_guvectorize_dynamic.begin
|
|
from numba import guvectorize
|
|
import numpy as np
|
|
|
|
@guvectorize('(n),()->(n)')
|
|
def g(x, y, res):
|
|
for i in range(x.shape[0]):
|
|
res[i] = x[i] + y
|
|
# magictoken.ex_guvectorize_dynamic.end
|
|
|
|
# magictoken.ex_guvectorize_dynamic_call_one.begin
|
|
x = np.arange(5, dtype=np.int64)
|
|
y = 10
|
|
res = np.zeros_like(x)
|
|
g(x, y, res)
|
|
# res == array([10, 11, 12, 13, 14])
|
|
print(g.types)
|
|
# ['ll->l']
|
|
# magictoken.ex_guvectorize_dynamic_call_one.end
|
|
|
|
correct = np.array([10, 11, 12, 13, 14])
|
|
np.testing.assert_array_equal(res, correct)
|
|
if IS_WIN32:
|
|
correct = ['qq->q']
|
|
else:
|
|
correct = ['ll->l']
|
|
self.assertEqual(g.types, correct)
|
|
|
|
# magictoken.ex_guvectorize_dynamic_call_two.begin
|
|
x = np.arange(5, dtype=np.double)
|
|
y = 2.2
|
|
res = np.zeros_like(x)
|
|
g(x, y, res)
|
|
# res == array([2.2, 3.2, 4.2, 5.2, 6.2])
|
|
# magictoken.ex_guvectorize_dynamic_call_two.end
|
|
|
|
# magictoken.ex_guvectorize_dynamic_call_three.begin
|
|
print(g.types) # shorthand for g.ufunc.types
|
|
# ['ll->l', 'dd->d']
|
|
# magictoken.ex_guvectorize_dynamic_call_three.end
|
|
|
|
if IS_WIN32:
|
|
correct = ['qq->q', 'dd->d']
|
|
else:
|
|
correct = ['ll->l', 'dd->d']
|
|
self.assertEqual(g.types, correct)
|
|
|
|
# magictoken.ex_guvectorize_dynamic_call_four.begin
|
|
x = np.arange(5, dtype=np.int64)
|
|
y = 2.2
|
|
res = np.zeros_like(x)
|
|
g(x, y, res)
|
|
print(res)
|
|
# res == array([2, 3, 4, 5, 6])
|
|
# magictoken.ex_guvectorize_dynamic_call_four.end
|
|
|
|
correct = np.array([2, 3, 4, 5, 6])
|
|
np.testing.assert_array_equal(res, correct)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|