Subsections

2. 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 fulfill a community need. Here is a selection of what is available now.

2.1 Polynomials

SAGE has some support for polynomials. Some examples of their usage is given in this section.

2.1.1 Univariate Polynomials

sage: R = PolynomialRing(QQ)
sage: x = R.gen()
sage: R = PolynomialRing(QQ, "x")
sage: x = R.gen()     # same as R._0 or R.gen(0)
sage: x in R
      True
sage: f = 2*x^7 + 3*x^2 - QQ(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(QQ, "y")
sage: y = S.gen()
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 the ring R defined above.

sage: T = PolynomialRing(QQ, "x")
sage: R == T
      True
sage: R.gen() == T.gen()
      True

SAGE also has support for power series and Laurent series.

2.1.2 Multivariate Polynomials

To play around with polynomials of several variables in SAGE, you declare the polynomial ring first, then the variables, then you can type in your polynomial.

sage: R = MPolynomialRing(GF(5),3,"z")
sage: R
Polynomial ring in z0, z1, z2 over Finite field of size 5
sage: z = R.gens()
sage: z
(z0, z1, z2)
sage: (z[0]+z[1]+z[2])^2
z2^2 + 2*z1*z2 + z1^2 + 2*z0*z2 + 2*z0*z1 + z0^2

Multivariate polynomials are implemented in SAGE using the Python dictionaries and the ``distributive representation'' of a polynomial. This enables polynomial computations to be relatively fast.

It is hoped that in a future version, SAGE will be able to access Singular [Si], where very fast polynomial routines (such as for Gröbner bases) are implemented.

2.2 Number Theory and Modular Forms

2.2.1 Elementary Number Theory

SAGE can compute several basic functions in number theory.

For example, arithmetic in $\mathbf{Z}/N\mathbf{Z}$ is easy:

sage: R = IntegerModRing(97)
sage: a = R(2) / R(3)
sage: a
      33
sage: a.rational_reconstruction()
      2/3
sage: b=R(47)
sage: time b^20052005
      50
Time: 0.0 seconds
sage: b.modulus()
      97
sage: b.is_square()
      True

SAGE has some number theory functions programmed in python, Others are called from PARI (see arith.py to see which is which).

sage: gcd(515,2005)
      5
sage: factor(2005)
      [(5, 1), (401, 1)]
sage: c=factorial(25); c
      15511210043330985984000000L
sage: [valuation(c,p) for p in prime_range(2,23)]
      [22, 10, 6, 3, 2, 1, 1, 1]
sage: next_prime(2005)
      2011
sage: prev_prime(2005)
      2003
sage: divisors(28); sum(divisors(28)); 2*28
      [1, 2, 4, 7, 14, 28]
      56
      56
Perfect.

SAGE's sigma(k,n) function adds up the $k^{th}$ powers of the divisors of $n$:

sage: sigma(0,28); sigma(1,28); sigma(2,28)
      6
      56
      1050

The extended Euclidean algorithm has been implemented, as well as Euler's $\phi$-function, and the Chinese remainder theorem:

sage: d,u,v=XGCD(12,15)
sage: d==u*12+v*15
      True
sage: inverse_mod(3,2005)
      1337
sage: 3*1337
      4011
sage: n=2005
sage: prime_divisors(n)
      [5, 401]
sage: phi=n*prod([1-1/p for p in prime_divisors(n)]); phi
      1600
sage: eulerphi(2005)
      1600
sage: prime_to_m_part(n,5)
      401
sage: for i in range(1000):
   ....:    n=3*odd_part(n)+1
   ....:    if odd_part(n)==1:
   ....:       print i
   ....:       break
   ....:
38
sage: x=CRT(2, 1, 3, 5) # Chinese Remainder Theorem
sage: x % 3  # x mod 3 = 2
      2
sage: x % 5  # x mod 5 = 1
      1
sage: [binom(13,m) for m in range(14)]
      [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1]
sage: [binom(13,m)%2 for m in range(14)]
      [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1]
sage: [kronecker(m,13) for m in range(1,13)]
      [1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1]
sage: n=10000;sum([moebius(m) for m in range(1,n)]); sqrt(n)
      -23
      100
sage: list(partitions(4))
      [(1, 1, 1, 1), (1, 1, 2), (2, 2), (1, 3), (4,)]

2.2.2 Dirichlet Characters

A DirichletCharacter is the extension of a homomorphism

\begin{displaymath}
(\mathbf{Z}/N\mathbf{Z})^* \to R^*,
\end{displaymath}

for some ring $R$, to the map $\mathbf{Z}/N\mathbf{Z}\to R$ obtained by sending those $x\in\mathbf{Z}/N\mathbf{Z}$ with $\gcd(N,x)>1$ to $0$.

sage: G=DirichletGroup(21)
sage: list(G)

[[1,1],
 [-1,1],
 [1,zeta_6],
 [-1,zeta_6],
 [1,zeta_6-1],
 [-1,zeta_6-1],
 [1,-1],
 [-1,-1],
 [1,-zeta_6],
 [-1,-zeta_6],
 [1,-zeta_6+1],
 [-1,-zeta_6+1]]
sage: G.gens()
      [[-1,1], [1,zeta_6]]
sage: len(G)
      12
sage: chi=G[2]
sage: chi.values_on_gens()
      [1, zeta_6]
sage: chi.values()

[0,
 1,
 zeta_6 - 1,
 0,
 -zeta_6,
 -zeta_6 + 1,
 0,
 0,
 1,
 0,
 zeta_6,
 -zeta_6,
 0,
 -1,
 0,
 0,
 zeta_6 - 1,
 zeta_6,
 0,
 -zeta_6 + 1,
 -1]
sage: chi.conductor()
      7
sage: chi.modulus()
      21

It is also possible to compute the action of the Galois group $Gal(\mathbf{Q}(\zeta_n)/\mathbf{Q})$ on these characters, as well as the direct product decomposition corresponding to the factorization of the modulus.

sage: G.galois_orbits()

[[[1,1]],
 [[-1,1]],
 [[1,zeta_6], [1,-zeta_6+1]],
 [[-1,zeta_6], [-1,-zeta_6+1]],
 [[1,zeta_6-1], [1,-zeta_6]],
 [[-1,zeta_6-1], [-1,-zeta_6]],
 [[1,-1]],
 [[-1,-1]]]
sage: G.decomposition()

[Group of Dirichlet characters of modulus 3 over 
  Cyclotomic Field of order 6 and degree 2,
 Group of Dirichlet characters of modulus 7 over 
  Cyclotomic Field of order 6 and degree 2]

Next, we construct the group of Dirichlet character mod 20, but with values in $\mathbf{Q}(i)$:

sage: G = DirichletGroup(20)
sage: G.list()
      [[1,1], [-1,1], [1,zeta_4], [-1,zeta_4], [1,-1], 
       [-1,-1], [1,-zeta_4], [-1,-zeta_4]]

We next compute several invariants of G:

sage: G.gens()
      [[-1,1], [1,zeta_4]]
sage: G.unit_gens()
      [11, 17]
sage: G.zeta()
      zeta_4
sage: G.zeta_order()
      4

In this example we create a Dirichlet character with values in a number field. We have to give $\zeta$, but not its order.

sage: R = rings.PolynomialRing(rings.RationalField()); x = R.gen()
sage: K = rings.NumberField(x**4 + 1); a = K.gen(0)
sage: G = DirichletGroup(5, K, a); G
      Group of Dirichlet characters of modulus 5 over 
        Number Field with defining polynomial x^4 + 1
sage: G.list()
      [[1], [a^2], [-1], [-a^2]]

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

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

The EllipticCurve command has several forms:

Some examples using this command:

sage: EllipticCurve([0,0,1,-1,0])
      Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
sage: EllipticCurve([GF(5)(0),0,1,-1,0])
      Elliptic Curve defined by y^2 + y = x^3 - x over Finite field of size 5
sage: EllipticCurve(GF(5), [0, 0,1,-1,0])
      Elliptic Curve defined by y^2 + y = x^3 - x over Finite field of size 5

Here GF(5)(0) denotes the zero element of the field with $5$ elements. As indicated above, the last two commands are essentially equivalent.

Obviously $x=y=0$ is a point on the elliptic curve $E: y^2 + y = x^3 - x$. To create this point in SAGE type E([0,0]). SAGE can add points on such an elliptic curve (recall elliptic curves support an additive group structure where the ``point at infinity'' is the zero element and three co-linear points on the curve add to zero):

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

The elliptic curves over the complex numbers (denoted CC in SAGE ) are parameterized by the $j$-invariant. SAGE can compute these $j$-invariants:

sage: E = EllipticCurve([CC(0),0,1,-1,0])
sage: E
      Elliptic Curve defined by y^2 + y = x^3 - x over Complex Field
sage: E.j_invariant()
      2988.97297297297297297

We can compute the coefficients $a_n$ of the $L$-series or modular form $\sum_{n=0}^\infty a_nq^n$ 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)    
CPU times: user 0.09 s, sys: 0.00 s, total: 0.10 s
Wall time: 0.10
sage: time v = E.anlist(100000)
CPU times: user 0.98 s, sys: 0.06 s, total: 1.04 s
Wall time: 1.06

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

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

