Cours gratuits » Cours informatique » Cours développement web » Cours Ruby » Cours complet pour apprendre Ruby

Cours complet pour apprendre Ruby


Télécharger



★★★★★★★★★★5 étoiles sur 5 basé sur 2 votes.
5 stars
2 votes

Votez ce document:

Cours complet pour apprendre Ruby

...

Nombres entiers en Python

Les nombres entiers ne sont pas les seuls nombres, comme on le verra dans les chapitres suivants. Alors comment fait Python pour savoir qu'un nombre est entier? Comme le langage est faiblement typé, il doit le deviner. Le critère est simple: Pour qu'un nombre soit entier, il ne doit pas avoir de virgule (représentée dans Python par un point décimal).

a=3 print(type(a)) b=3.14 print(type(b)) c=int(b) print(c)

on constate que Python sait que a est en

tier, que b ne l'est pas, et que c peut être entier bien qu'obtenu à partir de b (qui est réel).

Certains calculs devant donner un résultat entier ne le font pas toujours en Python. Par exemple, alors que , Python considère ce nombre comme un réel (non entier)!

from math import * a=sqrt(100)

print(a.is_integer())

Opérations

Addition, soustraction et multiplication

Les trois premières opérations se notent avec les symboles +, - et * comme dans la plupart des langages de programmation. La somme, la différence et le produit de deux entiers (ou plus) sont des entiers (relatifs):

a=5

b=-8 print(a+b) print(a-b) print(a*b)

La tortue

On peut représenter l'addition par des mouvements successifs de la tortue. Pour cela il faut bien entendu importer le module turtle. Après ça pour additionner 55 et 34, on peut faire avancer la tortue successivement de 55 pixels puis 34 pixels, et regarder où elle est:

from turtle import * forward(55) forward(34) print(position())

Pour soustraire le deuxième nombre au lieu de l'additionner, il suffit de faire reculer la tortue au lieu de la faire avancer; et ça marche même avec des nombres négatifs:

from turtle import * forward(55) backward(-34) print(position())

Divisions

Il y a deux sortes de divisions d'entiers en Python: Le quotient euclidien, qui est un entier, et le quotient exact, qui est une fraction (pour Python, un réel):

Quotients

Dans les anciennes versions de Python, le script suivant

a=3 b=2

print(a/b)

affichait 1 au lieu de 1.5, parce que pour Python, comme a et b sont entiers, leur quotient était logiquement euclidien. Ceci a changé, maintenant le script ci-dessus produit bien 1.5; mais du coup, si par hasard on voulait quand même calculer une division euclidienne avec Python? Et bien dans ce cas il faudrait dédoubler le slash qui code la division:

a=3 b=2

