Subsections

2. A Guided Tour

This section is a guided tour of some of what is currently available in SAGE.

2.1 Basic Rings

We illustrate some basic rings in SAGE. For example, the field $\mathbf{Q}$ of rational numbers may be referred to using either RationalField() or QQ:

sage: RationalField()
Rational Field
sage: QQ
Rational Field
sage: 1.2 in QQ
False
sage: 1/2 in QQ
True

Note that if you use QQ as a variable, you can still fetch the rational numbers using the command RationalField(). By the way, some other pre-defined SAGE rings include the integers ZZ, the real numbers RR, the complex numbers CC (which uses I (or i), as usual, for the square root of $-1$ ). We discuss polynomial rings in Section 2.2.

Do not redefine ZZ or RR unless you really know what you are doing. They are used by the SAGE interpreter to wrap integer and real literals. For example, if you type ZZ = int, then integer literals will behave as the usually do in Python, so e.g., 4/3 evaluates to the Python int 1. For examples

sage: 4/3
      4/3
sage: parent(_)
      Rational Field
sage: ZZ = int
sage: 4/3
      1
sage: parent(_)
<type 'int'>
sage: ZZ = IntegerRing()
sage: 4/3
      4/3

Now we illustrate some arithmetic involving various numbers.

sage: a, b = 4/3, 2/3
sage: a + b
      2
sage: 2*b == a
      True
sage: parent(2/3)
      Rational Field
sage: parent(4/2)
      Rational Field
sage: 2/3 + 0.1       # automatic coercion before addition
      0.76666666666666661
sage: 0.1 + 2/3       # arithmetic binary operations are usually symmetric in SAGE
      0.76666666666666661
sage: z = a + b*I
sage: z
      1.3333333333333333 + 0.66666666666666663*I
sage: z.real() == a                   #automatic coercion before comparision
      True

Note that Python is dynamically typed, so the value referred to by each variable has a type associated with it, but a given variable may hold values of any Python type in a given scope:

sage: a = 5
sage: type(a)
      <type '_integer.Integer'>
sage: a = 5/3
sage: type(a)
      <type '_rational.Rational'>
sage: a = 'hello'
sage: type(a)
      <type 'str'>
The C programming language, which is statically typed, is much different; a variable declared to hold an int can only hold an int in it's scope.


2.2 Polynomials

In this section we illustrate how to create and use polynomials in SAGE.

2.2.1 Univariate Polynomials

sage: R = PolynomialRing(QQ, "x")
sage: R
      Univariate Polynomial Ring in x over Rational Field
sage: x = R.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) * (x^6 + x^5 + x^4 + x^3 + x^2 + x + 1)

We can also name the variable differently and get a different univariate polynomial ring.

sage: S = PolynomialRing(QQ, "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 the ring R defined above.

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

SAGE also has support for power series and Laurent series rings over any base ring. In the following example we create an element of $ \mathbf{F}_7[[T]]$ and divide to implicity create an element of $ \mathbf{F}_7((T))$ .

sage: R = PowerSeriesRing(GF(7), 'T'); R
Power series ring in T over Finite field of size 7
sage: T = R.0
sage: f = T  + 3*T^2 + T^3 + O(T^4)
sage: f^3
      T^3 + 2*T^4 + 2*T^5 + O(T^6)
sage: 1/f
      T^-1 + 4 + T + O(T^2)
sage: parent(1/f)
      Laurent series ring in T over Finite field of size 7

2.2.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 z_0, z_1, z_2 over Finite field of size 5
sage: z = R.gens()
sage: z
      (z_0, z_1, z_2)
sage: (z[0]+z[1]+z[2])^2
      z_2^2 + 2*z_1*z_2 + z_1^2 + 2*z_0*z_2 + 2*z_0*z_1 + z_0^2

Multivariate polynomials are implemented in SAGE using the Python dictionaries and the ``distributive representation'' of a polynomial.

SAGE makes some use of Singular [Si] (if present), where optimized polynomial routines (such as for Gröbner bases) are implemented.

2.3 Elementary Number Theory

SAGE can compute several basic functions in number theory.

For example, we do arithmetic in $\mathbf{Z}/N\mathbf{Z}$ as follows:

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
      CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 sWall time: 0.0050
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 * 401
sage: c=factorial(25); c
      15511210043330985984000000
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: previous_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

We next illustrate the extended Euclidean algorithm, the 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: euler_phi(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)   
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.00000000000000
sage: list(partitions(4))
      [(1, 1, 1, 1), (1, 1, 2), (2, 2), (1, 3), (4,)]

2.3.1 Dirichlet Characters

A DirichletCharacter is the extension of a homomorphism

$\displaystyle (\mathbf{Z}/N\mathbf{Z})^* \to R^*,
$

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: x = PolynomialRing(QQ).gen()
sage: K = NumberField(x^4 + 1, 'a'); a = K.gen(0)
sage: K
      Number Field in a with defining polynomial x^4 + 1
sage: G = DirichletGroup(5, K, a); G
      Group of Dirichlet characters of modulus 5 over 
        Number Field in a with defining polynomial x^4 + 1
sage: G.list()
      [[1], [a^2], [-1], [-a^2]]

2.4 Elliptic Curves

Elliptic curves functionality includes most of the elliptic curve functionality of PARI, access to the data in Cremona's online tables (requires optional database package), the functionality of mwrank, i.e., $2$ -descents with computation of the full Mordell-Weil group, the SEA algorithm, computation of all isogenies, and much more.

The command EllipticCurve for creating an elliptic curve has many forms:

We illustrate each of these constructors:

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 + 4*x over Finite field of size 5

sage: EllipticCurve([1,2])
      Elliptic Curve defined by y^2  = x^3 + x + 2 over Rational Field

sage: EllipticCurve('37a')
      Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field

sage: EllipticCurve(5)
      Elliptic Curve defined by y^2 + x*y  = x^3 + 36/1723*x + 1/1723 
            over Rational Field

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

Here GF(5)(0) denotes the zero element of the field with $5$ elements.

The pair $ (0,0$ is a point on the elliptic curve $ E$ defined by $ 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
      Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
sage: P = E([0,0])
sage: P + P
      (1, 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 the $j$ -invariants.

sage: E = EllipticCurve([0,0,1,-1,0]); E
      Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
sage: E.j_invariant()
      110592/37
Note that if we make a curve with $j$ -invariant the same as that of $ E$ , it need not be isomorphic to $ E$ . In the following example, the cuvres are not isomorphic because their conductors are different.
sage: F = EllipticCurve(110592/37)
sage: factor(F.conductor())
      2^6 * 37
However, the twist of $ F$ by $2$ gives an isomorphic curve.
sage: factor(conductor(F.quadratic_twist(2)))  
      37
sage: F.quadratic_twist(2).minimal_model()
      Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field

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:

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
It only takes a second to compute all $a_n$ for $ n\leq 10^5$ :
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, Tamagawa numbers, regulator, 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 Cremona database directly.

sage: db = sage.databases.cremona.CremonaDatabase()
sage: db.curves(37)
{'a1': [[0, 0, 1, -1, 0], 1, 1], 'b1': [[0, 1, 1, -23, -50], 0, 3]}
sage: db.allcurves(37)
{'a1': [[0, 0, 1, -1, 0], 1, 1],
 'b1': [[0, 1, 1, -23, -50], 0, 3],
 'b2': [[0, 1, 1, -1873, -31833], 0, 1],
 'b3': [[0, 1, 1, -3, 1], 0, 3]}

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. There is a small version of Cremona's database, which is distributed by default with SAGE, and contains limited information about elliptic curves of conductor $\leq 10000$ . There is also a large optional version, which contains extensive data about all curves of conductor up to $120000$ (as of October, 2005).

2.5 Modular Forms

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

There are several functions available for computing dimensions of spaces of modular forms. For example,

sage: dimension_cusp_forms(Gamma0(11),2)
      1
sage: dimension_cusp_forms(Gamma0(1),12)
      1
sage: 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()
      ([X^8*Y^2,(0,0)], [X^9*Y,(0,0)], [X^10,(0,0)])
sage: t2 = M.T(2)
sage: t2
      Hecke operator T_2 on Full Modular Symbols space for Gamma_0(1) of 
      weight 12 with sign 0 and dimension 3 over Rational Field
sage: t2.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) * (x + 24)^2
sage: M.T(11).charpoly().factor()
      (x - 285311670612) * (x - 534612)^2

We can also create spaces with various signs and of higher level for $\Gamma_0(N)$ and $\Gamma_1(N)$ .

sage: ModularSymbols(11,2)
      Full Modular Symbols space for Gamma_0(11) of weight 2 with 
      sign 0 and dimension 3 over Rational Field
sage: ModularSymbols(Gamma1(11),2)
      Full Modular Symbols space for Gamma_1(11) of weight 2 with 
      sign 0 and dimension 11 over Rational Field
sage: M = ModularSymbols(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) * (x + 2)^2 * (x^4 - 7*x^3 + 19*x^2 - 23*x + 11) 
              * (x^4 - 2*x^3 + 4*x^2 + 2*x + 11)

We can even compute spaces of modular symbols with character.

sage: G = DirichletGroup(13)
sage: e = G.gen(0)^2
sage: M = ModularSymbols(e,2)
sage: M
      Full Modular Symbols space of level 13, weight 2, character [zeta_6], 
      sign 0, and dimension 4 over Cyclotomic Field of order 6 and degree 2
sage: M.T(2).charpoly()
      x^4 + (-zeta_6 - 1)*x^3 + (-8*zeta_6)*x^2 + (10*zeta_6 - 5)*x + 21*zeta_6 - 21
sage: M.T(2).charpoly().factor()
      (x + -zeta_6 - 2) * (x + -2*zeta_6 - 1) * (x + zeta_6 + 1)^2

2.6 PARI

SAGE uses the PARI library to provide functionality similar to that provided by the gp/PARI interpreter, except with memory management.

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 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]

2.7 Linear Algebra

SAGE provides standard linear algebra commands, e.g., characteristic polynomial, echelon form, trace, decomposition, etc., of a matrix.

We create the space Mat$ _{3\times 3}(\mathbf{Q})$ :

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:

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] 
      [ 7571070245559489518592  9765907978125369019392 11960745710691248520192]
      [12675747871464351496704 16350421175823007521792 20025094480181663546880]
sage: A.kernel()
      Vector space of degree 3 and dimension 1 over Rational Field
      Basis matrix:
      [ 1 -2  1]

Next we illustrate computation of matrices 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 and 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.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.8 Sparse Linear Algebra

SAGE has support for 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: E = A.echelon_form()

The multi-modular algorithm in SAGE is good for square matrices, as the above timing suggests. It's not as good for non-square matrices, though it is more memory efficient.

sage: M = MatrixSpace(QQ, 50, 100, sparse=True)
sage: A = M.random_element(prob = 0.05)
sage: E = A.echelon_form()                  
sage: M = MatrixSpace(GF(2), 20, 40, sparse=True)
sage: A = M.random_element()
sage: E = A.echelon_form()

2.9 Object Persistence

A goal for SAGE V1.0.0 is that every object can be easily 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.

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.