From 79531e5bc8ffd94cb10d72fc370bef1761bc152c Mon Sep 17 00:00:00 2001 From: anirudnits Date: Wed, 25 Sep 2019 14:16:59 +0530 Subject: [PATCH 1/3] Added the matrix_exponentiation.py file in maths directory --- maths/matrix_exponentiation.py | 134 +++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 maths/matrix_exponentiation.py diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py new file mode 100644 index 000000000000..17b243baf7ca --- /dev/null +++ b/maths/matrix_exponentiation.py @@ -0,0 +1,134 @@ +"""Matrix Exponentiation""" + +import timeit + +""" +Matrix Exponentiation is a technique to solve linear recurrences in logarithmic time. +You read more about it here: +http://zobayer.blogspot.com/2010/11/matrix-exponentiation.html +https://www.hackerearth.com/practice/notes/matrix-exponentiation-1/ +""" + + +class Matrix(object): + def __init__(self, arg): + if isinstance(arg,list): #Initialzes a matrix identical to the one provided. + self.t = arg + self.n = len(arg) + + else: #Initializes a square matrix of the given size and set the values to zero. + self.n = arg + self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] + + def __mul__(self, b): + c = Matrix(self.n) + + for i in range(self.n): + for j in range(self.n): + for k in range(self.n): + c.t[i][j] += self.t[i][k]*b.t[k][j] + + return c + +def modular_exponentiation(a, b): + ret = Matrix([[1,0], [0,1]]) + + while b > 0: + if b&1: + ret = ret*a + + a = a*a + b >>= 1 + + return ret + +def fibonacci_with_matrix_exponentiation(n, f1, f2): + + #Trivial Cases + if n == 1: + return f1 + + if n == 2: + return f2 + + a = Matrix([[1,1], [1,0]]) + + m = modular_exponentiation(a, n-2) + + return f2*m.t[0][0] + f1*m.t[0][1] + +def simple_fibonacci(n, f1, f2): + + #Trival Cases + if n == 1: + return f1 + + if n == 2: + return f2 + + fn_1 = f1 + fn_2 = f2 + + n -= 2 + + while n > 0: + fn = fn_1 + fn_2 + + fn_2 = fn_1 + fn_1 = fn + + n -= 1 + + return fn + +def matrix_exponentiation_time(): + setup = ''' +from random import randint +from __main__ import fibonacci_with_matrix_exponentiation +''' + + code = ''' +n = randint(1,70000) + +f1 = 1 +f2 = 1 + + +fibonacci_with_matrix_exponentiation(n, f1, f2) +''' + exec_time = timeit.timeit(setup = setup, + stmt = code, + number = 100) + + print ("With matrix exponentiation the average execution time is ", exec_time/100) + + +def simple_fibonacci_time(): + setup = ''' +from random import randint +from __main__ import simple_fibonacci +''' + + code = ''' +n = randint(1,70000) + +f1 = 1 +f2 = 1 + + +simple_fibonacci(n, f1, f2) +''' + exec_time = timeit.timeit(setup = setup, + stmt = code, + number = 100) + + print ("Without matrix exponentiation the average execution time is ", exec_time/100) + + +def main(): + matrix_exponentiation_time() + simple_fibonacci_time() + + +if __name__ == "__main__": + main() \ No newline at end of file From f97cc0037da26aefccb5af11a795cdcb333bcd4f Mon Sep 17 00:00:00 2001 From: anirudnits Date: Wed, 25 Sep 2019 15:53:10 +0530 Subject: [PATCH 2/3] Implemented the requested changes --- maths/matrix_exponentiation.py | 138 ++++++++++++++++----------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index 17b243baf7ca..f2f2ad35b418 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -11,124 +11,122 @@ class Matrix(object): - def __init__(self, arg): - if isinstance(arg,list): #Initialzes a matrix identical to the one provided. - self.t = arg - self.n = len(arg) + def __init__(self, arg): + if isinstance(arg, list): # Initialzes a matrix identical to the one provided. + self.t = arg + self.n = len(arg) - else: #Initializes a square matrix of the given size and set the values to zero. - self.n = arg - self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] + else: # Initializes a square matrix of the given size and set the values to zero. + self.n = arg + self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] - def __mul__(self, b): - c = Matrix(self.n) + def __mul__(self, b): + c = Matrix(self.n) - for i in range(self.n): - for j in range(self.n): - for k in range(self.n): - c.t[i][j] += self.t[i][k]*b.t[k][j] + for i in range(self.n): + for j in range(self.n): + for k in range(self.n): + c.t[i][j] += self.t[i][k] * b.t[k][j] + + return c - return c def modular_exponentiation(a, b): - ret = Matrix([[1,0], [0,1]]) + ret = Matrix([[1, 0], [0, 1]]) + + while b > 0: + if b & 1: + ret = ret * a - while b > 0: - if b&1: - ret = ret*a + a = a * a + b >>= 1 - a = a*a - b >>= 1 + return ret - return ret def fibonacci_with_matrix_exponentiation(n, f1, f2): - - #Trivial Cases - if n == 1: - return f1 - if n == 2: - return f2 + # Trivial Cases + if n == 1: + return f1 + + if n == 2: + return f2 - a = Matrix([[1,1], [1,0]]) + a = Matrix([[1, 1], [1, 0]]) - m = modular_exponentiation(a, n-2) + m = modular_exponentiation(a, n - 2) + + return f2 * m.t[0][0] + f1 * m.t[0][1] - return f2*m.t[0][0] + f1*m.t[0][1] def simple_fibonacci(n, f1, f2): - #Trival Cases - if n == 1: - return f1 + # Trival Cases + if n == 1: + return f1 + + if n == 2: + return f2 - if n == 2: - return f2 + fn_1 = f1 + fn_2 = f2 - fn_1 = f1 - fn_2 = f2 + n -= 2 - n -= 2 + while n > 0: + fn = fn_1 + fn_2 - while n > 0: - fn = fn_1 + fn_2 + fn_2 = fn_1 + fn_1 = fn - fn_2 = fn_1 - fn_1 = fn + n -= 1 - n -= 1 + return fn - return fn def matrix_exponentiation_time(): - setup = ''' + setup = """ from random import randint from __main__ import fibonacci_with_matrix_exponentiation -''' - - code = ''' -n = randint(1,70000) +""" + code = """ f1 = 1 f2 = 1 -fibonacci_with_matrix_exponentiation(n, f1, f2) -''' - exec_time = timeit.timeit(setup = setup, - stmt = code, - number = 100) +fibonacci_with_matrix_exponentiation(randint(1,70000), f1, f2) +""" + exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - print ("With matrix exponentiation the average execution time is ", exec_time/100) + print("With matrix exponentiation the average execution time is ", exec_time / 100) def simple_fibonacci_time(): - setup = ''' + setup = """ from random import randint from __main__ import simple_fibonacci -''' - - code = ''' -n = randint(1,70000) +""" + code = """ f1 = 1 f2 = 1 -simple_fibonacci(n, f1, f2) -''' - exec_time = timeit.timeit(setup = setup, - stmt = code, - number = 100) +simple_fibonacci(randint(1,70000), f1, f2) +""" + exec_time = timeit.timeit(setup=setup, stmt=code, number=100) + + print( + "Without matrix exponentiation the average execution time is ", exec_time / 100 + ) - print ("Without matrix exponentiation the average execution time is ", exec_time/100) - def main(): - matrix_exponentiation_time() - simple_fibonacci_time() + matrix_exponentiation_time() + simple_fibonacci_time() if __name__ == "__main__": - main() \ No newline at end of file + main() From 8e64f021cc0ad35494bb130f77ec7a46d24f65b0 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 25 Sep 2019 20:08:29 +0200 Subject: [PATCH 3/3] Update matrix_exponentiation.py --- maths/matrix_exponentiation.py | 71 +++++++++------------------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/maths/matrix_exponentiation.py b/maths/matrix_exponentiation.py index f2f2ad35b418..ee9e1757687c 100644 --- a/maths/matrix_exponentiation.py +++ b/maths/matrix_exponentiation.py @@ -15,71 +15,53 @@ def __init__(self, arg): if isinstance(arg, list): # Initialzes a matrix identical to the one provided. self.t = arg self.n = len(arg) - else: # Initializes a square matrix of the given size and set the values to zero. self.n = arg self.t = [[0 for _ in range(self.n)] for _ in range(self.n)] def __mul__(self, b): - c = Matrix(self.n) - + matrix = Matrix(self.n) for i in range(self.n): for j in range(self.n): for k in range(self.n): - c.t[i][j] += self.t[i][k] * b.t[k][j] - - return c + matrix.t[i][j] += self.t[i][k] * b.t[k][j] + return matrix def modular_exponentiation(a, b): - ret = Matrix([[1, 0], [0, 1]]) - + matrix = Matrix([[1, 0], [0, 1]]) while b > 0: if b & 1: - ret = ret * a - - a = a * a + matrix *= a + a *= a b >>= 1 - - return ret + return matrix def fibonacci_with_matrix_exponentiation(n, f1, f2): - # Trivial Cases if n == 1: return f1 - - if n == 2: + elif n == 2: return f2 - - a = Matrix([[1, 1], [1, 0]]) - - m = modular_exponentiation(a, n - 2) - - return f2 * m.t[0][0] + f1 * m.t[0][1] + matrix = Matrix([[1, 1], [1, 0]]) + matrix = modular_exponentiation(matrix, n - 2) + return f2 * matrix.t[0][0] + f1 * matrix.t[0][1] def simple_fibonacci(n, f1, f2): - # Trival Cases if n == 1: return f1 - - if n == 2: + elif n == 2: return f2 fn_1 = f1 fn_2 = f2 - n -= 2 while n > 0: - fn = fn_1 + fn_2 - - fn_2 = fn_1 - fn_1 = fn - + fn_1, fn_2 = fn_1 + fn_2, fn_1 n -= 1 return fn @@ -90,17 +72,10 @@ def matrix_exponentiation_time(): from random import randint from __main__ import fibonacci_with_matrix_exponentiation """ - - code = """ -f1 = 1 -f2 = 1 - - -fibonacci_with_matrix_exponentiation(randint(1,70000), f1, f2) -""" + code = "fibonacci_with_matrix_exponentiation(randint(1,70000), 1, 1)" exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - print("With matrix exponentiation the average execution time is ", exec_time / 100) + return exec_time def simple_fibonacci_time(): @@ -108,19 +83,11 @@ def simple_fibonacci_time(): from random import randint from __main__ import simple_fibonacci """ - - code = """ -f1 = 1 -f2 = 1 - - -simple_fibonacci(randint(1,70000), f1, f2) -""" + code = "simple_fibonacci(randint(1,70000), 1, 1)" exec_time = timeit.timeit(setup=setup, stmt=code, number=100) - - print( - "Without matrix exponentiation the average execution time is ", exec_time / 100 - ) + print("Without matrix exponentiation the average execution time is ", + exec_time / 100) + return exec_time def main():