print(a//b)

Ce peut être utile parce que même en divisant 4 par 2, le résultat est un réel non entier, alors que la division euclidienne produit bien le nombre entier 2.

Reste euclidien

Le reste de la division euclidienne de 13 par 8 est 5. Pour le calculer, on utilise l'opérateur infixé %:

a=13 b=8

print(aob)

Cette opération permet de travailler sur les congruences. Remarque: Si b=0, on a le même message d'erreur que lorsqu'on divise par 0.

Divisibilité

Deux entiers quelconques on un pgcd. En Python, on l'obtient avec gcd. Mais cette fonction ne se trouve pas par défaut dans Python; elle se trouve dans le fichier fractions.py, dont on peut importer la totalité des objets par from fractions import *:

a=13572468

b=12345678

print(gcd(a,b))

Comme Python est libre, on peut consulter le source de fractions.py, où on trouve ceci:

def gcd(a, b): while b:

a, b = b, aob return a

On reconnaît (d'autant plus aisément que le langage est concis) l'algorithme d'Euclide.

Puissances

Beaucoup de langages de programmation utilisent le chapeau pour représenter les puissances. Pas Python pour qui le chapeau est déjà pris par une autre opération (le ou exclusif bit à bit). Alors c'est l'astérisque de la multiplication qui est utilisé pour les puissances, mais en le dédoublant:

a=4

b=2

print(a**b) print(b**a)

Remarque: Si l'exposant est négatif ou non entier, le résultat est un réel. En particulier, les deux opérations ci-dessous ont le même effet:

print(100**0.5)

from math import * print(sqrt(100))

Priorités opératoires

En Python comme en algèbre, on effectue dans l'ordre

  1. Les parenthèses
  2. Les fonctions (comme l'0l0vation à une puissance)
  3. Les multiplications et divisions
  4. Les additions et soustractions.

Ainsi

print(2+3*5)

affiche 17 et non 25: Les op0rations ne sont pas effectu0es de gauche à droite, mais en suivant les priorit0s op0ratoires.

Itérateurs

Un it0rateur de Python est une liste d'entiers. Par exemple, la liste 10, 13, 16, 19, 22, 25 (allant de 3 en 3, de 10 jusqu'à 25) s'appelle range(10,26,3). On peut abr0ger les it0rateurs en omettant le troisième argument (par d0faut 1) voire le premier (par d0faut 0). Ainsi range(5) contient les entiers 0, 1, 2, 3 et 4 (0 compris, 5 non compris, ce sont donc bien les 5 premiers entiers naturels).

Lorsqu'on lance un d0, le r0sultat obtenu peut être 1, 2, 3, 4, 5 ou 6. Il peut donc être d0crit par range(1,7). Pour v0rifier que l'0vènement "le d0 tombe sur 3" est possible alors que l'0vènement "le d0 tombe sur 7" est impossible, on peut faire

dice=range(1,7) print(3 in dice) print(7 in dice)

 Fractions en Python

 L'écriture de nombres non entiers sous forme de fractions a de loin précédé celle des nombres décimaux, puisque les égyptiens et les babyloniens les utilisaient déjà. Chaque fois que le dénominateur n'est pas une puissance de 10, on continue encore de nos jours à utiliser des écritures fractionnaires plus ou moins cachées, comme dans les exemples suivants:

  1. Lorsqu'on dit qu'un homme mesure 5 pieds 7 pouces, ça signifie que sa taille, en pieds, est (il y a douze pouces dans

un pied);

  1. Lorsqu'on dit qu'il est 8 heures 13, c'est que depuis minuit, il est passé exactement heures (soit

493 minutes).

  1. Lorsque Roméo se plaint d'avoir attendu Juliette pendant plus de trois quarts-d'heure, il exprime la durée de son attente insoutenable sous la forme d'une fraction...
  2. Les probabilités se donnent aussi souvent sous forme de fractions (le plus souvent des fractions égyptiennes). Comme dans "j'ai une chance sur 10 millions de recevoir une météorite sur la tête" ou "Casaque Jaune est donné favori à 5 contre 1".
  3. Idem parfois pour les statistiques: "5 Français sur 7 estiment qu'il y a trop de sondages sur les sondages"...

L'égalité 0,2+0,5=0,7 peut s'écrire mais l'égalité ne peut pas s'écrire sous forme décimale exacte parce que le résultat n'est pas décimal. Python affiche 1/2+1/3=0.8333333333333333 et malgré l'abondance de chiffres, cette égalité n'est pas exacte.

Pour faire des calculs exacts avec des fractions, Python a un module fractions.py. Pour transformer Python en un langage de programmation spécialisé dans les fractions, il suffit de précéder les scripts de ce chapitre de la ligne

from fractions import *

qui importe le module fractions en entier (pourquoi faire dans le détail?). Une alternative est de chercher le fichier __init__.py, initialement vide, et d'y mettre la ligne précédente.

Obtention d'une fraction

 Pour entrer la fraction dans Python, on entre Fraction(n,d) non sans avoir importé le module fractions:

from fractions import * a=Fraction(24,10) print(a)

On constate que la fraction a été automatiquement simplifiée par Python au moment de son instanciation.

Si on entre 0 comme dénominateur, la fraction ne se crée pas et on a un message d'erreur: Comme une fraction est un quotient, on ne peut pas diviser par 0.

Une fois qu'une fraction est calculée, on peut obtenir son numérateur et son dénominateur par

from fractions import * a=Fraction(24,10) print(a.numerator) print(a.denominator)

Bien entendu, le numérateur de n'est pas 24...

Pour obtenir la valeur de la fraction (le quotient de son numérateur par son dénominateur), on peut lui additionner 0.0: La somme d'une fraction et d'un réel, même nul, est un réel.

from fractions import * a=Fraction(24,10) print(a+0.0)

Réciproquement, on peut convertir un nombre réel en fraction, mais le résultat est parfois surprenant, si on prend un nombre dont le développement décimal s'arrête alors que le développement binaire ne le fait pas:

from fractions import * a=Fraction.from_float(1.2) print(a)

Opérations

Les opérations sur les fractions se notent comme celles sur les autres nombres, mais en général le résultat est une fraction.

Opérations unaires

Opposé

L'opposée d'une fraction s'obtient en la faisant précéder du signe -. Par exemple, la fraction suivante est positive:

from fractions import * a=Fraction(2,-3) print(-a)

Inverse

Pour obtenir l'inverse d'une fraction, on divise 1 par celle-ci:

from fractions import * a=Fraction(5,4) print(1/a)

Addition

La somme de deux fractions est une fraction:

from fractions import * a=Fraction(34,21) b=Fraction(21,13)

print(a+b)

Soustraction

La différence de deux fractions est une fraction:

from fractions import * a=Fraction(34,21) b=Fraction(21,13) print(a-b)

Multiplication

Le produit de deux fractions est une fraction:

from fractions import * a=Fraction(34,21) b=Fraction(21,13) print(a*b)

Division

Le quotient de deux fractions est une fraction (à condition que la deuxième ne soit pas nulle):

from fractions import * a=Fraction(34,21) b=Fraction(21,13) print(a/b)

Le reste euclidien continue à être défini pour des fractions, et le résultat est une fraction:

from fractions import * a=Fraction(32,7) b=Fraction(7,2) print(a%b)

Puissance

Si l'exposant est entier, la puissance d'une fraction est une fraction:

from fractions import * a=Fraction(3,2) print(a**12) print(a**(-1))

Mais si l'exposant est un réel, la puissance n'est pas une fraction mais un réel:

from fractions import * a=Fraction(9,4) print(a**0.5)

 Algorithmes Réduite de Farey

La création de réduite de Farey est aisée avec le module fractions de Python:

from fractions import *

def Farey(a,b):

n=a.numerator+b.numerator

d=a.denominator+b.denominator return Fraction(n,d)

a=Fraction(3,4) b=Fraction(1,13) print(Farey(a,b))

C'est si facile qu'on en vient tout de suite à la question suivante : à quoi ça peut bien servir ?

Si on répond que ça sert à fabriquer un arbre de Stern-Brocot, ça n'éclaire peut-être pas beaucoup, mais disons que ça sert à quelque chose de mathématique...

Fractions égyptiennes

Une fraction égyptienne est définie comme une somme d'inverses d'entiers. En effet les égyptiens avaient la réputation de ne pas utiliser de numérateurs. Toute fraction peut s'écrire comme une somme de fractions égyptiennes, et l'algorithme de Fibonacci permet d'en trouver un exemple à partir de la fraction. Dans la version Python ci-dessous, l'algorithme fournit une liste de fractions, toutes de numérateur 1, dont la somme est une fraction donnée f. Mais au cas où f serait supérieure à 1, on commence la liste par un entier:

from fractions import * from math import *

def egypt(f):

e=int(f)

f-=e

liste=[e]

while(f.numerator>1):

e=Fraction(1,int(ceil(1/f)))

liste.append(e)

f-=e

liste.append(f)

return liste

a=Fraction(21,13) print(egypt(a))

Quelques explications sur le bricolage ci-dessus: Le dénominateur d'une fraction égyptienne est choisi entier (bien sûr) et plus grand que l'inverse de la fraction f (pour que l'algorithme converge). Une solution serait de prendre la troncature int de l'inverse de f et ajouter 1. Mais si l'inverse de f est entier, on ne doit pas ajouter 1 (sinon la suite est infinie). Alors on utilise la fonction ceil. Donc

  1. Il a fallu importer le module math qui contient cette fonction ceil;
  2. Du coup l'objet ceil(1/f) n'est plus un entier mais un réel, et ne peut plus être le dénominateur d'une fraction (message d'erreur de Python). Alors il faut convertir ce réel (qui est déjà entier, mais Python ne le sait pas) en entier, ce qui se fait par int.

Enfin, Python ne possédant pas de boucle do..while, il faut ajouter la dernière fraction égyptienne à la liste, pour que celle-ci soit complète.

Nombres réels en Python

Écriture décimale

Si les fractions paraissent si abstraites, c'est sans doute à cause de l'écriture décimale qui est jugée plus concrète que l'écriture fractionnaire.

Nombres décimaux

Un nombre décimal est un nombre dont le développement décimal s'arrête. Un nombre non décimal (comme les premiers réels connus qui ne soient pas des fractions) a donc une infinité de chiffres, et ne peut donc pas être représenté de façon exacte en machine: On est obligé de travailler sur des approximations. Mais même avec des nombres décimaux, on travaille parfois sur des valeurs approchées: En effet les nombres sont représentés en base 2 dans la mémoire de l'ordinateur, et Python ne gère que les nombres binaires, ce que n'est pas 0,1.

Fractions

Une fraction se reconnaît à ce que son développement décimal est périodique à partir d'un certain rang.

print(1/3) print(1/9) print(1/11) print(1/13)

(ces illustrations nécessitent la version 3.2 de Python. En cas de version inférieure, il faut remplacer les numérateurs

par des 1.0 pour que la division se fasse dans ).

Pour mieux voir ces chiffres, on peut en afficher plus:

from decimal import *

print(Decimal(1)/Decimal(3))

print(Decimal(1)/Decimal(9)) print(Decimal(1)/Decimal(11)) print(Decimal(1)/Decimal(13))

Irrationnels

Pour "construire" un nombre irrationnel (un réel qui ne soit pas une fraction), on peut donc inventer une suite de chiffres qui ne risque pas d'être répétitive, comme avec la constante de Champernowne ou un autre nombre univers.

Nombres algébriques

Le plus vieil irrationnel connu est sans doute la racine carrée de 2:

print(2**0.5)

#autre version: from math import * print(sqrt(2))

D'autres connus depuis longtemps sont le nombre d'or, la racine cubique de 2, etc. Les nombres algébriques sont définis comme solutions d'équations polynomiales, donc leurs valeurs décimales approchées sont calculées avec des méthodes comme la dichotomie, la méthode de Newton etc.

Nombres transcendants

Deux nombres transcendants très connus sont e et :

from math import * print(e)

print(pi)

Voici une manière de calculer une valeur approchée du nombre de Champernowne en Python:

c='0.'

for n in range(1,40): c+=str(n)

print(float(c))

Exercice pour un premier avril: Calculer une valeur approchée à 3 décimales près de la constante de Chaitin...

Fonctions réelles Opérations

Les quatre opérations sont notées +, -, * et / en Python, et leur résultat (sauf si on divise par 0) est un réel. On peut aussi calculer le reste euclidien d'un réel par un réel!

from math import * angle=100%pi print(angle)

Le signe - désigne aussi l'opposé d'un réel. Sa valeur absolue est notée abs. Sa racine carrée sqrt. Pour additionner h au nombre x, on peut écrire x+=h au lieu du classique x=x+h.

Puissances, exponentielles et logarithmes Puissances et exposants

Comme pour les entiers, les puissances se notent avec l'astérisque de la multiplication, dédoublé. L'exemple du haut de la page montre comment ceci permet de calculer sans utiliser le module math.

Logarithmes

Le script ci-dessous calcule et affiche l'image de 0,5 par le logarithme népérien, par le logarithme décimal, par les fonctions réciproques du cosinus hyperbolique, du sinus hyperbolique, de la tangente hyperbolique:

print(log(0.5)) print(log10(0.5)) print(acosh(0.5)) print(asinh(0.5)) print(atanh(0.5))

Exponentielles

Pour calculer une puissance de 10, on peut utiliser la notation **. Pour calculer l'exponentielle d'un nombre, on peut utiliser exp:

from math import * a=e**pi

b=exp(pi) print(a==b) print(a-b)

Le script suivant calcule les cosinus, sinus et tangente hyperbolique de 2:

from math import * print(cosh(2)) print(sinh(2)) print(tanh(2))

Fonctions trigonométriques

On peut convertir des angles de radians en degrés et vice-versa avec degrees(x) et radians(x). Les fonctions trigonométriques directes se notent cos, sin et tan et ces trois fonctions sont en radians. Les fonctions inverses se notent acos, asin et atan et sont aussi en radians.

On peut calculer la fonction de deux variables   avec hypot:

from math import * a=sqrt(3**2+4**2) b=hypot(3,4) print(a==b)

Pour connaître l'angle aigu d'un triangle de côtés x et y, on peut, outre le calcul atan(y/x), faire atan2(x,y). Par exemple, si on veut connaître les angles et l'hypoténuse d'un triangle rectangle de côtés 12 cm et 5 cm, on peut utiliser ce script:

from math import * a=12

b=5 print(degrees(atan2(a,b))) print(degrees(atan2(b,a))) print(hypot(a,b))

Nombres complexes en Python

Python est un langage très utilisé dans le domaine scientifique, comme le montre par exemple le choix de SAGE. Et les sciences, en particulier, font grand usage des nombres complexes, essentiellement depuis leur choix par Cauchy. Les physiciens et les électriciens notant j le nombre complexe dont le carré vaut -1, Python suit ce choix.

Instanciation d'un nombre complexe

Dans Python, il suffit d'écrire complex(x,y) pour avoir un nombre complexe:  

z=complex(4,3) print(z)

Même si les coordonnées x et y du point sont entières ou des fractions, elles deviennent des réels lorsque Python instancie le complexe. Voir les propriétés du complexe ci-dessous pour le vérifier.

Si on veut quand même que la lettre i désigne le complexe de carré -1, il suffit de le déclarer comme tel:

i=complex(0,1) print(i**2)

Opérations

Les quatre opérations se notent respectivement +, -, * et /, et donnent toujours un complexe, même si celui-ci est réel (exemple de la soustraction ci-dessous):

a=complex(2,3) b=complex(4,3) print(a+b) print(a-b) print(a*b) print(a/b)

L'élévation à un exposant se note de la même manière que pour les autres nombres, par **. Mais l'exposant peut même être un complexe!

i=complex(0,1) print(i**i)

On constate que   ...

La racine carrée d'un complexe peut aussi s'obtenir par une élévation de celui-ci à la puissance 0,5 mais dans ce cas on n'obtient qu'une seule des deux racines carrées:

c=complex(7,24) print(c**0.5)

Mais -4-3i a aussi pour carré 7+24i. Comment fait Python pour choisir entre les deux racines carrées?

Même -1 a deux racines carrées dans , et comme on s'en doute, Python ne choisit pas -i mais i... ou plutôt un

complexe proche de celui-ci:

print((-1)**0.5)

Propriétés d'un nombre complexe

Les parties réelle et imaginaire d'un complexe sont des propriétés de l'objet:

z=complex(4,3) print(z.real) print(z.imag)

Par contre, le conjugué d'un complexe est une méthode de celui-ci:

z=complex(4,3)

print(z.conjugate())

(on remarque la présence des parenthèses après conjugate)

Forme trigonométrique

Pour avoir le module d'un nombre complexe, on entre abs:

z=complex(4,3) print(abs(z))

Bien entendu, le résultat est réel.

Cependant, pour avoir l'argument de a, il faut charger le module (c'est le cas de le dire!) cmath:

