Interface to Regina

Regina is an open source software for low-dimensional topology. From the home-page:

Note

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.

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.

The Regina interface will only work if the optional Sage package Regina is installed. The interface lets you send certain Sage objects to Regina, run Regina functions, import certain Regina expressions to Sage, or any combination of the above.

To send a Sage object sobj to Regina, call regina(sobj). This exports the Sage object to Regina and returns a new Sage object wrapping the Regina expression/variable, so that you can use the Regina variable from within Sage. You can then call Regina functions on the new object; for example:

sage: F3 = FreeGroup(3)
sage: F3r = regina(F3); F3r
<regina.GroupPresentation: < a b c >>
sage: (F3r.parent(), type(F3r))
(Regina, <class 'sage.interfaces.regina.ReginaElement'>)
sage: f = F3.an_element(); f
x0*x1*x2
sage: fr = regina(f); fr
<regina.GroupExpression: g0 g1 g2>
sage: rel = fr^2; rel
<regina.GroupExpression: g0 g1 g2 g0 g1 g2>
sage: (type(fr), type(rel))
(<class 'sage.interfaces.regina.ReginaElement'>,
 <class 'sage.interfaces.regina.ReginaElement'>)
sage: F3r.addRelation(rel); F3r
<regina.GroupPresentation: < a b c | a b c a b c >>
>>> from sage.all import *
>>> F3 = FreeGroup(Integer(3))
>>> F3r = regina(F3); F3r
<regina.GroupPresentation: < a b c >>
>>> (F3r.parent(), type(F3r))
(Regina, <class 'sage.interfaces.regina.ReginaElement'>)
>>> f = F3.an_element(); f
x0*x1*x2
>>> fr = regina(f); fr
<regina.GroupExpression: g0 g1 g2>
>>> rel = fr**Integer(2); rel
<regina.GroupExpression: g0 g1 g2 g0 g1 g2>
>>> (type(fr), type(rel))
(<class 'sage.interfaces.regina.ReginaElement'>,
 <class 'sage.interfaces.regina.ReginaElement'>)
>>> F3r.addRelation(rel); F3r
<regina.GroupPresentation: < a b c | a b c a b c >>

In the above example the relations are added using Regina’s addRelations method.

To see Regina’s output you can simply print the Regina wrapper object. However if you want to import Regina’s output back to Sage, call the Regina wrapper object’s sage() method. This method returns a native Sage object:

sage: G3 = F3r.sage(); G3
Finitely presented group < x0, x1, x2 | (x0*x1*x2)^2 >
sage: type(G3)
<class 'sage.groups.finitely_presented.FinitelyPresentedGroup_with_category'>
sage: regina(G3) == F3r
True
sage: fr.sage() == f
True
sage: rel.sage() == f^2
True
[Python]
>>> from sage.all import *
>>> G3 = F3r.sage(); G3
Finitely presented group < x0, x1, x2 | (x0*x1*x2)^2 >
>>> type(G3)
<class 'sage.groups.finitely_presented.FinitelyPresentedGroup_with_category'>
>>> regina(G3) == F3r
True
>>> fr.sage() == f
True
>>> rel.sage() == f**Integer(2)
True

If you want to run a Regina function and don’t already have the input in the form of a Sage object, then it might be simpler to input a string expr to regina(expr). This string will be evaluated as if you had typed it into Regina:

sage: rL = regina("Link('dabcabcv-')"); rL
<regina.Link: 3-crossing knot: +++ ( ^0 _1 ^2 _0 ^1 _2 )>
>>> from sage.all import *
>>> rL = regina("Link('dabcabcv-')"); rL
<regina.Link: 3-crossing knot: +++ ( ^0 _1 ^2 _0 ^1 _2 )>

Alternatively, all constructors of Regina classes can be used directly as attributes of the interface:

sage: rL == regina.Link('dabcabcv-')
True
[Python]
>>> from sage.all import *
>>> rL == regina.Link('dabcabcv-')
True

Finally, if you just want to use a Regina command line from within Sage, the IPython magic function %regina dumps you into an interactive command-line Regina session. As long as you work in this environment the prompt is regina:. To finish the environment type CTRL+D:

sage: %regina                                 # not tested

--> Switching to Regina <--

