begin process at 2010 02 10 06:02:43
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Maths

 > CLASS DE CALCUL MATRICIEL, DIAGONALISATION DE MATRICES SYMÈTRIQUES RÉELLES.

CLASS DE CALCUL MATRICIEL, DIAGONALISATION DE MATRICES SYMÈTRIQUES RÉELLES.


 Information sur la source

Note :
Aucune note
Catégorie :Maths Classé sous :matrices, diagonalisation, vecteurs, qr, algèbre Niveau :Initié Date de création :15/05/2006 Vu / téléchargé :12 705 / 3 732

Auteur : JnBiz

Ecrire un message privé
Commentaire sur cette source (8)
Ajouter un commentaire et/ou une note

 Description

Bon, voila, j'avais ecrit pour mon TIPE des bouts de programmes de calcul matriciel, et récemment j'ai du écrire des programmes en Matlab pour l'école. Je me suis dit qu'il était dommage de ne pas pouvoir utiliser ces fonctions dans mon langage favoris ;-) J'ai trouvé aussi que le sujet était intéressant d'un point de vu mathématique. Après quelques tests d'algorithmes sous Matlab j'ai vu que cela était faisable.

Cette unité définit donc une Class: TMatrix gérant des matrices réelles de dimensions variables.
Pour éviter autant que possible de remplir une matrice élément par élément, on définit une dizaine de fonctions de création de vecteurs et de matrices particulières (Equivalent des fonctions matlab Rand, LinSpace, SpDiags...).

Les opérations gérées sont:
Les fonctions de base addition, soustraction, multiplication, transposition, calcul de produits scalaires, de normes pour tous type de matrices.
Le reste des opérations est principalement destiné aux matrices carrés:

-Inversion, calcul de déterminants
-Divers types de décompositions: LU, QR, QL, Hessenberg pour toutes matrices carrés.
-Le calcul des valeurs propres d'une matrice symétrique  (en O(n^2))
-Le calcul des valeurs propres et des vecteurs propres d'une matrice symétrique (en O(n^3))

Une procédure permet de tracer des courbes 1D et 2D de plusieurs types représentant les matrices.


 Conclusion

Les 2 fonctions de diagonalisation utilisent la méthode itérative de factorisation QR avec décalage de Wilkinson.
Cette méthode à l'avantage d'être rapide ( 0,2 secondes pour une matrice 100X100 ), de plus elle est numériquement très stable, ce qui permet d'obtenir des valeurs et des vecteurs propres d'une précision de 10^-17.
Pour plus de précisions sur l'algorithme lire: http://www-math.mit.edu/~persson/18.335/lec16.pdf

Je vais étendre le travail aux matrices complexes, en particuliers pour diagonaliser tout types de matrices réelles et tout types de matrices complexes.
Cependant j'hésite encore entre 2 solutions: soit développer une class à part de matrices complexes, soit intégrer les matrices complexes dans une unique class de manière à ce que chaque fonction gére indifféremment des matrices réelles et complexes ce qui nécessite plus de travail.
Tout vos commentaires sont les bienvenus, notamment si vous savez comment autoriser des calculs du type M1:=add(M1,mul(M2,M3)) sans que cela ne génère des zones de mémoire non libérables, voir même surcharger les opérateurs.

 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 CLASS TCMATRIX, DIAGONALISATION DE TOUTES MATRICES COMPLEXES...
