Skip to content

Commit 641d9a4

Browse files
committed
consider moving several segments at a time
1 parent c296ac7 commit 641d9a4

File tree

1 file changed

+91
-10
lines changed

1 file changed

+91
-10
lines changed

src/cartesian/mod.rs

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use rayon::iter::IndexedParallelIterator;
66
use rayon::iter::IntoParallelRefIterator;
77
use rayon::iter::IntoParallelRefMutIterator;
88
use rayon::iter::ParallelIterator;
9+
use std::collections::BTreeMap;
910
use std::collections::HashMap;
11+
use std::collections::VecDeque;
1012
use std::fmt;
1113
use std::iter::Sum;
1214
use std::marker::PhantomData;
@@ -179,7 +181,7 @@ impl Grid<2> {
179181
let segs = iters.segments_2d(self, 1);
180182

181183
// Testing horizontal segments for imbalance.
182-
for seg in &segs.c[0] {
184+
for seg in segs.moves(0) {
183185
if seg.at != 0 {
184186
// Test if we can move segment down.
185187
let moved_cells = (seg.start..seg.end).map(|x| [x, seg.at - 1]);
@@ -213,7 +215,7 @@ impl Grid<2> {
213215
}
214216

215217
// Testing vertical segments for imbalance.
216-
for seg in &segs.c[1] {
218+
for seg in segs.moves(1) {
217219
if seg.at != 0 {
218220
// Test if we can move segment left.
219221
let moved_cells = (seg.start..seg.end).map(|y| [seg.at - 1, y]);
@@ -247,7 +249,7 @@ impl Grid<2> {
247249
}
248250

249251
// Testing horizontal segments for lambda cut.
250-
for seg in &segs.c[0] {
252+
for seg in segs.moves(0) {
251253
if seg.at >= 2 {
252254
// Test if we can move segment down.
253255
let a = (seg.start..seg.end).map(|x| [x, seg.at]);
@@ -275,7 +277,7 @@ impl Grid<2> {
275277
}
276278

277279
// Testing vertical segments for lambda cut.
278-
for seg in &segs.c[1] {
280+
for seg in segs.moves(1) {
279281
if seg.at >= 2 {
280282
// Test if we can move segment down.
281283
let a = (seg.start..seg.end).map(|y| [seg.at, y]);
@@ -631,7 +633,7 @@ impl SplitTree {
631633
}
632634
}
633635

634-
#[derive(Debug)]
636+
#[derive(Clone, Debug)]
635637
pub struct Segment {
636638
start: usize,
637639
end: usize,
@@ -656,6 +658,22 @@ impl Segment {
656658
},
657659
))
658660
}
661+
662+
pub fn p_start_2d(&self, coord: usize) -> [usize; 2] {
663+
if coord == 0 {
664+
[self.at, self.start]
665+
} else {
666+
[self.start, self.at]
667+
}
668+
}
669+
670+
pub fn p_end_2d(&self, coord: usize) -> [usize; 2] {
671+
if coord == 0 {
672+
[self.at, self.end]
673+
} else {
674+
[self.end, self.at]
675+
}
676+
}
659677
}
660678

661679
#[derive(Debug)]
@@ -664,11 +682,74 @@ pub struct Segments<const D: usize> {
664682
grid: Grid<D>,
665683
}
666684

667-
//impl Segments<2> {
668-
// pub fn moves(&self) -> impl Iterator<Item = Segment> {
669-
// // TODO
670-
// }
671-
//}
685+
impl Segments<2> {
686+
pub fn moves(&self, coord: usize) -> impl IntoIterator<Item = Segment> {
687+
let mut occs: BTreeMap<[usize; 2], Vec<&Segment>> = BTreeMap::new();
688+
689+
for seg in &self.c[coord] {
690+
let p1 = seg.p_start_2d(coord);
691+
let p2 = seg.p_end_2d(coord);
692+
occs.entry(p1).or_default().push(seg);
693+
occs.entry(p2).or_default().push(seg);
694+
}
695+
696+
occs.retain(|_, segs| segs.len() > 1);
697+
698+
let mut moves = self.c[coord].clone();
699+
700+
while let Some((joint, segs)) = occs.pop_first() {
701+
debug_assert_eq!(segs.len(), 2);
702+
let seg1 = segs[0];
703+
let seg2 = segs[1];
704+
705+
let mut multi_seg = VecDeque::new();
706+
707+
if seg1.p_end_2d(coord) == joint {
708+
// seg1 is before seg2
709+
multi_seg.push_back(seg1);
710+
multi_seg.push_back(seg2);
711+
} else {
712+
// seg1 is after seg2
713+
multi_seg.push_back(seg2);
714+
multi_seg.push_back(seg1);
715+
}
716+
717+
loop {
718+
// Add segments to the left of the multi-segment.
719+
let joint = multi_seg.front().unwrap().p_start_2d(coord);
720+
let Some(segs) = occs.remove(&joint) else { break };
721+
let seg = *segs
722+
.iter()
723+
.find(|seg| seg.p_end_2d(coord) == joint)
724+
.unwrap();
725+
multi_seg.push_front(seg);
726+
}
727+
loop {
728+
// Add segments to the right of the multi-segment.
729+
let joint = multi_seg.back().unwrap().p_end_2d(coord);
730+
let Some(segs) = occs.remove(&joint) else { break };
731+
let seg = *segs
732+
.iter()
733+
.find(|seg| seg.p_start_2d(coord) == joint)
734+
.unwrap();
735+
multi_seg.push_back(seg);
736+
}
737+
738+
for i in 0..multi_seg.len() {
739+
// i+1 because "moves" already contains individual segments.
740+
for j in i + 1..multi_seg.len() {
741+
moves.push(Segment {
742+
start: multi_seg[i].start,
743+
end: multi_seg[j].end,
744+
at: multi_seg[i].at,
745+
});
746+
}
747+
}
748+
}
749+
750+
moves
751+
}
752+
}
672753

673754
#[cfg(test)]
674755
mod tests {

0 commit comments

Comments
 (0)