Skip to content

Commit f8d0fc2

Browse files
committed
feat: add O(log n) lucas number implementation using matrix exponentiation
Added dynamic_lucas_number_logn function that uses matrix exponentiation to compute Lucas numbers in logarithmic time complexity, compared to the existing O(n) and O(n) recursive implementations. Updated module exports to include the new function and added comprehensive test coverage for all three implementations.
1 parent 4eec0b7 commit f8d0fc2

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

src/math/lucas_series.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,56 @@ pub fn dynamic_lucas_number(n: u32) -> u32 {
1616
let mut b = 1;
1717

1818
for _ in 0..n {
19-
let temp = a;
20-
a = b;
21-
b += temp;
19+
(a, b) = (b, a + b);
2220
}
2321

2422
a
2523
}
2624

25+
pub fn dynamic_lucas_number_logn(n: u32) -> u32 {
26+
if n == 0 {
27+
return 2;
28+
} else if n == 1 {
29+
return 1;
30+
}
31+
32+
// Matrix exponentiation: [[1, 1], [1, 0]]^n
33+
// say n = 11
34+
// We can write 11 as 1011 in binary
35+
// which is 2^3 * 1 + 2^1 * 1 + 2^0 * 1
36+
let mut matrix = [[1u32, 1u32], [1u32, 0u32]];
37+
let mut result = [[1u32, 0u32], [0u32, 1u32]]; // Identity matrix
38+
let mut power = n - 1;
39+
40+
while power > 0 {
41+
if power & 1 == 1 {
42+
result = matrix_multiply(result, matrix);
43+
}
44+
// always square the matrix, this will generate
45+
// the following sequence for each iteration of
46+
// i: matrix^(2^i) for i = 1, 2, 3...
47+
matrix = matrix_multiply(matrix, matrix);
48+
power >>= 1;
49+
}
50+
51+
// Return L(n) = result[0][0] * L(1) + result[0][1] * L(0) = result[0][0] * 1 + result[0][1] * 2
52+
result[0][0] + 2 * result[0][1]
53+
}
54+
55+
fn matrix_multiply(a: [[u32; 2]; 2], b: [[u32; 2]; 2]) -> [[u32; 2]; 2] {
56+
let mut result = [[0u32; 2]; 2];
57+
58+
for i in 0..2 {
59+
for j in 0..2 {
60+
for k in 0..2 {
61+
result[i][j] = result[i][j].wrapping_add(a[i][k].wrapping_mul(b[k][j]));
62+
}
63+
}
64+
}
65+
66+
result
67+
}
68+
2769
#[cfg(test)]
2870
mod tests {
2971
use super::*;
@@ -36,6 +78,7 @@ mod tests {
3678
let (n, expected) = $inputs;
3779
assert_eq!(recursive_lucas_number(n), expected);
3880
assert_eq!(dynamic_lucas_number(n), expected);
81+
assert_eq!(dynamic_lucas_number_logn(n), expected);
3982
}
4083
)*
4184
}

src/math/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub use self::least_square_approx::least_square_approx;
135135
pub use self::linear_sieve::LinearSieve;
136136
pub use self::logarithm::log;
137137
pub use self::lucas_series::dynamic_lucas_number;
138+
pub use self::lucas_series::dynamic_lucas_number_logn;
138139
pub use self::lucas_series::recursive_lucas_number;
139140
pub use self::matrix_ops::Matrix;
140141
pub use self::mersenne_primes::{get_mersenne_primes, is_mersenne_prime};

0 commit comments

Comments
 (0)