Source avec Zip Source avec une capture RÉSOLUTION DE L'ÉQUATION DE SCHRODINGER. CALCUL DES ÉTATS PR...
Source avec Zip Source avec une capture OUTIL DE CALCUL NUMÉRIQUE (MAJ 2) ( PARSER COMPLEXE + TRACÉ...

 Sources de la même categorie

Source avec Zip Source avec une capture CONVERTISSEUR D'UN NOMBRE DÉCIMAL EN BINAIRE ET HEXADECIMAL par ludokk
Source avec Zip Source avec une capture PREMIER OU PAS? par ludokk
Source avec Zip Source avec une capture CONJECTURE DU CARRÉ DES FACTEURS par Bacterius
Source avec Zip Source avec une capture GÉNÉRATEUR DE NOMBRES PSEUDO-ALÉATOIRES par Bacterius
Source avec Zip Source avec une capture ALGORITHME DE HASH LEA par Bacterius

 Sources en rapport avec celle ci

Source avec Zip CLASS TCMATRIX, DIAGONALISATION DE TOUTES MATRICES COMPLEXES... par JnBiz
Source avec Zip Source avec une capture RÉSOLUTION DE L'ÉQUATION DE SCHRODINGER. CALCUL DES ÉTATS PR... par JnBiz

Commentaires et avis

Commentaire de f0xi le 17/05/2006 04:35:49 administrateur CS

pour les fonctions qui renvois des objets :

function Methode(obj1, obj2 : TClasse) : TClasse;

fait plutot cela :

procedure Methode(const Obj1, Obj2 : TClasse;var ObjResultat : TClasse);

et ne fait pas la creation dans la procedure.

il faudrat ensuite faire comme cela :

procedure Methode(const Obj1, Obj2 : TClasse;var ObjResultat : TClasse);
begin
  if not assigned(ObjResultat) then exit;
  ObjResultat.Prop := Obj1.prop (calcul) Obj2.Prop;
end;

le "not assigned" permet de controller si l'objet est instancié ou non ... auquel cas il ne faut pas provoquer d'erreur de violation donc on sort de la procedure.
on pourrait egalement generer une exception (classe exception) avec cette methode :

type
  EEObjectNotAssigned = class(Exception);

procedure Methode(const Obj1, Obj2 : TClasse;var ObjResultat : TClasse);
begin
  if not assigned(ObjResultat) then begin
     raise EEObjectNotAssigned.Create('Erreur procedure [Methode] objet resultat non créé.');
     exit;
  end;
  ObjResultat.Prop := Obj1.prop (calcul) Obj2.Prop;
end;

et dans le code qui appel la procedure :

begin
  try
    // on essaye d'appliquer la methode
    Methode(M1,M2,MR);
  except
    // MR ne semble pas etre instancié
    on EEObjectNotAssigned do begin
       // alors on le crée
       MR := TClasse.Create;
       // et on retente d'appliquer la methode
       Methode(M1,M2,MR);
    end;
  end;
end;

si on ne gere pas l'exception, alors on aurat un message durant l'execution ... avec la gestion de l'exception en interne, on aurat pas de message durant l'execution.
bien sur, si on est en pleine session Delphi, comme l'execution est en mode de deboggage l'exception s'afficheras.
il faut lancer l'executable independament de Delphi pour ne pas la voir.

les fonctions ne doivent jamais renvoyer une classe ... ceci empeche la liberation propre de ces derniere.
on peu cependant renvoyer des tableaux ou des enregistrements (record) ou encore des ensembles (set of) mais aucunement des classes.

de meme que pour ta fonction "copy" qui devrait s'appelée "Assign" ou "AssignTo" tout depend le sens d'assignation qu'on desire et devrais appartenir a la classe TMatrix :

procedure TMatrix.AssignFrom(const Matrix : Tmatrix);
var i,j:integer;
begin
  if Not Assigned(Matrix) then exit;
  with Self do begin
    ColCount := Matrix.ColCount;
    RowCount := Matrix.RowCount;
    FSquare  := Matrix.Square;
    FSym     := Matrix.Sym;
    FLo      := Matrix.Lo;
    FUp      := Matrix.Up;
    FDiag    := Matrix.Diag;
    FHess    := Matrix.Hess;
    FTriDiag := Matrix.TriDiag;
    // on peut faire ça avec les tableaux a partir du moment qu'ils sont du meme type!
    Cells    := Matrix.Cells;
  end;
end;

ensuite on regle les petits problemes :

function TMatrix.GetRowCount : integer;
begin
  // on renvois la longueur et non l'indice maximum
  // un tableau dynamique commence a 0
  result := length(Cells);
end;

procedure TMatrix.SetRowCount(const RC : integer);
begin
  // si je veux 10 lignes elle seront numerotée de 0 a 9
  SetLength(Cells, RC);
end;

function TMatrix.GetColCount : integer;
begin
  // idem on commence a 0 et on renvois la longueur
  result := length(Cells[0]);
end;

procedure TMatrix.SetColCount(const CC : integer);
begin
  // tu le savais pas ça ? ben maintenant si ...
  SetLength(Cells,length(Cells),CC);
end;

encore d'autre petit probleme :

procedure TMatrix.Define;
var i,j,n : integer;
    a,b   : extended;
begin
   n := RowCount;
   if n = ColCount then begin
      FSquare  := True;  Fsym  := True;  FLo   := True;
      FUp      := True;  FDiag := True;  FHess := True;
      FTridiag := True;
      for i := 0 to n-1 do begin
      for j := 0 to n-1 do begin
          a := Cells[i,j];
          b := Cells[j,i];
          FSym  := not (a <> b);
          FDiag := not (a <> 0);
          if i<j then begin
             FLo := FDiag;
             FTriDiag := not ((j > i+1) and FDiag);
          end;
          if i>j then begin
             FUp := FDiag;
             FTriDiag := not ((i > j+1) and FDiag);
             FHess    := FTriDiag;
          end;
      end;
      end;
   end else begin
      FSquare  := False;  Fsym  := False;  FLo   := False;
      FUp      := False;  FDiag := False;  FHess := False;
      FTridiag := False;
   end;
end;

procedure TMatrix.Transpose;
var i,j,RC,CC:integer;
    M1 : TMatrix;
begin
  RC := RowCount;
  CC := ColCount;
  M1 := TMatrix.Create(RC,CC);
  M1.AssignFrom(Self);
  RowCount := CC;
  ColCount := RC;
  for i := 0 to RowCount-1 do
      for j := 0 to ColCount-1 do
          Cells[i,j] := M1.Cells[j,i];
  M1.Free;
end;

il faut bien rédadapter avec les nouveautées et les corrections d'erreurs.


procedure TMatrix.Add(M:TMatrix);
var i,j,RC,CC:integer;
begin
  RC := M.RowCount;
  CC := M.ColCount;
  if (RC<>RowCount) and (CC<>ColCount) then exit;
  for i := 0 to RC-1 do
      for j := 0 to CC-1 do
          Cells[i,j] := Cells[i,j] + M.Cells[i,j];
end;

procedure TMatrix.Sub(M:TMatrix);
var i,j,RC,CC:integer;
begin
  RC := M.RowCount;
  CC := M.ColCount;
  if (RC<>RowCount) and (CC<>ColCount) then exit;
  for i := 0 to RC-1 do
      for j := 0 to CC-1 do
          Cells[i,j] := Cells[i,j] - M.Cells[i,j];
end;


et enfin, pour liberer un objet on appel pas directement Destroy mais Free!
Free fait des verifications avant d'appeler Destroy.

et si on veux pas se prendre la tete a savoir ou commence le tableau et ou il finit :

for i := low(Cells) to high(Cells) do
    for j := low(Cells[i]) to high(Cells[i]) do
        ...

voila je pense t'avoir donner assé d'elements pour que tu puisse t'en sortir.

a plus

Commentaire de JnBiz le 17/05/2006 17:38:46

Tout d'abord, merci foxi de toutes ces suggestions.
Donc, si j'ai bien compris, on ne pourra pas traiter les matrices comme des nombres avec des fonctions.
Pour ce qui est de la numérotation des indices, je tiens à conserver le fait que le premier élément soit le numéro 1, car c'est quand même beaucoup plus logique pour une matrice.

Commentaire de f0xi le 17/05/2006 19:44:44 administrateur CS

alors, pour un humain oui, la logique veux qu'on appel le premier tiroir d'un meuble le tirroir numero 1.
mais pour un ordinateur cette logique n'est pas applicable le premier tiroir serat le tirroir numero 0.
car si il n'y a pas de tirroir il n'y a pas de valeur donc "null" et null n'est ni 0, ni 1, ni -1 ...
c'est une valeur flou qui determine un element vide, sans valeur.

et quand tu fait un SetLength sur une matrice dynamique, le premier indice serat 0 et non 1.
il faut donc prendre en compte cela car si tu fait SetLength(matrice,10)
low(matrice) renvois 0
high(matrice) renvois 9
et
length(matrice) renvois 10

ce serait comme dire, je compte les minutes a partir de 1 car c'est moins chiant ...
et donc on se retrouve avec des heures comprise dans un interval :
1h 1m 1s 1ms .. 24h 60m 60s 1000ms
ce qui serait une aberation.

si cela te parait plus logique, et je le concois bien, c'est parce que depuis qu'on est tout petit on nous dis que 0 n'est pas une valeur et quand on apprend a compter on compte de 1 a N ... ce qui est par definition mathematiquement inexacte.
on devrait apprendre a compter a partir de Zero qui est un nombre comme les autres et qui surtout est le premier nombre de toute base.
base 2 : 0..1
base 6 : 0..6
base 10: 0..9
base 16: 0..F

donc il est parfaitement logique que le premier indice d'un tableau soit 0 car si le tableau n'a pas de longeur l'indice 0 n'existe pas et on provoqueras une erreur en voulant y acceder.

car par exemple, si nous commencions tout nos tableaux a 1 ...
que ce passerais t'il quand dans un interval -N...+N nous arriverions a zero ?
simple ... il y'aurait un trou qui provoquerais une reaction en chaine ce qui pourrais dechirer le continium espace temps de l'univers entier et brisans ainsi l'equilibre Matiere/Anti-matiere et provoquant le plus grand cataclysme que l'univers est connus, une explosion de plusieurs yotta de yotta de yotta de yotta-tonnes qui detruirait toutes les structures dimensionnelles et qui auraient donc pour effet de boucher les toilettes de notre bon vieux Dieu.

bref ... ça craint du boudin.

donc fait comme tu le sens, mais d'experience je puis t'affirmer qu'il est preferable de compter a partir de 0 ... au moins pour eviter l'apocalypse.

^^


"Donc, si j'ai bien compris, on ne pourra pas traiter les matrices comme des nombres avec des fonctions."

mmm .. si pourquoi ne pourrait-on pas ?
aucune difference entre :

methode(A,B,C)
et
C := Methode(A,B)

c'est meme mieux et plus performant d'utiliser une procedure.
il faut penser "informatique" et pas "mathematique"

si tu connais un peu l'electricité, vois un peu cela comme la difference entre un branchement en serie et un branchement en parallele.

C := methode(A,B) (en serie)
methode(A,B,C) (en parallele)

c'est juste pour faire une analogie.

si A B et C sont des ampoules ... et qu'on les branches en serie C aurat moins de courant et donc brilleras moins.
par contre si on les mets en parrallele ... la elle brillerons toute a la meme intensitée...

ben la c'est pareil.

en passant j'ai fait une erreur : procedure (const M1,M2 : tmatrix; M3: TMatrix)
il ne faut pas mettre VAR.

dans une procedure on fournis 3 variable qui sont des references d'objet.
on vas donc travailler avec ces references ce qui serat plus rapide pour assigner les resultats.

avec une fonction, on doit instancier dynamiquement le resultat pour au final l'assigner a un objet existant. ce qui demande donc des traitements plus (creation > assignation)
sans parler de la gestion de la liberation, au plus propre il faudrait ecrire :

with methode(M1,M2) do
     M3.Cells := Cells;
     Free;
end;

et encore ... pas sur que ça marche et c'est pas trés propre je trouve.
car c'est l'utilisateur qui doit veiller a la liberation ... (on est pas en C++)

le mieux donc est de travailler avec des procedures et des buffers si besoin.

procedure methode(M1,M2,MR);
var buffer;
begin
  Buffer := Create;
  Buffer.Cells := M1.Cells (calcul) M2.Cells;
  MR.Cells := Buffer.Cells;
  Buffer.Free;
end;

ce qui ne nous empeche pas de faire :

methode(M1,M2,M1) ou methode(M1,M2,M2)

ou encore :

add(M1,M2) (additionne M1 et M2 et place le resultat dans M1)
sub(M1,M2) (soustrait M1 et M2 et place le resultat dans M2)

Commentaire de JnBiz le 17/05/2006 20:23:18

Je me suis fait mal comprendre:
J'ai très bien compris que les tableaux dynamiques commencent par 0, seulement dans l'utilisation pratique d'une matrice (donc par un humain) l'élément (1,1) est par convention mathématique le premier élément, d'où ce décalage.
De même pour l'utilisation des fonctions, methode(A,B,C) C := Methode(A,B) ont beau être équivalent pour le calcul, mais pour l'utilisateur (là encore humain) la 2° solution est plus pratique.
Pour résumer je cherche à faire quelque chose de pratique et de naturel pour l'humain qui ne le soit pas forcément pour l'ordinateur (avoue qu'il est plus facile de réecrire un programme que de réecrire l'algèbre des matrices ;-)).
Par contre la dernière solution add(M1,M2) (additionne M1 et M2 et place le resultat dans M1)) me parait un bon compromis, même si cela n'est pas forcément optimisé pour tout types de calculs (genre M3:=M1+M2). Il ne faut pas oublier que le principal facteur limitant dans le calcul matriciel est l'accès en mémoire qu'il faut limiter au max.
C'est pour ca que j'ai prévu 2 types de calcul:
M1.add(M2) (M1=M1+M2)
et M3:=add(M1,M2) (M3=M1+M2)

