Using For Loops in Octave or MATLAB to Investigate the Properties of a Magic Square

Donations

£1.00

Introduction

This example will look at a simple 4 by 4 magic square, shown below. Logical indexing and the sum function (with a single input argument) will be used to look at the sum of each row, each column, the diagonal and antidiagonal in the magic square. For this you need to be comfortable with running Octave/MATLAB and need to understand how to measure the size of an array and use logical indexing. See my guide Introduction to Arrays in Octave and MATLAB if you need a refresher.

As computing the sum of rows for example is an operation being carried out for a sequence of events, it can be automated by using a for loop.

Note much of the steps below can be simplified by inputting multiple input arguments into the sum function and using the diag, flip, flipud and fliplr functions however the main point of this written guide is to introduce the powerful tool of for loops using a simple example.


Create a Magic Square

Working with a Magic Square is a good way to practice working with logical indexing of arrays and hence explore the concept behind creating a for loop. A Magic Square can be created using the magic function, the input argument will be the size of the square, in this case I will use 4:

% The magic square
M=magic(4)

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]


Look at a Matrix Dimensions

Although we know the size of the square is 4 by 4, let’s use the size function to prescribe the magic squares dimensions to the variables m (number of rows) and n (number of columns).

[m,n]=size(M)

\displaystyle \begin{array}{l}\text{m}=4\\\text{n}=4\end{array}


Initialisation of Output Array – sumrow

To begin we should initialise our column vector which contains a column of sums for each row. This can be done using the zeros function, the inputs for the zero function are m and 1 as we are looking for a column vector that has m rows (and 1 column)

sumrow=zeros(m,1)

\displaystyle \text{sumrow}=\left[ {\begin{array}{*{20}{c}} 0 \\ 0 \\ 0 \\ 0 \end{array}} \right]

Initialisation in essence, creates an array with the desired variable name and desired final dimensions. In this case the column of sums which is going to be m rows by 1 column. At initialisation we don’t know the values of each element in the array so we prescribe each value to 0. We can sub-sequentially use logical indexing to replace each of the values in this column vector.


Look at the Sum of the First Row

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

Let’s look at the first row:

sumrow(1)=sum(M(1,[1:n]))

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {16+2+3+13} \\ 0 \\ 0 \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ 0 \\ 0 \\ 0 \end{array}} \right]\end{array}

This can also be abbreviated as:

sumrow(1)=sum(M(1,:))

What we are essentially doing on the left hand side is using logical indexing to prescribe the value to the 1st index of the column vector sumrow. To the right hand side we are using logical indexing to create a row vector and inputting this row vector into the sum function. The scalar calculated from the sum function is prescribed to the 1st index of the column vector sumrow.


Look at the Sum of Each Row

We can now manually go through the same process by looking at each row in turn.

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

sumrow(1)=sum(M(1,:))

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {16+2+3+13} \\ 0 \\ 0 \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ 0 \\ 0 \\ 0 \end{array}} \right]\end{array}

sumrow(2)=sum(M(2,:))

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {5+11+10+8} \\ 0 \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ 0 \\ 0 \end{array}} \right]\end{array}

sumrow(3)=sum(M(3,:))

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {9+7+6+12} \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {34} \\ 0 \end{array}} \right]\end{array}

sumrow(4)=sum(M(4,:))

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {34} \\ {4+14+15+1} \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {34} \\ {34} \end{array}} \right]\end{array}


Look at the Sum of Each Row in a For Loop

Note how we used the following lines of code, these all look identical with exception to the part highlighted in red

sumrow(1)=sum(M(1,:))

sumrow(2)=sum(M(2,:))

sumrow(3)=sum(M(3,:))

sumrow(4)=sum(M(4,:))

These can be combined together using a for loop. The for loop has to start with for followed by some condition which increments from a starting point in steps until an ending point. We use end to end the for loop.

for condition

end

