Call C language functions from Python to exchange multidimensional arrays

Introduction

This time, I'll use ctypes to call my own C function from Python. Since there was no Japanese article on how to give a variable of type double ** as an argument of a C function and return the result to Python with type double **, I searched briefly. So, to be precise, it's not a multidimensional array exchange, but a double ** type variable exchange (quiet).

code

First, prepare the following self-made function. This time we will add n to all the elements of the argument matrix.

libadd.c


#include <stdio.h>

void add_matrix(double **matrix, int row, int col, int n) {
  int i, j;
  for(i=0; i<row; i++){
      for(j=0; j<col; j++){
	      matrix[i][j] = matrix[i][j] + n;
      }
  }
}

And compile as follows.


$ gcc -cpp -fPIC -shared libadd.c -lm -o libadd.so -O3

You need to create libadd.so with the -shared option.

Then on the Python side,

test.py



from ctypes import *
import ctypes.util  
from numpy.ctypeslib import ndpointer 
import numpy as np
from numpy.random import *

#The libadd you just created.specify so file
lib = np.ctypeslib.load_library("libadd.so",".")

#Make it properly
row = 20
col = 5
n = 5
matrix = rand(row, col)

#Prepare pointer type of double pointer
_DOUBLE_PP = ndpointer(dtype=np.uintp, ndim=1, flags='C')
#add_matrix()Specify the type of function argument(ctypes) 
lib.add_matrix.argtypes = [_DOUBLE_PP, c_int32, c_int32, c_int32]
#add_matrix()Specifies the type of value returned by the function(No return value this time)
lib.add_matrix.restype = None

#Magic
tp = np.uintp
mpp = (matrix.__array_interface__['data'][0] + np.arange(matrix.shape[0])*matrix.strides[0]).astype(tp)

#int type is also c type c_Convert to int type and pass
n = ctypes.c_int(n)
row = ctypes.c_int(row)
col = ctypes.c_int(col)

print("before:", matrix)

lib.add_matrix(mpp, row, col, n)

print("after:", matrix)

