18
18
from collections .abc import Iterator
19
19
from math import sqrt
20
20
from time import time
21
+ import numpy as np
21
22
22
23
23
24
def time_func (func , * args , ** kwargs ):
@@ -232,38 +233,77 @@ def fib_binet(n: int) -> list[int]:
232
233
return [round (phi ** i / sqrt_5 ) for i in range (n + 1 )]
233
234
234
235
235
- def fib_matrix (n : int ) -> int :
236
- # https://www.nayuki.io/page/fast-fibonacci-algorithms#:~:text=
237
- # Summary:%20The%20two%20fast%20Fibonacci%20algorithms%20are%20matrix
238
- def matrix_mult (a , b ):
239
- return [
240
- [
241
- a [0 ][0 ] * b [0 ][0 ] + a [0 ][1 ] * b [1 ][0 ],
242
- a [0 ][0 ] * b [0 ][1 ] + a [0 ][1 ] * b [1 ][1 ],
243
- ],
244
- [
245
- a [1 ][0 ] * b [0 ][0 ] + a [1 ][1 ] * b [1 ][0 ],
246
- a [1 ][0 ] * b [0 ][1 ] + a [1 ][1 ] * b [1 ][1 ],
247
- ],
248
- ]
249
-
250
- def matrix_pow (m , power ):
251
- result = [[1 , 0 ], [0 , 1 ]] # Identity matrix
252
- base = m
253
- while power :
254
- if power % 2 == 1 :
255
- result = matrix_mult (result , base )
256
- base = matrix_mult (base , base )
257
- power //= 2
258
- return result
236
+ def matrix_mult_np (a , b ):
237
+ """
238
+ Multiplies two matrices using numpy's dot product.
239
+
240
+ Args:
241
+ a: First matrix as a numpy array
242
+ b: Second matrix as a numpy array
243
+
244
+ Returns:
245
+ The product of matrices a and b.
246
+ """
247
+ return np .dot (a , b )
248
+
249
+
250
+ def matrix_pow_np (m , power ):
251
+ """
252
+ Raises a matrix to the power of 'power' using binary exponentiation.
253
+
254
+ Args:
255
+ m: Matrix as a numpy array.
256
+ power: The power to which the matrix is to be raised.
257
+
258
+ Returns:
259
+ The matrix raised to the power.
260
+ """
261
+ result = np .identity (2 , dtype = int ) # Identity matrix
262
+ base = m
263
+ while power :
264
+ if power % 2 == 1 :
265
+ result = matrix_mult_np (result , base )
266
+ base = matrix_mult_np (base , base )
267
+ power //= 2
268
+ return result
259
269
270
+
271
+ def fib_matrix_np (n : int ) -> int :
272
+ """
273
+ Calculates the n-th Fibonacci number using matrix exponentiation.
274
+ https://www.nayuki.io/page/fast-fibonacci-algorithms#:~:text=
275
+ Summary:%20The%20two%20fast%20Fibonacci%20algorithms%20are%20matrix
276
+
277
+ Args:
278
+ n: Fibonacci sequence index
279
+
280
+ Returns:
281
+ The n-th Fibonacci number.
282
+
283
+ Raises:
284
+ ValueError: If n is negative.
285
+
286
+ >>> fib_matrix_np(0)
287
+ 0
288
+ >>> fib_matrix_np(1)
289
+ 1
290
+ >>> fib_matrix_np(10)
291
+ 55
292
+ >>> fib_matrix_np(-1)
293
+ Traceback (most recent call last):
294
+ ...
295
+ ValueError: n is negative
296
+ """
260
297
if n < 0 :
261
298
raise ValueError ("n is negative" )
262
299
if n == 0 :
263
300
return 0
264
- m = [[1 , 1 ], [1 , 0 ]]
265
- result = matrix_pow (m , n - 1 )
266
- return result [0 ][0 ]
301
+
302
+ m = np .array ([[1 , 1 ], [1 , 0 ]], dtype = int )
303
+ result = matrix_pow_np (m , n - 1 )
304
+ return result [0 , 0 ]
305
+
306
+
267
307
268
308
269
309
if __name__ == "__main__" :
@@ -278,4 +318,4 @@ def matrix_pow(m, power):
278
318
time_func (fib_memoization , num ) # 0.0100 ms
279
319
time_func (fib_recursive_cached , num ) # 0.0153 ms
280
320
time_func (fib_recursive , num ) # 257.0910 ms
281
- time_func (fib_matrix , num ) # 0.0000 ms
321
+ time_func (fib_matrix_np , num ) # 0.0000 ms
0 commit comments