Skip to content
Snippets Groups Projects
Commit c5849513 authored by Erik Frisk's avatar Erik Frisk
Browse files

cleanup - remove PyObject versions

parent 0d2aa9b4
No related branches found
No related tags found
No related merge requests found
...@@ -4,13 +4,6 @@ project(nbtest VERSION 0.1.0 LANGUAGES C CXX) ...@@ -4,13 +4,6 @@ project(nbtest VERSION 0.1.0 LANGUAGES C CXX)
find_package(Python 3.10 COMPONENTS Interpreter Development.Module REQUIRED) find_package(Python 3.10 COMPONENTS Interpreter Development.Module REQUIRED)
add_subdirectory(extern/nanobind) add_subdirectory(extern/nanobind)
# Find the NumPy include directory
execute_process(
COMMAND "${Python_EXECUTABLE}" -c "import numpy as np; print(np.get_include())"
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NUMPY_DIR)
message(STATUS "NumPy include directory: ${NUMPY_DIR}")
# Ensure Release build type is set # Ensure Release build type is set
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
...@@ -19,7 +12,6 @@ endif() ...@@ -19,7 +12,6 @@ endif()
# Add the extension module to the build # Add the extension module to the build
nanobind_add_module(my_ext src/my_ext.cc) nanobind_add_module(my_ext src/my_ext.cc)
target_include_directories(my_ext PRIVATE ${NUMPY_DIR})
# Copy the built extension to the src directory # Copy the built extension to the src directory
add_custom_command(TARGET my_ext POST_BUILD add_custom_command(TARGET my_ext POST_BUILD
......
# %% Imports # %% Imports
from my_ext import add, array_sum, array_sum_nocopy, array_sum_pyobj from my_ext import add, array_sum, array_sum_nocopy
import numpy as np import numpy as np
# %% The simple add function # %% The simple add function
...@@ -12,7 +12,6 @@ x = np.random.normal(0, 1, 500) ...@@ -12,7 +12,6 @@ x = np.random.normal(0, 1, 500)
x.sum() x.sum()
array_sum(x) array_sum(x)
array_sum_nocopy(x) array_sum_nocopy(x)
array_sum_pyobj(x)
# array_sum works with lists also (smart conversion) # array_sum works with lists also (smart conversion)
array_sum([1, 2, 3, 4, 5]) array_sum([1, 2, 3, 4, 5])
......
extern "C" {
#include <Python.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <numpy/ndarrayobject.h>
}
#include <nanobind/nanobind.h> #include <nanobind/nanobind.h>
#include <nanobind/ndarray.h> #include <nanobind/ndarray.h>
#include <nanobind/stl/vector.h> #include <nanobind/stl/vector.h>
...@@ -12,17 +6,6 @@ extern "C" { ...@@ -12,17 +6,6 @@ extern "C" {
namespace nb = nanobind; namespace nb = nanobind;
double
array_sum_pyobj(const nb::object &o)
{
// This is an unsafe solution ... but fast
auto *a = reinterpret_cast<PyArrayObject *>(o.ptr()); // Now numpy array object
const auto p = static_cast<double *>(PyArray_DATA(a)); // Pointer to data
const auto sizes = PyArray_SHAPE(a); // Sizes of each dimension
return std::accumulate(p, p + sizes[0], 0.0);
}
int int
add(int a, int b) add(int a, int b)
{ {
...@@ -47,5 +30,4 @@ NB_MODULE(my_ext, m) ...@@ -47,5 +30,4 @@ NB_MODULE(my_ext, m)
m.def("add", &add); m.def("add", &add);
m.def("array_sum", &array_sum); m.def("array_sum", &array_sum);
m.def("array_sum_nocopy", &array_sum_nocopy); m.def("array_sum_nocopy", &array_sum_nocopy);
m.def("array_sum_pyobj", &array_sum_pyobj);
} }
# %%
import timeit
from my_ext import array_sum, array_sum_nocopy, array_sum_pyobj # noqa
import numpy as np
import matplotlib.pyplot as plt
from seaborn import despine
# %% Utils
def bs_mean_ci(x, alpha=0.95, n_bootstrap=1000):
"""Bootstrap mean and confidence interval."""
n, _ = x.shape
mu = np.zeros(n)
ci = np.zeros((n, 2))
for k, xi in enumerate(x):
bs = np.random.choice(xi, size=(n_bootstrap,), replace=True)
mu[k] = bs.mean()
ci[k] = np.percentile(bs, [(1 - alpha) * 100 / 2, 100 - (1 - alpha) * 100 / 2])
return mu, ci
# %% Perform timing experiments
R = 20 # Number of repeated timing experiments
M = 500 # Number of iterations in each timing measurement
N = np.logspace(1, 5, 10).astype(int) # Sizes to test
res = {"np": [], "array_sum": [], "array_sum_nocopy": [], "array_sum_pyobj": []}
for Ni in N:
print(f"Ni = {Ni}")
x = np.random.normal(0, 1, int(Ni))
ri = np.array(timeit.repeat("x.sum()", globals=globals(), number=M, repeat=R)) / M
res["np"].append(ri)
ri = np.array(timeit.repeat("array_sum(x)", globals=globals(), number=M, repeat=R)) / M
res["array_sum"].append(ri)
ri = np.array(timeit.repeat("array_sum_nocopy(x)", globals=globals(), number=M, repeat=R)) / M
res["array_sum_nocopy"].append(ri)
ri = np.array(timeit.repeat("array_sum_pyobj(x)", globals=globals(), number=M, repeat=R)) / M
res["array_sum_pyobj"].append(ri)
for k in res:
res[k] = np.array(res[k])
# %% Plot results
fig, ax = plt.subplots(num=10, clear=True)
for k in res:
mu, ci = bs_mean_ci(res[k])
ax.loglog(N, mu * 1e9, label=k)
ax.fill_between(N, ci[:, 0] * 1e9, ci[:, 1] * 1e9, alpha=0.2)
ax.legend(frameon=False)
ax.set_xlabel("N")
ax.set_ylabel("Time (ns)")
despine(ax=ax)
# %%
plt.show()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment