Hi, My name is Hisham Bhatti. I'm an undergraduate student at the University of Washington participating in a Summer Math REU at Chico State. As part of the REU we were studying the intersection between a knot's Goeritz matrix and the associated graph's Laplacian. We wanted to use computation tools to experimentally test our ideas, but we noticed that there was no obvious way (using Sage and Snappy) to easily find the Tait graph for a given knot. We were going to develop an algorithm based on the extractable PD code of a link in an attempt to generate the checkerboard graph but realised that the white_graph() function in snappy gives us this already, it was just a matter of extracting the correct information from it. We modified the white_graph() function given in Snappy to see if the source code implicitly calculates the Tait graph, but we were not able to find a connection there (Neither of us are experts by any means, so please excuse us if we took the most naive approach and overlooked something that would have made this process easier):
def test_white_graph(self):
"""
Return the white graph of a non-split link projection.
This method generates a multigraph whose vertices correspond
to the faces of the diagram, with an edge joining two
vertices whenever the corresponding faces contain opposite
corners at some crossing. To avoid hashability issues, the
vertex corresponding to a face is the index of the face in the
list returned by Link.faces().
According to the conventions of "Gordon, C. McA. and
Litherland, R. A, 'On the signature of a link', Inventiones
math. 47, 23-69 (1978)", in a checkerboard coloring of a link
diagram the unbounded region is always the first white region.
Of course, the choice of which region is unbounded is
arbitrary; it is just a matter of which region on S^2 contains
the point at infinity. In this method an equivalent arbitrary
choice is made by just returning the second component of the
multigraph, as determined by Graph.connected_components().
(Empirically, the second component tends to be smaller than
the first.)
Note that this may produce a meaningless result in the case of
a split link diagram. Consequently if the diagram is split,
i.e if the multigraph has more than 2 components, a ValueError
is raised::
sage: K=Link('5_1')
sage: K.white_graph()
Subgraph of (): Multi-graph on 2 vertices
WARNING: While there is also a "black_graph" method, it need
not be the case that these two graphs are complementary in the
expected way.
"""
# Map corners (i.e. CrossingStrands) to faces.
face_of = {corner: n for n, face in enumerate(self.faces())
for corner in face}
# Create the edges, labeled with crossing and sign.
edges = []
for c in self.crossings:
edges.append((face_of[CrossingStrand(c, 0)],
face_of[CrossingStrand(c, 2)],
+1))
edges.append((face_of[CrossingStrand(c, 1)],
face_of[CrossingStrand(c, 3)],
-1))
# Build the graph.
G = graph.Graph(edges, multiedges=True)
components = G.connected_components()
if len(components) > 2:
raise ValueError('The link diagram is split.')
return G.subgraph(components[0]), G.subgraph(components[1])
And to test the graph we used the following code:
L = snappy.Link('9_42')
black, white = test_white_graph(L)
def decorate_and_plot_graph(g): plot = g.plot(layout = 'spring', dist = 0.15, iterations = 20, edge_labels=True) plot.show()
decorate_and_plot_graph(white) decorate_and_plot_graph(black)
Implementing this requires copying the source code (specifically CrossingStrand functionality) from snappy into our own jupyter notebook so that we could tweak the white_graph code without having it send to snappy source code on its own.