Content-Length: 742713 | pFad | http://github.com/EbTech/rust-algorithms/commit/1d345542b51e38d9ebe39bf52c855df8ec2929f8

AE v0.3 with const generics · EbTech/rust-algorithms@1d34554 · GitHub
Skip to content

Commit 1d34554

Browse files
committed
v0.3 with const generics
1 parent a2d9598 commit 1d34554

File tree

5 files changed

+45
-43
lines changed

5 files changed

+45
-43
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: rust
22
rust:
3-
#- 1.51.0 # Version currently supported by Codeforces
3+
- 1.51.0 # Version currently supported by Codeforces
44
- stable
55
- beta
66
- nightly

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "contest-algorithms"
3-
version = "0.2.1"
3+
version = "0.3.0"
44
authors = ["Aram Ebtekar"]
55
edition = "2018"
66

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ For help in getting started, you may check out [some of my past submissions](htt
4343

4444
My other goal is to appeal to developers who feel limited by ancient (yet still mainstream) programming languages, by demonstrating the power of modern techniques.
4545

46-
Rather than try to persuade you with words, this repository aims to show by example. If you're new to Rust, see [Jim Blandy's *Why Rust?*](http://www.oreilly.com/programming/free/files/why-rust.pdf) for a brief introduction, or just [dive in!](https://doc.rust-lang.org/book/)
46+
Rather than try to persuade you with words, this repository aims to show by example. If you'd like to learn the language, I recommend [the official book](https://doc.rust-lang.org/book/) or [Programming Rust](https://www.amazon.com/Programming-Rust-Fast-Systems-Development-dp-1492052590/dp/1492052590).
4747

4848
# Contents
4949

src/math/fft.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! The Fast Fourier Transform (FFT) and Number Theoretic Transform (NTT)
2-
use super::num::{Complex, Field, PI};
2+
use super::num::{CommonField, Complex, PI};
33
use std::ops::{Add, Div, Mul, Neg, Sub};
44

55
// We can delete this struct once f64::reverse_bits() stabilizes.
@@ -30,6 +30,7 @@ impl Iterator for BitRevIterator {
3030
}
3131
}
3232

