Mathématiques avec Python et Ruby/Quaternions et octonions en Ruby

Complexes.
On a vu dans le chapitre précédent que pour Ruby, 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.
Dans toute la suite, on va profiter de la gestion des fractions offerte par "cmath", avec
require 'cmath'
Quaternions.
Definition et affichage.
Définition.
La définition d'un quaternion se fait dans une classe nommée "Quaternion":
class Quaternion
end
La première méthode, l'initialisation, crée donc deux variables "a" et "b" (qui seront des complexes, mais Ruby ne le sait pas encore):
Initialisation.
 def initialize(a,b)
 @a,@b = a,b
 end
Les nombres complexes "a" et "b" seront des propriétés du quaternion:
Propriétés a et b.
 def a
 @a
 end
 def b
 @b
 end
Désormais on accède aux deux complexes "a" et "b" d'un quaternion "q" par "q.a" et "q.b".
Affichage.
Pour afficher un quaternion "q" avec "puts(q)", il est nécessaire de redéfinir (une sorte de surcharge) sa méthode de conversion en chaîne de caractères ("string"):
 def to_s
 '('+a.real.to_s+')+('+a.imag.to_s+')i+('+b.real.to_s+')j+('+b.imag.to_s+')k'
 end
La notation des points se lit de droite à gauche, par exemple "a.real" veut dire "la partie réelle de a" et "q.a.real", "la partie réelle du a de q".
Le quaternion de Ruby ne possède alors que deux propriétés, "a" et "b", mais on va se rattraper sur les méthodes, qui opèrent sur un quaternion (ou deux):
Fonctions.
Module.
Le module d'un quaternion est un réel:
 def abs
 Math.hypot(@a.abs,@b.abs)
 end
Conjugué.
Le conjugué d'un quaternion est un quaternion de même module que celui-ci:
 def conj
 Quaternion.new(@a.conj,-@b)
 end
Opérations.
Addition.
Pour additionner deux quaternions, on additionne leurs "a" respectifs, et leurs "b" respectifs, et on crée un nouveau quaternion à partir des deux nombres complexes obtenus:
 def +(q)
 Quaternion.new(@a+q.a,@b+q.b)
 end
Pour calculer et afficher la somme des quaternions "p" et "q", il suffit alors d'entrer "puts(p+q)".
Soustraction.
La soustraction des quaternions relève d'un principe analogue:
 def -(q)
 Quaternion.new(@a-q.a,@b-q.b)
 end
Multiplication.
Le produit de deux quaternions est plus difficile à définir:
 def *(q)
 Quaternion.new(@a*q.a-@b*q.b.conj,@a*q.b+@b*q.a.conj)
 end
La multiplication des quaternions n'est pas commutative, comme le montre l'exemple suivant:
p=Quaternion.new(Complex(2,1),Complex(3,4))
q=Quaternion.new(Complex(2,5),Complex(-3,-5))
puts(p*q)
puts(q*p)
Division.
Pour diviser un quaternion par un autre, on peut faire ainsi:
 def /(q)
 d=q.abs**2
 Quaternion.new((@a*q.a.conj+@b*q.b.conj)/d,(-@a*q.b+@b*q.a)/d)
 end
Comme ils ont le même module, le quotient d'un quaternion par son conjugué est égal à 1:
p=Quaternion.new(Complex(2,1),Complex(3,4))
puts((p/p.conj).abs)
Cet exemple révèle que formula_1, c'est-à-dire que formula_2, qui est une décomposition de formula_3 comme somme de 4 carrés.
Résumé.
La classe Quaternion de Ruby tient en entier dans un fichier plutôt léger, au vu de ses possibilités:
require 'cmath'
class Quaternion
 def initialize(a,b)
 @a,@b = a,b
 end
 def a
 @a
 end
 def b
 @b
 end
 def to_s
 '('+a.real.to_s+')+('+a.imag.to_s+')i+('+b.real.to_s+')j+('+b.imag.to_s+')k'
 end
 def +(q)
 Quaternion.new(@a+q.a,@b+q.b)
 end
 def -(q)
 Quaternion.new(@a-q.a,@b-q.b)
 end
 def *(q)
 Quaternion.new(@a*q.a-@b*q.b.conj,@a*q.b+@b*q.a.conj)
 end
 def abs
 Math.hypot(@a.abs,@b.abs)
 end
 def conj
 Quaternion.new(@a.conj,-@b)
 end
 def /(q)
 d=q.abs**2
 Quaternion.new((@a*q.a.conj+@b*q.b.conj)/d,(-@a*q.b+@b*q.a.conj)/d)
 end
end
Si on enregistre ce fichier sous le nom "quaternions.rb", il suffit d'insérer " require 'quaternions' " pour être en mesure d'effectuer des calculs sur les quaternions. 
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.
Comme pour les quaternions, on décrit l'objet "octonion" dans une classe "Octonion":
class Octonion
 def initialize(a,b)
 @a,@b = a,b
 end
 def a
 @a
 end
 def b
 @b
 end
