#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct KOptReconnection {
segment_order: [u8; 6],
reverse_mask: u8,
len: u8,
}
impl KOptReconnection {
#[inline]
pub const fn new(segment_order: [u8; 6], reverse_mask: u8, len: u8) -> Self {
Self {
segment_order,
reverse_mask,
len,
}
}
#[inline]
pub const fn k(&self) -> usize {
(self.len - 1) as usize
}
#[inline]
pub const fn segment_count(&self) -> usize {
self.len as usize
}
#[inline]
pub const fn segment_at(&self, pos: usize) -> usize {
self.segment_order[pos] as usize
}
#[inline]
pub const fn should_reverse(&self, idx: usize) -> bool {
(self.reverse_mask >> idx) & 1 == 1
}
#[inline]
pub fn segment_order(&self) -> &[u8] {
&self.segment_order[..self.len as usize]
}
const fn is_identity(&self) -> bool {
if self.reverse_mask != 0 {
return false;
}
let mut i = 0;
while i < self.len as usize {
if self.segment_order[i] != i as u8 {
return false;
}
i += 1;
}
true
}
}
pub static THREE_OPT_RECONNECTIONS: &[KOptReconnection] = &[
KOptReconnection::new([0, 1, 2, 3, 0, 0], 0b0010, 4), KOptReconnection::new([0, 1, 2, 3, 0, 0], 0b0100, 4), KOptReconnection::new([0, 1, 2, 3, 0, 0], 0b0110, 4), KOptReconnection::new([0, 2, 1, 3, 0, 0], 0b0000, 4), KOptReconnection::new([0, 2, 1, 3, 0, 0], 0b0010, 4), KOptReconnection::new([0, 2, 1, 3, 0, 0], 0b0100, 4), KOptReconnection::new([0, 2, 1, 3, 0, 0], 0b0110, 4), ];
pub fn enumerate_reconnections(k: usize) -> Vec<KOptReconnection> {
assert!((2..=5).contains(&k), "k must be between 2 and 5");
let num_segments = k + 1;
let num_middle = k - 1;
let mut result = Vec::new();
let middle_indices: Vec<u8> = (1..k as u8).collect();
let permutations = generate_permutations(&middle_indices);
for perm in permutations {
let mut segment_order = [0u8; 6];
segment_order[0] = 0;
for (i, &idx) in perm.iter().enumerate() {
segment_order[i + 1] = idx;
}
segment_order[num_segments - 1] = (num_segments - 1) as u8;
for mask in 0..(1u8 << num_middle) {
let reverse_mask = mask << 1;
let reconnection =
KOptReconnection::new(segment_order, reverse_mask, num_segments as u8);
if !reconnection.is_identity() {
result.push(reconnection);
}
}
}
result
}
fn generate_permutations(items: &[u8]) -> Vec<Vec<u8>> {
if items.is_empty() {
return vec![vec![]];
}
if items.len() == 1 {
return vec![vec![items[0]]];
}
let mut result = Vec::new();
for i in 0..items.len() {
let mut rest: Vec<u8> = items.to_vec();
let item = rest.remove(i);
for mut perm in generate_permutations(&rest) {
perm.insert(0, item);
result.push(perm);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_identity_in_patterns() {
for k in 2..=5 {
let patterns = enumerate_reconnections(k);
for p in &patterns {
assert!(!p.is_identity(), "Found identity in {}-opt patterns", k);
}
}
}
#[test]
fn static_patterns_not_identity() {
for p in THREE_OPT_RECONNECTIONS {
assert!(!p.is_identity());
}
}
}