LoginSignup
0
0

More than 3 years have passed since last update.

Python de 対称群 2

Last updated at Posted at 2020-12-17

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

0
0
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
0
0