Au passage on définit les propriétés "a" et "b" de l'octonion comme celles du quaternion, sauf que cette fois-ci ce ne sont plus des complexes mais des quaternions. Mais comme Ruby est faiblement typé, cette particularité n'apparaîtra que lorsque "a" ou "b" sera utilisé.
Affichage.
Là encore, la méthode "to_s" se définit comme celle des quaternions, mais il y a 8 nombres à afficher au lieu de 4:
 def to_s
 '('+a.a.real.to_s+')+('+a.a.imag.to_s+')i+('+a.b.real.to_s+')j+('+a.b.imag.to_s+')k+('+b.a.real.to_s+')l+('+b.a.imag.to_s+')li+('+b.b.real.to_s+')lj+('+b.b.imag.to_s+')lk'
 end
Pour accéder au premier de ces nombres, que est la partie réelle du "a" de "a", on note "a.a.real". Autrement dit, on parcourt un arbre binaire, de profondeur 3.
Fonctions.
Les fonctions sur les octonions se définissent presque comme celles sur les quaternions, Cayley-Dickson oblige:
Module.
Comme pour les quaternions:
 def abs
 Math.hypot(@a.abs,@b.abs)
 end
Conjugué.
 def conj
 Octonion.new(@a.conj,Quaternion.new(0,0)-@b)
 end
Opérations.
Addition.
Comme pour les quaternions, on additionne les octonions composante par composante ("a" avec "o.a", "b" avec "o.b"):
 def +(o)
 Octonion.new(@a+o.a,@b+o.b)
 end
Soustraction.
 def -(o)
 Octonion.new(@a-o.a,@b-o.b)
 end
Multiplication.
 def *(o)
 Octonion.new(@a*o.a-o.b*@b.conj,@a.conj*o.b+o.a*@b)
 end
Non seulement la multiplication des octonions n'est pas commutative, elle n'est plus associative non plus:
m=Octonion.new(p,q)
n=Octonion.new(q,p)
o=Octonion.new(p,p)
puts((m*n)*o)
puts(m*(n*o))
Division.
 def /(o)
 d=1/o.abs**2
 Octonion.new((@a*o.a.conj+o.b*@b.conj)*Quaternion.new(d,0),(Quaternion.new(0,0)-@a.conj*o.b+o.a.conj*@b)*Quaternion.new(d,0))
 end
Là encore, le quotient d'un octonion par son conjugué est de module 1:
puts(m/m.conj)
puts((m/m.conj).abs)
Résumé.
L'objet "Octonion" de Ruby est lui aussi, assez léger:
class Octonion
 def initialize(a,b)
 @a,@b = a,b
 end
 def a
 @a
 end
 def b
 @b
 end
 def to_s
 '('+a.a.real.to_s+')+('+a.a.imag.to_s+')i+('+a.b.real.to_s+')j+('+a.b.imag.to_s+')k+('+b.a.real.to_s+')l+('+b.a.imag.to_s+')li+('+b.b.real.to_s+')lj+('+b.b.imag.to_s+')lk'
 end
 def +(o)
 Octonion.new(@a+o.a,@b+o.b)
 end
 def -(o)
 Octonion.new(@a-o.a,@b-o.b)
 end
 def *(o)
 Octonion.new(@a*o.a-o.b*@b.conj,@a.conj*o.b+o.a*@b)
 end
 def abs
 Math.hypot(@a.abs,@b.abs)
 end
 def conj
 Octonion.new(@a.conj,Quaternion.new(0,0)-@b)
 end
 def /(o)
 d=1/o.abs**2
 Octonion.new((@a*o.a.conj+o.b*@b.conj)*Quaternion.new(d,0),(Quaternion.new(0,0)-@a.conj*o.b+o.a.conj*@b)*Quaternion.new(d,0))
 end
end
En l'enregistrant sous le nom "octonions.rb", il suffit d'écrire
require 'octonions'
pour être en mesure d'effectuer des calculs sur les octonions en Ruby.

Photographie/Fabricants/Olympus/Olympus E-P3

Photographie/Fabricants/FED/FED-2
Photographie/Fabricants/Canon/Canon PowerShot SD 1100 IS

Photographie/Fabricants/Nikon/Nikon Coolpix AW100

Photographie/Fabricants/Nikon/Nikon Nikkor PC-E 24 mm f/3,5 D ED

Photographie/Fabricants/Nikon/Nikon D3s
Photographie/Fabricants/Sony/Sony Mavica MVC-FD7

Patrons de conception/Type de base pour la couche

Les classes d'une même couche logicielle ont souvent un comportement similaire ou besoin des mêmes méthodes.
Afin d'éviter que ces méthodes soient définies en plusieurs endroits, il est préférable de créer une classe de base pour toutes ces classes afin de rassembler les méthodes communes dans une seule classe.

Blender 2.7/Traduire Blender en Français