from cmath import * z=complex(4,3) print(phase(z))

On remarque que Python utilise le mot phase et non le mot argument. cmath permet aussi de calculer d'un coup le module et l'argument d'un nombre complexe avec polar:

from cmath import * z=complex(4,3) print(polar(z))

Pour réaliser l'opération inverse (calculer l'exponentielle d'un nombre imaginaire), on utilise rect:

from cmath import * print(rect(2,pi/3))

Par exemple, si on veut calculer le plus petit angle et l'hypoténuse d'un triangle rectangle de côtés 12 cm et 5 cm, on peut faire ceci:

from cmath import * a=12

b=5

z=complex(a,b) print(phase(z)) print(abs(z))

Fonctions

Avec cmath, on peut appliquer certaines fonctions de la variable réelle à des complexes.

Exponentielles

Pour vérifier numériquement que   , on peut utiliser l'exponentielle d'un nombre complexe (en

l'occurence, imaginaire):

from cmath import * t=complex(0,pi/3) z=exp(t) print(z.real==0.5) print(z.real-0.5) print(z.imag==sqrt(3)/2)

On voit que la partie réelle n'est pas tout-à-fait égale à 0,5 (la différence est minime mais non nulle), c'est encore une conséquence de la représentation binaire des nombres en machine, puisque le développement binaire de 0,5 est infini, contrairement à son développement décimal.

Le script suivant calcule et affiche les fonctions trigonométriques hyperboliques d'un complexe:

from cmath import * z=complex(4,3) print(cosh(z)) print(sinh(z)) print(tanh(z))

Logarithmes

On peut même calculer le logarithme d'un nombre complexe:

Le script suivant calcule et affiche les fonctions trigonométriques hyperboliques d'un complexe:

from cmath import * z=complex(4,3) print(log(z))

Le script suivant calcule et affiche les arguments des fonctions trigonométriques hyperboliques d'un complexe:

from cmath import * z=complex(4,3) print(acosh(z)) print(asinh(z)) print(atanh(z))

Fonctions trigonométriques

Directes

Le script suivant calcule et affiche les fonctions trigonométriques d'un complexe:

from cmath import * z=complex(4,3) print(cos(z)) print(sin(z)) print(tan(z))

Inverses

Le script suivant calcule et affiche les arcs des fonctions trigonométriques d'un complexe:

from cmath import * z=complex(4,3) print(acos(z)) print(asin(z)) print(atan(z))

Quaternions et octonions en Python

Complexes

On a vu dans le chapitre précédent que pour Python, un nombre complexe z est essentiellement une structure abritant deux réels, accessibles par z.real et z.imag respectivement. La construction de Cayley-Dickson généralise ce point de vue: En prenant deux complexes a et b, on peut les regrouper dans une nouvelle structure qui est considérée comme un nombre: Un quaternion.

Pour toute la suite, il est conseillé d'importer les fonctions du module math de Python:

from math import *

Mais en réalité, seule la méthode hypot sera utilisée, ce qui signifie que le minimum nécessaire était

from math import hypot

Quaternions Définition

Toutes les méthodes (qui permettent de manipuler les quaternions) peuvent être regroupées dans une classe nommée Quaternion:

class Quaternion:

def __init__(self,a,b): self.a=a self.b=b

La première méthode, l'initialisation, crée donc deux variables a et b (qui seront des complexes, mais Python ne le sait pas encore) et les rendre accessibles par la notation avec un point, les nombres q.a et q.b (les deux complexes qui définissent le quaternion q) étant des propriétés du quaternion.

Affichage

Pour y voir quelque chose, une méthode d'affichage est nécessaire. Comme Python en possède déjà une (la conversion en chaîne de caractères, ou string, notée __str__), on va la surcharger:

def __str__(self):

aff='('

aff+=str(self.a.real)+')+(' aff+=str(self.a.imag)+')i+(' aff+=str(self.b.real)+')j+(' aff+=str(self.b.imag)+')k' return aff

Un quaternion possède deux propriétés qui sont des nombres complexes, mais chacun d'eux est formé de deux nombres réels, donc un quaternion est formé de 4 nombres réels, ce sont ceux qui sont affichés par la méthode ci-dessus, lorsqu'on entre par exemple print(q).

Fonctions

Opposé

def __neg__(self):

return Quaternion(-self.a,-self.b)

En écrivant -q, on aura désormais l'opposé de q.

Module

def __abs__(self):

return hypot(abs(self.a),abs(self.b))

Grâce à cette méthode, abs(q) retourne un réel, la racine carrée de sa norme.

Conjugué

def conjugate(self):

return Quaternion(self.a.conjugate(),-self.b)

abs(q.conjugate()) renvoie le même résultat que abs(q) parce que tout quaternion a la même norme que son conjugué.

Opérations

Addition

Pour additionner deux quaternions, on additionne leurs a respectifs, et leurs b respectifs:

def __add__(self,other):

return Quaternion(self.a+other.a,self.b+other.b)

Soustraction

def __sub__(self,other):

return Quaternion(self.a-other.a,self.b-other.b)

Multiplication

Le produit de deux quaternions est plus difficile à définir:

def __mul__(self,other):

c=self.a*other.a-self.b*other.b.conjugate() d=self.a*other.b+self.b*other.a.conjugate() return Quaternion(c,d)

Ce produit admet le quaternion Quaternion(1,0) comme élément neutre, et il est associatif comme tout produit qui se respecte. Mais il n'est pas commutatif:

p=Quaternion(-2+1J,2+3J) q=Quaternion(3-2J,5+1J) print(p*q)

print(q*p)

Division

Multiplication par un réel

Pour définir le plus facilement possible le quotient de deux quaternions, on a intérêt 0 définir le produit d'un quaternion par un réel (on peut déj0 l'effectuer avec la méthode de produit, en assimilant le réel r avec la quaternion Quaternion(r,0)). Mais comme le symbole de multiplication est déj0 utilisé pour la multiplication des quaternions, il en faut un autre pour la multiplication d'un quaternion par un réel. Or il se trouve que __rmul__ (multiplication 0 l'envers) est encore disponible, donc pour peu qu'on multiplie 0 droite dans la définition, et 0 gauche en pratique, on peut ajouter cette méthode:

