Movatterモバイル変換


[0]ホーム

URL:


ctypes-demo

Source files atgithub.com:casperdcl/ctypes-demo, based onbitbucket.org:chris_richardson/ctypes-demo

C Source

mylib.c:

#include "math.h"void add(double *in_data, double *out_data, int n){  int i;  for (i = 0; i != n; ++i)      out_data[i] += in_data[i];}

Compile

gcc -shared -fPIC -o mylib_shared.so mylib.cnm -a mylib_shared.so  # list symbols

Wrap

ctypes

mylib.py:

from ctypes import CDLL, POINTER, c_doubleimport numpy as npMYLIB = CDLL("./mylib_shared.so")def get_ptr(np_arr, dtype=c_double):    return np_arr.ctypes.data_as(POINTER(dtype))def add(x, y, n):    assert x.dtype == y.dtype == np.float64    MYLIB.add(get_ptr(x), get_ptr(y), n)

Use as:

import numpy as npimport mylibx = np.arange(3, dtype=numpy.float64)y = x.copy()mylib.add(x, y, 3)print(y)

cffi

mylib.py:

from cffi import FFIffi = FFI()ffi.cdef("void add(double *in_data, double *out_data, int n);")MYLIB = ffi.dlopen("./mylib_shared.so")def add(x, y, n):    MYLIB.add(        ffi.cast("double *", x.ctypes.data),        ffi.cast("double *", y.ctypes.data),        n)

Alternative in-place:

from cffi import FFIffi = FFI()ffi.cdef("void add(double *in_data, double *out_data, int n);")ffi.set_source("mylib_shared", open("mylib.c").read())ffi.compile(verbose=True)from mylib_shared import lib as MYLIBadd = MYLIB.add

Use as withctypes.

numba

Compile python itself:

from numba import jit@jitdef add(...):    ...

Advanced:

from numba import jitimport numpy as np@jitdef calculate_distances(n):    pts = np.random.random((n, 3))    d = np.zeros((n, n))    for i in range(n):        for j in range(n):            d[i, j] = np.linalg.norm(pts[i,:] - pts[j,:])    return dn = 1000d = calculate_distances(n)llvm = calculate_distances.inspect_llvm()for k, v in llvm.items():    print(k, v)print(d)

Even more advanced:

# Example demonstrating numba cfunc to provide a compiled callback kernelfrom ctypes import POINTER, c_double, c_intfrom numba import cfunc, types, carray, jitimport numpy as np# This is the kernel we want to call from our bigger librarydef calculate_distances(_d, _pts, n):    d = carray(_d, (n, n), dtype=np.float64)    pts = carray(_pts, (n, 3), dtype=np.float64)    for i in range(n):        for j in range(n):            d[i, j] = np.linalg.norm(pts[i, :] - pts[j, :])# C signaturesig = types.void(    types.CPointer(types.double),    types.CPointer(types.double),    types.intc)fn = cfunc(sig, nopython=True)(calculate_distances)  # compile with LLVM# Take a look at the codeprint(fn.inspect_llvm())# Show the memory address of the functionprint('0x%0x'%fn.address)n = 12d = np.zeros((n, n), dtype=np.float64)pts = np.random.random((n, 3))# Convenient ctypes wrapper allows us to test it from Pythonfn.ctypes(d.ctypes.data_as(POINTER(c_double)),          pts.ctypes.data_as(POINTER(c_double)), n)np.set_printoptions(precision=2)print(d)

Wrap C++

code.cpp:

class Foo{public:  std::vector<double> dist(){ ... }};

pybind11

Replacement forboost::python

point_cloud.cpp:

#include <cmath>#include <vector>class PointCloud {public:  PointCloud(std::vector<double> &points) : _points(points) {}  std::vector<double> calculate_distances() {    unsigned int n = _points.size() / 3;    std::vector<double> result(n * n);    for (unsigned int i = 0; i != n; ++i)      for (unsigned int j = 0; j != n; ++j)        result[i * n + j] = distance(i, j);    return result;  }private:  double distance(unsigned int i, unsigned int j) {    double d = 0.0;    for (unsigned int k = 0; k != 3; ++k) {      double d0 = _points[i * 3 + k] - _points[j * 3 + k];      d += d0 * d0;    }    return std::sqrt(d);  }  std::vector<double> _points;};

wrap_point_cloud.cpp:

#include <point_cloud.cpp>  // bad practice ...// ... you should have a header and link libs instead, but you get the idea#include <pybind11/pybind11.h>#include <pybind11/stl.h>// Wrappers using pybind11namespace py = pybind11;PYBIND11_MODULE(point_cloud, m) {  py::class_<PointCloud>(m, "PointCloud")  // class      .def(py::init<std::vector<double> &>())  // initialiser      .def("calculate_distances", &PointCloud::calculate_distances);}

setup.py:

from distutils.core import setupfrom distutils.extension import Extensionimport pybind11pybind11_include = pybind11.get_include()setup(name='point_cloud',      version='1.0',      ext_modules=[Extension(          "point_cloud",          ['wrap_point_cloud.cpp'],          language='c++',          #include_dirs=[pybind11_include, '/usr/include/eigen3'],          include_dirs=[pybind11_include],          extra_compile_args=['-std=c++11'])])

Use:

python setup.py buildPYTHONPATH="$PYTHONPATH:$PWD/build/lib*" python -c "
from point_cloud import PointCloudimport numpy as npn = 5pts = np.random.random((n, 3))p = PointCloud(pts.flatten().tolist())  # list -> std::vectord_list = p.calculate_distances()  # std::vector -> listd = np.array(d_list).reshape((n, n))  # Reshape with numpyprint(d)
"

swig

Best for multi-language interfaces, not great if only wrapping for Python.

pycuda

Similar to in-placecffi.


[8]ページ先頭

©2009-2025 Movatter.jp