33+
#[allow(clippy::upper_case_acronyms)]
3334
pub trait FFT: Sized + Copy {
3435
type F: Sized
3536
+ Copy
@@ -77,7 +78,7 @@ impl FFT for f64 {
7778
// 440564289 and 1713844692 are inverses and 2^27th roots of 1 mod (15<<27)+1
7879
// 125 and 2267742733 are inverses and 2^30th roots of 1 mod (3<<30)+1
7980
impl FFT for i64 {
80-
type F = Field;
81+
type F = CommonField;
8182

8283
const ZERO: Self = 0;
8384

@@ -197,9 +198,9 @@ mod test {
197198
let dft_v = dft_from_reals(&v, v.len());
198199
let new_v: Vec<i64> = idft_to_reals(&dft_v, v.len());
199200

200-
let seven = Field::from(7);
201-
let one = Field::from(1);
202-
let prim = Field::from(15_311_432).pow(1 << 21);
201+
let seven = CommonField::from(7);
202+
let one = CommonField::from(1);
203+
let prim = CommonField::from(15_311_432).pow(1 << 21);
203204
let prim2 = prim * prim;
204205

205206
let eval0 = seven + one + one;
@@ -230,6 +231,6 @@ mod test {
230231
let m = convolution(&vec![999], &vec![1_000_000]);
231232

232233
assert_eq!(z, vec![14, 30, 6, 4]);
233-
assert_eq!(m, vec![999_000_000 - Field::MOD]);
234+
assert_eq!(m, vec![999_000_000 - super::super::num::COMMON_PRIME]);
234235
}
235236
}

src/math/num.rs

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -165,87 +165,88 @@ impl Div for Complex {
165165
}
166166
}
167167

168-
//github.com/ Represents an element of the finite (Galois) field of prime order, given by
169-
//github.com/ MOD. Until Rust gets const generics, MOD must be hardcoded, but any prime in
170-
//github.com/ [1, 2^31.5] will work. If MOD is not prime, ring operations are still valid
168+
//github.com/ Represents an element of the finite (Galois) field of prime order M, where
169+
//github.com/ 1 <= M < 2^31.5. If M is not prime, ring operations are still valid
171170
//github.com/ but recip() and division are not. Note that the latter operations are also
172171
//github.com/ the slowest, so precompute any inverses that you intend to use frequently.
173172
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
174-
pub struct Field {
173+
pub struct Modulo<const M: i64> {
175174
pub val: i64,
176175
}
177-
impl Field {
178-
pub const MOD: i64 = 998_244_353; // 2^23 * 7 * 17 + 1
179-
180-
//github.com/ Computes self^exp in O(log(exp)) time
181-
pub fn pow(mut self, mut exp: u64) -> Self {
176+
impl<const M: i64> Modulo<M> {
177+
//github.com/ Computes self^n in O(log n) time
178+
pub fn pow(mut self, mut n: u64) -> Self {
182179
let mut result = Self::from_small(1);
183-
while exp > 0 {
184-
if exp % 2 == 1 {
180+
while n > 0 {
181+
if n % 2 == 1 {
185182
result = result * self;
186183
}
187184
self = self * self;
188-
exp /= 2;
185+
n /= 2;
189186
}
190187
result
191188
}
192189
//github.com/ Computes inverses of 1 to n in O(n) time
193190
pub fn vec_of_recips(n: i64) -> Vec<Self> {
194191
let mut recips = vec![Self::from(0), Self::from(1)];
195192
for i in 2..=n {
196-
let (md, dv) = (Self::MOD % i, Self::MOD / i);
193+
let (md, dv) = (M % i, M / i);
197194
recips.push(recips[md as usize] * Self::from_small(-dv));
198195
}
199196
recips
200197
}
201-
//github.com/ Computes self^-1 in O(log(Self::MOD)) time
198+
//github.com/ Computes self^-1 in O(log M) time
202199
pub fn recip(self) -> Self {
203-
self.pow(Self::MOD as u64 - 2)
200+
self.pow(M as u64 - 2)
204201
}
205-
//github.com/ Avoids the % operation but requires -Self::MOD <= x < Self::MOD
202+
//github.com/ Avoids the % operation but requires -M <= x < M
206203
fn from_small(s: i64) -> Self {
207-
let val = if s < 0 { s + Self::MOD } else { s };
204+
let val = if s < 0 { s + M } else { s };
208205
Self { val }
209206
}
210207
}
211-
impl From<i64> for Field {
208+
impl<const M: i64> From<i64> for Modulo<M> {
212209
fn from(val: i64) -> Self {
213-
// Self { val: val.rem_euclid(Self::MOD) }
214-
Self::from_small(val % Self::MOD)
210+
// Self { val: val.rem_euclid(M) }
211+
Self::from_small(val % M)
215212
}
216213
}
217-
impl Neg for Field {
214+
impl<const M: i64> Neg for Modulo<M> {
218215
type Output = Self;
219216
fn neg(self) -> Self {
220217
Self::from_small(-self.val)
221218
}
222219
}
223-
impl Add for Field {
220+
impl<const M: i64> Add for Modulo<M> {
224221
type Output = Self;
225222
fn add(self, other: Self) -> Self {
226-
Self::from_small(self.val + other.val - Self::MOD)
223+
Self::from_small(self.val + other.val - M)
227224
}
228225
}
229-
impl Sub for Field {
226+
impl<const M: i64> Sub for Modulo<M> {
230227
type Output = Self;
231228
fn sub(self, other: Self) -> Self {
232229
Self::from_small(self.val - other.val)
233230
}
234231
}
235-
impl Mul for Field {
232+
impl<const M: i64> Mul for Modulo<M> {
236233
type Output = Self;
237234
fn mul(self, other: Self) -> Self {
238235
Self::from(self.val * other.val)
239236
}
240237
}
241238
#[allow(clippy::suspicious_arithmetic_impl)]
242-
impl Div for Field {
239+
impl<const M: i64> Div for Modulo<M> {
243240
type Output = Self;
244241
fn div(self, other: Self) -> Self {
245242
self * other.recip()
246243
}
247244
}
248245

246+
//github.com/ Prime modulus that's commonly used in programming competitions
247+
pub const COMMON_PRIME: i64 = 998_244_353; // 2^23 * 7 * 17 + 1;
248+
pub type CommonField = Modulo<COMMON_PRIME>;
249+
249250
#[derive(Clone, PartialEq, Debug)]
250251
pub struct Matrix {
251252
cols: usize,
@@ -268,15 +269,15 @@ impl Matrix {
268269
let inner = vec.to_vec().into_boxed_slice();
269270
Self { cols, inner }
270271
}
271-
pub fn pow(&self, mut exp: u64) -> Self {
272+
pub fn pow(&self, mut n: u64) -> Self {
272273
let mut base = self.clone();
273274
let mut result = Self::one(self.cols);
274-
while exp > 0 {
275-
if exp % 2 == 1 {
275+
while n > 0 {
276+
if n % 2 == 1 {
276277
result = &result * &base;
277278
}
278279
base = &base * &base;
279-
exp /= 2;
280+
n /= 2;
280281
}
281282
result
282283
}
@@ -417,10 +418,10 @@ mod test {
417418

418419
#[test]
419420
fn test_field() {
420-
let base = Field::from(1234);
421+
let base = CommonField::from(1234);
421422
let zero = base - base;
422423
let one = base.recip() * base;
423-
let two = Field::from(2 - 5 * Field::MOD);
424+
let two = CommonField::from(2 - 5 * COMMON_PRIME);
424425

425426
assert_eq!(zero.val, 0);
426427
assert_eq!(one.val, 1);
@@ -430,11 +431,11 @@ mod test {
430431

431432
#[test]
432433
fn test_vec_of_recips() {
433-
let recips = Field::vec_of_recips(20);
434+
let recips = CommonField::vec_of_recips(20);
434435

435436
assert_eq!(recips.len(), 21);
436437
for i in 1..recips.len() {
437-
assert_eq!(recips[i], Field::from(i as i64).recip());
438+
assert_eq!(recips[i], CommonField::from(i as i64).recip());
438439
}
439440
}
440441

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/EbTech/rust-algorithms/commit/1d345542b51e38d9ebe39bf52c855df8ec2929f8

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy