Skip to content

Commit 72d1d42

Browse files
authored
Add Fibonacci Using Matrix Exponentiation (TheAlgorithms#420)
1 parent 1c37c24 commit 72d1d42

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
* [Quadratic Residue](https://github.com/TheAlgorithms/Rust/blob/master/src/math/quadratic_residue.rs)
123123
* [Random](https://github.com/TheAlgorithms/Rust/blob/master/src/math/random.rs)
124124
* [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/Rust/blob/master/src/math/sieve_of_eratosthenes.rs)
125+
* [Signum](https://github.com/TheAlgorithms/Rust/blob/master/src/math/signum.rs)
125126
* [Simpson Integration](https://github.com/TheAlgorithms/Rust/blob/master/src/math/simpson_integration.rs)
126127
* [Square Root](https://github.com/TheAlgorithms/Rust/blob/master/src/math/square_root.rs)
127128
* [Trial Division](https://github.com/TheAlgorithms/Rust/blob/master/src/math/trial_division.rs)

src/dynamic_programming/fibonacci.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,69 @@ fn _memoized_fibonacci(n: u32, cache: &mut HashMap<u32, u128>) -> u128 {
123123
*f
124124
}
125125

126+
/// matrix_fibonacci(n) returns the nth fibonacci number
127+
/// This function uses the definition of Fibonacci where:
128+
/// F(0) = 0, F(1) = 1 and F(n+1) = F(n) + F(n-1) for n>0
129+
///
130+
/// Matrix formula:
131+
/// [F(n + 2)] = [1, 1] * [F(n + 1)]
132+
/// [F(n + 1)] [1, 0] [F(n) ]
133+
///
134+
/// Warning: This will overflow the 128-bit unsigned integer at n=186
135+
pub fn matrix_fibonacci(n: u32) -> u128 {
136+
let multiplier: Vec<Vec<u128>> = vec![vec![1, 1], vec![1, 0]];
137+
138+
let multiplier = matrix_power(&multiplier, n);
139+
let initial_fib_matrix: Vec<Vec<u128>> = vec![vec![1], vec![0]];
140+
141+
let res = matrix_multiply(&multiplier, &initial_fib_matrix);
142+
143+
res[1][0]
144+
}
145+
146+
fn matrix_power(base: &Vec<Vec<u128>>, power: u32) -> Vec<Vec<u128>> {
147+
let identity_matrix: Vec<Vec<u128>> = vec![vec![1, 0], vec![0, 1]];
148+
149+
vec![base; power as usize]
150+
.iter()
151+
.fold(identity_matrix, |acc, x| matrix_multiply(&acc, x))
152+
}
153+
154+
// Copied from matrix_ops since u128 is required instead of i32
155+
#[allow(clippy::needless_range_loop)]
156+
fn matrix_multiply(multiplier: &[Vec<u128>], multiplicand: &[Vec<u128>]) -> Vec<Vec<u128>> {
157+
// Multiply two matching matrices. The multiplier needs to have the same amount
158+
// of columns as the multiplicand has rows.
159+
let mut result: Vec<Vec<u128>> = vec![];
160+
let mut temp;
161+
// Using variable to compare lenghts of rows in multiplicand later
162+
let row_right_length = multiplicand[0].len();
163+
for row_left in 0..multiplier.len() {
164+
if multiplier[row_left].len() != multiplicand.len() {
165+
panic!("Matrix dimensions do not match");
166+
}
167+
result.push(vec![]);
168+
for column_right in 0..multiplicand[0].len() {
169+
temp = 0;
170+
for row_right in 0..multiplicand.len() {
171+
if row_right_length != multiplicand[row_right].len() {
172+
// If row is longer than a previous row cancel operation with error
173+
panic!("Matrix dimensions do not match");
174+
}
175+
temp += multiplier[row_left][row_right] * multiplicand[row_right][column_right];
176+
}
177+
result[row_left].push(temp);
178+
}
179+
}
180+
result
181+
}
182+
126183
#[cfg(test)]
127184
mod tests {
128185
use super::classical_fibonacci;
129186
use super::fibonacci;
130187
use super::logarithmic_fibonacci;
188+
use super::matrix_fibonacci;
131189
use super::memoized_fibonacci;
132190
use super::recursive_fibonacci;
133191

@@ -250,4 +308,22 @@ mod tests {
250308
127127879743834334146972278486287885163
251309
);
252310
}
311+
312+
#[test]
313+
fn test_matrix_fibonacci() {
314+
assert_eq!(matrix_fibonacci(0), 0);
315+
assert_eq!(matrix_fibonacci(1), 1);
316+
assert_eq!(matrix_fibonacci(2), 1);
317+
assert_eq!(matrix_fibonacci(3), 2);
318+
assert_eq!(matrix_fibonacci(4), 3);
319+
assert_eq!(matrix_fibonacci(5), 5);
320+
assert_eq!(matrix_fibonacci(10), 55);
321+
assert_eq!(matrix_fibonacci(20), 6765);
322+
assert_eq!(matrix_fibonacci(21), 10946);
323+
assert_eq!(matrix_fibonacci(100), 354224848179261915075);
324+
assert_eq!(
325+
matrix_fibonacci(184),
326+
127127879743834334146972278486287885163
327+
);
328+
}
253329
}

src/dynamic_programming/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub use self::egg_dropping::egg_drop;
2020
pub use self::fibonacci::classical_fibonacci;
2121
pub use self::fibonacci::fibonacci;
2222
pub use self::fibonacci::logarithmic_fibonacci;
23+
pub use self::fibonacci::matrix_fibonacci;
2324
pub use self::fibonacci::memoized_fibonacci;
2425
pub use self::fibonacci::recursive_fibonacci;
2526
pub use self::fractional_knapsack::fractional_knapsack;

0 commit comments

Comments
 (0)