Table des matières

  1. Introduction à l’environnemnt de travail et à SageMath
    1. Environnement de travail
    2. Prise en main de SageMath
  2. Anneaux, corps, polynômes, expressions
    1. Structures prédéfinies
    2. Variables et expressions symboliques
    3. Polynômes
    4. Idéaux et bases de Gröbner
    5. Résultants et élimination
  3. Syntaxe Python/Sage
    1. Variables, assignement
    2. Syntaxe
    3. Structures de contrôle
    4. Listes
    5. Fonctions
  4. La hyérarchie des types en Sage
    1. Parents et éléments
    2. Base
    3. Classes, types
  5. Tracer des courbes et des surfaces en Sage
    1. Tracés implicites et paramétriques

Introduction à l’environnemnt de travail et à SageMath

Environnement de travail

Prise en main de SageMath

Interfaces pour l’utilisation de SageMath

Premiers pas avec SageMath

Référence : chapitre 1 du Sagebook.

Anneaux, corps, polynômes, expressions

Structures prédéfinies

Sage prédéfinit pour l’utilisateur certaines structures algèbriques de base, les noms s’expliquent tous seuls :

sage: NN
Non negative integer semiring
sage: ZZ
Integer Ring
sage: QQ
Rational Field
sage: QQbar
Algebraic Field
sage: RR
Real Field with 53 bits of precision
sage: RDF
Real Double Field
sage: CC
Complex Field with 53 bits of precision
sage: GF(7)
Finite Field of size 7
sage: Zmod(15)
Ring of integers modulo 15
sage: Zmod(7)
Ring of integers modulo 7
sage: Qp(5)
5-adic Field with capped relative precision 20

Variables et expressions symboliques

Voir le Sagebook, Section 1.2.

Sage peut utiliser toute la syntaxe du langage Python, à partir de la possibilité de définir des variables :

sage: a = 2+2
sage: a
4
sage: a+2
6

Une variable spéciale, _ (tiret bas), permet de faire référence à la dernière valeur affichée :

sage: _
6

Cette variable est plus utile dans le terminal que dans le notebook, où on peut revenir sur une cellule précédemment saisie.

Sage inclut un moteur de calcul symbolique. Le nom x est une variable symbolique prédéfinie au lancement de Sage.

sage: a = (x^2 + 2) * (x^3 + 4)
sage: a
(x^3 + 4)*(x^2 + 2)
sage: a.expand()
x^5 + 2*x^3 + 4*x^2 + 8

On peut définir d’autres variables symboliques avec la fonction var. Ses effets sont une entorse aux conventions de bon usage des langages de programmation, mais Sage met la facilité d’utilisation en avant…

sage: var('y')
y
sage: (x+y)*(x-y)
(x + y)*(x - y)

Une façon équivalente, mais moins magique d’écrire la même chose :

sage: y = var('y')
sage: (x+y)*(x-y)
(x + y)*(x - y)

Mais attention !

sage: Z = var('z')
sage: Z + z
2*z

Beurk ! En programmation il est bon usage de faire une différence entre Z (un nom de variable) et sa valeur z (une expression symbolique).

Beaucoup moins risqué : utiliser la méthode SR.var à la place de var :

sage: SR.var('t')
t
sage: t
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
...
NameError: name 't' is not defined

Correct, le nom t ne souille pas l’espace des noms. Maintenant :

sage: T = SR.var('t')
sage: T + T
2*t
sage: T + t
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
...
NameError: name 't' is not defined

Attention à ne pas confondre les noms de variables et les variables symboliques, même lorsqu’elles ont la même écriture.

sage: X = SR.var('x')
sage: X
x
sage: x = 6
sage: x
6
sage: X+x
x + 6

Dans l’exemple ci-dessus, X est un nom de variable qui pointe vers une variable symbolique représentée par le caractère x. Plus bas, x est encore un nom de variable qui pointe vers la valeur entière 6.

Polynômes

Voir le Sagebook, chapitre 7.

En plus des polynômes symboliques, Sage possède plusieurs classes spécialisées de polynômes à coefficients dans différents anneaux.

La syntaxe la plus simple pour définir un anneau de polynômes (par exemple sur le corps des rationnels) est

sage: A.<x> = QQ[]
sage: A
Univariate Polynomial Ring in x over Rational Field

Cette syntaxe associe le nom x au générateur de A. Il ne s’agit plus d’expressions symboliques, tout calcul est maintenant exécuté immédiatement :

sage: (x^2 + 2) * (x^3 + 4)
x^5 + 2*x^3 + 4*x^2 + 8

La syntaxe utilisée pour définir les polynômes n’est pas une syntaxe Python standard. Voici deux autres façons de définir A qui sont valides en Python.

sage: A = QQ['x']
sage: x = A.gen()
sage: A = PolynomialRing(QQ, 'x')
sage: x = A.gen()

Dans les deux cas, on voit bien la différence entre le nom de variable x et sa représentation (aussi x). Cela ne doit pas être nécessairement ainsi :

sage: A = QQ['x']
sage: toto = A.gen()
sage: toto^2 + 1
x^2 + 1

Polynômes multivariés

Avec la même syntaxe, on peut définir des anneaux de polynômes à plusieurs variables :

sage: B.<x,y,z> = RR[]; B
Multivariate Polynomial Ring in x, y, z over Real Field with 53 bits of precision

L’ordre monomial par défaut sur les anneaux multivariés est degrevlex :

sage: B.term_order()
Degree reverse lexicographic term order
sage: z < y < x < z^2 < y*z < x*z < y^2 < x*y < x^2
True

Il est possible de choisir l’ordre au moment de la création :

sage: C.<x,y,z> = PolynomialRing(QQ, order='lex')
sage: C
Multivariate Polynomial Ring in x, y, z over Rational Field
sage: C.term_order()
Lexicographic term order
sage: z < z^2 < x < x*y < x^2 
True

Il est aussi possible d’obtenir une copie d’un anneau avec un ordre différent :

sage: D = B.change_ring(order='invlex')
sage: D.term_order()
Inverse lexicographic term order
sage: D == B
False

Sage supporter quelques ordres prédéfinis : lex, invlex, degrevlex, … La liste complète peut être obtenue interactivement :

sage.rings.polynomial.term_order?

Il est possible de construire des ordres arbitraires grâce à la classe TermOrder. Il est par exemple possible de construire un ordre avec poids :

sage: t = TermOrder('wdegrevlex', (1,2,3)); t
Weighted degree reverse lexicographic term order with weights (1, 2, 3)
sage: E.<x,y,z> = PolynomialRing(QQ, order=t)
sage: x < y < x^2 < z < x*y < x^3 < y^2
True

Lire la documentation de TermOrder pour plus de détails.

Idéaux et bases de Gröbner

Sage sait calculer la division Euclidienne entre polynômes multivariés :

sage: A.<x,y> = QQ[]
sage: (x^2 - y) % (x + y)
x^2 + x
sage: (x^2 - y) // (x + y)
-1
sage: (x^2 - y).quo_rem(x + y)
(-1, x^2 + x)

Le résultat est bien évidemment dépendant de l’ordre choisi :

sage: (x^2 - y).quo_rem(x + y)
(-y + x, y^2 - y)

Le point de départ pour travailler avec les bases de Gröbner est la méthode .ideal() des anneaux de polynômes.

sage: A.<x,y,z> = QQ[]
sage: I = A.ideal(x^2 - y*z, x^3*y + 2*y*z - 4*z^2); I
Ideal (x^2 - y*z, x^3*y + 2*y*z - 4*z^2) of Multivariate Polynomial Ring in x, y, z
over Rational Field

Les idéaux ont une méthode .groebner_basis(), dont le résultat dépend bien évidemment de l’ordre choisi :

