Recursive function to calculate matrix multiplication - python

I'm trying to write a recursive function to calculate matrix multiplication.
EDITED :
This is the code :
def mult_mat(x, nbr):
result = [[2, 4],
[1, 3]]
if nbr == 1:
return result
else:
for i in range(len(x)):
for j in range(len(result[0])):
for k in range(len(result)):
result[i][j] += x[i][k] * result[k][j]
mult_mat(result, nbr-1)
return result
m = [[2, 4],
[1, 3]]
# the number of times m1 will be multiplied
n = 3
res = mult_mat(m, n)
for r in res:
print(r)
As an example, for n = 3 I am trying to get the result:
m1 * m1 will be [[8, 20], [5, 3]] = result and result * m1 will be [[36, 92], [23, 59]] and so on.
the output of this code is:
[10, 24]
[44, 108]
and what i want is this :
[36, 92]
[23, 59]

Okay, let's understand conceptually what you want to achieve with recursion. You want to multiply a matrix, M, with itself. mult_mat(M, 2) will give M * M, therefore, mult_mat(M, 1) just returns M itself.
In the multiplication, you have 3 matrices going on. x and y are the two matrices you're multiplying together, which you store in result. Now, let's look what happens for the first few multiplications.
x * x # n = 2
x * (x * x) # n = 3
# here, we initially calculate x * x,
# which we pass as y in the next stack for x * y
As you can see, for n = 2, you multiply x by itself, but for n > 2, y is different than x, so you must pass it on to the function somehow. We can code this idea as follows.
def mult_mat(x, nbr, y=None):
if nbr == 1:
# if y is None, it means we called `mult_mat(x, 1)`, so return `x`
if y is not None:
return y
return x
if y is None:
y = x
result = [[0, 0],
[0, 0]]
for i in range(len(x)):
for j in range(len(result[0])):
for k in range(len(result)):
result[i][j] += x[i][k] * y[k][j]
return mult_mat(x, nbr-1, result)
m = [[2, 4],
[1, 3]]
# the number of times m1 will be multiplied
n = 3
res = mult_mat(m, n)
for r in res:
print(r)
It's may look like ugly code and that's probably because there are better ways to achieve what you want without recursion. However, I couldn't think of a different way while implementing recursion. My solution logically flowed from the points I laid out at the beginning.

Related

How to print an index of element in a list - python

#Program that will load 2 arrays. ELements of the first array are coordinates X. and#the elements of the second array are coordinates Y of a point on a plane.# find the point and print the index of coordinates of the point which is the closest to the#starting point, coordinate 0,0.
import math
i = 0
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min = math.sqrt(X[0])**2 + math.sqrt(Y[0])**2
while i < len(X):
U = math.sqrt(X[i])**2 + math.sqrt(Y[i])**2
if U < min:
min = U
else:
min = min
i = i + 1
mindex = X.index(min)
print(min)
print(mindex)
so basically the coordinates should be 1,1 since that is the shortest distance from the nul-point with the distance D = 2.But how do I also print the index of that element 1. With the index being 7
Edit: in python
Here you go:
import math
X = [3, 32, 15, 43, 5, 22, 90, 1]
Y = [3, 32, 15, 43, 5, 22, 90, 1]
# calculate distances using list comprehension
distances = [math.sqrt(x) ** 2 + math.sqrt(y) ** 2 for x, y in zip(X, Y)]
# find minimal distance
min_distance = min(distances)
# find index of minimal index
min_distance_index = distances.index(min_distance)
print(min_distance, min_distance_index) # Output: 2.0 7
Just a heads up, you got the wrong formula for euclidean distance. Your formula comes down to x + y if they're both positive, otherwise you get an error. The actual formula is math.sqrt(x ** 2 + y ** 2)
From the phrasing of your question it sounds like you only want to print the index, in which case the following is enough
import math
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min_index = min(range(len(X)), key=lambda i: math.sqrt(X[i] ** 2 + Y[i] ** 2))
print(min_index)
Super easy, barely an inconvenience.
>>> min(range(len(X)), key=lambda i: X[i] + Y[i])
7
(No idea what you think squaring square roots achieves, so I removed that.)
check this:
import math
i = 0
X = [3,32,15,43,5,22,90,1]
Y = [3,32,15,43,5,22,90,1]
min = math.sqrt(X[0])**2 + math.sqrt(Y[0])**2
idx = 0
while i < len(X):
U = math.sqrt(X[i])**2 + math.sqrt(Y[i])**2
if U < min:
min = U
idx = i
i = i + 1
print(min)
print(idx)

Is there any possibility to vectorize this?

Currently I'm working on a project that implements cubic spline interpolation. So far I have managed to calculate coefficients for my equations.
Now I'm trying to return an interpolating function that for any x returns y.
Let's assume that we have
x = [1, 3, 5]
y = [6, -2, 4]
The coefficients that we get are as follow:
[ 6, -5.75, 0, 0.4375, -2, -0.5, 2.625, -0.4375]
It is equal to
[ a<sub>0</sub>, b<sub>0</sub>, c<sub>0</sub>, d<sub>0</sub>, a<sub>1</sub>, b<sub>1</sub>, c<sub>1</sub>, d<sub>1</sub>]
The interpolating polynomials are
S<sub>0</sub>(x) = a<sub>0</sub> + b<sub>0</sub>*x + c<sub>0</sub>*x<sup>2</sup> + d<sub>0</sub>*x<sup>3</sup> x ∈ [1, 3]
S<sub>1</sub>(x) = a<sub>1</sub> + b<sub>1</sub>*x + c<sub>1</sub>*x<sup>2</sup> + d<sub>1</sub>*x<sup>3</sup> x ∈ (3, 5]
And so on - it can be calculated for more than only 3 points
Right now I have implemented a method that works only if one x is given as an input.
def interpolate_spline(x, x_array, coefficients):
i = 1
while x_array[i] < x:
i += 1
i = i - 1
a = coefficients[4 * i]
b = coefficients[4 * i + 1]
c = coefficients[4 * i + 2]
d = coefficients[4 * i + 3]
return a + b * x + c * (x ** 2) + d * (x ** 3)
And coming back to my question: Is there any possibility that it can be vectorized or at least take whole array as an input?
I don't know if that matters but assume that x_array is sorted

In Python, how do I rotate a matrix 90 degrees counterclockwise?

