La gestion des structures de données complexes comme les matrices, les volumes de pixels ou les tenseurs scientifiques peut s'avérer fastidieuse avec les tableaux standards de JavaScript. La bibliothèque ndarray offre une interface robuste pour manipuler des tableaux multidimensionnels de manière efficace, sans duplication de mémoire.
Concept fondamental de ndarray
Contrairement aux tbaleaux imbriqués classiques, ndarray crée une vue sur un espace mémoire contigu (généralement un TypedArray). Cela permet d'accéder aux données via des coordonnées (x, y, z...) tout en conservant des performances optimales. Ses points forts incluent :
- Une empreinte mémoire réduite.
- Le support des dimensions arbitraires.
- La création de "vues" (slices, transpositions) sans copier les données sources.
Installation
Intégrez la bibliothèque à votre projet Node.js ou via un gestionnaire de paquets avec la commande suivante :
npm install ndarray
Initialisation d'un tableau multidimensionnel
Pour créer un ndarray, vous devez fournir un support de stockage (buffer) et définir la forme (shape) de votre structure.
const ndarray = require("ndarray");
// Initialisation d'un buffer de 6 éléments
const donnees = new Float32Array([10, 20, 30, 40, 50, 60]);
// Transformation en une matrice de 3 lignes et 2 colonnes
const matrice = ndarray(donnees, [3, 2]);
/*
Représentation logique :
[ [10, 20],
[30, 40],
[50, 60] ]
*/
Lecture et écriture de données
L'accès aux éléments s'effectue via les méthodes get() et set(), qui font abstraction de l'indexation linéaire du buffer sous-jacent.
// Récupérer l'élément à la ligne 2, colonne 0
console.log(matrice.get(2, 0)); // Affiche 50
// Modifier la valeur à la ligne 0, colonne 1
matrice.set(0, 1, 99);
// Le buffer d'origine 'donnees' est mis à jour automatiquement
console.log(donnees[1]); // Affiche 99
Manipulation avancée : Vues et Transformations
L'un des principaux avantages de ndarray est sa capacité à transformer la perspective sur les données sans modifier le buffer original.
Découpage avec lo() et hi()
Vous pouvez restreindre la vue à une sous-section spécifique du tableau.
const base = ndarray(new Uint8Array(100), [10, 10]);
// Créer une sous-vue de 5x5 à partir de l'index (2, 2)
const sousSection = base.lo(2, 2).hi(5, 5);
// Toute modification de 'sousSection' impacte directement 'base'
sousSection.set(0, 0, 255);
console.log(base.get(2, 2)); // 255
Transposition et inversion
La méthode transpose() réorganise l'ordre des axes, ce qui est essentiel pour les calculs d'algèbre linéaire.
const rect = ndarray(new Float64Array(12), [4, 3]);
const rectTranspose = rect.transpose(1, 0); // Devient une vue de 3x4
Échantillonnage avec step()
step() permet de créer une vue en sautant des éléments ou en inversant l'ordre de lecture.
const sequence = ndarray(new Int32Array(10), [10]);
// Vue contenant un élément sur deux
const impairs = sequence.step(2);
// Vue inversée
const inverse = sequence.step(-1);
Exemple concret : Traitement de grille (Automate cellulaire)
Voici comment implémenter une logique de voisinage, comme celle requise pour le Jeu de la Vie de Conway, en exploitant l'accès multidimensionnel :
function mettreAJourGrille(grilleActuelle, grilleSuivante) {
const largeurs = grilleActuelle.shape[0];
const hauteurs = grilleActuelle.shape[1];
for (let x = 1; x < largeurs - 1; ++x) {
for (let y = 1; y < hauteurs - 1; ++y) {
let voisinsVivant = 0;
// Parcours des 8 cellules adjacentes
for (let i = -1; i <= 1; ++i) {
for (let j = -1; j <= 1; ++j) {
if (i === 0 && j === 0) continue;
voisinsVivant += grilleActuelle.get(x + i, y + j);
}
}
const etatCellule = grilleActuelle.get(x, y);
// Application des règles simplifiées
if (voisinsVivant === 3 || (voisinsVivant === 2 && etatCellule === 1)) {
grilleSuivante.set(x, y, 1);
} else {
grilleSuivante.set(x, y, 0);
}
}
}
}
Écosystème et performance
ndarray n'est pas seulement une bibliothèque isolée, c'est le cœur d'un vaste écosystème. Il existe des modules complémentaires pour :
- ndarray-ops : Pour les opérations arithmétiques vectorisées.
- ndarray-fft : Pour les transformées de Fourier rapides.
- ndarray-gemm : Pour la multiplication de matrices performante.
En utilisant ces outils, vous pouvez atteindre des performances proches du code natif tout en restant dans l'environnement flexible de JavaScript.