Jordi 45454
Jordi 45454

Reputation: 295

Multiply 2 matrices in Javascript

I'm doing a function that multiplies 2 matrices.

The matrices will always have the same number of rows and columns. (2x2, 5x5, 23x23, ...)

When I print it, it doesn't work. Why?

For example, if I create two 2x2 matrices:

matrixA:

[1][2]

[3][4]

matrixB:

[5][6]

[7][8]

The result should be:

[19][22]

[43][50]

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

But, I get:

[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

Upvotes: 21

Views: 91304

Answers (14)

David Contreras
David Contreras

Reputation: 236

this can also work with mathjs.

A = [[1, 2],
     [3, 4]]

B = [[5, 6],
     [7, 8]]

math.multiply(A, B)

Upvotes: 2

Ivan
Ivan

Reputation: 1

UP =)

function multiplyMatrices(m1, m2) {
  const result = new Array(m1.length)
    .fill(0)
    .map(() => new Array(m2[0].length)
      .fill(0));

  return result
    .map((row, i) => row
      .map((_, j) => m1[i]
        .reduce((sum, e, k) => sum + (e * m2[k][j]), 0)));
}

Upvotes: -1

Italo
Italo

Reputation: 11

A little bit late for the party, but I think I got a good solution.

IMHO the main challenge that we find when trying to solve this is to relate MatrixA.row1 with MatrixB.col1 and that is one of the reasons, most of the solutions use something like MatrixB[0].length to get the number of columns for the resulting matrix, and, personally, I don't like this "workaround" (I don't have a good reason, I just don't like it). But I do like the combinations of map()s and reduce() as proposed by Jan Turoň.

Then, inspired by this Matrix Multiplication website I thought: If the resulting matrix is always MatrixA.number_of_rows by MatrixB.number_of_columns and the pain is basically to "iterate" through columns, why not transpose the second matrix?

Thank you hobs, for the transpose function.

The final result is the following (I am pretty happy with the result since the time for execution is pretty close to Duloren's solution):

You will notice that I couldn't get rid of the Matrix[0] thing because I needed this approach to transposing the matrix. Well...I am still happy with the result :)

const a = [
  [1, 2, 0],
  [6, 3, 8]
];

const b = [
  [4, 6],
  [1, 9],
  [4, 8]
];

function multiplyMatrix(a, b) {
  const tB = transpose(b);

  // Return the matrix (array of rows)
  return a.map((row_a) => {
  
    // Return the rows with the values (array of values where the length
    // will be the number of columns of 'b', which is the same as
    // the length of `tB` (transposed `b`))
    return tB.map((row_b) => {

      // Return the sum of the products, which is the final value itself
      // (therefore, defines the columns)
      return row_a.reduce((carry, value_of_a, index_of_column_of_a) => {
        
        // Because we transposed `b` the value in b that corresponds to a specific
        // value in `a` will have the same `column_index`.
        const corresponding_b = row_b[index_of_column_of_a];

        return carry + (value_of_a * corresponding_b);
      }, 0);
    });
  });
}

function transpose(m) {
  return Object.keys(m[0]).map(columnIndex => {
    return m.map(row => row[columnIndex])
  });
}


function printMatrix(m, h = '') {
  // console.table(m);
  
  // For those that don't support the console.table()
  let output = h + '\n--------\n';
  
  output += m.reduce((carry, row) => {
    return carry += row.join('    ') + '\n';
  },'');

  console.log(output);
}


printMatrix(a, 'A');
printMatrix(b, 'B');
printMatrix(multiplyMatrix(a, b), 'A times B');
console.log('==========');
printMatrix(transpose(b), 'Transposed B');

Upvotes: 1

anjanesh
anjanesh

Reputation: 4251

You can now achieve this using TensorFlow.js:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
    <script>
      const matrix_1 = tf.tensor([[1,2],[3,4]]);
      const matrix_2 = tf.tensor([[5,6],[7,8]]);
      
      const matrix_result = tf.matMul(matrix_1, matrix_2);
      matrix_result.print()
    </script>
  </head>
  <body>
    <h1>Check the console log!</h1>
  </body>
</html>

Upvotes: 0

Duloren
Duloren

Reputation: 2711

This version stores rows as temporaries thus reducing the effective amount of index lookups. By this benchmark the achieved performance is almost 2 times faster if compared to the version withou storing rows.

function multiply(a, b) {
    let aRows = a.length;
    let aCols = a[0].length;
    let bCols = b[0].length;
    let result = new Array(aRows); 
    for (let r = 0; r < aRows; ++r) {
        const row = new Array(bCols);
        result[r] = row;
        const ar = a[r];
        for (let c = 0; c < bCols; ++c) {
            let sum = 0.;     
            for (let i = 0; i < aCols; ++i) {
                sum += ar[i] * b[i][c];
            }
            row[c] = sum;  
        }
    }
    return result;
}

const m = multiply(
        [[8, 3], [2, 4], [3, 6]],
        [[1, 2, 3], [4, 6, 8]]
    );
console.log(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));

Upvotes: 2

Alex Chebotarsky
Alex Chebotarsky

Reputation: 513

Here's my ES6 soulution with math error handling:

const matrixDot = (A, B) => {
  // Error handling
  const mx = [A, B];
  const cols = mx.map((matrix) => matrix[0].length);
  if (!mx.every((matrix, i) => matrix.every((row) => row.length === cols[i]))) {
    throw new Error(
      'All rows in a matrix must have the same number of columns'
    );
  } else if (cols[0] !== B.length) {
    throw new Error(
      'The number of columns in the 1st matrix must be equal to the number of rows in the 2nd matrix'
    );
  }

  // Calculations
  return A.map((rowA) =>
    B[0].map((_, xb) =>
      rowA.reduce((acc, itemA, yb) => acc + itemA * B[yb][xb], 0)
    )
  );
};

