Arraymatrix -matrice multidimensionelle et générique- , implementation , test de perfomance et test de l'unité

Soyez le premier à donner votre avis sur cette source.

Vue 3 282 fois - Téléchargée 237 fois

Description

Approche répondant à la source de Julien39 sur l'alternative sur des Array's d'object.

Méthodes:
- Ajouter un élément de type T
- lire un élément de type T

Test de performance:
- cette classe est testée contre un tableau multidimensionnel classique: voir resultat ci-dessous

la classe ci-dessous est la classe de Test. l'implementation de ArrayMatrix est dans le zip

Source / Exemple :


package crx.lbs.math;

import junit.framework.Assert;

import org.junit.Test;

/**

  • @author Labandus
  • /
public class MockingArrayMatrix { /**
  • functionTest of this Unit methods like put(), get() , inbound are tested
  • /
@Test public void _functionTestArrayMatrix() { ArrayMatrix<String> arrayMatrix = new ArrayMatrix<String>(new int[] { 2, 3, 4 }); // checking if the coordinates are inbound ([1,2,4] --> only the last // coordinate 4 is out of the bound) Assert.assertFalse(arrayMatrix.isInBound(new int[] { 1, 2, -3 })); // inserting in the bound and retrieving in the bound arrayMatrix.putElement(new int[] { 0, 1, 3 }, "Hallo"); Assert.assertTrue("Hallo".equals(arrayMatrix.getElement(new int[] { 0, 1, 3 }))); // inserting out of bound and retrieving out of bound arrayMatrix.putElement(new int[] { 0, 1, 4 }, "Hallo"); Assert.assertFalse("Hallo".equals(arrayMatrix.getElement(new int[] { 0, 1, 4 }))); } /**
  • checking the performance of the ArrayMatrix against a "classic" Array
  • /
@Test public void _perfomanceTestArrayMatrix() { short dim_x = 5; short dim_y = 7; short dim_z = 10; long arrayStartTime = 0; // start Time for the "classic" Array; long arrayEndTime = 0; // end Time for the "classic" Array; long arrayMatrixStartTime = 0; // start Time for the ArrayMatrix; long arrayMatrixEndTime = 0; // end Time for the ArrayMatrix; // ----- Initialization of the classic Array---- arrayStartTime = System.currentTimeMillis(); String[][][] arrayString = new String[dim_x][dim_y][dim_z]; for (int i = 0; i < dim_x; i++) for (int j = 0; j < dim_y; j++) for (int k = 0; k < dim_z; k++) arrayString[i][j][k] = "String (" + i + " " + j + " " + k + ")"; arrayEndTime = System.currentTimeMillis(); System.out.println(" classic Array elapsed time for initialization: " + (arrayEndTime - arrayStartTime) + " ms"); // ----- Initialization of the ArrayMatrix---- arrayMatrixStartTime = System.currentTimeMillis(); ArrayMatrix<String> arrayMatrix = new ArrayMatrix<String>(new int[] { dim_x, dim_y, dim_z }); for (short i = 0; i < dim_x; i++) for (short j = 0; j < dim_y; j++) for (short k = 0; k < dim_z; k++) arrayMatrix.putElement(new int[] { i, j, k }, "String (" + i + " " + j + " " + k + ")"); arrayMatrixEndTime = System.currentTimeMillis(); System.out.println(" ArrayMatrix elapsed time for initialization: " + (arrayMatrixEndTime - arrayMatrixStartTime) + " ms"); // ----- Reading of the classic Array---- arrayStartTime = System.currentTimeMillis(); for (int i = 0; i < dim_x; i++) for (int j = 0; j < dim_y; j++) for (int k = 0; k < dim_z; k++) System.out.println(arrayString[i][j][k]); arrayEndTime = System.currentTimeMillis(); System.out.println("elapsed time for reading: " + (arrayEndTime - arrayStartTime) + " ms"); // ----- Reading of the ArrayMatrix---- arrayMatrixStartTime = System.currentTimeMillis(); for (short i = 0; i < dim_x; i++) for (short j = 0; j < dim_y; j++) for (short k = 0; k < dim_z; k++) System.out.println(arrayMatrix.getElement(i, j, k)); arrayMatrixEndTime = System.currentTimeMillis(); System.out.println("ArrayMatrix elapsed time for reading: " + (arrayMatrixEndTime - arrayMatrixStartTime) + " ms"); } }

Conclusion :


après mes test j'ai juste trouvé la classe moins rapide (qq ms en plus sur le normal) aussi bien dans l'initialisation( worst case: 4ms de plus ) que dans la lecture des données( worst case: 1,6 de plus que le classic).. mais plus SURE dans le design et la maintenance du code dans un projet:

En effet cette classe, contrairement à l'array nous permettra d'ajouter des nouvelles fonctionalité pour de multiples classes graces à la généricité.

Design VS rapidité ? on choisit quoi ?
merci pour vos commentaires pour améliorer la rapidité d'exécution des méthodes... je crois qu'avec une bonne approche, on peut égaler l'array classique.

la lenteur vient du fait de gérer l'aspect multidimensionnel manuellement (vérifier la validité des coordonnées, ajouter , etc).

Neamoins c fut une bon exo sur la conception et le design des classes.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
25
Date d'inscription
jeudi 14 décembre 2000
Statut
Membre
Dernière intervention
25 juillet 2013
1
quand au nombres complexes s'ils sont stockés , ils le seront dans des objects... object que peut contenir la classe.
Messages postés
25
Date d'inscription
jeudi 14 décembre 2000
Statut
Membre
Dernière intervention
25 juillet 2013
1
pour eviter de me repeter , je demanderais de regarder ma réponse: cette source est un APPROCHE et pas une source productive. C'est pour cela que que j'ai des test de performances, représentée dans la classe Mock..

Quand à des NIO Buffers, c'est cas spécial , qui n'était pas considérés au début de l’écriture de la source...
je verrais ce cas dans plus tard.

les matrices creuses sont spéciales et demanderaient une approche speciale.. , a cause de valeur "nulles". Une méthode pourrait être le format Yale Sparse Matrix (A,IA,JA), l'approche semble intéressante je ferais de mis À jour...

par conformité aux autres APIs, j'ai mis des int.
Utilisateur anonyme
Ce serait bien que tu postes un lien vers la source de Julien39 pour que les gens sachent de quoi nous parlons.

Tu ne devrais pas utiliser une liste pour faire ça comme tu es sensé connaître la taille de la matrice dès le début et que le temps d'accès à une liste est plus long que le temps d'accès à un tableau.

J'ai parlé des matrices creuses mais ton implémentation ne dispose pas d'optimisation pour stocker ce genre de matrice donc je ne vois pas pour le moment ce que ton implémentation apporte de plus aux APIs existantes.

Les nombres complexes peuvent être stockées sous forme de nombres réels si tu les exprimes dans leur forme vectorielle, de même pour les nombres hypercomplexes donc je maintiens que je ne vois absolument pas l'intérêt de l'utilisation de la généricité dans ce cas précis.

Elle va être super la communication avec le monde extérieur surtout dans le cas des NIO buffers s'il faut répercuter les modifications de la matrice dans une autre structure de données et allouer de la mémoire pour une structure séparée. Si tu avais utilisé un tableau, une API utilisant des NIO buffers aurait simplement eu à envelopper le tableau dans un NIO buffer (avec la méthode wrap) et les modifications dans le tableau auraient été automatiquement répercutées dans le NIO buffer. En gros, ta solution n'est pas adaptée à des solutions de calcul ayant besoin de communiquer avec OpenCL (JOCL), OpenGL (JOGL) et d'autres API écrites dans d'autres langages (en Fortran par exemple, cas courant en physique) qui peuvent avoir besoin de passer par les NIO buffers pour éviter la duplication mémoire dans la communication entre le code Java et le code natif.

Dans les API Java standards, les indices sont stockés sur des entiers signés 32 bits (int) et non sur des shorts. Pourquoi garder des shorts alors que les autres API utilisent des ints? Cela ajoute de la confusion et est sans intérêt.
Messages postés
25
Date d'inscription
jeudi 14 décembre 2000
Statut
Membre
Dernière intervention
25 juillet 2013
1
@gouessej merci pour ton message. ma réponse:

1- pourquoi la classe ArrayMatrix ? : la description de cette source répond à ta question. Cette classe est une "réponse" à une source qui avait été donnée par un utilisateur. Certaines faiblesses (selon moi) de son code et surtout le désir de tester la performance qu'une matrice multidim , basée sur une liste, aurait par rapport un array multidim ont été les causes de l'ecriture de cette classe. Celle ci est une APPROCHE et non un produit fini, venant concurrencer avec les APIS courantes.Toi même tu l'as dit: aucune API courantes n'a "d'implémentations optimisées des matrices creuses (sauf peut-être celle du C.E.R.N)". Le travail fait dans cette classe est un travail de recherche.

2- pourquoi un paramètre générique au lieu d'un paramètre de classe connue (ex.: Number, Integer): tout simplement parce qu'un matrice est une structure qui ne se limite pas seulement au nombre réels, représenter par la Number et ses derivées. A part ces classes, la matrices peuvent au contenir des variables de l'ensemble C , des complexes, ou des types plus abstraits. Matrice ne rime pas seulement avec nombres réels, mais elle est d'abord une structure d'ORDRE et d'ARRANGEMENT pour des valeur d'un certain types. j'essaie juste de donner une valeur la plus flexible possible; d’où le type générique.

3- "Pour qu'une classe générique de matrice puisse communiquer avec des APIs basées sur des NIO buffers, il faudrait au moins que tu stockes tes valeurs dans un seul tableau à une dimension" : pour toutes communication avec le monde extérieur, j'ai défini des getters/setters (comme getElement/putElement). cela suffit pour communiquer avec le monde extérieur (les NIO BUFFER inclus).

4- Pourquoi utiliser des shorts pour les coordonnées: juste parce que je sais, par expérience que la dimension correspond au besoin moyenne dans le monde réel (max 32,767 element). tu voudrais elargir la tente , alors tu es libre: c'est ça la miracle de l'open source

5- "Je crois qu'on peut faire "pêter" ta classe en passant des valeurs négatives": cette phrase doit maintenant être prononcée au passé, car le bug est fixé... ;)
Utilisateur anonyme
Bonjour

Je n'aime pas trop la classe ArrayMatrix. Déjà, on peut stocker très peu de types d'objets différents dans une matrice, une simple classe reprenant les opérations de base sur les matrices et manipulant des instances de la classe abstraite Number aurait été un peu plus utile.

D'autre part, en informatique, on a souvent besoin de manipuler des matrices creuses, elles sont plutôt implémentées à l'aide de graphes pour occuper moins de mémoire, cela ne veut pas dire que les classes en question ont un mauvais design.

Pourquoi utiliser des shorts pour les coordonnées??

Je crois qu'on peut faire "pêter" ta classe en passant des valeurs négatives...

As-tu regardé ce qui se fait dans des APIs couramment utilisées? On n'essaie pas d'avoir une classe générique pour gérer les matrices, on fait au plus 2 classes (une pour les floats, une pour les doubles) voire 2 classes par dimension et ça s'arrête là.

Pour qu'une classe générique de matrice puisse communiquer avec des APIs basées sur des NIO buffers, il faudrait au moins que tu stockes tes valeurs dans un seul tableau à une dimension (tu peux simuler un tableau multi-dimensionnel avec un tableau à une seule dimension bien évidemment).

Tu ajoutes des valeurs nulles au lieu de simplement utiliser le constructeur qui permet de fixer la capacité d'une liste.

Pour résumer, si une classe Matrix n'existe pas dans l'API standard Java, c'est surtout parce que l'implémentation diffère beaucoup entre les matrices creuses et les autres. Tu crées des tonnes d'objets alors que dans de vrais calculs, on essaie d'utiliser à fond des types primitifs (sauf pour les très grandes valeurs, cf. les classes BigInteger et BigDecimal). Je ne vois pas la valeur ajoutée qu'apporte ta classe. Je te conseille de jeter un coup d'oeil aux codes sources d'OpenMaLi, de javax.vecmath, de C.E.R.N Colt et d'Ardor3D-core math sachant que ces bibliothèques n'ont pas d'implémentations optimisées des matrices creuses (sauf peut-être celle du C.E.R.N).

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.