regina: u = Link()
None
regina: u
<regina.Link: Empty link>
regina: type(u)
<class 'regina.engine.Link'>
regina: v = u.fromKnotSig('iabcdbefcdghaefghRsgF+m')
None
regina: v
<regina.Link: 8-crossing knot: ++++--++ ( ^0 ^1 _2 ^3 _1 ^4 _5 ^2 _3 _6 ^7 _0 _4 ^5 ^6 _7 )>
regina: type(v)
<class 'regina.engine.Link'>
regina: v.homfly()
<regina.Laurent2: 2 x^-2 y^2 + 3 x^-2 - x^-4 y^4 - 3 x^-4 y^2 - 3 x^-4 + x^-6 y^2 + x^-6>
regina: u.homfly()
<regina.Laurent2: 0>
regina: type(u)
<class 'regina.engine.Link'>

--> Exiting back to Sage <--

sage:                                         # not tested
>>> from sage.all import *
>>> %regina                                 # not tested

--> Switching to Regina <--

regina: u = Link()
None
regina: u
<regina.Link: Empty link>
regina: type(u)
<class 'regina.engine.Link'>
regina: v = u.fromKnotSig('iabcdbefcdghaefghRsgF+m')
None
regina: v
<regina.Link: 8-crossing knot: ++++--++ ( ^0 ^1 _2 ^3 _1 ^4 _5 ^2 _3 _6 ^7 _0 _4 ^5 ^6 _7 )>
regina: type(v)
<class 'regina.engine.Link'>
regina: v.homfly()
<regina.Laurent2: 2 x^-2 y^2 + 3 x^-2 - x^-4 y^4 - 3 x^-4 y^2 - 3 x^-4 + x^-6 y^2 + x^-6>
regina: u.homfly()
<regina.Laurent2: 0>
regina: type(u)
<class 'regina.engine.Link'>

--> Exiting back to Sage <--

>>>                                         # not tested

Complicated translations

The robj.sage() method tries to convert a Regina object to a Sage object. In many cases, it will just work. In particular, it should be able to convert expressions entirely consisting of:

  • numbers, i.e. integers, floats, complex numbers;

  • functions and named constants also present in Sage, where:

    • Sage knows how to translate the function or constant’s name from Regina’s, or

    • the Sage name for the function or constant is trivially related to Regina’s;

  • symbolic variables whose names don’t pathologically overlap with objects already defined in Sage.

This method will not work when Regina’s output includes:

  • strings;

  • functions unknown to Sage;

  • Regina functions with different parameters/parameter order to the Sage equivalent.

AUTHORS:

  • Sebastian Oehms (2025): first version.

class sage.interfaces.regina.AlgorithmExt(*values)[source]

Bases: Enum

Enum to select algorithm choices.

This extends the Algorithm class of Regina.

ALG_SIMPLIFY = 4[source]
ALG_USE_EXTERIOR = 6[source]
ALG_WIRTINGER = 5[source]
class sage.interfaces.regina.Regina[source]

Bases: ExtraTabCompletion, Interface

Interface to the Regina interpreter.

EXAMPLES:

sage: K = Knots().from_table(8, 21)
sage: Kr = regina(K); Kr
<regina.Link: 8-crossing knot: ----++-- ( _5 _0 ^1 _2 _3 ^6 _7 ^3 _4 ^5 _6 ^7 ^0 _1 ^2 ^4 )>
sage: Kr.knotSig()
'iabcdbefcdghaefghRsgF+m'
>>> from sage.all import *
>>> K = Knots().from_table(Integer(8), Integer(21))
>>> Kr = regina(K); Kr
<regina.Link: 8-crossing knot: ----++-- ( _5 _0 ^1 _2 _3 ^6 _7 ^3 _4 ^5 _6 ^7 ^0 _1 ^2 ^4 )>
>>> Kr.knotSig()
'iabcdbefcdghaefghRsgF+m'

More examples can be found in the module header.

eval(code, *args, **kwds)[source]

Evaluates a command inside the Regina interpreter and returns the output in printable form.

EXAMPLES:

sage: regina.eval('1+1')
'2'
>>> from sage.all import *
>>> regina.eval('1+1')
'2'
get(var)[source]

Get the value of the variable var.

EXAMPLES:

sage: regina.get('Link')
<class 'regina.engine.Link'>
>>> from sage.all import *
>>> regina.get('Link')
<class 'regina.engine.Link'>
help(cmd, long=False)[source]

Return the Regina documentation of the given command.

EXAMPLES:

sage: regina.help('AbelianGroup')
Represents a finitely generated abelian group.

The torsion elements of the group are stored in terms of their
invariant factors. For instance, Z_2+Z_3 will appear as Z_6, and
Z_2+Z_2+Z_3 will appear as Z_2+Z_6.

