@@ -123,11 +123,69 @@ fn _memoized_fibonacci(n: u32, cache: &mut HashMap<u32, u128>) -> u128 {
123
123
* f
124
124
}
125
125
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
+
126
183
#[ cfg( test) ]
127
184
mod tests {
128
185
use super :: classical_fibonacci;
129
186
use super :: fibonacci;
130
187
use super :: logarithmic_fibonacci;
188
+ use super :: matrix_fibonacci;
131
189
use super :: memoized_fibonacci;
132
190
use super :: recursive_fibonacci;
133
191
@@ -250,4 +308,22 @@ mod tests {
250
308
127127879743834334146972278486287885163
251
309
) ;
252
310
}
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
+ }
253
329
}
0 commit comments