LoginSignup
2
2

More than 1 year has passed since last update.

SymPyのシンボル生成について色々触れてみる

Posted at

以前の記事でもSymPyのシンボル生成についてある程度触れていましたが、その記事で漏れている点などもぼちぼちあったため再度記事にまとめておきます。

インストール手順などは今回はスキップするため、必要な方は以下の記事などをご確認ください。

※記事の執筆者は理系出身ではないため数学の知識などで粗い点はご容赦ください。

使うもの

  • Python 3.9.0
  • Jupyter (VS Code上のものを利用)
  • sympy==1.8

Symbolクラスによるシンボル単体の作成

一番シンプルなシンボル単体の生成法としてはSymbolクラスを使う形となります。第一引数には基本的に割り当てる変数名と同じ名前の文字列を指定します。

from sympy import Symbol

x = Symbol('x')
y = Symbol('y')

symbols関数による複数シンボルの一括作成

symbols関数で複数のシンボルを同時に作成することができます。シンボル名以外の設定が一緒な場合などに便利です。第一引数にはコンマ区切りもしくはスペース区切りで設定するシンボル名を指定します。

from sympy import symbols

x, y, z = symbols('x,y,z')

上記の記述は以下のようにスペース区切りで指定しても同様の挙動をします。

x, y, z = symbols('x y z')

シンボルに下付き文字の数字と上付き文字を設定する

シンボル名下付き文字の数字__上付き文字といったように第一引数に指定すると、シンボルに下付き文字と上付き文字を設定することができます。たとえばxというシンボルに3という下付き文字と5という上付き文字を設定したければx3__5という記述になります。

x = Symbol('x3__5')
x

image.png

なお、この書き方の場合は下付き文字は数字のみ受け付けられます。アルファベットなどを指定するとシンボル名の一部として扱われてしまいます。アンダースコア2つの後の上付き文字の指定は数字以外でも指定することができます。

x = Symbol('xa__b')
x

image.png

アンダースコア1つで下付き文字、2つで上付き文字を設定する

下付き文字は直前にアンダースコア1つを付けて指定する書き方もできます。この書き方の場合前節であったような数字縛りなどはなくアルファベットの下付き文字などを設定できます。

x = Symbol('x_a__b')
x

image.png

上付き文字などをLaTeXで設定する

下付き文字はLaTeXでもアンダースコア1つなので変わりませんが、上付き文字はLaTeXと同じ記述でキャレットの記号(^)で指定することもできます。

x = Symbol('x_1^2')
x

image.png

その他のシンボル設定をLaTeXで行う

他のシンボル設定もLaTeXの記法で行うことができます。\の記号を使うことが多くなると思いますが、その場合にはraw文字としてのrの指定を文字列の前に設定しておくのが無難そうです。

x = Symbol(r'\dot{\textrm{x}}_a^b')
x

image.png

ギリシャ文字の文字列などは1つの文字に変換される

シンボル名に指定したギリシャ文字は単一のギリシャ文字のシンボルに変換されます。例えばalphaと指定するとαになります。

alpha = Symbol('alpha')
alpha

image.png

日本語環境のIMEなど使われている場合はαなどは普通に変換できるでしょうからダイレクトにそれらの文字を指定しても変わりません。

alpha = Symbol('α')
alpha

image.png

仮定の設定

シンボルにはassumption(仮定)の各種属性の設定が存在します。例えば「整数である」「素数である」「交換可能である」といったような各属性が該当します。

それぞれはSymbolクラスのコンストラクタ(もしくはsymbols関数など)でキーワード引数に真偽値で指定します。例えば「整数である」という仮定であればinteger=Trueと指定します。

x = Symbol('x', integer=True)

各assumptionの設定値はis_<assumption名>というプロパティで参照できます。例えば整数かどうかであればis_integerというプロパティ名でアクセスすることができます。

>>> x.is_integer
True

なお、これらのプロパティの値は満たす場合にはTrue、満たさない場合にはFalse、どちらか分からない場合(設定が明示されていない場合など)にはNoneとなります。TrueとFalseだけでなくNoneのケースも発生するので注意してください。たとえば以下のようにinteger引数を指定せずにシンボルを作成してみるとis_integerの値がNoneになっていることが確認できます。

