Subsections

3. Overview of Capabilities

SAGE is not at version 1.0 yet, and should still be considered a work in active progress. The main reason you should try to use SAGE today is so that you can give feedback and contribute to its development, since SAGE will fill a community need. Here is a selection of what is available now.

3.1 Polynomials

SAGE has some support for polynomials.
sage: R = PolynomialRing(Q)
sage: x = R.0
sage: R = PolynomialRing(Q, "x")
sage: x = R.0     # same as R.gen() or R.gen(0)
sage: x in R
      True
sage: f = 2*x^7 + 3*x^2 - 15/19
sage: f^2
      4*x^14 + 12*x^9 - 60/19*x^7 + 9*x^4 - 90/19*x^2 + 225/361
sage: g = (x^5+10*x+2)*R.cyclotomic_polynomial(7)*x^5
sage: g
      x^16 + x^15 + x^14 + x^13 + 11*x^12 + 13*x^11 + 13*x^10 + 12*x^9 
                                         + 12*x^8 + 12*x^7 + 12*x^6 + 2*x^5
sage: factor(g)
      [(x, 5), (x^5 + 10*x + 2, 1), (x^6 + x^5 + x^4 + x^3 + x^2 + x + 1, 1)]
One can also name the variable differently and get a different univariate polynomial ring.
sage: S = PolynomialRing(Q, "y")
sage: y = S.0
sage: x == y
      False
sage: R == S
      False
sage: R(y)
      x
sage: R(y^2 - 17)
      x^2 - 17
The ring is determined by the variable so making ``another'' ring with variable called x actually just returns a reference to R defined above.
sage: T = PolynomialRing(Q, "x")
sage: R == T
      True
sage: R.0 == T.0
      True

SAGE currently has no support for power series, though such support will be added very soon.

3.2 Elliptic Curves

The near-term plan for elliptic curves functionality is to include:
  1. All elliptic curves functionality of PARI. (Some is already available.)
  2. Easy access to all data in Cremona's online tables, but with more data about each curve precomputed. (Already available, if you install the optional database package.)
  3. Implicit access to the functionality of mwrank, i.e., $2$-descents with computation of the full Mordell-Weil group. (Almost available.)
  4. Access to Cremona's allisog program, which computes all elements of the $\mathbf{Q}$-rational isogeny class of an elliptic curve. (Not available yet.)

Here is ane example of computing with an elliptic curve.

sage: E = EllipticCurve([0,0,1,-1,0])
sage: E
      y^2 + y = x^3 - x
sage: P = E([0,0])
sage: 10*P
      (161/16, -2065/64)
sage: 20*P
      (683916417/264517696, -18784454671297/4302115807744)
sage: E.conductor()
      37

We can compute the coefficients of the $L$-series or modular form attached to the elliptic curve. This computation uses the PARI C-library, which is the fastest implementation I know:

sage: E = EllipticCurve([0,0,1,-1,0])
sage: print E.anlist(30)  
      [0, 1, -2, -3, 2, -2, 6, -1, 0, 6, 4, -5, -6, -2, 2, 6, 
       -4, 0, -12, 0, -4, 3, 10, 2, 0, -1, 4, -9, -2, 6, -12]
sage: time v = E.anlist(10000)     # on Thinkpad T42p with 1.8Ghz Pentium-M
Time: 0.05 seconds
sage: time v = E.anlist(100000)
Time: 0.64 seconds

Elliptic curves can be constructed using their Cremona labels. This preloads the elliptic curve with information about its rank, conductor, etc.

sage: E = EllipticCurve("37B2")
sage: E
      Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over 
      Rational Field
sage: E = EllipticCurve("389A")
sage: E
      Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x  over Rational Field
sage: E.rank()
      2
sage: E = EllipticCurve("5077A")
sage: E.rank()
      3

We can also access the compressed database directly.

sage: import sage.tables.elliptic_curves
sage: db = sage.tables.elliptic_curves.Database()
sage: db.
db._db                     db.changed                 db.dump_as_dict            
                                                         db.optimal_curves
db._dbname                 db.clone                   db.dump_as_dict_intervals  
                                                         db.pack
db._root                   db.commit                  db.has_key                 
                                                         db.read_only
db._storage                db.conn                    db.import_allcurves        
                                                         db.rebuild
db._thresh                 db.curve                   db.import_degphi           
                                                         db.restore_from_dict
db.abort                   db.curves                  db.keys                    
                                                         db.restore_from_dict_all
db.as_dict                 db.delete_all              db.name                    
                                                         db.root
sage: db.curves(37)
[37A1: invs=[0, 0, 1, -1, 0], rank=1, tors=1, cp={37: 1},
 37B1: invs=[0, 1, 1, -23, -50], rank=0, tors=3, cp={37: 3},
 37B2: invs=[0, 1, 1, -1873, -31833], rank=0, tors=1, cp={37: 1},
 37B3: invs=[0, 1, 1, -3, 1], rank=0, tors=3, cp={37: 1}]
sage: db.optimal_curves(37)
[37A1: invs=[0, 0, 1, -1, 0], rank=1, tors=1, cp={37: 1},
 37B1: invs=[0, 1, 1, -23, -50], rank=0, tors=3, cp={37: 3}]
sage: E = db.curves(37)[0]
sage: E.
E.a_invariants      E.iso_class         E.rank              E.tamagawa_product  
                                                                E.traces
E.conductor         E.number            E.tamagawa          E.torsion
Note that the objects returned from the database are not of type EllipticCurve. They are elements of a database and have a couple of fields, and that's it. At present the entire elliptic curves database occupies only 6.4MB; it contains all the above listed fields for all elliptic curves of conductor up to $30000$.

3.3 Modular Forms

SAGE can do some computations related to modular forms, including dimension, computing spaces of modular symbols, Hecke operators, and decompositions.

Use help(dims) to see what functions are available for computing dimensions of spaces of modular forms.

sage: help(dims)
Help on module sage.modular.dims in sage.modular:
...
FUNCTIONS
    ...
    dimension_cusp_forms(group, k=2)
        The dimension of the space of cusp forms for the congruence
        subgroup group.
    ...
Let's try it out:
sage: dims.dimension_cusp_forms(Gamma0(11),2)
      1
sage: dims.dimension_cusp_forms(Gamma0(1),12)
      1
sage: dims.dimension_cusp_forms(Gamma1(389),2)
      6112

Next we illustrate computation of Hecke operators on a space of modular symbols of level $1$ and weight $12$.

sage: M = ModularSymbols(1,12)
sage: M.basis()
      [(1 0 0), (0 1 0), (0 0 1)]
sage: t2 = M.T(2)
sage: t2
Linear function defined by matrix:
[ -24    0    0]
[   0  -24    0]
[4860    0 2049]
sage: f = t2.charpoly(); f
      x^3 - 2001*x^2 - 97776*x - 1180224
sage: factor(f)
      [(x - 2049, 1), (x + 24, 2)]
sage: M.T(11).charpoly().factor()
      [(x - 285311670612, 1), (x - 534612, 2)]
We can also create spaces with various signs and of higher level for $\Gamma_0(N)$ and $\Gamma_1(N)$. Note that we use MS below, which is a shortcut for ModularSymbols.
sage: MS(11,2)
      Full Modular Symbols space for Gamma_0(11) of weight 2 and 
      dimension 3 over Rational Field
sage: MS(Gamma1(11),2)
      Full Modular Symbols space for Gamma_1(11) of weight 2 and 
      dimension 11 over Rational Field
sage: M = MS(Gamma1(11),2)
sage: M.T(2).charpoly()
      x^11 - 8*x^10 + 20*x^9 + 10*x^8 - 145*x^7 + 229*x^6 + 58*x^5 
           - 360*x^4 + 70*x^3 - 515*x^2 + 1804*x - 1452
sage: M.T(2).charpoly().factor()

[(x - 3, 1),
 (x + 2, 2),
 (x^4 - 7*x^3 + 19*x^2 - 23*x + 11, 1),
 (x^4 - 2*x^3 + 4*x^2 + 2*x + 11, 1)]
We can even compute spaces of modular symbols with character.
sage: G = DirichletGroup(13)
sage: e = G.0^2
sage: M = ModularSymbols(e,2)
sage: M
      Full Modular Symbols space of level 13, weight 2, character [zeta_12^2] and 
      dimension 4 over Cyclotomic Field of order 12 and degree 4
sage: M.T(2).charpoly()
      x^4 + (-zeta_12^2 - 1)*x^3 + (-8*zeta_12^2)*x^2 + 
            (10*zeta_12^2 - 5)*x + 21*zeta_12^2 - 21
sage: M.T(2).charpoly().factor()
      [(x + -2*zeta_12^2 - 1, 1), (x + -zeta_12^2 - 2, 1), 
            (x + zeta_12^2 + 1, 2)]

Decomposition and computation of $q$-expansions is currently not finished, but a very high priority. Also, the machinery for these computations has not been sufficiently optimized, and there are surely some places where computations take much longer than necessary.

3.4 PARI Access

