### Navigation

- index
- modules |
- next |
- previous |
- Interpreter Interfaces »

# Interface to GAP

Sage provides an interface to the GAP system. This system provides extensive group theory, combinatorics, etc.

The GAP interface will only work if GAP is installed on your computer; this should be the case, since GAP is included with Sage. The interface offers three pieces of functionality:

1. `gap_console()` - A function that dumps you into an interactive command-line GAP session.
2. `gap(expr)` - Evaluation of arbitrary GAP expressions, with the result returned as a string.
3. `gap.new(expr)` - Creation of a Sage object that wraps a GAP object. This provides a Pythonic interface to GAP. For example, if `f=gap.new(10)`, then `f.Factors()` returns the prime factorization of \(10\) computed using GAP.

## First Examples

We factor an integer using GAP:

    sage: n = gap(20062006); n
    20062006
    sage: n.parent()
    Gap
    sage: fac = n.Factors(); fac
    [ 2, 17, 59, 73, 137 ]
    sage: fac.parent()
    Gap
    sage: fac[1]
    2

## GAP and Singular

This example illustrates conversion between Singular and GAP via Sage as an intermediate step. First we create and factor a Singular polynomial.

    sage: singular(389)
    389
    sage: R1 = singular.ring(0, '(x,y)', 'dp')
    sage: f = singular('9*x^16-18*x^13*y^2-9*x^12*y^3+9*x^10*y^4-18*x^11*y^2+36*x^8*y^4+18*x^7*y^5-18*x^5*y^6+9*x^6*y^4-18*x^3*y^6-9*x^2*y^7+9*y^8')
    sage: F = f.factorize()
    sage: print F
    [1]:
       _[1]=9
       _[2]=x^6-2*x^3*y^2-x^2*y^3+y^4
       _[3]=-x^5+y^2
    [2]:
       1,1,2

Next we convert the factor \(-x^5+y^2\) to a Sage multivariate polynomial. Note that it is important to let \(x\) and \(y\) be the generators of a polynomial ring, so the eval command works.

    sage: R.<x,y> = PolynomialRing(QQ,2)
    sage: s = F[1][3].sage_polystring(); s
    '-x**5+y**2'
    sage: g = eval(s); g
    -x^5 + y^2

Next we create a polynomial ring in GAP and obtain its indeterminates:

    sage: R = gap.PolynomialRing('Rationals', 2); R
    PolynomialRing( Rationals, ["x_1", "x_2"] )
    sage: I = R.IndeterminatesOfPolynomialRing(); I
    [ x_1, x_2 ]

In order to eval \(g\) in GAP, we need to tell GAP to view the variables `x0` and `x1` as the two generators of \(R\). This is the one tricky part. In the GAP interpreter the object `I` has its own name (which isn’t `I`). We can access its name using `I.name()`.

    sage: _ = gap.eval("x := %s[1];; y := %s[2];;"%(I.name(), I.name()))

Now \(x_0\) and \(x_1\) are defined, so we can construct the GAP polynomial \(f\) corresponding to \(g\):

    sage: R.<x,y> = PolynomialRing(QQ,2)
    sage: f = gap(str(g)); f
    -x_1^5+x_2^2

We can call GAP functions on \(f\). For example, we evaluate the GAP `Value` function, which evaluates \(f\) at the point \((1,2)\).

    sage: f.Value(I, [1,2])
    3
    sage: g(1,2)        # agrees
    3

## Saving and loading objects

Saving and loading GAP objects (using the dumps method, etc.) is not supported, since the output string representation of Gap objects is sometimes not valid input to GAP. Creating classes that wrap GAP objects is supported, via simply defining the a _gap_init_ member function that returns a string that when evaluated in GAP constructs the object. See `groups/perm_gps/permgroup.py` for a nontrivial example of this.

## Long Input

The GAP interface reads in even very long input (using files) in a robust manner, as long as you are creating a new object.

Note

Using `gap.eval` for long input is much less robust, and is not recommended.

    sage: t = '"%s"'%10^10000   # ten thousand character string.
    sage: a = gap(t)

## Changing which GAP is used

Use this code to change which GAP interpreter is run. E.g.,

    import sage.interfaces.gap
    sage.interfaces.gap.gap_cmd = "/usr/local/bin/gap"

