pub struct Gray {
length: usize,
weight: usize,
current_column: Vec<bool>,
forward_index: Vec<usize>,
backward_index: Vec<usize>,
forward_weight: usize,
backward_weight: usize,
column_num: usize,
}
impl Gray {
pub fn new(length: usize, weight: usize) -> Self {
let mut g: Vec<bool> = vec![true; weight];
g.extend(vec![false; length - weight]);
let mut forward_index: Vec<usize> = (1..=length).collect();
forward_index[0] = weight;
let backward_index: Vec<usize> = vec![length; length];
Self {
length,
weight,
current_column: g,
forward_index,
backward_index,
forward_weight: weight,
backward_weight: weight,
column_num: 0,
}
}
pub fn with_column(&mut self, col_num: usize) {
self.current_column = vec![true; self.weight];
self.current_column
.extend(vec![false; self.length - self.weight]);
self.forward_index = (1..=self.length).collect();
self.forward_index[0] = self.weight;
self.backward_index = vec![self.length; self.length];
self.forward_weight = self.weight;
self.backward_weight = self.weight;
self.column_num = 0;
for _ in 0..col_num {
self.next_column();
}
}
pub fn previous_delta(&mut self) -> Vec<usize> {
let current_column = self.current_column.clone();
self.previous_column();
self.current_column
.iter()
.zip(current_column.iter())
.map(|(x, y)| *x ^ *y)
.enumerate()
.filter(|(_, x)| *x)
.map(|(i, _)| i)
.collect()
}
#[allow(dead_code)] pub fn current_column(&self) -> Vec<u8> {
self.current_column
.iter()
.map(|x| if *x { 1 } else { 0 })
.collect()
}
pub fn current_column_positions(&self) -> Vec<usize> {
self.current_column
.iter()
.enumerate()
.filter(|(_, x)| **x)
.map(|(i, _)| i)
.collect()
}
#[allow(dead_code)]
pub fn current_forward_state(&self) -> (usize, usize) {
(self.forward_index[0], self.forward_weight)
}
#[allow(dead_code)]
pub fn current_backward_state(&self) -> (usize, usize) {
(self.backward_index[0], self.backward_weight)
}
pub fn next_column(&mut self) {
let idx = self.forward_index[0];
if idx == self.length {
self.forward_index[0] = self.weight;
self.current_column[self.weight - 1] = true;
self.current_column[self.length - 1] = false;
self.forward_weight = self.weight;
self.backward_index = vec![self.length; self.length];
self.column_num = 0;
return;
}
self.forward_index[0] = self.forward_index[idx];
self.forward_index[idx] = idx + 1;
if self.current_column[idx] {
if self.forward_weight > 0 {
self.current_column[self.forward_weight - 1] =
!self.current_column[self.forward_weight - 1];
} else {
self.current_column[idx - 1] = !self.current_column[idx - 1];
}
self.forward_weight += 1;
} else {
if self.forward_weight > 1 {
self.current_column[self.forward_weight - 2] =
!self.current_column[self.forward_weight - 2];
} else {
self.current_column[idx - 1] = !self.current_column[idx - 1];
}
self.forward_weight -= 1;
}
self.current_column[idx] = !self.current_column[idx];
self.backward_weight = self.forward_weight;
let mut i = 0;
while i < self.length {
if idx < self.backward_index[i] {
self.backward_index[idx] = self.backward_index[i];
break;
} else {
i = self.backward_index[i];
}
}
self.backward_index[0] = idx;
if self.forward_weight == idx || self.forward_weight == 0 {
self.forward_weight += 1;
} else {
self.forward_weight -= self.current_column[idx - 1] as usize;
self.forward_index[idx - 1] = self.forward_index[0];
if self.forward_weight == 0 {
self.forward_index[0] = idx - 1;
} else {
self.forward_index[0] = self.forward_weight;
}
}
self.column_num += 1;
}
pub fn previous_column(&mut self) {
let idx = self.backward_index[0];
if idx == self.length {
self.backward_index = (1..=self.length).collect();
if self.weight == 1 {
self.backward_index[0] = self.length - 1;
} else {
self.backward_index[0] = self.weight - 1;
}
self.current_column[self.weight - 1] = false;
self.current_column[self.length - 1] = true;
self.backward_weight = self.weight - 1;
self.forward_index[0] = self.length;
self.column_num = 0;
return;
}
self.backward_index[0] = self.backward_index[idx];
self.backward_index[idx] = idx + 1;
if self.current_column[idx] {
if self.backward_weight > 0 {
self.current_column[self.backward_weight - 1] =
!self.current_column[self.backward_weight - 1];
} else {
self.current_column[idx - 1] = !self.current_column[idx - 1];
}
self.backward_weight += 1;
} else {
if self.backward_weight > 1 {
self.current_column[self.backward_weight - 2] =
!self.current_column[self.backward_weight - 2];
} else {
self.current_column[idx - 1] = !self.current_column[idx - 1];
}
self.backward_weight -= 1;
}
self.current_column[idx] = !self.current_column[idx];
self.forward_weight = self.backward_weight;
if idx < self.forward_index[0] {
self.forward_index[idx] = self.forward_index[0];
} else if idx < self.forward_index[idx - 1] {
self.forward_index[idx] = self.forward_index[idx - 1];
}
self.forward_index[0] = idx;
if self.backward_weight == idx || self.backward_weight == 0 {
self.backward_weight += 1;
} else {
self.backward_weight -= self.current_column[idx - 1] as usize;
self.backward_index[idx - 1] = self.backward_index[0];
if self.backward_weight == 0 {
self.backward_index[0] = idx - 1;
} else {
self.backward_index[0] = self.backward_weight;
}
}
self.column_num -= 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
fn binomial(n: usize) -> usize {
if n == 1 {
2
} else {
binomial(n - 1) * (4 * n - 2) / n
}
}
#[test]
fn test_gray_code_with_column() {
let length = 12;
let weight = length / 2;
let mut gray = Gray::new(length, weight);
let col_num = binomial(weight);
println!("col_num: {}", col_num);
gray.with_column(col_num - 1);
assert_eq!(gray.column_num, col_num - 1);
for _ in 0..col_num - 1 {
assert_eq!(
gray.current_column().iter().filter(|&&x| x == 1).count(),
weight
);
assert_eq!(gray.previous_delta().len(), 2);
}
assert_eq!(gray.current_column_positions().len(), weight);
}
#[test]
fn test_gray_code_backward() {
let mut gray = Gray::new(5, 2);
for i in 0..9 {
println!("i: {}", i);
gray.next_column();
println!("current_column: {:?}", gray.current_column());
println!(
"current state: forward {:?}, backward {:?}",
gray.current_forward_state(),
gray.current_backward_state()
);
println!("forward_index: {:?}", gray.forward_index);
println!("backward_index: {:?}", gray.backward_index);
}
for i in 0..9 {
println!("i: {}", i);
gray.previous_column();
println!("current_column: {:?}", gray.current_column());
println!(
"current state: forward {:?}, backward {:?}",
gray.current_forward_state(),
gray.current_backward_state()
);
println!("forward_index: {:?}", gray.forward_index);
println!("backward_index: {:?}", gray.backward_index);
}
}
#[test]
fn test_gray_code_5_2_forward() {
let mut gray = Gray::new(5, 2);
let state = [
(2, 2),
(1, 0),
(3, 2),
(2, 0),
(1, 0),
(4, 2),
(3, 0),
(2, 0),
(1, 0),
(5, 2),
];
for i in 0..state.len() {
assert_eq!(gray.current_forward_state(), state[i]);
gray.next_column();
}
println!("current_column: {:?}", gray.current_column());
println!("current_forward_state: {:?}", gray.current_forward_state());
println!("forward_index: {:?}", gray.forward_index);
println!("backward_index: {:?}", gray.backward_index);
gray.previous_column();
println!(
"current_backward_state: {:?}",
gray.current_backward_state()
);
println!("current_column: {:?}", gray.current_column());
println!("forward_index: {:?}", gray.forward_index);
println!("backward_index: {:?}", gray.backward_index);
gray.next_column();
println!("current_column: {:?}", gray.current_column());
println!("current_forward_state: {:?}", gray.current_forward_state());
println!("forward_index: {:?}", gray.forward_index);
println!("backward_index: {:?}", gray.backward_index);
let column = gray.current_column();
let state = gray.current_forward_state();
let forward_index = gray.forward_index.clone();
let backward_index = gray.backward_index.clone();
for _ in 0..10 {
gray.previous_column();
gray.next_column();
assert_eq!(gray.current_forward_state(), state);
assert_eq!(gray.forward_index, forward_index);
assert_eq!(gray.backward_index, backward_index);
assert_eq!(gray.current_column(), column);
}
}
#[test]
fn test_gray_code_forward_backward() {
let w = 5;
let mut gray = Gray::new(2 * w, w);
let mut state: Vec<(usize, usize)> = Vec::new();
let mut column: Vec<Vec<u8>> = Vec::new();
let length = binomial(w) - 1;
for i in 0..length {
println!("i: {}", i);
state.push(gray.current_forward_state());
column.push(gray.current_column());
println!("current_state: {:?}", gray.current_forward_state());
println!("current_column: {:?}", gray.current_column());
gray.next_column();
}
for i in 0..length {
println!("i: {}", length - i - 1);
gray.previous_column();
println!("current_state: {:?}", gray.current_forward_state());
println!("current_column: {:?}", gray.current_column());
assert_eq!(gray.current_column(), column[length - i - 1]);
}
}
#[test]
fn test_gray_code_next_column() {
let mut gray = Gray::new(6, 3);
let _expected_states = [(3, 3), (1, 1), (2, 1), (4, 3), (2, 1), (5, 3)];
for _ in 0..63 {
let current_state = gray.current_forward_state();
println!("current_state: {:?}", current_state);
println!("current_column: {:?}", gray.current_column());
gray.next_column();
}
}
}