We illustrate some basic rings in SAGE.
For example, the field
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
). 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'>
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
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
and divide to
implicity create an element of
.
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
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.
SAGE can compute several basic functions in number theory.
For example, we do arithmetic in
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
SAGE's sigma(k,n) function adds up the
th powers of
the divisors of
:
sage: sigma(0,28); sigma(1,28); sigma(2,28) 6 56 1050
We next illustrate the extended Euclidean algorithm, the Euler's
-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,)]
A DirichletCharacter is the extension of a homomorphism
for some ring
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
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
:
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
, 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]]
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.,
-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:
where the
"11a"
or "37b2"
. Note that the letter
must be lower case (to distinguish it from the old labeling).
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
elements.
The pair
is a point on the elliptic curve
defined by
. 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
-invariant. SAGE can compute
the
-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
sage: F = EllipticCurve(110592/37) sage: factor(F.conductor()) 2^6 * 37
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
of the
-series
or modular form
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
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
.
There is also a large optional version, which contains extensive
data about all curves of conductor up to
(as of October, 2005).
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
and weight
.
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
and
.
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
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]
SAGE provides standard linear algebra commands, e.g., characteristic polynomial, echelon form, trace, decomposition, etc., of a matrix.
We create the space
Mat
:
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
used by SAGE is obtained
from the non-zero rows of the reduced row echelon
form of the matrix of generators of
.
SAGE has support for sparse linear algebra over
and
.
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()
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.