generate geodesic automaton and lex reduced geodesic automaton
This commit is contained in:
commit
fc4dfa195d
222
automaton.py
Executable file
222
automaton.py
Executable file
@ -0,0 +1,222 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# 0 is infinity
|
||||
coxeter_matrix = [[1, 2, 3],
|
||||
[2, 1, 0],
|
||||
[3, 0, 1]]
|
||||
|
||||
import math
|
||||
from copy import copy
|
||||
from collections import deque
|
||||
|
||||
class Root:
|
||||
def __init__(self, id, rank, depth = 0, v = None, neighbors = None):
|
||||
self.id = id
|
||||
self.rank = rank
|
||||
self.depth = depth
|
||||
if v:
|
||||
self.v = v
|
||||
else:
|
||||
self.v = [0] * rank
|
||||
if neighbors:
|
||||
self.neighbors = neighbors
|
||||
else:
|
||||
self.neighbors = [None] * rank
|
||||
|
||||
def __copy__(self):
|
||||
return Root(self.id, self.rank, self.depth, self.v.copy(), self.neighbors.copy())
|
||||
|
||||
# compute <alpha_k, beta> where alpha_k is one of the simple roots and beta any root
|
||||
def form_gen_root(form, k, root):
|
||||
rank = len(form)
|
||||
return sum([root[i] * form[i][k] for i in range(rank)])
|
||||
|
||||
# compute beta - 2<alpha_k, beta>alpha_k, i.e. the reflection of beta along alpha_k
|
||||
def apply_gen_to_root(form, k, root):
|
||||
root[k] -= 2*form_gen_root(form, k, root)
|
||||
|
||||
# find a sequence of generators to apply to obtain a negative root, from left to right
|
||||
# "startwidth" argument can be used to force the first entry
|
||||
def find_word_to_negative(form, root_, startwith = None):
|
||||
rank = len(form)
|
||||
root = root_.copy()
|
||||
word = []
|
||||
while not next(filter(lambda x: x < -1e-6, root), None): # while root has no negative entry
|
||||
for k in range(rank):
|
||||
if startwith and k != startwith:
|
||||
continue
|
||||
# avoiding 0 might be a problem for reducible groups?
|
||||
f = form_gen_root(form, k, root)
|
||||
if f > 1e-6:
|
||||
apply_gen_to_root(form, k, root)
|
||||
word.append(k)
|
||||
break
|
||||
startwith = None
|
||||
return word
|
||||
|
||||
# use find_word_to_negative() to find the root, if we already have it
|
||||
def find_root_from_vector(form, roots, vector):
|
||||
rank = len(form)
|
||||
for k in range(rank):
|
||||
word = find_word_to_negative(form, vector, startwith = k)
|
||||
|
||||
if not word:
|
||||
continue
|
||||
|
||||
rootobj = roots[word.pop()]
|
||||
|
||||
while len(word) > 0:
|
||||
letter = word.pop()
|
||||
if not rootobj.neighbors[letter]:
|
||||
rootobj = None
|
||||
break
|
||||
else:
|
||||
rootobj = rootobj.neighbors[letter]
|
||||
|
||||
if rootobj:
|
||||
return rootobj
|
||||
return None
|
||||
|
||||
def find_small_roots(form):
|
||||
rank = len(form)
|
||||
small_roots = []
|
||||
|
||||
# the simple roots are just the standard basis vectors
|
||||
for i in range(rank):
|
||||
r = Root(i, rank)
|
||||
r.v[i] = 1
|
||||
r.depth = 1
|
||||
small_roots.append(r)
|
||||
|
||||
# find the other small roots by applying generators to all existing roots
|
||||
# and using find_root_from_vector() to see if we already have it
|
||||
# then add it if it is a small root = was obtained via a short edge (form between -1 and 0)
|
||||
i = 0
|
||||
while i < len(small_roots):
|
||||
root = small_roots[i]
|
||||
for k in range(rank):
|
||||
newroot = root.v.copy()
|
||||
apply_gen_to_root(form, k, newroot)
|
||||
|
||||
rootobj = find_root_from_vector(form, small_roots, newroot)
|
||||
|
||||
if rootobj:
|
||||
root.neighbors[k] = rootobj
|
||||
else:
|
||||
f = form_gen_root(form, k, root.v)
|
||||
if f > -1 + 1e-6 and f < -1e-6: # root is new and is a small root
|
||||
rootobj = Root(len(small_roots), rank, root.depth+1, newroot)
|
||||
small_roots.append(rootobj)
|
||||
root.neighbors[k] = rootobj
|
||||
i = i+1
|
||||
return small_roots
|
||||
|
||||
|
||||
def apply_gen_to_node(small_roots, k, node, position, lex_reduced = False):
|
||||
# if we want to get the lex reduced langauge
|
||||
if lex_reduced:
|
||||
for j in range(k):
|
||||
if small_roots[j].neighbors[k] and position == small_roots[j].neighbors[k].id:
|
||||
return 1
|
||||
|
||||
if position == k:
|
||||
return 1
|
||||
elif small_roots[position].neighbors[k]:
|
||||
swappos = small_roots[position].neighbors[k].id
|
||||
return node[swappos]
|
||||
else:
|
||||
return 0
|
||||
|
||||
def generate_automaton(small_roots, lex_reduced = False):
|
||||
nroots = len(small_roots)
|
||||
rank = small_roots[0].rank
|
||||
start = tuple([0]*nroots)
|
||||
todo = deque([start])
|
||||
nodes = {start: 0}
|
||||
levels = {start: 0}
|
||||
edges = []
|
||||
id = 1
|
||||
|
||||
while todo:
|
||||
node = todo.pop()
|
||||
for k in range(rank):
|
||||
if node[k] == 1:
|
||||
continue
|
||||
newnode = tuple(
|
||||
apply_gen_to_node(small_roots, k, node, i, lex_reduced = lex_reduced)
|
||||
for i in range(nroots))
|
||||
if not newnode in nodes:
|
||||
nodes[newnode] = id
|
||||
levels[newnode] = levels[node]+1
|
||||
todo.appendleft(newnode)
|
||||
id += 1
|
||||
edges.append((nodes[node], nodes[newnode], k))
|
||||
|
||||
return (nodes, levels, edges)
|
||||
|
||||
# main program
|
||||
|
||||
form = [[-math.cos(math.pi/m) if m > 0 else -1 for m in row] for row in coxeter_matrix]
|
||||
rank = len(coxeter_matrix)
|
||||
small_roots = find_small_roots(form)
|
||||
nodes, levels, edges = generate_automaton(small_roots, lex_reduced = False)
|
||||
nodes_lex, levels_lex, edges_lex = generate_automaton(small_roots, lex_reduced = True)
|
||||
|
||||
#for r in small_roots:
|
||||
# print((r.id,r.v,[n.id if n else -1 for n in r.neighbors]))
|
||||
|
||||
revedges = sorted(edges, key = lambda x:x[1])
|
||||
|
||||
adjlist = {}
|
||||
revadjlist = {}
|
||||
for efrom, eto, egen in edges:
|
||||
if not efrom in adjlist:
|
||||
adjlist[efrom] = [-1]*rank
|
||||
adjlist[efrom][egen] = eto
|
||||
if not eto in revadjlist:
|
||||
revadjlist[eto] = [-1]*rank
|
||||
revadjlist[eto][egen] = efrom
|
||||
|
||||
words = [([], 0)]
|
||||
depth = 0
|
||||
i = 0
|
||||
while len(words[i][0]) < 10:
|
||||
curword = words[i][0]
|
||||
curnode = words[i][1]
|
||||
for gen, nextnode in enumerate(adjlist[curnode]):
|
||||
if nextnode < 0:
|
||||
continue
|
||||
nextword = curword.copy()
|
||||
nextword.append(gen)
|
||||
words.append((nextword, nextnode))
|
||||
i += 1
|
||||
|
||||
#print(sorted([x[1] for x in words]))
|
||||
#print(["".join([chr(ord('a')+x) for x in w[0]]) for w in words])
|
||||
|
||||
levelnodes = []
|
||||
for n,id in nodes.items():
|
||||
level = levels[n]
|
||||
if level >= len(levelnodes):
|
||||
levelnodes.append([])
|
||||
levelnodes[level].append(id)
|
||||
|
||||
print("digraph test123 {")
|
||||
print('rankdir="TB"')
|
||||
|
||||
for (level,ns) in enumerate(levelnodes):
|
||||
print('{rank = "same";', end = ' ')
|
||||
for n in ns:
|
||||
print("{id:d};".format(id=n), end = ' ')
|
||||
print('}')
|
||||
|
||||
|
||||
colors = ['red', 'darkgreen', 'blue', 'orange']
|
||||
|
||||
for e in edges:
|
||||
print("{fr:d} -> {to:d} [color={color}];".format(
|
||||
fr = e[0],
|
||||
to = e[1],
|
||||
color = colors[e[2]]))
|
||||
|
||||
print("}")
|
Loading…
Reference in New Issue
Block a user