def cross_strand(crossings, loose_cs, strand_to_cross, new_label): opposite = strand_to_cross.opposite() new_crossing = Crossing(new_label) crossings.append(new_crossing) cs0, cs1, cs2, cs3 = new_crossing.crossing_strands() connect_crossing_strands(cs0, loose_cs) connect_crossing_strands(cs1, strand_to_cross) connect_crossing_strands(cs3, opposite) return cs2
def random_knot(n, method='close_under', alternate=False, bias=False, num_opportunities=1): if method == 'close_under': crossings, loose_cs, final_cs = random_open_string(n, alternate=alternate, bias=bias) connect_loose_strands(crossings, loose_cs, final_cs) return Link(crossings) elif method == 'close_on_opportunity': crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] i = 0 while num_opportunities > 0: available = available_strands(loose_cs) strand_to_cross = choice(available) if alternate: over_or_under = 1 - (i % 2) else: over_or_under = randint(0, 1) loose_cs = cross_strand(crossings, loose_cs, strand_to_cross, str(i + 1), over_or_under) same_face = set(available_strands(loose_cs)) == set( available_strands(final_cs)) if same_face: num_opportunities -= 1 i += 1 if i >= n: raise Exception('Not closeable after n crossings') connect_loose_strands(crossings, loose_cs, final_cs) return Link(crossings)
def random_open_string(n): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] for i in range(n): available = available_strands(loose_cs) # print('available') # print(available) # print(loose_cs, final_cs) # print('crossings before') # [c.info() for c in crossings] if final_cs in available: available.remove(final_cs) strand_to_cross = choice(available) # print('strand_to_cross') # print(strand_to_cross) # print('available after') # print(available) loose_cs = cross_strand(crossings, loose_cs, strand_to_cross, str(i + 1)) # print('crossings after') # [c.info() for c in crossings] return crossings, loose_cs, final_cs
def cross_strand(crossings, loose_cs, strand_to_cross, new_label, over_vs_under): opposite = strand_to_cross.opposite() new_crossing = Crossing(new_label) crossings.append(new_crossing) # cs0, cs1, cs2, cs3 = new_crossing.crossing_strands() # connect_crossing_strands(cs0, loose_cs) # connect_crossing_strands(cs1, strand_to_cross) # connect_crossing_strands(cs3, opposite) css = new_crossing.crossing_strands() connect_crossing_strands(css[0 + over_vs_under], loose_cs) connect_crossing_strands(css[1 + over_vs_under], strand_to_cross) connect_crossing_strands(css[(3 + over_vs_under) % 4], opposite) return css[2 + over_vs_under]
def open_string_from_turn_list(turn_list): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] for i, turn in enumerate(turn_list): available = available_strands(loose_cs) # print('available') # print(available) # print(loose_cs, final_cs) # print('crossings before') # [c.info() for c in crossings] if final_cs in available: available.remove(final_cs) strand_to_cross = available[(abs(turn) - 1) % len(available)] # print('strand_to_cross') # print(strand_to_cross) # print('available after') # print(available) loose_cs = cross_strand(crossings, loose_cs, strand_to_cross, str(i + 1), (turn > 0)) # print('crossings after') # [c.info() for c in crossings] return crossings, loose_cs, final_cs
def link(self): active = dict() component_starts = [] crossings = [] for event in self.events: if event.kind == 'cup': S = Strand() crossings.append(S) active = insert_space(active, event.min) active[event.a] = S[0] active[event.b] = S[1] elif event.kind == 'cap': S = Strand() crossings.append(S) S[0] = active[event.a] S[1] = active[event.b] active = remove_space(active, event.min) elif event.kind == 'cross': C = Crossing() crossings.append(C) if event.a < event.b: C[3] = active[event.a] C[0] = active[event.b] active[event.a] = C[2] active[event.b] = C[1] else: C[3] = active[event.a] C[2] = active[event.b] active[event.a] = C[0] active[event.b] = C[1] return Link(crossings)
def mirror(link): """ Create the mirror image of the link, preserving link orientations and component order. """ # Basically, we just mirror every crossing, but the particular data # structures used make this a little involved. new_crossings = dict() for C in link.crossings: C_new = Crossing(label=C.label) C_new.sign = -C.sign new_crossings[C] = C_new def convert(C, c): """ Go from a crossing to the mirror, which requires the a rotation of the entry points; the direction of rotation depends on the sign of the crossing. """ return new_crossings[C], (c + C.sign) % 4 for A in link.crossings: entry_points = [CEP.entry_point for CEP in A.entry_points()] for a in entry_points: B, b = A.adjacent[a] B_new, b_new = convert(B, b) B_new[b_new] = convert(A, a) new_link = Link(new_crossings.values(), check_planarity=False, build=False) # Build the link components, starting in the same place as # the original link. component_starts = [] for component in link.link_components: C_new, c_new = convert(*component[0]) component_starts.append( CrossingEntryPoint(C_new, c_new) ) new_link._build_components(component_starts) return new_link
def link(self): G = self.fat_graph crossing_dict, slot_dict = {}, {} for v in G.vertices: c = Crossing(v[0]) c.make_tail(0) if G.sign(v) == 1: c.make_tail(3) else: c.make_tail(1) c.orient() crossing_dict[v] = c if v.upper_pair() == (0, 2): slot_dict[v] = (3, 0, 1, 2) else: slot_dict[v] = (2, 3, 0, 1) if G.flipped(v) else (0, 1, 2, 3) for edge in G.edges: v0, v1 = edge s0, s1 = edge.slots a0, a1 = slot_dict[v0][s0], slot_dict[v1][s1] c0, c1 = crossing_dict[v0], crossing_dict[v1] c0[a0] = c1[a1] link = Link(list(crossing_dict.values()), check_planarity=False, build=False) assert link.all_crossings_oriented() component_starts = [] i = 1 for comp in self.code: c = self[i] if i == c[0]: e = slot_dict[c][2] if G.flipped(c) else slot_dict[c][0] else: e = slot_dict[c][1] ce = CrossingEntryPoint(crossing_dict[c], e) component_starts.append(ce) i += 2 * len(comp) link._build_components(component_starts) if not link.is_planar(): raise ValueError( 'DT code does not seem to define a *planar* diagram') return link
def knot_tree(depth): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] tree = nx.Graph() tree.add_node('') leaves = [''] for i in range(depth): print(i) leaves = split_leaves(tree, leaves) return tree, [map(int, leaf.split()) for leaf in leaves]
def gausscode_to_crossings(gc): cl = gc._gauss_code crossings = [] incomplete_crossings = {} line_lengths = [len(line) for line in cl] total_lines = sum(line_lengths) line_indices = [1] + list(n.cumsum(line_lengths)[:-1] + 1) curline = 1 for i, line in enumerate(cl): curline = line_indices[i] for index, over, clockwise in line: if index in incomplete_crossings: crossing = incomplete_crossings.pop(index) else: crossing = Crossing() inline = curline curline += 1 if curline >= (line_indices[i] + line_lengths[i]): curline = line_indices[i] outline = curline if over == -1: crossing[0] = inline crossing[2] = outline crossings.append(crossing) else: if clockwise == 1: crossing[3] = inline crossing[1] = outline else: crossing[1] = inline crossing[3] = outline if not crossing.valid(): incomplete_crossings[index] = crossing return crossings
def link(self): G = self.fat_graph crossing_dict = {} for v in G.vertices: c = Crossing(v[0]) c.make_tail(0) if G.sign(v) == 1: c.make_tail(3) else: c.make_tail(1) c.orient() crossing_dict[v] = c for edge in G.edges: if edge.slots[0] in edge[0].upper_pair(): a = 1 if G.sign(edge[0]) == 1 else 3 else: a = 2 if edge.slots[1] in edge[1].upper_pair(): b = 3 if G.sign(edge[1]) == 1 else 1 else: b = 0 crossing_dict[edge[0]][a] = crossing_dict[edge[1]][b] return Link(crossing_dict.values(), check_planarity=False)
def shorthand_to_crossings(s): ''' Takes a planar diagram shorthand string, and returns a list of :class:`Crossing`s. ''' crossings = [] cs = s.split(' ') for entry in cs: entry = entry.split('_') if entry[0] == 'X': a, b, c, d = [int(j) for j in entry[1].split(',')] crossings.append(Crossing(a, b, c, d)) elif entry[0] == 'P': a, b = [int(j) for j in entry[1].split(',')] crossings.append(Point(a, b)) return crossings
def alexander_evolution(n): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] alex_polys = [] for i in range(n): print(i) available = available_strands(loose_cs) if final_cs in available: available.remove(final_cs) strand_to_cross = choice(available) loose_cs = cross_strand(crossings, loose_cs, strand_to_cross, str(i + 1), randint(0, 1)) alex_polys.append(open_string_alexander(crossings)) return alex_polys
def random_open_string(n, alternate=False, bias=False): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] for i in range(n): available = available_strands(loose_cs) if bias: strand_to_cross = choice(bias_middle(available)) else: strand_to_cross = choice(available) if alternate: over_or_under = 1 - (i % 2) else: over_or_under = randint(0, 1) loose_cs = cross_strand(crossings, loose_cs, strand_to_cross, str(i + 1), over_or_under) return crossings, loose_cs, final_cs
def function_evolution(n, function, simplify='level', skip_first=0): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] values = [] for i in range(n): print(i) available = available_strands(loose_cs) if final_cs in available: available.remove(final_cs) strand_to_cross = choice(available) loose_cs = cross_strand(crossings, loose_cs, strand_to_cross, str(i + 1), randint(0, 1)) if i >= skip_first: values.append(open_string_evaluation(crossings, function, simplify)) return values
def as_spherogram(self): ''' Get a planar diagram class from the Spherogram module, which can be used to access SnapPy's manifold tools. This method requires that spherogram and SnapPy are installed. ''' from spherogram import Crossing, Link scs = [Crossing() for crossing in self] indices = {} for i in range(len(self)): c = self[i] for j in range(len(c)): number = c[j] if number in indices: otheri, otherj = indices.pop(number) scs[i][j] = scs[otheri][otherj] else: indices[number] = (i, j) return Link(scs)
def start_string(): crossings = [Crossing('0')] crossings[0][2] = crossings[0][3] final_cs = crossings[0].crossing_strands()[0] loose_cs = crossings[0].crossing_strands()[1] return crossings, loose_cs, final_cs