https://arxiv.org/abs/math/9201304
D. E. Knuth, Efficient representation of perm groups,
arXiv:math/9201304 [math.GR].
Przedstawiona implementacja jest działającą wersją roboczą.
Podana implementacja przy pierwszym przebiegu wyznacza zwykle zbyt dużą liczbę silnych generatorów. Dlatego warto uzyskane silne generatory wstawić jeszcze raz do algorytmu, w kolejności rosnącego perm.max().
from perms import Perm
class Group:
"""The class defining a perm group."""
def __init__(self, size):
"""Load up a Group instance."""
self.size = size # rozmiar permutacji w grupie
# Inicjalizacja struktur.
self.Sigma = [(k+1) * [None] for k in range(self.size)]
# Lista Sigma[k] zawiera co najmniej identyczność.
for k in range(self.size):
self.Sigma[k][k] = Perm(self.size) # identyczność sigma_kk
# Silne generatory.
self.all_Sigma = [Perm(self.size)] # E też dodam raz
self.all_T = []
def __str__(self):
"""Return a string representation of the group."""
t = len(self.all_T)
return "Group({}) with {} strong generators".format(self.size, t)
def order(self):
"""Return the group order."""
result = 1
for k in range(self.size):
result = result * sum(1 for perm in self.Sigma[k] if perm)
return result
def __contains__(self, perm):
""" Test if the perm belongs to the group."""
k = self.size - 1 # start od samej góry
while k > 0:
j = perm.data[k]
if self.Sigma[k][j] is None:
return False
perm = ~self.Sigma[k][j] * perm
k = k - 1
return True
def insert(self, perm):
"""The perm inserted into the group generates new
perms in order to satisfy the group properties."""
if self.size != perm.size:
raise ValueError("wrong size of the perm")
self.alg_A(perm.max(), perm)
def alg_A(self, k, perm):
"""Append the perm to the strong generators."""
if perm in self:
return
j = perm.data[k]
if self.Sigma[k][j] is not None:
perm2 = ~self.Sigma[k][j] * perm
# Trzeba się upewnić, jakiego rzędu jest perm.
self.alg_A(perm2.max(), perm2)
return
self.all_T.append(perm)
for item in self.all_Sigma:
# Trzeba się upewnić, jakiego rzędu jest perm.
perm2 = perm * item
self.alg_B(perm2.max(), perm2)
def alg_B(self, k, perm):
"""Update the Sigma."""
if perm in self:
return
j = perm.data[k]
if self.Sigma[k][j] is None:
self.Sigma[k][j] = perm
self.all_Sigma.append(perm)
for item in self.all_T:
# Trzeba się upewnić, jakiego rzędu jest perm.
perm2 = item * perm
k_max = perm2.max()
if k_max != k:
self.alg_A(k_max, perm2)
else:
self.alg_B(k_max, perm2)
return
item = ~self.Sigma[k][j] * perm
# Trzeba się upewnić, jakiego rzędu jest perm.
# Tu na pewno k_max < k.
self.alg_A(item.max(), item)
def iterperms(self):
"""The generator for perms from the group."""
a = [0] * self.size
while True:
# M2. Odwiedziny.
if all(self.Sigma[k][a[k]] is not None for k in range(self.size)):
perm = Perm(self.size)
for k in range(self.size):
perm = self.Sigma[k][a[k]] * perm
yield perm
# M3. Przygotowanie do dodania jedynki.
j = self.size - 1
# M4. Przeniesienie, jeśli trzeba.
while a[j] == j and j >= 0:
a[j] = 0
j = j - 1
# M5. Zwiększenie, o ile nie koniec.
if j < 0:
break
else:
a[j] = a[j] + 1
def is_trivial(self):
"""Test if the group is trivial."""
return self.order() == 1