Once installed, the gamma0wt2 modular forms database can be accessed.

   sage: import sage.tables.gamma0wt2 as D
   sage: db = D.Database()
   sage: db[389]
   [Modular form: level 389, degree 1, number 1, Wq: [-1], an rank bnd: 2,
    Modular form: level 389, degree 2, number 2, Wq: [1], an rank bnd: 1,
    Modular form: level 389, degree 3, number 3, Wq: [1], an rank bnd: 1,
    Modular form: level 389, degree 6, number 4, Wq: [1], an rank bnd: 1,
    Modular form: level 389, degree 20, number 5, Wq: [-1], an rank bnd: 0]

2.5 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 true memory management, garbage collection, automatic increasing of stack size and prime table, etc. This will be the foundation for the elementary and algebraic number theory functionality of SAGE. It will also 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'

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.

2.6 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(QQ,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.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

Matrices also can be defined over finite fields,

sage: M = MatrixSpace(GF(2),4,8)
sage: A=M([1,1,0,0,1,1,1,1,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,1,0,0,1,1,1,1,1,0])
sage: A

[1 1 0 0 1 1 1 1]
[0 1 0 0 1 0 1 1]
[0 0 1 0 1 1 0 1]
[0 0 1 1 1 1 1 0]
sage: rows=A.rows()
sage: A.columns()

[(1 0 0 0),
 (1 1 0 0),
 (0 0 1 1),
 (0 0 0 1),
 (1 1 1 1),
 (1 0 1 1),
 (1 1 0 1),
 (1 1 1 0)]

sage: rows
      [(1 1 0 0 1 1 1 1), (0 1 0 0 1 0 1 1), (0 0 1 0 1 1 0 1), (0 0 1 1 1 1 1 0)]
sage: V=VectorSpace(GF(2),8)
sage: S=V.subspace(rows)
sage: S

Vector space of degree 8, dimension 4 over Finite field of size 2
Basis matrix:
[1 0 0 0 0 1 0 0]
[0 1 0 0 1 0 1 1]
[0 0 1 0 1 1 0 1]
[0 0 0 1 0 0 1 1]

sage: A.reduced_row_echelon_form()

[1 0 0 0 0 1 0 0]
[0 1 0 0 1 0 1 1]
[0 0 1 0 1 1 0 1]
[0 0 0 1 0 0 1 1]
Note that the basis of $S$ used by SAGE is obtained from the non-zero rows of the reduced row echelon form of the matrix of generators of $S$.

2.7 Sparse Linear Algebra

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

sage: M = MatrixSpace(QQ, 100, sparse=True)
sage: A = M.random_element(prob = 0.05)
sage: len(A.nonzero_positions())
      536
sage: time E = A.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(QQ, 100, 150, sparse=True)
sage: A = M.random_element(prob = 0.05)
sage: len(A.nonzero_positions())
      695
sage: time E = A.echelon_form()
Time: 1.81 seconds 
sage: len(E.nonzero_positions())
      4357
sage: M = MatrixSpace(GF(2), 20, 40, sparse=True)
sage: A = M.random_element()
sage: A.rank()
      20
sage: time E = A.reduced_row_echelon_form()
Time: 0.53 seconds

2.8 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 July 2005). For example, matrices over $\mathbf{Z}$ can be saved but not over $\mathbf{Q}$:

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

sage: M = MatrixSpace(ZZ, 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.