begin process at 2012 05 28 11:46:58
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Divers

 > VECTEURS ET MATRICES: OUTILS GRAPHIQUES UTILES

VECTEURS ET MATRICES: OUTILS GRAPHIQUES UTILES


 Description

En commençant à écrire quelques codes graphiques 3D basés sur l'axonométrie et la perspective, j'ai rapidement constaté qu'il me fallait un ensemble de procédures de calcul vectoriel et matriciel de dimension 1,2,3 et même 4 (certaines transformations 2D sont déjà compris dans le contexte 2D de <canvas>).
Plutôt que de créer ou copier une flopée de petites méthodes selon toutes les combinaisons ces dimensions, je me suis finalement décidé d'écrire (en POO, OOP) quelque chose de beaucoup plus général et plus simple d'utilisation et de documentation.
Les vecteurs y sont considérés comme des matrices dont l'une des dimensions est 1 (vecteur 'ligne' ou vecteur 'colonne').

Voici le mode d'emploi de la 'library' élémentaire de calcul matriciel, basée sur l'objet MatWV, contenu dans le fichier 'MatWV.js' et écrit entièrement en Javascript:

Objet MatWV: Utilisation:         Signification:                         Conditions:
¯¯¯¯¯¯¯¯¯¯¯  ¯¯¯¯¯¯¯¯¯¯¯           ¯¯¯¯¯¯¯¯¯¯¯¯¯                         ¯¯¯¯¯¯¯¯¯¯
Constructeur:
  MatWV      m = new MatWV(nC,nL) Crée une matrice nC*nL
                                    avec des valeurs indéfinies

Méthodes:
  Str        str=m.Str(sep,eol)   Crée un string de m avec
                                    séparateurs et fins de ligne
  Const      m.Const(k)           Multiplie m par la constante k
  Norm       len=m.Norm()         Norme (longueur) du vecteur m          (nC==1)||(nL==1)
  Det        m.Det()              Retourne le déterminant de m           m carrée
  Invert     m.Invert()           Inverse m, return det                  m carrée
  EcartI     m.EcartI()           Retourne l'écart abs max par           m carrée
                                    rapport à la matrice unité

Les méthodes suivantes créent une nouvelle matrice:
  Copy       c=m.Copy()           Crée une copie (Clone) de m
  Transp     t=m.Transp()         Crée la matrice transposée de m
  Sum        s=m.Sum(a)           Crée la somme m + a                    dimensions égales
  Prod       p=m.Prod(r)          Crée le produit m * r                  m.nC==r.nL
  Inv        i=m.Inv()            Crée la matrice inverse de m           m carrée
  
Méthodes statiques:
  Uni        I=MatWV.Uni(n)       Crée la matrice unité n*n              (n>0)
  Rnd        m=MatWV.Rnd(C,L,b,d) Crée une matrice 'aléatoire' C*L,      (0<=d<=5)
                                    valeurs bornées par -b et +b,
                                    avec d chiffres après la virgule