sage: I.groebner_basis()
[y^3*z^2 + 2*x*y*z - 4*x*z^2, x*y^2*z + 2*y*z - 4*z^2, x^2 - y*z]

C’est cette base qui est utilisée pour calculer les formes normales de polynômes modulo l’idéal. Les méthodes .mod (définie sur les polynômes) et .reduce (définie sur les idéaux et sur les polynômes), calculent la forme normale :

sage: (x^6*z - y*z^3 + x*z).mod(I)
-2*x*y*z^3 + 4*x*z^4 - y*z^3 + x*z
sage: I.reduce(x^6*z - y*z^3 + x*z)
-2*x*y*z^3 + 4*x*z^4 - y*z^3 + x*z
sage: (x^6*z - y*z^3 + x*z).reduce(I)
-2*x*y*z^3 + 4*x*z^4 - y*z^3 + x*z

Attention : les méthodes définies sur les polynômes se comportent différemment lorsqu’elles reçoivent en paramètre une liste de polynômes plutôt qu’un idéal.

sage: (x^6*z - y*z^3 + x*z).reduce([x^2 - y*z, x^3*y + 2*y*z - 4*z^2])
y^3*z^4 - y*z^3 + x*z
sage: (x^6*z - y*z^3 + x*z).mod([x^2 - y*z, x^3*y + 2*y*z - 4*z^2])
-2*x*y*z^3 + 4*x*z^4 - y*z^3 + x*z

De manière générale, préférez I.reduce en toute occasion.

Lorsque un polynôme appartient à l’idéal, la méthode lift permet de l’exprimer comme une combinaison linéaire de ses générateurs :

sage: p = 2*x^3*y^3 - x*y^4*z + 2*y^3*z - 4*y^2*z^2
sage: I.reduce(p)
0
sage: p.lift(I)
[x*y^3, y^2]
sage: _[0] * I.0 + _[1] * I.1 == p
True

Résultants et élimination

Le résultant de deux polynômes est calculé par la méthode .resultant()

sage: A.<x> = QQ[]
sage: (x^2+1).resultant(2*x)
4

Dans les anneaux à plusieurs variables, Sage élimine par défaut la première variable :

sage: A.<x,y,z> = QQ[]
sage: (x*y + z).resultant(x+z+y)
y^2 + y*z - z

Il est aussi possible d’indiquer la variable que l’on souhaite éliminer :

sage: (x*y + z).resultant(x+z+y, z)
-x*y + x + y

Des éliminations plus complexes peuvent être réalisées grâce aux bases de Gröbner, en effet on a déjà vu plus haut que Sage supporte le calcul de bases de Gröbner pour l’ordre lex, ce qui permet de calculer les idéaux d’élimination. Cette même fonctionnalité est encapsulée dans la méthode .elimination_ideal(), que voici à l’œuvre sur le même exemple :

sage: I = A.ideal(x*y + z, x+z+y)
sage: I.elimination_ideal(z)
Ideal (x*y - x - y) of Multivariate Polynomial Ring in x, y, z over Rational Field

.elimination_ideal() peut aussi prendre une liste de variables à éliminer :

sage: A.<w,x,y,z> = QQ[]
sage: I = A.ideal(x*y + w*z, x*z + w*y, x*w + y*z, x^2 + y^2 + z^2 + w^2)
sage: I.elimination_ideal([x,y]).gens()
[3*w^2*z + z^3, w^3 + 3*w*z^2, w*z^3, z^5]

Syntaxe Python/Sage

Variables, assignement

Python est un langage dynamiquement typé, les variables n’ont pas besoin d’être déclarées, et leur type peut changer au cours de l’exécution.

python: a = 3
python: type(a)
<type 'int'>
python: a = '3'
python: type(a)
<type 'str'>
python: a
'3'
python: int(a)
3

Syntaxe

L’indentation en python a une valeur syntaxique : elle sert à délimter les blocs. Toutes les lignes d’un même bloc doivent être précédées du même nombre d’espaces blancs ; en général on conseille d’utiliser 4 espaces blancs.

