Matthew Bennett

Logo

I am a data scientist working on time series forecasting (using R and Python 3) at the London Ambulance Service NHS Trust. I earned my PhD in cognitive neuroscience at the University of Glasgow working with fmri data and neural networks. I favour linux machines, and working in the terminal with Vim as my editor of choice.

View my GitHub Profile

View my LinkedIn Profile

View my CV

Element-wise functions of one or more matrices

We define a useful method for applying any function to each element of a matrix (e.g. scaling, raising to any power) and for applying any function to the elements in two matrices to produce a third matrix (e.g. adding, Hadamard products). The 'function_elwise' method forms the basis for several operations.

Code implementation

The method requires an arbitrary function as an argument, and can also take an optional second matrix, B. If B is supplied, then the function must be a function of two variables (these will be the elements in the $i,j$ positions of the two matrices).

We loop over the row and column indices of the matrix and, depending on if a second matrix, B, was supplied, apply the function to yield the new element:

def function_elwise(self, function, B=None):
    C = gen_mat(self.size())
    for i in range(self.size(0)):
        for j in range(self.size(1)):
            if B:
                C.data[i][j] = function(self.ind(i,j), B.ind(i,j))
            else:
                C.data[i][j] = function(self.ind(i,j))
    return C

We also define a method to choose which of a list of supplied functions to apply, given the argument B. If the argument B was not an instance of the class 'Mat' we assume an integer or float was passed and that the user wants to use the first listed function, and otherwise wants to apply the second function. Thus the appropriate function is passed, along with the argument B into function_elwise:

def function_choice(self, B, functions):
    if isinstance(B, Mat) == False:
        return self.function_elwise(functions[0])
    return self.function_elwise(functions[1], B)

Addition and subtraction

Code implementation

Here we call the function_choice method with a list of two lambda functions. In the case that B was not a matrix, we assume that the user wants to add/subtract the same scaler to each element. This is a simple function of each element and is reflected in the first lambda function in the list. On the other hand, if the B argument was a matrix, the second lambda function of two variables (x and y: the $i,j$ elements from the original matrix and matrix B) will be applied:

def add(self, B):
    return self.function_choice(B, [lambda x: x+B, lambda x, y: x+y])

def subtract(self, B):
    return self.function_choice(B, [lambda x: x-B, lambda x, y: x-y])

Element-wise multiplication/division and scalar multiplication

Just what it sounds like. We will use $\odot$ and $\oslash$ to denote these two operations:

\[\begin{equation} A \odot B = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 0 & 0 \\ 4 & -2 & -1 \end{bmatrix} \odot \begin{bmatrix} 2 & 2 & 3 \\ 4 & 2 & 1 \\ 1 & 3 & 2 \end{bmatrix} = \begin{bmatrix} 2 & 4 & 9 \\ 8 & 0 & 0 \\ 8 & -6 & -2 \end{bmatrix} \end{equation}\] \[\begin{equation} A \oslash B = \begin{bmatrix} 1 & 2 & 3 \\[5pt] 2 & 0 & 0 \\[5pt] 4 & -2 & -1 \end{bmatrix} \oslash \begin{bmatrix} 2 & 2 & 3 \\[5pt] 4 & 2 & 1 \\[5pt] 1 & 3 & 2 \end{bmatrix} = \begin{bmatrix} \frac{1}{2} & 1 & 1 \\[5pt] \frac{1}{2} & 0 & 0 \\[5pt] 4 & -\frac{2}{3} & -\frac{1}{2} \end{bmatrix} \end{equation}\]

Scalar multiplication, which is a legal operation in linear algebra, is a simple matter of taking some matrix (or vector) and multiplying all of its elements by some number (the scalar):

\[\begin{equation} 2A = 2 \begin{bmatrix} 1 & 2 & 3 \\ 2 & 2 & 6 \\ 4 & 5 & 6 \end{bmatrix} = \begin{bmatrix} 2 & 4 & 6 \\ 4 & 4 & 12 \\ 8 & 10 & 12 \end{bmatrix} \end{equation}\]

Code implementation

Just as with the case in the add and subtract methods, we check if the B argument is of class matrix and decide whether to use a function of one or of two variables:

def multiply_elwise(self, B):
    return self.function_choice(B, [lambda x: x*B, lambda x, y: x*y])

def div_elwise(self, B):
    return self.function_choice(B, [lambda x: x/B, lambda x, y: x/y])

Demo

The method requires an arbitrary function as an argument, and can also take an optional second matrix, B. If B is supplied, then the function must be a function of two variables (these will be the elements in the $i,j$ positions of the two matrices).

We loop over the row and column indices of the matrix and, depending on if a second matrix, B, was supplied, apply the function to yield the new element:

def function_elwise(self, function, B=None):
    C = gen_mat(self.size())
    for i in range(self.size(0)):
        for j in range(self.size(1)):
            if B:
                C.data[i][j] = function(self.ind(i,j), B.ind(i,j))
            else:
                C.data[i][j] = function(self.ind(i,j))
    return C

< Combining matrices and getting the diagonal

Dot Product >

back to project main page
back to home