AUTHORS:

- David Joyner and William Stein: initial version(s)
- William Stein (2006-02-01): modified gap_console command so it uses exactly the same startup command as Gap.__init__.
- William Stein (2006-03-02): added tab completions: gap.[tab], x = gap(...), x.[tab], and docs, e.g., gap.function? and x.function?

class `sage.interfaces.gap.``Gap`(max_workspace_size=None, maxread=100000, script_subdirectory=None, use_workspace_cache=True, server=None, server_tmpdir=None, logfile=None)

  Bases: `sage.interfaces.gap.Gap_generic`

  Interface to the GAP interpreter.

  AUTHORS:

  - William Stein and David Joyner
  `console`()

    Spawn a new GAP command-line session.

    EXAMPLES:

        sage: gap.console()  # not tested
        *********   GAP, Version 4.5.7 of 14-Dec-2012 (free software, GPL)
        *  GAP  *   http://www.gap-system.org
        *********   Architecture: x86_64-unknown-linux-gnu-gcc-default64
        Libs used:  gmp, readline
        Loading the library and packages ...
        Packages:   GAPDoc 1.5.1
        Try '?help' for help. See also  '?copyright' and  '?authors'
        gap>

  `cputime`(t=None)

    Returns the amount of CPU time that the GAP session has used. If `t` is not None, then it returns the difference between the current CPU time and `t`.

    EXAMPLES:

        sage: t = gap.cputime()
        sage: t  #random
        0.13600000000000001
        sage: gap.Order(gap.SymmetricGroup(5))
        120
        sage: gap.cputime(t)  #random
        0.059999999999999998

  `get`(var, use_file=False)

    Get the string representation of the variable var.

    EXAMPLES:

        sage: gap.set('x', '2')
        sage: gap.get('x')
        '2'

  `help`(s, pager=True)

    Print help on a given topic.

    EXAMPLES:

        sage: print gap.help('SymmetricGroup', pager=False)
        <BLANKLINE>
        50 Group Libraries
        <BLANKLINE>
        When you start GAP, it already knows several groups. Currently GAP initially
        knows the following groups:
        ...

  `save_workspace`()

    Save the GAP workspace.

    TESTS:

    We make sure that #9938 (GAP does not start if the path to the GAP workspace file contains more than 82 characters) is fixed:

        sage: ORIGINAL_WORKSPACE = sage.interfaces.gap.WORKSPACE
        sage: sage.interfaces.gap.WORKSPACE = os.path.join(SAGE_TMP, "gap" + "0"*(80-len(SAGE_TMP)))
        sage: gap = Gap()
        sage: gap('3+2')  # long time (4s on sage.math, 2013)
        5
        sage: sage.interfaces.gap.WORKSPACE = ORIGINAL_WORKSPACE

  `set`(var, value)

    Set the variable var to the given value.

    EXAMPLES:

        sage: gap.set('x', '2')
        sage: gap.get('x')
        '2'

  `trait_names`()

    EXAMPLES:

        sage: c = gap.trait_names()
        sage: len(c) > 100
        True
        sage: 'Order' in c
        True

class `sage.interfaces.gap.``GapElement`(parent, value, is_name=False, name=None)

  Bases: `sage.interfaces.gap.GapElement_generic`

  `str`(use_file=False)

    EXAMPLES:

        sage: print gap(2)
        2

  `trait_names`()

    EXAMPLES:

        sage: s5 = gap.SymmetricGroup(5)
        sage: 'Centralizer' in s5.trait_names()
        True

class `sage.interfaces.gap.``GapElement_generic`(parent, value, is_name=False, name=None)

  Bases: `sage.interfaces.expect.ExpectElement`

  Generic interface to the GAP3/GAP4 interpreters.

  AUTHORS:

  - William Stein and David Joyner (interface for GAP4)
  - Franco Saliola (Feb 2010): refactored to separate out the generic code
  `bool`()

    EXAMPLES:

        sage: bool(gap(2))
        True
        sage: gap(0).bool()
        False
        sage: gap('false').bool()
        False

class `sage.interfaces.gap.``GapFunction`(parent, name)

  Bases: `sage.interfaces.expect.ExpectFunction`

