Python Matrix Multiplication, - python

I'm trying to create a python program to perform the strassen and regular matrix multiplication methods. However, when I try to run my strassen function with the randomly generated matrix created with the createRandom Matrix function, get this error:
Traceback (most recent call last):
File "matrixMult.py", line 106, in <module>
print strassen(c, d, 10)
File "matrixMult.py", line 77, in strassen
p1 = strassen(addMatrix(a11,a22), addMatrix(b11,b22), n/2)
File "matrixMult.py", line 78, in strassen
p2 = strassen(addMatrix(a21,a22), b11, n/2)
File "matrixMult.py", line 82, in strassen
p6 = strassen(subMatrix(a21,a11), addMatrix(b11,b12), n/2)
File "matrixMult.py", line 62, in subMatrix
c.append(a[i][j] - b[i][j])
IndexError: list index out of range
Here's the code. I randomly create a 10x10 matrix, then try to perform Strassen with it, and I get the preceding error. However, when I use the simple 4x4 matrices I have defined at the end, strassen works fine, and it seems my random matrices are being generated without a problem, so I'm not sure where the issue is. Anyone have any ideas?
import random
import time
random.seed()
def createEmptyMatrix(x, y): # create empty matrix
matrix = [[0 for row in range(x)] for col in range(y)]
return matrix
def createRandomMatrix(size): # create matrix filled with random ints
matrix = []
matrix = [[random.randint(1,20) for row in range(size)] for col in range(10)]
return matrix
def regular(a, b): # standard O(n^3) matrix multiplication
c = createEmptyMatrix(len(a), len(b[0]))
for i in range(len(a)):
for j in range(len(b[0])):
for k in range(len(b)):
c[i][j] += a[i][k]*b[k][j]
return c
def split(matrix): # split matrix into quarters for strassen
a = matrix
b = matrix
c = matrix
d = matrix
while(len(a) > len(matrix)/2):
a = a[:len(a)/2]
b = b[:len(b)/2]
c = c[len(c)/2:]
d = d[len(d)/2:]
while(len(a[0]) > len(matrix[0])/2):
for i in range(len(a[0])/2):
a[i] = a[i][:len(a[i])/2]
b[i] = b[i][len(b[i])/2:]
c[i] = c[i][:len(c[i])/2]
d[i] = d[i][len(d[i])/2:]
return a,b,c,d
def addMatrix(a, b): # add 2 matrices
d = []
for i in range(len(a)):
c = []
for j in range(len(a[0])):
c.append(a[i][j] + b[i][j])
d.append(c)
return d
def subMatrix(a, b): # subtract 2 matrices
d = []
for i in range(len(a)):
c = []
for j in range(len(a[0])):
c.append(a[i][j] - b[i][j])
d.append(c)
return d
def strassen(a, b, n): # strassen matrix multiplication method
#base case
if n == 1:
d = [[0]]
d[0][0] = a[0][0] * b[0][0]
return d
else:
a11, a12, a21, a22 = split(a)
b11, b12, b21, b22 = split(b)
p1 = strassen(addMatrix(a11,a22), addMatrix(b11,b22), n/2)
p2 = strassen(addMatrix(a21,a22), b11, n/2)
p3 = strassen(a11, subMatrix(b12,b22), n/2)
p4 = strassen(a22, subMatrix(b21,b11), n/2)
p5 = strassen(addMatrix(a11,a12), b22, n/2)
p6 = strassen(subMatrix(a21,a11), addMatrix(b11,b12), n/2)
p7 = strassen(subMatrix(a12,a22), addMatrix(b21,b22), n/2)
c11 = addMatrix(subMatrix(addMatrix(p1, p4), p5), p7)
c12 = addMatrix(p3, p5)
c21 = addMatrix(p2, p4)
c22 = addMatrix(subMatrix(addMatrix(p1, p3), p2), p6)
c = createEmptyMatrix(len(c11)*2,len(c11)*2)
for i in range(len(c11)):
for j in range(len(c11)):
c[i][j] = c11[i][j]
c[i][j+len(c11)] = c12[i][j]
c[i+len(c11)][j] = c21[i][j]
c[i+len(c11)][j+len(c11)] = c22[i][j]
return c
a = [[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4]]
b = [[5,5,5,5],[6,6,6,6],[7,7,7,7],[8,8,8,8]]
c = createRandomMatrix(10)
d = createRandomMatrix(10)
print "Strassen Outputs:"
#print strassen(c, d, 10)
print "Should be:"
print regular(c, d)
print c
print d
print a
print b
print strassen(a, b, 4)

