|
216 | 216 | AUTHORS:
|
217 | 217 |
|
218 | 218 | - Sebastian Oehms August 2020: initial version
|
| 219 | +- Sebastian Oehms June 2022: add :meth:`conway_polynomial` and :meth:`khovanov_polynomial` (:trac:`33969`) |
219 | 220 |
|
220 | 221 | Thanks to Chuck Livingston and Allison Moore for their support. For further acknowledgments see the correspondig hompages.
|
221 | 222 | """
|
@@ -1620,6 +1621,161 @@ def alexander_polynomial(self, var='t', original=False, laurent_poly=False):
|
1620 | 1621 | exp = ap.exponents()
|
1621 | 1622 | return t ** ((-max(exp) - min(exp)) // 2) * ap
|
1622 | 1623 |
|
| 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)) |
1623 | 1779 |
|
1624 | 1780 | @cached_method
|
1625 | 1781 | def link(self, use_item=db.columns().pd_notation, snappy=False):
|
|
0 commit comments