Skip to content

Commit 9096302

Browse files
author
Release Manager
committed
gh-40370: Interface for Regina (3-manifold topology and normal surface theory) <!-- ^ Please provide a concise and informative title. --> <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes #12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> <!-- v Why is this change required? What problem does it solve? --> <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes #12345". --> This PR is intended to resolve the old Trac ticket #17077 (now a GitHub issue). This branch is based on the branch of Trac ticket #31456, which addressed the implementation of the optional `SPKG`. In the latter ticket it was noted that the package is not compatible with 32-bit systems and is therefore considered *experimental* (see #31456 (comment)). According to #31456 (comment), this should now be resolved. However, I haven't verified this yet. Are there still CI runs for this? Is this still a policy? If this issue turns out to have resisted, I will change the type to *experimental*. This PR initiates the integration of [Regina](https://regina- normal.github.io/) via the Sage interface framework. Most of the basics should be included, but given Regina's broad functionality, this PR is still selective focusing on some applications of knot theory. However, future extensions should now be fairly straightforward. Explicitly it starts with the following specific conversions: * integers * rationals * rational univariate polynomials * integral uni- and bivariate Laurent polynomials * finitely presented groups * links (including fundamental group and Homfly polynomial integration and adding link simplification) ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - #12345: short description why this is a dependency --> <!-- - #34567: ... --> URL: #40370 Reported by: Sebastian Oehms Reviewer(s): Sebastian Oehms, Travis Scrimshaw
2 parents 59a67bb + 4baf0d6 commit 9096302

File tree

20 files changed

+1518
-35
lines changed

20 files changed

+1518
-35
lines changed

build/pkgs/regina/SPKG.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
regina: Low-dimensional topology: triangulations, knots, links, normal surfaces, angle structures
2+
=================================================================================================
3+
4+
Description
5+
-----------
6+
7+
Regina is a software package for 3-manifold and 4-manifold topologists, with a focus on triangulations, knots and links, normal surfaces, and angle structures.
8+
9+
For 3-manifolds, it includes high-level tasks such as 3-sphere recognition, connected sum decomposition and Hakenness testing, comes with a rich database of census manifolds, and incorporates the SnapPea kernel for working with hyperbolic manifolds. For 4-manifolds, it offers a range of combinatorial and algebraic tools, plus support for normal hypersurfaces. For knots and links, Regina can perform combinatorial manipulation, compute knot polynomials, and work with several import/export formats.
10+
11+
License
12+
-------
13+
14+
GPLv2+
15+
16+
Upstream Contact
17+
----------------
18+
19+
Regina: https://regina-normal.github.io/
20+
21+
We use the Python packaging from https://pypi.org/project/regina/
22+
(https://github.com/3-manifolds/regina_wheels)

build/pkgs/regina/dependencies

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
$(PYTHON) | $(PYTHON_TOOLCHAIN) numpy
2+
3+
----------
4+
All lines of this file are ignored except the first.

build/pkgs/regina/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
regina
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SAGE_SPKG_CONFIGURE([regina], [SAGE_PYTHON_PACKAGE_CHECK([regina])])

build/pkgs/regina/type

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
optional

src/doc/en/reference/interfaces/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ and testing to make sure nothing funny is going on).
100100
sage/interfaces/psage
101101
sage/interfaces/qepcad
102102
sage/interfaces/r
103+
sage/interfaces/regina
103104
sage/interfaces/rubik
104105
sage/interfaces/sage0
105106
sage/interfaces/scilab

src/sage/doctest/external.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ def external_features():
384384
yield from sage.features.ffmpeg.all_features()
385385
import sage.features.interfaces
386386
for feature in sage.features.interfaces.all_features():
387-
if feature.name != 'mathics':
387+
if feature.name not in ('mathics', 'regina'):
388388
yield feature
389389
from sage.features.mip_backends import CPLEX, Gurobi
390390
yield CPLEX()

src/sage/features/interfaces.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,40 @@ def __classcall__(cls):
108108
return InterfaceFeature.__classcall__(cls, 'mathics', 'sage.interfaces.mathics')
109109

110110