Voici un exemple de bloc conditionnel mettant en évidence cette syntaxe.

if a == 0:
    print 'a vaut 0'
elif a > 0:
    print 'a est positif'
    print 'il vaut %d' % a
else:
    print 'a est négatif'
print 'encore des questions sur a?'

Les retours à la ligne sont interdits en Python, sauf entre parenthèses (), crochets [], et accolades {}. L’exemple suivant est incorrect :

if a == b
   and c == d:
    print 'yes'

Alors que ceci est correct (et équivalent à la sémantique entendue):

if (a == b
    and c == d):
    print 'yes'

Structures de contrôle

Source : https://docs.python.org/2/tutorial/controlflow.html

if... else

La seule construction conditionnelle existante en Python est if... elif... else.... Toutes les branches sont optionnelles, à l’exception du if, il peut y avoir un nombre quelconque de elif, mais un seul else à la fin.

if a == b == c:
    print 'égaux'
elif a <= b <= c  or  c <= b <= a:
    print 'b au milieu'
elif b <= a <= c  or  c <= a <= b:
    print 'a au milieu'
else:
    print 'c au milieu'

Boucle for... in

Il existe deux types de boucles en Python. La plus couramment utilisée est le for... in qui permet de parcourir les éléments d’une liste.

for i in range(10):
    print i

La fonction range

La boucle for est souvent utilisée en conjonction avec la fonction range, dont la syntaxe générale est :

range(start, end, step)

Ainsi appelée, la fonction génère la liste des entiers entre start (inclus) et end (non inclus) avec pas de step :

python: range(0, 10, 2)
[0, 2, 4, 6, 8]

Les deux autres syntaxes admissibles sont range(start, end) (pas égal à 1) et range(end) (début égal à 0).

Note : À partir de Python 3.x, range ne renvoie plus une liste, mais un générateur. La différence réside exclusivement dans l’utilisation de la mémoire, beaucoup plus efficace avec la 3.x. Le même comportement est réalisé par la fonction xrange en Python 2.x.

Boucle while

La deuxième boucle est très similaire à la boucle while en C.

a = 0
while a < 10:
    a += 1
    print a

Pas étonnant qu’il soit alors beaucoup plus facile d’écrire une boucle infinie :

while True:
    print 'boucle toujours'

Interrompre les boucles: break, continue et return

Comme en C, l’instruction break sort de la boucle sans vérifier la condition :

for i in range(10):
    print i
    if i > 2:
        break

L’instruction continue passe à l’itération suivante en sautant le reste du corps :

for i in range(10):
    if i % 2 == 0:
        continue
    print i

Et le return sort immédiatement de toute boucle et de la fonction qui le contient.

Listes

Source : https://docs.python.org/2/tutorial/datastructures.html#more-on-lists

L’un des objets les plus utilisés en Python, ce sont les listes. On déclare une liste avec les crochets [], et on accède à ses éléments comme on accède aux éléments d’un tableau en C :

