@@ -47,12 +47,11 @@ def __init__(self, link):
4747
4848 def two_cycles (self ):
4949 """
50- Find all two cycles and yield them as a pair of CrossingStrands which
51- are dual to the edges in the cycle.
50+ Find all two cycles and yield them as a pair of
51+ CrossingStrands which are dual to the edges in the cycle.
5252
53- The crossing strands are
54- oriented consistently with respect to one of the faces which a
55- vertex for the cycle.
53+ The crossing strands are oriented consistently with respect to
54+ one of the faces which a vertex for the cycle.
5655 """
5756 for face0 in self .vertices :
5857 for dual_edge0 in self .incident (face0 ):
@@ -298,19 +297,41 @@ def dual_graph_as_nx(link, graph_class=nx.Graph):
298297 interface = {face .label : edge , neighbor .label : opp_edge })
299298
300299 G .edge_to_face = to_face_index
300+ G .faces = faces
301301 return G
302302
303303
304- def deconnect_sum (link ):
304+ def disjoint_deconnect_sum_once (link ):
305305 """
306306 Warning: Destroys the original link.
307+
308+ If the diagram is an obvious connected sum, return a decomposition
309+ of the link into nontrivial summands. A summand may itself still
310+ be a connected sum.
311+
312+ This is just a helper function for deconnect_sum.
313+
314+ Here is a connect sum of 3 trefoils, but we'll only pull off 1 at this
315+ step.
316+
317+ >>> K = Link('DT: iaibiahcgefd.001010111')
318+ >>> sorted(len(P) for P in disjoint_deconnect_sum_once(K))
319+ [3, 6]
307320 """
308321 G = dual_graph_as_nx (link , nx .MultiGraph )
322+ faces_used = set ()
309323 for path in simple_cycles (G , 2 ):
310324 if len (path ) == 2 :
311325 face0 , face1 = path
326+
327+ # Ensure all cycles we use are disjoint.
328+ if face0 in faces_used or face1 in faces_used :
329+ continue
330+ else :
331+ faces_used .update (path )
332+
333+ # Identify where we need to change things.
312334 edges = G [face0 ][face1 ]
313- assert len (edges ) == 2
314335 cs0 = edges [0 ]['interface' ][face0 ]
315336 cs1 = edges [1 ]['interface' ][face0 ]
316337
@@ -325,6 +346,49 @@ def deconnect_sum(link):
325346 return link .split_link_diagram (destroy_original = True )
326347
327348
349+ def deconnect_sum (link ):
350+ """
351+ Warning: Destroys the original link.
352+
353+ >>> L = Link('K5a1')
354+ >>> L = L.connected_sum(Link('K6a2'))
355+ >>> L = L.connected_sum(Link('K6a3'))
356+ >>> L = L.connected_sum(Link('K7a1'))
357+ >>> len(L)
358+ 24
359+ >>> sorted(len(P) for P in deconnect_sum(L))
360+ [5, 6, 6, 7]
361+
362+ Here's 3 trefoils:
363+ >>> K = Link('DT: iaibiahcgefd.001010111')
364+ >>> sorted(len(P) for P in deconnect_sum(K))
365+ [3, 3, 3]
366+
367+ """
368+
369+ # A diagrammatic connected sum corresponds to a path in the dual
370+ # graph of length 2. The tricky case is when there are several
371+ # such paths, as they may overlap or even cross. We deal with
372+ # this by doing several rounds of cutting along families of
373+ # disjoint paths.
374+
375+ active = [link ]
376+ finished = []
377+
378+ while active :
379+ work_remains = []
380+ for A in active :
381+ pieces = disjoint_deconnect_sum_once (A )
382+ if len (pieces ) == 1 :
383+ finished += pieces
384+ else :
385+ work_remains += pieces
386+
387+ active = work_remains
388+
389+ return finished
390+
391+
328392def dual_edges (overstrand , graph ):
329393 """
330394 Find the set of crossings and edges of the dual graph encountered
0 commit comments