We need to create a condition that increments during each iteration of the for loop, let’s call it A. From the above, the only change in the line of code is the value in red, we need to set this to A and have A to equal the value shown above for each iteration of a for loop. Thus we know that A starts at 1, then steps up by increments of 1 to 2, 3 and ends at m which in this case is 4. This condition is met when A=[1:m]', the transpose is used because we are looking for a column vector, containing the sum value of each row.

for A=[1:m]'

end

Now we can rewrite:

sumrow(1)=sum(M(1,:))

sumrow(2)=sum(M(2,:))

sumrow(3)=sum(M(3,:))

sumrow(4)=sum(M(4,:))

As a single line in terms of A:

sumrow(A)=sum(M(A,:))

To the left hand side we are embedding into the Ath index of the column vector sumrow. To the right hand side we are calculating the sum of each row of M.

This line of code should be embedded within the for loop. The convention is to indent any code embedded in a loop therefore it will have the form:

for  A=[1:m]'

    sumrow(A)=sum(M(A,:))

end

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

When running this code, we will therefore start with the following

sumrow=zeros(m,1)

\displaystyle \text{sumrow}=\left[ {\begin{array}{*{20}{c}} 0 \\ 0 \\ 0 \\ 0 \end{array}} \right]

The code

for A=[1:m]'

    sumrow(A)=sum(M(A,:))

end

In the first step will become

for A=1

    sumrow(1)=sum(M(1,:))

end

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {16+2+3+13} \\ 0 \\ 0 \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ 0 \\ 0 \\ 0 \end{array}} \right]\end{array}

In the second step will become

for A=2

    sumrow(2)=sum(M(2,:))

end

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {5+11+10+8} \\ 0 \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ 0 \\ 0 \end{array}} \right]\end{array}

In the third step it will become

for A=3

    sumrow(3)=sum(M(3,:))

end

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {9+7+6+12} \\ 0 \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {34} \\ 0 \end{array}} \right]\end{array}

In the mth step, it will become

for A=m

    sumrow(m)=sum(M(m,:))

end

\displaystyle \begin{array}{l}\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {34} \\ {4+14+15+1} \end{array}} \right]\\\text{sumrow}=\left[ {\begin{array}{*{20}{c}} {34} \\ {34} \\ {34} \\ {34} \end{array}} \right]\end{array}

This gives us the m by 1 column vector of the sums of the rows of the magic square respectively.


Initialisation of Output Array – sumcol

Now we can follow a similar procedure. This time looking at the sums of each column which will give us a row vector called sumcol. To begin we should initialise our row vector which contains a row of sums for each column. This can be done using the zeros function, the inputs for the zero function are 1 and n as we are looking for a row vector that has (1 row and) m columns

sumrow=zeros(1,n)

\displaystyle \text{sumcol}=\left[ {\begin{array}{*{20}{c}} 0 & 0 & 0 & 0 \end{array}} \right]

Initialisation in essence, creates an array with the desired variable name and desired final dimensions. In this case the column of sums which is going to be m rows by 1 column. At initialisation we don’t know the values of each element in the array so we prescribe each value to 0. We can sub-sequentially use logical indexing to replace each of the values in this column vector.


Look at the Sum of the First Column

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

Let’s look at the first column

sumcol(1)=sum(M([1:m]',1))

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} \begin{array}{l}16\\+\\5\\+\\9\\+\\4\end{array} & 0 & 0 & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & 0 & 0 & 0 \end{array}} \right]\end{array}

This can also be abbreviated as:

sumcol(1)=sum(M(:,1))

What we are essentially doing on the left hand side is using logical indexing to prescribe the value to the 1st index of the row vector sumcol. To the right hand side we are using logical indexing to create a column vector and inputting this column vector into the sum function. The scalar calculated from the sum function is prescribed to the 1st index of the row vector sumcol.


Look at the Sum of Each Column

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

