Sage és un programari matemàtic gratuït i de codi obert que dóna suport a la recerca i l’ensenyament en àlgebra, geometria, teoria de nombres, criptografia, càlcul numèric, i àrees relacionades. Tant el model de desenvolupament de Sage com la tecnologia pròpia de Sage es distingeixen per un èmfasi extremadament fort en el fet de ser lliure, en la comunitat, la cooperació i la col.laboració: estem construint el cotxe, no pas reinventant la roda. L’objectiu global de Sage és el de crear una alternativa viable, lliure, i de codi obert als paquets de Maple, Mathematica, Magma, i MATLAB.
Aquest tutorial és una introducció al Sage basada en un manual escrit per Maria Bras-Amorós. Es pot llegir bé sigui en HTML o en PDF.
Aquest tutorial està publicat amb una llicència Creative Commons Attribution-Share Alike 3.0 License.
La pàgina oficial de Sage és http://sagemath.org. Des d’allà podeu descarregar-vos el programa.
Es comença amb sage i s’acaba amb quit.
Totes les ordres han d’acabar en salt de línia.
Per interrompre un càlcul: Ctrl + C.
Es pot fer servir la tecla per recuperar codi escrit anteriorment.
Per escriure ordres de sistema: !ordre.
Per llegir el fitxer fin.sage: load fin.sage.
Per llegir el fitxer fin.sage i escriure els resultats al fitxer fout: sage fin.sage > fout.
Per comentar una línia utilitzem # .... Tot el que hi hagi després de # no serà llegit per Sage.
Per comentar tot un paràgraf o part d’un fitxer escrivim tres vegades cometes al principi i al final i el que quedi entremig no serà llegit per Sage:
"""
bla
bla
bla
"""
Per buscar ordres, escrivim les primeres lletres i utilizem el tabulador per veure les possibles complecions.
Sage té definides les seves pròpies funcions que depenen d’una o vàries variables (o cap). Per cridar-les escrivim el nom de la funció seguit de les variables entre parèntesis. Per exemple:
sage: floor(3.141592)
3
sage: gcd(12,8)
4
sage: sum([3,2,5])
10
Hi ha funcions que retornen més d’un valor. Per exemple la funció
divmod(a,b) ens retorna el quocient i el residu de dividir
entre
:
sage: divmod(19,7)
(2, 5)
Per assignar aquests valors a variables ho fem de la manera següent:
sage: q,r = divmod(19,7)
sage: q
2
sage: r
5
També podríem assignar el parell de valors a una sola variable:
sage: D = divmod(19,7)
sage: D
(2, 5)
sage: D[0]
2
sage: D[1]
5
L’estructura següent executarà bloc1 només si condicio1 és certa. El bloc bloc2 només s’executarà si condicio1 és falsa, i condicio2 és certa. Si ambdues condicions són falses, aleshores s’executarà bloc3.
Cal tenir en compte que la indentació determina l’inici i fi dels blocs i que, per tant, és obligatòria.
sage: if condicio1:
....: bloc1
....: elif condicio2:
....: bloc2
....: else:
....: bloc3
Les estructures següents executaran bloc repetides vegades. La primera ho farà vegades,
i la variable i prendrà valors consecutius
. El segon bloc és similar, però i prendrà els valors que apareguin a llista, en el mateix ordre en què hi apareguin. Finalment, el tercer bloc s’executarà mentre condicio sigui certa. Si condicio és falsa al començament, bloc no s’executarà cap vegada.
sage: for i in [i0..i1]:
....: bloc
sage: for i in llista:
....: bloc
sage: while condicio:
....: bloc
Exemples:
sage: for i in [2..5]:
....: print i + 1
3
4
5
6
sage: for i in [-1,"foo",3.4]:
....: print i
-1
foo
3.40000000000000
sage: i = 1
sage: while i < 4:
....: print i
....: i += 1
1
2
3
Tant els conjunts (set) com les seqüències (list) són col.leccions d’objectes. Un conjunt no és ordenat, per tant, un element pot ser en un conjunt com a molt una vegada. Una seqüència, en canvi, és ordenada i, per tant, la repetició és possible. Les seqüències s’escriuen entre [ i ]. Els conjunts es construeixen a partir de seqüències fent servir Set(sequencia).
Per exemple:
sage: S = [ (-11)^2, (-7)^2, (-5)^2, (-3)^2, 3^2, 5^2, 7^2, 11^2 ]
sage: C = Set(S)
sage: S
[121, 49, 25, 9, 9, 25, 49, 121]
sage: C
{121, 9, 49, 25}
La -èssima entrada d’una seqüència (o d’un conjunt)
és C[i]. Però compte perquè Sage
enumera les posicions des de
!:
sage: S[1] = 1000
sage: S
[121, 1000, 25, 9, 9, 25, 49, 121]
sage: S[3]
9
Sage té constructors especials per a seqüències.
Les expressions [a..b] i [a,a+k..b] designen respectivament
les progressions [a,a+1,a+2,...,b] i [a,a+k,a+2k,...,b'],
on és el màxim enter de la forma
menor o igual que
.
D’altra banda,
[ expressio(x) for x in D ]
[ expressio(x,y) for x in D for y in E ]
denota
la seqüència de valors
expressio(x) (resp. expressió(x,y))
avaluada per tot (resp.
).
Així mateix,
[ expressio(x) for x in D if condicio ]
denota
la seqüència de valors expressio(x) avaluada per tot
tals que el booleà condicio és cert.
Per exemple, hauríem pogut crear S
de la manera següent:
sage: S = [ n^2 for n in [-11,-9..11] if is_prime(abs(n)) ]
sage: print S
[121, 49, 25, 9, 9, 25, 49, 121]
Podem aplicar una funció a tots els elements d’una llista de la manera següent:
sage: map(cos, [0,pi..6*pi])
[1, -1, 1, -1, 1, -1, 1]
La declaració general d’una funció
de arguments
per la que s’hagi de fer
una sèrie d’operacions és:
def f(x1, x2, ..., xn):
...
return (val1, val2, ...)
Per exemple:
sage: def solucions_reals_equacio_segon_grau(a,b,c):
....: discriminant = b^2 - 4*a*c
....: arrel_discr = sqrt(discriminant)
....: if discriminant > 0:
....: print "hi ha dues solucions reals"
....: sol1 = (-b + arrel_discr) / (2*a)
....: sol2 = (-b - arrel_discr) / (2*a)
....: return (sol1, sol2)
....: elif discriminant == 0:
....: print "hi ha una solucio real"
....: sol = -b / (2*a)
....: return (sol)
....: else:
....: print "no hi ha solucions reals"
....: return ()
Observem que l’indentat és important. Ara podem cridar-la:
sage: solucions_reals_equacio_segon_grau(1,0,-1)
hi ha dues solucions reals
(1, -1)
Com que en l’exemple donat la funció retorna dos valors, podem assignar-los a dues variables:
sage: a,b = solucions_reals_equacio_segon_grau(1,0,-1)
hi ha dues solucions reals
sage: a
1
sage: b
-1
Aquesta crida, però, ens donaria un error si la solució no existís o fos única.
Observem que totes les variables utilitzades
són per defecte locals i que
no ha calgut declarar-les. Una variable externa a la funció amb nom igual a una de
les variables locals
no es modificarà a causa de la funció. Per exemple, considerem la funció :
sage: def f():
....: a = 5
....: return a
Observem el resultat del codi següent:
sage: a = 3
sage: print f()
5
sage: print a
3
L’anell dels enters el cridem o bé amb Integers() o bé amb ZZ. A continuació llistem algunes funcions pels enters:
L’anell de residus mòdul el cridem amb Integers(n) o amb Zmod(n).
Si posem R = Zmod(n) per algun
aleshores els elements de
els cridem utilitzant R(1), R(2), etc.
Algunes funcions que ens poden ser útils són
sage: x, y = var('x','y')
sage: solve_mod(3*x + 2*y == 1, 5)
[(0, 3), (1, 4), (2, 0), (3, 1), (4, 2)]
L’exemple que segueix pot ser il.lustratiu:
sage: is_prime(19)
True
sage: primitive_root(19)
2
sage: Z19 = Zmod(19)
sage: [x for x in Z19]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
sage: Z19(2).additive_order()
19
sage: Z19(2).multiplicative_order()
18
sage: Z19(5).multiplicative_order()
9
sage: Set([2^i % 19 for i in [1..18]])
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
sage: Set([5^i % 19 for i in [1..18]])
{1, 4, 5, 6, 7, 9, 11, 16, 17}
El cos dels nombres racionals es denota amb RationalField() o QQ. Algunes operacions que podem fer amb els racionals són
El cos dels reals el denotem amb RealField() o RR. Algunes funcions per als reals són:
Es poden resoldre equacions utilitzant l’ordre solve(). Escrivint ?solve el sage ens dóna una explicació molt extensa. Aquí en repetim els primers exemples:
sage: x, y = var('x, y')
sage: solve([x + y == 6, x - y == 4], x, y)
[[x == 5, y == 1]]
sage: solve([x^2 + y^2 == 1, y^2 == x^3 + x + 1], x, y)
[[x == -1/2*I*sqrt(3) - 1/2, y == -sqrt(-1/2*I*sqrt(3) + 3/2)], [x == -1/2*I*sqrt(3) - 1/2, y == sqrt(-1/2*I*sqrt(3) + 3/2)], [x == 1/2*I*sqrt(3) - 1/2, y == -sqrt(1/2*I*sqrt(3) + 3/2)], [x == 1/2*I*sqrt(3) - 1/2, y == sqrt(1/2*I*sqrt(3) + 3/2)], [x == 0, y == -1], [x == 0, y == 1]]
sage: solutions = solve([sqrt(x) + sqrt(y) == 5, x + y == 10], x, y,solution_dict = True)
sage: len(solutions)
2
sage: type(solutions[0])
<type 'dict'>
sage: for sol in solutions: print sol[x].n(digits=3), ",", sol[y].n(digits=3)
5.00 - 5.59*I , 5.00 + 5.59*I
5.00 + 5.59*I , 5.00 - 5.59*I
Per generar l’anell de polinomis sobre un anell
ho fem així:
sage: P.<x> = PolynomialRing(R)
A més, així queda definida com la indeterminada dels polinomis de
.
Per escriure un polinomi de
ho podem fer
de dues maneres:
sage: P.<x> = PolynomialRing(QQ)
sage: x^3-7*x^2+5
x^3 - 7*x^2 + 5
sage: P([5,0,-7,1])
x^3 - 7*x^2 + 5
Vegem un exemple:
sage: P.<x> = PolynomialRing(GF(49,'a'))
sage: f = 4*x^5+5*x+2
sage: g = x^8 + 6*x^7 + x^2
sage: d,a,b = xgcd(f,g)
sage: d
1
sage: d == a*f + b*g
True
Per crear el cos finit de elements
escrivim:
sage: K = GF(p^n,'a')
o bé:
sage: K.<a> = GF(p^n)
Queda així definida també com la classe de la indeterminada dels polinomis sobre
tal que
. Només podem obviar la variable
quan
.
També podem definir cossos finits forçant un determinat polinomi de l’anell de polinomis sobre
i de grau
utilitzant:
sage: F = GF(q, modulus = f)
Donat un cos finit sempre podem conèixer-ne el cos primer
escrivint F.prime_subfield().
Si hem definit com a extensió d’un cos
direm que
és el cos base de
i el podrem conèixer escrivint
F.base_ring().
Per a un cos que haguem definit directament es considera que el cos base és
el cos primer.
Donat un cos , creem l’espai vectorial
mitjançant VectorSpace(K,n), o escrivint K^n.
Per crear vectors podem fer una coerció dins l’espai dels vectors corresponent o bé els podem definir directament:
sage: K = GF(9,'a')
sage: V3 = VectorSpace(K,3)
sage: v = V3([1,0,1])
sage: v
(1, 0, 1)
sage: v[1]
0
sage: w = vector(K,[1,2,3])
sage: w
(1, 2, 0)
sage: w[2]
0
Donat un anell , creem el conjunt de matrius
de
files i
columnes mitjançant MatrixSpace(R,m,n).
Per crear matrius podem fer una coerció dins l’espai de les matrius corresponent o bé les podem definir directament:
sage: F9.<alpha> = GF(9)
sage: M = MatrixSpace(F9,2,3)
sage: M([alpha, 2*alpha, 3*alpha, alpha, alpha^2, alpha^3])
[ alpha 2*alpha 0]
[ alpha alpha + 1 2*alpha + 1]
sage: matrix(2,3,[alpha,2*alpha,3*alpha,alpha,alpha^2,alpha^3])
[ alpha 2*alpha 0]
[ alpha alpha + 1 2*alpha + 1]
sage: matrix(3,2,[alpha,2*alpha,3*alpha,alpha,alpha^2,alpha^3])
[ alpha 2*alpha]
[ 0 alpha]
[ alpha + 1 2*alpha + 1]
Si volem, podem especificar l’anell sobre el qual està definida una matriu. Així, les dues ordres següents ens donarien matrius diferents:
sage: m1 = matrix(Zmod(5),[[1,2],[3,4]]); m1
[1 2]
[3 4]
sage: m2 = matrix(Zmod(7),[[1,2],[3,4]]); m2
[1 2]
[3 4]
sage: m1 == m2
False
Per obtenir els elements d’una matriu utilitzarem m[i,j] i per
obtenir les seves files utilitzarem m[i].
Seguint l’exemple anterior,
sage: m = matrix(F9,[[alpha,2*alpha,3*alpha],[alpha,alpha^2,alpha^3]])
sage: m[0,1]
2*alpha
sage: m[1]
(alpha, alpha + 1, 2*alpha + 1)
Per sumar, restar i multiplicar per escalars es fa amb
la notació usual. Per trobar la matriu inversa d’una
matriu invertible
escriurem m^-1.
Per trobar les solucions d’un sistema lineal on
és una matriu i
és un vector tenim m.solve_left()
mentre que per resoldre el sistema
tenim
m.solve_right().
sage: m = matrix(Integers(),[[0,1],[2,0]])
sage: m
[0 1]
[2 0]
sage: v = vector(Integers(),[2,2])
sage: v
(2, 2)
sage: m.solve_left(v)
(2, 1)
sage: m.solve_right(v)
(1, 2)
També podem calcular submatrius. Per obtenir la submatriu començant a l’entrada
d’una matriu
:
sage: m = matrix(4, [1..16])
sage: m.submatrix(1, 1)
[ 6 7 8]
[10 11 12]
[14 15 16]
Ara només n’agafem dues files:
sage: m.submatrix(1, 1, 2)
[ 6 7 8]
[10 11 12]
I ara només una columna:
sage: m.submatrix(1, 1, 2, 1)
[ 6]
[10]
També es poden escollir files o columnes:
sage: m.submatrix(1, 1, 0)
[]
Amb Sage es poden calcular les derivades i integrals de moltes funcions. Per exemple, per
calcular la derivada de respecte
, fem:
sage: u = var('u')
sage: diff(sin(u), u)
cos(u)
La quarta derivada de s’obté mitjançant:
sage: diff(sin(x^2), x, 4)
16*x^4*sin(x^2) - 48*x^2*cos(x^2) - 12*sin(x^2)
Per calcular les derivades parcials de respecte
i
fem:
sage: x, y = var('x,y')
sage: f = x^2 + 17*y^2
sage: f.diff(x)
2*x
sage: f.diff(y)
34*y
També podem calcular integrals, tant definides com indefinides. Per calcular
i
fem:
sage: integral(x*sin(x^2), x)
-1/2*cos(x^2)
sage: integral(x/(x^2+1), x, 0, 1)
1/2*log(2)
També podem aconseguir una descomposició en fraccions parcials, per exemple de
:
sage: f = 1/((1+x)*(x-1))
sage: f.partial_fraction(x)
-1/2/(x + 1) + 1/2/(x - 1)
Amb Sage podem produir gràfics 2-D i 3-D.
Podem dibuixar cercles, línies, polígons; gràfics de funcions en coordenades cartesianes; i també en coordenades polars, corbes de nivell i gràfics de camps vectorials. Podem trobar més exemples de les funcions gràfiques del Sage a la documentació Sage Constructions
Per dibuixar un cercle groc de radi 1, centrat a l’origen, fem:
sage: circle((0,0), 1, rgbcolor=(1,1,0))
Graphics object consisting of 1 graphics primitive
I un cercle sòlid:
sage: circle((0,0), 1, rgbcolor=(1,1,0), fill=True)
Graphics object consisting of 1 graphics primitive
També podem assignar el cercle a una variable. Llavors no obtindrem cap dibuix:
sage: c = circle((0,0), 1, rgbcolor=(1,1,0))
I el podem visualitzar mitjançant c.show() o show(c):
sage: c.show()
L’ordre c.save('fitxer.png') desa el dibuix al disc.
Amb l’opció aspect_ratio = 1 podem aconseguir que els dos eixos estiguin a la mateixa escala:
sage: c.show(aspect_ratio=1)
També hauriem pogut utilitzar show(c, aspect_ratio=1), o desar-ho amb l’ordre c.save('fitxer.png', aspect_ratio=1).
Així obtenim el gràfic d’una funció bàsica:
sage: plot(cos, (-5,5))
Graphics object consisting of 1 graphics primitive
Si primer alliberem una variable, podem obtenir gràfics de funcions paramètriques:
sage: x = var('x')
sage: parametric_plot((cos(x),sin(x)^3),(x,0,2*pi),rgbcolor=hue(0.6))
Graphics object consisting of 1 graphics primitive
Podem combinar diversos gràfics en una de sol:
sage: x = var('x')
sage: p1 = parametric_plot((cos(x),sin(x)),(x,0,2*pi),rgbcolor=hue(0.2))
sage: p2 = parametric_plot((cos(x),sin(x)^2),(x,0,2*pi),rgbcolor=hue(0.4))
sage: p3 = parametric_plot((cos(x),sin(x)^3),(x,0,2*pi),rgbcolor=hue(0.6))
sage: show(p1+p2+p3, axes=false)
També podem crear polígons. Comencem amb una llista L de punts, i després utilitzem la funció polygon per dibuixar el polígon que té aquests punts com a frontera. Per exemple, un deltoide verd:
sage: L = [[-1+cos(pi*i/100)*(1+cos(pi*i/100)),\
....: 2*sin(pi*i/100)*(1-cos(pi*i/100))] for i in range(200)]
sage: p = polygon(L, rgbcolor=(1/8,3/4,1/2))
sage: p
Graphics object consisting of 1 graphics primitive
Si no volem veure els eixos, utilitzem show(p, axes=false).
També podem afegir text a un gràfic:
sage: L = [[6*cos(pi*i/100)+5*cos((6/2)*pi*i/100),\
....: 6*sin(pi*i/100)-5*sin((6/2)*pi*i/100)] for i in range(200)]
sage: p = polygon(L, rgbcolor=(1/8,1/4,1/2))
sage: t = text("hipotrocoide", (5,4), rgbcolor=(1,0,0))
sage: show(p+t)
Un gràfic més complicat és el que mostra múltiples branques
de la funció arcsinus: és a dir, el gràfic de
on
entre
i
, i rotat un angle de 45 graus. Així és com ho
construirem en Sage:
sage: v = [(sin(x),x) for x in srange(-2*float(pi),2*float(pi),0.1)]
sage: line(v)
Graphics object consisting of 1 graphics primitive
Finalment, un exemple d’un gràfic de corbes de nivell:
sage: f = lambda x,y: cos(x*y)
sage: contour_plot(f, (-4, 4), (-4, 4))
Graphics object consisting of 1 graphics primitive
També podem aconseguir gràfics 3-D amb Sage. Per defecte, aquests gràfics es visualitzen amb el paquet [Jmol], que permet rotar i ampliar l’objecte de manera interactiva, utilitzant el ratolí.
Per visualitzar una funció de la forma utilitzem plot3d:
sage: x, y = var('x,y')
sage: plot3d(x^2 + y^2, (x,-2,2), (y,-2,2))
Graphics3d Object
També podem utilitzar parametric_plot3d per visualitzar
una superfície paramètrica on cadascuna de les coordenades
ve determinada per una funció d’una o dues variables (normalment
denotades per
i
). Així, el gràfic anterior també es pot visualitzar
paramètricament de la manera següent:
sage: u, v = var('u, v')
sage: f_x(u, v) = u
sage: f_y(u, v) = v
sage: f_z(u, v) = u^2 + v^2
sage: parametric_plot3d([f_x, f_y, f_z], (u, -2, 2), (v, -2, 2))
Graphics3d Object
Finalment, podem utilitzar implicit_plot3d,
per visualitzar les corbes de nivell d’una funció com . Aquesta
ordre visualitza una esfera utilitzant la fórmula clàssica:
sage: x, y, z = var('x, y, z')
sage: implicit_plot3d(x^2 + y^2 + z^2 - 4, (x,-2, 2), (y,-2, 2), (z,-2, 2))
Graphics3d Object
[Jmol] | Jmol: un visualitzador d’estructures químiques en 3D, de codi obert i escrit en Java i Javascript. http://www.jmol.org/. |