(Ce mode d'emploi gagne à être affiché avec une police à chasse fixe, p.ex.: 'Courier New').


La méthode 'Invert()' de l'inversion de matrice que je propose est 'rare', surtout en Javascript !
Elle correspond à une version non récursive, simplifiée et optimisée du code 'C'
donné chez Wikipédia sous forme de deux fonctions:
  (http://fr.wikipedia.org/wiki/Matrice_inversible).
Les différences sont les suivantes:
- On opère sur la matrice elle-même.
- Pour augmenter la précision du calcul, on choisit à chaque étape le
     meilleur pivot possible (méthode de Gauss-Jordan).
- La boucle la plus intérieure est particulièrement optimisée.
- On retourne le déterminant qui est calculé en même temps.

Le fichier 'Determinant.rtf' (dans le zip) montre comment on peut 'créer' un code de calcul du déterminant en se basant sur trois règles du calcul matriciel.

Le code HTML montre par quelques exemples comment utiliser l'objet MatWV.
A la fin, on mesure le temps nécessaire pour inverser une matrice M de 200*200 (c.-à-d. 40000 éléments remplis aléatoirement) !
Puis on mesure aussi la précision de la matrice unité I obtenue par M * M.Inv().

Attention: Pour le déterminant, l'inversion et le produit, le temps de calcul augmente avec le cube de la dimension: donc pour un N deux fois plus grand, il faut ~ huit fois plus de temps.

Notez qu'avec l'utilisation de MatWV.Rnd(...), vous obtenez chaque fois une matrice différente.
Remarquez également qu'une matrice de déterminant nul ne s'inverse pas; et plus ce déterminant s'approche de 0, moins l'inversion est précise.

Les méthodes Str(), Rnd() et EcartI() ne sont pas strictement nécessaires, elles ont été ajoutées pour faciliter les tests.

Source

  • function MatWV(nCol,nLin) { // Constructeur: Matrice à coefficients réels
  • this.nC=nCol; // nombre de colonnes
  • this.nL=nLin; // nombre de lignes
  • this.M=new Array(nCol*nLin); // valeurs ligne par ligne
  • } // http://fr.wikipedia.org/wiki/Matrice_(math%C3%A9matiques)
  • //============================================================================
  • // Méthodes d'instance qui ne modifient pas la matrice concernée:
  • MatWV.prototype.Copy=function() { // Crée une copie (clone) de la matrice
  • var m=new MatWV(this.nL,this.nC),NN=this.M.length;
  • for (var i=0;i<NN;i++) m.M[i]=this.M[i];
  • return m;
  • }
  • MatWV.prototype.Det=function() { // Calcule le déterminant de la matrice
  • var d=1,e,h,hN,k,kN,i,j,jN,N=this.nC,p,m=this.M.slice(0);
  • if (N!=this.nL) return 0; // seulement pour matrices carrées
  • for (k=N-1,kN=k*N;k>0;k--,kN-=N) {
  • for (j=0,h=k,p=0;j<=k;j++) if ((e=Math.abs(m[k+j*N]))>p) {h=j; p=e;}
  • if (h!=k) { // permutation des linges h et k
  • hN=h*N; d=-d; // inversion du signe;
  • for (i=0;i<=k;i++) {e=m[i+hN]; m[i+hN]=m[i+kN]; m[i+kN]=e;}
  • }
  • if ((!isFinite(d*=(e=m[k+kN])))||(d==0)) return d;
  • for (j=0,jN=0;j<k;j++,jN+=N) // pour chaque ligne (sauf la dernière)
  • for (i=0,f=m[k+jN]/e;i<k;i++) m[i+jN]-=f*m[i+kN];
  • }
  • return d*m[0];
  • } // http://fr.wikipedia.org/wiki/D%C3%A9terminant_(math%C3%A9matiques)
  • MatWV.prototype.EcartI=function() { // Ecart abs max de this par rapport à la matrice unité
  • var a,e=0,m=this.M,N=1+this.nC,NN=m.length;
  • for (var i=0;i<NN;i++) if ((a=Math.abs(((i%N)==0)?1-m[i]:m[i]))>e) e=a;
  • return e;
  • }
  • MatWV.prototype.Inv=function() { // Crée la matrice inverse de this
  • var mi=this.Copy(); return (mi.Invert()!=0)?mi:null;
  • }
  • MatWV.prototype.Norm=function() { // Norme d'un vecteur
  • if ((this.nC>1)&&(this.nL>1)) return 0; // seulement pour vecteurs
  • var i,NN=this.M.length,s=0;
  • for (i=0;i<NN;i++) s+=this.M[i]*this.M[i];
  • return Math.sqrt(s);
  • }
  • MatWV.prototype.Prod=function(r) { // Crée la matrice produit: Prod = this * r
  • var m=this.M,tC=this.nC,tL=this.nL,rC=r.nC,rL=r.nL;
  • if (tC!=rL) return null;
  • var i,l,lt,k=0,c,p=new MatWV(rC,tL),s;
  • for (l=0;l<tL;l++) {
  • for (c=0,lt=l*tC;c<rC;c++) {
  • for (i=0,s=0;i<tC;i++) s+=m[lt+i]*r.M[c+i*rC];
  • p.M[k++]=s;
  • }
  • }
  • return p;
  • } // http://fr.wikipedia.org/wiki/Produit_matriciel
  • MatWV.prototype.Str=function(sep,eol) { // Crée un string de la matrice 'arrondie'
  • var i,q=this.nC,NN=q*this.nL,s=eol; // avec séparateurs de valeurs et de lignes
  • for (i=0;i<NN;i++) s+=Math.round(this.M[i]*1000000)/1000000+(((i+1)%q)?sep:eol);
  • return s; // sans arrondi: ... s+=this.M[i]+(((i+1)%q)?sep:eol);
  • }
  • MatWV.prototype.Sum=function(a) { // Crée la matrice somme: Sum = this + a
  • if ((this.nC!=a.nC)||(this.nL!=a.nL)) return null;
  • var m=new MatWV(this.nC,this.nL);
  • for (var i=0;i<this.M.length;i++) m.M[i]=this.M[i]+a.M[i];
  • return m;
  • } // http://fr.wikipedia.org/wiki/Addition_matricielle
  • MatWV.prototype.Transp=function() { // Crée la matrice transposée
  • var m=new MatWV(this.nL,this.nC);
  • for (var l=0;l<this.nL;l++)
  • for (var c=0;c<this.nC;c++) m.M[l+c*this.nL]=this.M[c+l*this.nC];
  • return m;
  • } // http://fr.wikipedia.org/wiki/Matrice_transpos%C3%A9e
  • //============================================================================
  • // Méthodes d'instance qui modifient la matrice concernée:
  • MatWV.prototype.Const=function() { // Multiplie this par la constante k
  • for (var i=0;i<this.nC*this.nL;i++) this.M[i]*=k;
  • }
  • MatWV.prototype.Invert=function() { // Inverse la matrice this sur elle-même
  • var d=1,e,h,hh,ii,j,k,kk=0,m=this.M,N=this.nC,NN=N*N,p,idx=new Array(N);
  • if (N!=this.nL) return 0; // Seulement pour matrice carrée
  • for (k=0;k<N;k++,kk+=N) {
  • for (j=k,p=0;j<N;j++) if ((e=Math.abs(m[j*N+k]))>p) {p=e; h=j;}
  • if (p==0) return 0; // meilleur pivot = 0 ==> déterminant = 0
  • idx[k]=h; hh=h*N; p=m[hh+k]; d*=(h==k)?p:-p; m[hh+k]=m[kk+k]; m[kk+k]=1;
  • for (ii=k;ii<NN;ii+=N) m[ii]/=p;
  • for (j=0;j<N;j++) if (k!=j) {
  • e=m[hh+j]; m[hh+j]=m[kk+j]; m[kk+j]=0;
  • if (e!=0) for (ii=0;ii<NN;ii+=N) m[ii+j]-=e*m[ii+k];
  • }
  • }
  • for (j=N-1;j>=0;j--) // on réarrange les colonnes
  • for (ii=0,h=idx[j];ii<NN;ii+=N) {e=m[ii+h]; m[ii+h]=m[ii+j]; m[ii+j]=e;}
  • return d; // retourne le déterminant
  • } // http://fr.wikipedia.org/wiki/Matrice_inversible
  • //============================================================================
  • // Les méthodes suivantes sont 'statiques':
  • MatWV.Rnd=function(nC,nL,lim,dig) { // Crée une matrice 'aléatoire' à valeurs entre -lim et lim
  • var m=new MatWV(nC,nL),lim2=2*lim,d=[1,10,100,1000,10000][dig];
  • for (var i=0;i<nC*nL;i++) m.M[i]=Math.round(d*(lim-lim2*Math.random()))/d;
  • return m; // valeurs arrondies à 'dig' chiffres après la virgule (0<=dig<4)
  • }
  • MatWV.Uni=function(n) { // Crée la matrice unité n*n
  • var m=new MatWV(n,n);
  • for (var i=0;i<n*n;i++) m.M[i]=(i%(n+1))?0:1;
  • return m;
  • } // http://fr.wikipedia.org/wiki/Matrice_unit%C3%A9
  • // William Voirol, Switzerland, Sep 2011
function MatWV(nCol,nLin) { // Constructeur: Matrice à coefficients réels
   this.nC=nCol;                // nombre de colonnes
   this.nL=nLin;                // nombre de lignes
   this.M=new Array(nCol*nLin); // valeurs ligne par ligne
} // http://fr.wikipedia.org/wiki/Matrice_(math%C3%A9matiques)

//============================================================================
// Méthodes d'instance qui ne modifient pas la matrice concernée:

MatWV.prototype.Copy=function() { // Crée une copie (clone) de la matrice
   var m=new MatWV(this.nL,this.nC),NN=this.M.length;
   for (var i=0;i<NN;i++) m.M[i]=this.M[i];
   return m;
}

MatWV.prototype.Det=function() { // Calcule le déterminant de la matrice
   var d=1,e,h,hN,k,kN,i,j,jN,N=this.nC,p,m=this.M.slice(0);
   if (N!=this.nL) return 0; // seulement pour matrices carrées
   for (k=N-1,kN=k*N;k>0;k--,kN-=N) {
      for (j=0,h=k,p=0;j<=k;j++) if ((e=Math.abs(m[k+j*N]))>p) {h=j; p=e;}
      if (h!=k) { // permutation des linges h et k
         hN=h*N; d=-d; // inversion du signe;
         for (i=0;i<=k;i++) {e=m[i+hN]; m[i+hN]=m[i+kN]; m[i+kN]=e;}
      }
      if ((!isFinite(d*=(e=m[k+kN])))||(d==0)) return d;
      for (j=0,jN=0;j<k;j++,jN+=N) // pour chaque ligne (sauf la dernière)
         for (i=0,f=m[k+jN]/e;i<k;i++) m[i+jN]-=f*m[i+kN];
   }
   return d*m[0];
} // http://fr.wikipedia.org/wiki/D%C3%A9terminant_(math%C3%A9matiques)

MatWV.prototype.EcartI=function() { // Ecart abs max de this par rapport à la matrice unité
   var a,e=0,m=this.M,N=1+this.nC,NN=m.length;
   for (var i=0;i<NN;i++) if ((a=Math.abs(((i%N)==0)?1-m[i]:m[i]))>e) e=a;
   return e;
}

MatWV.prototype.Inv=function() { // Crée la matrice inverse de this
   var mi=this.Copy(); return (mi.Invert()!=0)?mi:null;
}

MatWV.prototype.Norm=function() { // Norme d'un vecteur
   if ((this.nC>1)&&(this.nL>1)) return 0; // seulement pour vecteurs
   var i,NN=this.M.length,s=0;
   for (i=0;i<NN;i++) s+=this.M[i]*this.M[i];
   return Math.sqrt(s);
}

MatWV.prototype.Prod=function(r) { // Crée la matrice produit: Prod = this * r
   var m=this.M,tC=this.nC,tL=this.nL,rC=r.nC,rL=r.nL;
   if (tC!=rL) return null;
   var i,l,lt,k=0,c,p=new MatWV(rC,tL),s;
   for (l=0;l<tL;l++) {
      for (c=0,lt=l*tC;c<rC;c++) {
         for (i=0,s=0;i<tC;i++) s+=m[lt+i]*r.M[c+i*rC];
         p.M[k++]=s;
      }
   }
   return p;
} // http://fr.wikipedia.org/wiki/Produit_matriciel

MatWV.prototype.Str=function(sep,eol) { // Crée un string de la matrice 'arrondie'
   var i,q=this.nC,NN=q*this.nL,s=eol;  // avec séparateurs de valeurs et de lignes
   for (i=0;i<NN;i++) s+=Math.round(this.M[i]*1000000)/1000000+(((i+1)%q)?sep:eol);
   return s; // sans arrondi: ... s+=this.M[i]+(((i+1)%q)?sep:eol);
}

MatWV.prototype.Sum=function(a) { // Crée la matrice somme: Sum = this + a
   if ((this.nC!=a.nC)||(this.nL!=a.nL)) return null;
   var m=new MatWV(this.nC,this.nL);
   for (var i=0;i<this.M.length;i++) m.M[i]=this.M[i]+a.M[i];
   return m;
} // http://fr.wikipedia.org/wiki/Addition_matricielle
 
MatWV.prototype.Transp=function() { // Crée la matrice transposée
   var m=new MatWV(this.nL,this.nC);
   for (var l=0;l<this.nL;l++) 
      for (var c=0;c<this.nC;c++) m.M[l+c*this.nL]=this.M[c+l*this.nC];
   return m;
} // http://fr.wikipedia.org/wiki/Matrice_transpos%C3%A9e
//============================================================================
// Méthodes d'instance qui modifient la matrice concernée:

MatWV.prototype.Const=function() { // Multiplie this par la constante k
   for (var i=0;i<this.nC*this.nL;i++) this.M[i]*=k;
}

MatWV.prototype.Invert=function() { // Inverse la matrice this sur elle-même
   var d=1,e,h,hh,ii,j,k,kk=0,m=this.M,N=this.nC,NN=N*N,p,idx=new Array(N);
   if (N!=this.nL) return 0; // Seulement pour matrice carrée
   for (k=0;k<N;k++,kk+=N) {
      for (j=k,p=0;j<N;j++) if ((e=Math.abs(m[j*N+k]))>p) {p=e; h=j;}
      if (p==0) return 0; // meilleur pivot = 0 ==> déterminant = 0
      idx[k]=h; hh=h*N; p=m[hh+k]; d*=(h==k)?p:-p; m[hh+k]=m[kk+k]; m[kk+k]=1;
      for (ii=k;ii<NN;ii+=N) m[ii]/=p;
      for (j=0;j<N;j++) if (k!=j) {
         e=m[hh+j]; m[hh+j]=m[kk+j]; m[kk+j]=0;
         if (e!=0) for (ii=0;ii<NN;ii+=N) m[ii+j]-=e*m[ii+k];
      }
   }
   for (j=N-1;j>=0;j--) // on réarrange les colonnes
      for (ii=0,h=idx[j];ii<NN;ii+=N) {e=m[ii+h]; m[ii+h]=m[ii+j]; m[ii+j]=e;}
   return d; // retourne le déterminant
} // http://fr.wikipedia.org/wiki/Matrice_inversible

//============================================================================
// Les méthodes suivantes sont 'statiques':

MatWV.Rnd=function(nC,nL,lim,dig) { // Crée une matrice 'aléatoire' à valeurs entre -lim et lim
   var m=new MatWV(nC,nL),lim2=2*lim,d=[1,10,100,1000,10000][dig];
   for (var i=0;i<nC*nL;i++) m.M[i]=Math.round(d*(lim-lim2*Math.random()))/d;
   return m; // valeurs arrondies à 'dig' chiffres après la virgule (0<=dig<4)
}

MatWV.Uni=function(n) { // Crée la matrice unité n*n
   var m=new MatWV(n,n);
   for (var i=0;i<n*n;i++) m.M[i]=(i%(n+1))?0:1;
   return m;
} // http://fr.wikipedia.org/wiki/Matrice_unit%C3%A9

// William Voirol, Switzerland, Sep 2011

 Conclusion

Jusqu'à présent, il était conseillé d'envoyer les calculs lourds au serveur et de récupérer les résultats, ce qui implique pas mal de programmation, de tests et de synchronisation.
Si votre processeur n'est pas trop ancien, vous constaterez que tout cela est de moins en moins nécessaire et beaucoup de calculs peuvent se faire localement.
L'inversion d'une matrice 200x200 (ce qui est déjà assez extrème) prend chez moi entre un quart et deux secondes (le dernier temps avec un tout petit portable 10" à ~160 euros)
Ce programme permet aussi de tester l'efficacité des différents navigateurs.

J'admets que tout cela est assez 'technique' et pas très intéressant pour celui qui n'a pas ou peu de connaissances en calcul vectoriel et matriciel. Mais mes prochains articles montreront qu'il est très pratique d'utiliser les notions de vecteurs et de matrices, surtout pour le graphique 2D et 3D.
Les 'librairies' de calcul matriciel (écrits en différents langages) qui dévoilent leur code ont souvent des 'désagréments' tels que:
- calcul peu précis ou même incorrect !
- généralisation de la méthode de Sarrus (calcul du déterminant), alors qu'elle est limitée à 3*3 !
- choix direct de l'élément diagonal comme pivot, ce qui 'bloque'
     souvent inutilement le calcul (inversion, déterminant, ...).
- ils n'utilisent pas la programmation objet.
- manque d'un ensemble de tests de précision et de temps de calcul.

Faites directement un test: (observez la remarque ci-dessous)
    http://www.william-voirol.ch/Prog/Transformations/ Matrices

Remarque: de temps en temps, des espaces (caractères blancs) s'immiscent
dans certains textes. (CodeS-SourceS est au courant du problème).
Si c'était le cas ici, enlevez les espaces avant d'utiliser l'adresse Web ci-dessus.

L'exemple complet se trouve sur le fichier zip.

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip Source avec une capture ONGLETS ET CHANGEMENT INSTANTANÉ DE LA LANGUE
Source avec Zip Source avec une capture RÉSOLUTION D'UN SYSTÈME D'ÉQUATIONS LINÉAIRES À N INCONNUES
Source avec Zip DIALOGUE ENTRE FENÊTRES MÈRE ET FILLE
Source avec Zip ROTATION D'UNE IMAGE, ANIMATION
Source avec Zip FRACTALES, FOUGÈRE, TRIANGLE, CARRÉ

 Sources de la même categorie

Source avec Zip Source avec une capture SLIDESHOW IMAGES ET TEXTES EN PUR JAVASCRIPT par ansuzpeorth
Source avec Zip INPUT TEXT AUTOMATIQUE CREATION SUPPRESSION par lycanges
Source avec Zip Source avec une capture TABLE_SV : TABLEAU DYNAMIQUE, MONTRER/CACHER COLONNE SUR DEM... par synanceia
COLONNES ADAPTABLES EN HAUTEUR par dronoide
Source avec Zip Source avec une capture HTML5 PLAYER par kazma

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture RÉSOLUTION D'UN SYSTÈME D'ÉQUATIONS LINÉAIRES À N INCONNUES par william voirol
OPÉRATIONS SUR MATRICES par Minilogus
Source avec Zip Source avec une capture CALCULATEUR DES PARTS FINANCIÈRES par voisinpi
Source avec Zip Source avec une capture MENU DYNAMIQUE HORIZONTAL SIMPLE par FasteX_
EFFET MATRIX par bob3000

Commentaires et avis

Commentaire de PulsarSan le 13/12/2011 12:27:09

Impressionnant !
J'ai testé la page que tu donnes sur mon dual-core (4 Go de MeV). Je te mets les lignes indiquant le temps et la précision (Plein de choses étaient ouvertes) :

M[200*200]: M.Det() = 8.018572297294273e+161 ; temps = 51 ms
Inversion de la matrice M [200*200]: temps = 167 ms
Test de précision de I = M * M-1:
Ecart max de I (par rapport à la matrice unité) = 4.241051954068098e-14

Bonne continuation ^^

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Matrix [ par Dante36 ] Dans le javascript "matrix", Comment fait on pour changer les "0000000001" qui défile en autre chose?*Merci de me répondre* création des vecteurs sous JAVA [ par sihamu ] comment je peut créer des vecteurs, les remplir aléatoirement puis les afficher?j'ai essayé :for(int i=0; i&lt;=3; i++){ int repD[] = new int [3]repD[ Calculs matriciels [ par mefire ] Bonjour, Merci de m'aider avec le code JAVA des opérations sur les matrices suivantes: * addition de deux matrices * multiplication de deux matrices *


Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,967 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales