1use super::{AbelianGroup, AbelianMonoid, Group, Monoid, RangeBoundsExt};
2use std::{
3 fmt::{self, Debug, Formatter},
4 iter::FromIterator,
5 ops::RangeBounds,
6};
7
8pub struct Accumulate<M>
10where
11 M: Monoid,
12{
13 data: Vec<M::T>,
14}
15
16impl<M> Debug for Accumulate<M>
17where
18 M: Monoid<T: Debug>,
19{
20 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
21 f.debug_struct("Accumulate")
22 .field("data", &self.data)
23 .finish()
24 }
25}
26
27impl<M> FromIterator<M::T> for Accumulate<M>
28where
29 M: Monoid,
30{
31 fn from_iter<T>(iter: T) -> Self
32 where
33 T: IntoIterator<Item = M::T>,
34 {
35 let iter = iter.into_iter();
36 let (lower, _) = iter.size_hint();
37 let mut data = Vec::with_capacity(lower.saturating_add(1));
38 let mut acc = M::unit();
39 for x in iter {
40 let y = M::operate(&acc, &x);
41 data.push(acc);
42 acc = y;
43 }
44 data.push(acc);
45 Self { data }
46 }
47}
48
49impl<M> Accumulate<M>
50where
51 M: Monoid,
52{
53 pub fn from_vec(mut data: Vec<M::T>) -> Self {
54 let mut acc = M::unit();
55 for x in &mut data {
56 let y = M::operate(&acc, x);
57 *x = acc;
58 acc = y;
59 }
60 data.push(acc);
61 Self { data }
62 }
63
64 pub fn accumulate(&self, k: usize) -> M::T {
66 assert!(
67 k < self.data.len(),
68 "index out of range: the len is {} but the index is {}",
69 self.data.len(),
70 k
71 );
72 unsafe { self.data.get_unchecked(k) }.clone()
73 }
74}
75
76impl<M> Accumulate<M>
77where
78 M: Group,
79{
80 pub fn fold<R>(&self, range: R) -> M::T
82 where
83 R: RangeBounds<usize>,
84 {
85 let n = self.data.len() - 1;
86 let range = range.to_range_bounded(0, n).expect("invalid range");
87 let (l, r) = (range.start, range.end);
88 assert!(l <= r, "bad range [{}, {})", l, r);
89 M::operate(&M::inverse(unsafe { self.data.get_unchecked(l) }), unsafe {
90 self.data.get_unchecked(r)
91 })
92 }
93}
94
95pub struct Accumulate2d<M>
97where
98 M: AbelianMonoid,
99{
100 h: usize,
101 w: usize,
102 data: Vec<M::T>,
103}
104
105impl<M> Debug for Accumulate2d<M>
106where
107 M: AbelianMonoid<T: Debug>,
108{
109 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
110 f.debug_struct("Accumulate2d")
111 .field("h", &self.h)
112 .field("w", &self.w)
113 .field("data", &self.data)
114 .finish()
115 }
116}
117
118impl<M> Accumulate2d<M>
119where
120 M: AbelianMonoid,
121{
122 pub fn new(arr2d: &[Vec<M::T>]) -> Self {
123 let h = arr2d.len();
124 assert!(h > 0);
125 let w = arr2d[0].len();
126 assert!(w > 0);
127 let w1 = w + 1;
128 let mut data = Vec::with_capacity((h + 1) * w1);
129 data.resize_with(w1, M::unit);
130 for (i, arr) in arr2d.iter().enumerate() {
131 assert_eq!(w, arr.len(), "expected 2d array");
132 let mut acc = M::unit();
133 for (j, x) in arr.iter().enumerate() {
134 let y = M::operate(&acc, x);
135 data.push(M::operate(&acc, unsafe { data.get_unchecked(w1 * i + j) }));
136 acc = y;
137 }
138 data.push(M::operate(&acc, unsafe { data.get_unchecked(w1 * i + w) }));
139 }
140 Self { h, w, data }
141 }
142 pub fn from_fn<F>(h: usize, w: usize, mut f: F) -> Self
143 where
144 F: FnMut(usize, usize) -> M::T,
145 {
146 let w1 = w + 1;
147 let mut data = Vec::with_capacity((h + 1) * w1);
148 data.resize_with(w1, M::unit);
149 for i in 0..h {
150 let mut acc = M::unit();
151 for j in 0..w {
152 let y = M::operate(&acc, &f(i, j));
153 data.push(M::operate(&acc, unsafe { data.get_unchecked(w1 * i + j) }));
154 acc = y;
155 }
156 data.push(M::operate(&acc, unsafe { data.get_unchecked(w1 * i + w) }));
157 }
158 Self { h, w, data }
159 }
160 pub fn accumulate(&self, x: usize, y: usize) -> M::T {
162 let h1 = self.h + 1;
163 let w1 = self.w + 1;
164 assert!(
165 x < h1,
166 "index out of range: the first len is {} but the index is {}",
167 h1,
168 x
169 );
170 assert!(
171 y < w1,
172 "index out of range: the second len is {} but the index is {}",
173 w1,
174 y
175 );
176 unsafe { self.data.get_unchecked(w1 * x + y) }.clone()
177 }
178}
179
180impl<M> Accumulate2d<M>
181where
182 M: AbelianGroup,
183{
184 pub fn fold<R0, R1>(&self, range0: R0, range1: R1) -> M::T
186 where
187 R0: RangeBounds<usize>,
188 R1: RangeBounds<usize>,
189 {
190 let range0 = range0.to_range_bounded(0, self.h).expect("invalid range");
191 let range1 = range1.to_range_bounded(0, self.w).expect("invalid range");
192 let (xl, xr) = (range0.start, range0.end);
193 let (yl, yr) = (range1.start, range1.end);
194 assert!(xl <= xr, "bad range [{}, {})", xl, xr);
195 assert!(yl <= yr, "bad range [{}, {})", yl, yr);
196 let w1 = self.w + 1;
197 unsafe {
198 M::rinv_operate(
199 &M::operate(
200 self.data.get_unchecked(w1 * xl + yl),
201 self.data.get_unchecked(w1 * xr + yr),
202 ),
203 &M::operate(
204 self.data.get_unchecked(w1 * xl + yr),
205 self.data.get_unchecked(w1 * xr + yl),
206 ),
207 )
208 }
209 }
210}
211
212pub struct AccumulateKd<const K: usize, M>
213where
214 M: AbelianMonoid,
215{
216 dim: [usize; K],
217 offset: [usize; K],
218 data: Vec<M::T>,
219}
220
221impl<const K: usize, M> Debug for AccumulateKd<K, M>
222where
223 M: AbelianMonoid<T: Debug>,
224{
225 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
226 f.debug_struct("AccumulateKd")
227 .field("dim", &self.dim)
228 .field("offset", &self.offset)
229 .field("data", &self.data)
230 .finish()
231 }
232}
233
234impl<const K: usize, M> AccumulateKd<K, M>
235where
236 M: AbelianMonoid,
237{
238 pub fn from_fn(dim: [usize; K], mut f: impl FnMut([usize; K]) -> M::T) -> Self {
239 fn fill<const K: usize, T>(
240 dim: &[usize; K],
241 offset: &[usize; K],
242 data: &mut [T],
243 f: &mut impl FnMut([usize; K]) -> T,
244 mut index: [usize; K],
245 pos: usize,
246 ) {
247 if pos < K {
248 for i in 0..dim[pos] {
249 index[pos] = i;
250 fill(dim, offset, data, f, index, pos + 1);
251 }
252 } else {
253 let i: usize = index.iter().zip(offset).map(|(x, y)| (x + 1) * y).sum();
254 data[i] = f(index);
255 }
256 }
257
258 let mut offset = [1; K];
259 for d in (1..K).rev() {
260 offset[d - 1] = offset[d] * (dim[d] + 1);
261 }
262 let size = offset[0] * (dim[0] + 1);
263 let mut data = vec![M::unit(); size];
264 fill(&dim, &offset, &mut data, &mut f, [0; K], 0);
265 for d in 0..K {
266 for i in 1..size {
267 if i / offset[d] % (dim[d] + 1) != 0 {
268 data[i] = M::operate(&data[i], &data[i - offset[d]]);
269 }
270 }
271 }
272 Self { dim, offset, data }
273 }
274 pub fn accumulate(&self, x: [usize; K]) -> M::T {
275 for (d, x) in x.into_iter().enumerate() {
276 assert!(
277 x <= self.dim[d],
278 "index out of range: the len is {} but the index is {}",
279 self.dim[d] + 1,
280 x
281 );
282 }
283 let p: usize = x.iter().zip(&self.offset).map(|(x, y)| x * y).sum();
284 unsafe { self.data.get_unchecked(p) }.clone()
285 }
286}
287
288impl<const K: usize, M> AccumulateKd<K, M>
289where
290 M: AbelianGroup,
291{
292 pub fn fold<R>(&self, ranges: [R; K]) -> M::T
293 where
294 R: RangeBounds<usize>,
295 {
296 let ranges: [_; K] = std::array::from_fn(|i| {
297 let range = ranges[i]
298 .to_range_bounded(0, self.dim[i])
299 .expect("invalid range");
300 let (l, r) = (range.start, range.end);
301 assert!(l <= r, "bad range [{}, {})", l, r);
302 [l, r]
303 });
304 let mut p: usize = ranges
305 .iter()
306 .zip(&self.offset)
307 .map(|(range, offset)| range[1] * offset)
308 .sum();
309 let delta: [_; K] = std::array::from_fn(|d| (ranges[d][1] - ranges[d][0]) * self.offset[d]);
310 let mut acc = M::unit();
311 let len = 1usize << K;
312 let mut gray = 0usize;
313 let mut inv = false;
314 for i in 0..len {
315 if inv {
316 acc = M::rinv_operate(&acc, unsafe { self.data.get_unchecked(p) });
317 } else {
318 acc = M::operate(&acc, unsafe { self.data.get_unchecked(p) });
319 }
320 if i + 1 < len {
321 let next_gray = (i + 1) ^ ((i + 1) >> 1);
322 let changed = gray ^ next_gray;
323 let d = changed.trailing_zeros() as usize;
324 if (next_gray >> d) & 1 == 1 {
325 p -= delta[d];
326 } else {
327 p += delta[d];
328 }
329 gray = next_gray;
330 inv = !inv;
331 }
332 }
333 acc
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340 use crate::{
341 algebra::{AdditiveOperation, LinearOperation, Magma, Unital},
342 num::mint_basic::MInt1000000007,
343 rand,
344 tools::Xorshift,
345 };
346 type M = LinearOperation<MInt1000000007>;
347 type A = AdditiveOperation<MInt1000000007>;
348
349 #[test]
350 fn test_accumlate() {
351 let mut rng = Xorshift::default();
352 const Q: usize = 1_000;
353 const N: usize = 50;
354 for n in 0..Q {
355 let n = n % N;
356 rand!(rng, v: [(.., ..); n], t: 0..2);
357 let acc: Accumulate<M> = if t == 0 {
358 v.iter().cloned().collect()
359 } else {
360 Accumulate::from_vec(v.clone())
361 };
362 for r in 0..=n {
363 assert_eq!(
364 v[..r].iter().fold(M::unit(), |x, y| M::operate(&x, y)),
365 acc.accumulate(r)
366 );
367 for l in 0..=r {
368 assert_eq!(
369 v[l..r].iter().fold(M::unit(), |x, y| M::operate(&x, y)),
370 acc.fold(l..r)
371 );
372 }
373 }
374 }
375 }
376
377 #[test]
378 fn test_accumlate2d() {
379 let mut rng = Xorshift::default();
380 const Q: usize = 1_000;
381 const N: usize = 10;
382 for i in 0..Q {
383 let h = i % N + 1;
384 let w = i / N % N + 1;
385 rand!(rng, v: [[..; w]; h]);
386 let acc2d = Accumulate2d::<A>::new(&v);
387 for xr in 0..=h {
388 for yr in 0..=w {
389 assert_eq!(
390 v[..xr]
391 .iter()
392 .flat_map(|v| v[..yr].iter())
393 .fold(A::unit(), |x, y| A::operate(&x, y)),
394 acc2d.accumulate(xr, yr)
395 );
396 for xl in 0..=xr {
397 for yl in 0..=yr {
398 assert_eq!(
399 v[xl..xr]
400 .iter()
401 .flat_map(|v| v[yl..yr].iter())
402 .fold(A::unit(), |x, y| A::operate(&x, y)),
403 acc2d.fold(xl..xr, yl..yr)
404 );
405 }
406 }
407 }
408 }
409 }
410 }
411
412 #[test]
413 fn test_accumlate2d_from_fn() {
414 let mut rng = Xorshift::default();
415 const Q: usize = 1_000;
416 const N: usize = 10;
417 for i in 0..Q {
418 let h = i % N;
419 let w = i / N % N;
420 rand!(rng, v: [[..; w]; h]);
421 let acc2d = Accumulate2d::<A>::from_fn(h, w, |i, j| v[i][j]);
422 for xr in 0..=h {
423 for yr in 0..=w {
424 assert_eq!(
425 v[..xr]
426 .iter()
427 .flat_map(|v| v[..yr].iter())
428 .fold(A::unit(), |x, y| A::operate(&x, y)),
429 acc2d.accumulate(xr, yr)
430 );
431 for xl in 0..=xr {
432 for yl in 0..=yr {
433 assert_eq!(
434 v[xl..xr]
435 .iter()
436 .flat_map(|v| v[yl..yr].iter())
437 .fold(A::unit(), |x, y| A::operate(&x, y)),
438 acc2d.fold(xl..xr, yl..yr)
439 );
440 }
441 }
442 }
443 }
444 }
445 }
446
447 #[test]
448 fn test_accumlatekd_from_fn_3d() {
449 let mut rng = Xorshift::default();
450 const N: usize = 5;
451 for i in 0..N * N * N {
452 let dim = [i % N, i / N % N, i / N / N % N];
453 rand!(rng, v: [[[..; dim[2]]; dim[1]]; dim[0]]);
454 let acc = AccumulateKd::<3, A>::from_fn(dim, |[i, j, k]| v[i][j][k]);
455 for xr in 0..=dim[0] {
456 for yr in 0..=dim[1] {
457 for zr in 0..=dim[2] {
458 assert_eq!(
459 v[..xr]
460 .iter()
461 .flat_map(|v| v[..yr].iter().flat_map(|v| v[..zr].iter()))
462 .fold(A::unit(), |x, y| A::operate(&x, y)),
463 acc.accumulate([xr, yr, zr])
464 );
465 for xl in 0..=xr {
466 for yl in 0..=yr {
467 for zl in 0..=zr {
468 assert_eq!(
469 v[xl..xr]
470 .iter()
471 .flat_map(|v| v[yl..yr]
472 .iter()
473 .flat_map(|v| v[zl..zr].iter()))
474 .fold(A::unit(), |x, y| A::operate(&x, y)),
475 acc.fold([xl..xr, yl..yr, zl..zr])
476 );
477 }
478 }
479 }
480 }
481 }
482 }
483 }
484 }
485
486 #[test]
487 fn test_accumlatekd_from_fn_4d() {
488 let mut rng = Xorshift::default();
489 const N: usize = 4;
490 for i in 0..N * N * N * N {
491 let dim = [i % N, i / N % N, i / N / N % N, i / N / N / N % N];
492 rand!(rng, v: [[[[..; dim[3]]; dim[2]]; dim[1]]; dim[0]]);
493 let acc = AccumulateKd::<4, A>::from_fn(dim, |[i, j, k, l]| v[i][j][k][l]);
494 for xr in 0..=dim[0] {
495 for yr in 0..=dim[1] {
496 for zr in 0..=dim[2] {
497 for wr in 0..=dim[3] {
498 assert_eq!(
499 v[..xr]
500 .iter()
501 .flat_map(|v| v[..yr]
502 .iter()
503 .flat_map(|v| v[..zr].iter().flat_map(|v| v[..wr].iter())))
504 .fold(A::unit(), |x, y| A::operate(&x, y)),
505 acc.accumulate([xr, yr, zr, wr])
506 );
507 for xl in 0..=xr {
508 for yl in 0..=yr {
509 for zl in 0..=zr {
510 for wl in 0..=wr {
511 assert_eq!(
512 v[xl..xr]
513 .iter()
514 .flat_map(|v| v[yl..yr]
515 .iter()
516 .flat_map(|v| v[zl..zr]
517 .iter()
518 .flat_map(|v| v[wl..wr].iter())))
519 .fold(A::unit(), |x, y| A::operate(&x, y)),
520 acc.fold([xl..xr, yl..yr, zl..zr, wl..wr])
521 );
522 }
523 }
524 }
525 }
526 }
527 }
528 }
529 }
530 }
531 }
532}