Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

Exercise: Matrix Arithmetic

Exercise 31 Easy

Prerequisites for the exercise

  1. JavaScript Array Methods
  2. JavaScript Arrays Basics
  3. All previous chapters

Objective

Implement two functions in JavaScript to return the sum and product of two given matrices.

Description

A matrix is a rectangular block of nubmers comprised of rows and columns. A matrix with ::m:: rows and ::n:: columns is said to be an ::m \times n:: matrix.

Shown below are a couple of matrices, along with their dimensions:

::\begin{bmatrix} 1 & 5 \\ 10 & -2 \end{bmatrix}::
::2 \times 2::
::\begin{bmatrix} 1 & 3 \\ 0 & 0 \\ 6 & 15 \end{bmatrix}::
::3 \times 2::
::\begin{bmatrix} 1 & 9 & 0 & -8 & 10 & 0 \end{bmatrix}::
::1 \times 6::

In JavaScript, a matrix can be represented using a 2D array as follows:

var matrix = [
   [1, 5],
   [10, -2]
];

matrix = [
   [1, 3],
   [0, 0],
   [6, 15]
];

matrix = [
   [1, 9, 0, -8, 10, 0]
];

Each row is represented as an array in the main array. In this inner array, each element represents an entry of the given row.

Matrices can be added, subtracted, and multiplied together.

The addition is represented as ::\text{A} + \text{B}:: and is defined if and only if ::\text{A}:: is ::m \times n:: and ::\text{B}:: is also ::m \times n::. The addition is computed by adding corresponding items in ::\text{A}:: and ::\text{B}:: together.

Following is an illustration:

::\begin{bmatrix} 1 & 3 \\ 0 & 0 \end{bmatrix} + \begin{bmatrix} 5 & -3 \\ 6 & 10 \end{bmatrix} = \begin{bmatrix} 1 + 5 & 3 + (-3) \\ 0 + 6 & 0 + 10 \end{bmatrix} = \begin{bmatrix} 6 & 0 \\ 6 & 10 \end{bmatrix}::

The case for multiplication is quite different.

The multiplication of ::\text{A}:: and ::\text{B}:: is denoted as ::\text{AB}::, and is defined if the number of columns of ::\text{A}:: is the same as the number of rows of ::\text{B}::. In other terms, ::\text{AB}:: is defined if and only if ::\text{A}:: is ::m \times n:: and ::\text{B}:: is ::n \times p::.

It is computed as follows. The ::(i, j)^{th}:: element of ::\text{AB}:: is computed by multiplying corresponding elements in the ::i^{th}:: row of ::\text{A}:: and the ::j^{th}:: column of ::\text{B}:: and then adding them together.

An example is shown below:

::\begin{bmatrix} 1 & 2 \end{bmatrix} \times \begin{bmatrix} 0 & 3 \\ 1 & 5 \end{bmatrix} = \begin{bmatrix} (1 \times 0 + 2 \times 1) & (1 \times 3 + 2 \times 5) \end{bmatrix}::

In this exercise, you have to create two functions multiply and add() that work as follows:

  1. add() takes in two matrices a and b as argument and returns their sum.
  2. multiply() takes in two matrices a and b as argument and returns their product.
View Solution

New file

Inside the directory you created for this course on JavaScript, create a new folder called Exercise-31-Matrix-Arithmetic and put the .html solution files for this exercise within it.

Solution

Let's start with creating the simpler of the two functions namely add() and multiply().

Recall that the function add() takes in two args a and b, both matrices. What we assert is that a and b have the same dimensions and in this way skip the part of checking whether both of them could be validly added together.

However, if this function was part of a JavaScript's predefined set of functions, there would be many many checks laid out in its definition, such as checking whether an and b have the same dimensions; and whether they are arrays or not; and so on. For now, we don't need to worry about these small details.

Coming back to add(), step one is to determine ::m:: and ::n:: from the given matrices a and b.

How to do so?

::m:: is the number of rows of a and b as well, and could simply be determined by inspecting the length property of either array (since both have the same dimensions). Similarly, ::n:: is the number of columns of a (as well as b) and could be determined by inspecting the length of anyone element of a (or b) which is itself an array.

In the code below, we get done with these two prerequisites before moving on to address other concerns:

function add(a, b) {
   var m = a.length,
       n = a[0].length;
}

Alright, let's now see what ought to be done ahead.

Let's start with a question...

How many elements are there in ::\text{A} + \text{B}::?

