在 Javascript 中乘以 2 个矩阵

问题描述 投票:0回答:14

我正在做一个将 2 个矩阵相乘的函数。

矩阵将始终具有相同的行数和列数。 (2x2, 5x5, 23x23, ...)

当我打印它时,它不起作用。为什么?

例如,如果我创建两个 2x2 矩阵:

矩阵A:

[1][2]

[3][4]

矩阵B:

[5][6]

[7][8]

结果应该是:

[19][22]

[43][50]

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

但是,我得到:

[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

javascript arrays matrix matrix-multiplication
14个回答
23
投票

您对各种临时数组感到困惑。

undefined
值是由最内层循环下方的行上的越界访问引起的。

我建议您坚持为乘法结果制作一个数组。您可能已经知道,问题在于 JavaScript 不允许您初始化多维数组。要制作二维数组,您必须初始化一维数组,然后遍历其元素并将每个元素初始化为一维数组。

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


20
投票

您可以使用来自以下网址的 multiplyMatrices() 函数:http://tech.pro/tutorial/1527/matrix-multiplication-in-functional-javascript 它就像魅力一样。示例(您可以使用 console.table() 在 Chrome 和 Firefox 控制台中打印带有样式的矩阵):

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


15
投票

我知道这是一个老问题,但我recommend切换到我的答案。

我的解决方案有很好的性能,因为它使用了

Map
Reduce
功能

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


7
投票

对于那些对纯功能解决方案感兴趣的人:

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

浏览器测试代码:

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

2
投票

此版本将行存储为临时行,从而减少索引查找的有效数量。通过这个 benchmark 与没有存储行的版本相比,实现的性能几乎快 2 倍。

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


1
投票

这是我的带有数学错误处理的 ES6 解决方案:

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

希望对某人有所帮助;)


1
投票

聚会有点晚了,但我想我找到了一个很好的解决方案。

恕我直言,我们在尝试解决此问题时发现的主要挑战是将

MatrixA.row1
MatrixB.col1
联系起来,这是原因之一,大多数解决方案都使用类似
MatrixB[0].length
的方法来获取结果的列数矩阵,而且,就我个人而言,我不喜欢这种“解决方法”(我没有充分的理由,我只是不喜欢它)。但我确实喜欢
map()
s 和
reduce()
的组合,正如 Jan Turoň 所提出的那样。

然后,受到这个矩阵乘法网站的启发,我想:如果生成的矩阵总是

MatrixA.number_of_rows
乘以
MatrixB.number_of_columns
并且痛苦基本上是通过列“迭代”,为什么不转置第二个矩阵?

谢谢hobs,对于transpose function.

最终结果如下(我对结果很满意,因为执行时间非常接近Duloren的解决方案):

你会注意到我无法摆脱

Matrix[0]
的东西,因为我需要这种方法来转置矩阵。好吧...我仍然对结果感到满意:)

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


0
投票

如果你想走疯狂的路线,你也可以在一些现代浏览器中可用的 WebGL 工具中做一些顶点转换。

不太确定这是否会以与 OpenCL 中的向量转换相同的方式工作(**实际上它们是类型等效/可互操作的),但总体思路是:

  • 将您的值添加到缓冲区

  • “假装”它是一个顶点数组

  • 使用 GPU 引擎转换 en-mass

  • 从向量中检索修改后的值

(看这里的演示) http://www.html5rocks.com/en/tutorials/webgl/webgl_transforms/

只是通常的循环方法的替代方法。老实说,考虑到 OpenCL 是为这种事情设计的,有点麻烦

在 OpenCL 1.2 规范中,可以使用 OpenCL 加载和转换来自 OpenGL 的顶点缓冲区(参见。https://software.intel.com/en-us/articles/opencl-and-opengl-interoperability-tutorial


0
投票

您可以使用 Memoization 通过 动态规划 解决此问题。这是一个描述优化技术的术语,您可以在其中缓存先前计算的结果,并在再次需要相同的计算时返回缓存的结果。

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

对于上述saveComputation的输入值将是

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

0
投票

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


0
投票

您可以now 使用 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>

0
投票

向上=)

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

0
投票

这也可以与mathjs一起使用。

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

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

math.multiply(A, B)

-8
投票

npm 安装快递

节点服务器.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);
© www.soinside.com 2019 - 2024. All rights reserved.