I was looking for a family of symplectic nilpotent matrices with prescribed associated permutation conjugacy classes. So I made a GUI in Jupyter+ipywidgets to go over matrices, and it actually worked.
Here is the code the GUI:
In [1]:
from collections import Counter
import numpy as np
import ipywidgets as widgets
In [2]:
def get_k(A):
"""Get nullity sequence of A"""
n = len(A)
k = []
for i in range(2 * n + 1):
nullity = 2*n - np.linalg.matrix_rank(np.linalg.matrix_power(A, i))
k.append(nullity)
if nullity == 2 * n:
break
else:
return None
return np.array(list(filter(bool, np.diff(k))))
def k_to_perm(k):
"""Convert nullity sequence to permutation conjugacy class by taking dual and fancy python"""
if k is None:
return None
perm = Counter()
for i in range(1, max(k) + 1):
perm += Counter({np.sum(k >= i)})
return perm
def pretty_perm(p):
"""Return nice two-rowed representation of permutaion conjugacy class"""
if p is None:
return 'not nilpotent'
top = ''
bottom = ''
for i in sorted(p.keys()):
b = str(i)
t = str(p[i])
bottom += b + ' '
top += (' ' * len(b)) + t + ' '
return '%s\n%s' % (top, bottom)
def favorite_symplectic(n):
w = np.zeros((n, n), np.int64)
for i in range(n//2):
w[i, n - i - 1] = 1
for i in range(n//2, n):
w[i, n - i - 1] = -1
return w
def favorite_orthogonal(n):
w = np.zeros((n, n), np.int64)
for i in range(n):
w[i, n - i - 1] = 1
return w
def show_grid(n, preserve=None):
"""Show nxn grid of buttons and a textarea for permutation conjugacy class"""
if preserve is not None:
if preserve == 'symplectic':
preserve = favorite_symplectic(n)
elif preserve == 'orthogonal':
preserve = favorite_orthogonal(n)
w_inv = np.linalg.inv(preserve)
A = np.zeros((n, n), np.int64)
bs = []
txt = widgets.Textarea()
for i in range(n):
row = []
for j in range(n):
w = widgets.Button(description='0', layout=widgets.Layout(width='5px'))
w.style.button_color = 'red'
def foo(b, i=i, j=j):
if b.description == '0':
v, c = 1, 'lightgreen'
else:
v, c = 0, 'red'
A[i, j] = v
b.description = str(v)
b.style.button_color = c
if preserve is not None:
M = np.zeros((n, n), np.int64)
M[i, j] = 1
M = -np.dot(np.dot(w_inv, M.T), preserve)
(i2,), (j2,) = np.where(M)
if (i, j) != (i2, j2):
A[i2, j2] = int(M[i2, j2] * v)
bs[i2][j2].description = str(A[i2, j2])
bs[i2][j2].style.button_color = c
txt.value = pretty_perm(k_to_perm(get_k(A)))
w.on_click(foo)
row.append(w)
bs.append(row)
display(widgets.VBox([widgets.HBox(row) for row in bs] + [txt]))
In [3]:
show_grid(4, 'orthogonal')