// Example
const A = [
  [3, 2, 5],
  [6, 4, 1],
];
const B = [
  [2, 6],
  [5, 3],
  [1, 4],
];
console.log(matrixDot(A, B));

Hope it helps somebody ;)

Upvotes: 1

davidames0523
davidames0523

Reputation: 1

const getDot = (arrA, arrB, row, col) => {
    return arrA[row].map((val, i) => (val * arrB[i][col]))
  .reduce((valA, valB) => valA + valB);
}

const multiplyMatricies = (a, b) => {
    let matrixShape = new Array(a.length).fill(0)
      .map(() => new Array(b[0].length).fill(0));
        return matrixShape.map((row, i) =>
          row.map((val, j) => getDot(a, b, i, j)));
      }

    const arrA = [
      [1, 3, 0],
      [2, 1, 1]
    ];
    const arrB = [
      [1, 2, 0, 1],
      [2, 3, 1, 2],
      [1, 2, 1, 1]
    ];

    let product = multiplyMatricies(arrA, arrB);
    console.log("product:", product);

Upvotes: 0

Jan Turoň
Jan Turoň

Reputation: 32912

For those interested in pure functional solution:

let MatrixProd = (A, B) =>
  A.map((row, i) =>
    B[0].map((_, j) =>
      row.reduce((acc, _, n) =>
        acc + A[i][n] * B[n][j], 0
      )
    )
  )

Testing code for your browser:

let A = [[8, 3], [2, 4], [3, 6]];
let B = [[1, 2, 3], [4, 6, 8]];
console.table(MatrixProd(A,B));

Upvotes: 8

Fernando Carvajal
Fernando Carvajal

Reputation: 1945

I know it's an old question but I recommend to switch to my answer.

My solution's got good performance because it uses Map Reduce functions

//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));

Upvotes: 14

Shumi Gupta
Shumi Gupta

Reputation: 1525

You can solve this problem with dynamic programming using Memoization. It is a term describing an optimization technique where you cache previously computed results, and return the cached result when the same computation is needed again.

        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);

For the above input value of saveComputation will be

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

Upvotes: 0

EDdy
EDdy

Reputation: 25

npm install express

node server.js

var express = require('express');
var app = express();


var A=new Array(3);
var B=new Array(3);
var preA = [ 1, 2, 3, 4, 5, 6,7, 8, 9 ];
var preB = [ 1,1 ,1,2,2, 2,3, 3, 3 ];

//#########################preparing blank 3*3 matrix A and B###############
for(i=0;i<3;i++){
    A[i]=new Array(3);
    B[i]=new Array(3);
}



//#####################Assigning values to matrix places from predefine arrays preA and preB #####
var k=0;
for(i=0;i<3;i++){
    for(j=0;j<3;j++){

        A[i][j]=preA[k];
        B[i][j]=preB[k];
        k++;
    }
};


console.log('################################');
console.log('First matrix:');
console.log(A[0]);
console.log(A[1]);
console.log(A[2]);
console.log('');
console.log('################################');
console.log('Second matrix:');
console.log(B[0]);
console.log(B[1]);
console.log(B[2]);

//###################### multiplication logic as disscussed ################
var result =[];
 for (var i = 0; i < 3; i++) {
        result[i] = new Array(3);
        for (var j = 0; j < 3; j++) {
            var sum = 0;
            for (var k = 0; k < 3; k++) {
                sum += A[i][k] * B[k][j];
            }
            result[i][j] = sum;
        }
    }
console.log('');
console.log('################################');
console.log('################################');
console.log('After Multiplication');

console.log(result[0]);
console.log(result[1]);
console.log(result[2]);



app.listen(9999);

Upvotes: -9

user3580838
user3580838

Reputation: 39

If you wanted to go the bonkers route, you could also possibly do something with the vertices transformation in WebGL facilities now available in some modern browsers.

Not really sure if this would work in the same way as one might approach vector transformation in OpenCL (**in fact they're type-equivalent / interoperable), but the general idea is:

  • adding your values to a buffer

  • "pretending" it's an array of vertices

  • transforming en-mass using the GPU engine

  • retrieving the revised values from the vector

(see demo here) http://www.html5rocks.com/en/tutorials/webgl/webgl_transforms/

Just an alternative to the usual loop-in-loop approach. And to be honest, a bit of a fiddle, given that OpenCL was designed for this kind of thing

Within the OpenCL 1.2 spec vertex buffers from OpenGL can be loaded and transformed using OpenCL (see. https://software.intel.com/en-us/articles/opencl-and-opengl-interoperability-tutorial)

Upvotes: 1

Johann Echavarria
Johann Echavarria

Reputation: 9945

You can use multiplyMatrices() function from: http://tech.pro/tutorial/1527/matrix-multiplication-in-functional-javascript it works like charm. Example (You can print a matrix with style in Chrome and Firefox console with 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()

Upvotes: 20

Michael Laszlo
Michael Laszlo

Reputation: 12239

You're getting confused with your various temporary arrays. The undefined values are caused by out-of-bounds access on the line below your innermost loop.

I recommend that you stick to making a single array for the result of the multiplication. As you're probably aware, the hitch is that JavaScript doesn't allow you to initialize a multi-dimensional array. To make a two-dimensional array, you have to initialize a one-dimensional array, then iterate over its elements and initialize each one to a one-dimensional array.

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));

Upvotes: 24

Related Questions