1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Shared fixed-point constants for the engine.
//!
//! All constants are constructed as exact rational values using
//! FixedPoint integer division. No floats are used.
use FixedPoint;
/// Below this many nodes, `nearest_semantic` stays on the brute-force scan:
/// a VP-tree build costs O(n log n) distance evaluations, which small stores
/// never amortize (see `docs/SEMANTIC_INDEX.md`).
pub const SEMANTIC_INDEX_MIN_NODES: usize = 256;
/// Maximum number of dimension slices the semantic index caches at once.
/// Eviction is deterministic (lowest key first), not wall-clock LRU.
pub const SEMANTIC_INDEX_MAX_SLICES: usize = 16;
/// Minimum population for `find_outliers`: z-scores over fewer nodes
/// are statistically meaningless, so smaller populations return no outliers.
pub const OUTLIER_MIN_POPULATION: usize = 5;
/// Neighborhood size for `find_outliers`: each node's outlier score is
/// its average distance to this many nearest peers (capped at population−1).
pub const OUTLIER_KNN: usize = 10;
/// 0.5 = 1/2
/// Largest norm/ratio the model represents: `1 − 10⁻¹²`.
///
/// This bounds the greatest expressible hyperbolic distance at
/// `2·atanh(1 − 10⁻¹²) ≈ 28.3`, which with the default τ = 1 is roughly 27
/// levels of nesting. The limit is a deliberate margin, not an arithmetic
/// one: `atanh`/`tanh` round-trip at 0 ULP out to `1 − 10⁻¹⁸`, and `1 − r²`
/// stays representable until about `1 − 10⁻¹⁹`, so this sits six orders of
/// magnitude clear of the floor.
///
/// It was 0.99 until 2026-07-30, which capped distance at 5.29 — about seven
/// levels — and, worse, made `ensure_in_disk` collapse anything deeper back
/// onto this value, so norms cycled instead of growing. See
/// `docs/HYPERBOLIC_INDEX.md`.
/// 0.99999 = 99999/100000 — tanh saturation bound
/// 0.0001 = 1/10000 — standard epsilon for near-zero checks
/// 0.00001 = 1/100000 — small epsilon for origin detection
/// How close to the boundary a point may sit before it is projected back in:
/// `ensure_in_disk` rescales when `1 − ‖p‖² < 10⁻¹²`.
///
/// Matched to [`near_boundary`] so a rescaled point lands *inside* the
/// margin and does not immediately re-trigger. Was 1/1000, which fired at
/// ‖p‖ ≈ 0.9995 — reachable by depth 8 — and rescaled all the way back to
/// 0.99, producing an observable 4-cycle in the norms
/// (0.99 → 0.9963 → 0.9986 → 0.9995 → 0.99) rather than a depth limit.
/// Below this, the Möbius denominator `|1 − p̄q|²` is treated as degenerate.
///
/// Purely a division-safety bound, not a geometric one. `dist_sq ≤ 4` for any
/// two points in the disk, so the quotient stays inside Q64.64 as long as the
/// denominator exceeds `4 / (2⁶³−1) ≈ 8` ULP; 16 ULP doubles that margin.
///
/// This was `epsilon()² = 10⁻⁸` until 2026-07-30 — ten orders of magnitude
/// above the real floor. Since `|1 − p̄q|² = (1 − ‖p‖²)² + ‖p − q‖²` for
/// points at equal radius, ordinary sibling geometry at depth 11 evaluates to
/// ~3.5e-9 and tripped the guard, making the kernel return the saturation
/// value for *every* pair from that depth on. Every node became equidistant,
/// so nearest-neighbour ranking became arbitrary — the real cause of what
/// looked like a spatial-index limit.
/// 0.3 = 3/10 — region radius for hash table origin bucket
/// Pi, parsed from string for maximum precision
/// Two * pi
/// Golden angle = pi * (3 - sqrt(5))
/// Safe atanh: clamps input to (-0.99, 0.99) then calls gMath's .atanh()
/// Default Sarkar embedding scale factor τ = 1.0.
/// Controls parent-child hyperbolic distance. Q64.64 supports depth ~44/τ.
/// Quantization helper: converts a FixedPoint to an i32 by multiplying
/// by 1000 and rounding to the nearest integer.
/// Replaces the pattern `(x.to_f32() * 1000.0).round() as i32`
/// High-resolution quantization for node-identity position signatures:
/// 2^20 steps per unit (coordinates live inside the unit disk, so the
/// result fits an i32 with room to spare).
///
/// Node identity must NOT use `quantize_1000`: at 1/1000 resolution two
/// depth-2 cousins in *different branches* can quantize to identical
/// signatures at a few hundred nodes (silent data
/// crossover). 2^-20 resolution pushes the same birthday bound past
/// millions of nodes, and rainbow fan-out banding guarantees the true
/// positions are distinct.