111+
class Regina(InterfaceFeature):
112+
r"""
113+
A :class:`~sage.features.Feature` describing whether :class:`sage.interfaces.regina.Regina`
114+
is present and functional.
115+
116+
EXAMPLES::
117+
118+
sage: from sage.features.interfaces import Regina
119+
sage: Regina().is_present() # not tested
120+
FeatureTestResult('regina', False)
121+
"""
122+
123+
@staticmethod
124+
def __classcall__(cls):
125+
r"""
126+
TESTS::
127+
128+
sage: from sage.features.interfaces import Regina
129+
sage: F = Regina()
130+
sage: F.module.hide()
131+
sage: regina(~7)
132+
Traceback (most recent call last):
133+
...
134+
FeatureNotPresentError: sage.interfaces.regina is not available.
135+
Feature `sage.interfaces.regina` is hidden.
136+
Use method `unhide` to make it available again.
137+
sage: F.module.unhide()
138+
"""
139+
from sage.features.join_feature import JoinFeature
140+
interface = 'sage.interfaces.regina'
141+
mod = JoinFeature(interface, (PythonModule('regina'), PythonModule(interface)))
142+
return InterfaceFeature.__classcall__(cls, 'regina', mod)
143+
144+
111145
# The following are provided by external software only (no SPKG)
112146

113147
class Magma(InterfaceFeature):
@@ -244,6 +278,7 @@ def all_features():
244278
Feature('maple'),
245279
Feature('macaulay2'),
246280
Feature('octave'),
281+
Feature('regina'),
247282
Feature('scilab')]
248283
"""
249284
return [Magma(),
@@ -253,4 +288,5 @@ def all_features():
253288
Maple(),
254289
Macaulay2(),
255290
Octave(),
291+
Regina(),
256292
Scilab()]

src/sage/groups/finitely_presented.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,22 @@ def _latex_(self):
858858
r = r+'\\rangle'
859859
return r
860860

861+
def _regina_(self, regina):
862+
r"""
863+
Return the string used to construct the object in Regina.
864+
865+
EXAMPLES::
866+
867+
sage: B = BraidGroup(3)
868+
sage: regina(B) # optional regina
869+
<regina.GroupPresentation: < a b | a b a b^-1 a^-1 b^-1 >>
870+
"""
871+
F = regina(self._free_group)
872+
new = F.__deepcopy__()
873+
for r in self.relations():
874+
new.addRelation(regina(r))
875+
return new
876+
861877
def free_group(self):
862878
"""
863879
Return the free group (without relations).

src/sage/groups/free_group.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,29 @@ def __reduce__(self):
291291
"""
292292
return (self.parent(), (self.Tietze(),))
293293

294+
def _regina_(self, regina):
295+
r"""
296+
Return the string used to construct the object in Regina.
297+
298+
EXAMPLES::
299+
300+
sage: F = FreeGroup(3)
301+
sage: f = F.an_element(); f
302+
x0*x1*x2
303+
sage: regina(f) # optional regina
304+
<regina.GroupExpression: g0 g1 g2>
305+
"""
306+
import string
307+
word = ''
308+
for i in self.Tietze():
309+
if i > 0:
310+
next_char = string.ascii_lowercase[i - 1]
311+
else:
312+
next_char = string.ascii_uppercase[-i - 1]
313+
word = '%s%s' % (word, next_char)
314+
res = regina.GroupExpression(word)
315+
return res
316+
294317
@cached_method
295318
def Tietze(self):
296319
"""
@@ -812,6 +835,18 @@ def _gap_init_(self):
812835
gen_str = ', '.join(gap_names)
813836
return 'FreeGroup(['+gen_str+'])'
814837

838+
def _regina_(self, regina):
839+
r"""
840+
Return this group as an object in Regina.
841+
842+
EXAMPLES::
843+
844+
sage: F = FreeGroup(3)
845+
sage: regina(F) # optional regina
846+
<regina.GroupPresentation: < a b c >>
847+
"""
848+
return regina.GroupPresentation(int(self.ngens()))
849+
815850
def _element_constructor_(self, *args, **kwds):
816851
"""
817852
TESTS::

0 commit comments

Comments
 (0)