Start Typing !!! type the highlighted character. You can't scroll once you start typing.
filename

nth_fibonacci_using_matrix_exponentiation.py

"""

Implementation of finding nth fibonacci number using matrix exponentiation.

Time Complexity is about O(log(n)*8), where 8 is the complexity of matrix multiplication of size 2 by 2.

And on the other hand complexity of bruteforce solution is O(n).

As we know

f[n] = f[n-1] + f[n-1]

Converting to matrix,

[f(n),f(n-1)] = [[1,1],[1,0]] * [f(n-1),f(n-2)]

-> [f(n),f(n-1)] = [[1,1],[1,0]]^2 * [f(n-2),f(n-3)]

...

...

-> [f(n),f(n-1)] = [[1,1],[1,0]]^(n-1) * [f(1),f(0)]

So we just need the n times multiplication of the matrix [1,1],[1,0]].

We can decrease the n times multiplication by following the divide and conquer approach.

"""

def multiply(matrix_a, matrix_b):

matrix_c = []

n = len(matrix_a)

for i in range(n):

list_1 = []

for j in range(n):

val = 0

for k in range(n):

val = val + matrix_a[i][k] * matrix_b[k][j]

list_1.append(val)

matrix_c.append(list_1)

return matrix_c

def identity(n):

return [[int(row == column) for column in range(n)] for row in range(n)]

def nth_fibonacci_matrix(n):

"""

>>> nth_fibonacci_matrix(100)

354224848179261915075

>>> nth_fibonacci_matrix(-100)

-100

"""

if n <= 1:

return n

res_matrix = identity(2)

fibonacci_matrix = [[1, 1], [1, 0]]

n = n - 1

while n > 0:

if n % 2 == 1:

res_matrix = multiply(res_matrix, fibonacci_matrix)

fibonacci_matrix = multiply(fibonacci_matrix, fibonacci_matrix)

n = int(n / 2)

return res_matrix[0][0]

def nth_fibonacci_bruteforce(n):

"""

>>> nth_fibonacci_bruteforce(100)

354224848179261915075

>>> nth_fibonacci_bruteforce(-100)

-100

"""

if n <= 1:

return n

fib0 = 0

fib1 = 1

for i in range(2, n + 1):

fib0, fib1 = fib1, fib0 + fib1

return fib1

def main():

fmt = "{} fibonacci number using matrix exponentiation is {} and using bruteforce is {}\n"

for ordinal in "0th 1st 2nd 3rd 10th 100th 1000th".split():

n = int("".join(c for c in ordinal if c in "0123456789")) # 1000th --> 1000

print(fmt.format(ordinal, nth_fibonacci_matrix(n), nth_fibonacci_bruteforce(n)))

# from timeit import timeit

# print(timeit("nth_fibonacci_matrix(1000000)",

# "from main import nth_fibonacci_matrix", number=5))

# print(timeit("nth_fibonacci_bruteforce(1000000)",

# "from main import nth_fibonacci_bruteforce", number=5))

# 2.3342058970001744

# 57.256506615000035

if __name__ == "__main__":

main()