Exercise: Matrix Arithmetic

Exercise 21 Easy

Prerequisites for the exercise

  1. PHP Multidimensional Arrays
  2. PHP Arrays — Basics
  3. All previous chapters

Objective

Implement two functions in PHP 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 PHP, a matrix can be represented using a 2D array, as follows:

<?php

$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 inside the main array. Then inside 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 p:: and ::\text{B}:: is ::p \times n::.

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} = \begin{bmatrix} 2 & 13 \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 arguments and returns their sum, as another matrix.
  2. multiply() takes in two matrices $a and $b as arguments and returns their product, as a matrix.

For the sake of brevity and simplicity, you shall assume that the arguments provided to add() and multiply() are valid, i.e. you don't have to worry about implementing the functions so as to detect any invalid matrices passed in.

In a later exercise in the upcoming units, we'll extend both these functions with error-handling capabilities in them.

Anyways, shown below is an illustration of the functions in action:

<?php

/* Functions defined here */

$a = [ [1, 3], [0, 0] ];
$b = [ [5, -3], [6, 10] ];
print_r(add($a, $b));

$a = [ [1, 2] ];
$b = [ [0, 3], [1, 5] ];
print_r(multiply($a, $b));
Array ( [0] => Array ( [0] => 6 [1] => 0 ) [1] => Array ( [0] => 6 [1] => 10 ) ) Array ( [0] => Array ( [0] => 2 [1] => 13 ) )
View Solution

New file

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

Solution

Let's start with creating the simpler of the two functions — add().

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

So 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, which is the same as that of $b, and could simply be determined by inspecting the length of $a. Similarly, ::n:: is the number of columns of $a (as well as that of $b) and could be determined by inspecting the length of any element of $a (or $b).

In the code below, we define two variables $m and $n to hold the values of ::m:: and ::n::, respectively:

<?php

function add($a, $b) {
   $m = count($a);
   $n = count($a[0]);
}

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

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 add() function would have to compute a total of $m * $n elements. For each corresponding set of rows in $a and $b, add the corresponding elements in both of them, and then put the sum in the final matrix.

We'll accomplish this using a set of nested for loops — the outer loop taking care of iterating over the given rows while the inner loop taking care of iterating over the given columns.

First and foremost, let's define a variable $matrix to represent the sum matrix, ultimately returned by add(). We'll populate this array in our set of nested loops:

<?php

function add($a, $b) {
   $m = count($a);
   $n = count($a[0]);
$matrix = []; // The matrix representing $a + $b; }

Let's now take a look over the loops:

<?php

function add($a, $b) {
   $m = count($a);
   $n = count($a[0]);
   $matrix = [];

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

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

Inside the outer loop, precisely at line 9, we create a new row in the $matrix array where we'll eventually put the sums computed in the inner loop. If we don't perform this step, the assignment of $matrix[$i][$j] would fail as $matrix[$i] would get resolved as NULL!

In the inner loop, which goes over each column in $a[$i], we compute the sum $a[$i][$j] + $b[$i][$j], in line 11, and then add the result to the matrix[$i] array, as its jth element.

In the end, $matrix is returned.

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:

<?php

function multiply($a, $b) {
   $m = count($a);
$p = count($b); $n = count($b[0]); $matrix = []; }

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 p:: and ::p \times n:: matrices, respectively, ::\text{AB}:: then becomes an ::m \times n:: matrix.

This just means that in our function, we need to compute $m * $n elements.

As before, a set of nested loops ought to be set up — the outer one iterating $m times while the inner one iterating $n times.

The way we'll be populating the $matrix array, which represents the product of $a and $b here, would also be the same as in the function add(), i.e. using $matrix[$i] = [] in the outer loop to add a new row to $matrix, and then assigning to $matrix[$i][$j] to add a new item to this row.

Below, we implement this minimal loop setup:

<?php

function multiply($a, $b) {
   $m = count($a);
   $p = count($b);
   $n = count($b[0]);
   $matrix = [];

   for ($i = 0; $i < $m; $i++) {
      $matrix[$i] = [];
      for ($j = 0; $j < $n; $j++) {
         // Code to go here...
      }
   }
   return $matrix;
}

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{AB}::. Recall the following statement from the exercise's description 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, multiplying each element with the corresponding element in the ::j^{th}:: column of $b, and then sum all these products to obtain $matrix[$i][$j].

This hints us at two things:

  1. We need another nested loop to compute these sums.
  2. We need a variable to hold the sum of the products while we aggregate more values into it and then ultimately dump it into $matrix[$i][$j].

Since this nested loop needs to iterate over the entire $ith row of $a, which has a total of $p items, it'll need to iterate a total of $p times as well (computing the product of corresponding elements in the $ith row of $a and the $jth column of $b).

As for the variable, we'll call it $sum.

Altogether, we get to the following:

<?php

function multiply($a, $b) {
   $m = count($a);
   $p = count($b);
   $n = count($b[0]);
   $matrix = [];

   for ($i = 0; $i < $m; $i++) {
      $matrix[$i] = [];
      for ($j = 0; $j < $n; $j++) {
$sum = 0;
for ($k = 0; $k < $p; $k++) {
$sum += $a[$i][$k] * $b[$k][$j];
}
$matrix[$i][$j] = $sum; } } return $matrix; }

And this completes our exercise.