SAGEis not at version 1.0 yet, and should still be considered a work in active progress. The main reason you should try to use SAGEtoday is so that you can give feedback and contribute to its development, since SAGEwill fulfill a community need. Here is a selection of what is available now.
SAGEhas some support for polynomials. Some examples of their usage is given in this section.
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
sage: T = PolynomialRing(QQ, "x") sage: R == T True sage: R.gen() == T.gen() True
SAGEcurrently has no support for power series, though such support will be added very soon.
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 SAGEusing the Python disctionaries and the ``distributive representation'' of a polynomial. This enables polynomial computations to be relatively fast.
It is hoped that in a future version, SAGEwill be able to access Singular [Si], where very fast polynomial routines (such as for Gröbner bases) are implemented.
SAGEcan compute several basic functions in number theory.
For example, arithmetic in
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
SAGEhas 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
SAGE's sigma(k,n) function adds up the powers of
the divisors of
:
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 -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,)]
A DirichletCharacter is the extension of a homomorphism
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: 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]]
sage: T=ModularForms(Gamma0(11),2) sage: T Space of modular forms on Gamma0(11) of weight 2 and dimension 2 over Rational Field sage: V=T.vector_space() sage: V Full Vector space of degree 2 over Rational Field sage: V.degree() 2 sage: T.level() 11 sage: T.group() Gamma0(11) sage: T.dimension() 2 sage: T.dim_cuspidal() 1 sage: T.dim_eisenstein() 1 sage: T.dim_new_cuspidal() 1 sage: M = ModularSymbols(11) sage: M Full Modular Symbols space for Gamma_0(11) of weight 2 and dimension 3 over Rational Field sage: M.weight() 2 sage: M.basis() [(1 0 0), (0 1 0), (0 0 1)] sage: M.sign() 0
Let denote the usual Hecke operators (
prime).
How do the Hecke operators
,
,
act
on the space of modular symbols?
sage: M.T(2) Linear function defined by matrix: [ 3 0 -1] [ 0 -2 0] [ 0 0 -2] sage: M.T(3) Linear function defined by matrix: [ 4 0 -1] [ 0 -1 0] [ 0 0 -1] sage: M.T(5) Linear function defined by matrix: [ 6 0 -1] [ 0 1 0] [ 0 0 1]
The near-term plan for elliptic curves functionality is to include:
The EllipticCurve command has several forms:
"11A"
or "37B2"
.
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
elements. As indicated above, the last two commands are essentially
equivalent.
Obviously is a point on the elliptic curve
.
To create this point in SAGEtype E([0,0]). SAGEcan 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 -invariant. SAGEcan compute
these
-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 of the
-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) 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
SAGEcan 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. ...
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 and weight
.
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)]
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)]
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 -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]
Part of SAGEis 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 SAGEand 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]
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]). SAGEis 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: 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 SAGEis used. Instead, when people are implementing SAGEand 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 SAGEis 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.
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
sage: B = M.basis() sage: len(B) 9 sage: B[1] [0 1 0] [0 0 0] [0 0 0]
sage: A = M(range(9)); A [0 1 2] [3 4 5] [6 7 8]
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]
SAGEhas support for optimized sparse linear algebra over
and
.
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
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
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 SAGEV1.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 can be saved but not
over
:
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.