I will prepare it like this. Here are some things to watch out for (where I'm addicted):

--The add_matrix part of lib.add_matrix.argtypes () and lib.add_matrix.restype () should specify the name of the function you want to call. --Convert integer type variables to types for ctypes. --On the Python side, the result should be stored in matrix instead of mpp. (You don't have to set it in the return value of the C add_matrix () function)

Also, I thought that _DOUBLE_PP could be used with POINTER (POINTER (c_double)), but it was not passed by reference to the C side. (Please tell me if there is another good method.)

The execution result is as follows.

Execution result



$ python test.py
before: [[ 0.38897722  0.46313741  0.84976397  0.64423638  0.95435434]
 [ 0.60333226  0.37742093  0.3465723   0.77567722  0.74132703]
 [ 0.87302221  0.43188915  0.1211892   0.03272387  0.16480218]
 [ 0.60387532  0.37643299  0.72456328  0.67993591  0.6592758 ]
 [ 0.63544435  0.7261329   0.16825874  0.11123031  0.97664729]
 [ 0.58328763  0.85650723  0.77429203  0.12418374  0.44881621]
 [ 0.25106831  0.22417529  0.22837031  0.17608283  0.49529552]
 [ 0.75357385  0.3937937   0.99262338  0.23625638  0.37777575]
 [ 0.887013    0.85391559  0.32386967  0.30482811  0.67282479]
 [ 0.96701627  0.23598535  0.29455679  0.37472803  0.28614415]
 [ 0.82208389  0.87058549  0.21354254  0.18766391  0.13951804]
 [ 0.22836767  0.4051488   0.79205244  0.17489158  0.83368298]
 [ 0.99464033  0.91165387  0.48920652  0.69251231  0.3369773 ]
 [ 0.39567888  0.08322727  0.50138724  0.00972839  0.53206287]
 [ 0.4981778   0.81622292  0.73376253  0.19702753  0.56725497]
 [ 0.37709128  0.8219189   0.59531858  0.60284025  0.75683106]
 [ 0.11898215  0.93335749  0.39432259  0.9733907   0.355181  ]
 [ 0.54600745  0.36843876  0.52919308  0.22250149  0.66595212]
 [ 0.33897066  0.68039774  0.89937153  0.77007464  0.57667845]
 [ 0.08015923  0.42939639  0.82431951  0.05494513  0.89979669]]
after: [[ 5.38897722  5.46313741  5.84976397  5.64423638  5.95435434]
 [ 5.60333226  5.37742093  5.3465723   5.77567722  5.74132703]
 [ 5.87302221  5.43188915  5.1211892   5.03272387  5.16480218]
 [ 5.60387532  5.37643299  5.72456328  5.67993591  5.6592758 ]
 [ 5.63544435  5.7261329   5.16825874  5.11123031  5.97664729]
 [ 5.58328763  5.85650723  5.77429203  5.12418374  5.44881621]
 [ 5.25106831  5.22417529  5.22837031  5.17608283  5.49529552]
 [ 5.75357385  5.3937937   5.99262338  5.23625638  5.37777575]
 [ 5.887013    5.85391559  5.32386967  5.30482811  5.67282479]
 [ 5.96701627  5.23598535  5.29455679  5.37472803  5.28614415]
 [ 5.82208389  5.87058549  5.21354254  5.18766391  5.13951804]
 [ 5.22836767  5.4051488   5.79205244  5.17489158  5.83368298]
 [ 5.99464033  5.91165387  5.48920652  5.69251231  5.3369773 ]
 [ 5.39567888  5.08322727  5.50138724  5.00972839  5.53206287]
 [ 5.4981778   5.81622292  5.73376253  5.19702753  5.56725497]
 [ 5.37709128  5.8219189   5.59531858  5.60284025  5.75683106]
 [ 5.11898215  5.93335749  5.39432259  5.9733907   5.355181  ]
 [ 5.54600745  5.36843876  5.52919308  5.22250149  5.66595212]
 [ 5.33897066  5.68039774  5.89937153  5.77007464  5.57667845]
 [ 5.08015923  5.42939639  5.82431951  5.05494513  5.89979669]]

Let's do it! Great! Even if you do this, it will be considerably faster depending on the content of the process.

I feel like I've read that this will free me from the GIL, so I'd like to use multithreading, or multiprocessing or hybrid parallelism ... but it's not working so far.

reference

Recommended Posts

Call C language functions from Python to exchange multidimensional arrays
Call c language from python (python.h)
C language to see and remember Part 2 Call C language from Python (argument) string
C language to see and remember Part 1 Call C language from Python (hello world)
C language to see and remember Part 4 Call C language from Python (argument) double
C language to see and remember Part 5 Call C language from Python (argument) Array
[Python] How to call a c function from python (ctypes)
C language to see and remember Part 3 Call C language from Python (argument) c = a + b
Call Matlab from Python to optimize
Call C from Python with DragonFFI
Call popcount from Ruby / Python / C #
Introduction to Protobuf-c (C language ⇔ Python)
Python to switch from another language
Go language to see and remember Part 8 Call GO language from Python
Call C / C ++ from Python on Mac
Call your own C language shared library from Python using ctypes
Generate C language from S-expressions in Python
Use C ++ functions from python with pybind11
Writing logs to CSV file (Python, C language)
How to call Cloud API from GCP Cloud Functions
[Python] Precautions when assigning values to multidimensional arrays
Call a Python script from Embedded Python in C ++ / C ++
I want to make C ++ code from Python code!
An easy way to call Java from Python
Changes from Python 3.0 to Python 3.5
Changes from Python 2 to Python 3.0
Introduction to Python language
Try to make a Python module in C language
Call CPLEX from Python (DO cplex)
Post from Python to Slack
Cheating from PHP to Python
Anaconda updated from 4.2.0 to 4.3.0 (python3.5 updated to python3.6)
Study from Python Hour3: Functions
Switch from python2.7 to python3.6 (centos7)
Connect to sqlite from python
Use a scripting language for a comfortable C ++ life-OpenCV-Port Python to C ++-
Pass OpenCV data from the original C ++ library to Python
How to call Python or Julia from Ruby (experimental implementation)
Ported from R language of "Sazae-san's rock-paper-scissors data analysis" to Python
[Python] Hit Keras from TensorFlow and TensorFlow from c ++ to speed up execution
Post a message from IBM Cloud Functions to Slack in Python
Simple code to call a python program from Javascript on EC2
How to connect to Cloud Firestore from Google Cloud Functions with python code
Call dlm from python to run a time-varying coefficient regression model
Pass a list by reference from Python to C ++ with pybind11
[It's not too late to learn Python from 2020] Part 3 Python Language Basic (1)
Call a Python function from p5.js.
Create folders from '01' to '12' with python
Post from python to facebook timeline
[Lambda] [Python] Post to Twitter from Lambda!
Connect to utf8mb4 database from python
Python (from first time to execution)
Post images from Python to Tumblr
10 functions of "language with battery" python
Tips for calling Python from C
Execute Python code from C # GUI
How to wrap C in Python
Run Python scripts synchronously from C #
Call python from nim with Nimpy
How to access wikipedia from python
Did not change from Python 2 to 3