#plusone() 関数の改良
どうもどこかで見たはずの,前回の tuple でやる方式は,スタンダードではないらしいので,list に変えて,更に拡張・改良する.
##1 前回の関数
以前の関数.出力はコメントアウトで表現.名前は plusone_tuple() に変えた.
import numpy as np
from sympy.combinatorics import *
from sympy import *
init_printing(pretty_print=False)
n = 3
def plusone_tuple(x):
X = tuple([0])
for i in range(n):
a = tuple([tuple(x)[i] + 1])
X = X + a
return Permutation(tuple(X))
print(plusone_tuple(Permutation(0,1,2)))
#(1 2 3)
少し結合が面倒になったり,添字に注意が必要だったりするが,tuple でやるよりも list でやったほうがいい.
とりあえず,内包表記を使って3次対称群の元を[0, 1, 2]に掛けたものを書いてみる.
A = PermutationGroup(SymmetricGroup(n)[0], SymmetricGroup(n)[1])._elements
print(A)
[list(A[i]) for i in range(len(A))]
'''
[Permutation(2), Permutation(0, 1, 2), Permutation(0, 2, 1), Permutation(1, 2), Permutation(2)(0, 1), Permutation(0, 2)]
[[0, 1, 2], [1, 2, 0], [2, 0, 1], [0, 2, 1], [1, 0, 2], [2, 1, 0]]
'''
##2 今回の関数
list にした関数と複数の置換のリストを扱えるよう改良した関数.
from sympy.combinatorics import *
from sympy import *
init_printing(pretty_print=False)
def plusone(x):
add_one = [(i > 0) * (list(x)[i - 1] + 1) for i in range(1 + len(list(x)))]
#(i > 0) is a step function.
return Permutation(add_one)
n = 3
def plusone_list(x):
return plusone(x)
def plusone_multi(list_of_permutations):
return [plusone(list_of_permutations[i]) for i in range(len(list_of_permutations))]
print(A)
AA = plusone_multi(A)
AA
'''
[Permutation(2), Permutation(0, 1, 2), Permutation(0, 2, 1), Permutation(1, 2), Permutation(2)(0, 1), Permutation(0, 2)]
[(3), (1 2 3), (1 3 2), (2 3), (3)(1 2), (1 3)]
'''
ちなみに面倒くさいがこうしても同じである.
generate_Sym3_perm = PermutationGroup(plusone(SymmetricGroup(n)[0]), plusone(SymmetricGroup(n)[1]))._elements
generate_Sym3_perm
'''
[(3), (1 2 3), (1 3 2), (2 3), (3)(1 2), (1 3)]
'''
以下の list_multi() が複数の置換のリストを list に変換する.これで tuple を介在させずに,list で統一的に対称群の元を扱えるようになった.このほうがどう考えてもシンプルである.
def list_multi(list_of_permutations):
return [list(list_of_permutations[i]) for i in range(len(list_of_permutations))]
print(list_multi(A))
print(list_multi(AA))
'''
[[0, 1, 2], [1, 2, 0], [2, 0, 1], [0, 2, 1], [1, 0, 2], [2, 1, 0]]
[[0, 1, 2, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 1, 3, 2], [0, 2, 1, 3], [0, 3, 2, 1]]
'''
##3 3次対称群をシンプルに計算
3次対称群の要素を表示する.
Sym3_perm = SymmetricGroup(n)._elements
Sym3_perm
'''
[(2), (0 1 2), (0 2 1), (1 2), (2)(0 1), (0 2)]
'''
1から始まる表示にして,リスト([0,1,2,3]に置換を掛けた結果)に直してみる.
Sym3_list = list_multi(plusone_multi(Sym3_perm))
Sym3_list
'''
[[0, 1, 2, 3], [0, 2, 3, 1], [0, 3, 1, 2], [0, 1, 3, 2], [0, 2, 1, 3], [0, 3, 2, 1]]
'''
得たかった結果がえられた.
置換とリストを相互に変換できなくなるので,0は残しておく.プログラムは,「3を固定して1, 2を入れ替え」を先に扱い,「2を固定して1, 3を入れ替え」= (1 3) を後に置いている.元の命名が課題になりそうだ.元の数が24になる4次対称群ならなおさらである.
#考察
np.array で出来ることに気づいたので計算時間を測定して比較してみる.
まずは上の.
%%timeit
Sym3_list = list_multi(plusone_multi(Sym3_perm))
Sym3_list
#129 µs ± 6.92 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
#132 µs ± 13.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
#132 µs ± 13.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
numpy.
%%timeit
Sym3_list_np = np.array(plusone_multi(Sym3_perm)).tolist()
Sym3_list_np
#139 µs ± 10.7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
#135 µs ± 5.21 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
#143 µs ± 8.14 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
・1回目は list_multi → np.array
・2回目は np.array → list_multi
・3回目は並列に実行してみた.
誤差の範囲で同じ,と言えそうだ.
ただ,np.array を使って少し重くなるのか,list_multi() を用いたほうがこころなしか速く,安定しているように思う.ここでは,numpy を import する必要もなさそうだ.
前回記事:
Python de 対称群 - Qiita
次の記事:
Python de 対称群 3 - Qiita