use crate::graph::{Graph, GraphBuilder};
pub const Z1_RULES: [(i64, i64); 4] = [(1, 0), (2, 1), (2, 3), (4, 1)];
pub fn z1_grid(w: usize, h: usize, j: f64, bias: f64) -> Graph {
let mut gb = GraphBuilder::new(w * h);
let rots = |a: i64, b: i64| [(a, b), (-b, a), (-a, -b), (b, -a)];
for y in 0..h as i64 {
for x in 0..w as i64 {
let i = (y * w as i64 + x) as usize;
if bias != 0.0 {
gb.bias(i, bias);
}
for &(a, b) in &Z1_RULES {
for (dx, dy) in rots(a, b) {
let (nx, ny) = (x + dx, y + dy);
if nx >= 0 && ny >= 0 && nx < w as i64 && ny < h as i64 {
let jdx = (ny * w as i64 + nx) as usize;
if jdx > i {
gb.couple(i, jdx, j);
}
}
}
}
}
}
gb.build()
}
pub fn parity(w: usize, i: usize) -> u8 {
let (x, y) = (i % w, i / w);
((x + y) % 2) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn grid_is_degree_16_and_bipartite() {
let g = z1_grid(24, 24, 0.1, 0.0);
let w = 24usize;
let i = 12 * w + 12;
assert_eq!(g.offset[i + 1] - g.offset[i], 16);
for a in 0..g.n {
for k in g.offset[a]..g.offset[a + 1] {
let b = g.nbr[k] as usize;
assert_ne!(parity(w, a), parity(w, b), "edge {a}-{b} same parity");
}
}
let mut max_d2 = 0i64;
for a in 0..g.n {
let (ax, ay) = ((a % w) as i64, (a / w) as i64);
for k in g.offset[a]..g.offset[a + 1] {
let b = g.nbr[k] as usize;
let (bx, by) = ((b % w) as i64, (b / w) as i64);
max_d2 = max_d2.max((ax - bx).pow(2) + (ay - by).pow(2));
}
}
assert_eq!(max_d2, 17);
}
}