fix(experiment): score occupied perimeter cells including one-column cycles
This commit is contained in:
@@ -54,23 +54,49 @@ fn components(arcs: &[BTreeSet<usize>], work: &mut usize) -> Result<Vec<Vec<usiz
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clockwise perimeter slots. Restrict to near-square physical envelopes when
|
fn perimeter_slots(n: usize, rows: usize, cols: usize) -> Vec<(usize, usize)> {
|
||||||
// possible; minimizing perimeter area without this restriction makes a strip.
|
let mut slots = Vec::new();
|
||||||
|
if rows == 1 {
|
||||||
|
slots.extend((0..cols).map(|col| (col, 0)));
|
||||||
|
} else if cols == 1 {
|
||||||
|
slots.extend((0..rows).map(|row| (0, row)));
|
||||||
|
} else {
|
||||||
|
slots.extend((0..cols).map(|col| (col, 0)));
|
||||||
|
slots.extend((1..rows).map(|row| (cols - 1, row)));
|
||||||
|
slots.extend((0..cols - 1).rev().map(|col| (col, rows - 1)));
|
||||||
|
slots.extend((1..rows - 1).rev().map(|row| (0, row)));
|
||||||
|
}
|
||||||
|
slots.truncate(n);
|
||||||
|
slots
|
||||||
|
}
|
||||||
|
|
||||||
|
// Score occupied maximum-member cells, excluding unused perimeter slots.
|
||||||
|
// Heterogeneous members may occupy less than this nominal cell envelope.
|
||||||
fn perimeter(
|
fn perimeter(
|
||||||
n: usize,
|
n: usize,
|
||||||
cell: Size,
|
cell: Size,
|
||||||
gap: Size,
|
gap: Size,
|
||||||
work: &mut usize,
|
work: &mut usize,
|
||||||
) -> Result<(Vec<Position>, usize, usize), ModelError> {
|
) -> Result<(Vec<Position>, usize, usize), ModelError> {
|
||||||
let mut best: Option<((bool, f32, f32, usize, usize), usize, usize)> = None;
|
type GridScore = (bool, f32, f32, usize, usize);
|
||||||
for rows in 2..=n.max(2) {
|
let mut best: Option<(GridScore, usize, usize)> = None;
|
||||||
for cols in 2..=n.max(2) {
|
for rows in 1..=n {
|
||||||
|
for cols in 1..=n {
|
||||||
charge(work, 1)?;
|
charge(work, 1)?;
|
||||||
if 2 * rows + 2 * cols - 4 < n {
|
let capacity = if rows == 1 || cols == 1 {
|
||||||
|
rows * cols
|
||||||
|
} else {
|
||||||
|
2 * rows + 2 * cols - 4
|
||||||
|
};
|
||||||
|
if capacity < n {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let width = cols as f32 * cell.width + (cols - 1) as f32 * gap.width;
|
charge(work, capacity)?;
|
||||||
let height = rows as f32 * cell.height + (rows - 1) as f32 * gap.height;
|
let slots = perimeter_slots(n, rows, cols);
|
||||||
|
let max_x = slots.iter().map(|p| p.0).max().unwrap();
|
||||||
|
let max_y = slots.iter().map(|p| p.1).max().unwrap();
|
||||||
|
let width = (max_x + 1) as f32 * cell.width + max_x as f32 * gap.width;
|
||||||
|
let height = (max_y + 1) as f32 * cell.height + max_y as f32 * gap.height;
|
||||||
let aspect = (width / height).max(height / width);
|
let aspect = (width / height).max(height / width);
|
||||||
let key = (
|
let key = (
|
||||||
aspect > 2.0,
|
aspect > 2.0,
|
||||||
@@ -89,19 +115,7 @@ fn perimeter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (_, rows, cols) = best.ok_or_else(|| error("no perimeter grid"))?;
|
let (_, rows, cols) = best.ok_or_else(|| error("no perimeter grid"))?;
|
||||||
let mut slots = Vec::new();
|
let slots = perimeter_slots(n, rows, cols);
|
||||||
for col in 0..cols {
|
|
||||||
slots.push((col, 0));
|
|
||||||
}
|
|
||||||
for row in 1..rows {
|
|
||||||
slots.push((cols - 1, row));
|
|
||||||
}
|
|
||||||
for col in (0..cols - 1).rev() {
|
|
||||||
slots.push((col, rows - 1));
|
|
||||||
}
|
|
||||||
for row in (1..rows - 1).rev() {
|
|
||||||
slots.push((0, row));
|
|
||||||
}
|
|
||||||
Ok((
|
Ok((
|
||||||
slots
|
slots
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -548,4 +562,27 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_node_perimeter_scores_occupied_cells_instead_of_an_unused_row() {
|
||||||
|
let (positions, rows, cols) = perimeter(
|
||||||
|
2,
|
||||||
|
Size {
|
||||||
|
width: 224.0,
|
||||||
|
height: 160.0,
|
||||||
|
},
|
||||||
|
Size {
|
||||||
|
width: 250.0,
|
||||||
|
height: 56.0,
|
||||||
|
},
|
||||||
|
&mut 0,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!((rows, cols), (2, 1));
|
||||||
|
assert_eq!(
|
||||||
|
positions,
|
||||||
|
vec![Position { x: 0.0, y: 0.0 }, Position { x: 0.0, y: 216.0 }]
|
||||||
|
);
|
||||||
|
assert!(224.0_f32 / 376.0 > 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user