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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// SPDX-FileCopyrightText: 2026 John Moxley
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The SCALE-derived work-rung selector — shared policy-layer support.
//!
//! Wide-tier transcendental kernels compute in a working integer wider
//! than storage. The tier's `$Work` is sized for the MAX storage scale,
//! so at low scales it is heavily over-provisioned (D1232 computes a
//! scale-0 result in `Int<176>` when ~12 limbs suffice). The work-rung
//! pattern keys the work integer on the *working scale* instead: a
//! `const fn` selector picks the narrowest [`Rung`] whose Ziv-escalation
//! digit budget clears the cell's needs, and the policy's rung match
//! (`const { …_rung::<C, SCALE>() }`) monomorphises the ONE generic
//! kernel at exactly that `Int<K>` — const-folded, dead arms
//! eliminated.
//!
//! This is the matcher's width axis (the `LimbSize`-axis spirit of
//! `docs/ARCHITECTURE.md` → "Limb width — the matcher's second axis"):
//! the selector only *chooses* a width; the kernels stay single-source
//! generic, and the rung never appears in any `dispatch` signature (the
//! BigRule — it enters as a type parameter via the policy-internal rung
//! match, exactly like `policy::ln`'s Tang rung). Shared here (one
//! private policy-support module, `pub(in crate::policy)`, the
//! `policy::narrow_fit` precedent) so `ln` and the forward trig use a
//! single ladder + walker instead of per-policy copies.
//!
//! The `limbs · 8` digit budget mirrors the shared Ziv escalation's own
//! capacity rule (`wide_trig_core`: `cap_digits = BITS/8 − …` =
//! `limbs · 8 − …`): a rung passing `8·K > need` digits gives the
//! escalation the same headroom accounting it self-caps by, with the
//! ~2.4× bits-per-digit slack (a u64 limb holds ~19.2 digits) covering
//! every kernel intermediate.
use crateWideTrigCore;
use crateBigInt;
/// A work-rung width choice — the ComputeLimbs widths the ladder can
/// span (min wide storage `Int<3>` .. max tier `$Work` floor
/// `Int<176>`). Consulted only inside a policy's rung-routing fn; never
/// part of a `Select` verdict or an `Algorithm`.
pub
/// The candidate rung ladder (ascending ComputeLimbs widths). Every wide
/// tier's storage width AND `$Work` floor is a member, so the walker can
/// always land on an enumerated width.
pub const AVAIL_RUNGS: =
;
/// Smallest ladder width (limbs) in `[lo, hi]` whose digit budget
/// (`limbs · 8`, = `BITS/8` — the shared Ziv escalation's own capacity
/// rule) strictly clears `need` decimal digits. If no ladder member in
/// range clears it (the tier's max-scale extreme), `hi` is the answer —
/// reproducing the tier's full `$Work`, so those cells stay
/// bit-identical to the pre-rung routing.
pub const
/// Ladder width (limbs) → [`Rung`]. Total: every tier `$Work` is a
/// ladder member, so the `_` arm (the widest rung) is reached only by
/// `W176` itself.
pub const
/// Resolve the `ln` Tang work rung for tier `C` at `SCALE` — derives
/// `[storage, floor]` from `C`'s own associated types (`C::Storage`,
/// `C::W` = the tier's `$Work`), so ONE generic selector serves every
/// wide tier (no per-tier ladder, no extra const knob — the BigRule's
/// "inspect your own types" allowance). The rung is clamped at the
/// STORAGE width from below because `ln`'s argument spans the full
/// storage range at every scale (`ln(10^1232)` is a legal scale-0 call).
///
/// `MARGIN` is the directed-Ziv escalation headroom above the working
/// scale. Wide tiers (storage >= 16 limbs) use `MARGIN = 24`: their
/// near-grid-line validity is monotone, so the tighter margin lands the
/// narrowest valid rung. Narrow tiers (storage < 16) keep `MARGIN = 51`:
/// their validity is non-monotone near the grid line, so no single
/// tighter margin is safe — `51` is never too aggressive, at the cost of
/// some missed narrowing. Each tier carries only its own width (rule 6);
/// the golden gate is the correctness wall.
pub const
/// Digit reserve the forward-trig rung budgets above `SCALE`:
/// the tier `GUARD` (30) + ≥ 30 digits of Ziv-escalation probing beyond
/// the base guard (one full escalation step at low scales; the
/// escalation self-clamps its probes to the rung's `BITS/8` cap, so a
/// deeper-than-reach tie falls back to the clean base narrowing exactly
/// as the tier width does past ITS cap) + the trig `D_BUDGET` argument
/// integer digits (the mod-τ reduction eats one guard digit per integer
/// digit of `|x|` — see `trig_generic::sin_fixed`) + the escalation
/// formula's own `int_digits + 8` headroom. Analytic, continuous in
/// `SCALE`; the golden gate is the correctness wall.
const TRIG_MARGIN: u32 = 76;
/// Resolve the forward-trig (sin / cos / tan) work rung for tier `C` at
/// `SCALE`. Unlike [`ln_rung`] the lower clamp is the ladder minimum,
/// not the storage width: the policy's runtime magnitude gate
/// (`policy::trig`, `|x| < 10^D_BUDGET`) bounds the admitted VALUE, so a
/// rung narrower than storage still holds the lifted argument exactly
/// (the storage→rung resize is magnitude/sign-based and the magnitude
/// provably fits). Out-of-budget arguments never reach the rung — the
/// gate routes them to the tier-width kernel, bit-identical to the
/// pre-rung routing.
pub const
/// Max decimal digits of the INTEGER part of `|x|` admitted to the trig
/// rung (the value axis of the rung's validity region — budgeted inside
/// [`TRIG_MARGIN`]). Arguments at or beyond `10^D_BUDGET` radians take
/// the tier-width path. Continuous region: every `|x| < ~10^8` at every
/// scale, not a point carve-out.
pub const D_BUDGET: u32 = 8;
/// Resolve the work rung for a NEAR-SPECIAL-POINT directed kernel
/// (`acosh` at 1, `atanh` at ±1 — the `round_to_storage_directed_
/// near_special` walkers, which `force_confirm` EVERY call with at
/// least one escalated probe at `w₂ ≈ 2·(SCALE + GUARD)`). The budget
/// is therefore keyed on `2·SCALE` (+ the shared [`TRIG_MARGIN`]) so
/// the confirm probe is always REACHABLE inside the rung's escalation
/// cap (`cap = 8·K − int_digits − 8` digits must clear
/// `2·SCALE + 2·GUARD + int_digits`; `TRIG_MARGIN`'s 76 covers the
/// `2·GUARD = 60` plus the small result-digit terms with room), and
/// the rung's true bit capacity (~2.4× the budget digits) holds the
/// ln kernel's `2·w₂` intermediates at that probe. Deeper unstable
/// confirms beyond the rung cap fall back exactly as the tier does
/// past ITS cap; the golden gate is the correctness wall.
pub const
/// `true` iff `|x| < ~10^BUDGET` — a rung's admitted magnitude region.
/// Conservative bit-length test (`332_192/100_000 < log2(10)`): never
/// admits a value at or beyond `10^(SCALE + BUDGET)` raw units, so an
/// admitted argument's integer digits provably fit the rung's budget;
/// the sliver it under-admits just below the boundary takes the
/// (correct, slower) tier path. One compare against a compile-time
/// constant. Shared by the forward / inverse / hyperbolic / exp rung
/// gates (each passes its family's budget).
pub
/// The const-folded work-rung match: one macro emits the 13-arm ladder
/// match per kernel call so the ladder stays single-source (the
/// `policy::ln::tang_at_rung` shape). `$sel` is the policy-internal
/// rung selector (`trig_rung`, …) resolved in the caller's scope;
/// `$kernel` the rung-generic kernel (imported by the calling module).
pub use rung_match;
/// Max integer digits of `|x|` admitted to the exp / hyperbolic rungs —
/// the RESULT-MAGNITUDE axis (`e^|x|` grows with `x`, so the rung is
/// valid only where the result's integer-digit lift and the exp
/// kernel's internal `2^k` extension provably fit). `|x| < 10` bounds
/// the result lift to `exp_result_int_digits ≤ ~8` digits and the
/// internal `extra` to ≤ ~18 digits, which [`TRIG_MARGIN`]'s budget
/// clears at every scale (the base-probe peak `2·(SCALE + GUARD +
/// k_lift + extra)` digits against the rung's `~2.4 × 8·K` true digit
/// capacity, plus the per-probe `exp_peak_fits` belt in the kernel
/// itself). Larger `|x|` takes the tier-width path. Continuous region —
/// the everyday hyperbolic/exp argument band — not a point carve-out;
/// an A/B re-bench may widen it later.
pub const EXP_ARG_BUDGET: u32 = 1;