Maintenant je me demande si le plus pratique ne serait pas de faire un parser qui gérerait les expression du type "M3=(M1+M2)*M2" cela éviterait d'avoir à gérer des matrices temporaires ce qui est pénible.

Commentaire de BruNews le 17/05/2006 20:35:48 administrateur CS

Salut f0xi,

à propos du NULL : à moins d'un cpu comprenant la philo, par force une comparaison à null (comme à quoi que ce soit d'autre) ne se fait que par arythmétique, aucune valeur 'floue' représentable en binaire ni autre base. Il est d'usage de définir NULL à zéro.

JnBiz > 1 comme base d'indexation n'est en RIEN logique, ça indique simplement l'incompréhension de ce qu'est un tableau. L'index indique l'offset pour accéder à l'élément partant de l'adresse de base du tableau:
exemple d'un tableau de INT32:
tab[n] se trouve à: adresse(tab) + n * sizeof(INT32)
Le 1er élém est donc bien à: adresse(tab) + 0 * sizeof(INT32)
Ceci ne te parait pas nettement plus logique ???

Commentaire de JnBiz le 17/05/2006 20:59:59

Brunews, il s'agit d'une convention mathématique, je n'y peux rien, de même le dernier numéro est le numéro n qui correspond également à la taille de la matrice (ce qui n'est pas le cas si on numérote à partir de 0). Une matrice n'est pas qu'un tableau, il y a des règles, des conventions, on ne peut pas faire ce qu'on veut et decréter que le premier élément est placé en (0,0).
C'est juste que les logiques mathématique et informatique différent.
Mais quand il ne s'agit pas de matrices, je rejoins évidemment votre point de vue.

