Skip to content

Commit b5d16b4

Browse files
committed
[WIP] Add document for convolution
1 parent a8c306d commit b5d16b4

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

src/convolution.rs

+154
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
//! Functions that calculate $(+, \times)$ convolution.
2+
//!
3+
//! Given two non-empty sequences $a_0, a_1, \ldots, a_{N - 1}$ and $b_0, b_1, \ldots, b_{M - 1}$, they calculate the sequence $c$ of length $N + M - 1$ defined by
4+
//!
5+
//! \\[
6+
//! c_i = \sum_ {j = 0}^i a_j b_{i - j}
7+
//! \\]
8+
//!
9+
//! # Major changes from the original ACL
10+
//!
11+
//! - Separated the overloaded `convolution` into `convolution<_>` and `convolution_raw<_, _>`.
12+
//! - Renamed `convolution_ll` to `convolution_i64`.
13+
114
macro_rules! modulus {
215
($($name:ident),*) => {
316
$(
@@ -29,6 +42,54 @@ use std::{
2942
fmt,
3043
};
3144

45+
/// Calculates the $(+, \times)$ convolution in $\mathbb{Z}/p\mathbb{Z}$.
46+
///
47+
/// See the [module-level documentation] for more details.
48+
///
49+
/// Returns a empty `Vec` if `a` or `b` is empty.
50+
///
51+
/// # Constraints
52+
///
53+
/// - $2 \leq m \leq 2 \times 10^9$
54+
/// - $m$ is a prime number.
55+
/// - $\exists c \text{ s.t. } 2^c \mid (m - 1), |a| + |b| - 1 \leq 2^c$
56+
///
57+
/// where $m$ is `M::VALUE`.
58+
///
59+
/// # Complexity
60+
///
61+
/// - $O(n \log n + \log m)$ where $n = |a| + |b|$.
62+
///
63+
/// # Example
64+
///
65+
/// ```
66+
/// use ac_library_rs::ModInt1000000007 as Mint;
67+
/// use proconio::{input, source::once::OnceSource};
68+
///
69+
/// input! {
70+
/// from OnceSource::from(
71+
/// "3\n\
72+
/// 1 2 3\n\
73+
/// 3\n\
74+
/// -1 -2 -3\n",
75+
/// ),
76+
/// a: [Mint],
77+
/// b: [Mint],
78+
/// }
79+
///
80+
/// assert_eq!(
81+
/// ac_library_rs::convolution(&a, &b),
82+
/// [
83+
/// Mint::new(-1),
84+
/// Mint::new(-4),
85+
/// Mint::new(-10),
86+
/// Mint::new(-12),
87+
/// Mint::new(-9),
88+
/// ],
89+
/// );
90+
/// ```
91+
///
92+
/// [module-level documentation]: ./index.html
3293
#[allow(clippy::many_single_char_names)]
3394
pub fn convolution<M>(a: &[StaticModInt<M>], b: &[StaticModInt<M>]) -> Vec<StaticModInt<M>>
3495
where
@@ -68,6 +129,61 @@ where
68129
a
69130
}
70131

132+
/// Calculates the $(+, \times)$ convolution in $\mathbb{Z}/p\mathbb{Z}$.
133+
///
134+
/// See the [module-level documentation] for more details.
135+
///
136+
/// Returns a empty `Vec` if `a` or `b` is empty.
137+
///
138+
/// # Constraints
139+
///
140+
/// - $2 \leq m \leq 2 \times 10^9$
141+
/// - $m$ is a prime number.
142+
/// - $\exists c \text{ s.t. } 2^c \mid (m - 1), |a| + |b| - 1 \leq 2^c$
143+
/// - $(0, m] \subseteq$ `T`
144+
///
145+
/// where $m$ is `M::VALUE`.
146+
///
147+
/// # Complexity
148+
///
149+
/// - $O(n \log n + \log m)$ where $n = |a| + |b|$.
150+
///
151+
/// # Panics
152+
///
153+
/// Panics if any element of the result ($\in [0,$ `M::VALUE`$)$) is outside of the range of `T`.
154+
///
155+
/// # Example
156+
///
157+
/// ```
158+
/// use ac_library_rs::{Mod1000000007 as M, Modulus as _};
159+
/// use proconio::{input, source::once::OnceSource};
160+
///
161+
/// const M: i32 = M::VALUE as _;
162+
///
163+
/// input! {
164+
/// from OnceSource::from(
165+
/// "3\n\
166+
/// 1 2 3\n\
167+
/// 3\n\
168+
/// -1 -2 -3\n",
169+
/// ),
170+
/// a: [i32],
171+
/// b: [i32],
172+
/// }
173+
///
174+
/// assert_eq!(
175+
/// ac_library_rs::convolution::convolution_raw::<_, M>(&a, &b),
176+
/// [
177+
/// (-1i32).rem_euclid(M),
178+
/// (-4i32).rem_euclid(M),
179+
/// (-10i32).rem_euclid(M),
180+
/// (-12i32).rem_euclid(M),
181+
/// (-9i32).rem_euclid(M),
182+
/// ],
183+
/// );
184+
/// ```
185+
///
186+
/// [module-level documentation]: ./index.html
71187
pub fn convolution_raw<T, M>(a: &[T], b: &[T]) -> Vec<T>
72188
where
73189
T: RemEuclidU32 + TryFrom<u32> + Clone,
@@ -86,6 +202,44 @@ where
86202
.collect()
87203
}
88204

205+
/// Calculates the $(+, \times)$ convolution in `i64`.
206+
///
207+
/// See the [module-level documentation] for more details.
208+
///
209+
/// Returns a empty `Vec` if `a` or `b` is empty.
210+
///
211+
/// # Constraints
212+
///
213+
/// - $|a| + |b| - 1 \leq 2^{24}$
214+
/// - All elements of the result are inside of the range of `i64`
215+
///
216+
/// # Complexity
217+
///
218+
/// - $O(n \log n)$ where $n = |a| + |b|$.
219+
///
220+
/// # Example
221+
///
222+
/// ```
223+
/// use proconio::{input, source::once::OnceSource};
224+
///
225+
/// input! {
226+
/// from OnceSource::from(
227+
/// "3\n\
228+
/// 1 2 3\n\
229+
/// 3\n\
230+
/// -1 -2 -3\n",
231+
/// ),
232+
/// a: [i64],
233+
/// b: [i64],
234+
/// }
235+
///
236+
/// assert_eq!(
237+
/// ac_library_rs::convolution_i64(&a, &b),
238+
/// [-1, -4, -10, -12, -9],
239+
/// );
240+
/// ```
241+
///
242+
/// [module-level documentation]: ./index.html
89243
#[allow(clippy::many_single_char_names)]
90244
pub fn convolution_i64(a: &[i64], b: &[i64]) -> Vec<i64> {
91245
const M1: u64 = 754_974_721; // 2^24

0 commit comments

Comments
 (0)