Preliminaries

Here we’ll very briefly talk about the basic definitions and conventions I will use when talking about and writing code. Most important, how we will write matrices, row vectors, and column vectors. Note that I will be taking an entirely functional (as opposed to object-oriented) approach as I feel it’s more transparent to most people. We’ll use the odd class here and there as an organisational tool, for example to store common matrices.

Programmers will probably think of the list as the natural datatype for matrices, and I would agree. Respectively, we will write row vectors, column vectors, and matrices in the form:

rowvec = [[1, 2, 3, 4]]
colvec = [[1], [2], [3], [4]]
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

The reason for what may seem like redundant braces on the row and column vectors is simply consistency. It will allow us to treat all of these objects as the same thing, without having to constantly check and write different code for each type. We aren’t going to worry much about making our functions type-safe; we will run with the assumption that they will only ever receive valid inputs, and we will ensure it by guaranteeing that our return statements only ever return valid matrices.

Regarding for loops (and list comprehensions), it is generally not considered best practice to say things like

for i in range(len(matrix)):
    do something to matrix[i]

instead favouring

for each in matrix:
    do something to each

There are good reasons for this, but I am usually going to use the first style, simply because it is so incredibly common and necessary to refer to matrix elements by their indices. However, because I find the range(len(matrix)) really packs out the line and makes it hard to read, I’ll usually declare ranges first, as in

rows = range(len(matrix))
cols = range(len(matrix[0]))

for i in rows:
    for j in cols
        do something to matrix[i][j]

Hopefully that looks a little cleaner, and not too much longer, but be careful to keep in mind that rows and cols are ranges, and the objects in them should always be treated as indices. We’ll go one step further and define our first two functions which will get the number of rows and number of columns in any matrix, including vectors:

def rows(matrix):
    return len(matrix)

def columns(matrix):
    return len(matrix[0])

The columns() function works only if we assume that the matrix has at least one row, which it must or it is not a valid input for our purposes. If we ever do have occasion to submit an empty matrix (I don’t think we will) it will be defined by a double pair of empty braces: [[]].

Finally, regarding mathematical notation, I will generally only be using standard notations and conventions. If I do anything that I don’t think is standard, I will try to point it out. My educational background is in mathematical physics so hopefully what I write will be sensible. I’m not going to do anything especially proofy or rigorous here (perhaps another series for that), but please be assured that all of the mathematical statements I make are proven, and any physical statements I make are in line with current theoretical consensus.

Summary

So far our functional repertoire is:

  • rows(matrix): count the number of rows in a matrix.
  • columns(matrix): count the number of columns in a matrix.

Next: List comprehensions

Leave a Reply