[PYTHON] Writing C language with Sympy (metaprogramming)

Introduction

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).

Overview

** 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.

Installation

You can install Sympy with pip.

pip install sympy

For download, click below.

import

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.

Creating a symbol

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.

Matrix multiplication

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.

Convert to C language

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.

Source 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)

Summary

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

Writing C language with Sympy (metaprogramming)
Segfault with 16 characters in C language
Build a C language development environment with a container
Writing logs to CSV file (Python, C language)
Debugging C / C ++ with gdb
C language ALDS1_3_B Queue
Container-like # 2 made with C
[C language algorithm] Endianness
Overlay graphs with sympy
With Sympy, don't worry
[C language algorithm] Block movement
[Python] Solve equations with sympy
Machine language embedding in C language
C language ALDS1_4_B Binary Search
Heapsort made in C language
ABC163 C problem with python3
Equation of motion with sympy
[C language] readdir () vs readdir_r ()
Format C source with pycparser
C language ALDS1_4_A Linear Search
ABC188 C problem with python3
ABC187 C problem with python
Let's utilize the design pattern like C language with OSS design_pattern_for_c!