mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-01-18 16:27:02 +00:00
Added Matrix Exponentiation (#1203)
* Added the matrix_exponentiation.py file in maths directory * Implemented the requested changes * Update matrix_exponentiation.py
This commit is contained in:
parent
01601e6382
commit
e40d4a25f9
99
maths/matrix_exponentiation.py
Normal file
99
maths/matrix_exponentiation.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
"""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):
|
||||
matrix = Matrix(self.n)
|
||||
for i in range(self.n):
|
||||
for j in range(self.n):
|
||||
for k in range(self.n):
|
||||
matrix.t[i][j] += self.t[i][k] * b.t[k][j]
|
||||
return matrix
|
||||
|
||||
|
||||
def modular_exponentiation(a, b):
|
||||
matrix = Matrix([[1, 0], [0, 1]])
|
||||
while b > 0:
|
||||
if b & 1:
|
||||
matrix *= a
|
||||
a *= a
|
||||
b >>= 1
|
||||
return matrix
|
||||
|
||||
|
||||
def fibonacci_with_matrix_exponentiation(n, f1, f2):
|
||||
# Trivial Cases
|
||||
if n == 1:
|
||||
return f1
|
||||
elif n == 2:
|
||||
return f2
|
||||
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
|
||||
elif n == 2:
|
||||
return f2
|
||||
|
||||
fn_1 = f1
|
||||
fn_2 = f2
|
||||
n -= 2
|
||||
|
||||
while n > 0:
|
||||
fn_1, fn_2 = fn_1 + fn_2, fn_1
|
||||
n -= 1
|
||||
|
||||
return fn
|
||||
|
||||
|
||||
def matrix_exponentiation_time():
|
||||
setup = """
|
||||
from random import randint
|
||||
from __main__ import fibonacci_with_matrix_exponentiation
|
||||
"""
|
||||
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():
|
||||
setup = """
|
||||
from random import randint
|
||||
from __main__ import simple_fibonacci
|
||||
"""
|
||||
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)
|
||||
return exec_time
|
||||
|
||||
|
||||
def main():
|
||||
matrix_exponentiation_time()
|
||||
simple_fibonacci_time()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user