See, ::\text{A} + \text{B}:: is an ::m \times n:: matrix, likewise it would trivially have ::m \times n:: elements.

For instance, a ::2 \times 2:: matrix would have 4 elements; a ::3 \times 1:: matrix would have 3 elements; a ::10 \times 25:: matrix would have 250 elements; and so on and so forth.

This means that our function would have to compute a total of m * n elements. For each corresponding row in a and b, add the corresponding elements and put them in the final array. And this could be accomplished using a nested for loop — the outer loop taking care of iterating over the given rows and the inner loop taking care of iterating over the given columns.

Altogether, this gives the following code:

function add(a, b) {
   var m = a.length,
       n = a[0].length;

   for (var i = 0; i < m; i++) {
      for (var j = 0; j < n; j++) {
         a[i][j] + b[i][j];
      }
   }
}

Everything is clear uptil now, except for one thing: where do we put the computed sums?

No doubt, we'll need an array. But creating an array isn't sufficient. A matrix is a 2D array, likewise we'll need an array of arrays.

Now there are mainly two ways of doing so:

  1. One is to predefine the final array ::\text{A} + \text{B}:: before we move on to actually compute its elements.
  2. The second is to create the array on-the-go inside the loop where we compute the matrix ::\text{A} + \text{B}::.

We'll go with the latter approach.

Consider the code below:

function add(a, b) {
   var m = a.length,
       n = a[0].length,
sum = []; // this represents a + b for (var i = 0; i < m; i++) {
sum.push([]); for (var j = 0; j < n; j++) {
sum[i].push(a[i][j] + b[i][j]); } }
return sum; }

Time to understand what's happening over here...

At the start, we define an array sum to hold the sum of a and b. This will eventually be the return value of the function.

Moving on, in the outer loop in line 7, we create a row in the array sum using sum.push([]). This enables array operations to be performed on sum[i] (such as sum[i].push()) later on in the following inner loop.

In the inner loop, which goes over each column in a[i], in line 9, we compute the sum a[i][j] + b[i][j], and push it to sum[i] using sum[i].push().

Simple?

This completes our add() function.

Let's now move on to the second function multiply.

The initial setup would be the same as that for add() except for that now there is a third value to consider i.e. p — the number of columns of the matrix b:

function multiply(a, b) {
   var m = a.length,
       n = a[0].length,
p = b[0].length; }

Moving on, as before, let's put forward a simple question.

How many elements are there in ::\text{AB}::?

Given that a and b are ::m \times n:: and ::n \times p:: matrices, respectively, ::\text{AB}:: is an ::m \times p:: matrix, with a total of ::m \times p:: elements.

This just means that in our function, we need to compute ::m \times p:: elements.

As before, a nested loop is to be set up, the outer one going over m rows while the inner one going over p columns in each row.

The way we'll be populating the array would also be the same as in the function add() we defined above i.e. use push([]) to add a new row to the matrix in the outer loop, and then call push() on this row to add a new element to it.

Below, we implement this:

function multiply(a, b) {
   var m = a.length,
       n = a[0].length,
       p = b[0].length;

   var product = []; // this represents a x b

   for (var i = 0; i < m; i++) {
      product.push([]);
      for (var j = 0; j < p; j++) {
         // code to go here
      }
   }
}

As long as the computation itself is concerned, it's a bit thought-provoking. Let's see what's there in it...

Inside the nested loop, we compute the ::(i, j)^{th}:: element of ::\text{A}::. Recall from the statement in the description section above:

The ::(i, j)^{th}:: element of ::\text{AB}:: is computed by multiplying corresponding elements in the ::i^{th}:: row of ::\text{A}:: and the ::j^{th}:: column of ::\text{B}:: and then adding them together.

This means that we need to iterate over the entire ::i^{th}:: row of a and multiply each element with the corresponding element in the ::j^{th}:: column of b, and then sum all these products.

This hints us two things: we need another loop to compute each element and also need a variable to hold the sum of the products within this loop.

Both of these are accomplished in the code below:

function multiply(a, b) {
   var m = a.length,
       n = a[0].length,
       p = b[0].length;

   var product = []; // this represents a x b

   for (var i = 0; i < m; i++) {
      product.push([]);
      for (var j = 0; j < p; j++) {
         var sum = 0;
         for (var k = 0; k < n; k++) {
            sum += a[i][k] * b[k][j]
         }
         product[i].push(sum);
      }
   }
}

Guess what, this is it. This is our multiply() function which will return the product of the matrices a and b.

Amazing!