Skip to content

Commit 2356379

Browse files
author
Release Manager
committedOct 11, 2022
Trac #33969: Implement missing KnotInfo wrappers for polynomial invariants
A couple of wrappers for link properties listed in the [https://knotinfo.math.indiana.edu/ KnotInfo] and [https://linkinfo.sitehost.iu.edu/ LinkInfo] databases have already been implemented in #30352. But since there are more than 120 of them there are still a lot missing. Here we add missing polynomial link invariants, explicitly the Conway and Khovanov polynomials. Furthermore we let Sage point to the current version of [https://pypi.org/project/database-knotinfo/ database_knotinfo]. URL: https://trac.sagemath.org/33969 Reported by: soehms Ticket author(s): Sebastian Oehms Reviewer(s): Matthias Koeppe
2 parents a9abd3b + b9b8743 commit 2356379

File tree

4 files changed

+219
-5
lines changed

4 files changed

+219
-5
lines changed
 

Diff for: ‎build/pkgs/database_knotinfo/checksums.ini

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
tarball=database_knotinfo-VERSION.tar.gz
2-
sha1=187e6b5ee2a935e3a50bc7648b181dfc7cb7bfa2
3-
md5=90822e09a1a84c8dbb84e20773c367f1
4-
cksum=1855405219
2+
sha1=16039d4e399efc78e4b1278527019f4bcdfdde13
3+
md5=3095993756f6b51d14c35adae5a75930
4+
cksum=2884062991
55
upstream_url=https://pypi.io/packages/source/d/database_knotinfo/database_knotinfo-VERSION.tar.gz

Diff for: ‎build/pkgs/database_knotinfo/package-version.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2021.10.1
1+
2022.7.1

Diff for: ‎src/sage/databases/knotinfo_db.py

+59-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class KnotInfoColumns(Enum):
7575
'PD Notation (vector)',
7676
'PD Notation (KnotTheory)',
7777
'Braid Notation',
78+
'Quasipositive Braid',
7879
'Multivariable Alexander Polynomial',
7980
'HOMFLYPT Polynomial',
8081
'Unoriented',
@@ -822,6 +823,8 @@ def _test_database(self, **options):
822823
'homfly_polynomial': ['HOMFLY', KnotInfoColumnTypes.OnlyKnots],
823824
'homflypt_polynomial': ['HOMFLYPT Polynomial', KnotInfoColumnTypes.OnlyLinks],
824825
'kauffman_polynomial': ['Kauffman', KnotInfoColumnTypes.KnotsAndLinks],
826+
'khovanov_polynomial': ['Khovanov', KnotInfoColumnTypes.KnotsAndLinks],
827+
'khovanov_torsion_polynomial': ['Khovanov Torsion', KnotInfoColumnTypes.OnlyKnots],
825828
'determinant': ['Determinant', KnotInfoColumnTypes.KnotsAndLinks],
826829
'positive': ['Positive', KnotInfoColumnTypes.OnlyKnots],
827830
'fibered': ['Fibered', KnotInfoColumnTypes.OnlyKnots],
@@ -1089,5 +1092,60 @@ def _test_database(self, **options):
10891092
'1-3*t+ 3*t^2-3*t^3+ t^4',
10901093
'1-3*t+ 5*t^2-3*t^3+ t^4',
10911094
'1-t+ t^2-t^3+ t^4-t^5+ t^6',
1092-
'3-5*t+ 3*t^2']
1095+
'3-5*t+ 3*t^2'],
1096+
dc.conway_polynomial: [
1097+
'1',
1098+
'1+z^2',
1099+
'1-z^2',
1100+
'1+3*z^2+z^4',
1101+
'1+2*z^2',
1102+
'1-2*z^2',
1103+
'1-z^2-z^4',
1104+
'1+z^2+z^4',
1105+
'1+6*z^2+5*z^4+z^6',
1106+
'1+3*z^2',
1107+
'-z',
1108+
'z',
1109+
'-2*z',
1110+
'2*z + z^3',
1111+
'z^3',
1112+
'z^3',
1113+
'-2*z + z^3',
1114+
'2*z + 2*z^3',
1115+
'-3*z-2*z^3',
1116+
'3*z + 2*z^3',
1117+
'-3*z-4*z^3-z^5'],
1118+
dc.khovanov_polynomial: [
1119+
'',
1120+
'q^(-9)t^(-3)+q^(-5)t^(-2)+q^(-3)+q^(-1)',
1121+
'q^(-5)t^(-2)+q^(-1)t^(-1)+q+q^(-1)+qt+q^5t^2',
1122+
'q^(-15)t^(-5)+q^(-11)t^(-4)+q^(-11)t^(-3)+q^(-7)t^(-2)+q^(-5)+q^(-3)',
1123+
'q^(-13)t^(-5)+q^(-9)t^(-4)+q^(-9)t^(-3)+(q^(-7)+q^(-5))t^(-2)+q^(-3)t^(-1)+q^(-3)+q^(-1)',
1124+
'q^(-9)t^(-4)+q^(-5)t^(-3)+q^(-5)t^(-2)+(q^(-3)+q^(-1))t^(-1)+2q+q^(-1)+qt+q^5t^2',
1125+
'q^(-11)t^(-4)+(q^(-9)+q^(-7))t^(-3)+(q^(-7)+q^(-5))t^(-2)+(q^(-5)+q^(-3))t^(-1)+q^(-3)+2q^(-1)+tq^(-1)+q^3t^2',
1126+
'q^(-7)t^(-3)+(q^(-5)+q^(-3))t^(-2)+(q^(-3)+q^(-1))t^(-1)+2q+2q^(-1)+t(q+q^3)+(q^3+q^5)t^2+q^7t^3',
1127+
'q^(-21)t^(-7)+q^(-17)t^(-6)+q^(-17)t^(-5)+q^(-13)t^(-4)+q^(-13)t^(-3)+q^(-9)t^(-2)+q^(-7)+q^(-5)',
1128+
'q^(-17)t^(-7)+q^(-13)t^(-6)+q^(-13)t^(-5)+(q^(-11)+q^(-9))t^(-4)+(q^(-9)+q^(-7))t^(-3)+(q^(-7)+q^(-5))t^(-2)+q^(-3)t^(-1)+q^(-3)+q^(-1)',
1129+
'1 + q^(-2) + 1/(q^6*t^2) + 1/(q^4*t^2)',
1130+
'1 + q^2 + q^4*t^2 + q^6*t^2',
1131+
'1 + q^(-2) + 1/(q^10*t^4) + 1/(q^8*t^4) + 1/(q^6*t^2) + 1/(q^2*t)',
1132+
'q^2 + q^4 + q^6*t^2 + q^10*t^3 + q^10*t^4 + q^12*t^4',
1133+
'2 + 2/q^2 + 1/(q^8*t^3) + 1/(q^6*t^2) + 1/(q^4*t^2) + 1/(q^2*t) + t + q^4*t^2',
1134+
'2 + 2/q^2 + 1/(q^8*t^3) + 1/(q^6*t^2) + 1/(q^4*t^2) + 1/(q^2*t) + t + q^4*t^2',
1135+
'1 + 2/q^2 + 1/(q^10*t^4) + 1/(q^8*t^4) + 1/(q^8*t^3) + 2/(q^6*t^2) + 1/(q^4*t^2) + 2/(q^2*t) + t + q^2*t + q^4*t^2',
1136+
'q^2 + q^4 + q^4*t + 2*q^6*t^2 + q^8*t^2 + 2*q^10*t^3 + 2*q^10*t^4 + q^12*t^4 + q^12*t^5 + q^14*t^5 + q^16*t^6',
1137+
'q^(-4) + q^(-2) + 1/(q^16*t^6) + 1/(q^14*t^6) + 1/(q^14*t^5) + 1/(q^12*t^4) + 1/(q^10*t^4) + 1/(q^10*t^3) + 1/(q^8*t^3) + 1/(q^8*t^2) + 1/(q^6*t^2) + 1/(q^4*t)',
1138+
'q^2 + q^4 + q^4*t + q^6*t^2 + q^8*t^2 + q^8*t^3 + q^10*t^3 + q^10*t^4 + q^12*t^4 + q^14*t^5 + q^14*t^6 + q^16*t^6',
1139+
'q^(-6) + q^(-4) + 1/(q^18*t^6) + 1/(q^16*t^6) + 1/(q^16*t^5) + 1/(q^12*t^4) + 1/(q^12*t^3) + 1/(q^8*t^2)'],
1140+
dc.khovanov_torsion_polynomial: [
1141+
'',
1142+
'Q^(-7)t^(-2)',
1143+
'Q^(-3)t^(-1)+Q^3t^2',
1144+
'Q^(-13)t^(-4)+Q^(-9)t^(-2)',
1145+
'Q^(-11)t^(-4)+Q^(-7)t^(-2)+Q^(-5)t^(-1)',
1146+
'Q^(-7)t^(-3)+Q^(-3)t^(-1)+Q^(-1)+Q^3t^2',
1147+
'Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)+Q^(-3)+Qt^2',
1148+
'Q^(-5)t^(-2)+Q^(-3)t^(-1)+Q^(-1)+Qt+Q^3t^2+Q^5t^3',
1149+
'Q^(-19)t^(-6)+Q^(-15)t^(-4)+Q^(-11)t^(-2)',
1150+
'Q^(-15)t^(-6)+Q^(-11)t^(-4)+Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)']
10931151
}

