You are on page 1of 9

# -*- coding: utf-8 -*-

import sys
from numpy import asarray
import numpy as np

# STOCK_PRICES = [100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97]

STOCK_PRICE_CHANGES = [13, -3, -25, 20, -3, -16,


-23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
MOB = [-2, -3, 4, -1, -2, 1, 5, -3]
NEG = [-4, -6, -2, -9, -7]
POS = [1, 2, 3, 4, 8, 2, 12, 1]
XYZ = [[1, 2], [3, 4]]
PQR = [[2, 3], [4, 5]]
EMPTY_MATRIX = []
ABC = [[1, 2, 3, 4], [3, 4, 2, 1], [1, 2, 3, 4], [3, 4, 2, 1]]
DEF = [[2, 3, 1, 4], [4, 5, 6, 7], [1, 2, 3, 4], [4, 5, 6, 7]]

# ==============================================================

# The brute force method to solve max subarray problem


def find_maximum_subarray_brute(A):

"""

Return a tuple (i,j) where A[i:j] is the maximum subarray.

time complexity = O(n^2)

"""

if len(A) == 0:
return None

max = -sys.maxsize
start_index = 0
last_index = 0

for idx, number in enumerate(A):


sum = 0
for j in range(idx, len(A)):

sum = sum + A[j]


if sum > max:
max = sum
start_index = idx
last_index = j

return (start_index, last_index)

# ==============================================================

# The maximum crossing subarray method for solving the max subarray problem
def find_maximum_crossing_subarray(A, low, mid, high):

"""

Find the maximum subarray that crosses mid


Return a tuple ((i, j), sum) where sum is the maximum subarray of A[i:j].

"""

sum = 0
right_array_sum = -sys.maxsize
rindex = high
index = mid+1
while index <= high:
sum = sum + A[index]
if sum > right_array_sum:
right_array_sum = sum
rindex = index

index = index + 1

sum = 0
left_array_sum = -sys.maxsize
lindex = mid
index = mid
while index >= low:
sum = sum + A[index]
if sum > left_array_sum:
left_array_sum = sum
lindex = index

index = index-1

total_sum_left_and_right = left_array_sum + right_array_sum

return [(lindex, rindex), total_sum_left_and_right]

# The recursive method to solve max subarray problem


def find_maximum_subarray_recursive_helper(A, low=0, high=-1):

"""

Return a tuple ((i, j), sum) where sum is the maximum subarray of A[i:j].

"""

if low == high:
return ((low, high), A[low])

mid = (low + high) / 2

mid = int(mid)

left_maximum_sum = find_maximum_subarray_recursive_helper(A, low, mid)


# print (left_maximum_sum)

right_maximum_sum = find_maximum_subarray_recursive_helper(A,
mid + 1, high)
# print (right_maximum_sum)
crossing_subarray = find_maximum_crossing_subarray(A, low, mid, high)

# ans =
# max(left_maximum_sum[1], right_maximum_sum[1], crossing_subarray[1])
items = [left_maximum_sum, right_maximum_sum, crossing_subarray]
max_item = max(items, key=lambda item: item[1])

return max_item

# The recursive method to solve max subarray problem


def find_maximum_subarray_recursive(A):

"""

Return a tuple (i,j) where A[i:j] is the maximum subarray.

"""
if len(A) == 0:
return None

return find_maximum_subarray_recursive_helper(A, 0, len(A) - 1)[0]

# ==============================================================

# The iterative method to solve max subarray problem


def find_maximum_subarray_iterative(A):
NEG
"""

Return a tuple (i,j) where A[i:j] is the maximum subarray.

"""
if len(A) == 0:
return None

global_max = A[0]
max_current = A[0]
start = 0
finish = 0
temp_index = 0
for index, obj in enumerate(A):

if obj > max_current + obj:


max_current = obj
temp_index = index

else:
max_current = max_current + obj

if global_max < max_current:


global_max = max_current
finish = index
start = temp_index

return (start, finish)

# =================================================================

def square_matrix_multiply(A, B):

"""
Return the product AB of matrix multiplication.

"""

A = asarray(A)

B = asarray(B)

if len(A) == 0 or len(B) == 0:
return None
assert A.shape == B.shape
assert A.shape == A.T.shape

result = np.zeros([A.shape[0], B.shape[1]], dtype=int)


for row_index in range(0, A.shape[0]):
for col_index in range(0, B.shape[1]):
for k in range(0, B.shape[0]):
result[row_index][col_index] = \
result[row_index][col_index] \
+ A[row_index][k] * B[k][col_index]

return result

def add(A, B):


n = len(A)
C = [[0 for j in range(0, n)] for i in range(0, n)]
for i in range(0, n):
for j in range(0, n):
C[i][j] = A[i][j] + B[i][j]
return C

def subtract(A, B):


n = len(A)
C = [[0 for j in range(0, n)] for i in range(0, n)]
for i in range(0, n):
for j in range(0, n):
C[i][j] = A[i][j] - B[i][j]
return C

# ==============================================================

def square_matrix_multiply_strassens(A, B):

"""

Return the product AB of matrix multiplication.

Assume len(A) is a power of 2

"""

A = asarray(A)
B = asarray(B)

if len(A) == 0 or len(B) == 0:
return None

assert A.shape == B.shape

assert A.shape == A.T.shape

assert (len(A) & (len(A) - 1)) == 0, "A is not a power of 2"

matrix_size = len(A)
if matrix_size == 1:
# return matrixProductfor2by2(A, B)
return [A[0] * B[0]]
else:
new_size = int(matrix_size/2)
# initializng 4 sub matrices for both a and b
a11 = np.zeros([new_size, new_size], dtype=int)
a12 = np.zeros([new_size, new_size], dtype=int)
a21 = np.zeros([new_size, new_size], dtype=int)
a22 = np.zeros([new_size, new_size], dtype=int)
aResult = np.zeros([new_size, new_size], dtype=int)

b11 = np.zeros([new_size, new_size], dtype=int)


b12 = np.zeros([new_size, new_size], dtype=int)
b21 = np.zeros([new_size, new_size], dtype=int)
b22 = np.zeros([new_size, new_size], dtype=int)
bResult = np.zeros([new_size, new_size], dtype=int)

for row in range(new_size):


for col in range(new_size):
a11[row][col] = A[row][col]
a12[row][col] = A[row][col + new_size]
a21[row][col] = A[row + new_size][col]
a22[row][col] = A[row + new_size][col + new_size]

b11[row][col] = B[row][col]
b12[row][col] = B[row][col + new_size]
b21[row][col] = B[row + new_size][col]
b22[row][col] = B[row + new_size][col + new_size]

# M1 = (a11+a22) * (b11+b22)
# M2 = (a21+a22) * (b11)
# M3 = (a11) * (b12 - b22)
# M4 = (a22) * (b21 - b11)
# M5 = (a11+a12) * (b22)
# M6 = (a21-a11) * (b11+b12)
# M7 = (a12-a22) * (b21+b22)

# C11 = m1 + m4 - m5 + m7
# C12 = m3 + m5
# C21 = m2 + m4
# C22 = m1 + m3 - m2 + m6

# Find m1 to m7:
# M1 = (a11+a22) * (b11+b22)
# aResult = add(a11, a22)
a = np.matrix(a11)
b = np.matrix(a22)
aResult = a + b
# bResult = add(b11, b22)
a = np.matrix(b11)
b = np.matrix(b22)
bResult = a + b
m1 = square_matrix_multiply_strassens(aResult, bResult)

# M2 = (a21+a22) * (b11)
aResult = add(a21, a22)
a = np.matrix(a21)
b = np.matrix(a22)
aResult = a + b
m2 = square_matrix_multiply_strassens(aResult, b11)

# M3 = (a11) * (b12 - b22)


# bResult = subtract(b12, b22)
a = np.matrix(b12)
b = np.matrix(b22)
bResult = a - b
m3 = square_matrix_multiply_strassens(a11, bResult)

# M4 = (a22) * (b21 - b11)


# bResult = subtract(b21, b11)
a = np.matrix(b21)
b = np.matrix(b11)
bResult = a - b
m4 = square_matrix_multiply_strassens(a22, bResult)

# M5 = (a11+a12) * (b22)
aResult = add(a11, a12)

m5 = square_matrix_multiply_strassens(aResult, b22)

# M6 = (a21-a11) * (b11+b12)
aResult = subtract(a21, a11)
bResult = add(b11, b12)
m6 = square_matrix_multiply_strassens(aResult, bResult)

# M7 = (a12-a22) * (b21+b22)
aResult = subtract(a12, a22)
bResult = add(b21, b22)
m7 = square_matrix_multiply_strassens(aResult, bResult)
# calculating c21, c21, c11 e c22:
c12 = add(m3, m5) # c12 = m3 + m5
c21 = add(m2, m4) # c21 = m2 + m4

aResult = add(m1, m4) # m1 + m4


bResult = add(aResult, m7) # m1 + m4 + m7
c11 = subtract(bResult, m5) # c11 = m1 + m4 - m5 + m7

aResult = add(m1, m3) # m1 + m3


bResult = add(aResult, m6) # m1 + m3 + m6
c22 = subtract(bResult, m2) # c22 = m1 + m3 - m2 + m6

# Grouping the results obtained in a single matrix:


C = [[0 for j in range(0, matrix_size)] for i in range(0, matrix_size)]
for i in range(0, new_size):
for j in range(0, new_size):
C[i][j] = c11[i][j]
C[i][j + new_size] = c12[i][j]
C[i + new_size][j] = c21[i][j]
C[i + new_size][j + new_size] = c22[i][j]
return C

pass
# ==============================================================

def test():

a = find_maximum_subarray_brute(STOCK_PRICE_CHANGES)
print("brute")
print(a)
a = find_maximum_subarray_recursive(STOCK_PRICE_CHANGES)
print ("Recurisve")
print (a)
a = find_maximum_subarray_iterative(STOCK_PRICE_CHANGES)
print("Iterative")
print(a)

p = square_matrix_multiply(ABC, DEF)
print("Multiplication: " + str(p))
p = square_matrix_multiply_strassens(ABC, DEF)
print("Strassens Multiplication: " + str(p))
pass

if __name__ == '__main__':

test()

# ==============================================================

Output:
If you see the output carefully the output of matrix multiplication of
Strassens is a 2D array whereas the output for the normal
multiplication is matrix. This is because:
1) In Strassens the output 2D array is created using:
[[0 for j in range(0, matrix_size)] for i in
range(0, matrix_size)]
2) In first case of normal matrix
multiplication we are creating a matrix
using numpy i.e
np.zeros([A.shape[0], B.shape[1]],
dtype=int)
The above line creates matrix with rows
A.shape[0] and B.shape[1]

In Strassens Algorithm I have used addition


and subtraction methods. I have also used
numpy for addition and subtraction in few
cases just to check how it works.
Flake8 output:

You might also like