diff --git a/automaton.py b/coxeter_automaton.py old mode 100755 new mode 100644 similarity index 82% rename from automaton.py rename to coxeter_automaton.py index ad8e62f..c4b9493 --- a/automaton.py +++ b/coxeter_automaton.py @@ -1,10 +1,4 @@ -#!/usr/bin/python - -# 0 is infinity -coxeter_matrix = [[1, 5, 5], - [5, 1, 5], - [5, 5, 1]] - +import numpy as np import math from copy import copy from collections import deque @@ -48,7 +42,7 @@ 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 +# "startwith" argument can be used to force the first entry def find_word_to_negative(form, root_, startwith = None): rank = len(form) root = root_.copy() @@ -169,29 +163,24 @@ def generate_automaton(small_roots, lex_reduced = False): graph[fr][gen] = to return graph -# 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) -graph = generate_automaton(small_roots, lex_reduced = False) -graph_lex = generate_automaton(small_roots, lex_reduced = True) +def enumerate_group(graph, graph_lex, max_len): + rank = len(graph[0]) + group = [Groupelement(0, rank, tuple())] + group[0].inverse = group[0] + group[0].node = group[0].lex_node = 0 -group = [Groupelement(0, rank, tuple())] -group[0].inverse = group[0] -group[0].node = group[0].lex_node = 0 + i = 0 + size = 1 + while True: + current = group[i] + i+=1 -i = 0 -size = 1 -while True: - current = group[i] - i+=1 + # break if current has the max length we have, as that's when we would start adding elements 1 longer + if current.length >= max_len: + break - if current.length >= 10: - break - - for gen, new_lex_node in enumerate(graph_lex[current.lex_node]): - if new_lex_node: + for gen, new_lex_node in filter(lambda x: x[1], enumerate(graph_lex[current.lex_node])): new_element = Groupelement(size, rank, current.word + (gen,)) new_element.lex_node = new_lex_node new_element.node = graph[current.node][gen] @@ -199,10 +188,8 @@ while True: size += 1 # w = w_1 t, w s = w_1 - # right multiplication (and left in case it does the same as a right mult) + # right multiplication, if it decreases length for k in range(rank): - - # if right multiplication by k decreases length if not graph[new_element.node][k]: word = list(new_element.word) longer_suffix = group[0] @@ -213,7 +200,6 @@ while True: # w = w_1 t w_2, w_2 s_k = t w_2 # in the case word = [] longer_suffix could be None - # found it if len(word) == 0 or shorter_suffix.right[k] == longer_suffix: # finish word while len(word) > 0: @@ -240,8 +226,25 @@ while True: other = new_element.right[k].inverse inverse.left[k] = other other.left[k] = inverse + return group -length = 0 -for i in range(1,len(group)+1): - if i == len(group) or group[i].length > group[i-1].length: - print("{number:d} elements up to length {length:d}".format(number = i, length = group[i-1].length)) +def word(w): + return ''.join([chr(ord('a')+x) for x in w]) + +def generate_automaton_coxeter_matrix(coxeter_matrix, lex_reduced = False): + 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) + return generate_automaton(small_roots, lex_reduced) + +def even_graph(graph): + rank = len(graph[0]) + result = [] + for node in graph: + newnode = {} + for i in range(rank): + for j in range(rank): + if node[i] and graph[node[i]][j]: + newnode[(i,j)] = graph[node[i]][j] + result.append(newnode) + return result diff --git a/dot_graph.py b/dot_graph.py new file mode 100755 index 0000000..6571ea9 --- /dev/null +++ b/dot_graph.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# outputs the automaton as a graphviz dot file, arranging the vertices +# in levels according to their distance from the starting vertex +# to convert to a PDF, run: +# ./dot_graph.py | dot -Tpdf > output.pdf + +import coxeter_automaton +from collections import deque + +coxeter_matrix = [[1, 2, 0, 0, 0, 2], + [2, 1, 2, 0, 0, 0], + [0, 2, 1, 2, 0, 0], + [0, 0, 2, 1, 2, 0], + [0, 0, 0, 2, 1, 2], + [2, 0, 0, 0, 2, 1]] + +graph = coxeter_automaton.generate_automaton_coxeter_matrix(coxeter_matrix, lex_reduced = False) + +colors = {0: "red", 1: "darkgreen", 2: "blue", 3: "orange", 4: "black", 5: "gray"} + +todo = deque([0]) +distances = [None]*len(graph) +distances[0] = 0 + +while todo: + node = todo.pop() + for newnode in graph[node]: + if newnode: + if not distances[newnode] or distances[newnode] > distances[node] + 1: + distances[newnode] = distances[node] + 1 + todo.appendleft(newnode) + +max_distance = max(filter(None, distances)) +nodes_by_distance = [[] for _ in range(max_distance+1)] +for n,d in enumerate(distances): + if d != None: + nodes_by_distance[d].append(n) + +print('digraph test123 {') +for dn in nodes_by_distance: + print('{rank = same; %s}' % "; ".join([str(x) for x in dn])) + +for i,node in enumerate(graph): + for edge,j in enumerate(node): + if j: + print('{i:d} -> {j:d} [color={color}];'.format(i = i, j = j, color = colors[edge])) +print('}') diff --git a/example.py b/example.py new file mode 100755 index 0000000..3cfd788 --- /dev/null +++ b/example.py @@ -0,0 +1,18 @@ +#!/usr/bin/python + +import coxeter_automaton + +# (2, 3, infinity) triangle group; 0 stands for infinity +coxeter_matrix = [[1, 0, 3], + [0, 1, 2], + [3, 2, 1]] + +graph = coxeter_automaton.generate_automaton_coxeter_matrix(coxeter_matrix, lex_reduced = False) +graph_shortlex = coxeter_automaton.generate_automaton_coxeter_matrix(coxeter_matrix, lex_reduced = True) + +print(graph) + +group = coxeter_automaton.enumerate_group(graph, graph_shortlex, 10) + +# for each group element g and generator a, print index of a*g +print([[l.id if l else None for l in g.left] for g in group])