def euler_cocycle(tri, angle): """ Given a regina triangulation "tri", with oriented edges, and a transverse taut angle structure "angle", returns the associated two-cocycle E representing the Euler class E(tri). """ assert is_transverse_taut(tri, angle) face_coorientations = is_transverse_taut(tri, angle, return_type = "face_coorientations") # E will be a _row_ vector, because it eats column vectors. E = [] # First deal with the truncated faces for face in tri.faces(2): # 2 = dimension # First we compute the number of Regina oriented edges that agree with the Regina orientation on face AC = 0 for i in range(3): perm = face.faceMapping(1, i) # print perm[0], perm[1] if perm[1] == ((perm[0] + 1) % 3): # the edge and face orientations agree so, AC = AC + 1 # print "AC", AC # Now we condition on whether or not Regina and angle agree on the (co-)orientation of the face. if face_coorientations[face.index()] == 1: E.append(AC - 2) else: E.append(1 - AC) # Now deal with the peripheral faces for tet in tri.tetrahedra(): for j in range(4): E.append(0) return E
def get_non_triv_sol(tri, angle): N = edge_equation_matrix_taut(tri, angle) N = Matrix(N) non_triv, sol = non_trivial_solution(N, real_bool = False, int_bool = True) twiddles = is_transverse_taut(tri, angle, return_type = "face_coorientations") sol = [int(a * b) for a, b in zip(sol, twiddles)] return sol
def veering_polynomial(tri, angle, alpha=True, normalisation=True, mode="lower"): # set up ZH = group_ring(tri, angle, [], alpha=alpha) P = ZH.polynomial_ring() if verbose > 0: print(("angle", angle)) coorientations = is_transverse_taut(tri, angle, return_type="tet_vert_coorientations") if mode == "upper": coorientations = [[-x for x in coor] for coor in coorientations] ET = edges_to_tetrahedra_matrix(tri, angle, coorientations, normalisation, ZH, P) #print(ET) if normalisation == True: return normalise_poly(ET.determinant(), ZH, P) else: perm = permutation_tet_top_diagonal(tri, angle, coorientations) #print(perm, "sign", sign(perm)) return sign(perm) * ET.determinant()
def upper_branched_surface(tri, angle, return_lower=False): """Returns the upper branched surface for a veering triangulation""" veering_colours = is_veering(tri, angle, return_type="veering_colours") tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") assert veering_colours != False and tet_vert_coorientations != False branch = [] for i, a in enumerate(angle): assert tet_vert_coorientations[i][0] == tet_vert_coorientations[i][ a + 1] ### the other end of the pi edge at 0 large_edge_num = vert_pair_to_edge_num[(0, a + 1)] tiny_edge_num = 5 - large_edge_num if ( tet_vert_coorientations[i][0] == -1 ) != return_lower: ### into the tetrahedron through face 0, xor get lower branched surface large_edge_num, tiny_edge_num = tiny_edge_num, large_edge_num # swap tiny_edge_colour = veering_colours[tri.tetrahedron(i).edge( tiny_edge_num).index()] mixed_edge_pair_num = (vert_pair_to_edge_num[(0, a + 1)] + 1) % 3 ### can view as an edge num too... if veering_colours[tri.tetrahedron(i).edge( mixed_edge_pair_num).index()] != tiny_edge_colour: mixed_edge_pair_num = (mixed_edge_pair_num + 1) % 3 ### then its the other one branch.append( branch_num_from_large_edge_and_mixed_edge_pair_num( large_edge_num, mixed_edge_pair_num)) # assert is_branched(tri, branch) assert has_non_sing_semiflow(tri, branch) return branch
def perform_all_mutations(tri, angle, weights, tet_vert_coorientations=None, print_stratum=True): if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") surface, edge_colours = build_surface(tri, angle, weights, return_edge_colours=True) if print_stratum == True: this_stratum = stratum(tri, angle, weights) print('stratum:', this_stratum) veering_isoms = veering_symmetry_group(surface, edge_colours) if len(veering_isoms) > 1: sig = isosig_from_tri_angle(tri, angle) for i in range(1, len(veering_isoms)): isom = veering_isoms[i] tri, angle = isosig_to_tri_angle(sig) mutate(tri, angle, weights, isom) else: print('surface has no veering symmetries')
def mutate(tri, angle, weights, isom, tet_vert_coorientations=None, quiet=False): if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") regluing = surface_isom_to_regluing_pattern(tri, angle, weights, isom, tet_vert_coorientations) #print('regluing data:', regluing) # first unglue all faces that need to be unglued, then reglue them via isom # can't do both at the same step, because regina goes crazy when you try to glue a face to a face which is already glued somewhere else for x in regluing: tet_below_top_triangle = tri.tetrahedron(x[0]) which_face = x[1] tet_below_top_triangle.unjoin(which_face) #print('unglued face', which_face, 'of tet', tet_below_top_triangle.index()) for x in regluing: tet_below_top_triangle = tri.tetrahedron(x[0]) which_face = x[1] tet_above_image_triangle = tri.tetrahedron(x[2]) perm = x[3] tet_below_top_triangle.join(which_face, tet_above_image_triangle, perm) #print('glued face', which_face, 'of tet', tet_below_top_triangle.index(), 'to tet', tet_above_image_triangle.index(), 'via', perm) assert tri.isValid() assert tri.countBoundaryFacets() == 0 if quiet == False: print('mutant isosig:', tri.isoSig()) print('taut:', is_taut(tri, angle)) if is_taut(tri, angle): print('transverse taut:', is_transverse_taut(tri, angle)) print('veering:', is_veering(tri, angle)) else: edge_num = tri.countEdges() print('Got', edge_num, 'edges out of', tri.countTetrahedra()) totals = is_taut(tri, angle, return_totals=True) print('Angles:', totals)
def non_tree_edge_loops_oriented(tri, angle): """ Suppose that T is the (dual) spanning tree. For every non-tree edge e, there is a unique oriented loop in T union e whose orientation agrees with the orientation of e (as given by alpha). We return this as a list of faces (starting with e) and a list of signs (starting with +1). """ loops = non_tree_edge_loops(tri) oriented_loops = [] all_signs = [] coorientations = is_transverse_taut(tri, angle, return_type="tet_vert_coorientations") assert coorientations != False for loop in loops: if len(loop) == 1: all_signs.append([1]) elif len(loop) == 2: embeddings = tri.triangle(loop[0]).embeddings() tet0, _ = (embed.simplex() for embed in embeddings) tet0_faces = [tet0.triangle(i).index() for i in range(4)] local_loop0 = tet0_faces.index(loop[0]) local_loop1 = tet0_faces.index(loop[1]) tet0_coor = coorientations[tet0.index()] if tet0_coor[local_loop0] == tet0_coor[local_loop1]: all_signs.append([1, -1]) else: all_signs.append([1, 1]) else: # at least three # first decide if we need to reverse the loop embeddings = tri.triangle(loop[0]).embeddings() tet0, tet1 = (embed.simplex() for embed in embeddings) tet0_faces = [tet0.triangle(i).index() for i in range(4)] local_loop0 = tet0_faces.index(loop[0]) tet0_coor = coorientations[tet0.index()] if tet0_coor[local_loop0] != 1: loop.reverse() loop = loop[-1:] + loop[:-1] tet0, tet1 = tet1, tet0 # now everything is sensible: that is, tet0 is below face0 loop_signs = [] curr_tet = tet0 for face_ind in loop: curr_tet_faces = [ curr_tet.triangle(i).index() for i in range(4) ] local_face_ind = curr_tet_faces.index(face_ind) curr_tet_coor = coorientations[curr_tet.index()] loop_signs.append(curr_tet_coor[local_face_ind]) curr_tet = curr_tet.adjacentSimplex(local_face_ind) assert loop_signs[0] == 1 all_signs.append(loop_signs) oriented_loops.append(loop) return (oriented_loops, all_signs)
def find_veering_isosigs_from_regina_isosig(regina_isosig, transverse_taut_only = True): t = regina.Triangulation3.fromIsoSig(regina_isosig) t.orient() veer_structs = find_veering_structures(t) if transverse_taut_only: veer_structs = [struct for struct in veer_structs if is_transverse_taut(t, struct)] veering_isosigs = [isosig_from_tri_angle(t, alpha) for alpha in veer_structs] veering_isosigs = list(set(veering_isosigs)) veering_isosigs.sort() return veering_isosigs
def boundary_cycles_from_surface(tri, angle, surface, tet_vert_coorientations = None): """ Takes a carried surface. For each cusp of tri, look at the boundary curve of the surface on the boundary torus for that cusp. Push it up slightly, record which faces of tri it goes through. """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut(tri, angle, return_type = "tet_vert_coorientations") # set up output vectors out = [] for vertex in tri.faces(0): # 0 is the dimension of the face, so this is cusps out.append([0] * tri.countFaces(2)) edge_sides = edge_side_face_collections(tri, angle, tet_vert_coorientations = tet_vert_coorientations) face_coorientations = convert_tetrahedron_coorientations_to_faces(tri, tet_vert_coorientations) for f in tri.faces(2): weight = surface[f.index()] # this should be an integer. :) for vert_num in range(3): cusp_index = f.face(0, vert_num).index() sgn = face_coorientations[f.index()] trailing_vert_num = (vert_num + sgn) % 3 trailing_edge = f.face(1, trailing_vert_num) leading_vert_num = (vert_num - sgn) % 3 leading_edge = f.face(1, leading_vert_num) # these are with respect to right hand rule on surface as viewed from above # the faces above us on the trailing edge get -weight, # the faces above us on the leading edge get +weight. left, right = edge_sides[trailing_edge.index()] pair = (f.index(), trailing_vert_num) if pair in left: side = left else: assert pair in right side = right above = side[side.index(pair) + 1:] for (f_ind, vert) in above: out[cusp_index][f_ind] -= weight left, right = edge_sides[leading_edge.index()] pair = (f.index(), leading_vert_num) if pair in left: side = left else: assert pair in right side = right above = side[side.index(pair) + 1:] for (f_ind, vert) in above: out[cusp_index][f_ind] += weight return out
def __init__(self, tri, angle, tet_shapes=None): self.tri = tri self.angle = angle assert is_taut(tri, angle) self.coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") assert self.coorientations != False self.veering_colours = is_veering(tri, angle, return_type="veering_colours") assert self.veering_colours != False self.tet_types = is_veering(tri, angle, return_type="tet_types") self.tet_shapes = tet_shapes
def triangle_is_red(tri, angle, face_index, tet_vert_coorientations=None): if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_index_where_uppermost = where_faces_are_uppermost( tri, angle, tet_vert_coorientations )[face_index] #face has the same colour as the edge where it is uppermost colour = is_veering( tri, angle, return_type='veering_colours')[edge_index_where_uppermost] return (colour == 'red')
def verts_of_large_small_same_coloured_edges_in_embeds( tri, angle, face_index, tet_vert_coorientations=None): """ returns [vertices of large edge, vertices of small edge of the same colour] for top embedding and bottom embedding of a face """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") top_embed, bottom_embed = top_bottom_embeddings_of_faces( tri, angle, tet_vert_coorientations )[0][face_index], top_bottom_embeddings_of_faces( tri, angle, tet_vert_coorientations)[1][face_index] tet_below = top_embed.simplex() tet_above = bottom_embed.simplex() tet_below_coor = tet_vert_coorientations[tet_below.index()] tet_above_coor = tet_vert_coorientations[tet_above.index()] verts_of_top_diagonal_of_tet_below = [ i for i in range(4) if tet_below_coor[i] == -1 ] # this edge is small, of the same colour as large verts_of_bottom_diagonal_of_tet_above = [ i for i in range(4) if tet_above_coor[i] == +1 ] # this edge is large #print('small edge in top embed', verts_of_top_diagonal_of_tet_below) #print('large edge in bottom embed', verts_of_bottom_diagonal_of_tet_above) vertex_correspondence = vertex_correspondence_between_embeds( bottom_embed, top_embed) #print('bottom top vertex correspondence', vertex_correspondence) verts_of_large_edge_of_top_embed = [] for x in vertex_correspondence: if x[0] == verts_of_bottom_diagonal_of_tet_above[0] or x[ 0] == verts_of_bottom_diagonal_of_tet_above[1]: verts_of_large_edge_of_top_embed.append(x[1]) verts_of_other_edge_of_same_colour_in_bottom_embed = [] for x in vertex_correspondence: if x[1] == verts_of_top_diagonal_of_tet_below[0] or x[ 1] == verts_of_top_diagonal_of_tet_below[1]: verts_of_other_edge_of_same_colour_in_bottom_embed.append(x[0]) #print('large edge in top embed', verts_of_large_edge_of_top_embed) #print('small edge in bottom embed', verts_of_other_edge_of_same_colour_in_bottom_embed) return [ verts_of_large_edge_of_top_embed, verts_of_top_diagonal_of_tet_below ], [ verts_of_bottom_diagonal_of_tet_above, verts_of_other_edge_of_same_colour_in_bottom_embed ]
def pairing_of_faces_across_an_edge(tri, angle, weights, edge_index, tet_vert_coorientations=None): """ given a solution to the system of branch equations gives a pairing of faces across an edge (together with the index of the edge in that face) """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_sides = edge_side_face_collections( tri, angle, tet_vert_coorientations=tet_vert_coorientations)[edge_index] side0 = edge_sides[0] for i in range(len(side0)): face_index = side0[i][0] weight = weights[face_index] side0[i] = [ side0[i], weight ] #first replace side_collections into weighted_side_collections sum_of_weights0 = sum(weight for [_, weight] in side0) side0_nonzero_weights = [] for x in side0: for k in range(x[1]): side0_nonzero_weights.append(x[0]) side1 = edge_sides[1] for i in range(len(side1)): face_index = side1[i][0] weight = weights[face_index] side1[i] = [side1[i], weight] sum_of_weights1 = sum(weight for [_, weight] in side1) assert sum_of_weights0 == sum_of_weights1 side1_nonzero_weights = [] for x in side1: for k in range(x[1]): side1_nonzero_weights.append(x[0]) return ([side0_nonzero_weights, side1_nonzero_weights])
def taut_cone_homological_dim(tri, angle): # find the dimension of the projection of the taut cone into # homology # boundaries of tets bdys = zeroth_coboundary(tri) bdys = matrix_transpose(bdys) rays = taut_rays(tri, angle) # but these are all 'upwards', so we need to fix the # co-orientations coorient = is_transverse_taut(tri, angle, return_type = "face_coorientations") rays = [[int(a * b) for a, b in zip(coorient, ray)] for ray in rays] # now work in the space of two-chains Rays = IntegerLattice(rays + bdys) Bdys = Matrix(bdys) Cobs = Bdys.transpose() Anns = Cobs.kernel() return Rays.intersection(Anns).dimension()
def appears_twice_on_the_same_side(tri, angle, face_index, edge_index, tet_vert_coorientations=None): """ tells if a face is attached twice on the same side of an edge (if so, then lowermost and uppermost) """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_sides = edge_side_face_collections( tri, angle, tet_vert_coorientations=tet_vert_coorientations)[edge_index] side0 = edge_sides[0] side1 = edge_sides[1] return side0[0][0] == side0[-1][0] and side0[-1][0] == face_index or side1[ 0][0] == side1[-1][0] and side1[-1][0] == face_index
def is_uppermost(tri, angle, face_index, edge_index_in_face, edge_index, tet_vert_coorientations=None): """ tells if (face_index, edge_index_in_face) is uppermost for that edge """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_sides = edge_side_face_collections( tri, angle, tet_vert_coorientations=tet_vert_coorientations)[edge_index] side0 = edge_sides[0] side1 = edge_sides[1] return (side0[-1] == (face_index, edge_index_in_face) or side1[-1] == (face_index, edge_index_in_face))
def where_faces_are_uppermost(tri, angle, tet_vert_coorientations=None): """ returns a list whose ith elements is the index of the edge where the ith face is uppermost """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") n = tri.countTetrahedra() where_uppermost = [None] * 2 * n sides = edge_side_face_collections(tri, angle, tet_vert_coorientations) for edge in tri.edges(): uppermost0_index = sides[edge.index()][0][-1][0] where_uppermost[uppermost0_index] = edge.index() uppermost1_index = sides[edge.index()][1][-1][0] where_uppermost[uppermost1_index] = edge.index() for x in where_uppermost: assert x != None return where_uppermost
def is_fibered(snappy_name, tries=1000, with_data=False): """ Given an snappy_name, tries to find a layered transverse taut triangulation for the manifold via random search. """ sigs = get_many_sigs(snappy_name, tries) for sig in sigs: T = regina.Triangulation3(sig) T.orient() angle_strs = list(regina.AngleStructures.enumerate(T, True)) angle_strs = [ taut_regina_angle_struct_to_taut_struct(angle_str) for angle_str in angle_strs ] for angle in angle_strs: # we are not interested in semi-fibered manifolds so: if is_transverse_taut(T, angle) and is_layered(T, angle): if with_data: return (True, T.isoSig(), angle) return True return False
def top_bottom_embeddings_of_faces(tri, angle, tet_vert_coorientations=None): """ returns two lists: one whose ith entry is the top embedding of face i, another whose ith entry is the bottom embedding of face i (top embedding = embedding as a top face) """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") n = tri.countTetrahedra() top_embeddings = [None] * 2 * n bottom_embeddings = [None] * 2 * n for face in tri.triangles(): embed0 = face.embedding(0) embed1 = face.embedding(1) tet0_index = embed0.simplex().index() tet1_index = embed1.simplex().index() index_of_face_in_tet0 = embed0.vertices()[3] index_of_face_in_tet1 = embed1.vertices()[3] if tet_vert_coorientations[tet0_index][ index_of_face_in_tet0] == 1: # coorientation points out of tet0, i.e. tet0 is below f top_embedding = embed0 bottom_embedding = embed1 else: top_embedding = embed1 bottom_embedding = embed0 top_embeddings[face.index()] = top_embedding bottom_embeddings[face.index()] = bottom_embedding for i in range(2 * n): assert top_embeddings[i] != None and bottom_embeddings[i] != None return top_embeddings, bottom_embeddings
def coboundary(tri, angle): """ Given a triangulation "tri" (T), with oriented edges, and a transverse taut angle structure "angle", returns the co-boundary operator delta^1 \from C^1(T', ZZ) \to C^2(T', ZZ), as a matrix, for the truncated triangulation T'. Note that, strictly speaking, we don't need to use "angle" for this, but we use it to determine orientation on faces for the Euler class, so we might as well use it again here. """ # \delta^1 takes row vectors (functions on edges) and spits out # row vectors (functions on faces). So, if c is a one-cochain # then c \cdot \delta is a two-cochain. delta = [] assert is_transverse_taut(tri, angle) tet_vert_coorientations = is_transverse_taut(tri, angle, return_type = "tet_vert_coorientations") face_coorientations = is_transverse_taut(tri, angle, return_type = "face_coorientations") for edge in tri.edges(): # A row for every truncated edge row = [] for face in tri.triangles(): # A row entry for every truncated face count = 0 for i in range(3): if face.edge(i) == edge: perm = face.faceMapping(1, i) if perm[1] == ((perm[0] + 1) % 3): # the edge and face orientations agree so, count += 1 else: count -= 1 row.append(count * face_coorientations[face.index()]) # +1 if face is to the left of the edge, -1 if face is to # the right of the edge, using Regina's edge orientation # when viewed from above (using the transverse taut notion # of up) # ,'| # ,' | # ,' | # ,' CCW | gets a +1 # `. ^ # `. | # `. | # `.| for tet in tri.simplices(): for i in range(4): row.append(0) delta.append(row) for face in tri.triangles(): face_embeddings = [] for j in range(2): face_embeddings.append( face.embedding(j) ) for i in range(3): # vertices of the face # A row for every peripheral edge row = [] for face2 in tri.triangles(): # A row entry for every truncated face if face2 == face: row.append(1) else: row.append(0) for tet in tri.simplices(): for k in range(4): # A row entry for every peripheral face count = 0 for j in range(2): if (tet == face_embeddings[j].simplex()) and (face_embeddings[j].vertices()[i] == k): # the tetrahedron is on the jth side of the # face and the ith vertex of face is the kth # vertex of tet face_num_in_tet = face_embeddings[j].vertices()[3] count -= tet_vert_coorientations[tet.index()][face_num_in_tet] # tet_vert_coorientations is +1 if # coorientation on face points out of the # tetrahedron, and we want count += 1 if # the peripheral face is above the # peripheral edge row.append(count) delta.append(row) return delta
def top_triangles_to_surface_triangles(tri, angle, weights, tet_vert_coorientations=None): """ Gives a map from the top triangles of the cut 3-manifold to the surface triangles (works only for surface built using build_surface!). If weight > 1 then the map sends a triangle f of the 3D-triangulation to the triangle of the surface corresponding to the "lowermost" (first) copy of f in the surface. The output format is a list of length 2*num_tet, whose entries are either None (if the face is not unglued in the cut manifold) or a list [tet_num, [vertices of tet], triangle_num, [vertices of tri]] """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") n = tri.countTetrahedra() top_embeddings, _ = top_bottom_embeddings_of_faces( tri, angle, tet_vert_coorientations) #print('top embeddings', top_embeddings) for i in range(2 * n): if weights[i] > 0: # the ith face of the 3D-triangulation is unglued which_surface_triangle = sum( weights[:i] ) # the index of the surface triangle corresponding to the "lowermost" copy of face i top_embed = top_embeddings[i] [verts_of_large_edge, verts_of_small_edge_of_same_colour ] = verts_of_large_small_same_coloured_edges_in_embeds( tri, angle, i, tet_vert_coorientations)[0] common_vertex = [ x for x in verts_of_large_edge if x in verts_of_small_edge_of_same_colour ][0] #print('verts of large', verts_of_large_edge) #print('verts_of_small_edge_of_same_colour', verts_of_small_edge_of_same_colour) #print('common vertex', common_vertex) #verts_of_large_edge_copy = verts_of_large_edge.copy() verts_of_large_edge.remove(common_vertex) other_vertex_of_large = verts_of_large_edge[0] #print('other_vertex_of_large', other_vertex_of_large) verts_of_small_edge_of_same_colour.remove(common_vertex) other_vertex_of_small = verts_of_small_edge_of_same_colour[0] if triangle_is_red(tri, angle, i, tet_vert_coorientations): # mapping common_vertex --> 0, other_vertex_of_large --> 1, other_vertex_of_small --> 2 vertex_mapping = [ top_embed.simplex().index(), [ common_vertex, other_vertex_of_large, other_vertex_of_small ], which_surface_triangle, [0, 1, 2] ] else: # mapping common_vertex --> 1, other_vertex_of_large --> 0, other_vertex_of_small --> 2 vertex_mapping = [ top_embed.simplex().index(), [ other_vertex_of_large, common_vertex, other_vertex_of_small ], which_surface_triangle, [0, 1, 2] ] #top_embeddings[i] = [top_embeddings[i]] #top_embeddings[i].append(vertex_mapping) top_embeddings[i] = vertex_mapping else: top_embeddings[ i] = None #so that it is clear that this face is not unglued in the cut manifold return top_embeddings
def build_surface(tri, angle, weights, tet_vert_coorientations=None, return_edge_colours=False): if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") surface = regina.Triangulation2() n = tri.countTetrahedra() for i in range(2 * n): for j in range(weights[i]): surface.newTriangle() colours = is_veering(tri, angle, return_type='veering_colours') edge_colours_pairs = [] # red, blue or black (dual to large branches) for edge in tri.edges(): pairings = pairing_of_faces_across_an_edge(tri, angle, weights, edge.index(), tet_vert_coorientations) height = len(pairings[0]) #print('height', height) #now we get (face_index, index of e in the face) so have to pick the first one face_indices0 = [pairings[0][i][0] for i in range(height)] face_indices1 = [pairings[1][i][0] for i in range(height)] for i in range(height): #face0_index = pairings[0][i][0] #now we get (face_index, index of e in the face) so have to pick the first one face0_index = face_indices0[i] edge_index_in_face0 = pairings[0][i][1] #face1_index = pairings[1][i][0] face1_index = face_indices1[i] edge_index_in_face1 = pairings[1][i][1] which_copy0 = face_indices0[:i].count(face0_index) # check if not overcounting (if a face is both uppermost and lowermost on the same side) if is_uppermost(tri, angle, face0_index, edge_index_in_face0, edge.index(), tet_vert_coorientations ) and appears_twice_on_the_same_side( tri, angle, face0_index, edge.index(), tet_vert_coorientations): which_copy0 = which_copy0 - weights[face0_index] which_copy1 = face_indices1[:i].count(face1_index) if is_uppermost(tri, angle, face1_index, edge_index_in_face1, edge.index(), tet_vert_coorientations ) and appears_twice_on_the_same_side( tri, angle, face1_index, edge.index(), tet_vert_coorientations): which_copy1 = which_copy1 - weights[face1_index] #which_copy0 = face_indices0[:i].count(face0_index) #which_copy1 = face_indices1[:i].count(face1_index) which_triangle0 = sum(weights[:face0_index]) + which_copy0 which_triangle1 = sum(weights[:face1_index]) + which_copy1 #print('which triangle 0', which_triangle0) #print('which triangle 1', which_triangle1) if colours[edge.index( )] == 'red': # gluing triangles across a red edge if is_uppermost(tri, angle, face0_index, edge_index_in_face0, edge.index(), tet_vert_coorientations): if is_uppermost(tri, angle, face1_index, edge_index_in_face1, edge.index(), tet_vert_coorientations): surface.triangle(which_triangle0).join( 2, surface.triangle(which_triangle1), regina.Perm3(1, 0, 2)) #first we append edge_colours with tuples [face_index, edge_index_in_face, colour]; after finishing the triangulation we will change it into a tuple of colours ordered by indices edge_colours_pairs.append( [which_triangle0, 2, 'black']) else: # middle and lowermost have the same permutation surface.triangle(which_triangle0).join( 2, surface.triangle(which_triangle1), regina.Perm3(0, 2, 1)) edge_colours_pairs.append([which_triangle0, 2, 'red']) else: # middle or lowermost if is_uppermost(tri, angle, face1_index, edge_index_in_face1, edge.index(), tet_vert_coorientations): surface.triangle(which_triangle0).join( 1, surface.triangle(which_triangle1), regina.Perm3(0, 2, 1)) edge_colours_pairs.append([which_triangle0, 1, 'red']) else: surface.triangle(which_triangle0).join( 1, surface.triangle(which_triangle1), regina.Perm3(2, 1, 0)) edge_colours_pairs.append([which_triangle0, 1, 'red']) else: # gluing triangles across a blue edge if is_uppermost(tri, angle, face0_index, edge_index_in_face0, edge.index(), tet_vert_coorientations): if is_uppermost(tri, angle, face1_index, edge_index_in_face1, edge.index(), tet_vert_coorientations): surface.triangle(which_triangle0).join( 2, surface.triangle(which_triangle1), regina.Perm3(1, 0, 2)) edge_colours_pairs.append( [which_triangle0, 2, 'black']) else: # middle and lowermost have the same permutation surface.triangle(which_triangle0).join( 2, surface.triangle(which_triangle1), regina.Perm3(2, 1, 0)) edge_colours_pairs.append([which_triangle0, 2, 'blue']) else: # middle or lowermost if is_uppermost(tri, angle, face1_index, edge_index_in_face1, edge.index(), tet_vert_coorientations): surface.triangle(which_triangle0).join( 0, surface.triangle(which_triangle1), regina.Perm3(2, 1, 0)) edge_colours_pairs.append([which_triangle0, 0, 'blue']) else: surface.triangle(which_triangle0).join( 0, surface.triangle(which_triangle1), regina.Perm3(0, 2, 1)) edge_colours_pairs.append([which_triangle0, 0, 'blue']) assert surface.isClosed() #print (edge_colours_pairs) if return_edge_colours == True: k = surface.countEdges() edge_colours = [None] * k for x in edge_colours_pairs: edge_index = surface.triangle(x[0]).edge(x[1]).index() edge_colours[edge_index] = x[2] return surface, edge_colours return surface
def surface_triangles_to_bottom_triangles(tri, angle, weights, tet_vert_coorientations=None): """ Gives a map from (some) surface triangles to bottom triangles of the cut 3-manifold. If weight > 1 then only the uppermost (last) copy of the 3-manifold triangle in the surface has a 3-manifold triangle assigned. The output format is a list of length 2*num_tet, whose entries are either None (if the face is not unglued in the cut manifold) or a list [triangle_num, [vertices of tri], tet_num, [vertices of tet]] """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") n = tri.countTetrahedra() _, bottom_embeddings = top_bottom_embeddings_of_faces( tri, angle, tet_vert_coorientations) for i in range(2 * n): if weights[i] > 0: # the ith face of the 3D-triangulation is unglued which_surface_triangle = sum( weights[:i + 1] ) - 1 # the "uppermost" copy of face i which appears in the surface bottom_embed = bottom_embeddings[i] [verts_of_large_edge, verts_of_small_edge_of_same_colour ] = verts_of_large_small_same_coloured_edges_in_embeds( tri, angle, i, tet_vert_coorientations)[1] common_vertex = [ x for x in verts_of_large_edge if x in verts_of_small_edge_of_same_colour ][0] #print('verts of large', verts_of_large_edge) #print('verts_of_small_edge_of_same_colour', verts_of_small_edge_of_same_colour) #print('common vertex', common_vertex) verts_of_large_edge.remove(common_vertex) other_vertex_of_large = verts_of_large_edge[0] #print('other_vertex_of_large', other_vertex_of_large) verts_of_small_edge_of_same_colour.remove(common_vertex) other_vertex_of_small = verts_of_small_edge_of_same_colour[0] if triangle_is_red(tri, angle, i, tet_vert_coorientations): #mapping common_vertex --> 0, other_vertex_of_large --> 1, other_vertex_of_small --> 2 vertex_mapping = [ which_surface_triangle, [0, 1, 2], bottom_embed.simplex().index(), [ common_vertex, other_vertex_of_large, other_vertex_of_small ] ] else: #mapping common_vertex --> 1, other_vertex_of_large --> 0, other_vertex_of_small --> 2 vertex_mapping = [ which_surface_triangle, [0, 1, 2], bottom_embed.simplex().index(), [ other_vertex_of_large, common_vertex, other_vertex_of_small ] ] #bottom_embeddings[i] = [bottom_embeddings[i]] #bottom_embeddings[i].append(vertex_mapping) bottom_embeddings[i] = vertex_mapping else: bottom_embeddings[ i] = None #so that it is clear that this face is not unglued in the cut manifold return bottom_embeddings
def surface_isom_to_regluing_pattern(tri, angle, weights, isom, tet_vert_coorientations=None): """ Translation between a combinatorial isomorphism of a carried surface and the associated mutation pattern. """ #isom must be a combinatorial isomorphism of a surface build using build_surface # 1. Get the top embeds to surface triangles map (if weights > 1 then the lowermost copy - the one which has a tet below, and not a 'prism'). # 2. Find images of triangles and permutations on vertices under the isomorphism. # 3. For every simpImage check if it is in the list obtained via surface_triangles_to_bottom triangles. If so, then it has a tet above (and not a prism), so the regluing pattern is # top embed --> surface triangle (lowermost over top embed) --isom--> surface triangle (uppermost over some tet) --> bottom face of the tet above # Otherwise, we look at the copy of the 3D-triangle in the surface which is above this surface triangle, apply isom again etc. if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") top_tri_to_surface_tri = top_triangles_to_surface_triangles( tri, angle, weights, tet_vert_coorientations) surface_tri_to_bottom_tri = surface_triangles_to_bottom_triangles( tri, angle, weights, tet_vert_coorientations) k = len(surface_tri_to_bottom_tri) auxiliary = [None] * k for i in range(k): if surface_tri_to_bottom_tri[i] != None: auxiliary[i] = surface_tri_to_bottom_tri[i][0] # auxiliary[k] is either None or an index of a surface triangle which has a tet above -- I want to keep Nones so that later I can find the index of the bottom triangle in surface_tri_to_bottom_tri by value regluing = [] for i in range(len(top_tri_to_surface_tri)): if top_tri_to_surface_tri[ i] != None: # this triangle is unglued in the cut manifold #print('top triangle to surface triangle', top_tri_to_surface_tri[i]) surface_tri_index = top_tri_to_surface_tri[i][2] tri_image = isom.simpImage(surface_tri_index) isom_perm = isom.facetPerm(surface_tri_index) #print('first tri image and perm', tri_image, isom_perm) if tri_image in auxiliary: index_in_surface_to_bottom_tri = auxiliary.index(tri_image) #print('surface triangle', tri_image, 'has a tet above') while tri_image not in auxiliary: #look at further images #print('tri_image does not have a tet above') triangle_above = tri_image + 1 tri_image = isom.simpImage( triangle_above) #look at the image of the upper copy isom_perm = isom.facetPerm(triangle_above) * isom_perm #print('next tri image and perm', tri_image, isom_perm) if tri_image in auxiliary: index_in_surface_to_bottom_tri = auxiliary.index(tri_image) #print('surface triangle', tri_image, 'has a tet above') top_to_surface_perm = vertex_correspondence_to_perm4( top_tri_to_surface_tri[i][1], top_tri_to_surface_tri[i][3]) #print('top tri to surface tri perm', top_to_surface_perm) isom_perm4 = regina.Perm4(isom_perm[0], isom_perm[1], isom_perm[2], 3) #print('4perm associated to isom', isom_perm4) bottom_to_surface_perm = vertex_correspondence_to_perm4( surface_tri_to_bottom_tri[index_in_surface_to_bottom_tri][3], surface_tri_to_bottom_tri[index_in_surface_to_bottom_tri][1]) #print('bottom tri to surface tri perm', bottom_to_surface_perm) surface_to_bottom_perm = bottom_to_surface_perm.inverse() #print('surface to bottom perm', surface_to_bottom_perm) perm = surface_to_bottom_perm * isom_perm4 * top_to_surface_perm #print('gluing perm', perm) tet_below_top_embed = top_tri_to_surface_tri[i][0] which_face = face_num_in_tet(top_tri_to_surface_tri[i][1]) tet_above_image = surface_tri_to_bottom_tri[ index_in_surface_to_bottom_tri][2] regluing.append( [tet_below_top_embed, which_face, tet_above_image, perm]) return regluing
def drill(tri, loop, angle=None, branch=None, sig=None): # sig just for diagnostics """ Returns the new cusp formed by drilling """ if angle != None: face_coorientations = is_transverse_taut( tri, angle, return_type="face_coorientations") assert face_coorientations != False tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") assert tet_vert_coorientations != False original_tri = regina.Triangulation3(tri) original_countTetrahedra = tri.countTetrahedra() original_countBoundaryComponents = tri.countBoundaryComponents() ### add new tetrahedra new_0_tets = [] new_1_tets = [] ## both relative to regina's two embeddings for the face for i in range(len(loop)): new_0_tets.append(tri.newTetrahedron()) new_1_tets.append(tri.newTetrahedron()) ### we will glue tetrahedra together with a numbering that is convenient but ### unfortunately not oriented. We will orient later. # 1 pivot # /|\ # / | \ # / ,3. \ # /,' `.\ # 0---------2 leading # trailing for i in range(len(loop)): new_0_tets[i].join(1, new_1_tets[i], regina.Perm4(0, 1, 2, 3)) ### now glue along the loop path, need to worry about regina's embeddings for neighbouring triangles loop_face_tets0 = [] loop_face_vertices0 = [] loop_face_tets1 = [] loop_face_vertices1 = [ ] ### need to store these because they cannot be recomputed once we start ungluing faces for i in range(len(loop)): # print('collect info: i', i) face_data = loop[i] face_index = face_data[0] vert_nums = face_data[1] face = tri.triangles()[face_index] face_embed0 = face.embedding(0) face_tet = face_embed0.simplex() face_vertices = face_embed0.vertices() face_opposite_vert = face_vertices[3] face_other_non_edge_vert = face_vertices[ vert_nums[0]] ## opposite trailing vertex face_data_next = loop[(i + 1) % len(loop)] face_index_next = face_data_next[0] vert_nums_next = face_data_next[1] face_next = tri.triangles()[face_index_next] face_next_embed0 = face_next.embedding(0) face_next_tet = face_next_embed0.simplex() face_next_vertices = face_next_embed0.vertices() face_next_opposite_vert = face_next_vertices[3] face_next_other_non_edge_vert = face_next_vertices[ vert_nums_next[2]] ## opposite leading vertex ### things to store for later loop_face_tets0.append(face_tet) # store for later loop_face_vertices0.append(face_vertices) #store for later face_embed1 = face.embedding(1) loop_face_tets1.append(face_embed1.simplex()) loop_face_vertices1.append(face_embed1.vertices()) edge = face.edge(vert_nums[0]) ## opposite trailing vertex # print('edge index', edge.index()) assert edge == face_next.edge( vert_nums_next[2]) ## opposite leading vertex edgemapping = face.faceMapping(1, vert_nums[0]) next_edgemapping = face_next.faceMapping(1, vert_nums_next[2]) face_gluing_regina_numbering = next_edgemapping * ( edgemapping.inverse() ) ### maps vertices 0,1,2 on face to corresponding vertices on face_next assert face_gluing_regina_numbering[3] == 3 face_gluing_regina_numbering = regina.Perm3( face_gluing_regina_numbering[0], face_gluing_regina_numbering[1], face_gluing_regina_numbering[2]) assert face_gluing_regina_numbering[vert_nums[0]] == vert_nums_next[2] face_gluing = vert_nums_next.inverse( ) * face_gluing_regina_numbering * vert_nums assert face_gluing[0] == 2 signs = [] edge_embeddings = edge.embeddings() for embed in edge_embeddings: if embed.simplex() == face_tet: if set([embed.vertices()[2], embed.vertices()[3]]) == set( [face_opposite_vert, face_other_non_edge_vert]): # print('embed data face_tet', embed.simplex().index(), embed.vertices()) # print('embed edge vert nums', embed.vertices()[0], embed.vertices()[1]) signs.append(face_opposite_vert == embed.vertices()[2]) if embed.simplex() == face_next_tet: if set([embed.vertices()[2], embed.vertices()[3]]) == set([ face_next_opposite_vert, face_next_other_non_edge_vert ]): # print('embed data face_next_tet', embed.simplex().index(), embed.vertices()) # print('embed edge vert nums', embed.vertices()[0], embed.vertices()[1]) signs.append( face_next_opposite_vert == embed.vertices()[2]) # print('signs', signs) assert len(signs) == 2 if signs[0] == signs[ 1]: ### coorientations are same around the edge (not a transverse taut coorientation!) new_0_tets[i].join( 0, new_1_tets[(i + 1) % len(loop)], regina.Perm4(2, face_gluing[1], face_gluing[2], 3)) new_1_tets[i].join( 0, new_0_tets[(i + 1) % len(loop)], regina.Perm4(2, face_gluing[1], face_gluing[2], 3)) else: new_0_tets[i].join( 0, new_0_tets[(i + 1) % len(loop)], regina.Perm4(2, face_gluing[1], face_gluing[2], 3)) new_1_tets[i].join( 0, new_1_tets[(i + 1) % len(loop)], regina.Perm4(2, face_gluing[1], face_gluing[2], 3)) ### now unglue tri along the loop and glue in the new tetrahedra for i in range(len(loop)): # print('modify triangulation: i', i) vert_nums = loop[i][1] face_tet0 = loop_face_tets0[i] face_vertices0 = loop_face_vertices0[i] face_tet1 = loop_face_tets1[i] face_vertices1 = loop_face_vertices1[i] face_opposite_vert0 = face_vertices0[3] face_tet0.unjoin(face_opposite_vert0) ### glue torus shell to the old tetrahedra vert_nums_Perm4 = regina.Perm4(vert_nums[0], vert_nums[1], vert_nums[2], 3) new_0_tets[i].join(3, face_tet0, face_vertices0 * vert_nums_Perm4) new_1_tets[i].join(3, face_tet1, face_vertices1 * vert_nums_Perm4) assert tri.isValid() assert tri.countBoundaryComponents( ) == original_countBoundaryComponents + 1 if angle != None: for i in range(len(loop)): face_data = loop[i] face_index = face_data[0] face = original_tri.triangles()[face_index] vert_nums = face_data[1] face_embed0 = face.embedding(0) face_tet = face_embed0.simplex() face_vertices = face_embed0.vertices() face_opposite_vert = face_vertices[3] coor_points_out_of_tet0 = (tet_vert_coorientations[ face_tet.index()][face_opposite_vert] == +1) # if (flow_agrees_with_regina_numbers != face_cor_agrees_with_regina_numbers) != coor_points_out_of_tet0: if coor_points_out_of_tet0: angle.extend([0, 2]) else: angle.extend([2, 0]) # print(sig, loop, angle, is_taut(tri, angle)) assert is_taut(tri, angle) if branch != None: for i in range(len(loop)): branch.extend([1, 1]) assert is_branched(tri, branch) M = snappy.Manifold(tri) if M.volume() < 1.0: print('not hyperbolic', sig, loop, angle, M.volume()) assert False # print(M.verify_hyperbolicity()) ### very slow # print(M.volume()) # assert M.volume() > 1.0 ### ### now orient swaps = [regina.Perm4() ] * original_countTetrahedra ### identity permutations for i in range(len(loop)): if new_0_tets[i].adjacentGluing(3).sign() == 1: if angle != None: this_tet_angle = angle[original_countTetrahedra + 2 * i] else: this_tet_angle = 0 ### pi_location = 0 is an arbitrary choice swaps.append( reverse_tet_orientation(tri, new_0_tets[i], this_tet_angle)) else: swaps.append(regina.Perm4()) if new_1_tets[i].adjacentGluing(3).sign() == 1: if angle != None: this_tet_angle = angle[original_countTetrahedra + 2 * i + 1] else: this_tet_angle = 0 ### pi_location = 0 is an arbitrary choice swaps.append( reverse_tet_orientation(tri, new_1_tets[i], this_tet_angle)) else: swaps.append(regina.Perm4()) assert tri.isOriented() if angle != None: assert is_taut(tri, angle) if branch != None: # print('loop, branch, swaps', loop, branch, swaps) apply_swaps_to_branched_surface(branch, swaps) # print('loop, branch, swaps', loop, branch, swaps) assert is_branched(tri, branch) assert has_non_sing_semiflow(tri, branch) ### return the vertex of the triangulation corresponding to the drilled cusp drilled_cusp = new_0_tets[0].vertex(swaps[new_0_tets[0].index()][3]) assert drilled_cusp.degree() == len(new_0_tets) + len(new_1_tets) return drilled_cusp.index()
def edges_to_triangles_matrix(triangulation, angle_structure, cycles, ZH, P, mode = "taut"): # In mode alexander, we are computing the transpose of the # boundary operator from relative 1-chains to relative 0-chains of # the dual 2-complex (relative to its vertex set). Note that we # technically should only be taking a single dual vertex # downstairs and lifting that... but then we would have to compute # a kernel. By using all of the dual vertices we are splitting # off a free summand of the correct rank. # In mode "taut" we are computing the matrix which assigns to a # triangle the switch condition on its dual lower track coorientations = is_transverse_taut(triangulation, angle_structure, return_type = "tet_vert_coorientations") if verbose > 0: print(("coorientations", coorientations)) face_laurents = faces_in_laurent(triangulation, angle_structure, cycles, ZH) if verbose > 0: print(("face_laurents", face_laurents)) ET_matrix = [] # now to find the face coefficients relative to each edge for tet in triangulation.tetrahedra(): # get its upper edge - we iterate over upper edges of tetrahedra if verbose > 0: print(("tet_index", tet.index())) edge = tet_lower_upper_edges(tet, coorientations)[1] if verbose > 0: print(("edge_index", edge.index())) embeddings = list(edge.embeddings()) # find index of tet in the list of embeddings of edge for i, embed in enumerate(embeddings): tet = embed.tetrahedron() if verbose > 0: print(("current_tet", tet.index())) vert_perm = embed.vertices() trailing_vert_num, leading_vert_num = vert_perm[2], vert_perm[3] if (coorientations[tet.index()][trailing_vert_num] == +1 and coorientations[tet.index()][leading_vert_num] == +1): bottom_index = i break # rotate embeddings = embeddings[bottom_index:] + embeddings[:bottom_index] face_coeffs = [ ZH(0) ] * 2 * triangulation.countTetrahedra() sign = -1 # we are going up the left side of the edge current_coeff = ZH(1) embed = embeddings[0] assert tet.index() == embed.tetrahedron().index() # sanity check if mode == "taut": # because of a sign change, we install the first and last by hand. vert_perm = embed.vertices() trailing_vert_num, leading_vert_num = vert_perm[2], vert_perm[3] leading_face = tet.triangle(trailing_vert_num) face_coeffs[leading_face.index()] = face_coeffs[leading_face.index()] + current_coeff trailing_face = tet.triangle(leading_vert_num) face_coeffs[trailing_face.index()] = face_coeffs[trailing_face.index()] + current_coeff if verbose > 0: print(("face_coeffs", face_coeffs)) embeddings = embeddings[1:-1] # and remove them for embed in embeddings: tet = embed.tetrahedron() vert_perm = embed.vertices() trailing_vert_num, leading_vert_num = vert_perm[2], vert_perm[3] leading_face = tet.triangle(trailing_vert_num) trailing_face = tet.triangle(leading_vert_num) if sign == -1: use_face = trailing_face else: # sign == -1 use_face = leading_face current_coeff = current_coeff * (face_laurents[use_face.index()])**sign if verbose > 0: print(("current_coeff", current_coeff)) if (coorientations[tet.index()][trailing_vert_num] == -1 and coorientations[tet.index()][leading_vert_num] == -1): ## we are the top embed sign = 1 # so now are going down the right side of the edge current_coeff = current_coeff * (face_laurents[leading_face.index()])**sign if verbose > 0: print(("top current_coeff", current_coeff)) if mode == "taut": face_coeffs[leading_face.index()] = face_coeffs[leading_face.index()] - current_coeff elif mode == "alexander": face_coeffs[leading_face.index()] = face_coeffs[leading_face.index()] + sign*current_coeff if verbose > 0: print(("face_coeffs", face_coeffs)) ET_matrix.append(face_coeffs) # convert and return return matrix_laurent_to_poly(ET_matrix, ZH, P)
def run_tests(num_to_check=10, smaller_num_to_check = 10): import taut veering_isosigs = parse_data_file("Data/veering_census.txt") print("testing is_taut") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) assert taut.is_taut(tri, angle), sig print("testing isosig round trip") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) recovered_sig = taut.isosig_from_tri_angle(tri, angle) assert sig == recovered_sig, sig # we only test this round trip - the other round trip does not # make sense because tri->isosig is many to one. import transverse_taut print("testing is_transverse_taut") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) assert transverse_taut.is_transverse_taut(tri, angle), sig non_transverse_taut_isosigs = parse_data_file("Data/veering_non_transverse_taut_examples.txt") print("testing not is_transverse_taut") for sig in non_transverse_taut_isosigs: tri, angle = taut.isosig_to_tri_angle(sig) assert not transverse_taut.is_transverse_taut(tri, angle), sig import veering print("testing is_veering") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) assert veering.is_veering(tri, angle), sig # tri, angle = taut.isosig_to_tri_angle("cPcbbbdxm_10") # explore_mobius_surgery_graph(tri, angle, max_tetrahedra = 12) # # tests to see that it makes only veering triangulations as it goes import veering_dehn_surgery print("testing veering_dehn_surgery") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) for face_num in veering_dehn_surgery.get_mobius_strip_indices(tri): (tri_s, angle_s, face_num_s) = veering_dehn_surgery.veering_mobius_dehn_surgery(tri, angle, face_num) assert veering.is_veering(tri_s, angle_s), sig import veering_fan_excision print("testing veering_fan_excision") m003, _ = taut.isosig_to_tri_angle('cPcbbbdxm_10') m004, _ = taut.isosig_to_tri_angle('cPcbbbiht_12') for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) tet_types = veering.is_veering(tri, angle, return_type = "tet_types") if tet_types.count("toggle") == 2: excised_tri, _ = veering_fan_excision.excise_fans(tri, angle) assert ( excised_tri.isIsomorphicTo(m003) != None or excised_tri.isIsomorphicTo(m004) != None ), sig import pachner print("testing pachner with taut structure") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) face_num = random.randrange(tri.countTriangles()) result = pachner.twoThreeMove(tri, face_num, angle = angle, return_edge = True) if result != False: tri2, angle2, edge_num = result tri3, angle3 = pachner.threeTwoMove(tri2, edge_num, angle = angle2) assert taut.isosig_from_tri_angle(tri, angle) == taut.isosig_from_tri_angle(tri3, angle3), sig import branched_surface import regina print("testing branched_surface and pachner with branched surface") for sig in random.sample(veering_isosigs, num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) tri_original = regina.Triangulation3(tri) #copy branch = branched_surface.upper_branched_surface(tri, angle, return_lower = random.choice([True, False])) ### test branch isosig round trip sig_with_branch = branched_surface.isosig_from_tri_angle_branch(tri, angle, branch) tri2, angle2, branch2 = branched_surface.isosig_to_tri_angle_branch(sig_with_branch) assert (branch == branch2) and (angle == angle2), sig branch_original = branch[:] #copy face_num = random.randrange(tri.countTriangles()) out = pachner.twoThreeMove(tri, face_num, branch = branch, return_edge = True) if out != False: tri, possible_branches, edge_num = out tri, branch = pachner.threeTwoMove(tri, edge_num, branch = possible_branches[0]) all_isoms = tri.findAllIsomorphisms(tri_original) all_branches = [branched_surface.apply_isom_to_branched_surface(branch, isom) for isom in all_isoms] assert branch_original in all_branches, sig import flow_cycles import drill print("testing taut and branched drill + semiflows on drillings") for sig in random.sample(veering_isosigs, smaller_num_to_check): tri, angle = taut.isosig_to_tri_angle(sig) branch = branched_surface.upper_branched_surface(tri, angle) ### also checks for veering and transverse taut found_loops = flow_cycles.find_flow_cycles(tri, branch) for loop in random.sample(found_loops, min(len(found_loops), 5)): ## drill along at most 5 loops tri, angle = taut.isosig_to_tri_angle(sig) branch = branched_surface.upper_branched_surface(tri, angle) tri_loop = flow_cycles.flow_cycle_to_triangle_loop(tri, branch, loop) if tri_loop != False: if not flow_cycles.tri_loop_is_boundary_parallel(tri_loop, tri): drill.drill(tri, tri_loop, angle = angle, branch = branch, sig = sig) assert branched_surface.has_non_sing_semiflow(tri, branch), sig print("all basic tests passed") try: import snappy import snappy_util snappy_working = True except: print("failed to import from snappy?") snappy_working = False if snappy_working: print("testing algebraic intersection") census = snappy.OrientableCuspedCensus() # not a set or list, so can't use random.sample for i in range(10): M = random.choice(census) n = M.num_cusps() peripheral_curves = M.gluing_equations()[-2*n:] for i in range(2*n): for j in range(i, 2*n): alg_int = snappy_util.algebraic_intersection(peripheral_curves[i], peripheral_curves[j]) if i % 2 == 0 and j == i + 1: assert alg_int == 1, M.name() else: assert alg_int == 0, M.name() if snappy_working: import veering_drill_midsurface_bdy print("testing veering drilling and filling") for sig in random.sample(veering_isosigs[:3000], num_to_check): T, per = veering_drill_midsurface_bdy.drill_midsurface_bdy(sig) M = snappy.Manifold(T.snapPea()) M.set_peripheral_curves("shortest") L = snappy_util.get_slopes_from_peripherals(M, per) M.dehn_fill(L) N = snappy.Manifold(sig.split("_")[0]) assert M.is_isometric_to(N), sig if snappy_working: print("all tests depending on snappy passed") # try: # from hashlib import md5 # from os import remove # import pyx # from boundary_triangulation import draw_triangulation_boundary_from_veering_isosig # pyx_working = True # except: # print("failed to import from pyx?") # pyx_working = False # ladders_style_sigs = { # "cPcbbbiht_12": "f34c1fdf65db9d02994752814803ae01", # "gLLAQbecdfffhhnkqnc_120012": "091c85b4f4877276bfd8a955b769b496", # "kLALPPzkcbbegfhgijjhhrwaaxnxxn_1221100101": "a0f15a8454f715f492c74ce1073a13a4", # } # geometric_style_sigs = { # "cPcbbbiht_12": "1e74d0b68160c4922e85a5adb20a0f1d", # "gLLAQbecdfffhhnkqnc_120012": "856a1fce74eb64f519bcda083303bd8f", # "kLALPPzkcbbegfhgijjhhrwaaxnxxn_1221100101": "33bd23b34c5d977a103fa50ffe63120a", # } # args = { # "draw_boundary_triangulation":True, # "draw_triangles_near_poles": False, # "ct_depth":-1, # "ct_epsilon":0.03, # "global_drawing_scale": 4, # "delta": 0.2, # "ladder_width": 10.0, # "ladder_height": 20.0, # "draw_labels": True, # } # shapes_data = read_from_pickle("Data/veering_shapes_up_to_ten_tetrahedra.pkl") # if pyx_working: # for sig in ladders_style_sigs: # print("testing boundary triangulation pictures, ladder style", sig) # args["tet_shapes"] = shapes_data[sig] # args["style"] = "ladders" # file_name = draw_triangulation_boundary_from_veering_isosig(sig, args = args) # f = open(file_name, "rb") # file_hash = md5(f.read()) # assert file_hash.hexdigest() == ladders_style_sigs[sig] # f.close() # remove(file_name) # if pyx_working: # for sig in geometric_style_sigs: # print("testing boundary triangulation pictures, ladder style", sig) # args["tet_shapes"] = shapes_data[sig] # args["style"] = "geometric" # file_name = draw_triangulation_boundary_from_veering_isosig(sig, args = args) # f = open(file_name, "rb") # file_hash = md5(f.read()) # assert file_hash.hexdigest() == geometric_style_sigs[sig] # f.close() # remove(file_name) # if pyx_working: # print("all tests depending on pyx passed") veering_polys = { "cPcbbbiht_12": [-4, -1, 1, 4], "eLMkbcddddedde_2100": [-2, -2, -2, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 2, 2], "gLLAQbecdfffhhnkqnc_120012": [-1, -1, -1, -1, 1, 1, 1, 1], "gLLPQcdfefefuoaaauo_022110": [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1], } # veering_polys = { ### old # "cPcbbbiht_12": "a^3 - 4*a^2 + 4*a - 1", # "eLMkbcddddedde_2100": "a^6*b - a^6 - 2*a^5*b - a^4*b^2 + a^5 + 2*a^4*b + a^3*b^2 - 2*a^3*b + a^3 + 2*a^2*b + a*b^2 - a^2 - 2*a*b - b^2 + b", # "gLLAQbecdfffhhnkqnc_120012": "a^7 + a^6 + a^5 + a^4 - a^3 - a^2 - a - 1", # "gLLPQcdfefefuoaaauo_022110": "a^12*b^3 - a^11*b^2 - a^10*b^3 - a^10*b^2 - a^7*b^3 - a^7*b^2 - a^6*b^3 + a^7*b + a^5*b^2 - a^6 - a^5*b - a^5 - a^2*b - a^2 - a*b + 1", # } taut_polys = { "cPcbbbiht_12": [-3, 1, 1], "eLMkbcddddedde_2100": [-1, -1, -1, 1, 1], "iLLAwQcccedfghhhlnhcqeesr_12001122": [], } # taut_polys = { ### old # "cPcbbbiht_12": "a^2 - 3*a + 1", # "eLMkbcddddedde_2100": "a^2*b - a^2 - a*b - b^2 + b", # "iLLAwQcccedfghhhlnhcqeesr_12001122": "0", # } torus_bundles = [ "cPcbbbiht_12", "eLMkbcdddhhqqa_1220", "gLMzQbcdefffhhqqqdl_122002", ] measured = [ "gLLAQbecdfffhhnkqnc_120012", "iLLALQcccedhgghhlnxkxrkaa_12001112", "iLLAwQcccedfghhhlnhcqeesr_12001122", ] empties = [ "fLAMcaccdeejsnaxk_20010", "gLALQbcbeeffhhwsras_211220", "hLALAkbcbeefgghhwsraqj_2112202", ] try: from sage.rings.integer_ring import ZZ sage_working = True except: print("failed to import from sage?") sage_working = False if sage_working: import taut_polytope print("testing is_layered") for sig in veering_isosigs[:17]: assert taut_polytope.is_layered(sig), sig for sig in veering_isosigs[17:21]: assert not taut_polytope.is_layered(sig), sig if sage_working: import fibered print("testing is_fibered") mflds = parse_data_file("Data/mflds_which_fiber.txt") mflds = [line.split("\t")[0:2] for line in mflds] for (name, kind) in random.sample(mflds, num_to_check): assert fibered.is_fibered(name) == (kind == "fibered"), name if sage_working: import veering_polynomial import taut_polynomial print("testing veering poly") for sig in veering_polys: p = veering_polynomial.veering_polynomial(sig) assert check_polynomial_coefficients(p, veering_polys[sig]), sig ### Nov 2021: sage 9.4 changed how smith normal form works, which changed our polynomials ### to equivalent but not equal polynomials. To avoid this kind of change breaking things ### in the future, we changed to comparing the list of coefficients. # assert p.__repr__() == veering_polys[sig] print("testing taut poly") for sig in taut_polys: p = taut_polynomial.taut_polynomial_via_tree(sig) assert check_polynomial_coefficients(p, taut_polys[sig]), sig # assert p.__repr__() == taut_polys[sig] print("testing divide") for sig in random.sample(veering_isosigs[:3000], num_to_check): p = veering_polynomial.veering_polynomial(sig) q = taut_polynomial.taut_polynomial_via_tree(sig) if q == 0: assert p == 0, sig else: assert q.divides(p), sig if sage_working: print("testing alex") for sig in random.sample(veering_isosigs[:3000], num_to_check): snap_sig = sig.split("_")[0] M = snappy.Manifold(snap_sig) if M.homology().betti_number() == 1: assert taut_polynomial.taut_polynomial_via_tree(sig, mode = "alexander") == M.alexander_polynomial(), sig if sage_working: # would be nice to automate this - need to fetch the angle # structure say via z_charge.py... print("testing is_torus_bundle") for sig in torus_bundles: assert taut_polytope.is_torus_bundle(sig), sig if sage_working: # ditto print("testing is_layered") for sig in torus_bundles: assert taut_polytope.is_layered(sig), sig print("testing measured") for sig in measured: assert taut_polytope.LMN_tri_angle(sig) == "M", sig print("testing empty") for sig in empties: assert taut_polytope.LMN_tri_angle(sig) == "N", sig if sage_working: # warning - this takes random amounts of time! print("testing hom dim") for sig in random.sample(veering_isosigs[:3000], 3): # magic number # dimension = zero if and only if nothing is carried. assert (taut_polytope.taut_cone_homological_dim(sig) == 0) == (taut_polytope.LMN_tri_angle(sig) == "N"), sig if sage_working: boundary_cycles = { ("eLMkbcddddedde_2100",(2,5,5,1,3,4,7,1)): "((-7, -7, 0, 0, 4, -3, 7, 0), (7, 7, 0, 0, -4, 3, -7, 0))", ("iLLLQPcbeegefhhhhhhahahha_01110221",(0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,0)): "((0, 0, -1, 1, 1, 0, 1, 1, -1, 0, 0, 0, 0, 1, 0, 1), (0, 0, 1, -1, -1, 0, -1, -1, 1, 0, 0, 0, 0, -1, 0, -1))", ("ivvPQQcfhghgfghfaaaaaaaaa_01122000",(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)): "((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0), (-2, 0, -3, 1, 2, -1, 0, 2, -1, 0, 3, 1, -2, 1, 0, -1), (0, -2, 1, -3, 0, -1, 2, 0, -1, 2, -1, 1, 0, 1, -2, 3))", } taut_polys_with_cycles = { ("eLMkbcddddedde_2100", ((7, 7, 0, 0, -4, 3, -7, 0),)): [-1, -1, -1, 1, 1], ("iLLLQPcbeegefhhhhhhahahha_01110221", ((0, 0, 1, -1, -1, 0, -1, -1, 1, 0, 0, 0, 0, -1, 0, -1),)): [1, 1, 2], ("ivvPQQcfhghgfghfaaaaaaaaa_01122000", ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0))): [-4, -1, -1, 1, 1], } # taut_polys_with_cycles = { # ("eLMkbcddddedde_2100", ((7, 7, 0, 0, -4, 3, -7, 0),)): "a^14 - a^8 - a^7 - a^6 + 1", # ("iLLLQPcbeegefhhhhhhahahha_01110221", ((0, 0, 1, -1, -1, 0, -1, -1, 1, 0, 0, 0, 0, -1, 0, -1),)): "a^2 + 2*a + 1", # ("ivvPQQcfhghgfghfaaaaaaaaa_01122000", ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0))): "a*b^2 - a^2 - 4*a*b - b^2 + a", # } taut_polys_image = { ('eLMkbcddddedde_2100', ((7, 8, -1, 0, -4, 4, -8, 0),)):[-1, -1, -1, 1, 1], ('ivvPQQcfhghgfghfaaaaaaaaa_01122000', ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2),)):[-2, -2, -1, -1, 1, 1], ('ivvPQQcfhghgfghfaaaaaaaaa_01122000', ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0))):[-4, -1, -1, 1, 1] } # taut_polys_image = { # ('eLMkbcddddedde_2100', ((7, 8, -1, 0, -4, 4, -8, 0),)):"a^16 - a^9 - a^8 - a^7 + 1", # ('ivvPQQcfhghgfghfaaaaaaaaa_01122000', ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2),)):"a*b^2*c - 2*a*b*c - b^2*c - a^2 - 2*a*b + a", # ('ivvPQQcfhghgfghfaaaaaaaaa_01122000', ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0))):"a*b^2 - a^2 - 4*a*b - b^2 + a" # } alex_polys_with_cycles = { ("eLMkbcddddedde_2100",((7, 7, 0, 0, -4, 3, -7, 0),)): [-2, -1, -1, -1, 1, 1, 1, 2], ("iLLLQPcbeegefhhhhhhahahha_01110221", ((0, 0, 1, -1, -1, 0, -1, -1, 1, 0, 0, 0, 0, -1, 0, -1),)): [-3, -1, 1, 3], ("ivvPQQcfhghgfghfaaaaaaaaa_01122000", ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0))): [-1, -1, 1, 1], } # alex_polys_with_cycles = { # ("eLMkbcddddedde_2100",((7, 7, 0, 0, -4, 3, -7, 0),)): "a^15 - a^14 + a^9 - 2*a^8 + 2*a^7 - a^6 + a - 1", # ("iLLLQPcbeegefhhhhhhahahha_01110221", ((0, 0, 1, -1, -1, 0, -1, -1, 1, 0, 0, 0, 0, -1, 0, -1),)): "3*a^3 - a^2 + a - 3", # ("ivvPQQcfhghgfghfaaaaaaaaa_01122000", ((1, 1, 2, 0, -1, 2, 1, -3, 0, -1, 0, -2, -1, 0, 3, -2), (1, 1, 0, 2, -1, 0, -3, 1, 2, -1, -2, 0, 3, -2, -1, 0))): "a*b^2 - a^2 - b^2 + a", # } if sage_working: import taut_carried print("testing boundary cycles") for sig, surface in boundary_cycles: surface_list = list(surface) cycles = taut_carried.boundary_cycles_from_surface(sig, surface_list) cycles = tuple(tuple(cycle) for cycle in cycles) assert cycles.__repr__() == boundary_cycles[(sig, surface)], sig if sage_working: print("testing taut with cycles") for sig, cycles in taut_polys_with_cycles: cycles_in = [list(cycle) for cycle in cycles] p = taut_polynomial.taut_polynomial_via_tree(sig, cycles_in) assert check_polynomial_coefficients(p, taut_polys_with_cycles[(sig, cycles)]), sig # assert p.__repr__() == taut_polys_with_cycles[(sig, cycles)] if sage_working: print("testing taut with images") for sig, cycles in taut_polys_image: cycles_in = [list(cycle) for cycle in cycles] p = taut_polynomial.taut_polynomial_image(sig, cycles_in) assert check_polynomial_coefficients(p, taut_polys_image[(sig, cycles)]), sig # assert p.__repr__() == taut_polys_image[(sig, cycles)] if sage_working: print("testing alex with cycles") for sig, cycles in alex_polys_with_cycles: cycles_in = [list(cycle) for cycle in cycles] p = taut_polynomial.taut_polynomial_via_tree(sig, cycles_in, mode = "alexander") assert check_polynomial_coefficients(p, alex_polys_with_cycles[(sig, cycles)]), sig # assert p.__repr__() == alex_polys_with_cycles[(sig, cycles)] if sage_working: import edge_orientability import taut_euler_class print("testing euler and edge orientability") for sig in random.sample(veering_isosigs[:3000], 3): # Theorem: If (tri, angle) is edge orientable then e = 0. assert not ( edge_orientability.is_edge_orientable(sig) and (taut_euler_class.order_of_euler_class_wrapper(sig) == 2) ), sig if sage_working: # Theorem: If (tri, angle) is edge orientable then taut poly = alex poly. # taut_polynomial.taut_polynomial_via_tree(sig, mode = "alexander") == # taut_polynomial.taut_polynomial_via_tree(sig, mode = "taut") pass if sage_working: print("testing exotics") for sig in random.sample(veering_isosigs[:3000], 3): tri, angle = taut.isosig_to_tri_angle(sig) T = veering.veering_triangulation(tri, angle) is_eo = T.is_edge_orientable() for angle in T.exotic_angles(): assert taut_polytope.taut_cone_homological_dim(tri, angle) == 0, sig assert is_eo == transverse_taut.is_transverse_taut(tri, angle), sig ### test for drill_midsurface_bdy: drill then fill, check you get the same manifold if sage_working: from sage.combinat.words.word_generators import words from sage.modules.free_module_integer import IntegerLattice from sage.modules.free_module import VectorSpace from sage.matrix.constructor import Matrix import z_charge import z2_taut import regina ZZ2 = ZZ.quotient(ZZ(2)) sig_starts = ["b+-LR", "b++LR"] print("testing lattice for punc torus bundle") for i in range(3): for sig_start in sig_starts: sig = sig_start + str(words.RandomWord(8, 2, "LR")) # 8 is a magic number M = snappy.Manifold(sig) tri = regina.Triangulation3(M) t, A = z_charge.sol_and_kernel(M) B = z_charge.leading_trailing_deformations(M) C = z2_taut.cohomology_loops(tri) AA = IntegerLattice(A) BB = IntegerLattice(B) assert AA == BB.saturation(), sig dim = 3*M.num_tetrahedra() V = VectorSpace(ZZ2, dim) AA = V.subspace(A) BB = V.subspace(B) CM = Matrix(ZZ2, C) CC = CM.right_kernel() assert AA.intersection(CC) == BB , sig ## so l-t defms are the part of the kernel that doesn't flip over if sage_working: print("testing charges for punc torus bundle") for i in range(3): for sig_start in sig_starts: sig = sig_start + str(words.RandomWord(8, 2, "LR")) # 8 is a magic number M = snappy.Manifold(sig) assert z_charge.can_deal_with_reduced_angles(M), sig if sage_working: import carried_surface import mutation print("testing building carried surfaces and mutations") sigs_weights = [ ['iLLLPQccdgefhhghqrqqssvof_02221000', (0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0)], ['jLLAvQQcedehihiihiinasmkutn_011220000', (2, 0, 1, 0, 0, 0, 1, 2, 0, 2, 0, 2, 1, 0, 0, 0, 1, 0)], ['jLLAvQQcedehihiihiinasmkutn_011220000', (0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0)], ['jLLLMPQcdgfhfhiiihshassspiq_122201101', (0, 0, 4, 0, 4, 1, 0, 2, 2, 0, 1, 0, 0, 4, 0, 4, 0, 0)] ] strata = [ ((1, 2), [2, 2]), ((2, 4), [5, 5, 1, 1]), ((0, 3), [2, 0, 0]), ((6, 1), [22]) ] orders_of_veering_symmetry_groups = [4, 2, 2, 2] for i in range(len(sigs_weights)): tri, angle = taut.isosig_to_tri_angle(sigs_weights[i][0]) weights = sigs_weights[i][1] surface, edge_colours = carried_surface.build_surface(tri, angle, weights, return_edge_colours = True) assert strata[i] == carried_surface.stratum_from_weights_surface(weights, surface) veering_isoms = carried_surface.veering_symmetry_group(surface, edge_colours) assert len(veering_isoms) == orders_of_veering_symmetry_groups[i] isom = veering_isoms[1] mutation.mutate(tri, angle, weights, isom, quiet = True) if i == 0: assert tri.isoSig() == 'ivLLQQccfhfeghghwadiwadrv' #print('svof to wadrv passed') elif i == 1: assert tri.isoSig() == 'jvLLAQQdfghhfgiiijttmtltrcr' #print('smkutn to tltrcr passed') elif i == 2: assert tri.isoSig() == 'jLLMvQQcedehhiiihiikiwnmtxk' #print('smkutn to mtxk passed') elif i == 3: assert tri.isoSig() == 'jLLALMQcecdhggiiihqrwqwrafo' #print('spiq to rafo passed') if sage_working: print("all tests depending on sage passed")
# sig = 'eLMkbcddddedde_2100' # sig = 'eLMkbcdddhxqlm_1200' # sig = 'eLAkaccddjsnak_2001' # sig = 'eLAkbbcdddhwqj_2102' # sig = 'fLLQcbcdeeelonlel_02211' ## should have three different midsurface bdy components, so four total after drilling # sig = 'fLLQcbddeeehrcdui_12000' ## five boundary components # sig = 'fLAMcbbcdeedhwqqs_21020' # sig = 'qvvLPQwAPLQkfhgffijlkmnopoppoaaaaaaaaaaaaadddd_1020212200111100' # t = excise_fans(sig) # t.save('excise_fans_' + sig + '.rga') # t0, _ = isosig_to_tri_angle('cPcbbbdxm_10') # t1, _ = isosig_to_tri_angle('cPcbbbiht_12') # print t.isIsomorphicTo(t0) != None or t.isIsomorphicTo(t1) != None # print fan_stacks(sig) import veering import transverse_taut import taut from file_io import parse_data_file census = parse_data_file('Data/veering_census.txt') for sig in census[:200]: tri, angle = excise_fans(sig) print((sig, tri.countTetrahedra(), angle, taut.is_taut(tri, angle))) assert veering.is_veering(tri, angle) assert transverse_taut.is_transverse_taut(tri, angle) # print sig, fan_stacks(sig)
def is_edge_orientable(tri, angle, return_type="boolean"): """ checks to see if this veering triangulation is edge orientable. If return type is "tri angle" it returns the edge orientable double cover with its angle structure. Note that this is disconnected if and only if the given triangulation is edge orientable """ # return type can be "boolean", "veering_tet_vert_nums", or "tri angle" n = tri.countTetrahedra() veering_colours = is_veering(tri, angle, return_type="veering_colours") assert veering_colours != False # so we are veering tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") ### assumption: the first n tetrahedra have upper edge oriented according to Regina, the last n have it against Regina ### build our own model vertex numbering for each tetrahedron as follows: ### the top edge e is oriented by regina numbering, and gets vert_nums 1 and 2 in our ordering ### an equatorial edge e' of the same colour as e shares a vertex v with it. ### e and e' both point away from v or towards it. If away then the other end of e' is 3, ### else, the other end is 0 veering_tet_vert_nums = [ ] ### will populate with regina's vert nums, but our order. ### that is, veering_tet_vert_nums[1] and [2] will be the regina vert nums for the ends of the top edge for i in range(n): tet = tri.tetrahedron(i) veering_vert_nums = [None, None, None, None] top_vert_pair = get_tet_top_vert_nums(tet_vert_coorientations, i) # print(i, top_vert_pair) if not regina_edge_orientation_agrees(tet, top_vert_pair): top_vert_pair.reverse() assert regina_edge_orientation_agrees(tet, top_vert_pair) veering_vert_nums[1] = top_vert_pair[0] veering_vert_nums[2] = top_vert_pair[1] top_edge_num = vert_pair_to_edge_num[tuple(top_vert_pair)] top_edge_col = veering_colours[tet.edge(top_edge_num).index()] bottom_vert_pair = list(set(range(4)) - set(top_vert_pair)) bv, bv2 = bottom_vert_pair ## choose arbitrarily, now find which edge from the top vertices has same colour as bv for j, tv in enumerate(top_vert_pair): edge_col = veering_colours[tet.edge( vert_pair_to_edge_num[(bv, tv)]).index()] if edge_col == top_edge_col: if j == 0: ### bv shares an edge of same colour as top with tail of top edge veering_vert_nums[3] = bv veering_vert_nums[0] = bv2 else: ### bv shares an edge of same colour as top with head of top edge veering_vert_nums[0] = bv veering_vert_nums[3] = bv2 veering_tet_vert_nums.append(veering_vert_nums) # print('veering_tet_vert_nums', veering_tet_vert_nums) if return_type == "veering_tet_vert_nums": return veering_tet_vert_nums ### Now, when we glue two tetrahedra together along a face, the first of the three vertices in the veering_vert_num order ### on that tet's face glues to the first of the three vertices on the other tet's face, or to the third. ### depending on this, we go to the other part of the double cover, or not cover_tri = regina.Triangulation3() ## starts empty for i in range(2 * n): cover_tri.newTetrahedron() tet_faces = [] for i in range(n): for j in range(4): tet_faces.append((i, j)) while len(tet_faces) > 0: i, j = tet_faces.pop() tet = tri.tetrahedron(i) adjtet, adjgluing = tet.adjacentTetrahedron(j), tet.adjacentGluing(j) iN, jN = adjtet.index(), adjgluing[j] tet_faces.remove((iN, jN)) cover_tets = [cover_tri.tetrahedron(i), cover_tri.tetrahedron(i + n)] cover_tetsN = [ cover_tri.tetrahedron(iN), cover_tri.tetrahedron(iN + n) ] ### find the veering indices for the verts in the gluing on this tet and on adjtet face_veering_nums = veering_tet_vert_nums[i][:] face_veering_nums.remove(j) a, b, c = face_veering_nums neighbour_face_veering_nums = veering_tet_vert_nums[iN][:] neighbour_face_veering_nums.remove(jN) aN, bN, cN = neighbour_face_veering_nums assert adjgluing[b] == bN ### middles should match if adjgluing[a] == aN: ### veering orderings agree across the gluing assert adjgluing[c] == cN for k in range(2): cover_tets[k].join(j, cover_tetsN[k], adjgluing) else: ### veering orderings disagree across the gluing assert adjgluing[a] == cN and adjgluing[c] == aN for k in range(2): cover_tets[k].join(j, cover_tetsN[(k + 1) % 2], adjgluing) assert not cover_tri.hasBoundaryFacets() assert is_veering(cover_tri, angle + angle) if return_type == "boolean": return not cover_tri.isConnected( ) ### not connected if the original veering triangulation is edge orientable else: assert return_type == "tri angle" return cover_tri, angle + angle