Skip to content

Commit f234157

Browse files
verify_ribbon_to_unknot: increase robustness
1 parent 1d50cf0 commit f234157

File tree

2 files changed

+58
-7
lines changed

2 files changed

+58
-7
lines changed

spherogram_src/links/bands/merge_links.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ def are_isometric_as_links(A, B):
3333
return False
3434

3535

36+
def are_same_triangulations_and_links(A, B):
37+
if hasattr(A, 'exterior'):
38+
A = A.exterior(with_hyperbolic_structure=False)
39+
40+
if hasattr(B, 'exterior'):
41+
B = B.exterior(with_hyperbolic_structure=False)
42+
43+
isos = A.isomorphisms_to(B)
44+
return any(iso.extends_to_link() for iso in isos)
45+
46+
3647
def link_isotopy_classes(links_with_manifolds):
3748
"""
3849
Given a collection of links, try to select one from each isotopy

spherogram_src/links/bands/search.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from ..links import Link
2-
from .merge_links import link_isotopy_classes, are_isometric_as_links
2+
from .merge_links import (link_isotopy_classes,
3+
are_isometric_as_links,
4+
are_same_triangulations_and_links)
35
from .core import Band, add_one_band, banded_links, normalize_crossing_labels
46

57

@@ -81,6 +83,33 @@ def remove_reidemeister_I(link):
8183
link._build_components(component_starts)
8284
return success
8385

86+
def are_same_link(L0, L1, tries=10):
87+
"""
88+
Try to determine whether the given links are isotopic *or* one is
89+
isotopic to the mirror of the other.
90+
91+
If it returns True, then the links are definitely equivalent. If
92+
it returns False, then they may still be the same.
93+
94+
When both links are hyperbolic, this is function is robust.
95+
Otherwise, whether it succeeds is pretty stocastic.
96+
"""
97+
L0, L1 = L0.copy(), L1.copy()
98+
for i in range(tries):
99+
if (L0.PD_code() == L1.PD_code() or
100+
are_isometric_as_links(L0, L1) or
101+
are_same_triangulations_and_links(L0, L1)):
102+
return True
103+
104+
L0.backtrack(30)
105+
L0.simplify()
106+
L0.simplify('global')
107+
L1.backtrack(30)
108+
L1.simplify()
109+
L1.simplify('global')
110+
111+
return False
112+
84113

85114
def verify_ribbon_to_unknot(link, certificate):
86115
"""
@@ -92,22 +121,29 @@ def verify_ribbon_to_unknot(link, certificate):
92121
>>> verify_ribbon_to_unknot(L, cert) #doctest: +SNAPPY
93122
True
94123
95-
TODO: Doesn't work when some intermediate link is non-hyperbolic,
96-
in this case a connected sum of two trefoils. The below should
97-
return True
124+
TODO: Sometimes doesn't work when some intermediate link is
125+
non-hyperbolic. in this case a connected sum of two trefoils.
126+
The below should return True but might fail occasionally.
98127
99128
>>> L = Link([(0,28,1,27),(10,1,11,2),(2,11,3,12),(36,3,37,4),(19,5,20,4),(5,23,6,22),(15,6,16,7),(34,8,35,7),(8,25,9,26),(26,9,27,10),(12,36,13,35),(13,20,14,21),(21,14,22,15),(23,17,24,16),(17,31,18,30),(31,19,32,18),(24,33,25,34),(28,0,29,37),(29,33,30,32)])
100129
>>> cert = [[(0,28,1,27),(10,1,11,2),(2,11,3,12),(36,3,37,4),(19,5,20,4),(5,23,6,22),(15,6,16,7),(34,8,35,7),(8,25,9,26),(26,9,27,10),(12,36,13,35),(13,20,14,21),(21,14,22,15),(23,17,24,16),(17,31,18,30),(31,19,32,18),(24,33,25,34),(28,0,29,37),(29,33,30,32)],'483d_0_0',[(5,2,6,3),(3,6,4,7),(1,4,2,5),(7,11,8,10),(11,9,0,8),(9,1,10,0)],'1603_0_1','unknot']
101130
>>> verify_ribbon_to_unknot(L, cert) #doctest: +SNAPPY
102-
False
131+
True
103132
"""
104-
assert certificate[-1] == 'unknot'
133+
import snappy
134+
if certificate[-1] != 'unknot':
135+
try:
136+
snappy.RibbonLinks[certificate[-1]]
137+
except KeyError:
138+
raise ValueError('ribbon_cert does not end with known ribbon link')
139+
105140
L = link.copy()
106141
E = L.exterior()
107142
for i in range(0, len(certificate) - 1, 2):
108143
L_cert = Link(certificate[i])
109144
E_cert = L_cert.exterior()
110-
if not (L.PD_code() == L_cert.PD_code() or are_isometric_as_links(E, E_cert)):
145+
146+
if not are_same_link(L, L_cert):
111147
return False
112148

113149
band = Band(certificate[i + 1])
@@ -123,6 +159,10 @@ def verify_ribbon_to_unknot(link, certificate):
123159
L.unlinked_unknot_components = 0
124160
E = L.exterior()
125161

162+
if certificate[-1] != 'unknot':
163+
E_cert = snappy.RibbonLinks[certificate[-1]]
164+
return are_isometric_as_links(E, E_cert)
165+
126166
return len(L.link_components) == 0 or is_unlink_exterior(E)
127167

128168

0 commit comments

Comments
 (0)