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:
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
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 to a Sage
multivariate polynomial. Note that it is important to let
and
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 in GAP, we need to tell GAP to view
the variables x0 and x1 as the two
generators of
. 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 and
are defined, so we can
construct the GAP polynomial
corresponding to
:
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 . For example, we evaluate
the GAP Value function, which evaluates
at the point
.
sage: f.Value(I, [1,2])
3
sage: g(1,2) # agrees
3
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/permutation_group.py for a nontrivial example of this.
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)
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:
Interface to the GAP interpreter.
AUTHORS:
EXAMPLES:
sage: gap == loads(dumps(gap))
True
EXAMPLES:
sage: gap.__reduce__()
(<function reduce_load_GAP at 0x...>, ())
sage: f, args = _
sage: f(*args)
Gap
EXAMPLES:
sage: Integers = gap('Integers')
sage: two = gap(2)
sage: gap._contains(two.name(), Integers.name())
True
sage: 2 in gap('Integers')
True
Returns the continuation prompt in GAP.
EXAMPLES:
sage: gap._continuation_prompt()
'> '
Returns the symbol for equality in GAP.
EXAMPLES:
sage: gap._equality_symbol()
'='
sage: gap(2) == gap(2)
True
EXAMPLES:
sage: gap._eval_line('2+2;')
'4'
Returns the symbol for falsity in GAP.
EXAMPLES:
sage: gap._false_symbol()
'false'
sage: gap(2) == gap(3)
False
Returns the GapFunction class.
EXAMPLES:
sage: gap._function_class()
<class 'sage.interfaces.gap.GapFunction'>
sage: type(gap.Order)
<class 'sage.interfaces.gap.GapFunction'>
Returns the GapFunctionElement class.
EXAMPLES:
sage: gap._function_element_class()
<class 'sage.interfaces.gap.GapFunctionElement'>
sage: type(gap.SymmetricGroup(4).Order)
<class 'sage.interfaces.gap.GapFunctionElement'>
TESTS:
We check to make sure that the gap interface behaves correctly after a keyboard interrupt.
sage: gap(2) 2 sage: try: ... gap._keyboard_interrupt() ... except: ... pass Interrupting Gap... sage: gap(2) 2
Returns the next unused variable name.
EXAMPLES:
sage: g = Gap()
sage: g._next_var_name()
'$sage1'
sage: g(2)^2
4
sage: g._next_var_name()
'$sage...'
Returns the GapElement class.
EXAMPLES:
sage: gap._object_class()
<class 'sage.interfaces.gap.GapElement'>
sage: type(gap(2))
<class 'sage.interfaces.gap.GapElement'>
EXAMPLES:
sage: gap._pre_interact()
sage: gap._post_interact()
EXAMPLES:
sage: gap._pre_interact()
sage: gap._post_interact()
Returns the string used to quit GAP.
EXAMPLES:
sage: gap._quit_string()
'quit'
sage: g = Gap()
sage: a = g(2); g.is_running()
True
sage: g.quit()
sage: g.is_running()
False
Returns the command use to read in a file in GAP.
EXAMPLES:
sage: gap._read_in_file_command('test')
'Read("test");'
sage: filename = tmp_filename()
sage: f = open(filename, 'w')
sage: f.write('xx := 22;\n')
sage: f.close()
sage: gap.read(filename)
sage: gap.get('xx').strip()
'22'
EXAMPLES:
sage: g = Gap()
sage: g.is_running()
False
sage: g._start()
sage: g.is_running()
True
sage: g.quit()
Returns the symbol for truth in GAP.
EXAMPLES:
sage: gap._true_symbol()
'true'
sage: gap(2) == gap(2)
True
Spawn a new GAP command-line session.
EXAMPLES:
sage: gap.console() #not tested
GAP4, Version: 4.4.10 of 02-Oct-2007, x86_64-unknown-linux-gnu-gcc
gap>
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
Send the code in the string s to the GAP interpreter and return the output as a string.
INPUT:
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'
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.expect.AsciiArtString'>
sage: s.startswith('CT')
True
Get the string representation of the variable var.
EXAMPLES:
sage: gap.set('x', '2')
sage: gap.get('x')
'2'
Print help on a given topic.
EXAMPLES:
sage: print gap.help('SymmetricGroup', pager=False)
Basic Groups _____________________________________________ Group Libraries
...
Load the Gap package with the given name.
If loading fails, raise a RuntimeError exception.
Set the variable var to the given value.
EXAMPLES:
sage: gap.set('x', '2')
sage: gap.get('x')
'2'
EXAMPLES:
sage: c = gap.trait_names()
sage: len(c) > 100
True
sage: 'Order' in c
True
Clear the variable named var.
EXAMPLES:
sage: gap.set('x', '2')
sage: gap.get('x')
'2'
sage: gap.unbind('x')
sage: gap.get('x')
...
RuntimeError: Gap produced error output
Variable: 'x' must have a value
...
Returns the version of GAP being used.
EXAMPLES:
sage: gap.version()
'4.4.10'
EXAMPLES:
sage: a = gap([1,2,3])
sage: a[1]
1
EXAMPLES:
sage: v = gap('[1,2,3]'); v
[ 1, 2, 3 ]
sage: len(v)
3
len is also called implicitly by if:
sage: if gap('1+1 = 2'):
... print "1 plus 1 does equal 2"
1 plus 1 does equal 2
sage: if gap('1+1 = 3'):
... print "it is true"
... else:
... print "it is false"
it is false
Note that GAP elements cannot be pickled.
EXAMPLES:
sage: gap(2).__reduce__()
(<function reduce_load at 0x...>, ())
sage: f, args = _
sage: f(*args)
(invalid object -- defined in terms of closed session)
EXAMPLES:
sage: gap(2)
2
EXAMPLES:
sage: s = gap("[[1,2], [3/4, 5/6]]")
sage: latex(s)
\left(\begin{array}{rr} 1&2\\ 3/4&\frac{5}{6}\\ \end{array}\right)
Return matrix over the (Sage) ring R determined by self, where self should be a Gap matrix.
EXAMPLES:
sage: s = gap("(Z(7)^0)*[[1,2,3],[4,5,6]]"); s
[ [ Z(7)^0, Z(7)^2, Z(7) ], [ Z(7)^4, Z(7)^5, Z(7)^3 ] ]
sage: s._matrix_(GF(7))
[1 2 3]
[4 5 6]
sage: s = gap("[[1,2], [3/4, 5/6]]"); s
[ [ 1, 2 ], [ 3/4, 5/6 ] ]
sage: m = s._matrix_(QQ); m
[ 1 2]
[3/4 5/6]
sage: parent(m)
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
sage: s = gap('[[Z(16),Z(16)^2],[Z(16)^3,Z(16)]]')
sage: s._matrix_(GF(16,'a'))
[ a a^2]
[a^3 a]
EXAMPLES:
sage: bool(gap(2))
True
sage: gap(0).bool()
False
sage: gap('false').bool()
False
EXAMPLES:
sage: print gap(2)
2
EXAMPLES:
sage: s5 = gap.SymmetricGroup(5)
sage: 'Centralizer' in s5.trait_names()
True
EXAMPLES:
sage: print gap.SymmetricGroup._sage_doc_()
Basic Groups _____________________________________________ Group Libraries
...
EXAMPLES:
sage: print gap(4).SymmetricGroup._sage_doc_()
Basic Groups _____________________________________________ Group Libraries
...
Spawn a new GAP command-line session.
EXAMPLES:
sage: gap.console() #not tested
GAP4, Version: 4.4.10 of 02-Oct-2007, x86_64-unknown-linux-gnu-gcc
gap>
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 the file
$HOME/.sage/gap-workspace
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.
Returns the version of GAP being used.
EXAMPLES:
sage: gap_version()
'4.4.10'
INPUT:
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:
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
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()
(invalid object -- defined in terms of closed session)
sage: loads(dumps(gap(2)))
(invalid object -- defined in terms of closed session)
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