>>> x = Symbol('x')
>>> print(x.is_integer)
None

仮定の属性値の伝搬

各種仮定の属性を持ったシンボルを使って数式表現などを作った場合それらの属性は引き継がれたり値が変わったりするケースがあります。

例として「偶数である」という仮定をeven=Trueという引数で設定してxのシンボルを作ってみます。

>>> x = Symbol('x', even=True)
>>> x.is_even
True

このシンボルに2を加えて数式表現を作ってみます。

expression = x + 2
expression

image.png

元が「偶数である」というシンボルに対して2を加える数式の場合必ず偶数になることは分かります。そのためその数式のis_evenプロパティの値はTrueのまま伝搬していることが確認できます。

>>> expression.is_even
True

逆に1を指定してみると結果の数式表現のis_evenプロパティはFalseになっていることを確認できます。

>>> expression = x + 1
>>> expression.is_even
False

また、直接は設定していない仮定の属性でも同時に設定されることがあります。たとえばシンボルが「偶数ある」という仮定が設定されていれば「奇数ではない」という条件も成り立ちます。以下のようにis_oddを確認するとFalseとなっていることが分かります。

>>> x.is_odd
False

主な仮定の属性値の一覧

前節まででis_evenやis_integerなどに触れてきましたが、他にも色々な属性があり一覧にすると主に以下のような仮定の属性がSymPyに存在します。それぞれevenやintegerのキーワード引数でコンストラクタで指定したりis_の形式の属性でアクセスすることができます。

属性名 属性の説明
is_integer 整数かどうか。
is_odd 奇数かどうか。
is_even 偶数かどうか。
is_zero 0かどうか。
is_nonzero 0以外かどうか。
is_positive 正の値かどうか。
is_nonpositive 正の値以外かどうか。
is_negative 負の値かどうか。
is_nonnegative 負の値以外かどうか。
is_prime 素数かどうか。
is_complex 複素数かどうか。
is_real 実数かどうか。
is_imaginary 虚数かどうか。
is_rational 有理数かどうか。
is_irrational 無理数かどうか。
is_algebraic 代数的数かどうか。
is_transendental 超越数かどうか。
is_commutative 可換(交換可能)かどうか。
is_hermitian エルミート作用素かどうか。
is_antihermitian エルミート作用素以外かどうか。

symbols関数での返却値の型の変動

symbols関数ではコンマやスペースなどを含まずに単一のシンボル名のみを指定すると返却値はSymbolクラスを使ったときと同じように単一のシンボルが返ってきます。

from sympy import symbols

x = symbols('x')
x

image.png

一方で前節までで触れたようにコンマやスペースを含めると返却値はタプルとなります(返却値側もx, yといったようにコンマ区切りなどで設定するか、一旦タプルのままで受け取る必要があります)。

from sympy import symbols

x, y = symbols('x,y')

このように引数に応じて返却値の型が変わるので指定を動的に変える場合などは注意が必要です。

symbols関数の返却値をタプルに固定する

単一のシンボル名をsymbols関数の引数に指定した場合でも返却値をタプルに固定したい場合にはseq引数にTrueを指定します。引数のシンボル名の指定を問わず単一の型となるので扱いがシンプルになるケースがあるかもしれません。

tuple_val = symbols('x', seq=True)
print(tuple_val)
print(type(tuple_val))
(x,)
<class 'tuple'>

symbols関数にコンマやスペース区切りの文字列でなはくタプルを指定する

symbols関数にはコンマ区切りなどの文字列ではなくそのままシンボル名を格納しタプルを指定することもできます。挙動はコンマ区切りの文字列などで指定した際の同じです。

x, y, z = symbols(('x', 'y', 'z'))

symbols関数にリストや集合を指定した場合にはそのままリストや集合になる

symbols関数にリストや集合(set)で値を指定した場合にはタプルの時のように各シンボルに展開されることはなくそのままリストや集合の値で返ってきます。ただしリストなどに含まれる値はSymPyのシンボルになっています。

