Interface to Regina - Interpreter Interfaces

Skip to content
Back to top
View this page
Edit this page

# 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

    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 >>

Python

    >>> 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

    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

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

Python

    >>> 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

    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

    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

Python

    >>> 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)

  Bases: `Enum`

  Enum to select algorithm choices.

  This extends the `Algorithm` class of Regina.

  ALG_SIMPLIFY = 4
  ALG_USE_EXTERIOR = 6
  ALG_WIRTINGER = 5

class sage.interfaces.regina.Regina

  Bases: `ExtraTabCompletion`, `Interface`

  Interface to the Regina interpreter.

  EXAMPLES:

  Sage

      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'

  Python

      >>> 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)

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

    EXAMPLES:

    Sage

        sage: regina.eval('1+1')
        '2'

    Python

        >>> from sage.all import *
        >>> regina.eval('1+1')
        '2'

  get(var)

    Get the value of the variable `var`.

    EXAMPLES:

    Sage

        sage: regina.get('Link')
        <class 'regina.engine.Link'>

    Python

        >>> from sage.all import *
        >>> regina.get('Link')
        <class 'regina.engine.Link'>

  help(cmd, long=False)

    Return the Regina documentation of the given command.

    EXAMPLES:

    Sage

        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.

    Python

        >>> 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)

    Set the variable `var` to the given `value`.

    EXAMPLES:

    Sage

        sage: regina.set('myLink', 'Link')
        sage: regina.get('myLink')
        <class 'regina.engine.Link'>

    Python

        >>> 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)

  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

      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'>

  Python

      >>> 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

      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

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

  Python

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

  Conversion to Sage:

  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)

  Bases: `InterfaceFunction`

  Interface Function.

  EXAMPLES:

  Sage

      sage: m = regina.MatrixInt; m
      <class 'regina.engine.MatrixInt'>
      sage: type(m)
      <class 'sage.interfaces.regina.ReginaFunction'>

  Python

      >>> 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)

  Bases: `InterfaceFunctionElement`

  Interface methods of interface elements.

  EXAMPLES:

  Sage

      sage: A = regina.AbelianGroup()
      sage: A.addRank
      <bound method pybind11_detail_function_record_v1_system_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_1.addRank of <regina.AbelianGroup: 0>>
      sage: type(A.addRank)
      <class 'sage.interfaces.regina.ReginaFunctionElement'>

  Python

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