def __rmul__(self,k):

return Quaternion(self.a*k,self.b*k)

Alors, pour tripler un quaternion q, on peut faire, au choix, q*Quaternion(3,0), ou 3*q.

Division

Le quotient de deux quaternions est désormais simple 0 définir:

def __div__(self,other):

return self.conjugate()*(1./abs(other)**2*other)

Le quotient d'un quaternion par son conjugué est de norme 1:

p=Quaternion(-2+1J,2+3J) print(p/p.conjugate())

Puissances

Même si la multiplication des quaternions n'est pas commutative, elle est associative, c'est tout ce qu'il faut pour définir les puissances des quaternions 0 exposants entiers (et donc, par formules de Taylor, de la trigonométrie et des exponentielles de quaternions):

def  pow__(self,n):

r=1

for i in range(n): r=r*self return r

Par exemple, on peut calculer le carré d'un quaternion:

q=Quaternion(2J/7,(3+6J)/7) print(q**2)

Plus généralement, l'ensemble des solutions de   est une sphère.

L'étude des itérés de où q et c sont des quaternions, mène 0 des ensembles de Mandelbrot quaternionniques

([1])

Résumé

Voici le contenu complet de la classe Quaternion de Python:

from math import hypot class Quaternion:

def __init__(self,a,b): self.a=a self.b=b