Part of SAGE is a Python-based extension class that uses the PARI C library to provide functionality similar to that provided by the GP PARI interpreter, except with more robust memory management, garbage collection, automatic increasing of stack size and prime table, etc.; it is slower but more robust than GP. This will be the foundation for the elementary and algebraic number theory functionality of SAGE. In addition, this Python-based extension class will be released separately from SAGE and not depend on SAGE. See the file sage/pari/py_pari.pyx for more details.

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]
Every PARI object is of type py_pari.gen, though the PARI type of the underlying object can be obtained using the type member function.
sage: type(v)
      <type 'py_pari.gen'>
sage: v.type()
      't_VEC'
Array access is $0$-based like in C and Python, but unlike in the GP interpreter.
sage: v[0]
      1
sage: v[4]
      5
Array slicing is supported, just like in Python:
sage: v[:3]
      [1, 2, 3]
sage: v[2:4]
      [3, 4]

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'
Now that we have an elliptic curve PARI object, we can compute 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]

The full functionality of GP/PARI will (eventually) be available in this way, this is not meant to be the way SAGE is used. Instead, when people are implementing SAGE and discover that something has already been implemented in PARI, they can use it without any robustness penalties. For example, computing the conductor of an elliptic curve in SAGE is better accomplished by typing the following which is implemented by creating the PARI elliptic curve and calling ellglobalred:

sage: E = EllipticCurve([1,2,3,4,5])
sage: E
      Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 
      over Rational Field
sage: E.conductor()
      10351

It is taking some time to implement py_pari since the author must understand almost every single PARI C-library function, write a wrapper around it, and provide example usage. (Volunteers needed!) Also, there are some subtle issues that arise because PARI and Python both fight over trapping signals.

3.5 Linear Algebra

Some standard linear algebra commands, such as characteristic polynomial, reduced row-echelon form, trace, decomposition, etc.

Create a space of matrices.

sage: M = MatrixSpace(Q,3)
sage: M
Full MatrixSpace of 3 by 3 dense matrices over Rational Field
The space of matrices has a basis, just like any vector space:
sage: B = M.basis()
sage: len(B)
9
sage: B[1]
[0 1 0]
[0 0 0]
[0 0 0]
We create a matrix as an element of M.
sage: A = M(range(9)); A
[0 1 2]
[3 4 5]
[6 7 8]
Next we compute its reduced row echelon form and kernel.
sage: A.reduced_row_echelon_form()
[ 1  0 -1]
[ 0  1  2]
[ 0  0  0]
sage: A^20
[ 2466392619654627540480  3181394780427730516992 3896396941200833493504] 
       ...
sage: A.kernel()
Vector space of degree 3, dimension 1 over Rational Field
Basis matrix:
[ 1 -2  1]
sage: kernel(A)      # example of functional notation

3.6 Sparse Linear Algebra

SAGE has support for optimized sparse linear algebra over $\mathbf{Q}$ and $\mathbf{Z}/p\mathbf{Z}$.

sage: M = MatrixSpace(Q, 100, sparse=True)
sage: A = M.random_element(prob = 0.05)
sage: len(A.nonzero_positions())
      536
sage: time E = A.reduced_row_echelon_form()
Time: 0.02 seconds
The multimodular algorithm that we've implemented is good for square matrices as the above timing suggests. It's not as good for non-square matrices, though it is very memory efficient.
sage: M = MatrixSpace(Q, 100, 150, sparse=True)
sage: A = M.random_element(prob = 0.05)
sage: len(A.nonzero_positions())
      695
sage: time E = A.reduced_row_echelon_form()
Time: 1.81 seconds 
sage: len(E.nonzero_positions())
      4357

3.7 Object Persistence

Use the commands db.save and db.load to save and load objects to files, as the following example illustrates.

was@form:~$ sage
...
sage: db.save?
 ... 
sage: f = x^10 + 3*x + 1
sage: db.save(f, "f")

was@form:~$ ls -l f
-rw-r--r--  1 was was 585 Apr 10 15:30 f
was@form:~$ sage
...
sage: g = db.load("f")
sage: g
      x^10 + 3*x + 1

One goal for SAGE V1.0 is that every object can be saved to a file and loaded from a file. This is currently not the case, because some types that are implemented as C extensions require special support for saving and loading, and this hasn't been completed yet (as of April 2005). For example, matrices over $\mathbf{Z}$ can be saved but not over $\mathbf{Q}$:

sage: M = MatrixSpace(Q, 2)
sage: A = M([1,2,3,4])
sage: db.save(A, "A")
...
TypeError: can't pickle Matrix_rational objects

sage: M = MatrixSpace(Z, 2)
sage: A = M([1,2,3,4])
sage: db.save(A, "A")
sage: db.load("A")

[1 2]
[3 4]

There is also support for creating bzip2 compressed object-oriented databases for SAGE. See the source code in sage/tables/ for some examples (further documentation is needed here).

See About this document... for information on suggesting changes.