Need to speed up things by calling a C function from your Python script? Check this out.
This will be a really short blogpost which mainly serves as a personal reminder on how to call a C function from Python… the title is pretty self-explanatory.
I will show how to call some really simple c
functions
wich return a double or an array (which will be a np.array
in Python).
Here we have our simple c
file
cfunctions.c
:
#include<stdlib.h>
long factorial(int n){
//
long res = 1;
if (n <= 0) {
return -1;
}
else {
for (long i = 1; i <= n; i++) {
*= i;
res }
}
return res;
}
double dotproduct(int dim, double a[dim], double b[dim]){
// Compute the dot product between two vectors...
// e.g. a = [1,2,3,4] , b = [4,3,2,1]
// res = 1*4 + 2*3 + 3*2 + 4*1 = 4 + 6 + 6 + 4 = 20
double res = 0;
for(int i = 0; i < dim; i++){
= res + a[i]*b[i];
res }
return res;
}
double * elementwiseproduct(int dim, double a[dim], double b[dim]){
// Compute the elementiwise product between two vectors...
// e.g. a = [1,2,3,4] , b = [4,3,2,1]
// res will point to an array such as [1*4, 2*3, 3*2, 4*1] = [4,6,6,4]
double * res = (double *) malloc(sizeof(double) * dim);
for(int i = 0; i < dim; i++){
[i] = a[i]*b[i];
res}
return res;
}
We then create a shared object witht the following command:
cc -fPIC -shared -o cfunctions.so cfunctions.c
Then we can write a Python script py_cfunctions.py
such
as:
import ctypes
import numpy as np
def factorial(num: int):
= ctypes.c_long
py_cfunctions.factorial.restype return py_cfunctions.factorial(num)
def dotproduct(dim: int, a: np.array, b: np.array):
# Convert np.array to ctype doubles
= a.astype(np.double)
a_data = a_data.ctypes.data_as(c_double_p)
a_data_p = b.astype(np.double)
b_data = b_data.ctypes.data_as(c_double_p)
b_data_p = ctypes.c_double
py_cfunctions.dotproduct.restype # Compute result...
return py_cfunctions.dotproduct(dim,a_data_p,b_data_p)
def elementwiseproduct(dim: int, a: np.array, b: np.array):
# Convert np.array to ctype doubles
= a.astype(np.double)
a_data = a_data.ctypes.data_as(c_double_p)
a_data_p = b.astype(np.double)
b_data = b_data.ctypes.data_as(c_double_p)
b_data_p
= np.ctypeslib.ndpointer(dtype=ctypes.c_double,shape=(dim,))
py_cfunctions.elementwiseproduct.restype # Compute result...
return py_cfunctions.elementwiseproduct(dim,a_data_p,b_data_p)
# so_file genreated with:
# cc -fPIC -shared -o cfunctions.so cfunctions.c
= 'MY_PATH/cfunctions.so'
so_file = ctypes.CDLL(so_file)
py_cfunctions = ctypes.POINTER(ctypes.c_double)
c_double_p = [ctypes.c_int]
py_cfunctions.factorial.argtypes = [ctypes.c_int, c_double_p, c_double_p]
py_cfunctions.elementwiseproduct.argtypes = [ctypes.c_int, c_double_p, c_double_p] py_cfunctions.dotproduct.argtypes
And that’s it! You now can import py_cfunctions
and call
factorial()
, dotproduct()
and
elementwiseproduct()
.
For attribution, please cite this work as
Bonvini (2021, March 3). Last Week's Potatoes: How to call a C function from Python.. Retrieved from https://lastweekspotatoes.com/posts/2021-07-21-how-to-call-a-c-function-from-python/
BibTeX citation
@misc{bonvini2021how, author = {Bonvini, Andrea}, title = {Last Week's Potatoes: How to call a C function from Python.}, url = {https://lastweekspotatoes.com/posts/2021-07-21-how-to-call-a-c-function-from-python/}, year = {2021} }