>>> def rotate_matrix( k: List[List[int]]):
"""
For example, if I have:
m = [[1,2,3],
[2,3,3],
[5,4,3]]
rotate_matrix(m) should give me [[3,3,3],[2,3,4],[1,2,5]].
"""
Edit: Preferably without numpy.
Here is the counter clockwise matrix rotation as one line in pure python (i.e., without numpy):
new_matrix = [[m[j][i] for j in range(len(m))] for i in range(len(m[0])-1,-1,-1)]
If you want to do this in a function, then
def rotate_matrix( m ):
return [[m[j][i] for j in range(len(m))] for i in range(len(m[0])-1,-1,-1)]
and either way, the result for
m = [ [1,2,3], [2,3,3], [5,4,3]]
is
[[3, 3, 3], [2, 3, 4], [1, 2, 5]]
Aside, if you want the usual transpose, then the simple one line pure python version is
[[m[j][i] for j in range(len(m))] for i in range(len(m[0]))]
You could use the numpy function rot90
import numpy as np
m = np.array([[1,2,3],
[2,3,3],
[5,4,3]])
def rotate_matrix(mat):
return np.rot90(mat)
#solution1
print(list(list(x) for x in zip(*m))[::-1])
#solution2
print([[x[i] for x in m] for i in range(len(m))][::-1])
#solution3
r = []
i = 0
for row in m:
listToAdd = [item[i] for item in m]
r.append(listToAdd)
i +=1
print(r[::-1])
def rotate_90_degree_anticlckwise(matrix):
new_matrix = []
for i in range(len(matrix[0]), 0, -1):
new_matrix.append(list(map(lambda x: x[i-1], matrix)))
return new_matrix
def rotate_90_degree_clckwise(matrix):
new_matrix = []
for i in range(len(matrix[0])):
li = list(map(lambda x: x[i], matrix))
li.reverse()
new_matrix.append(li)
return new_matrix
def rotate_90_degree_clckwise_by_zip_method(matrix):
return list(list(x)[::-1] for x in zip(*matrix))
Look at this code. This is the way to rotate any matrix by 90 degrees using scratch
[This is the code to have a matrix rotated by 90 degrees][1]
n = input("enter input:")
l =[]
while (n !=""):
l.append(n.split(" "))
n = input("enter input:")
l1=[]
for i in range(len(l[0])):
l1.append([])
for j in range (len(l1)):
for p in range(len(l)):
l1[j].append(l[p][-(j+1)])
for s in l1:
print(*s)
'''
[1]: https://i.stack.imgur.com/c8jHC.png
Just flip the matrix vertically, then switch the upper-right triangle with the lower-left triangle
def rotate_matrix_ccw(mat):
if mat is None:
return None
n = len(mat)
if n == 1:
return mat
for i in range(n):
if len(mat[i]) != n:
raise Exception("Matrix must be square")
# flip the matrix vertically
for j in range(n // 2):
for i in range(n):
mat[i][j], mat[i][n - 1 - j] = mat[i][n - 1 - j], mat[i][j]
# switch the upper-right triangle with the lower-left triangle
for i in range(n):
for j in range(i):
mat[i][j], mat[j][i] = mat[j][i], mat[i][j]
return mat
You can loop through the original matrix and create a new one. This is my approach for counterclockwise, for the other way it would be similar.
This doesn't require it to be a square.
def left_rotate(mat):
if not mat: return []
colcount = len(mat[0])
# Initialize empty lists
new = [list() for _ in range(colcount)]
# Go through the rows, append elements one by one
for row in mat:
for j in range(colcount):
new[j].append(row[colcount - 1 - j])
return new
Example:
>>> print(left_rotate([[1, 2], [3, 4], [5, 6]]))
[[2, 4, 6], [1, 3, 5]]
flip vertically (left to right) then transpose:
m = [[1,2,3],
[2,3,3],
[5,4,3]]
print([list(x) for x in zip(*[x[::-1] for x in m])])
def rotateMatrix(self, matrix):
for i in range(len(matrix)):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
matrix.reverse()
Rotate matrix anti-clockwise 90deg (In-place)
def rotate(matrix):
for i in range(len(matrix) - 1, -1, -1):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
matrix.reverse()
Rotate matrix clockwise 90deg (In-place)
def rotate(matrix):
matrix.reverse()
for i in range(len(matrix)):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
In case you're working with square matrixes (rows == cols) then you can use this:
list(zip(*reversed(a))) # 90 degrees clockwise
list(zip(*reversed(a)))[::-1] # 90 degrees counter-clockwise
def rotated_array(array):
new_array = np.zeros([array.shape[0], array.shape[1]])
for i in range(array.shape[0]):
for j in range(array.shape[1]):
t = array.shape[0]-j-1 # To Start with last row and first column
new_array[i, j] = array[t, i]
return new_array

Vectorized Computation of Compositional Variance

Given an n X m matrix with entries xi, j, the compositional variance is an m X m matrix, with the i, j entry including the expression
∑k = 1n [ ln2(xk, i / xk, j)]
(it includes other, easily calculated, expressions).
This is very easy to calculate in a loop, but how can it be calculated using vectorization?
Here is the crappy loop code:
x = np.array([[1, 2, 3], [4, 5, 6]], dtype=float)
v = np.zeros((3, 3))
for i in range(3):
for j in range(3):
for k in range(2):
v[i, j] += np.log(x[k, i] / x[k, j])**2
Assuming you meant something like (np.log(x[k, i] / x[k, j])**2) in NumPy terms, being summed over for k = 1:n, one vectorized approach could be suggested with broadcasting -
((np.log(x[:,:,None]/x[:,None])**2)).sum(0)

How to calculate auto-covariance in Python

I want to calculate auto-covariance of 3 arrays X1, X2 and Y which are all stationary random process. Is there any function in sciPy or other library can solve this problem?
Statsmodels has auto- and cross covariance functions
http://statsmodels.sourceforge.net/devel/generated/statsmodels.tsa.stattools.acovf.html
http://statsmodels.sourceforge.net/devel/generated/statsmodels.tsa.stattools.ccovf.html
plus the correlation functions and partial autocorrelation
http://statsmodels.sourceforge.net/devel/tsa.html#descriptive-statistics-and-tests
According to the standard estimation of the autocovariance coefficient for discrete signals, which can be expressed by equation:
...where x(i) is a given signal (i.e specific 1D vector), k stands for the shift of x(i) signal by k samples, N is the length of x(i) signal, and:
...which is simple average, we can write:
'''
Calculate the autocovarriance coefficient.
'''
import numpy as np
Xi = np.array([1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5])
N = np.size(Xi)
k = 5
Xs = np.average(Xi)
def autocovariance(Xi, N, k, Xs):
autoCov = 0
for i in np.arange(0, N-k):
autoCov += ((Xi[i+k])-Xs)*(Xi[i]-Xs)
return (1/(N-1))*autoCov
print("Autocovariance:", autocovariance(Xi, N, k, Xs))
If you would like to normalize the autocovariance coefficient, which will become the autocorrelation coefficient expressed as:
...than you just have to add to the above code just two additional lines:
def autocorrelation():
return autocovariance(Xi, N, k, Xs) / autocovariance(Xi, N, 0, Xs)
Here is full script:
'''
Calculate the autocovarriance and autocorrelation coefficients.
'''
import numpy as np
Xi = np.array([1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5])
N = np.size(Xi)
k = 5
Xs = np.average(Xi)
def autocovariance(Xi, N, k, Xs):
autoCov = 0
for i in np.arange(0, N-k):
autoCov += ((Xi[i+k])-Xs)*(Xi[i]-Xs)
return (1/(N-1))*autoCov
def autocorrelation():
return autocovariance(Xi, N, k, Xs) / autocovariance(Xi, N, 0, Xs)
print("Autocovariance:", autocovariance(Xi, N, k, Xs))
print("Autocorrelation:", autocorrelation())
A small tweak to the previous answers, which avoids python for loops and uses numpy array operations instead. This will be quicker if you have a lot of data.
def lagged_auto_cov(Xi,t):
"""
for series of values x_i, length N, compute empirical auto-cov with lag t
defined: 1/(N-1) * \sum_{i=0}^{N-t} ( x_i - x_s ) * ( x_{i+t} - x_s )
"""
N = len(Xi)
# use sample mean estimate from whole series
Xs = np.mean(Xi)
# construct copies of series shifted relative to each other,
# with mean subtracted from values
end_padded_series = np.zeros(N+t)
end_padded_series[:N] = Xi - Xs
start_padded_series = np.zeros(N+t)
start_padded_series[t:] = Xi - Xs
auto_cov = 1./(N-1) * np.sum( start_padded_series*end_padded_series )
return auto_cov
Comparing this against #bluevoxel's code, using a time-series of 50,000 data points and computing the auto-correlation for a single fixed value of lag, the python for loop code averaged about 30 milli-seconds and using numpy arrays averaged faster than 0.3 milli-seconds (running on my laptop).
Get sample auto covariance:
# cov_auto_samp(X,delta)/cov_auto_samp(X,0) = auto correlation
def cov_auto_samp(X,delta):
N = len(X)
Xs = np.average(X)
autoCov = 0.0
times = 0.0
for i in np.arange(0, N-delta):
autoCov += (X[i+delta]-Xs)*(X[i]-Xs)
times +=1
return autoCov/times
#user333700 has the right answer. Using a library (such as statsmodels) is generally preferred over writing your own. However, it is insightful to implement your own at least once.
def _check_autocovariance_input(x):
if len(x) < 2:
raise ValueError('Need at least two elements to calculate autocovariance')
def get_autocovariance_given_lag(x, lag):
_check_autocovariance_input(x)
x_centered = x - np.mean(x)
a = np.pad(x_centered, pad_width=(0, lag), mode='constant')
b = np.pad(x_centered, pad_width=(lag, 0), mode='constant')
return np.dot(a, b) / len(x)
def get_autocovariance(x):
_check_autocovariance_input(x)
x_centered = x - np.mean(x)
return np.correlate(x_centered, x_centered, mode='full')[len(x) - 1:] / len(x)
The function I have get_autocovariance_given_lag calculates the autocovariance for a given lag.
If you are interested in all lags, the get_autocovariance can be used. The np.correlate function is what statsmodels uses under the hood. It calculates the cross correlation. This is a sliding dot product. For example, suppose the array is [1, 2, 3]. Then we get:
[1, 2, 3] = 3 * 1 = 3
[1, 2, 3]
[1, 2, 3] = 2 * 1 + 3 * 2 = 8
[1, 2, 3]
[1, 2, 3] = 1 * 1 + 2 * 2 + 3 * 3 = 14
[1, 2, 3]
[1, 2, 3] = 2 * 1 + 3 * 2 = 8
[1, 2, 3]
[1, 2, 3] = 3 * 1 = 3
[1, 2, 3]
But note we are interested in the covariance that starts at lag 0. Where is this? Well, this occurs after we have moved N - 1 positions to the right where N is the length of the array. This is why we return the array starting at N-1.

Categories