I would recommend using numpy, in which you can use matrices easily and all these functions already exist.
In the meantime, if you run into index errors in this function try adding something like an assert:
def subMatrix(a, b): # subtract 2 matrices
assert len(a) == len(b), "Number of rows does not match!"
assert len(a[0]) == len(b[0]), "Number of columns does not match!"
d = []
for i in range(len(a)):
c = []
for j in range(len(a[0])):
c.append(a[i][j] - b[i][j])
d.append(c)
return d
However you don't need to write this function at all:
import numpy as np
a = np.matrix(np.random.randint(10, size=(3,3)))
b = np.matrix(np.random.randint(10, size=(3,))).T
c = a * b
d = a - b
print a
[[5 8 1]
[7 6 1]
[9 2 9]]
print b
[[5]
[2]
[4]]
print c
[[45]
[51]
[85]]
print d
[[ 0 3 -4]
[ 5 4 -1]
[ 5 -2 5]]

The last line of the trackback tells you what's wrong:
File "matrixMult.py", line 62, in subMatrix
c.append(a[i][j] - b[i][j])
IndexError: list index out of range
This line contains 4 usages of array index, one of them is out of the range of the array.
To debug this, go to line 62, add a print i,j just before it. You'll get lots of output and the output line just before the exception will tell you what index is out of range. This way it might be possible for you to track down the bug you have here.
"Just debug it"

Related

Comparing another array with a list full of arrays

So I've essentially split an array#1(full of float values) into 100 arrays contained in a list, and what I want to do is compare it to an array#2(also full of floats) and have the program give me the number of values in array#2 that fall within the range of each of the 100 arrays in the list.
I may not have explained it well enough, but I've done this successfully for the first two arrays however I can't find a way to do it elegantly through a 'for' loop so I don't have to type it out 100 times.
Here's the code:
manual_bins_threshim = np.array_split(threshim_by_size, 100)
def count(rand, l, r):
return len(list(i for i in rand if l <= i <= r))
a = np.array(manual_bins_threshim[0:1])
l = a[:][0][0]
r = a[:][0][len(a[:][0]) -1]
a_1 = count(array2, l, r)
b = np.array(manual_bins_threshim[1:2])
l = b[:][0][0]
r = b[:][0][len(b[:][0]) -1]
b_1 = count(array2, l, r)
print(a_1,b_1)
I'm also open to a function that can do this in a different way if I've made it way more complicated than it needs to be.
Just iterate over the elements of manual_bins_threshim :
for a in manual_bins_threshim:
l = a[0,0]
r = a[0,-1]
print(count(array2, l, r))
A few words about my modifications:
l = a[:][0][0] → l = a[0,0] - I don't think [:] is needed here (it creates a new array referring to the same data).
r = a[:][0][len(a[:][0]) -1] → r = a[0,-1] - the last element of an array (or a list) can be accessed with -1 (by the way, the n-th element from the end can be accessed with -n).
This question requires some numpy high dimension array operation:
import numpy as np
threshim_by_size = np.random.rand(300)
manual_bins_threshim = np.array_split(threshim_by_size, 100)
array2 = np.random.rand(20)
def count(rand, ll, rr):
return len(list(i for i in rand if ll <= i <= rr))
a = np.array(manual_bins_threshim[0:1])
l = a[:][0][0]
r = a[:][0][len(a[:][0]) - 1]
a_1 = count(array2, l, r)
b = np.array(manual_bins_threshim[1:2])
l = b[:][0][0]
r = b[:][0][len(b[:][0]) - 1]
b_1 = count(array2, l, r)
print(a_1, b_1)
def array_op():
reshaped_threshim_by_size = np.reshape(threshim_by_size, [100, -1])
ll = reshaped_threshim_by_size[:, 0:1]
rr = reshaped_threshim_by_size[:, -1:]
reshape_array2 = np.reshape(array2, [1, -1])
mask = np.logical_and(ll <= reshape_array2, reshape_array2 <= rr)
return np.sum(mask, axis=1)
res = array_op()
assert res[0] == a_1 and res[1] == b_1

Compare position and elements of 3 different lists

