|
|
|
@@ -0,0 +1,108 @@ |
|
|
|
import numpy as np |
|
|
|
import itertools |
|
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
def s_n(n): |
|
|
|
return list(itertools.permutations(range(1,n+1))) |
|
|
|
|
|
|
|
def canon_tab(n): |
|
|
|
return list(range(1,n+1)) |
|
|
|
|
|
|
|
def split_rows(part, lst): |
|
|
|
assert(sorted(part, reverse=True) == part) |
|
|
|
n = sum(part) |
|
|
|
xs = lst.copy() |
|
|
|
split = [] |
|
|
|
for s in part: |
|
|
|
split.append(xs[0:s]) |
|
|
|
xs = xs[s:] |
|
|
|
return split |
|
|
|
|
|
|
|
def is_row_stab(part, perm): |
|
|
|
n = sum(part) |
|
|
|
assert(len(perm) == n) |
|
|
|
return list(map(sorted, split_rows(part, canon_tab(n)))) == list(map(sorted, split_rows(part, list(perm)))) |
|
|
|
|
|
|
|
def cycles(perm): |
|
|
|
cycles = [] |
|
|
|
xs = list(range(1, len(perm)+1)) |
|
|
|
while len(xs) > 0: |
|
|
|
c = [xs[0]] |
|
|
|
k = xs[0] |
|
|
|
while (perm[k-1] not in c): |
|
|
|
k = perm[k-1] |
|
|
|
c.append(k) |
|
|
|
xs = [ x for x in xs if x not in c ] |
|
|
|
cycles.append(c) |
|
|
|
return cycles |
|
|
|
|
|
|
|
def cycle_type(perm): |
|
|
|
cs = cycles(perm) |
|
|
|
types = {} |
|
|
|
for c in cs: |
|
|
|
if len(c) not in types: |
|
|
|
types[len(c)] = 1 |
|
|
|
else: |
|
|
|
types[len(c)] += 1 |
|
|
|
t = [] |
|
|
|
for i in range(1, max(perm)+1): |
|
|
|
t.append(types.get(i, 0)) |
|
|
|
return tuple(t) |
|
|
|
|
|
|
|
def conjugacy_classes(n): |
|
|
|
cs = {} |
|
|
|
for perm in s_n(n): |
|
|
|
ct = cycle_type(perm) |
|
|
|
if ct not in cs: |
|
|
|
cs[ct] = [perm] |
|
|
|
else: |
|
|
|
cs[ct].append(perm) |
|
|
|
l = list(cs.items()) |
|
|
|
return sorted(l, key=lambda x: x[0], reverse=True) |
|
|
|
|
|
|
|
def partitions(n, conj_classes=None): |
|
|
|
parts = [] |
|
|
|
if conj_classes == None: |
|
|
|
conj_classes = conjugacy_classes(n) |
|
|
|
for cycle_type, conj in conj_classes: |
|
|
|
part = [] |
|
|
|
for i, c in enumerate(cycle_type): |
|
|
|
for s in range(0, c): |
|
|
|
part.append(i+1) |
|
|
|
parts.append(sorted(part, reverse=True)) |
|
|
|
#parts.append([(i+1) * cycle_type[i] for i in range(0, n)]) |
|
|
|
return list(sorted(parts, reverse=True)) |
|
|
|
|
|
|
|
def psi(n): |
|
|
|
cs = conjugacy_classes(n) |
|
|
|
ps = partitions(n, cs) |
|
|
|
m = np.zeros((len(cs), len(cs))) |
|
|
|
for i, part in enumerate(ps): |
|
|
|
row_stabs = set(filter(lambda sigma: is_row_stab(part, sigma), s_n(n))) |
|
|
|
for j, (cycle_type, conj) in enumerate(cs): |
|
|
|
m[i, j] = len(row_stabs & set(conj)) * np.math.factorial(n) / (len(row_stabs) * len(conj)) |
|
|
|
return m |
|
|
|
|
|
|
|
def sigma(n): |
|
|
|
cs = conjugacy_classes(n) |
|
|
|
m = np.zeros((len(cs), len(cs))) |
|
|
|
for i, (cycle_type, conj) in enumerate(cs): |
|
|
|
m[i, i] = len(conj) / np.math.factorial(n) |
|
|
|
return m |
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
if len(sys.argv) >= 2: |
|
|
|
n = int(sys.argv[1]) |
|
|
|
else: |
|
|
|
n = 3 |
|
|
|
|
|
|
|
psi = psi(n) |
|
|
|
sigma = sigma(n) |
|
|
|
|
|
|
|
a = np.dot(psi, np.dot(sigma, np.transpose(psi))) |
|
|
|
k = np.linalg.cholesky(a) |
|
|
|
x = np.dot(np.linalg.inv(k), psi) |
|
|
|
print("Character table for S_n where n =", n) |
|
|
|
print("Rows are indexed by partitions and columns by conjugacy classes") |
|
|
|
print(x.round()) |