|
| 1 | +//! Morton (Z-order) tile-pyramid codec — the universal `high:low = tile:cell` |
| 2 | +//! address primitive. |
| 3 | +//! |
| 4 | +//! The convergence the addressing rides on: a node's position in any |
| 5 | +//! container→unit hierarchy (galaxy:planet, country:city, organ:tissue, |
| 6 | +//! cm²:mm², residue:atom) is a **Z-order quadtree path**. Interleave the x/y |
| 7 | +//! bits 2-at-a-time (`2bit×2bit` → a 4×4 = 16-way branch per level) and the |
| 8 | +//! address bijects to a 2-D tile pyramid: |
| 9 | +//! |
| 10 | +//! * **bijective** — every (x, y) has exactly one code, every code one (x, y). |
| 11 | +//! No overflow basin to collide (the class of bug that hit `ti=15`). |
| 12 | +//! * **locality-preserving** — nearby codes are nearby in space, so a layout is |
| 13 | +//! a deinterleave, not a force pass. |
| 14 | +//! * **hierarchical** — the high bits are the coarse tile (family), the low bits |
| 15 | +//! the fine cell (identity); truncating the code climbs the pyramid. |
| 16 | +//! |
| 17 | +//! Domain-agnostic: the FMA heart slice, OSINT basins, and a chess board all ride |
| 18 | +//! the same codec; only what fills the tiles differs. |
| 19 | +
|
| 20 | +/// Spread the low 16 bits of `n` into the even bit positions (0,2,4,…) — the |
| 21 | +/// "part-1-by-1" bit-interleave half (standard Morton magic-number cascade). |
| 22 | +const fn part1by1(mut n: u32) -> u32 { |
| 23 | + n &= 0x0000_ffff; |
| 24 | + n = (n | (n << 8)) & 0x00ff_00ff; |
| 25 | + n = (n | (n << 4)) & 0x0f0f_0f0f; |
| 26 | + n = (n | (n << 2)) & 0x3333_3333; |
| 27 | + n = (n | (n << 1)) & 0x5555_5555; |
| 28 | + n |
| 29 | +} |
| 30 | + |
| 31 | +/// Gather the even bit positions of `n` back into the low 16 bits — the inverse |
| 32 | +/// of [`part1by1`]. |
| 33 | +const fn compact1by1(mut n: u32) -> u32 { |
| 34 | + n &= 0x5555_5555; |
| 35 | + n = (n | (n >> 1)) & 0x3333_3333; |
| 36 | + n = (n | (n >> 2)) & 0x0f0f_0f0f; |
| 37 | + n = (n | (n >> 4)) & 0x00ff_00ff; |
| 38 | + n = (n | (n >> 8)) & 0x0000_ffff; |
| 39 | + n |
| 40 | +} |
| 41 | + |
| 42 | +/// Interleave `(x, y)` into a 32-bit Z-order (Morton) code: x in the even bits, |
| 43 | +/// y in the odd bits. `2bit×2bit` per pyramid level falls out naturally — bits |
| 44 | +/// `[2k, 2k+1]` are level *k*'s 4×4 cell. |
| 45 | +pub const fn encode(x: u16, y: u16) -> u32 { |
| 46 | + part1by1(x as u32) | (part1by1(y as u32) << 1) |
| 47 | +} |
| 48 | + |
| 49 | +/// Deinterleave a Z-order code back to `(x, y)` — this is what `position()` |
| 50 | +/// becomes: the address *is* the coordinate. |
| 51 | +pub const fn decode(m: u32) -> (u16, u16) { |
| 52 | + (compact1by1(m) as u16, compact1by1(m >> 1) as u16) |
| 53 | +} |
| 54 | + |
| 55 | +/// Push one 4×4 level onto a Z-order path: `(tx, ty)` each in `0..4` (2 bits). |
| 56 | +/// Descending the container→unit hierarchy one step = one `descend`, high bits |
| 57 | +/// first, so the most-significant levels are the coarsest tiles (the family). |
| 58 | +pub const fn descend(parent: u32, tx: u16, ty: u16) -> u32 { |
| 59 | + (parent << 4) | encode(tx & 0b11, ty & 0b11) |
| 60 | +} |
| 61 | + |
| 62 | +#[cfg(test)] |
| 63 | +mod tests { |
| 64 | + use super::*; |
| 65 | + |
| 66 | + #[test] |
| 67 | + fn round_trips() { |
| 68 | + for &(x, y) in &[(0u16, 0u16), (1, 0), (0, 1), (3, 2), (255, 255), (40_000, 25_000)] { |
| 69 | + assert_eq!(decode(encode(x, y)), (x, y), "round-trip ({x},{y})"); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + #[test] |
| 74 | + fn interleaves_2bit_by_2bit() { |
| 75 | + // x=0b01 (1), y=0b10 (2) → bits: x at 0,2 ; y at 1,3 → 0b1001 = 9. |
| 76 | + assert_eq!(encode(0b01, 0b10), 0b1001); |
| 77 | + // the 4×4 cell at level 0 is the low nibble; level 1 is the next nibble. |
| 78 | + assert_eq!(encode(3, 3) & 0b1111, 0b1111, "(3,3) fills one 4×4 cell"); |
| 79 | + } |
| 80 | + |
| 81 | + #[test] |
| 82 | + fn descend_nests_tiles() { |
| 83 | + // a path: root → quadrant (1,1) → sub-cell (2,0). The high nibble is the |
| 84 | + // coarse tile (family), the low nibble the fine cell (identity). |
| 85 | + let coarse = descend(0, 1, 1); |
| 86 | + let fine = descend(coarse, 2, 0); |
| 87 | + assert_eq!(fine >> 4, coarse, "truncating climbs to the parent tile"); |
| 88 | + // sibling cells under the same parent share the high bits. |
| 89 | + let sib = descend(coarse, 0, 3); |
| 90 | + assert_eq!(fine >> 4, sib >> 4, "siblings share the family prefix"); |
| 91 | + assert_ne!(fine, sib, "but differ in the identity cell"); |
| 92 | + } |
| 93 | + |
| 94 | + #[test] |
| 95 | + fn locality_preserving() { |
| 96 | + // horizontally-adjacent cells stay within one 4×4 block of each other. |
| 97 | + let a = encode(10, 10); |
| 98 | + let b = encode(11, 10); |
| 99 | + assert!((a as i64 - b as i64).abs() <= 16, "adjacent cells stay near in Z-order"); |
| 100 | + } |
| 101 | +} |
0 commit comments