def __str__(self):

aff='('

aff+=str(self.a.real)+')+(' aff+=str(self.a.imag)+')i+(' aff+=str(self.b.real)+')j+(' aff+=str(self.b.imag)+')k' return aff

def __neg__(self):

return Quaternion(-self.a,-self.b)

def __add__(self,other):

return Quaternion(self.a+other.a,self.b+other.b)

def __sub__(self,other):

return Quaternion(self.a-other.a,self.b-other.b)

def __mul__(self,other):

c=self.a*other.a-self.b*other.b.conjugate() d=self.a*other.b+self.b*other.a.conjugate() return Quaternion(c,d)

def __rmul__(self,k):

return Quaternion(self.a*k,self.b*k)

def __abs__(self):

return hypot(abs(self.a),abs(self.b))

def conjugate(self):

return Quaternion(self.a.conjugate(),-self.b)

def __div__(self,other):

return self.conjugate()*(1./abs(other)**2*other)

def  pow__(self,n):

r=1

for i in range(n): r=r*self return r

Il suffit de placer tout ça dans un fichier appelé quaternions.py et disposer de toutes ces méthodes en important le module nouvellement créé par

from quaternions import *

Ce qui permet alors de déclarer des quaternions, puis d'effectuer des opérations dessus.

Octonions

