Skip to content
Snippets Groups Projects
Commit 5759530a authored by Repo Updater's avatar Repo Updater
Browse files

b10c604c polish pybind11 example, add README.md to f2py example

parent a95c8dbf
No related branches found
No related tags found
No related merge requests found
Showing with 95 additions and 26 deletions
# directories
__pycache__
#__pycache__
.unison
.ipynb_checkpoints
# files
*.so
*.o
#*.so
#*.o
*.lprof
*.tmp
......@@ -2,11 +2,10 @@
## Features
* Python module "foobar" lives in the directory "foobar" (has `__index__.py`)
* Python module "foobar.hello" lives in the directory "foobar" (has `__index__.py`)
* `c_hello.c` contains a hello-world implementation in C
* `hello.pyx` provides the sub-module 'foobar.hello' and contains the Python interface written in Cython
* `hello.pyx` provides the module 'foobar.hello' and contains the Python interface written in Cython
* `setup.py` contains code to compile the extension, both the source files are compiled into the same shared object
* `setup.py` demonstrates how to implement a clean command
## Usage
......@@ -15,5 +14,5 @@
`python -c "from foobar import hello; hello.say_hello()"`
* or install the package, and run the extension from anywhere
`python setup.py install --user`
* alternatively, run `test_foobar.py` to call the compiled code example
* run `test_foobar.py` to call the compiled code example
......@@ -2,7 +2,8 @@ import os
from setuptools import setup, Extension
ext = Extension("foobar.hello",
sources=["foobar/hello.pyx", "foobar/c_hello.c"])
sources=["foobar/hello.pyx", "foobar/c_hello.c"]
)
setup(name="foobar",
ext_modules=[ext],
......
......@@ -6,10 +6,10 @@
* `hello.pyx` contains the Python interface written in Cython
* `c_hello.c` contains a hello-world implementation in C, however, in contrast
to the previous simple example it is located in a different library (.so,
shared object) in the directory `libhello`. Use `make` to generate the
shared object.
shared object) in the directory `libhello`.
Use `make` to generate the shared object in that directory.
* `setup.py` contains code to compile the extension, demonstrating how to link
the shared object in a stable way
the shared object in a stable way.
## Usage
......
all: libhello.so
libhello.so: c_hello.c
gcc -Wall -fPIC -c c_hello.c
gcc -shared -o $@ c_hello.o
$(CC) -Wall -fPIC -c c_hello.c
$(CC) -shared -o $@ c_hello.o
.PHONY: clean
clean:
......
import os
from setuptools import setup, Extension
libhello_dir = os.path.abspath("./libhello")
# We need to specify the location of the include file.
......@@ -19,7 +18,8 @@ ld_flags.append("-lhello") # link libhello
ext = Extension("wrap_libhello.hello",
sources=["wrap_libhello/hello.pyx"],
extra_link_args=ld_flags,
include_dirs=include_dirs)
include_dirs=include_dirs
)
setup(name="wrap_libhello",
ext_modules=[ext],
......
......@@ -2,7 +2,7 @@
## Features
* Python module "ctonumpy" lives in the directory "ctonumpy" (has `__init__.py`)
* Python module "ctonumpy.cube" lives in the directory "ctonumpy" (has `__init__.py`)
* `c_cube.c` contains a OMP parallel loop-based computation of the third power of an array
* `cube.pyx` contains the Python interface written in Cython
* `setup.py` contains code to compile the extension with optimizing compiler flags
......
......@@ -16,14 +16,15 @@ c_flags.append("-fopt-info")
include_dirs = []
include_dirs.append(np.get_include())
# extra link flags are possible as well; we leave them empty here
ld_flags = []
# extra link flags are possible as well; here we use the same as for compilation to link to libgomp
ld_flags = c_flags
ext = Extension("ctonumpy.cube",
sources=["ctonumpy/cube.pyx", "ctonumpy/c_cube.c"],
extra_compile_args=c_flags,
extra_link_args=ld_flags,
include_dirs=[np.get_include()])
include_dirs=[np.get_include()]
)
setup(name="ctonumpy",
ext_modules=[ext],
......
# Minimal example on how-to interface with Fortran code using 'f2py'
Options:
* compile on the command line using `f2py`, cf. 'compile_with_f2py.sh'
* compile using 'setup.py', using the command `python setup.py build_ext --inplace`
Run the module using 'test_fibonacci.py'.
File moved
# Minimal example showing how to wrap C/C++ code into Python/Numpy using pybind11
* you may need to run `pip install --user pybind11` if not yet installed
* run `python test_pybex.py` to see the 'pybex' module in action
......@@ -2,10 +2,15 @@ from setuptools import setup
# run `pip install --user pybind11` if not yet installed
from pybind11.setup_helpers import Pybind11Extension, build_ext
# extra compile/link args may be injected, e.g. here for optimization and openmp with gcc
extra_gcc_args=['-O3', '-march=native', '-fopenmp']
ext_modules = [
Pybind11Extension(
"pybex",
["src/pybex.cpp",],
extra_compile_args=extra_gcc_args,
extra_link_args=extra_gcc_args
),
]
......
// pybind11 example module 'pybex'
#include <vector>
#include <numeric>
#include <functional>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
// C/C++ implementation of the function to be wrapped
void c_cube(const double * v_in, double * v_out, size_t n_elem) {
#pragma omp parallel for simd default(none) shared(v_in, v_out, n_elem)
for (size_t i=0; i<n_elem; ++i) {
v_out[i] = v_in[i] * v_in[i] * v_in[i];
}
}
namespace py = pybind11;
// wrapper function, accepting a NumPy array as input and returning a NumPy array
py::array_t<double> py_cube(py::array_t<double, py::array::c_style> v_in)
py::array_t<double> py_cube(py::array_t<double, py::array::c_style> np_in)
{
// allocate buffer to be returned as a NumPy array
auto v_out = py::array_t<double>(v_in.size());
double * v_out_ptr = (double*) v_out.request().ptr;
// obtain information about the input array
py::buffer_info pybuf_in = np_in.request();
auto shape = pybuf_in.shape;
// create output NumPy array of the same size and dimension
py::array_t<double, py::array::c_style> np_out(shape);
c_cube(v_in.data(), v_out_ptr, v_in.size());
// call C/C++ function with proper arguments
double * pybuf_in_ptr = (double*) pybuf_in.ptr;
double * pybuf_out_ptr = (double*) np_out.request().ptr;
size_t count = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<size_t>());
c_cube(pybuf_in_ptr, pybuf_out_ptr, count);
return v_out;
return np_out;
}
// define Python module, expose py_cube function as "cube" to python
PYBIND11_MODULE(pybex, m) {
m.doc() = "pybind11 example module"; // module docstring
......
#!/usr/bin/env python
import numpy as np
from time import time
from pybex import cube
def test_pybex_cube(N=384):
v = np.full((N, N, N), fill_value=2.0)
# (1) compute the result using our C extension
t0 = time()
w_ext = cube(v)
dt0 = time() - t0
# (2) compute the result using NumPy, note the relative inefficiency
t0 = time()
w_ref = v * v * v
dt1 = time() - t0
# (3) compare both the results, be careful with NumPy temporary arrays
try:
assert(np.allclose(w_ext, w_ref))
#assert(np.allclose(w_ext[-1,-1,-1], w_ref[-1,-1,-1]))
except:
raise
else:
print("OK! t(C)=%f, t(NumPy)=%f" % (dt0, dt1))
if __name__ == "__main__":
test_pybex_cube()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment