initial commit

main
commit 79ed111299

@ -0,0 +1,4 @@
# Implementation of the Kauffman Polynomial in SageMath
Report written in Typst for the _Computational Laboratory_ project at the
University of Pisa.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.9 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 123 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 317 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 330 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 302 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 300 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 155 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 225 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 188 KiB

@ -0,0 +1,397 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="296.22858pt"
height="345.60001pt"
viewBox="0 0 296.22858 345.6"
version="1.1"
id="svg40"
sodipodi:docname="sage-monster-unknot.svg"
inkscape:version="1.4.1 (93de688d07, 2025-03-30)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview40"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="pt"
inkscape:zoom="1.4192708"
inkscape:cx="191.64771"
inkscape:cy="201.51193"
inkscape:window-width="1600"
inkscape:window-height="863"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg40" />
<metadata
id="metadata1">
<rdf:RDF>
<cc:Work>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:date>2025-04-01T14:14:17.503929</dc:date>
<dc:format>image/svg+xml</dc:format>
<dc:creator>
<cc:Agent>
<dc:title>Matplotlib v3.8.0, https://matplotlib.org/</dc:title>
</cc:Agent>
</dc:creator>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1">
<style
type="text/css"
id="style1">*{stroke-linejoin: round; stroke-linecap: butt}</style>
</defs>
<g
id="patch_1"
transform="translate(-82.285714)">
<path
d="M 0,345.6 H 460.8 V 0 H 0 Z"
style="fill:none"
id="path1" />
</g>
<g
id="axes_1"
transform="translate(-82.285714)">
<g
id="patch_2">
<path
d="M 82.285714,345.6 H 378.51429 V 0 H 82.285714 Z"
style="fill:none"
id="path2" />
</g>
<g
id="matplotlib.axis_1" />
<g
id="matplotlib.axis_2" />
<g
id="line2d_1">
<path
d="m 235.14725,101.59121 h 42.72528"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path3" />
</g>
<g
id="line2d_2">
<path
d="M 230.4,101.59121 V 58.865934"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path4" />
</g>
<g
id="patch_3">
<path
d="m 225.65275,101.59121 q -42.72528,0 -42.72528,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path5" />
</g>
<g
id="line2d_3">
<path
d="m 182.92747,149.06374 v 47.47252"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path6" />
</g>
<g
id="patch_4">
<path
d="m 230.4,101.59121 q 0,47.47253 42.72527,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path7" />
</g>
<g
id="line2d_4">
<path
d="m 273.12527,149.06374 v 0"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path8" />
</g>
<g
id="line2d_5">
<path
d="m 277.87253,106.33846 v 42.72528"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path9" />
</g>
<g
id="patch_5">
<path
d="m 277.87253,101.59121 c 47.47252,0 47.47252,47.47253 4.74725,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path10" />
</g>
<g
id="line2d_6">
<path
d="m 282.61978,149.06374 v 0"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path11" />
</g>
<g
id="patch_6">
<path
d="m 277.87253,96.843956 q 0,-42.725275 -47.47253,-42.725275"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path12" />
</g>
<g
id="line2d_7">
<path
d="m 230.4,54.118681 v 0"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path13" />
</g>
<g
id="patch_7">
<path
d="m 230.4,49.371429 q 0,-42.725275 47.47253,-42.725275"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path14" />
</g>
<g
id="line2d_8">
<path
d="m 277.87253,6.646154 h 47.47252"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path15" />
</g>
<g
id="patch_8">
<path
d="m 325.34505,6.646154 q 47.47253,0 47.47253,47.472527"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path16" />
</g>
<g
id="line2d_9">
<path
d="M 372.81758,54.118681 V 149.06374"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path17" />
</g>
<g
id="patch_9">
<path
d="m 372.81758,149.06374 q 0,47.47252 -47.47253,47.47252"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path18" />
</g>
<g
id="line2d_10">
<path
d="M 325.34505,196.53626 H 282.61978"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path19" />
</g>
<g
id="line2d_11">
<path
d="M 230.4,54.118681 H 135.45494"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path20" />
</g>
<g
id="patch_10">
<path
d="m 135.45494,54.118681 q -47.472522,0 -47.472522,47.472529"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path21" />
</g>
<g
id="line2d_12">
<path
d="M 87.982418,101.59121 V 244.00879"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path22" />
</g>
<g
id="patch_11">
<path
d="m 87.982418,244.00879 q 0,47.47253 47.472522,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path23" />
</g>
<g
id="line2d_13">
<path
d="m 135.45494,291.48132 h 42.72528"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path24" />
</g>
<g
id="patch_12">
<path
d="m 178.18022,196.53626 c -42.72528,0 -42.72528,47.47253 0,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path25" />
</g>
<g
id="line2d_14">
<path
d="m 178.18022,244.00879 h 4.74725"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path26" />
</g>
<g
id="line2d_15">
<path
d="m 182.92747,196.53626 v 42.72528"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path27" />
</g>
<g
id="line2d_16">
<path
d="m 187.67472,196.53626 h 85.45055"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path28" />
</g>
<g
id="line2d_17">
<path
d="m 277.87253,149.06374 v 47.47252"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path29" />
</g>
<g
id="line2d_18">
<path
d="m 277.87253,196.53626 v 47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path30" />
</g>
<g
id="patch_13">
<path
d="m 182.92747,291.48132 q 0,47.47253 47.47253,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path31" />
</g>
<g
id="line2d_19">
<path
d="m 230.4,338.95385 v 0"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path32" />
</g>
<g
id="patch_14">
<path
d="m 230.4,338.95385 q 47.47253,0 47.47253,-42.72528"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path33" />
</g>
<g
id="line2d_20">
<path
d="m 277.87253,296.22857 v 0"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path34" />
</g>
<g
id="line2d_21">
<path
d="m 187.67472,291.48132 h 90.19781"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path35" />
</g>
<g
id="line2d_22">
<path
d="M 182.92747,291.48132 V 248.75604"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path36" />
</g>
<g
id="line2d_23">
<path
d="m 182.92747,244.00879 h 90.1978"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path37" />
</g>
<g
id="patch_15">
<path
d="m 282.61978,244.00879 c 42.72527,0 42.72527,47.47253 0,47.47253"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linejoin:miter"
id="path38" />
</g>
<g
id="line2d_24">
<path
d="m 282.61978,291.48132 h -4.74725"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path39" />
</g>
<g
id="line2d_25">
<path
d="m 277.87253,244.00879 v 42.72528"
clip-path="url(#pca122556d6)"
style="fill:none;stroke:#0000ff;stroke-linecap:square"
id="path40" />
</g>
</g>
<defs
id="defs40">
<clipPath
id="pca122556d6">
<rect
x="82.285713"
y="0"
width="296.22858"
height="345.60001"
id="rect40" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

@ -0,0 +1,365 @@
#import "theme.typ": ams-article, definition, theorem, proposition, proof, todo
#import "@preview/algorithmic:0.1.0"
#import algorithmic: algorithm
#import "@preview/cetz:0.3.4"
#let kL = $L$
#let draw-strand = (polyline) => {
import cetz.draw: *
set-style(stroke: (paint: white, thickness: 5pt, cap: "butt"))
polyline
set-style(stroke: (paint: black, thickness: 0.75pt, cap: "round"))
polyline
}
#let skein-canvas = body => cetz.canvas(
length: 0.25cm,
padding: 0.25,
{
import cetz.draw: *
rect((-1, -1), (1, 1), fill: white, stroke: none)
body
}
)
#let skein = (
unit: skein-canvas({
import cetz.draw: *
circle((0, 0), radius: 1, stroke: (paint: black, thickness: 0.75pt))
}),
// over: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// draw-strand({ line((-1, -1), (1, 1)) })
// draw-strand({ line((-1, 1), (1, -1)) })
// }
// ),
// under: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// draw-strand({ line((-1, 1), (1, -1)) })
// draw-strand({ line((-1, -1), (1, 1)) })
// }
// ),
// h: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// draw-strand({ hobby((-1, -1), (0, -0.61), (1, -1), omega: 1) })
// draw-strand({ hobby((-1, 1), (0, +0.61), (1, 1), omega: 1) })
// }
// ),
// v: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// draw-strand({ hobby((-1, -1), (-0.61, 0), (-1, 1), omega: 1) })
// draw-strand({ hobby((1, -1), (+0.61, 0), (1, 1), omega: 1) })
// }
// ),
// strand: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// rect((-1, -1), (1, 1), fill: white, stroke: none)
// draw-strand({ hobby((-1, 0), (0, 0.25), (1, 0), omega: 1) })
// }
// ),
// over-twist: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// draw-strand({ hobby((1.5, +1), (1, +1), (-0.5, 0), (-0.1, -1), (0, -1)) })
// draw-strand({ hobby((-1.5, +1), (-1, +1), (0.5, 0), (0.1, -1), (0, -1)) })
// }
// ),
// under-twist: cetz.canvas(
// length: 0.25cm,
// padding: 0.25,
// {
// import cetz.draw: *
// draw-strand({ hobby((-1.5, +1), (-1, +1), (0.5, 0), (0.1, -1), (0, -1)) })
// draw-strand({ hobby((1.5, +1), (1, +1), (-0.5, 0), (-0.1, -1), (0, -1)) })
// }
// )
over: skein-canvas({
import cetz.draw: *
draw-strand({ line((-1, -1), (1, 1)) })
draw-strand({ line((-1, 1), (1, -1)) })
}),
under: skein-canvas({
import cetz.draw: *
draw-strand({ line((-1, 1), (1, -1)) })
draw-strand({ line((-1, -1), (1, 1)) })
}),
h: skein-canvas({
import cetz.draw: *
draw-strand({ hobby((-1, -1), (0, -0.61), (1, -1), omega: 1) })
draw-strand({ hobby((-1, 1), (0, +0.61), (1, 1), omega: 1) })
}),
v: skein-canvas({
import cetz.draw: *
draw-strand({ hobby((-1, -1), (-0.61, 0), (-1, 1), omega: 1) })
draw-strand({ hobby((1, -1), (+0.61, 0), (1, 1), omega: 1) })
}),
strand: skein-canvas({
import cetz.draw: *
rect((-1, -1), (1, 1), fill: white, stroke: none)
draw-strand({ hobby((-1, 0), (0, 0.25), (1, 0), omega: 1) })
}),
over-twist: skein-canvas({
import cetz.draw: *
draw-strand({ hobby((1.5, +1), (1, +1), (-0.5, 0), (-0.1, -1), (0, -1)) })
draw-strand({ hobby((-1.5, +1), (-1, +1), (0.5, 0), (0.1, -1), (0, -1)) })
}),
under-twist: skein-canvas({
import cetz.draw: *
draw-strand({ hobby((-1.5, +1), (-1, +1), (0.5, 0), (0.1, -1), (0, -1)) })
draw-strand({ hobby((1.5, +1), (1, +1), (-0.5, 0), (-0.1, -1), (0, -1)) })
})
)
#show: ams-article.with(
paper-size: "a4",
title: [Implementation of the Kauffman Polynomial in SageMath],
authors: (
(
name: "Antonio De Lucreziis",
organization: [Dipartimento di Matematica],
location: [Pisa, Italia],
email: "antonio.delucreziis@gmail.com",
url: "https://poisson.phc.dm.unipi.it/~delucreziis/"
),
),
abstract: [
In this project we implement the Kauffman polynomial in SageMath (Python).
]
)
#outline()
= Introduction
Actually we don't like Python so we will be using Rust and then write bindings for Python that can be used in SageMath.
== The Kauffman Polynomial
The Kauffman polynomial $kL$ is a two-variable polynomial invariant of unoriented knots and links in 3-dimensional space. It is defined using _Skein relations_, more precisely an implicit functional equation.
The defining axioms of the Kauffman polynomial are the following, given a link diagram $K$ we have $kL_K(a,z) in ZZ[a, a^(-1), z, z^(-1)]$ and:
1. If $K$ and $K'$ are two equivalent up to regular isotopy, then $kL_(K)(a,z) = kL_(K')(a,z)$.
2. We have the following identities:
- $kL(#skein.over) + kL(#skein.under) = z (kL(#skein.h) + kL(#skein.v))$
- $kL(#skein.unit) = 1$
- $kL(#skein.over-twist) = a kL(#skein.strand)$
- $kL(#skein.under-twist) = a^(-1) kL(#skein.strand)$
We will later be seeing that the Kauffman polynomial can be defined in a more explicit way, using a recursive definition that is the one we will be using to derive our algorithm.
== Computational Knot Theory
The first problem in computational knot theory is to find a good representation for knots and links. There are various common representations, such as:
- *Gauss codes*:
This is very simple to generate, we just need to label each crossing with a number and then write down the sequence of numbers in the order they appear by walking along the knot. This has the problem that it is not unique, for example it does not distinguish between the trefoil knot and its mirror image.
- *Signed Gauss codes*:
This is an improvement over the previous representation, on the second occurrence of a number we use a $+$ or $-$ sign to indicate the handedness of the crossing.
- *Planar diagram codes (PD codes)*, this is the one we will be using in this project:
The PD code for a link is generated by labelling each arc of the link with a number. Then we choose a starting point and walk along the link, when we pass at an over-crossing for the current strand we write down a $4$-uple of counter-clockwise numbers for the arc incident to the crossing.
There are also other codes like *Braid representations* and *DT (Dowker-Thistlethwaite) Codes* we will not be using in this project.
=== PD codes
Reference: #link("https://knotinfo.math.indiana.edu/descriptions/pd_notation.html")[PD notation article from KnotInfo]
The PD code for a link is generated by labelling each arc of the link with a number. Then we choose a starting point for each component and process each component in order.
For each component we walk along it from the starting point in the component direction.
#figure(
image("assets/pd-code-crossing-ordering.svg"),
)
When we pass at a crossing that is an over-crossing for the current strand we write down a $4$-uple of counter-clockwise numbers for the arc incident to the crossing starting from the _entering under-crossing_ arc.
*Algorithm*:
```
Input: An oriented link diagram.
Output: List<(Nat, Nat, Nat, Nat)>
- Choose an ordering for the components and starting point for each component
- Label each arc with a number
- For each component:
- Walk along it from the starting point in its orientation
- At each crossing, when at an over-crossing for the current strand
- Write down a 4-uple of counter-clockwise numbers for the arc incident to the crossing starting from the entering under-crossing arc
```
Let's see an example of how to construct the PD code for the following link diagram
#figure(
image("assets/pd-code-0.svg"),
)
First let's choose a starting point for each component and label accordingly the arcs of the link. We will use the following convention:
#figure(
image("assets/pd-code-labelling.svg"),
caption: [Oriented link with starting points and edge labels.],
)
Now we can start processing each component of the link by walking along it in its orientation and writing down the over-crossings we encounter.
#{
align(center,
grid(
columns: 2,
align: horizon,
column-gutter: 2em,
row-gutter: 1em,
image("assets/pd-code-crossing-1.svg"),
block[
#set align(left)
First link component \
First over-crossing \
$=>$ `(6,1,7,2)`
],
image("assets/pd-code-crossing-2.svg"),
block[
#set align(left)
First link component \
Second over-crossing \
$=>$ `(8,3,5,4)`
],
image("assets/pd-code-crossing-3.svg"),
block[
#set align(left)
Second link component \
First over-crossing \
$=>$ `(2,5,3,6)`
],
image("assets/pd-code-crossing-4.svg"),
block[
#set align(left)
Second link component \
Second over-crossing \
$=>$ `(4,7,1,8)`
],
)
)
}
Every directed crossing appears only once as an over-crossing so this algorithm terminates when all crossings have been visited. So the final PD code for this link is
#{
set align(center)
set text(size: 1.125em)
`[(6,1,7,2), (8,3,5,4), (2,5,3,6), (4,7,1,8)]`
}
=== Link reconstruction from a PD code
We briefly mention that reconstructing a link from a PD code is not trivial, for example the KnotTheory package in SageMath has a #link("https://doc.sagemath.org/html/en/reference/knots/sage/knots/link.html#sage.knots.link.Link.plot")[`Link.plot()`] that can be used as follows
#[
#set align(center)
```python
# The "monster" unknot
L = Link([[ 3, 1, 2, 4], [ 8, 9, 1, 7], [ 5, 6, 7, 3], [ 4, 18, 6, 5],
[17, 19, 8, 18], [ 9, 10, 11, 14], [10, 12, 13, 11], [12, 19, 15, 13],
[20, 16, 14, 15], [16, 20, 17, 2]])
L.plot()
```
#box(
fill: luma(93%),
radius: 0.5em,
inset: 1em,
image("assets/sage-monster-unknot.svg", width: 40%)
)
]
This internally uses a #link("https://github.com/sagemath/sage/blob/e0cf1e41d419feb9ddbc0e3c54823928a01587dc/src/sage/knots/link.py#L3639")[_mixed integer linear programming_ (MILP)] solver to generate a knot diagram from a PD code. Another library called #link("https://github.com/3-manifolds/Spherogram/blob/725086a1d8c5d1381ff6a70315047efd8e0dac3f/spherogram_src/links/orthogonal.py")[Spherogram uses _network flows_] to generate this visualization by computing the minimum number of left and right bends for an "orthogonal" presentation of the link.
More references:
- #link("https://www.sciencedirect.com/science/article/pii/S0096300305002778")[A better heuristic for area-compaction of orthogonal representations]
== Algorithm for computing the Kauffman Polynomial
#definition[
Let $K$ be an un-oriented link. We denote by $hat(K)(p)$ the *standard unknot* for $K$ where $p$ is a _directed starting point_. This is build by considering the planar shadow $U$ of $K$ and walking along $U$ starting from $p$ and making each crossing an over-crossing when passing on it the first time.
TODO: Disegnini
]
#definition[
Let's give a name to the following knot modifications for $K$ near a specific crossing $i$
#align(center,
grid(
columns: 4,
column-gutter: 2em,
row-gutter: 0.5em,
skein.over,
skein.under,
skein.h,
skein.v,
$K$,
$S_i K$,
$E_i K$,
$e_i K$,
)
)
]
Let now $K$ be an oriented link with $n$ components so $K = K_1 union ... union K_n$.
*Algorithm.* Here follows the algorithm that computes $kL_(K)(a,z)$.

@ -0,0 +1,329 @@
// Sizes used across the template.
#let script-size = 7.97224pt
#let footnote-size = 8.50012pt
#let small-size = 9.24994pt
#let normal-size = 10.00002pt
#let large-size = 11.74988pt
#let definition-counter = counter("definition")
#let theorem-counter = counter("theorem")
// This function gets your whole document as its `body` and formats
// it as an article in the style of the American Mathematical Society.
#let ams-article(
// The article's title.
title: [Paper title],
// An array of authors. For each author you can specify a name,
// department, organization, location, and email. Everything but
// but the name is optional.
authors: (),
// Your article's abstract. Can be omitted if you don't have one.
abstract: none,
// The article's paper size. Also affects the margins.
paper-size: "us-letter",
// The result of a call to the `bibliography` function or `none`.
bibliography: none,
// The document's content.
body,
) = {
// Formats the author's names in a list with commas and a
// final "and".
let names = authors.map(author => author.name)
let author-string = if authors.len() == 2 {
names.join(" and ")
} else {
names.join(", ", last: ", and ")
}
// Set document metadata.
set document(title: title, author: names)
// Set the body font. AMS uses the LaTeX font.
set text(size: normal-size, font: "New Computer Modern")
// set text(size: normal-size, font: "Fira Sans", weight: 400)
// show math.equation: set text(font: "Fira Math")
// set strong(delta: 100)
// Configure the page.
set page(
paper: paper-size,
// The margins depend on the paper size.
margin: (
top: 2.5cm,
left: 3.5cm,
right: 3.5cm,
bottom: 2.5cm,
),
// The page header should show the page number and list of
// authors, except on the first page. The page number is on
// the left for even pages and on the right for odd pages.
header-ascent: 18pt,
header: context {
let i = counter(page).get().first()
if i == 1 { return }
set text(size: script-size)
align(center)[
#upper(title)
]
},
// On the first page, the footer should contain the page number.
footer-descent: 6pt,
footer: context {
let i = counter(page).get().first()
align(center, text(size: script-size, [#i]))
}
)
// Configure headings.
set heading(numbering: "1.")
show heading: it => {
// Create the heading numbering.
let number = if it.numbering != none {
counter(heading).display(it.numbering)
h(7pt, weak: true)
}
// Level 1 headings are centered and smallcaps.
// The other ones are run-in.
set text(size: normal-size, weight: 400)
set par(first-line-indent: 0em)
if it.level == 1 {
// set align(center)
set text(size: 17pt)
smallcaps[
#v(1.5em, weak: true)
#number
#it.body
#v(normal-size, weak: true)
]
counter(figure.where(kind: "definition")).update(0)
counter(figure.where(kind: "theorem")).update(0)
} else {
if it.level == 2 {
set text(size: 12pt)
v(1.5em, weak: true)
number
smallcaps(it.body)
h(7pt, weak: true)
} else {
set text(size: 12pt)
v(1.5em, weak: true)
number
it.body
h(7pt, weak: true)
}
}
}
// Configure paragraph properties.
set par(spacing: 1.5em, leading: 1em, justify: true)
// Configure lists and links.
set list(spacing: 1.5em, indent: 0.5em, body-indent: 0.5em, marker: ([•]))
set enum(spacing: 1.5em, indent: 0.5em, body-indent: 0.5em, numbering: "i.1.a)")
show link: it => {
// Set the link color to blue.
let blue2 = color.mix((blue, 50%), (black, 50%))
// let blue2 = color.mix((blue, 10%), (white, 75%))
set text(blue2)
// Underline the link.
underline(offset: 1pt, stroke: blue2, it)
// box(fill: blue2, outset: (x: 2pt, y: 2pt), radius: 2pt, text(fill: navy, it))
}
// Configure equations.
show math.equation: set block(below: 8pt, above: 9pt)
show math.equation: set text(weight: 400)
show raw: set text(font: "JetBrains Mono")
show raw: it => box(
fill: luma(92%),
radius: 3pt,
outset: (x: 2pt, y: 3pt),
it
)
show raw.where(block: true): it => box(
fill: luma(92%),
radius: 4pt,
inset: 4pt,
it
)
// Configure citation and bibliography styles.
set std.bibliography(style: "springer-mathphys", title: [References])
set figure(gap: 17pt)
show figure: set block(above: 12.5pt, below: 15pt)
show figure: it => {
// Customize the figure's caption.
show figure.caption: caption => {
smallcaps(caption.supplement)
if caption.numbering != none {
[ ]
numbering(caption.numbering, ..caption.counter.at(it.location()))
}
[. ]
caption.body
}
// We want a bit of space around tables and images.
show selector.or(table, image): pad.with(x: 23pt)
// Display the figure's body and caption.
it
}
// Definitions
show figure.where(kind: "definition"): set align(start)
show figure.where(kind: "definition"): it => block(spacing: 11.5pt, {
strong({
it.supplement
if it.numbering != none {
[ ]
it.counter.display(it.numbering)
}
[.]
})
[ ]
it.body
})
// Definitions
show figure.where(kind: "theorem"): set align(start)
show figure.where(kind: "theorem"): it => block(spacing: 11.5pt, {
strong({
it.supplement
if it.numbering != none {
[ ]
it.counter.display(it.numbering)
}
[.]
})
[ ]
emph(it.body)
})
// Display the title and authors.
v(35pt, weak: true)
align(center, smallcaps({
text(size: 18pt, weight: 600, title)
v(25pt, weak: true)
// text(authors.map(author => link(author.url, author.name)).join(", "))
text(author-string)
}))
// Display the abstract
if abstract != none {
v(20pt, weak: true)
// set text(script-size)
show: pad.with(x: 35pt)
smallcaps[Abstract. ]
abstract
}
// Display the article's contents.
v(29pt, weak: true)
body
// Display the bibliography, if any is given.
if bibliography != none {
show std.bibliography: set text(footnote-size)
show std.bibliography: set block(above: 11pt)
show std.bibliography: pad.with(x: 0.5pt)
bibliography
}
// Display details about the authors at the end.
// v(12pt, weak: true)
// show: pad.with(x: 11.5pt)
// set par(first-line-indent: 0pt)
// set text(script-size)
// for author in authors {
// let keys = ("department", "organization", "location")
// let dept-str = keys
// .filter(key => key in author)
// .map(key => author.at(key))
// .join(", ")
// smallcaps(dept-str)
// linebreak()
// if "email" in author [
// _Email address:_ #link("mailto:" + author.email) \
// ]
// if "url" in author [
// _URL:_ #link(author.url)
// ]
// v(12pt, weak: true)
// }
}
#let definition(body, numbered: true) = figure(
body,
kind: "definition",
supplement: [Definition],
numbering: if numbered { n => [#n] }
)
#let theorem(body, numbered: true) = figure(
body,
kind: "theorem",
supplement: [Theorem],
numbering: if numbered { n => [#n] }
)
#let proposition(body, numbered: true) = figure(
body,
kind: "theorem",
supplement: [Proposition],
numbering: if numbered { n => [#n] }
)
#let todo(msg: "", body) = grid(
rows: 2,
box(stroke: orange, fill: orange, inset: 3pt)[
#set text(fill: white, font: "Noto Sans")
#if msg != "" [
`TODO:` #text(size: footnote-size, msg)
] else [
`TODO`
]
],
box(stroke: orange, inset: 5pt, body)
)
// And a function for a proof.
#let proof(body) = block(spacing: 11.5pt, {
emph[Proof.]
[ ]
body
h(1fr)
// Add a word-joiner so that the proof square and the last word before the
// 1fr spacing are kept together.
sym.wj
// Add a non-breaking space to ensure a minimum amount of space between the
// text and the proof square.
sym.space.nobreak
$square.stroked$
})
Loading…
Cancel
Save