def tangle_cut(link, cycle): """ Creates two Tangle objects from a given cycle (with no self intersections) in the dual graph of a link (inside and outside). Cycle is given as a list of (oriented) edges in the dual graph. Make sure crossings are uniquely labeled. Destroys original link. """ sides = { } #keeps track of which side each crossing strand is as dictionary sides[cslabel( cycle[0].interface[0])] = 0 #start by assigning to first pair sides[cslabel(cycle[0].interface[1])] = 1 #sides side0 = [cycle[0].interface[0]] side1 = [cycle[0].interface[1]] for i in range(len(cycle) - 1): # print(i) edge1 = cycle[i] edge2 = cycle[i + 1] edge1_cs1, edge1_cs2 = edge1.interface #crossing strands on each end edge2_cs1, edge2_cs2 = edge2.interface edge1_cs1_side = sides[cslabel(edge1_cs1)] edge1_cs2_side = 1 - edge1_cs1_side wrong_face = False #starting with edge1_cs1, travel around face #if I run into one of edge2_cs*, they are on different sides #if I don't, try again with the other while True: # print('sides:') # print(sides) # print('edge1:') # print(edge1_cs1,edge1_cs2) # print('edge2:') # print(edge2_cs1,edge2_cs2) edge1_cs1 = edge1_cs1.next_corner() # print(type(edge1_cs1.crossing.label)) # print(edge1_cs1) if edge1_cs1 == edge2_cs1: sides[cslabel(edge2_cs1)] = edge1_cs2_side sides[cslabel(edge2_cs2)] = edge1_cs1_side if edge1_cs2_side == 1: side1.append(edge2_cs1) side0.append(edge2_cs2) else: side0.append(edge2_cs1) side1.append(edge2_cs2) # print('case 1') break if edge1_cs1 == edge2_cs2: sides[cslabel(edge2_cs1)] = edge1_cs1_side sides[cslabel(edge2_cs2)] = edge1_cs2_side if edge1_cs2_side == 1: side0.append(edge2_cs1) side1.append(edge2_cs2) else: side1.append(edge2_cs1) side0.append(edge2_cs2) # print('case 2') break if edge1_cs1.opposite( ) == edge1_cs2: #returned without seeing them wrong_face = True # print('case 3') break # Try again with other side while wrong_face: edge1_cs1_side = sides[cslabel(edge1_cs1)] edge1_cs2_side = 1 - edge1_cs1_side edge1_cs2 = edge1_cs2.next_corner() if edge1_cs2 == edge2_cs1: # print('case 4') sides[cslabel(edge2_cs1)] = edge1_cs1_side sides[cslabel(edge2_cs2)] = edge1_cs2_side if edge1_cs2_side == 1: side0.append(edge2_cs1) side1.append(edge2_cs2) else: side1.append(edge2_cs1) side0.append(edge2_cs2) break if edge1_cs2 == edge2_cs2: # print('case 5') sides[cslabel(edge2_cs1)] = edge1_cs2_side sides[cslabel(edge2_cs2)] = edge1_cs1_side if edge1_cs2_side == 1: side1.append(edge2_cs1) side0.append(edge2_cs2) else: side0.append(edge2_cs1) side1.append(edge2_cs2) break if edge1_cs2.opposite( ) == edge1_cs1: #returned without seeing them again, must be error raise Exception("Neither side worked") crossing_sides = fill_in_crossings(link, sides) n = len(cycle) side0[n / 2:] = reversed(side0[n / 2:]) #flip to use as adjacent in tangle side1[n / 2:] = reversed(side1[n / 2:]) crossings0 = [ crossing_from_name(link, c) for c in crossing_sides if crossing_sides[c] == 0 ] crossings1 = [ crossing_from_name(link, c) for c in crossing_sides if crossing_sides[c] == 1 ] #clear crossing info clear_orientations(crossings0) clear_orientations(crossings1) #One of the tangles is the 'outside', and needs to be flipped #Just check side0 side0_needs_flip = False c, i = side0[0] while True: next_cep = c.crossing_strands()[(i + 1) % 4] c, i = next_cep.crossing, next_cep.strand_index # print(c,i) # print(side0) if (c, i) in side0: # print('hit_end') # print(c,i) # print(side0[1]) # print((c,i)==side0[1]) side0_needs_flip = (c, i) != (side0[1]) break c, i = next_cep.opposite().crossing, next_cep.opposite().strand_index if side0_needs_flip: # print('flipped side 0') flip(side0) else: # print('flipped side 1') flip(side1) return Tangle(n / 2, crossings0, side0), Tangle(n / 2, crossings1, side1)
def tangle_neighborhood(link, crossing, radius, return_gluings=True, hull=False): """ Splits a link into two tangles along a ball around a crossing of the given radius. Destroys original link. This might not generate an actual tangle; the graph metric ball will usually have multiple boundary components. """ crossings, adjacent = crossing_ball(crossing, radius) crossings = list(crossings) opposites = list(reversed(map(lambda x: x.opposite(), adjacent))) outside_crossings = [c for c in link.crossings if c not in crossings] if len(outside_crossings) == 0: raise Exception("Neighborhood is entire link") n = len(adjacent) / 2 if hull: comps = list(boundary_components(link, crossing, radius)) largest_comp = max(comps) sides = dict([(cslabel(cross_strand), cross_strand) for cross_strand in adjacent]) c = largest_comp.pop() cs = choice(c.crossing_strands()) exit_strand = meander(cs, sides)[1] exit_strand = exit_strand[0].crossing_strands()[exit_strand[1]] main_boundary_comp = trace_boundary_component(exit_strand, adjacent) print('main_boundary_comp' + str(main_boundary_comp)) print('all comps: ' + str(comps)) comps.remove(largest_comp) #remove largest component for comp in comps: print('crossings: ' + str(crossings)) print('filling in comp:' + str(comp)) print('adjacent: ' + str(adjacent)) c = comp.pop() cs = choice(c.crossing_strands()) print('cs: ' + str(cs)) exit_strand = meander(cs, sides)[1] #meander until you hit boundary exit_strand = exit_strand[0].crossing_strands()[exit_strand[1]] print('exit_strand: ' + str(exit_strand)) bound_comp = trace_boundary_component(exit_strand, adjacent) print('traced component: ' + str(bound_comp)) if exit_strand not in main_boundary_comp: for x in bound_comp: adjacent.remove(x) print('updated adjacent: ' + str(adjacent)) crossings.append(c) crossings.extend(list(comp)) adjacent[n:] = reversed(adjacent[n:]) opposites[n:] = reversed(opposites[n:]) gluings = [] seen_cs = [] # figure out which strands are glued to each other for cs in adjacent: if cs in seen_cs: continue next_cross = cs.next_corner() while next_cross not in adjacent: next_cross = next_cross.next_corner() if next_cross != cs: gluings.append((adjacent.index(cs), adjacent.index(next_cross))) seen_cs.append(next_cross) clear_orientations(crossings) clear_orientations(outside_crossings) gluings.sort() if return_gluings: return Tangle(n, crossings, adjacent), Tangle(n, outside_crossings, opposites), gluings else: return Tangle(n, crossings, adjacent), Tangle(n, outside_crossings, opposites)