python: l = [1, 2, 'a', True]
python: l
[1, 2, 'a', True]
python: l[0]
1
python: l[3]
True
python: l[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

La syntaxe pour accéder aux éléments d’une liste est plus puissante en Python qu’en C. Les indices négatifs accèdent aux éléments à partir du dernier :

python: l[-1]
True
python: l[-4]
1
python: l[-5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

Il est aussi possible d’obtenir les sous-listes d’une liste avec une syntaxe qui rappelle les paramètres de la fonction range. L’expression l[start:end:step] donne la sous-liste de l qui démarre à l’élément start (inclus), se termine à l’élément end (exclus) et saute tous les step éléments. Chacun des composants peut être omis, il prendra alors une valeur par défaut (0 pour start, la longueur de la liste pour end, 1 pour step).

python: l = range(10)
python: l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
python: l[0:4]
[0, 1, 2, 3]
python: l[0:4:2]
[0, 2]
python: l[2:]
[2, 3, 4, 5, 6, 7, 8, 9]
python: l[:-3]
[0, 1, 2, 3, 4, 5, 6]
python: l[0::3]
[0, 3, 6, 9]
python: l[4:-2]
[4, 5, 6, 7]
python: l[::]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
python: l[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

La syntaxe [:] est un raccourci courant pour copier une liste :

python: l[:] == l
True
python: l[:] is l
False

Compréhensions

Python offre une syntaxe pour la création des listes qui devrait être familière aux mathématiciens. C’est un héritage du langage Lisp appelé compréhensions de listes :

python: [a + 0.5 for a in range(10)]
[0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]

ce qui est sémantiquement équivalent à

l = []
for a in range(10):
	l.append(a + 0.5)

On peut ajouter un nombre arbitraire de for et de if (sans else) dans une compréhension, ils seront déroulés dans l’ordre :

[x*y for x in range(10)
     for y in range(x)
     if (x + y) % 2 == 0]

(les retours à la ligne sont optionnels) est équivalent à

l = []
for x in range(10):
    for y in range(x):
        if (x + y) % 2 == 0:
            l.append(x*y)

Opérateurs fonctionnels sur les listes

Python définit quelques fonctions typiques des langages fonctionnels pour traiter efficacement une liste. Les plus importantes sont map, filter, et reduce ; elles laissent inchangée la liste d’origine.

map applique une fonction à chaque élément d’une liste et renvoie la liste des résultats. Dans l’exemple ci-dessous, hex est la fonction qui renvoie la représentation hexadécimale d’un entier :

python: map(hex, range(10,20))
['0xa', '0xb', '0xc', '0xd', '0xe', '0xf', '0x10', '0x11', '0x12', '0x13']

filter applique une fonction à chaque élément d’une liste et renvoie la liste des éléments pour lesquels la fonction à donné True. L’exemple suivant utilise la fonction is_prime de Sage, qui teste la primalité de son paramètre :

sage: filter(is_prime, range(20))
[2, 3, 5, 7, 11, 13, 17, 19]

reduce parcourt la liste de gauche à droite. Le résultat de chaque itération est obtenu en appliquant une fonction bivariée au résultat de l’itération précédente et à l’élément courant. Dans l’exemple suivant, reduce calcule la somme des entiers de 0 à 9 ; la fonction standard operator.add est l’équivalent de l’opérateur + :

python: import operator
python: reduce(operator.add, range(10))
45

À partir de l’opérateur reduce, il est facile de définir quelques autres fonctions très utiles : sum, all, any, max, min, join. Vous êtes invités à en lire la documentation.

Fonctions

Source : https://docs.python.org/2/tutorial/controlflow.html

Les fonctions Python sont définies par le mot clef def. Elles peuvent prendre un nombre arbitraire de paramètres, et renvoyent une valeur à l’aide du mot clef return. Toute fonction renvoye une valeur, les fonctions qui n’ont pas de return renvoient la valeur spéciale None.

def max(x, y):
    if x > y:
        return x
    else:
        return y

Certains paramètres peuvent prendre des valeurs par défaut. Si un paramètre prend une valeur par défaut, tous ceux qui le suivent doivent aussi en prendre.

python: def test(a, b, c=0, d=False):
.......    return a, b, c, d

python: test(1, 2)
(1, 2, 0, False)
python: test(1, 2, 3)
(1, 2, 3, False)
python: test(1, 2, 3, 4)
(1, 2, 3, 4)
python: test(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: test() takes at least 2 arguments (1 given)

Les paramètres d’une fonction peuvent être assignés hors ordre avec la notation paramètre=valeur :

python: test(b=1, a=2)
(2, 1, 0, False)
python: test(1, 2, d=4)
(1, 2, 0, 4)

Python fournit deux opérateurs unaires pour transformer des objets en paramètres d’une fonction. L’opérateur * transforme une liste ou un tuple, tandis que l’opérateur ** transforme un dictionnaire :

python: l = range(4)
python: test(*a)
(0, 1, 2, 3)
python: d = { 'a' : 3, 'b' : 5, 'd' : 1 }
python: test(**d)
(3, 5, 0, 1)

La hyérarchie des types en Sage

Parents et éléments

Beaucoup de structures algèbriques en Sage sont organisées autour du concept de parent-élément.

Par exemple, un anneau de polynômes est un parent, à qui appartiennent des éléments. La majorité des valeurs en Sage possède un parent, qu’on peut interroger avec la méthode parent() :

sage: 1.parent()
Integer Ring
sage: (1/2).parent()
Rational Field
sage: (0.5).parent()
Real Field with 53 bits of precision

Attention, beaucoup de noms prédéfinis appartiennent à l’anneau symbolique, même si l’on pourrait imaginer qu’ils appartiennent à un parent plus spécifique (réels, complexes, …).

sage: i.parent()
Symbolic Ring
sage: pi.parent()
Symbolic Ring
sage: x.parent()
Symbolic Ring

Sage connaît un bon nombre de coercitions automatiques, qui permettent de faire des opérations sur des éléments de parents différents.

sage: A.<x> = QQ[]
sage: x.parent()
Univariate Polynomial Ring in x over Rational Field
sage: 2.parent()
Integer Ring
sage: (2+x).parent()
Univariate Polynomial Ring in x over Rational Field

Parfois Sage ne sait pas trouver de coercition canonique, dans ce cas il donne une erreur :

sage: a = GF(7)(2); a
2
sage: a.parent()
Finite Field of size 7
sage: x + a
...
TypeError: unsupported operand parent(s) for '+': 'Univariate Polynomial Ring in
x over Rational Field' and 'Finite Field of size 7'

Il est possible dans ces cas de convertir un élément en l’associant à un nouveau parent, Sage appliquera alors d’autres règles, dites de conversion, qui ne doivent pas être canoniques. Toutes les conversions prennent la forme de parent(élément).

sage: x + QQ(a)
x + 2
sage: _.parent()
Univariate Polynomial Ring in x over Rational Field

Observons cela sur un exemple simple. Il existe un morphisme canonique de vers , Sage peut alors additionner deux éléments appartenant à ces deux parents, et le résultat sera un élément de .

sage: a = Zmod(10)(2)
sage: a.parent()
Ring of integers modulo 10
sage: 11.parent()
Integer Ring
sage: 11 + a
3
sage: _.parent()
Ring of integers modulo 10

Le lift d’un élément de vers n’a rien de canonique, mais il est tout de même convenable d’appliquer cette conversion lorsque elle est demandée par l’utilisateur :

sage: QQ(a).parent()
Rational Field
sage: 11 + QQ(a)
13

De façon similaire, il n’existe pas de morphisme naturel de vers . Sage donne donc correctement une erreur ici :

sage: 1/3 + a
...
TypeError: unsupported operand parent(s) for '+': 'Rational Field' and 'Ring of
integers modulo 10'

Mais, puisque 3 est inversible modulo 10, il est tout de même possible de donner un sens à cette conversion :

sage: Zmod(10)(1/3) + a
9

Base

Beaucoup de structures algèbriques en Sage ont une base. Par exemple, les anneaux de polynômes ont pour base leur anneau de coefficients.

sage: A.<x> = GF(7)[]
sage: A.base()
Finite Field of size 7
sage: A.base_ring()
Finite Field of size 7

Sage considère aussi les bases lorsque il cherche à trouver une coercition entre deux éléments. Dans cet exemple, x est un polynôme à coefficients dans , alors que 10 est un entier. Au moment de la coercition, Sage transforme 10 en un élément de , puis le en un élément de .

sage: 10.parent()
Integer Ring
sage: x + 10
x + 3
sage: _.parent()
Univariate Polynomial Ring in x over Finite Field of size 7

Il est possible d’obtenir une copie d’un anneau avec une base différente grâce à la méthode change_ring() :

sage: B = A.change_ring(QQ); B
Univariate Polynomial Ring in x over Rational Field
sage: B(x)
x
sage: B(x).parent()
Univariate Polynomial Ring in x over Rational Field
sage: x.parent()
Univariate Polynomial Ring in x over Finite Field of size 7

Classes, types

Chaque objet mathématique est représenté par une classe Python. L’opérateur Python type permet d’interroger la classe d’un objet :

sage: type(1)
<type 'sage.rings.integer.Integer'>

Souvent, différentes classes Python réalisent le même objet mathématique, ce qui permet d’avoir plusieurs implantations pour un même objet. Cela est particulièrement évident pour les corps finis, où différents sous-systèmes sont choisis selon la cardinalité.

sage: A.<x> = GF(2)[]
sage: B.<y> = GF(3)[]
sage: C.<z> = GF(3^2,'a')[]
sage: type(x)
<type 'sage.rings.polynomial.polynomial_gf2x.Polynomial_GF2X'>
sage: type(y)
<type 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'>
sage: type(z)
<type 'sage.rings.polynomial.polynomial_zz_pex.Polynomial_ZZ_pEX'>

Voici un autre exemple où deux classes différentes réalisent le même objet mathématique, mais avec un code différent :

sage: A = matrix([[1,1],[1,1]])
sage: B = matrix([[1,1],[1,1]], sparse=True)
sage: A == B
True
sage: type(A)
<type 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>
sage: type(B)
<type 'sage.matrix.matrix_integer_sparse.Matrix_integer_sparse'>

Tracer des courbes et des surfaces en Sage

Source: Sage Tutorial

Beaucoup d’objets en Sage peuvent être tracés :

sage: plot(cos)   # Affiche la fonction cosinus entre -1 et 1

sage: plot(cos, -5, 5)  # même fonction entre -5 et 5

La majorité des objets sont tracés par la fonction plot(), mais beaucoup disposent aussi d’une méthode plus spécifique .plot() attachée à l’objet, qui peut donner accès à plus d’options :

sage: A.<x,y,z> = QQ[]
sage: C = Curve(x^3 + y^3 + x*z^2)
sage: plot(C)    # Affiche la courbe C

sage: C.plot()   # Affiche la même courbe

sage: C.plot(patch=0)  # Affiche la même courbe dans une carte affine différente

Les plots sont des objets, qu’on peut stocker, copier…

sage: a = C.plot()
sage: a.set_aspect_ratio(2.0)
sage: a

et même additionner, le résultat étant la superposition de plusieurs plots.

sage: C.plot(patch=0) + C.plot(patch=1) + a

Tracés implicites et paramétriques

Le lieu d’annulation d’un polynôme à deux variables est tracé par la fonction implicit_plot(). Cette fonction prend en argument le polynôme à tracer et des bornes sur les axes sous forme de tuples :

sage: A.<x,y> = QQ[]
sage: implicit_plot(x*y - 1, (x, -10, 10), (y, -10, 10))

Il est important que le polynôme appartienne à un anneau bivarié, faute de quoi, Sage va donner une erreur :

sage: A.<x,y,z> = QQ[]
sage: implicit_plot(x*y -1, (x, -10, 10), (y, -10, 10))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
...
ValueError: Variable 'z' not found

La fonction implicit_plot3d() a les mêmes conventions d’appel et permet de tracer des surfaces dans un espace à trois dimensions.

sage: implicit_plot3d(x*y*z - 1, (x,-10,10), (y,-10,10), (z,-10,10))

La fonction parametric_plot() permet de tracer des courbes ou des surfaces paramétriques dans un espace à deux ou trois dimensions. Dans ce sens, il s’agit d’une forme plus générale de plot(cos).

sage: var('a,b')
(a, b)
sage: parametric_plot([cos(a), sin(a)], (a,-pi,pi))

sage: parametric_plot([cos(a), cos(a*b), sin(a)], (a,-pi,pi), (b,-pi,pi))

Fork me on GitHub