diff --git a/src/numeric/README.md b/src/numeric/README.md index 31d9eb8c..4eda4508 100644 --- a/src/numeric/README.md +++ b/src/numeric/README.md @@ -17,6 +17,10 @@ Several interpolation methods are supported as follow: Return the cumulative sum of the elements ([see also](https://numpy.org/doc/stable/reference/generated/numpy.cumsum.html#numpy-cumsum)). +## [Cumprod](./src/cumprod.cairo) + +Return the cumulative product of the elements ([see also](https://numpy.org/doc/stable/reference/generated/numpy.cumprod.html#numpy-cumprod)). + ## [Diff](./src/diff.cairo) Return the discrete difference of the elements ([see also](https://numpy.org/doc/stable/reference/generated/numpy.diff.html#numpy.diff)). diff --git a/src/numeric/src/cumprod.cairo b/src/numeric/src/cumprod.cairo new file mode 100644 index 00000000..656a503e --- /dev/null +++ b/src/numeric/src/cumprod.cairo @@ -0,0 +1,27 @@ +//! The cumulative product of the elements. + +/// Compute the cumulative product of a sequence. +/// # Arguments +/// * `sequence` - The sequence to operate. +/// # Returns +/// * `Array` - The cumulative product of sequence. +fn cumprod, +Copy, +Drop,>(mut sequence: Span) -> Array { + // [Check] Inputs + assert(sequence.len() >= 1, 'Array must have at least 1 elt'); + + // [Compute] Interpolation + let mut array = array![]; + let mut prev_value = *sequence.pop_front().unwrap(); + array.append(prev_value); + loop { + match sequence.pop_front() { + Option::Some(current_value) => { + let prod = *current_value * prev_value; + array.append(prod); + prev_value = prod; + }, + Option::None => { break; }, + }; + }; + array +} diff --git a/src/numeric/src/lib.cairo b/src/numeric/src/lib.cairo index 5ff687ad..e9585afb 100644 --- a/src/numeric/src/lib.cairo +++ b/src/numeric/src/lib.cairo @@ -1,3 +1,4 @@ +mod cumprod; mod cumsum; mod diff; mod integers; diff --git a/src/numeric/src/tests.cairo b/src/numeric/src/tests.cairo index b914422b..65219c6f 100644 --- a/src/numeric/src/tests.cairo +++ b/src/numeric/src/tests.cairo @@ -1,3 +1,4 @@ +mod cumprod_test; mod cumsum_test; mod diff_test; mod integers_test; diff --git a/src/numeric/src/tests/cumprod_test.cairo b/src/numeric/src/tests/cumprod_test.cairo new file mode 100644 index 00000000..fa729c5e --- /dev/null +++ b/src/numeric/src/tests/cumprod_test.cairo @@ -0,0 +1,19 @@ +use alexandria_numeric::cumprod::cumprod; + +#[test] +#[available_gas(2000000)] +fn cumprod_test() { + let xs: Array = array![3, 5, 7]; + let ys = cumprod(xs.span()); + assert(*ys[0] == *xs[0], 'wrong value at index 0'); + assert(*ys[1] == *xs[0] * *xs[1], 'wrong value at index 1'); + assert(*ys[2] == *xs[0] * *xs[1] * *xs[2], 'wrong value at index 2'); +} + +#[test] +#[should_panic(expected: ('Array must have at least 1 elt',))] +#[available_gas(2000000)] +fn cumprod_test_revert_empty() { + let xs: Array = array![]; + let ys = cumprod(xs.span()); +}