Ce qui est intéressant avec la construction de Cayley-Dickson utilisée ci-dessus pour les quaternions, c'est qu'elle se généralise: En définissant une structure (un objet) comprenant deux quaternions a et b, on définit un octonion.

Définition et affichage

Définition

from math import hypot class Octonion:

def __init__(self,a,b): self.a=a self.b=b

Affichage

Comme est de dimension 8 sur , l'affichage est plus compliqué que celui des quaternions:

def __str__(self):

aff='('

aff+=str(self.a.a.real)+')+(' aff+=str(self.a.a.imag)+')i+(' aff+=str(self.a.b.real)+')j+(' aff+=str(self.a.b.imag)+')k+(' aff+=str(self.b.a.real)+')l+(' aff+=str(self.b.a.imag)+')li+(' aff+=str(self.b.b.real)+')lj+(' aff+=str(self.b.b.imag)+')lk' return aff

On voit une arborescence apparaître, le a.a.real désignant la partie réelle du a du quaternion a de l'octonion. La notation avec les points prend ici tout son intérêt, permettant une concision pythonienne qui rendrait presque apprivoisés ces redoutables octonions!

Fonctions

Les fonctions sur les octonions se définissent presque comme celles sur les quaternions, Cayley-Dickson oblige:

Opposé