In general the factors will appear as Z_*d0*+...+Z_*dn*, where the
invariant factors *di* are all greater than 1 and satisfy
*d0*|*d1*|...|*dn*. Note that this representation is unique.

This class implements C++ move semantics and adheres to the C++
Swappable requirement. It is designed to avoid deep copies wherever
possible, even when passing or returning objects by value.
>>> from sage.all import *
>>> regina.help('AbelianGroup')
Represents a finitely generated abelian group.
<BLANKLINE>
The torsion elements of the group are stored in terms of their
invariant factors. For instance, Z_2+Z_3 will appear as Z_6, and
Z_2+Z_2+Z_3 will appear as Z_2+Z_6.
<BLANKLINE>
In general the factors will appear as Z_*d0*+...+Z_*dn*, where the
invariant factors *di* are all greater than 1 and satisfy
*d0*|*d1*|...|*dn*. Note that this representation is unique.
<BLANKLINE>
This class implements C++ move semantics and adheres to the C++
Swappable requirement. It is designed to avoid deep copies wherever
possible, even when passing or returning objects by value.
set(var, value)[source]

Set the variable var to the given value.

EXAMPLES:

sage: regina.set('myLink', 'Link')
sage: regina.get('myLink')
<class 'regina.engine.Link'>
>>> from sage.all import *
>>> regina.set('myLink', 'Link')
>>> regina.get('myLink')
<class 'regina.engine.Link'>
class sage.interfaces.regina.ReginaElement(parent, value, is_name=False, name=None)[source]

Bases: ExtraTabCompletion, InterfaceElement

Element class of the Regina interface.

Its instances are usually constructed via the instance call of its parent. It wrapes the Regina library for this object. In a session Regina methods can be obtained using tab completion.

EXAMPLES:

sage: b = BraidGroup(3)((1,2,-1))
sage: re = regina(b); re
<regina.GroupExpression: g0 g1 g0^-1>
sage: type(re)
<class 'sage.interfaces.regina.ReginaElement'>
sage: P = re.parent(); P
Regina
sage: type(P)
<class 'sage.interfaces.regina.Regina'>
>>> from sage.all import *
>>> b = BraidGroup(Integer(3))((Integer(1),Integer(2),-Integer(1)))
>>> re = regina(b); re
<regina.GroupExpression: g0 g1 g0^-1>
>>> type(re)
<class 'sage.interfaces.regina.ReginaElement'>
>>> P = re.parent(); P
Regina
>>> type(P)
<class 'sage.interfaces.regina.Regina'>

Access to the Regina expression objects:

sage: res = re._inst
sage: type(res)
 <class 'regina.engine.GroupExpression'>
[Python]
>>> from sage.all import *
>>> res = re._inst
>>> type(res)
 <class 'regina.engine.GroupExpression'>

Applying Regina methods:

sage: re.cycleLeft(); re
<regina.GroupExpression: g0^-1 g0 g1>
>>> from sage.all import *
>>> re.cycleLeft(); re
<regina.GroupExpression: g0^-1 g0 g1>

Conversion to Sage:

sage: re.sage() == b
False
sage: re.cycleRight()
sage: re.sage() == b
True
[Python]
>>> from sage.all import *
>>> re.sage() == b
False
>>> re.cycleRight()
>>> re.sage() == b
True
class sage.interfaces.regina.ReginaFunction(parent, name)[source]

Bases: InterfaceFunction

Interface Function.

EXAMPLES:

sage: m = regina.MatrixInt; m
<class 'regina.engine.MatrixInt'>
sage: type(m)
<class 'sage.interfaces.regina.ReginaFunction'>
>>> from sage.all import *
>>> m = regina.MatrixInt; m
<class 'regina.engine.MatrixInt'>
>>> type(m)
<class 'sage.interfaces.regina.ReginaFunction'>
class sage.interfaces.regina.ReginaFunctionElement(obj, name)[source]

Bases: InterfaceFunctionElement

Interface methods of interface elements.

EXAMPLES:

sage: A = regina.AbelianGroup()
sage: A.addRank
<bound method pybind11_detail_function_record_v1_system_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_0.addRank of <regina.AbelianGroup: 0>>
sage: type(A.addRank)
<class 'sage.interfaces.regina.ReginaFunctionElement'>
>>> from sage.all import *
>>> A = regina.AbelianGroup()
>>> A.addRank
<bound method pybind11_detail_function_record_v1_system_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_0.addRank of <regina.AbelianGroup: 0>>
>>> type(A.addRank)
<class 'sage.interfaces.regina.ReginaFunctionElement'>