web-dev-qa-db-fra.com

Multipliez 2 matrices en Javascript

Je fais une fonction qui multiplie 2 matrices. Les matrices auront toujours le même nombre de lignes et de colonnes. (2x2, 5x5, 23x23, ...)

Lorsque je l'imprime, cela ne fonctionne pas. Pourquoi?

Par exemple, si je crée deux matrices 2x2:

matriceA:

[1][2]

[3][4]

matriceB:

[5][6]

[7][8]

Le résultat devrait être:

[19][22]

[43][50]

( http://ncalculators.com/matrix/2x2-matrix-multiplication-calculator.htm )

Mais je reçois:

[19][undefined]

[22][indefined]
function multiplyMatrix(matrixA, matrixB)
{
    var result = new Array();//declare an array   

    //var numColsRows=$("#matrixRC").val();
    numColsRows=2;
    
    //iterating through first matrix rows
    for (var i = 0; i < numColsRows; i++) 
    {
        //iterating through second matrix columns
        for (var j = 0; j < numColsRows; j++) 
        { 
            var matrixRow = new Array();//declare an array
            var rrr = new Array();
            var resu = new Array();
            //calculating sum of pairwise products
            for (var k = 0; k < numColsRows; k++) 
            {
                rrr.Push(parseInt(matrixA[i][k])*parseInt(matrixB[k][j]));
            }//for 3
            resu.Push(parseInt(rrr[i])+parseInt(rrr[i+1]));

            result.Push(resu);
            //result.Push(matrixRow);
        }//for 2
    }//for 1
    return result;
}// function multiplyMatrix
11
Jordi 45454

Vous vous confondez avec vos différents tableaux temporaires. Les valeurs undefined sont provoquées par un accès hors limites sur la ligne sous votre boucle la plus intérieure.

Je vous recommande de vous en tenir à faire un seul tableau pour le résultat de la multiplication. Comme vous le savez probablement, le problème est que JavaScript ne vous permet pas d'initialiser un tableau multidimensionnel. Pour créer un tableau bidimensionnel, vous devez initialiser un tableau unidimensionnel, puis parcourir ses éléments et initialiser chacun en un tableau unidimensionnel.

function multiply(a, b) {
  var aNumRows = a.length, aNumCols = a[0].length,
      bNumRows = b.length, bNumCols = b[0].length,
      m = new Array(aNumRows);  // initialize array of rows
  for (var r = 0; r < aNumRows; ++r) {
    m[r] = new Array(bNumCols); // initialize the current row
    for (var c = 0; c < bNumCols; ++c) {
      m[r][c] = 0;             // initialize the current cell
      for (var i = 0; i < aNumCols; ++i) {
        m[r][c] += a[r][i] * b[i][c];
      }
    }
  }
  return m;
}

function display(m) {
  for (var r = 0; r < m.length; ++r) {
    document.write('&nbsp;&nbsp;'+m[r].join(' ')+'<br />');
  }
}

var a = [[8, 3], [2, 4], [3, 6]],
    b = [[1, 2, 3], [4, 6, 8]];
document.write('matrix a:<br />');
display(a);
document.write('matrix b:<br />');
display(b);
document.write('a * b =<br />');
display(multiply(a, b));
16
Michael Laszlo

Vous pouvez utiliser la fonction multiplyMatrices () à partir de: http://tech.pro/tutorial/1527/matrix-multiplication-in-functional-javascript cela fonctionne comme un charme. Exemple (Vous pouvez imprimer une matrice avec style dans Chrome et console Firefox avec console.table ()):

function multiplyMatrices(m1, m2) {
    var result = [];
    for (var i = 0; i < m1.length; i++) {
        result[i] = [];
        for (var j = 0; j < m2[0].length; j++) {
            var sum = 0;
            for (var k = 0; k < m1[0].length; k++) {
                sum += m1[i][k] * m2[k][j];
            }
            result[i][j] = sum;
        }
    }
    return result;
}

var m1 = [[1,2],[3,4]]
var m2 = [[5,6],[7,8]]

var mResult = multiplyMatrices(m1, m2)

/*In Google Chrome and Firefox you can do:*/

console.table(mResult) /* it shows the matrix in a table */

Result matrix in console.table()

9
Johann Echavarria

Je sais que c'est une vieille question mais je recommande pour passer à ma réponse.

Ma solution a de bonnes performances car elle utilise les fonctions MapReduce

//The chosen one
function matrixDot (A, B) {
    var result = new Array(A.length).fill(0).map(row => new Array(B[0].length).fill(0));

    return result.map((row, i) => {
        return row.map((val, j) => {
            return A[i].reduce((sum, Elm, k) => sum + (Elm*B[k][j]) ,0)
        })
    })
}

var print = m => m.forEach(r => document.write(`&nbsp;&nbsp;${r.join(' ')}<br/>`)) 

var a = [[8, 3], [2, 4], [3, 6]]
var b = [[1, 2, 3], [4, 6, 8]]

document.write('matrix a:<br />');
print(a);
document.write('matrix b:<br />');
print(b);
document.write('a * b =<br />');
print(matrixDot(a,b));
8
Fernando Carvajal

Si vous vouliez emprunter la voie bonkers, vous pourriez également faire quelque chose avec la transformation des sommets dans les installations WebGL maintenant disponible dans certains navigateurs modernes.

Je ne sais pas vraiment si cela fonctionnerait de la même manière que l'on pourrait aborder la transformation vectorielle dans OpenCL (** en fait, ils sont de type équivalent/interopérables), mais l'idée générale est:

  • ajouter vos valeurs à un tampon

  • "faire semblant" c'est un tableau de sommets

  • transformation en masse à l'aide du moteur GPU

  • récupérer les valeurs révisées du vecteur

(voir la démo ici) http://www.html5rocks.com/en/tutorials/webgl/webgl_transforms/

Juste une alternative à l'approche habituelle en boucle. Et pour être honnête, un peu un violon, étant donné que OpenCL a été conçu pour ce genre de chose

Dans la spécification OpenCL 1.2, les tampons de vertex d'OpenGL peuvent être chargés et transformés à l'aide d'OpenCL (voir. https://software.intel.com/en-us/articles/opencl-and-opengl-interoperability-tutorial =)

1
user3580838

Vous pouvez résoudre ce problème avec programmation dynamique en utilisant mémorisation. Il s'agit d'un terme décrivant une technique d'optimisation dans laquelle vous mettez en cache les résultats précédemment calculés et renvoyez le résultat mis en cache lorsque le même calcul est à nouveau nécessaire.

        let mat1 = [[1, 2, 3], [2, 1, 2]];

        let mat2 = [[1, 2], [1, 2], [1, 2]];

        function matrixMulti(x, y) {
          let saveComputation = {};
          let finalMat = [],
               length=x.length,
               length1 =  y[0].length,
               length2 =  y.length;
          for (let i = 0; i < length; i++) {
            finalMat.Push([]);
            for (let j = 0; j < length1; j++) {
              finalMat[i][j] = 0;
              for (let k = 0; k < length2; k++) {
    // check if we already computed this calculation or not
                if (saveComputation[y[k][j] + '*' + x[i][k]] || saveComputation[x[i][k] + '*' + y[k][j]]) {
                  finalMat[i][j] = finalMat[i][j] + saveComputation[y[k][j] + '*' + x[i][k]];
                } else {
// save if not computed
                  saveComputation[x[i][k] + '*' + y[k][j]] = x[i][k] * y[k][j]; // check format below how it is saved.
                  saveComputation[y[k][j] + '*' + x[i][k]] = x[i][k] * y[k][j];
                  finalMat[i][j] = finalMat[i][j] + saveComputation[y[k][j] + '*' + x[i][k]];
                }
              }
            }
          }

          console.log(finalMat);
        }

        matrixMulti(mat1, mat2);

Pour la valeur d'entrée ci-dessus de saveComputation sera

{ '1*1': 1,
  '2*1': 2,
  '1*2': 2,
  '3*1': 3,
  '1*3': 3,
  '2*2': 4,
  '3*2': 6,
  '2*3': 6 }
1
Shumi Gupta