def __neg__(self):

return Octonion(-self.a,-self.b)

Module

def __abs__(self):

return hypot(abs(self.a),abs(self.b))

C'est pour permettre cette concision qu'on a importé la méthode hypot du module math.

Conjugué

def conjugate(self):

return Octonion(self.a.conjugate(),-self.b)

Opérations

Addition

def __add__(self,other):

return Octonion(self.a+other.a,self.b+other.b)

Encore une fois, le fait d'avoir surchargé la méthode __add__ de Python permet de noter simplement m+n la somme des octonions m et n.

Soustraction

def __sub__(self,other):

return Octonion(self.a-other.a,self.b-other.b)

Multiplication

def __mul__(self,other):

c=self.a*other.a-other.b*self.b.conjugate() d=self.a.conjugate()*other.b+other.a*self.b return Octonion(c,d)

Non seulement la multiplication des octonions n'est pas commutative, elle n'est plus associative non plus:

m=Octonion(Quaternion(3+4J,2-7J),Quaternion(1+3J,5-3J)) n=Octonion(Quaternion(2+1J,1-3J),Quaternion(2-2J,1+1J)) o=Octonion(Quaternion(3-2J,-5+3J),Quaternion(1-2J,2-1J)) print((m*n)*o)

print(m*(n*o))

Division

Grâce à la notion de conjugué, on peut facilement définir le quotient de deux octonions, mais c'est encore plus facile en multipliant un octonion par un réel:

Produit par un réel

def __rmul__(self,k):

return Octonion(k*self.a,k*self.b)

Quotient de deux octonions

def __div__(self,other):

return self.conjugate()*(1./abs(other)**2*other)

Là encore, le quotient d'un octonion par son conjugué est de norme 1:

m=Octonion(Quaternion(3+4J,2-7J),Quaternion(1+3J,5-3J)) n=Octonion(Quaternion(2+1J,1-3J),Quaternion(2-2J,1+1J))

print(m/m.conjugate())

print(abs(n/n.conjugate()))

Ces calculs permettent de décomposer un carré en somme de 8 carrés.

Puissances

Comme la multiplication des octonions n'est pas associative, les puissances des octonions ne présentent guère

d'intérêt, sauf pour la puissance 2, et sur , l'ensemble des solutions de l'équation est une sphère de dimension 6.

Résumé

La classe Octonion de Python peut se résumer à ceci:

class Octonion:

def __init__(self,a,b): self.a=a self.b=b

def __str__(self):

aff='('

aff+=str(self.a.a.real)+')+(' aff+=str(self.a.a.imag)+')i+(' aff+=str(self.a.b.real)+')j+(' aff+=str(self.a.b.imag)+')k+(' aff+=str(self.b.a.real)+')l+(' aff+=str(self.b.a.imag)+')li+(' aff+=str(self.b.b.real)+')lj+(' aff+=str(self.b.b.imag)+')lk' return aff

def __neg__(self):

return Octonion(-self.a,-self.b)

def __add__(self,other):

return Octonion(self.a+other.a,self.b+other.b)

def __sub__(self,other):

return Octonion(self.a-other.a,self.b-other.b)

def __mul__(self,other):

c=self.a*other.a-other.b*self.b.conjugate() d=self.a.conjugate()*other.b+other.a*self.b return Octonion(c,d)

def __rmul__(self,k):

return Octonion(k*self.a,k*self.b)

def __abs__(self):

return hypot(abs(self.a),abs(self.b))

def conjugate(self):

return Octonion(self.a.conjugate(),-self.b)

def __div__(self,other):

return self.conjugate()*(1./abs(other)**2*other)

Pour peu qu'on l'ait enregistrée dans un fichier octonions.py, il suffit pour pouvoir effectuer des calculs sur les octonions, d'importer ce fichier par from octonions import *

Bibliographie

  • De par leur utilité en infographie 3D, les quaternions sont utilisés dans Blender, avec cette description: [2]
  • Sur les octonions, le livre de John Baez est une lecture hautement conseillée: [3]

579