class `sage.interfaces.gap.``GapFunctionElement`(obj, name)

  Bases: `sage.interfaces.expect.FunctionElement`

class `sage.interfaces.gap.``Gap_generic`(name, prompt, command=None, server=None, server_tmpdir=None, ulimit=None, maxread=100000, script_subdirectory=None, restart_on_ctrlc=False, verbose_start=False, init_code=[], max_startup_time=None, logfile=None, eval_using_file_cutoff=0, do_cleaner=True, remote_cleaner=False, path=None, terminal_echo=True)

  Bases: `sage.interfaces.expect.Expect`

  Generic interface to the GAP3/GAP4 interpreters.

  AUTHORS:

  - William Stein and David Joyner (interface for GAP4)
  - Franco Saliola (Feb 2010): refactored to separate out the generic code
  `eval`(x, newlines=False, strip=True, split_lines=True, **kwds)

    Send the code in the string s to the GAP interpreter and return the output as a string.

    INPUT:

    - `s` - string containing GAP code.
    - `newlines` - bool (default: True); if False, remove all backslash-newlines inserted by the GAP output formatter.
    - `strip` - ignored
    - `split_lines` – bool (default: True); if True then each line is evaluated separately. If False, then the whole block of code is evaluated all at once.

    EXAMPLES:

        sage: gap.eval('2+2')
        '4'
        sage: gap.eval('Print(4); #test\n Print(6);')
        '46'
        sage: gap.eval('Print("#"); Print(6);')
        '#6'
        sage: gap.eval('4; \n 6;')
        '4\n6'
        sage: gap.eval('if 3>2 then\nPrint("hi");\nfi;')
        'hi'
        sage: gap.eval('## this is a test\nPrint("OK")')
        'OK'
        sage: gap.eval('Print("This is a test. Oh no, a #");# but this is a comment\nPrint("OK")')
        'This is a test. Oh no, a #OK'
        sage: gap.eval('if 4>3 then')
        ''
        sage: gap.eval('Print("Hi how are you?")')
        'Hi how are you?'
        sage: gap.eval('fi')
        ''

  `function_call`(function, args=None, kwds=None)

    Calls the GAP function with args and kwds.

    EXAMPLES:

        sage: gap.function_call('SymmetricGroup', [5])
        SymmetricGroup( [ 1 .. 5 ] )

    If the GAP function does not return a value, but prints something to the screen, then a string of the printed output is returned.

        sage: s = gap.function_call('Display', [gap.SymmetricGroup(5).CharacterTable()])
        sage: type(s)
        <class 'sage.interfaces.interface.AsciiArtString'>
        sage: s.startswith('CT')
        True

  `get_record_element`(record, name)

    Return the element of a GAP record identified by `name`.

    INPUT:

    - `record` – a GAP record
    - `name` – str

    OUTPUT:

    - `GapElement`

    EXAMPLES:

        sage: rec = gap('rec( a := 1, b := "2" )')
        sage: gap.get_record_element(rec, 'a')
        1
        sage: gap.get_record_element(rec, 'b')
        2

    TESTS:

        sage: rec = gap('rec( a := 1, b := "2" )')
        sage: type(gap.get_record_element(rec, 'a'))
        <class 'sage.interfaces.gap.GapElement'>

  `interrupt`(tries=None, timeout=1, quit_on_fail=True)

    Interrupt the GAP process

    Gap installs a SIGINT handler, we call it directly instead of trying to sent Ctrl-C. Unlike `interrupt()`, we only try once since we are knowing what we are doing.

    Sometimes GAP dies while interrupting.

    EXAMPLES:

        sage: gap._eval_line('while(1=1) do i:=1;; od;', wait_for_prompt=False);
        ''
        sage: rc = gap.interrupt(timeout=1)
        sage: [ gap(i) for i in range(10) ]   # check that it is still working
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    TESTS:

        sage: gap('"finished computation"'); gap.interrupt(); gap('"ok"')
        finished computation
        True
        ok

  `load_package`(pkg, verbose=False)

    Load the Gap package with the given name.

    If loading fails, raise a RuntimeError exception.

    TESTS:

        sage: gap.load_package("chevie")
        Traceback (most recent call last):
        ...
        RuntimeError: Error loading Gap package chevie. You may want to install the gap_packages SPKG.

  `trait_names`()

    EXAMPLES:

        sage: c = gap.trait_names()
        sage: len(c) > 100
        True
        sage: 'Order' in c
        True

  `unbind`(var)

    Clear the variable named var.

    EXAMPLES:

        sage: gap.set('x', '2')
        sage: gap.get('x')
        '2'
        sage: gap.unbind('x')
        sage: gap.get('x')
        Traceback (most recent call last):
        ...
        RuntimeError: Gap produced error output
        Error, Variable: 'x' must have a value
        ...

  `version`()

    Returns the version of GAP being used.

    EXAMPLES:

        sage: print gap.version()
        4.7...

