#[derive(Debug, Clone)]
pub struct EisensteinLattice {
pub n_chambers: usize,
}
impl EisensteinLattice {
pub fn new() -> Self {
EisensteinLattice { n_chambers: 12 }
}
pub fn chamber(coupling: &[f64; 12]) -> usize {
let mut max_idx = 0;
let mut max_val = coupling[0];
for (i, &val) in coupling.iter().enumerate() {
if val > max_val {
max_val = val;
max_idx = i;
}
}
max_idx
}
pub fn project(coordinates: &[f64; 12]) -> (f64, f64) {
let mut x = 0.0;
let mut y = 0.0;
for (chamber, &weight) in coordinates.iter().enumerate() {
let angle = chamber as f64 * std::f64::consts::PI / 6.0;
x += weight * angle.cos();
y += weight * angle.sin();
}
(x, y)
}
pub fn interval(chamber_a: usize, chamber_b: usize) -> usize {
let diff = if chamber_a > chamber_b { chamber_a - chamber_b } else { chamber_b - chamber_a };
diff.min(12 - diff) }
pub fn chamber_name(chamber: usize) -> &'static str {
["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
.get(chamber % 12)
.copied()
.unwrap_or("?")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chamber_selection() {
let coupling = [0.0, 0.0, 0.0, 0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
assert_eq!(EisensteinLattice::chamber(&coupling), 3);
}
#[test]
fn test_chamber_names() {
assert_eq!(EisensteinLattice::chamber_name(0), "C");
assert_eq!(EisensteinLattice::chamber_name(6), "F#");
}
#[test]
fn test_interval() {
assert_eq!(EisensteinLattice::interval(0, 7), 5); assert_eq!(EisensteinLattice::interval(0, 7), 5); assert_eq!(EisensteinLattice::interval(0, 4), 4); }
#[test]
fn test_project_center() {
let coupling = [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let (x, y) = EisensteinLattice::project(&coupling);
assert!((x - 1.0).abs() < 1e-10);
assert!((y - 0.0).abs() < 1e-10);
}
}