I'm trying to compare the position and elements of 3 different lists, to then save them in a new list, if at least 2 of the elements at the same position matched.
For Example:
a = [FF2, FF6, FC4]
b = [FB5, FB3, FC4]
c = [FF2, FB3, FM8]
Result = [FF2, FB3, FC4]
At the beginning I used the following code to compare 2 lists, and tried to adapt it for 3 lists, by adding an extra for loop after the for i1 and also adding an or to my if, but went horribly wrong (almost 10 times more values as expected as output).
for i, v in enumerate(a):
for i1, v1 in enumerate(b):
if (i==i1) & (v==v1):
Result.append(v)
This is my current approach, it's working fine, but I have no idea how can I append the matched value to my Result list.
Result = list(x for x, (xa, xb, xc) in enumerate(zip(a, b, c))
if xa == xb or xb == xc or xa == xc)
al = ['FF2', 'FF6', 'FC4']
bl = ['FB5', 'FB3', 'FC4']
cl = ['FF2', 'FB3', 'FM8']
res = []
for a,b,c in zip(al, bl, cl):
if a == b or b == c or c == a:
if a == b:
res.append(a)
elif b == c:
res.append(b)
elif c == a:
res.append(c)
print(res)
You can iterate through the 3 lists at the same time & append to the resulting list. Use zip()
You could avoid the issues you're having by eliminating the use of enumerate() and just using zip. We then check each unique element in each tuple created by zip and see if the count of that element is greater than 1. If so, we append this to our return list. The use of t.count() resolves the need for the untidy xa == xb or xb == xc or xa == xc condition & makes it easily extendable to n lists.
Code:
a = ['FF2', 'FF6', 'FC4']
b = ['FB5', 'FB3', 'FC4']
c = ['FF2', 'FB3', 'FM8']
r = [x for t in zip(a, b, c) for x in set(t) if t.count(x) > 1]
Output:
>>> r
['FF2', 'FB3', 'FC4']
You could do something like this,
a = ["FF2", "FF6", "FC4"]
b = ["FB5", "FB3", "FC4"]
c = ["FF2", "FB3", "FM8"]
result = []
for idx in range(len(a)):
if a[idx] == b[idx] or a[idx] == c[idx]:
result.append(a[idx])
elif b[idx] == c[idx]:
result.append(b[idx])
else:
pass
print(result)
the output will be,
['FF2', 'FB3', 'FC4']

Multiplying multidimensional arrays by one dimensional arrays Python

I want to do matrix multiplication with my function that takes 2 matrixs as parameters. My code works for all the test cases except
mul([0, 1, 2],[[0], [1], [2]])= [0, 1, 4]
which should = [5]. Any idea why?
rows_A = get_rowCount(A)
cols_A = get_columnCount(A)
rows_B = get_rowCount(B)
cols_B = get_columnCount(B)
if cols_A != rows_B:
return 'Error(mul): size mismatch'
if isinstance(A[0],list) == False:
# if one is 1d and other is 2d:
if isinstance(B[0], list):
new_list = []
for i in B:
new_list.append(i[0])
B = new_list
return [a*b for a,b in zip(A,B)]
# Create the result matrix
# Dimensions would be rows_A x cols_B
C = [[0 for row in range(cols_B)] for col in range(rows_A)]
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
return C

TypeError when using mergesort on large amounts of data (python)

So, I want to make a benchmark and compare different algorithm's processing speed on different size arrays. I have the following script which is supposed to use mergeSort on size 10, 100, 1000, 10000, 100000, 1000000 input arrays:
import sys
import time
import random
def merge(arr, l, m, r):
n1 = m - l + 1
n2 = r- m
# create temp arrays
L = [0] * (n1)
R = [0] * (n2)
# Copy data to temp arrays L[] and R[]
for i in range(0 , n1):
L[i] = arr[l + i]
for j in range(0 , n2):
R[j] = arr[m + 1 + j]
# Merge the temp arrays back into arr[l..r]
i = 0 # Initial index of first subarray
j = 0 # Initial index of second subarray
k = l # Initial index of merged subarray
while i < n1 and j < n2 :
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
# Copy the remaining elements of L[], if there
# are any
while i < n1:
arr[k] = L[i]
i += 1
k += 1
# Copy the remaining elements of R[], if there
# are any
while j < n2:
arr[k] = R[j]
j += 1
k += 1
# l is for left index and r is right index of the
# sub-array of arr to be sorted
def mergeSort(arr,l,r):
if l < r:
# Same as (l+r)/2, but avoids overflow for
# large l and h
m = (l+(r-1))/2
# Sort first and second halves
mergeSort(arr, l, m)
mergeSort(arr, m+1, r)
merge(arr, l, m, r)
data = []
L10 = []
L100 = []
L1000 = []
L10000 = []
L100000 = []
L1000000 = []
inf = open("10.txt", "r")
inputData = inf.readlines()
for line in inputData:
L10.append(int(line.rstrip()))
data.append(L10)
inf = open("100.txt", "r")
inputData = inf.readlines()
for line in inputData:
L100.append(int(line.rstrip()))
data.append(L100)
inf = open("1000.txt", "r")
inputData = inf.readlines()
for line in inputData:
L1000.append(int(line.rstrip()))
data.append(L1000)
inf = open("10000.txt", "r")
inputData = inf.readlines()
for line in inputData:
L10000.append(int(line.rstrip()))
data.append(L10000)
inf = open("100000.txt", "r")
inputData = inf.readlines()
for line in inputData:
L100000.append(int(line.rstrip()))
data.append(L100000)
inf = open("1000000.txt", "r")
inputData = inf.readlines()
for line in inputData:
L1000000.append(int(line.rstrip()))
data.append(L1000000)
for numList in data:
start = time.time()
mergeSort(numList, 0, len(numList)-1)
end = time.time()
print("Sort time for {} size list: {}".format(len(numList), end - start))
The error:
Traceback (most recent call last):
File "C:\Users\witcher\Documents\NJIT\CS 288\mergesort.py", line 110, in <module>
mergeSort(numList, 0, len(numList)-1)
File "C:\Users\witcher\Documents\NJIT\CS 288\mergesort.py", line 58, in mergeSort
mergeSort(arr, l, m)
File "C:\Users\witcher\Documents\NJIT\CS 288\mergesort.py", line 58, in mergeSort
mergeSort(arr, l, m)
File "C:\Users\witcher\Documents\NJIT\CS 288\mergesort.py", line 58, in mergeSort
mergeSort(arr, l, m)
File "C:\Users\witcher\Documents\NJIT\CS 288\mergesort.py", line 60, in mergeSort
merge(arr, l, m, r)
File "C:\Users\witcher\Documents\NJIT\CS 288\mergesort.py", line 10, in merge
L = [0] * (n1)
TypeError: can't multiply sequence by non-int of type 'float
I have no idea what causes this issue. This algorithm is directly from a tutorial website and worked perfectly fine with small lists. I believe the initial function call is correct as well. The input data is just a file where every line is a random integer, here is the script I used to create those scripts:
import math
import random
for num in [10, 100, 1000, 10000, 10000, 100000, 1000000]:
outf = open(str(num)+".txt", "w")
for i in range(num):
outf.write(str(random.randint(1,999))+"\n")
outf.close()
And yes, I manually removed the extra newline at the end of each file. Any help is appreciated.
Looks like you're on Python 3? I'm guessing the error stems from this line:
m = (l+(r-1))/2
In Python 3, this division will create a float (as opposed to just regular ints -- the behavior in Python 2). If you want to create ints still, you can use:
m = (l+(r-1)) // 2
This is a floor division and will give you an int, which should work for your use case.

List Index out of Range Error Whilst Making a Square

So I'm trying to make a function that takes an integer 'n' and returns a list of lists, and this is all in the vein of making a 'magic square' (start at 1 in the top center, then go right and up to the next, all with a 'wraparound' effect). Anyway, I feel my code is super clunky but also I can't test if it works because well it doesn't.. I get a list index out of range message for the line msq[row][col] = v. Here's the code:
def magicsquare(n):
msq = [[0 for c in range(n)] for r in range(n)]
row, col= n-1, (n-1)/2
M = n*(n+1)/2
v, r, c = 1,0,0
msq[row][col] = v
while v != M:
v= v+1
if row+1 >= n:
r = 0
else: r = row + 1
if (col+1) < n:
c = col + 1
else: c = 0
if msq[r][c]:
if (row+1) < n:
r = row+1
c = col
grid[r][c] = v
row = r
col = c
return magicsquare(n)
oh and the test I'm trying to pass is magicsquare(3) == magicsquare([[4, 3, 8], [9, 5, 1], [2, 7, 6]]). Any help is appreciated, thank you!!!!!!!

Categories