sumcol(1)=sum(M(:,1))

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} \begin{array}{l}16\\+\\5\\+\\9\\+\\4\end{array} & 0 & 0 & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & 0 & 0 & 0 \end{array}} \right]\end{array}

sumcol(2)=sum(M(:,2))

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & \begin{array}{l}2\\+\\11\\+\\7\\+\\14\end{array} & 0 & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & 0 & 0 \end{array}} \right]\end{array}

sumcol(3)=sum(M(:,3))

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & \begin{array}{l}2\\+\\11\\+\\7\\+\\14\end{array} & 0 & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & 0 & 0 \end{array}} \right]\end{array}

sumcol(4)=sum(M(:,4))

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & {34} & \begin{array}{l}13\\+\\8\\+\\12\\+\\1\end{array} \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & {34} & {34} \end{array}} \right]\end{array}


Look at the Sum of Each Column using a For Loop

Note how we used the following lines of code, these all look identical with exception to the part highlighted in orange

sumcol(1)=sum(M(:,1))

sumcol(2)=sum(M(:,2))

sumcol(3)=sum(M(:,3))

sumcol(4)=sum(M(:,4))

These can be combined together using a for loop. Once again we need to create a condition which has some starting value and increments in steps until a final value, let’s call it B. We know that B starts at 1, then steps up by increments of 1 to 2, 3 and ends at 4. In other words the row vector B=[1:n]. We use a row vector as we are looking to create a row vector which contains the sum of each columns. Therefore the for loop becomes:

for B=[1:n]

    sumcol(B)=sum(M(:,B))

end

To the left hand side we are embedding into the Bth index of the row vector sumcol. To the right hand side we are calculating the sum of each col of M. This line of code should once again be embedded within the for loop. Once again we follow the convention is to indent any code embedded in a loop.

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

When running this code, we will therefore start with the following

sumcol=zeros(1,n)

\displaystyle \text{sumcol}=\left[ {\begin{array}{*{20}{c}} 0 & 0 & 0 & 0 \end{array}} \right]

The code

for B=[1:n]

    sumcol(B)=sum(M(:,B))

end

In the first step will become

for B=1

    sumcol(1)=sum(M(:,1))

end

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} \begin{array}{l}16\\+\\5\\+\\9\\+\\4\end{array} & 0 & 0 & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & 0 & 0 & 0 \end{array}} \right]\end{array}

In the second step will become

for B=2

    sumcol(2)=sum(M(:,2))

end

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & \begin{array}{l}2\\+\\11\\+\\7\\+\\14\end{array} & 0 & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & 0 & 0 \end{array}} \right]\end{array}

In the third step will become

for B=3

    sumcol(3)=sum(M(:,3))

end

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & \begin{array}{l}3\\+\\10\\+\\6\\+\\15\end{array} & 0 \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & {34} & 0 \end{array}} \right]\end{array}

In the nth step it will become

for B=n

    sumcol(n)=sum(M(:,n))

end

\displaystyle \begin{array}{l}\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & {34} & \begin{array}{l}13\\+\\8\\+\\12\\+\\1\end{array} \end{array}} \right]\\\text{sumcol}=\left[ {\begin{array}{*{20}{c}} {34} & {34} & {34} & {34} \end{array}} \right]\end{array}

This gives us the 1 by n row vector of the sums of the columns of the magic square respectively.


Initialisation of Output Array – diag

It may not be immediately obvious but we can use the same method to look at the sum of the diagonal. To do this we need to turn the diagonal into a row (or column) vector, we will use a row vector.

Let’s first initialise the row vector diag using

diag=zeros(1,n)

\displaystyle \text{diag}=\left[ {\begin{array}{*{20}{c}} 0 & 0 & 0 & 0 \end{array}} \right]


Create diag row vector using a For Loop

Manually the diagonal has the position

diag(1)=M(1,1)

diag(2)=M(2,2)

diag(3)=M(3,3)

diag(4)=M(4,4)

