What is ** Metaprogramming **?
** Metaprogramming ** (metaprogramming) is a type of programming technique that does not code logic directly, but rather a pattern. How to program with high-level logic that generates logic with
Exhibitor: [wikipedia](https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%BF%E3%83%97%E3%83%AD%E3%82%B0%E3 % 83% A9% E3% 83% 9F% E3% 83% B3% E3% 82% B0)
In short, ** Write code that generates code and write complex code! ** That (I interpret it, please let me know if it's wrong).
** Generate formulas using Python's computer algebra library Sympy and convert them to C language. ** Sympy seems to be often used for computer algebra like Mathematica, but it also has the ability to convert mathematical formulas into various languages. I haven't used it much, but it also has the ability to output a function with a header file.
In this article, as an introduction, we will metaprogram the multiplication code of the ** n × n matrix with Sympy. ** ** The notation and usage of Sympy is summarized below, so if you are interested, please read it.
You can install Sympy with pip.
pip install sympy
For download, click below.
First, import Sympy.
from sympy import *
Since I want to implement matrix calculation this time, I will also import Matrix.
from sympy import Matrix
Now you can declare Matrix as well.
Variables used in formulas must be declared in advance as symbols. For example, to declare x and y as symbols
x = symbols('x')
y = symbols('y')
If so, it's OK. This time, for matrix calculation, we will define symbol as an element of n × n Matrix.
n = 3
A = Matrix([[symbols('a['+str(j)+']['+str(i)+']') for i in range(n)] for j in range(n)])
B = Matrix([[symbols('b['+str(j)+']['+str(i)+']') for i in range(n)] for j in range(n)])
Now the matrices A and B are declared as follows. Here, n = 3.
⎡a[0][0] a[0][1] a[0][2]⎤
⎢ ⎥
⎢a[1][0] a[1][1] a[1][2]⎥
⎢ ⎥
⎣a[2][0] a[2][1] a[2][2]⎦
⎡b[0][0] b[0][1] b[0][2]⎤
⎢ ⎥
⎢b[1][0] b[1][1] b[1][2]⎥
⎢ ⎥
⎣b[2][0] b[2][1] b[2][2]⎦
If you write pprint (A)
as the output of the matrix, it will be visually easy to understand.
Let the product of the matrices A and B above be the matrix C. Matrix multiplication is easy, and the following is OK.
C = A*B
Now when you look at the contents with print (C)
Matrix([[a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0], a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1], a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2]], [a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0], a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1], a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2]], [a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0], a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1], a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2]]])
You can see that the calculation is done properly.
Conversion to C language
ccode(<Formula>, <Variable to assign>, standard='C99')
It is described as. This time I want to convert and output all the elements of matrix C, so
for i in range(n):
for j in range(n):
idx = i*n+j
code = ccode(C[idx],assign_to=('c['+str(i)+']['+str(j)+']'), standard='C89')
print(code)
It was made. ʻIdx = i * n + j` is an expression that transforms i and j into one dimension. When the above code is executed, the following is output.
c[0][0] = a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0];
c[0][1] = a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1];
c[0][2] = a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2];
c[1][0] = a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0];
c[1][1] = a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1];
c[1][2] = a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2];
c[2][0] = a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0];
c[2][1] = a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1];
c[2][2] = a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2];
Each element of matrix C was calculated and output in C language. Properly; is also attached. All you have to do is paste this into your code.
This is the matrix calculation code created this time.
from sympy import *
from sympy import Matrix
from sympy.utilities.codegen import codegen
n = 3
A = Matrix([[symbols('a['+str(j)+']['+str(i)+']') for i in range(n)] for j in range(n)])
B = Matrix([[symbols('b['+str(j)+']['+str(i)+']') for i in range(n)] for j in range(n)])
pprint(A)
pprint(B)
C = A*B
print(C)
for i in range(n):
for j in range(n):
idx = i*n+j
code = ccode(C[idx],assign_to=('c['+str(i)+']['+str(j)+']'), standard='C89')
print(code)
I metaprogrammed the code to calculate matrix multiplication using Sympy. This kind of calculation can be written without metaprogramming, but it is very useful when implementing a complicated mathematical formula such as "partial differential of the original formula with t." (Is there a merit that the execution speed of matrix multiplication increases a little because there are no for statements?)
We hope for your reference!
Recommended Posts