diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index aae6f46d980..89fd66c6078 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -838,6 +838,8 @@ def _test_database(self, **options): 'fibered': ['Fibered', KnotInfoColumnTypes.OnlyKnots], 'unoriented': ['Unoriented', KnotInfoColumnTypes.OnlyLinks], 'symmetry_type': ['Symmetry Type', KnotInfoColumnTypes.OnlyKnots], + 'geometric_type': ['Geometric Type', KnotInfoColumnTypes.OnlyKnots], + 'cosmetic_crossing': ['Cosmetic Crossing', KnotInfoColumnTypes.OnlyKnots], 'width': ['Width', KnotInfoColumnTypes.OnlyKnots], 'arc_notation': ['Arc Notation', KnotInfoColumnTypes.OnlyLinks], 'dt_code': ['DT code', KnotInfoColumnTypes.OnlyLinks] @@ -1019,6 +1021,18 @@ def _test_database(self, **options): 'reversible', 'reversible' ], + dc.geometric_type: [ + '', + 'torus knot T(2,3)', + 'hyperbolic', + 'torus knot T(2,5)', + 'hyperbolic', + 'hyperbolic', + 'hyperbolic', + 'hyperbolic', + 'torus knot T(2,7)', + 'hyperbolic'], + dc.cosmetic_crossing: ['', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'], dc.homfly_polynomial: [ '', '(2*v^2-v^4)+v^2*z^2', diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 235ba1fddef..b0ff60eefa5 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -790,7 +790,7 @@ def braid_notation(self, original=False): return (1, ) braid_notation = eval_knotinfo(braid_notation) - if type(braid_notation) is list: + if type(braid_notation) in (list, tuple): # in some cases there are a pair of braid representations # in the database. If this is the case we select the # corresponding to the braid index. @@ -1183,6 +1183,23 @@ def is_amphicheiral(self, positive=False): return None + @cached_method + def is_hyperbolic(self): + r""" + Return whether ``self`` is hyperbolic. + + EXAMPLES:: + + sage: KnotInfo.K3_1.is_hyperbolic() + False + sage: KnotInfo.K5_2.is_hyperbolic() + True + """ + geometric_type = self[self.items.geometric_type] + if geometric_type == 'hyperbolic': + return True + return False + @cached_method def is_alternating(self): r""" @@ -1309,6 +1326,38 @@ def is_oriented(self): """ return not knotinfo_bool(self[self.items.unoriented]) + @cached_method + def cosmetic_crossing_conjecture_verified(self): + r""" + Return whether the Cosmetic Crossing Conjecture has been verified + for ``self``. + + From the KnotInfo `description page `__: + + A crossing change in a diagram of a knot ``K`` is called cosmetic if + the resulting diagram also represents ``K``. The cosmetic crossing + conjecture posits that for any knot ``K``, the only cosmetic crossing + changes are nugatory, i.e. there exists an embedded 2-sphere in + ``S3`` which intersects K only at the two points of the relevant + crossing. Conversely, it is not hard to see that any nugatory + crossing change is cosmetic. + + EXAMPLES:: + + sage: knots = [K for K in KnotInfo if K.is_knot() and K.crossing_number() < 10] + sage: all(K.cosmetic_crossing_conjecture_verified() for K in knots) + True + """ + cosmetic_crossing = self[self.items.cosmetic_crossing] + if self.crossing_number() == 0: + return True + if not cosmetic_crossing or cosmetic_crossing == 'Unknown': + return False + verified = not knotinfo_bool(cosmetic_crossing) + if not knotinfo_bool(cosmetic_crossing): + return True + raise AssertionError(f'{self} is a counterexample to the cosmetic crossing conjecture') + @cached_method def homfly_polynomial(self, var1='v', var2='z', original=False): r"""