Diff for: ‎src/sage/knots/knotinfo.py

+156
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@
216216
AUTHORS:
217217
218218
- Sebastian Oehms August 2020: initial version
219+
- Sebastian Oehms June 2022: add :meth:`conway_polynomial` and :meth:`khovanov_polynomial` (:trac:`33969`)
219220
220221
Thanks to Chuck Livingston and Allison Moore for their support. For further acknowledgments see the correspondig hompages.
221222
"""
@@ -1620,6 +1621,161 @@ def alexander_polynomial(self, var='t', original=False, laurent_poly=False):
16201621
exp = ap.exponents()
16211622
return t ** ((-max(exp) - min(exp)) // 2) * ap
16221623

1624+
@cached_method
1625+
def conway_polynomial(self, var='t', original=False):
1626+
r"""
1627+
Return the Conway polynomial according to the value of column
1628+
``conway_polynomial`` for this knot or link as an instance of
1629+
:class:`~sage.rings.polynomial.polynomial_element.Polynomial`.
1630+
1631+
It is obtained from the Seifert matrix `V` of ``self`` by the following
1632+
formula (see the KnotInfo description web-page; to launch it see the
1633+
example below):
1634+
1635+
.. MATH::
1636+
1637+
\nabla(L) = \det(t^{\frac{1}{2}} V -t^{\frac{-1}{2}} V^t)
1638+
1639+
Here `V^t` stands for the transpose of `V`.
1640+
1641+
1642+
INPUT:
1643+
1644+
- ``var`` -- (default: ``'t'``) the variable
1645+
- ``original`` -- boolean (optional, default ``False``) if set to
1646+
``True`` the original table entry is returned as a string
1647+
1648+
OUTPUT:
1649+
1650+
A polynomial over the integers, more precisely an instance of
1651+
:class:`~sage.rings.polynomial.polynomial_element.Polynomial`.
1652+
If ``original`` is set to ``True`` then a string is returned.
1653+
1654+
EXAMPLES::
1655+
1656+
sage: from sage.knots.knotinfo import KnotInfo
1657+
sage: K = KnotInfo.K4_1
1658+
sage: Kc = K.conway_polynomial(); Kc
1659+
-t^2 + 1
1660+
sage: L = KnotInfo.L5a1_0
1661+
sage: Lc = L.conway_polynomial(); Lc
1662+
t^3
1663+
1664+
Comparision to Sage's results::
1665+
1666+
sage: Kc == K.link().conway_polynomial()
1667+
True
1668+
sage: Lc == L.link().conway_polynomial()
1669+
True
1670+
1671+
Launch the KnotInfo description web-page::
1672+
1673+
sage: K.items.conway_polynomial.description_webpage() # not tested
1674+
True
1675+
"""
1676+
conway_polynomial = self[self.items.conway_polynomial]
1677+
1678+
if original:
1679+
return conway_polynomial
1680+
1681+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
1682+
R = PolynomialRing(ZZ, var)
1683+
1684+
if not conway_polynomial and self.crossing_number() == 0:
1685+
return R.one()
1686+
1687+
t, = R.gens()
1688+
lc = {'z': t}
1689+
return R(eval_knotinfo(conway_polynomial, locals=lc))
1690+
1691+
@cached_method
1692+
def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False):
1693+
r"""
1694+
Return the Khovanov polynomial according to the value of column
1695+
``khovanov_polynomial`` for this knot or link as an instance of
1696+
:class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`.
1697+
1698+
INPUT:
1699+
1700+
- ``var1`` -- (default: ``'q'``) the first variable
1701+
- ``var2`` -- (default: ``'t'``) the second variable
1702+
- ``base_ring`` -- (default: ``ZZ``) the ring of the polynomial's
1703+
coefficients
1704+
- ``original`` -- boolean (optional, default ``False``) if set to
1705+
``True`` the original table entry is returned as a string
1706+
1707+
OUTPUT:
1708+
1709+
A Laurent polynomial over the integers, more precisely an instance of
1710+
:class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`.
1711+
If ``original`` is set to ``True`` then a string is returned.
1712+
1713+
.. NOTE ::
1714+
1715+
The Khovanov polynomial given in KnotInfo corresponds to the mirror
1716+
image of the given knot for a `list of 140 exceptions
1717+
<https://raw.githubusercontent.com/soehms/database_knotinfo/main/hints/list_of_mirrored_khovanov_polynonmial.txt>`__.
1718+
1719+
EXAMPLES::
1720+
1721+
sage: from sage.knots.knotinfo import KnotInfo
1722+
sage: K = KnotInfo.K6_3
1723+
sage: Kk = K.khovanov_polynomial(); Kk
1724+
q^7*t^3 + q^5*t^2 + q^3*t^2 + q^3*t + q*t + 2*q + 2*q^-1 + q^-1*t^-1
1725+
+ q^-3*t^-1 + q^-3*t^-2 + q^-5*t^-2 + q^-7*t^-3
1726+
sage: Kk2 = K.khovanov_polynomial(var1='p', base_ring=GF(2)); Kk2
1727+
p^7*t^3 + p^5*t^3 + p^5*t^2 + p^3*t + p^-1 + p^-1*t^-1 + p^-3*t^-2 + p^-7*t^-3
1728+
1729+
sage: L = KnotInfo.L5a1_0
1730+
sage: Lk = L.khovanov_polynomial(); Lk
1731+
q^4*t^2 + t + 2 + 2*q^-2 + q^-2*t^-1 + q^-4*t^-2 + q^-6*t^-2 + q^-8*t^-3
1732+
1733+
Comparision to Sage's results::
1734+
1735+
sage: Kk == K.link().khovanov_polynomial()
1736+
True
1737+
sage: Kk2 == K.link().khovanov_polynomial(var1='p', base_ring=GF(2))
1738+
True
1739+
sage: Lk == L.link().khovanov_polynomial()
1740+
True
1741+
"""
1742+
khovanov_polynomial = self[self.items.khovanov_polynomial]
1743+
1744+
if original:
1745+
return khovanov_polynomial
1746+
1747+
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
1748+
var_names = [var1, var2]
1749+
R = LaurentPolynomialRing(base_ring, var_names)
1750+
1751+
if not khovanov_polynomial and self.crossing_number() == 0:
1752+
return R({(1, 0): 1, (-1, 0): 1})
1753+
1754+
ch = base_ring.characteristic()
1755+
if ch == 2:
1756+
if not self.is_knot():
1757+
raise NotImplementedError('Khovanov polynomial available only for knots in characteristic 2')
1758+
khovanov_torsion_polynomial = self[self.items.khovanov_torsion_polynomial]
1759+
khovanov_torsion_polynomial = khovanov_torsion_polynomial.replace('Q', 'q')
1760+
khovanov_polynomial = '%s + %s' % (khovanov_polynomial, khovanov_torsion_polynomial)
1761+
1762+
if not khovanov_polynomial:
1763+
# given just for links with less than 12 crossings
1764+
raise NotImplementedError('Khovanov polynomial not available for this link')
1765+
1766+
from sage.repl.preparse import implicit_mul
1767+
# since implicit_mul does not know about the choice of variable names
1768+
# we have to insert * between them separately
1769+
for i in ['q', 't',')']:
1770+
for j in ['q', 't', '(']:
1771+
khovanov_polynomial = khovanov_polynomial.replace('%s%s' % (i, j), '%s*%s' % (i, j))
1772+
khovanov_polynomial = implicit_mul(khovanov_polynomial)
1773+
gens = R.gens_dict()
1774+
lc = {}
1775+
lc['q'] = gens[var1]
1776+
lc['t'] = gens[var2]
1777+
1778+
return R(eval_knotinfo(khovanov_polynomial, locals=lc))
16231779

16241780
@cached_method
16251781
def link(self, use_item=db.columns().pd_notation, snappy=False):

0 commit comments

Comments
 (0)
Please sign in to comment.