#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum MigrationTopology {
#[default]
Ring,
FullyConnected,
Grid(usize, usize),
Hypercube,
Custom(Vec<Vec<usize>>),
}
pub fn neighbors(
island_index: usize,
num_islands: usize,
topology: &MigrationTopology,
) -> Vec<usize> {
if num_islands <= 1 {
return vec![];
}
match topology {
MigrationTopology::Ring => {
vec![(island_index + 1) % num_islands]
}
MigrationTopology::FullyConnected => {
(0..num_islands).filter(|&i| i != island_index).collect()
}
MigrationTopology::Grid(rows, cols) => grid_neighbors(island_index, *rows, *cols),
MigrationTopology::Hypercube => hypercube_neighbors(island_index, num_islands),
MigrationTopology::Custom(adjacency) => {
adjacency.get(island_index).cloned().unwrap_or_default()
}
}
}
fn grid_neighbors(index: usize, rows: usize, cols: usize) -> Vec<usize> {
let row = index / cols;
let col = index % cols;
let mut result = Vec::with_capacity(4);
if row > 0 {
result.push((row - 1) * cols + col);
}
if row + 1 < rows {
result.push((row + 1) * cols + col);
}
if col > 0 {
result.push(row * cols + (col - 1));
}
if col + 1 < cols {
result.push(row * cols + (col + 1));
}
result
}
fn hypercube_neighbors(index: usize, num_islands: usize) -> Vec<usize> {
let mut result = Vec::new();
let bits = (num_islands as f64).log2().ceil() as u32;
for bit in 0..bits {
let neighbor = index ^ (1 << bit);
if neighbor < num_islands {
result.push(neighbor);
}
}
result
}