We can create the above by using the for loop. We need to create a condition which has some starting value and increments in steps until an end value, let’s call it C. We know that C starts at 1, then steps up by increments of 1 to 2, 3 and ends at n=4 in this case. In other words the column vector C=[1:n]. Therefore the for loop becomes:

for C=1:n
     diag(C)=M(C,C)
end

To the left hand side we are embedding into the Cth index of the row vector diag. To the right hand side we are indexing the Cth index into both the row and column. This line of code should once again be embedded within the for loop. Recalling the convention is to indent any code embedded in a loop.

When running this code, we will therefore start with the following

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

diag=zeros(1,n)

\displaystyle \text{diag}=\left[ {\begin{array}{*{20}{c}} 0 & 0 & 0 & 0 \end{array}} \right]

The code

for C=1:n
     diag(C)=M(C,C)
end

In the first step will become

for C=1
     diag(1)=M(1,1)
end

\displaystyle \text{diag}=\left[ {\begin{array}{*{20}{c}} {16} & 0 & 0 & 0 \end{array}} \right]

In the second step will become

for C=2
     diag(2)=M(2,2)
end

\displaystyle \text{diag}=\left[ {\begin{array}{*{20}{c}} {16} & {11} & 0 & 0 \end{array}} \right]

In the third step will become

for C=3
     diag(3)=M(3,3)
end

\displaystyle \text{diag}=\left[ {\begin{array}{*{20}{c}} {16} & {11} & 6 & 0 \end{array}} \right]

In the nth step will become

for C=n
     diag(n)=M(n,n)
end

\displaystyle \text{diag}=\left[ {\begin{array}{*{20}{c}} {16} & {11} & 6 & 1 \end{array}} \right]


Calculate the sum of the diag

Now that we have the diag as a row vector, calculating the sum of it is fairly straight forward.

sumdiag=sum(diag)

\displaystyle 34


Initialisation of Output Array – antidiag

We can use the same method to look at the sum of the antidiagonal. To do this we need to turn the antidiagonal into a row (or column) vector, we will use a row vector.

Let’s first initialise the row vector diag using

antidiag=zeros(1,n)

\displaystyle \text{antidiag}=\left[ {\begin{array}{*{20}{c}} 0 & 0 & 0 & 0 \end{array}} \right]


Create antidiag row vector using a For Loop

Manually the diagonal has the position

antidiag(1)=M(1,4)

antidiag(2)=M(2,3)

antidiag(3)=M(3,2)

antidiag(4)=M(4,1)

We can create the above by using the for loop. We need to create a condition which has some starting value and increments in steps to a final value, let’s call it D. We know that D starts at 1, then steps up by increments of 1 to 2, 3 and ends at n=4 in this case. In other words the column vector D=[1:n]. It is obvious how to calculate the index on the left hand side and the row index on the right hand side in terms of D but in order to make a loop we also need to define the column index in terms of D. We have the size of the matrix as m by n and we know we are lowering our index as D increases. If we use n-D, this will give us 3,2,1,0 however what we want is 4,3,2,1 therefore we must use n+1-D. The +1 is required when indexing the column as we index the matrix from 1 upwards and not from 0 upwards.

antidiag(1)=M(1,n+1-1)

antidiag(2)=M(2,n+1-2)

antidiag(3)=M(3,n+1-3)

antidiag(n)=M(n,n+1-n)

Therefore the for loop becomes

for D=1:n
     antidiag(D)=M(D,n+1-D)
end

To the left hand side we are embedding into the Dth index of the row vector diag. To the right hand side we are indexing the Dth index into the row. For the antidiag, when the row=1, the column=end and when the row=end, the column=1. Introducing a variable D=1:n we know that the antidiag lies on M(D,n-D+1). This line of code should once again be embedded within the for loop. Once again we follow the convention to indent any code embedded in a loop. When running this code, we will therefore start with the following