`sage.interfaces.gap.``gap_command`(use_workspace_cache=True, local=True)

  x.__init__(...) initializes x; see help(type(x)) for signature

`sage.interfaces.gap.``gap_console`()

  Spawn a new GAP command-line session.

  Note that in gap-4.5.7 you cannot use a workspace cache that had no commandline to restore a gap session with commandline.

  EXAMPLES:

      sage: gap_console()  # not tested
      *********   GAP, Version 4.5.7 of 14-Dec-2012 (free software, GPL)
      *  GAP  *   http://www.gap-system.org
      *********   Architecture: x86_64-unknown-linux-gnu-gcc-default64
      Libs used:  gmp, readline
      Loading the library and packages ...
      Packages:   GAPDoc 1.5.1
      Try '?help' for help. See also  '?copyright' and  '?authors'
      gap>

  TESTS:

      sage: import subprocess
      sage: from sage.interfaces.gap import gap_command
      sage: cmd = 'echo "quit;" | ' + gap_command(use_workspace_cache=False)[0]
      sage: gap_startup = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
      sage: 'http://www.gap-system.org' in gap_startup
      True
      sage: 'Error' not in gap_startup
      True
      sage: 'sorry' not in gap_startup
      True

`sage.interfaces.gap.``gap_reset_workspace`(max_workspace_size=None, verbose=False)

  Call this to completely reset the GAP workspace, which is used by default when Sage first starts GAP.

  The first time you start GAP from Sage, it saves the startup state of GAP in a file `$HOME/.sage/gap/workspace-HASH`, where `HASH` is a hash of the directory where Sage is installed.

  This is useful, since then subsequent startup of GAP is at least 10 times as fast. Unfortunately, if you install any new code for GAP, it won’t be noticed unless you explicitly load it, e.g., with gap.load_package(“my_package”)

  The packages sonata, guava, factint, gapdoc, grape, design, toric, and laguna are loaded in all cases before the workspace is saved, if they are available.

  TESTS:

  Check that `gap_reset_workspace` still works when `GAP_DIR` doesn’t exist, see trac ticket #14171:

      sage: ORIGINAL_GAP_DIR = sage.interfaces.gap.GAP_DIR
      sage: ORIGINAL_WORKSPACE = sage.interfaces.gap.WORKSPACE
      sage: sage.interfaces.gap.GAP_DIR = os.path.join(tmp_dir(), "test_gap_dir")
      sage: sage.interfaces.gap.WORKSPACE = os.path.join(sage.interfaces.gap.GAP_DIR, "test_workspace")
      sage: os.path.isfile(sage.interfaces.gap.WORKSPACE)  # long time
      False
      sage: gap_reset_workspace()                          # long time
      sage: os.path.isfile(sage.interfaces.gap.WORKSPACE)  # long time
      True
      sage: sage.interfaces.gap.GAP_DIR = ORIGINAL_GAP_DIR
      sage: sage.interfaces.gap.WORKSPACE = ORIGINAL_WORKSPACE

  Check that the race condition from trac ticket #14242 has been fixed. We temporarily need to change the worksheet filename.

      sage: ORIGINAL_WORKSPACE = sage.interfaces.gap.WORKSPACE
      sage: sage.interfaces.gap.WORKSPACE = tmp_filename()
      sage: from multiprocessing import Process
      sage: import time
      sage: gap = Gap()  # long time (reset GAP session)
      sage: P = [Process(target=gap, args=("14242",)) for i in range(4)]
      sage: for p in P:  # long time, indirect doctest
      ....:     p.start()
      ....:     time.sleep(0.2)
      sage: for p in P:  # long time
      ....:     p.join()
      sage: os.unlink(sage.interfaces.gap.WORKSPACE)  # long time
      sage: sage.interfaces.gap.WORKSPACE = ORIGINAL_WORKSPACE

`sage.interfaces.gap.``get_gap_memory_pool_size`()

  Get the gap memory pool size for new GAP processes.

  EXAMPLES:

      sage: from sage.interfaces.gap import         ...       get_gap_memory_pool_size
      sage: get_gap_memory_pool_size()   # random output
      1534059315

`sage.interfaces.gap.``gfq_gap_to_sage`(x, F)

  INPUT:

  - `x` - gap finite field element
  - `F` - Sage finite field

  OUTPUT: element of F

  EXAMPLES:

      sage: x = gap('Z(13)')
      sage: F = GF(13, 'a')
      sage: F(x)
      2
      sage: F(gap('0*Z(13)'))
      0
      sage: F = GF(13^2, 'a')
      sage: x = gap('Z(13)')
      sage: F(x)
      2
      sage: x = gap('Z(13^2)^3')
      sage: F(x)
      12*a + 11
      sage: F.multiplicative_generator()^3
      12*a + 11

  AUTHOR:

  - David Joyner and William Stein

`sage.interfaces.gap.``intmod_gap_to_sage`(x)

  INPUT:

  - x – Gap integer mod ring element

  EXAMPLES:

      sage: a = gap(Mod(3, 18)); a
      ZmodnZObj( 3, 18 )
      sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
      3
      sage: b.parent()
      Ring of integers modulo 18

      sage: a = gap(Mod(3, 17)); a
      Z(17)
      sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
      3
      sage: b.parent()
      Ring of integers modulo 17

      sage: a = gap(Mod(0, 17)); a
      0*Z(17)
      sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
      0
      sage: b.parent()
      Ring of integers modulo 17

      sage: a = gap(Mod(3, 65537)); a
      ZmodpZObj( 3, 65537 )
      sage: b = sage.interfaces.gap.intmod_gap_to_sage(a); b
      3
      sage: b.parent()
      Ring of integers modulo 65537

`sage.interfaces.gap.``is_GapElement`(x)

  Returns True if x is a GapElement.

  EXAMPLES:

      sage: from sage.interfaces.gap import is_GapElement
      sage: is_GapElement(gap(2))
      True
      sage: is_GapElement(2)
      False

`sage.interfaces.gap.``reduce_load`()

  Returns an invalid GAP element. Note that this is the object returned when a GAP element is unpickled.

  EXAMPLES:

      sage: from sage.interfaces.gap import reduce_load
      sage: reduce_load()
      <repr(<sage.interfaces.gap.GapElement at 0x...>) failed: ValueError: The session in which this object was defined is no longer running.>
      sage: loads(dumps(gap(2)))
      <repr(<sage.interfaces.gap.GapElement at 0x...>) failed: ValueError: The session in which this object was defined is no longer running.>

`sage.interfaces.gap.``reduce_load_GAP`()

  Returns the GAP interface object defined in sage.interfaces.gap.

  EXAMPLES:

      sage: from sage.interfaces.gap import reduce_load_GAP
      sage: reduce_load_GAP()
      Gap

`sage.interfaces.gap.``set_gap_memory_pool_size`(size_in_bytes)

  Set the desired gap memory pool size.

  Subsequently started GAP/libGAP instances will use this as default. Currently running instances are unchanged.

  GAP will only reserve `size_in_bytes` address space. Unless you actually start a big GAP computation, the memory will not be used. However, corresponding swap space will be reserved so that GAP will always be able to use the reserved address space if needed. While nothing is actually written to disc as long as you don’t run a big GAP computation, the reserved swap space will not be available for other processes.

  INPUT:

  - `size_in_bytes` – integer. The desired memory pool size.

  EXAMPLES:

      sage: from sage.interfaces.gap import         ...       get_gap_memory_pool_size, set_gap_memory_pool_size
      sage: n = get_gap_memory_pool_size()
      sage: set_gap_memory_pool_size(n)
      sage: n == get_gap_memory_pool_size()
      True
      sage: n   # random output
      1534059315

### Navigation

- index
- modules |
- next |
- previous |
- Interpreter Interfaces »