xyz = symbols(['x', 'y', 'z'])
print(xyz)
print(type(xyz))
print(type(xyz[0]))
[x, y, z]
<class 'list'>
<class 'sympy.core.symbol.Symbol'>

スライス等のような記法で複数のシンボルの生成を行う

symbols関数ではPythonのリストやNumPyでのスライスのような記法で複数の連続したシンボルの生成処理を行うことができます。それぞれ書き方のパターンがあるため以降の節で触れていきます。

0から特定の値までの範囲の下付き文字を含んだシンボルを生成する

<シンボル名>:<終点の位置の番号>という形式でsymbols関数の引数に文字列で指定すると0~終点の位置の番号 - 1までの範囲の下付き文字のついた複数のシンボルを得ることができます。例えば'x:3'と指定すると$x_0$, $x_1$, $x_2$の3つのシンボルを得ることができます。

from IPython.display import display
x0, x1, x2 = symbols('x:3')
display(x0, x1, x2)

image.png

特定の始点位置から特定の最終位置までの下付き文字を含んだシンボルを生成する

<シンボル名><始点位置の番号>:<終点の位置の番号>という形でsymbols関数の引数に文字列を指定すると始点の位置の番号~終点の位置の番号 - 1の範囲の下付き文字のついた複数のシンボルを得ることができます。

例えば'x3:6'という指定をすれば$x_3$、$x_4$、$x_5$という3つのシンボルを得ることができます。

from sympy import symbols
from IPython.display import display

x3, x4, x5 = symbols('x3:6')
display(x3, x4, x5)

image.png

コンマ区切りなどでの複数のシンボルの指定と範囲指定を組み合わせる

symbols関数はコンマ区切りなどで複数のシンボルを生成できるとは以前の節で触れましたが、この使い方は範囲を指定して下付き文字を設定した場合も有効です。

例えば'x1:3,y3:6'と指定することで$x_1$, $x_2$, $y_3$, $y_4$, $y_5$といったようにxとyそれぞれのシンボルを生成することができます。

x1, x2, y3, y4, y5 = symbols('x1:3,y3:6')
display(x1, x2, y3, y4, y5)

image.png

括弧を付けることで行列やテンソルの表現ができる

'<シンボル名><通常の範囲指定の番号>(<2次元目(列)の範囲指定の番号>)'といったように()の括弧を付けることで行列の表現ができます。

例えば'x3:5'という指定であれば$x_3$, $x_4$という2つのベクトル的な値になりますが、ここに(1:4)という指定を追加して'x3:5(1:4)'と書けばすれば$x_{31}$, $x_{32}$, $x_{33}$, $x_{41}$, $x_{42}$, $x_{43}$といったように2次元目のインデックスが付与される形で各シンボルが生成されます。

tuple_value = symbols('x3:5(1:4)')
tuple_value
(x31, x32, x33, x41, x42, x43)
display(tuple_value[0], tuple_value[-1])

image.png

この括弧の記述はどんどん繋げて3階のテンソル、4階のテンソル・・・としていくことも可能です($x_{312}$, $x_{433}$といったように)。

tuple_value = symbols('x3:5(1:4)(2:4)')
tuple_value
(x312, x313, x322, x323, x332, x333, x412, x413, x422, x423, x432, x433)

アルファベットの範囲を指定してシンボルを生成する

'<始点シンボル名>:<終点シンボル名>'という記述でアルファベットの範囲でシンボルを生成することができます。例えば'x:z'とすればx, y, zの3つのシンボルが生成されます。数値の範囲の終点と異なりこちらの場合は終点の指定も含まれます。

x, y, z = symbols('x:z')
display(x, y, z)

image.png

タプルで範囲を指定すると2次元のタプルになって返ってくる

引数を文字列ではなくタプルで指定し、タプルの値を範囲指定をした文字列で指定すると2次元のタプルになって返ってきます。

tuples = symbols(('x1:3', 'y2:4'))
tuples
((x1, x2), (y2, y3))
x1 = tuples[0][0]
y2 = tuples[1][0]
display(x1, y2)

image.png

参考文献・参考サイトまとめ

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2