I recently found myself needing to know some things about knots – calculating fundamental groups and polynomial invariants, specifically. Going to the sources (Fox’s 1962 classic “A Quick Trip Through Knot Theory” is really great mathematical reading) reveals there is a pretty straightforward algorithm for doing these kinds of things, but it seems like I’m going to have to work out a lot of them. So I thought “oh, maybe it’s easy to do this in SageMath?”

Well, it totally is, so I’m going to just show a few examples. Most of what I’m going to show can easily be found on the Sage help pages for links, but I’ll focus on specifically what I am interested in. Since I’m also a beginner at Sage, this will be a very basic tutorial.

First, we should make sure we can use the tools on Sage to reproduce known results, so I’ll do that with the most popular non-trivial knot, the trefoil (it also happens the trefoil is a (2,3) torus knot, and I’m going to be interested in torus knots in general). I’ve tested the following both on my local installation of Sage and on the live SageMathCell.

First, we need to tell Sage which knot we are interested in by giving it the linking of the arcs of the knot. Each arc needs a number, and we need an orientation. The figure on the right shows my picture for the trefoil. Notice that the definition of “arc” is “between two crossings”, so although in this particular projection the arc 3 and 5 are “the same line”, in the link representation they are represented differently. There are three crossings, so the way you tell Sage which knot you want to know about is by specifying these three crossings as a list of the arcs, starting with the undercrossing on, going clockwise. This is done in the following manner:

L=Link([[2,6,5,1],[6,3,4,5],[3,2,1,4]])

So first (and maybe most impressively), you can get a nice plot of your knot:

L.plot()

It’s easy to verify this is the same knot that I drew above, although the orientation is not specified. We can also find the fundamental group,

L.fundamental_group()
Finitely presented group < x0, x1, x2 | x1*x0^-1*x2^-1*x0,x0*x2^-1*x1^-1*x2, x2*x1^-1*x0^-1*x1 >

Which we can simplify to the traditional representation by storing it as a group first:

G=L.fundamental_group()
G.simplified()
Finitely presented group < x0, x1 | x1*x0^-1*x1^-1*x0^-1*x1*x0 >

And, finally, we can easily find both the Alexander polynomial and the Jones polynomial:

L.alexander_polynomial()
t^-1 - 1 + t
L.jones_polynomial()
1/t + 1/t^3 - 1/t^4

So although working through the Fox derivatives is kinda fun, this is clearly easier!

So the problem I’m actually interested in is the following: given a covering space , branched over a knot , what is the preimage of the knot ? It turns out that there are some nice results in this area, but mostly dealing with the branched cover rather than with the knot . For instance, if you pick carefully (the Borromean Rings, for example), you can construct any closed 3-manifold as such a branched covering. The problem is, there aren’t many results on what the preimage of the knot actually is. What we do have is an algorithm for a presentation of the fundamental group (presented by Fox in that earlier article as a variation of the Reidemiser-Schurr algorithm). Basically, given a knot and a representation of the group of the knot on a symmetric group , we can determine the representation of the group in the cover. So that doesn’t directly tell us the knot itself, but at least we can use a presentation of the fundamental group to calculate the knot invariants and maybe learn something about the knot in that manner.

The problem with trying to do exactly what we did above is Sage doesn’t know how to find the Alexander polynomial directly from a group presentation. However, it does know how to find the Alexander matrix, so as long as we are careful with polynomial rings we can use this to find the Alexander polynomials.

What I’m going to do is an example from Fox. This is actually example 1 in his article, which is the knot shown below. I’ve added orientations which correspond to the later calculations.

To find the group presentation, we take the generators specified in the picture and define some relations, which are rather like the link relations we used above. Around each crossing, going under the first undercrossing is the same as going under the other three crossings, taking orientations into account. For instance, you can read the first one off the figure,

What we need to do is figure out how to implement these relations in Sage to reproduce the same fundamental group.

The first step will be to define a free group on the generators; in Sage this is easy:

H=FreeGroup(4)

Next we need to create our finitely presented group by taking the quotient of this free group with our relations. In Sage, each relation can be specified by first ordering the generators (1-4 in this case), and then specifying words by sequences of integers, where each integer represents a generator. The sign of the integer indicates the power to which the generator is raised. For instance, the word would be [1,2,-3,1] and the word would be [1,1,1]. Doing this for the knot above gives us

G=H/(H([4,1,-4,3,4,-1,-4,1,-2,-1]),H([1,2,-1,4,1,-2,-1,2,-3,-2]),H([2,3,-2,1,2,-3,-2,3,-4,-3]),H([3,4,-3,2,3,-4,-3,4,-1,-4]))

(Pay careful attention to the parenthiesis and brackets – Sage interprets them differently, and it matters if you have a series of relators as the case is here, or a single relator. For a single relator, the synthax is

G=H/[H([....])]

.)

So the next step is to find the Alexander matrix, which Sage knows how to do. But, we want to first specify the ring over which we want to defined the matrix. We really should use Laurent Polynomials, since that’s how the Alexander matrix is defined, but the last step (taking determinants) is not implemented in Sage for Laurent Polynomails, so the trick here is to use Polynomials over an integer ring:

R.<t>=PolynomialRing(ZZ)

With that done, we can find the Alexander matrix under the Abelianizing map, which sends each generator to a single generator (which I defined above):

M=G.alexander_matrix([t,t,t,t]);M
[-t^2 + 2*t - 1 -t t t^2 - 2*t + 1]
[ t^2 - 2*t + 1 -t^2 + 2*t - 1 -t t]
[ t t^2 - 2*t + 1 -t^2 + 2*t - 1 -t]
[ -t t t^2 - 2*t + 1 -t^2 + 2*t - 1]

(You can also just call this with empty parenthesis () and get the Alexander Matrix before the Abelianization).

Finally, we need to find the generator of the first elementary ideal of this matrix, which is the Alexander polynomial. I grabbed this code from someone smarter than me (a mathematician by the name of Nathan Dunfield):

alex_poly = gcd(M.minors(G.ngens() - 1))

There’s obviously nothing too magic about this line, I just wasn’t aware Sage knew about finding the GCD of polynomials. Anyway, we can check to make sure our answer is correct (that is, matches Fox’s original answer)

print alex_poly
t^6 - 5*t^5 + 10*t^4 - 13*t^3 + 10*t^2 - 5*t + 1

And it does!

So of course, I haven’t talked at all about the physics of these preimages of knots . This is related to a talk I gave at a recent conference The First Minkowski Meeting on the Foundations of Spacetime Physics, so I’ll post something on that as I work on the paper for the conference proceedings.