Skip to main content

mixed_calibration_map/
mixed_calibration_map.rs

1//! Mixed Bucketed-X / Uniform-Y calibration map.
2//!
3//! X is irregular characterized codes, so it keeps its knots and buys a
4//! smaller local bound with a compile-time bucket index. Y is an exact
5//! arithmetic progression, so Uniform drops its knot array. Changing these
6//! strategies cannot change a value or an error. The nested-index tuning that
7//! selected `B = 8` is in the strategy guide (not packaged):
8//! <https://github.com/photon-circus/ph-surfaces/blob/v0.1.0/docs/choosing-a-strategy.md>.
9//!
10//! Host `main` is an assertion harness. Declarations are `static` and
11//! `core`-compatible. Comparison counts are operation structure, not cycles.
12
13use ph_surfaces::{
14    AxisLookup, BilinearSurface, BinaryAxis, BucketedAxis, UniformAxis, bucket_index,
15    max_local_comparisons,
16};
17
18static X: [u16; 17] = [
19    0, 100, 210, 300, 405, 500, 610, 700, 805, 900, 1_010, 1_100, 1_205, 1_300, 1_410, 1_500, 1_600,
20];
21static X_INDEX_2: [u16; 2] = bucket_index(&X);
22static X_INDEX_4: [u16; 4] = bucket_index(&X);
23static X_INDEX_8: [u16; 8] = bucket_index(&X);
24static X_INDEX_16: [u16; 16] = bucket_index(&X);
25static Y: [u16; 9] = [0, 200, 400, 600, 800, 1_000, 1_200, 1_400, 1_600];
26static VALUES: [[i32; 17]; 9] = [[0; 17]; 9];
27
28type Mixed = BilinearSurface<17, 9, BucketedAxis<17, 8>, UniformAxis<9, 0, 200>>;
29type AllBinary = BilinearSurface<17, 9>;
30
31static MIXED: Mixed = BilinearSurface::from_axes(
32    BucketedAxis::new(&X, &X_INDEX_8),
33    UniformAxis::new(),
34    &VALUES,
35);
36static DEFAULT: AllBinary = BilinearSurface::new(&X, &Y, &VALUES);
37
38fn main() {
39    // Nested tuning: discard indexes that do not beat Binary's bound of 5.
40    assert_eq!(max_local_comparisons(&X, &X_INDEX_2), 9); // 4 index bytes; worse
41    assert_eq!(max_local_comparisons(&X, &X_INDEX_4), 5); // 8 bytes; no improvement
42    assert_eq!(max_local_comparisons(&X, &X_INDEX_8), 3); // 16 bytes; meets bound 3
43    assert_eq!(max_local_comparisons(&X, &X_INDEX_16), 2); // 32 bytes; only if 3 is not enough
44    assert_eq!(<BinaryAxis<17>>::MAX_SEARCH_COMPARISONS, 5);
45
46    assert_eq!(MIXED.evaluate(610, 400), DEFAULT.evaluate(610, 400));
47    assert_eq!(MIXED.evaluate(610, 400), Ok(0));
48    assert_eq!(MIXED.y_knot(8), 1_600); // described, not stored
49    for x in [0u16, 100, 610, 1_205, 1_600] {
50        for y in [0u16, 200, 800, 1_600] {
51            assert_eq!(MIXED.evaluate(x, y), DEFAULT.evaluate(x, y));
52        }
53    }
54
55    assert_eq!(<BucketedAxis<17, 8>>::KNOT_BYTES, 34);
56    assert_eq!(<BucketedAxis<17, 8>>::INDEX_BYTES, 16);
57    assert_eq!(<UniformAxis<9, 0, 200>>::KNOT_BYTES, 0);
58    assert_eq!(Mixed::PAYLOAD_BYTES, 662);
59    assert_eq!(AllBinary::PAYLOAD_BYTES, 664);
60}