\displaystyle \text{M}=\left[ {\begin{array}{*{20}{c}} {16} & 2 & 3 & {13} \\ 5 & {11} & {10} & 8 \\ 9 & 7 & 6 & {12} \\ 4 & {14} & {15} & 1 \end{array}} \right]

\displaystyle \text{antidiag}=\left[ {\begin{array}{*{20}{c}} 0 & 0 & 0 & 0 \end{array}} \right]

The code

for D=1:n
     antidiag(D)=M(D,n+1-D)
end

In the first step will become

for D=1
     antidiag(1)=M(1,n+1-1)
end

Which gives the first element of the antidiagonal (in the first row)

for D=1
     antidiag(1)=M(1,n)
end

\displaystyle \left[ {\begin{array}{*{20}{c}} {13} & 0 & 0 & 0 \end{array}} \right]

In the second step will become

for D=2
     antidiag(2)=M(2,n+1-2)
end

Which gives the second element of the antidiagonal (in the second row)

for D=2
     antidiag(2)=M(2,n-1)
end

\displaystyle \left[ {\begin{array}{*{20}{c}} {13} & {10} & 0 & 0 \end{array}} \right]

In the third step will become

for D=3
     antidiag(3)=M(3,n+1-3)
end

Which gives the third element of the antidiagonal (in the third row)

for D=3
     antidiag(3)=M(3,n-2)
end

\displaystyle \left[ {\begin{array}{*{20}{c}} {13} & {10} & 7 & 0 \end{array}} \right]

In the nth step will become

for D=n
     antidiag(n)=M(n,n+1-n)
end

However n=end, Which gives the last element of the antidiagonal

for D=n
     antidiag(n)=M(n,1)
end

\displaystyle \left[ {\begin{array}{*{20}{c}} {13} & {10} & 7 & 4 \end{array}} \right]


Calculate the sum of the diag

Now that we have the antidiag as a row vector, calculating the sum of it is fairly straight forward.

sumantidiag=sum(antidiag)

\displaystyle 34


Script to Measure Sum of All Sides of a Magic Square

% Create a Magic Square
M=magic(4)
% Get the Size of the Magic Square
[m,n]=size(M)
%
% The sums of the rows
% Initialisation of the column vector sumrow
sumrow=zeros(m,1);
% For Loop Measuring the sums of the rows
for A=[1:m]'
sumrow(A)=sum(M(A,:));
end
sumrow
%
% The sums of the cols
% Initialisation of the row vector sumcol
sumcol=zeros(1,n);
% For Loop Measuring the sums of the columns
for B=1:n
sumcol(B)=sum(M(B,:));
end
sumcol
%
% The sum of the diagonal
% Initialisation of the diagonal as a row vector
diag=zeros(1,n);
% For Loop computing the diagonal as a row vector
for C=1:n
diag(C)=M(C,C);
end
% The sum of the diagonal
sumdiag=sum(diag)
%
% The sum of the antidiagonal
% Intialisation of the antidiagonal as a row vector
antidiag=zeros(1,n);
% For Loop computing the antidiagonal as a row vector
for D=1:n
antidiag(D)=M(D,n+1-D);
end
% The sum of the antidiagonal
sumantidiag=sum(antidiag)

We used a relatively small Magic Square that was 4 by 4 where it is possible to visually manually calculate the sum of the rows, the sum of the columns and the sum of the diagonals i.e.

\displaystyle \begin{array}{*{20}{c}} {} & {} & {} & {} & {} & {34} \\ {} & {16} & 2 & 3 & {13} & {34} \\ {} & 5 & {11} & {10} & 8 & {34} \\ {} & 9 & 7 & 6 & {12} & {34} \\ {} & 4 & {14} & {15} & 1 & {34} \\ {} & {34} & {34} & {34} & {34} & {34} \end{array}

We can however change the code above to look at a far more complicated 9 by 9 magic square by changing the 4 in line 2 to a 9: