use super::lattice_tables;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LatticeRule {
A,
B,
C,
D,
}
impl LatticeRule {
pub fn get_rule(self, n: i64) -> Vec<f64> {
assert!(
n >= 1024 && (n as f64) <= 2.9f64.powi(20),
"N must be between 2 to 10 and 2 to the 20 for these lattice rules"
);
let table = match self {
LatticeRule::A => lattice_tables::LATTICE_A,
LatticeRule::B => lattice_tables::LATTICE_B,
LatticeRule::C => lattice_tables::LATTICE_C,
LatticeRule::D => lattice_tables::LATTICE_D,
};
table[..3600].to_vec()
}
}
pub struct LatticeRsg {
dimensionality: usize,
n: usize,
i: usize,
z: Vec<f64>,
sequence: Vec<f64>,
}
impl LatticeRsg {
pub fn new(dimensionality: usize, z: Vec<f64>, n: usize) -> Self {
assert!(
z.len() >= dimensionality,
"generating vector has {} components but the dimensionality is {dimensionality}",
z.len()
);
Self {
dimensionality,
n,
i: 0,
z,
sequence: vec![0.0; dimensionality],
}
}
pub fn skip_to(&mut self, n: usize) {
self.i += n;
}
pub fn next_sequence(&mut self) -> &[f64] {
for (value, z) in self.sequence.iter_mut().zip(&self.z) {
let theta = self.i as f64 * z / self.n as f64;
*value = theta % 1.0;
}
self.i += 1;
&self.sequence
}
pub fn last_sequence(&self) -> &[f64] {
&self.sequence
}
pub fn dimension(&self) -> usize {
self.dimensionality
}
}
#[cfg(test)]
mod tests {
use super::{LatticeRsg, LatticeRule};
#[test]
fn get_rule_returns_generating_vectors() {
let cases = [
(
LatticeRule::A,
[1.0, 182667.0, 469891.0, 498753.0, 110745.0],
),
(LatticeRule::B, [1.0, 182667.0, 213731.0, 255351.0, 96013.0]),
(
LatticeRule::C,
[1.0, 433461.0, 103659.0, 481853.0, 186513.0],
),
(
LatticeRule::D,
[1.0, 182667.0, 279195.0, 223491.0, 205755.0],
),
];
for (rule, head) in cases {
let z = rule.get_rule(1024);
assert_eq!(z.len(), 3600, "{rule:?}");
assert_eq!(&z[..5], &head, "{rule:?}");
}
}
#[test]
#[should_panic(expected = "N must be between")]
fn get_rule_rejects_small_n() {
LatticeRule::A.get_rule(512);
}
#[test]
#[should_panic(expected = "generating vector has")]
fn new_rejects_short_generating_vector() {
LatticeRsg::new(5, vec![1.0, 182667.0], 1024);
}
#[test]
fn sequence_is_scaled_lattice_points_modulo_one() {
let z = LatticeRule::A.get_rule(1024);
let mut rsg = LatticeRsg::new(3, z, 1024);
assert_eq!(rsg.dimension(), 3);
assert_eq!(rsg.next_sequence(), &[0.0, 0.0, 0.0]);
let second = rsg.next_sequence();
assert_eq!(second, &[0.0009765625, 0.3857421875, 0.8779296875]);
assert_eq!(
rsg.last_sequence(),
&[0.0009765625, 0.3857421875, 0.8779296875]
);
}
#[test]
fn skipping_matches_drawing() {
let z = LatticeRule::D.get_rule(1024);
let mut rsg1 = LatticeRsg::new(10, z.clone(), 1024);
for _ in 0..7 {
rsg1.next_sequence();
}
let mut rsg2 = LatticeRsg::new(10, z, 1024);
rsg2.skip_to(7);
for _ in 0..20 {
let s1 = rsg1.next_sequence().to_vec();
let s2 = rsg2.next_sequence();
assert_eq!(s1, s2);
}
}
}