Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implemented Matrix Exponentiation Method #11747

Merged
merged 29 commits into from
Oct 4, 2024
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f5211cc
feat: add Matrix Exponentiation method
Acuspeedster Oct 1, 2024
95421d7
feat: added new function matrix exponetiation method
Acuspeedster Oct 1, 2024
adf10bf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 1, 2024
ba1cbc6
feat: This function uses the tail-recursive form of the Euclidean alg…
Acuspeedster Oct 1, 2024
fd37108
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 1, 2024
50fd058
reduced the number of characters per line in the comments
Acuspeedster Oct 1, 2024
d6fec67
Merge branch 'branch1' of https://github.com/Acuspeedster/Python into…
Acuspeedster Oct 1, 2024
ede7215
removed unwanted code
Acuspeedster Oct 1, 2024
0f939a8
feat: Implemented a new function to swaap numbers without dummy variable
Acuspeedster Oct 1, 2024
5dc67f8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 1, 2024
b581cf5
removed previos code
Acuspeedster Oct 1, 2024
3ad4b6a
removed the previous code
Acuspeedster Oct 1, 2024
31c5645
Done with the required changes
Acuspeedster Oct 2, 2024
6ee1a40
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 2, 2024
e48a3f3
Done with the required changes
Acuspeedster Oct 2, 2024
8085e66
Merge branch 'branch1' of https://github.com/Acuspeedster/Python into…
Acuspeedster Oct 2, 2024
f82bd8c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 2, 2024
8bf1389
Done with the required changes
Acuspeedster Oct 2, 2024
7860646
Merge branch 'branch1' of https://github.com/Acuspeedster/Python into…
Acuspeedster Oct 2, 2024
9ffd634
Done with the required changes
Acuspeedster Oct 2, 2024
4e2456f
Done with the required changes
Acuspeedster Oct 2, 2024
07ed6b9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 2, 2024
955c792
Update maths/fibonacci.py
Acuspeedster Oct 4, 2024
70dd92d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 4, 2024
1909143
Done with the required changes
Acuspeedster Oct 4, 2024
6cc39c0
Merge branch 'branch1' of https://github.com/Acuspeedster/Python into…
Acuspeedster Oct 4, 2024
b7db4ca
Done with the required changes
Acuspeedster Oct 4, 2024
b706572
Done with the required changes
Acuspeedster Oct 4, 2024
6cfdbc3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions maths/fibonacci.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

NOTE 2: the Binet's formula function is much more limited in the size of inputs
that it can handle due to the size limitations of Python floats
NOTE 3: the matrix function is the fastest and most memory efficient for large n


See benchmark numbers in __main__ for performance comparisons/
https://en.wikipedia.org/wiki/Fibonacci_number for more information
Expand All @@ -17,6 +19,9 @@
from math import sqrt
from time import time

import numpy as np
from numpy import ndarray


def time_func(func, *args, **kwargs):
"""
Expand Down Expand Up @@ -230,6 +235,88 @@ def fib_binet(n: int) -> list[int]:
return [round(phi**i / sqrt_5) for i in range(n + 1)]


def matrix_pow_np(m: ndarray, power: int) -> ndarray:
"""
Raises a matrix to the power of 'power' using binary exponentiation.

Args:
m: Matrix as a numpy array.
power: The power to which the matrix is to be raised.

Returns:
The matrix raised to the power.

Raises:
ValueError: If power is negative.

>>> m = np.array([[1, 1], [1, 0]], dtype=int)
>>> matrix_pow_np(m, 0) # Identity matrix when raised to the power of 0
array([[1, 0],
[0, 1]])

>>> matrix_pow_np(m, 1) # Same matrix when raised to the power of 1
array([[1, 1],
[1, 0]])

>>> matrix_pow_np(m, 5)
array([[8, 5],
[5, 3]])

>>> matrix_pow_np(m, -1)
Traceback (most recent call last):
...
ValueError: power is negative
Comment on lines +265 to +268
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your code never actually checks whether the power is negative. I think this is why your tests are never finishing: this test is just running in an infinite loop with power = -1, -2, -3, ...

"""
result = np.array([[1, 0], [0, 1]], dtype=int) # Identity Matrix
base = m
if power < 0: # Negative power is not allowed
raise ValueError("power is negative")
while power:
if power % 2 == 1:
result = np.dot(result, base)
base = np.dot(base, base)
power //= 2
return result


def fib_matrix_np(n: int) -> int:
"""
Calculates the n-th Fibonacci number using matrix exponentiation.
https://www.nayuki.io/page/fast-fibonacci-algorithms#:~:text=
Summary:%20The%20two%20fast%20Fibonacci%20algorithms%20are%20matrix

Args:
n: Fibonacci sequence index

Returns:
The n-th Fibonacci number.

Raises:
ValueError: If n is negative.

>>> fib_matrix_np(0)
0
>>> fib_matrix_np(1)
1
>>> fib_matrix_np(5)
5
>>> fib_matrix_np(10)
55
>>> fib_matrix_np(-1)
Traceback (most recent call last):
...
ValueError: n is negative
"""
if n < 0:
raise ValueError("n is negative")
if n == 0:
return 0

m = np.array([[1, 1], [1, 0]], dtype=int)
result = matrix_pow_np(m, n - 1)
return int(result[0, 0])


if __name__ == "__main__":
from doctest import testmod

Expand All @@ -242,3 +329,4 @@ def fib_binet(n: int) -> list[int]:
time_func(fib_memoization, num) # 0.0100 ms
time_func(fib_recursive_cached, num) # 0.0153 ms
time_func(fib_recursive, num) # 257.0910 ms
time_func(fib_matrix_np, num) # 0.0000 ms