A central facet of SAGE is that it supports computation with objects in many different computer algebra systems ``under one roof'' using a common interface and clean programming language.
The console and interact methods of an interface do very different things. For example, using gap as an example:
gap.console()
: You are completely using another
program, e.g., gap/magma/gp
Here SAGE is serving as nothing more than a convenient
program launcher, similar to bash.
gap.interact()
: This is a convenient way to interact
with a running
gap instance that may be "full of" SAGE objects. You can
import SAGE objects into this gap (even from the interactive
interface), etc.
PARI is a compact, very mature, highly optimized C program whose primary focus is number theory. There are two very distinct interfaces that you can use in SAGE:
gp
- the ``Go PARI'' interpreter, and
pari
- the PARI C library.
sage: gp('znprimroot(10007)') Mod(5, 10007) sage: pari('znprimroot(10007)') Mod(5, 10007)
'znprimroot(10007)'
is sent to it, evaluated by GP, and the result is assigned
to a variable in GP (which takes up space in the child GP
processes memory that won't be freed). Then the value of that variable is displayed.
In the second case, no separate program is started,
and the string 'znprimroot(10007)'
is evaluated by
a certain PARI C library function. The result is stored
in a piece of memory on the Python heap, which is freed
when the variable is no longer referenced. The
objects have different types:
sage: type(gp('znprimroot(10007)')) <class 'sage.interfaces.gp.GpElement'> sage: type(pari('znprimroot(10007)')) <type 'gen.gen'>
Note: If the GP interface runs out of memory evaluating a given input line, it will silently and automatically double the stack size and retry that input line. Thus your computation won't crash if you didn't correctly anticipate the amount of memory that would be needed. This is a nice trick the usual GP interpreter doesn't seem to provide. Regarding the PARI C-library interface, it immediately copies each created object off of the PARI stack, hence the stack never grows. However, each object must not exceed 100MB in size, or the stack will overflow when the object is being created. This extra copying does impose a slight performance penalty.
In summary, SAGE uses the PARI C library to provide functionality similar to that provided by the GP/PARI interpreter, except with different sophisticated memory management and the Python programming language.
First we create a PARI list from a Python list.
sage: v = pari([1,2,3,4,5]) sage: v [1, 2, 3, 4, 5] sage: type(v) <type 'gen.gen'>
Every PARI object is of type py_pari.gen
. The PARI type of the
underlying object can be obtained using the type
member
function.
sage: v.type() 't_VEC'
In PARI, to create an elliptic curve we enter
ellinit([1,2,3,4,5])
.
SAGE is similar, except that ellinit
is a method that can be called on any PARI object,
e.g., our t_VEC v
.
sage: e = v.ellinit() sage: e.type() 't_VEC' sage: pari(e)[:13] [1, 2, 3, 4, 5, 9, 11, 29, 35, -183, -3429, -10351, 6128487/10351]
Now that we have an elliptic curve object, we can compute some things about it.
sage: e.elltors() [1, [], []] sage: e.ellglobalred() [10351, [1, -1, 0, -1], 1] sage: f = e.ellchangecurve([1,-1,0,-1]) sage: f[:5] [1, -1, 0, 4, 3]
SAGE comes with GAP 4.4.7 for computational discrete mathematics, especially group theory.
Here's an example of GAP's IdGroup
function, which uses the
optional small groups database that has to be installed separately, as
explained below.
sage: G = gap('Group((1,2,3)(4,5), (3,4))') sage: G Group([ (1,2,3)(4,5), (3,4) ]) sage: G.Center() Group(()) sage: G.IdGroup() # requires optional database_gap package [ 120, 34 ] sage: G.Order() 120
We can do the same computation in SAGE without explicitly invoking the GAP interface as follows:
sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() Permutation Group with generators [()] sage: G.group_id() # requires optional database_gap package [120, 34] sage: n = G.order(); n 120
Note:
For some GAP functionality, you should install two optional
SAGE packages.
Type sage -optional
for a list and choose
the one that looks like gap_packages-x.y.z
, then type
sage -i gap_packages-x.y.z
. Do the same
for database_gap-x.y.z
.
Some non-GPL'd GAP packages may be installed by downloading them
from the GAP web site [GAPkg],
and unpacking them in $SAGE_ROOT/local/lib/gap-4.4.7/pkg
.
Singular provides a massive and mature library for Gröbner bases, multivariate polynomial gcds, bases of Riemann-Roch spaces of a plane curve, and factorizations, among other things. We illustrate multivariate polynomial factorization using the SAGE interface to Singular:
sage: R1 = singular.ring(0, '(x,y)', 'dp') sage: R1 // characteristic : 0 // number of vars : 2 // block 1 : ordering dp // : names x y // block 2 : ordering C sage: f = singular('9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3 - 18*x^13*y^2 + 9*x^16')
Now that we have defined
, we print it and factor.
sage: f 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.parent() Singular sage: F = f.factorize(); 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 sage: F[1][2] x^6-2*x^3*y^2-x^2*y^3+y^4
As with the GAP example in Section 4.2, we can compute the above factorization without explicitly using the Singular interface (however, behind the scenes SAGE uses the Singular interface for the actual computation).
sage: x, y = QQ['x, y'].gens() sage: f = 9*y^8 - 9*x^2*y^7 - 18*x^3*y^6 - 18*x^5*y^6 + 9*x^6*y^4 + 18*x^7*y^5 + 36*x^8*y^4 + 9*x^10*y^4 - 18*x^11*y^2 - 9*x^12*y^3 - 18*x^13*y^2 + 9*x^16 sage: factor(f) 9 * (y^2 - x^5)^2 * (y^4 - x^2*y^3 - 2*x^3*y^2 + x^6)
Maxima is included with SAGE, as is clisp (a version of the Lisp language) and the gnuplot package (which Maxima uses for plotting). Among other things, Maxima does symbolic manipulation. Maxima can integrate and differentiate functions symbolically, solve 1st order ODEs, most linear 2nd order ODEs, and has implemented the Laplace transform method for linear ODEs of any degree. Maxima also knows about a wide range of special functions, has plotting capabilities via gnuplot, and has methods to solve and manipulate matrices (such as row reduction, eigenvalues and eigenvectors), and polynomial equations.
We illustrate the SAGE/Maxima interface by constructing the matrix
whose
entry is
, for
.
sage: f = maxima.eval('f[i,j] := i/j') sage: A = maxima('genmatrix(f,4,4)'); A matrix([1,1/2,1/3,1/4],[2,1,2/3,1/2],[3,3/2,1,3/4],[4,2,4/3,1]) sage: A.determinant() 0 sage: A.echelon() matrix([1,1/2,1/3,1/4],[0,0,0,0],[0,0,0,0],[0,0,0,0]) sage: A.eigenvalues() [[0,4],[3,1]] sage: A.eigenvectors() [[[0,4],[3,1]],[1,0,0, - 4],[0,1,0, - 2],[0,0,1, - 4/3],[1,2,3,4]]
We can also compute the echelon form in SAGE:
sage: B = matrix(A, QQ) sage: B.echelon_form() [ 1 1/2 1/3 1/4] [ 0 0 0 0] [ 0 0 0 0] [ 0 0 0 0] sage: B.charpoly().factor() (x - 4) * x^3
Here's another example:
sage: A = maxima("A: matrix ([1, 0, 0], [1, -1, 0], [1, 3, -2])") sage: eigA = A.eigenvectors() sage: V = VectorSpace(QQ,3) sage: eigA [[[ - 2, - 1,1],[1,1,1]],[0,0,1],[0,1,3],[1,1/2,5/6]] sage: v1 = V(sage_eval(eigA[1])); lambda1 = eigA[0][0][0] sage: v2 = V(sage_eval(eigA[2])); lambda2 = eigA[0][0][1] sage: v3 = V(sage_eval(eigA[3])); lambda3 = eigA[0][0][2] sage: M = MatrixSpace(QQ,3,3) sage: AA = M([[1,0,0],[1, - 1,0],[1,3, - 2]]) sage: AA*v1 == lambda1*v1 True sage: AA*v2 == lambda2*v2 True sage: AA*v3 == lambda3*v3 True
Finally, we give an example of using SAGE to compute the image under
the Riemann zeta function of an interval of the the critical line
, for 80 sampled values of
,
saving the real and imaginary points into lists, then using Maxima
(which calls gnuplot) to plot these points and save the resulting
graph into the current directory.
sage: Z = [ (1/2 + n*I/10).zeta() for n in range(70,150) ] sage: Z_x = [w.real() for w in Z] sage: Z_y = [w.imag() for w in Z]
We first make the graph appear in a pop-up window.
sage: maxima.plot_list(Z_x, Z_y)
We can also save the graph a file.
sage: opts='[gnuplot_preamble, "set nokey"], [gnuplot_term, ps], [gnuplot_out_file, "zeta.eps"]' sage: maxima.plot_list(Z_x, Z_y, opts)
See About this document... for information on suggesting changes.