Commentaire de cantador le 25/05/2006 11:32:07

Zéro n'existait pas à l'origine..
c'est pour çà qu'il n'existe pas d'année zéro.
il a donc fallut inventer ce chiffre.
Pour ma part, je concerve cet élément tant que je peux dans les tableaux sinon à chaque fois je tombe sur des cas non prévus déclenchant des exceptions.

Commentaire de tybman le 05/02/2007 22:31:27

Moi je suis un mathématicien et je trouve cela tout simplement fabuleux

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Probleme au niveau des matrices [ par balgrim ] J'aimerais savoir comment utiliser la commande length() dans une matrice: je m'expliquematrice:array of array of byte;X:=length(??? //---&gt; commen Impression QuickReport [ par FeuilleMorte ] Bonjour tout le monde.J'ai un petit soucis (sans gravité) pour mes impressions avec quick Report.Ma prévisualisation se déroule sans problème. Lorsque Problèe dynamique [ par ryadus ] Bonjour;Voici mon Probléme;je dois faire construire des tableau(Tableau=StringGrid et dans mon code ça sera des matrices), ensuite lorsque je rempli c Stocker des vecteurs dans une matrice [ par abidcha ] Bonjour,J'aimerai savoir comment stocker des vecteurs (array) dans un autre array.Merci abidcha choix imprimante sous QR [ par xantro ] bonjour a tous (et &#224; toutes ?)Je cherche &#224; imprimer un etat sous quickReport, cependant je veux que l'utilisateur puisse choisir l'imprimant Calcul de vecteurs propres [ par XgaletteX ] Bonjour,Je voudrai savoir si quelqu'un connait un algo permettant de calculer les valeurs et vecteurs propres d'une matrice carr&#233;e et sym&#233;tr Aide en TURBO PASCAL [ par akros77 ] Bonjour, j'ai actuellement un programme &#224; r&#233;aliser dont voici l'&#233;nonc&#233;: Faire un programme&nbsp; qui effectue la somme ou le produ Lecture d'un fichier [ par ngbalek ] Bonsoir,j'ai un probleme, je voudrai ecrire un programme qui multiplie deux matrices. les deux matrices sont dans deux fichiers differents m1.txt et m violation d'acces en delphi [ par anyaa ] Anyaa Bonjour a tous, je m'excuse d'avancs pour les acccents car je travaille sur un clavier 'qwerty'. J'ai realise un programme en delphi 7, i


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
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 : 1,170 sec (4)

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