Skip to content

Commit cac9ae5

Browse files
authored
Merge pull request #3 from AranMesquita/add-benchmark-test
Add benchmark test
2 parents b9d78fd + f833eb3 commit cac9ae5

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
/target
22
/.venv
33
Cargo.lock
4+
__pycache__
5+
.vscode

src-py/benchmark_funcs.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import test_rust_in_python
2+
from fibonacci_matrix_exponentiation import python_nth_fibonacci_using_matrix_exponentiation
3+
4+
def python_runtime_benchmark(nth_term: int):
5+
for n in range(nth_term):
6+
python_nth_fibonacci_using_matrix_exponentiation(n)
7+
8+
9+
def rust_runtime_benchmark(nth_term: int):
10+
test_rust_in_python.rust_runtime_benchmark(nth_term) # type: ignore

src-py/runtime_bench_mark.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import timeit
2+
from benchmark_funcs import python_runtime_benchmark, rust_runtime_benchmark # noqa: F401
3+
4+
# reason why we only have NTH_TERM = 93 as 93rd Fibonacci number is the largest that fits in a u64
5+
# and 94th Fibonacci number is the first that exceeds u64::MAX
6+
NTH_TERM = 93
7+
NUMBER_OF_CALLS = 100000
8+
9+
rust_time = timeit.timeit(
10+
stmt=f"rust_runtime_benchmark({NTH_TERM})",
11+
globals=globals(),
12+
number=NUMBER_OF_CALLS
13+
)
14+
python_time = timeit.timeit(
15+
stmt=f"python_runtime_benchmark({NTH_TERM})",
16+
globals=globals(),
17+
number=NUMBER_OF_CALLS
18+
)
19+
20+
print(f"Rust avg: {rust_time * 1_000:.2f} µs, Python avg: {python_time * 1_000:.2f} µs (per call, over a total of {NTH_TERM * NUMBER_OF_CALLS:,} iterations)")

src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,51 @@ fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
1010
#[pymodule]
1111
fn test_rust_in_python(m: &Bound<'_, PyModule>) -> PyResult<()> {
1212
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
13+
m.add_function(wrap_pyfunction!(rust_nth_fibonacci_using_matrix_exponentiation, m)?)?;
14+
m.add_function(wrap_pyfunction!(rust_runtime_benchmark, m)?)?;
1315
Ok(())
1416
}
17+
18+
// Calculates the nth Fibonacci number using matrix exponentiation.
19+
// The Fibonacci sequence is defined as:
20+
// F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2) for n >= 2
21+
// The nth Fibonacci number can be computed using matrix exponentiation in O(log n) time.
22+
#[pyfunction]
23+
fn rust_nth_fibonacci_using_matrix_exponentiation(n: u64) -> u64 {
24+
if n == 0 {
25+
0
26+
} else {
27+
let base: [u64; 4] = [1, 1, 1, 0];
28+
let result: [u64; 4] = _power(base, n - 1);
29+
result[0]
30+
}
31+
}
32+
33+
fn _power(mut m: [u64; 4], mut n: u64) -> [u64; 4] {
34+
let mut result: [u64; 4] = [1, 0, 0, 1];
35+
while n > 0 {
36+
if n % 2 == 1 {
37+
result = _multiply(result, m);
38+
}
39+
m = _multiply(m, m);
40+
n /= 2;
41+
}
42+
result
43+
}
44+
45+
fn _multiply(a: [u64; 4], b: [u64; 4]) -> [u64; 4] {
46+
[
47+
a[0] * b[0] + a[1] * b[2],
48+
a[0] * b[1] + a[1] * b[3],
49+
a[2] * b[0] + a[3] * b[2],
50+
a[2] * b[1] + a[3] * b[3],
51+
]
52+
}
53+
54+
#[pyfunction]
55+
fn rust_runtime_benchmark(nth_term: u64) {
56+
for n in 0..nth_term {
57+
rust_nth_fibonacci_using_matrix_exponentiation(n);
58+
}
59+
}
60+

0 commit comments

Comments
 (0)