Skip to main content

gam_math/
score_opt.rs

1//! Certified global optimization of one-dimensional scores on a bounded
2//! domain, together with the affine-pencil spectral profile shared by the
3//! Gaussian REML smoothing-parameter searches.
4//!
5//! Point samples alone cannot prove that a smooth function has no narrow
6//! stationary pair between them.  The search therefore requires two pieces of
7//! information from its caller:
8//!
9//! * a nearest-rounded point evaluation `(value, first derivative, second
10//!   derivative)`, used only as a representative and to propose refinements;
11//! * an OUTER enclosure of the exact score value and both exact derivatives
12//!   over every requested interval, accompanied by a certified forward-error
13//!   bound for the scalar score evaluator.
14//!
15//! A cell needs no stationary decomposition when its derivative enclosure
16//! excludes zero or its exact score upper bound is strictly below an attained
17//! point-score lower bound. A stationary point is refined only after the second-derivative
18//! enclosure excludes zero, proving that the first derivative is monotone and
19//! hence that certified endpoint derivative ranges of opposite sign contain
20//! exactly one root. Every other interval is subdivided unless the exact score
21//! range is narrower than the score evaluator's certified pairwise
22//! forward-error floor. Such a region is returned explicitly as a
23//! [`ResolutionFlatRegion`]; it is never mislabeled as a stationary point. A
24//! cell whose exact score upper bound is below an already attained exact
25//! point-score lower bound is retained as a [`DominatedRegion`] and needs no
26//! stationary decomposition: none of its structure can affect the global
27//! maximum. If neither exclusion, isolation, score-value flatness, nor exact
28//! dominance is proved before the requested abscissa resolution, the result is
29//! a typed [`ScoreSearchError::Unresolved`] rather than a best-effort optimum.
30//!
31//! [`AffineRemlProfile`] supplies both the point jets and rigorous interval
32//! formulas for scores whose penalized Hessian has simultaneously diagonal
33//! affine modes `h_i(lambda) = g_i + lambda s_i`.  This covers an ordinary
34//! Demmler--Reinsch eigensystem (`g_i = 1`) and a reference-Hessian pencil
35//! (`g_i = 1 - lambda_0 mu_i`, `s_i = mu_i`) without any matrix dependency in
36//! this crate.
37//!
38//! # The enclosure has to COLLAPSE, not merely be correct
39//!
40//! Everything above is a statement about what the search does with an
41//! enclosure; none of it says how tight one has to be, and the difference
42//! decides whether a domain can be decomposed at all. Every terminal verdict —
43//! derivative exclusion, stationary isolation, score-value flatness, exact
44//! dominance — is a comparison between an enclosure and a fixed quantity, so an
45//! enclosure whose overestimation is FIRST ORDER in the cell width buys a
46//! constant factor of resolution per subdivision, and the search enumerates
47//! cells until its budget is gone.
48//!
49//! That is not hypothetical: [`AffineRemlProfile::enclose`] was a natural
50//! interval extension, and on a REML score — whose log-determinant and deviance
51//! blocks each move by `O(rank)` per unit of `log lambda` while their sum does
52//! not — it returned a value range of exactly `rank * width`, up to `7.4e5`
53//! times wider than the cell's own derivative enclosure permitted, and refused
54//! designs it could certify. It is now a centred (mean value) form intersected
55//! with the natural one, in all three channels; see that method for the
56//! identity, the measurements, and what the centring is anchored on.
57
58use std::fmt;
59use std::sync::OnceLock;
60
61/// Closed real interval `[lo, hi]`.
62///
63/// Search callbacks may use infinite endpoints for conservative bounds, but
64/// neither endpoint may be NaN and `lo <= hi` must hold.  The search validates
65/// every enclosure returned by a callback.
66#[derive(Clone, Copy, Debug, PartialEq)]
67pub struct ClosedInterval {
68    pub lo: f64,
69    pub hi: f64,
70}
71
72impl ClosedInterval {
73    #[inline]
74    pub const fn new(lo: f64, hi: f64) -> Self {
75        Self { lo, hi }
76    }
77
78    #[inline]
79    pub const fn point(value: f64) -> Self {
80        Self {
81            lo: value,
82            hi: value,
83        }
84    }
85
86    #[inline]
87    pub const fn entire() -> Self {
88        Self {
89            lo: f64::NEG_INFINITY,
90            hi: f64::INFINITY,
91        }
92    }
93
94    #[inline]
95    pub fn contains(self, value: f64) -> bool {
96        self.lo <= value && value <= self.hi
97    }
98
99    #[inline]
100    pub fn contains_zero(self) -> bool {
101        self.contains(0.0)
102    }
103
104    #[inline]
105    fn is_valid(self) -> bool {
106        !self.lo.is_nan() && !self.hi.is_nan() && self.lo <= self.hi
107    }
108
109    #[inline]
110    fn hull(self, other: Self) -> Self {
111        Self {
112            lo: self.lo.min(other.lo),
113            hi: self.hi.max(other.hi),
114        }
115    }
116
117    #[inline]
118    fn intersection(self, other: Self) -> Option<Self> {
119        let intersection = Self {
120            lo: self.lo.max(other.lo),
121            hi: self.hi.min(other.hi),
122        };
123        (intersection.lo <= intersection.hi).then_some(intersection)
124    }
125
126    #[inline]
127    fn max_abs(self) -> f64 {
128        self.lo.abs().max(self.hi.abs())
129    }
130
131    #[inline]
132    fn widen(self, radius: f64) -> Self {
133        if radius == 0.0 {
134            return self;
135        }
136        if radius == f64::INFINITY {
137            return Self::entire();
138        }
139        Self {
140            lo: next_down(self.lo - radius),
141            hi: next_up(self.hi + radius),
142        }
143    }
144
145    #[inline]
146    /// Directed outer enclosure of the exact sum of two intervals.
147    pub fn add(self, other: Self) -> Self {
148        Self {
149            lo: sum_down(self.lo, other.lo),
150            hi: sum_up(self.hi, other.hi),
151        }
152    }
153
154    #[inline]
155    /// Directed outer enclosure of the exact interval difference.
156    pub fn sub(self, other: Self) -> Self {
157        Self {
158            lo: sum_down(self.lo, -other.hi),
159            hi: sum_up(self.hi, -other.lo),
160        }
161    }
162
163    #[inline]
164    /// Exact sign reversal of the interval.
165    pub fn neg(self) -> Self {
166        Self {
167            lo: -self.hi,
168            hi: -self.lo,
169        }
170    }
171
172    /// Directed outer enclosure of the exact interval product.
173    pub fn mul(self, other: Self) -> Self {
174        let pairs = [
175            (self.lo, other.lo),
176            (self.lo, other.hi),
177            (self.hi, other.lo),
178            (self.hi, other.hi),
179        ];
180        let mut lo = f64::INFINITY;
181        let mut hi = f64::NEG_INFINITY;
182        for (left, right) in pairs {
183            lo = lo.min(product_down(left, right));
184            hi = hi.max(product_up(left, right));
185        }
186        Self { lo, hi }
187    }
188
189    #[inline]
190    /// Directed outer enclosure after multiplication by an exact binary64
191    /// scalar.
192    pub fn scale(self, value: f64) -> Self {
193        self.mul(Self::point(value))
194    }
195
196    fn square(self) -> Self {
197        if self.lo >= 0.0 {
198            Self {
199                lo: product_down(self.lo, self.lo).max(0.0),
200                hi: product_up(self.hi, self.hi),
201            }
202        } else if self.hi <= 0.0 {
203            Self {
204                lo: product_down(self.hi, self.hi).max(0.0),
205                hi: product_up(self.lo, self.lo),
206            }
207        } else {
208            Self {
209                lo: 0.0,
210                hi: product_up(self.lo, self.lo).max(product_up(self.hi, self.hi)),
211            }
212        }
213    }
214
215    /// Natural logarithm of an interval known to be strictly positive.
216    fn ln_positive(self) -> Self {
217        assert!(
218            self.lo > 0.0,
219            "ln_positive requires a strictly positive interval, got lo={}",
220            self.lo
221        );
222        let lo = certified_ln_positive(self.lo)
223            .expect("ln_positive lower endpoint is finite and positive");
224        let hi = certified_ln_positive(self.hi)
225            .expect("ln_positive upper endpoint is finite and positive");
226        Self::new(lo.lo, hi.hi)
227    }
228
229    /// Divide by an interval known to be strictly positive.
230    fn div_positive(self, denominator: Self) -> Self {
231        assert!(
232            denominator.lo > 0.0,
233            "div_positive requires a strictly positive denominator interval, got lo={}",
234            denominator.lo
235        );
236        let reciprocal = Self {
237            lo: quotient_down(1.0, denominator.hi).max(0.0),
238            hi: quotient_up(1.0, denominator.lo),
239        };
240        self.mul(reciprocal)
241    }
242
243    /// Divide by an interval that excludes zero.
244    fn div_nonzero(self, denominator: Self) -> Self {
245        if denominator.lo > 0.0 {
246            self.div_positive(denominator)
247        } else {
248            assert!(
249                denominator.hi < 0.0,
250                "div_nonzero requires a denominator interval excluding zero, got {denominator:?}"
251            );
252            self.div_positive(denominator.neg()).neg()
253        }
254    }
255
256    #[inline]
257    fn nonnegative(self) -> Self {
258        Self {
259            lo: self.lo.max(0.0),
260            hi: self.hi.max(0.0),
261        }
262    }
263}
264
265/// Nearest-rounded value and analytic derivatives at one abscissa.
266///
267/// `third` is carried alongside the first two because every endpoint-anchored
268/// [`DerivativeEnclosure`] in this workspace is built from the endpoint
269/// curvature and third derivative. Dropping it here used to force the enclosure
270/// oracle to RE-EVALUATE the criterion at both endpoints of every
271/// branch-and-bound cell — endpoints the search had already sampled — which
272/// tripled the number of criterion evaluations the search actually paid for.
273/// Oracles that have no third derivative to report set it to zero; enclosures
274/// that do not consult it are unaffected.
275#[derive(Clone, Copy, Debug, PartialEq)]
276pub struct ScoreJet {
277    pub value: f64,
278    pub derivative: f64,
279    pub curvature: f64,
280    pub third: f64,
281}
282
283/// A point evaluation augmented with its abscissa.
284#[derive(Clone, Copy, Debug, PartialEq)]
285pub struct ScoreSample {
286    pub x: f64,
287    pub value: f64,
288    pub derivative: f64,
289    pub curvature: f64,
290    pub third: f64,
291}
292
293/// Exact score-value range and the numerical resolution of point values.
294///
295/// `value` contains the exact-real score at every point of the cell.
296/// `evaluation_error` is an absolute forward-error bound for both endpoint
297/// values supplied with that cell:
298///
299/// `|endpoint.value - exact_score(endpoint.x)| <= evaluation_error`.
300///
301/// An interval-extension oracle may provide the stronger cell-uniform bound.
302/// The search needs only the endpoint statement: every representative it
303/// retains is an evaluated cell endpoint. The corresponding uncertainty of a
304/// comparison between the two endpoints is at most `2 * evaluation_error`.
305#[derive(Clone, Copy, Debug, PartialEq)]
306pub struct ScoreValueEnclosure {
307    pub value: ClosedInterval,
308    pub evaluation_error: f64,
309}
310
311/// Exact-real score and derivative ranges supplied to the certified search.
312///
313/// Scalar derivative estimates are proposals only. Exclusion, monotonicity,
314/// and root-sign decisions use these mathematical ranges directly, so
315/// derivative-evaluator roundoff never becomes part of a proof predicate.
316#[derive(Clone, Copy, Debug, PartialEq)]
317pub struct DerivativeEnclosure {
318    pub score: ScoreValueEnclosure,
319    pub derivative: ClosedInterval,
320    pub curvature: ClosedInterval,
321}
322
323/// A region whose unresolved stationary structure is immaterial at the
324/// representable resolution of its score.
325///
326/// `max_score_gap` is the width of the cell's exact score-value enclosure.
327/// `score_resolution` is the certified forward-error bound for comparing two
328/// point score evaluations. The search records this region only when
329/// `max_score_gap <= score_resolution`.
330#[derive(Clone, Copy, Debug, PartialEq)]
331pub struct ResolutionFlatRegion {
332    pub sample: ScoreSample,
333    pub bracket: ClosedInterval,
334    /// Exact score range over `bracket`.
335    pub score: ClosedInterval,
336    pub max_score_gap: f64,
337    pub score_resolution: f64,
338}
339
340/// One stationary point together with the final bracket that certifies its
341/// location.  The bracket width is no larger than the requested resolution,
342/// unless the point was represented exactly (a zero-width bracket).
343#[derive(Clone, Copy, Debug, PartialEq)]
344pub struct StationaryPoint {
345    pub sample: ScoreSample,
346    pub bracket: ClosedInterval,
347    /// Exact score range over `bracket` and endpoint evaluation resolution.
348    pub score: ScoreValueEnclosure,
349    /// Strict curvature enclosure that proved the derivative root unique.
350    ///
351    /// This may be tighter than a fresh enclosure on the final tiny bracket:
352    /// cancellation can erase a sign under subdivision even though the wider
353    /// parent certificate remains valid on every subset.
354    pub curvature: ClosedInterval,
355}
356
357/// Exact-value certificate for the representative selected by the rounded
358/// evaluator.
359#[derive(Clone, Copy, Debug, PartialEq)]
360pub struct GlobalScoreCertificate {
361    /// Exact score at the returned representative.
362    pub selected: ClosedInterval,
363    /// Outer range containing the exact global maximum.
364    pub maximum: ClosedInterval,
365    /// Outward bound on `global maximum - exact score(representative)`.
366    /// Repeated certificates of the same represented point contribute zero:
367    /// they name the same exact real value, rather than independent uncertain
368    /// quantities.
369    pub maximum_excess: f64,
370    /// Outward sum of the selected point evaluator's forward error and the
371    /// largest competing representative's forward error. Exact terminal
372    /// ranges remain separate in [`Self::maximum_excess`].
373    pub comparison_resolution: f64,
374}
375
376#[derive(Clone, Copy, Debug, PartialEq, Eq)]
377pub enum ScoreOptimumLocation {
378    LowerBoundary,
379    UpperBoundary,
380    Stationary(usize),
381    ResolutionFlat(usize),
382}
383
384/// A cell excluded from the global maximum by exact score ordering.
385///
386/// `score.hi < incumbent_lower` proves every exact score in `bracket` is below
387/// an exact score already attained at an evaluated point. Stationary structure
388/// inside the cell is therefore irrelevant to the global maximum, but the
389/// region is retained so that this branch-and-bound decision remains auditable.
390#[derive(Clone, Copy, Debug, PartialEq)]
391pub struct DominatedRegion {
392    pub bracket: ClosedInterval,
393    pub score: ScoreValueEnclosure,
394    pub incumbent_lower: f64,
395}
396
397/// Complete successful search result. Endpoints, isolated stationary points,
398/// resolution-flat regions, and exactly dominated regions are retained
399/// explicitly so every terminal proof is independently checkable by the
400/// caller.
401#[derive(Clone, Debug, PartialEq)]
402pub struct ScoreSearchResult {
403    pub optimum: ScoreSample,
404    pub location: ScoreOptimumLocation,
405    pub lower_boundary: ScoreSample,
406    pub upper_boundary: ScoreSample,
407    pub stationary_points: Vec<StationaryPoint>,
408    pub resolution_flat_regions: Vec<ResolutionFlatRegion>,
409    /// Pairwise-disjoint terminal cells. A binary tree with at most `B`
410    /// subdivisions has at most `B + 1` leaves, so this audit is bounded by
411    /// the same [`subdivision_budget`] as the traversal.
412    pub dominated_regions: Vec<DominatedRegion>,
413    pub value_certificate: GlobalScoreCertificate,
414}
415
416/// Failure of the generic certified search.
417#[derive(Debug)]
418pub enum ScoreSearchError<E> {
419    InvalidDomain {
420        lo: f64,
421        hi: f64,
422    },
423    InvalidResolution {
424        resolution: f64,
425    },
426    PointEvaluation {
427        x: f64,
428        source: E,
429    },
430    EnclosureEvaluation {
431        lo: f64,
432        hi: f64,
433        source: E,
434    },
435    NonFiniteSample {
436        sample: ScoreSample,
437    },
438    InvalidEnclosure {
439        lo: f64,
440        hi: f64,
441        enclosure: DerivativeEnclosure,
442    },
443    ScoreValueEnclosureMissesEndpoint {
444        lo: f64,
445        hi: f64,
446        endpoint: ScoreSample,
447        score: ScoreValueEnclosure,
448    },
449    DisjointEndpointEnclosure {
450        lo: f64,
451        hi: f64,
452        endpoint: ScoreSample,
453        endpoint_derivative: ClosedInterval,
454        enclosure: DerivativeEnclosure,
455    },
456    /// Independent interval-Newton images of a root that was already proved
457    /// unique have empty intersection. This is a contradiction between
458    /// certificates, not an unresolved search cell.
459    InconsistentRootEnclosure {
460        lo: f64,
461        hi: f64,
462        left_derivative: ClosedInterval,
463        right_derivative: ClosedInterval,
464        curvature: ClosedInterval,
465        left_newton: ClosedInterval,
466        right_newton: ClosedInterval,
467        point_newton: ClosedInterval,
468    },
469    /// Neither stationary exclusion/isolation nor score flatness could be
470    /// proved before the requested or floating-point abscissa-resolution
471    /// floor.
472    Unresolved {
473        lo: f64,
474        hi: f64,
475        requested_resolution: f64,
476        enclosure: DerivativeEnclosure,
477    },
478    /// The traversal asked for more cell subdivisions than
479    /// [`subdivision_budget`] allows for this domain and resolution. Reported
480    /// with the cell that was being split when the budget ran out, so the
481    /// caller can see WHERE the criterion stopped being decomposable, and with
482    /// that cell's enclosure, so the caller can see WHETHER a larger budget
483    /// could ever have helped: once the certified evaluation error reaches the
484    /// requested resolution, no amount of subdivision separates stationary
485    /// structure at that tolerance (#2614).
486    SubdivisionBudget {
487        lo: f64,
488        hi: f64,
489        cell_lo: f64,
490        cell_hi: f64,
491        requested_resolution: f64,
492        subdivisions: usize,
493        budget: usize,
494        depth_bound: u32,
495        enclosure: DerivativeEnclosure,
496    },
497}
498
499/// Total cell subdivisions a converging certified 1-D search may spend on
500/// `[lo, hi]` at `resolution`.
501///
502/// Two facts set the scale. First, no cell can be halved more than
503/// `D = ceil(log2((hi - lo) / resolution))` times before it is narrower than
504/// `resolution`, where the search already stops with
505/// [`ScoreSearchError::Unresolved`] — so `D` bounds the depth of the
506/// subdivision tree outright. Second, a search that is ISOLATING structure
507/// spends at most `D` subdivisions per cell it finally certifies, because each
508/// one halves the cell it is working in.
509///
510/// So the whole traversal costs at most `D` times the size of the certified
511/// decomposition, and the budget is that product with the decomposition
512/// allowed `2 D` cells — twice as many certified cells as the domain has
513/// resolvable binary levels. Measured on #2546's cascade: every terminating
514/// search on that surface spent 33–39 subdivisions at `D = 32`, i.e. about `D`,
515/// against a budget of `2 D² = 2048`; the non-terminating one passes 40 000
516/// with its bracket still halving cleanly at every node. The margin over the
517/// deepest currently-successful search is ~60x, so the budget is invisible to
518/// every search that converges and is reached in under a second by one that
519/// does not.
520///
521/// gam#2614 — that ~60x margin is NOT general, and the `2 D` cell allowance is
522/// the reason. The `D` factor is derived: no cell survives more than `D`
523/// halvings before it is narrower than `resolution`. The cell allowance is an
524/// assumption about how many cells a criterion's certified decomposition
525/// contains, which is exactly what the search cannot know in advance.
526///
527/// Read the calibration above again: spending about `D` subdivisions IN TOTAL,
528/// at `D` per certified cell, means that surface's decomposition was about ONE
529/// cell. The `2 D` allowance (64 cells at `D = 32`) was never exercised there,
530/// so the quoted margin is headroom over a single-cell case.
531///
532/// Measured since, at the same `D = 32`, which is why the multiplier below is 8
533/// and not 2. Bisected across the FULL `spline_scan` set:
534///
535/// ```text
536///   2 D² (  64 cells)  order_one_scan_matches_dense_random_walk_posterior refused
537///   4 D² ( 128 cells)  passes
538///   8 D² ( 256 cells)  passes          <- shipped
539/// 128 D² (4096 cells)  passes, and NO further test passes
540/// ```
541///
542/// That search is not going deeper than `D` per cell — the depth bound is a hard
543/// geometric fact. It isolates structure over a decomposition of 65–128 cells,
544/// wider than the `2 D` allowance anticipated, so against that surface the older
545/// "~60x margin" was negative. Nothing above `8 D²` buys another passing test.
546///
547/// A larger allowance does NOT repair the other scan refusals, and raising it
548/// past this point actively HIDES their cause. At `128 D²` the budget message
549/// disappears entirely and
550/// `state_snapshot_round_trips_predict_and_training_sample_size_bit_for_bit` —
551/// which exhausted the budget at both 2048 and 8192 — instead reports
552/// `OptimumResolutionFlat` on a bracket `2.15e-6` wide, about twice the endpoint
553/// `eval_err` of `~9.6e-7`. The budget was masking a score-RESOLUTION floor.
554/// Likewise `weighted_scan_dgp_2300_search_terminates_in_bounded_evaluations`
555/// fails identically at every multiplier tested, because its certificates carry
556/// `eval_err ~1e-6` while the search requests `resolution = 1.49e-8`.
557///
558/// So: three of the four `spline_scan` failures are evaluation-conditioning, not
559/// cell shortage, and no allowance reaches them. Do not raise this constant
560/// further expecting it to fix them — it converts a budget refusal into a
561/// resolution refusal and gains no coverage.
562///
563/// A degenerate domain still gets a budget of at least one subdivision: the
564/// bound is a backstop against unbounded breadth, never a refusal of the first
565/// split.
566///
567/// # The request, not the budget, is what actually binds (#2614, measured 0731)
568///
569/// Callers pass `f64::EPSILON.sqrt()` (`1.4901161193847656e-8`) as the requested
570/// resolution — a MACHINE constant. The achievable certified evaluation error is
571/// a property of the problem and varies by more than forty times between callers:
572///
573/// | caller | `evaluation_error` | `requested_resolution` | terminal bracket |
574/// |---|---|---|---|
575/// | `gam-solve` spline_scan | `9.741e-7` | `1.490e-8` | — |
576/// | `gam-predict` weighted scan | `2.302e-8` | `1.490e-8` | `~4.8e-8` ≈ 2 × eval_err |
577///
578/// In both the error EXCEEDS the request, and `gam-predict` terminates at almost
579/// exactly twice its own evaluation error — the floor you would predict, since
580/// inside that width the endpoint enclosures overlap and no comparison is
581/// decidable. In both the derivative enclosure straddles zero, so even the sign
582/// of the slope is undecidable there.
583///
584/// A fixed `sqrt(EPSILON)` request cannot be right for both. The resolution
585/// should be derived from the evaluator's certified error at the working point
586/// rather than pinned to a machine constant.
587///
588/// # That recommendation is NOT the repair for a budget refusal, measured
589///
590/// It was taken as one, and the discriminator says otherwise. On a rank-deficient
591/// cascade design (36 rows, 1725 columns, 33 modes on a 40.6-wide domain) that
592/// refused here at 8193/8192 subdivisions, the same search was run at four
593/// requested resolutions spanning five orders — `1.49e-8`, `1e-6`, `1e-4`,
594/// `1e-3` — and **every one refused**, the terminal cell merely walking down the
595/// domain (`-16.79`, `-18.51`, `-20.08`, `-20.59`) as the request coarsened.
596/// Matching the request to the evaluator's error bought nothing there.
597///
598/// What bound that search was the ENCLOSURE, one level down: the score's value
599/// range was a natural interval extension, first order in the cell width with
600/// constant `rank` (`33.0·w`, over six decades) against an exact `|f'|` of
601/// `1.15e-5`. `resolution_flat_region` reads that range, so no cell could be
602/// retired at any request. With the centred form in
603/// [`AffineRemlProfile::enclose`] the same design certifies in 0.4 s at every
604/// one of those four requests.
605///
606/// The two `spline_scan` refusals named above also both PASS now
607/// (`cargo test -p gam-solve --lib`, 1898 of 1901, and neither is among the
608/// three reds). So the table above stands as a measurement of a real
609/// mismatch — a machine constant is still the wrong source for a
610/// problem-dependent tolerance — but the failures it was written to explain are
611/// gone, and it should not be cited as the cause of a fresh one without a
612/// discriminator like the ladder above.
613pub fn subdivision_budget(lo: f64, hi: f64, resolution: f64) -> (usize, u32) {
614    let width = hi - lo;
615    if !(width.is_finite() && width > 0.0 && resolution.is_finite() && resolution > 0.0) {
616        return (1, 0);
617    }
618    let levels = (width / resolution).log2().ceil();
619    let depth_bound = if levels.is_finite() && levels >= 1.0 {
620        // `f64::MANTISSA_DIGITS`-scaled domains cannot exceed the exponent
621        // range, so the cast is saturating in practice and clamped in fact.
622        levels.min(u32::MAX as f64) as u32
623    } else {
624        1
625    };
626    let depth = depth_bound as usize;
627    (8 * depth * depth, depth_bound)
628}
629
630impl<E: fmt::Display> fmt::Display for ScoreSearchError<E> {
631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632        match self {
633            Self::InvalidDomain { lo, hi } => {
634                write!(f, "score search: invalid domain [{lo}, {hi}]")
635            }
636            Self::InvalidResolution { resolution } => {
637                write!(f, "score search: invalid resolution {resolution}")
638            }
639            Self::PointEvaluation { x, source } => {
640                write!(f, "score search: evaluation failed at {x}: {source}")
641            }
642            Self::EnclosureEvaluation { lo, hi, source } => write!(
643                f,
644                "score search: score/derivative enclosure failed on [{lo}, {hi}]: {source}"
645            ),
646            Self::NonFiniteSample { sample } => write!(
647                f,
648                "score search: non-finite jet at {} (value {}, derivative {}, curvature {}, third {})",
649                sample.x, sample.value, sample.derivative, sample.curvature, sample.third
650            ),
651            Self::InvalidEnclosure { lo, hi, enclosure } => write!(
652                f,
653                "score search: invalid score/derivative enclosure on [{lo}, {hi}]: {enclosure:?}"
654            ),
655            Self::ScoreValueEnclosureMissesEndpoint {
656                lo,
657                hi,
658                endpoint,
659                score,
660            } => write!(
661                f,
662                "score search: exact score range {:?} plus evaluator error {} on [{lo}, {hi}] misses the rounded endpoint value {} at {}",
663                score.value, score.evaluation_error, endpoint.value, endpoint.x
664            ),
665            Self::DisjointEndpointEnclosure {
666                lo,
667                hi,
668                endpoint,
669                endpoint_derivative,
670                enclosure,
671            } => write!(
672                f,
673                "score search: derivative enclosures on [{lo}, {hi}] and its endpoint {} are disjoint: endpoint range {endpoint_derivative:?}, cell {enclosure:?}; point estimate {endpoint:?}",
674                endpoint.x
675            ),
676            Self::InconsistentRootEnclosure {
677                lo,
678                hi,
679                left_derivative,
680                right_derivative,
681                curvature,
682                left_newton,
683                right_newton,
684                point_newton,
685            } => write!(
686                f,
687                "score search: interval-Newton certificates for the unique root on [{lo}, {hi}] \
688                 are inconsistent: left derivative {left_derivative:?}, right derivative \
689                 {right_derivative:?}, curvature {curvature:?}, left image {left_newton:?}, \
690                 right image {right_newton:?}, point image {point_newton:?}"
691            ),
692            Self::Unresolved {
693                lo,
694                hi,
695                requested_resolution,
696                enclosure,
697            } => {
698                // The enclosure already carries both numbers, but a reader has
699                // to notice the comparison themselves. State it: when the
700                // certified evaluation error has reached the requested
701                // resolution, the request is the defect, not the search (#2614).
702                let evaluation_error = enclosure.score.evaluation_error;
703                let verdict = if evaluation_error >= *requested_resolution {
704                    " -- the REQUEST is unsatisfiable: the certified evaluation error at this cell \
705                     already reaches the requested resolution, so no bracket narrower than about \
706                     twice that error is decidable and no additional subdivision can close it"
707                } else {
708                    ""
709                };
710                write!(
711                    f,
712                    "score search: stationary structure unresolved on [{lo}, {hi}] at requested \
713                     resolution {requested_resolution} (certified evaluation error \
714                     {evaluation_error:e}){verdict}: {enclosure:?}"
715                )
716            }
717            Self::SubdivisionBudget {
718                lo,
719                hi,
720                cell_lo,
721                cell_hi,
722                requested_resolution,
723                subdivisions,
724                budget,
725                depth_bound,
726                enclosure,
727            } => {
728                // Which of these two numbers is larger decides whether a bigger
729                // budget is a fix or a distraction. Reporting the budget alone
730                // sends the reader to the wrong lever (#2614).
731                let evaluation_error = enclosure.score.evaluation_error;
732                let verdict = if evaluation_error >= *requested_resolution {
733                    "a LARGER BUDGET CANNOT HELP -- the certified evaluation error already reaches \
734                     the requested resolution, so no subdivision separates stationary structure at \
735                     this tolerance; the resolution asked for is finer than the evaluator delivers"
736                } else {
737                    "the evaluation error is below the requested resolution, so this cell was still \
738                     separable and a larger budget may resolve it"
739                };
740                write!(
741                    f,
742                    "score search: {subdivisions} cell subdivisions on [{lo}, {hi}] at requested \
743                     resolution {requested_resolution} exceed the budget {budget} derived from this \
744                     domain's subdivision depth bound {depth_bound}; the criterion is still \
745                     undecomposable at [{cell_lo}, {cell_hi}], so it neither excludes nor isolates \
746                     stationary structure over a region the search can only enumerate. Certified \
747                     evaluation error at this cell is {evaluation_error:e} against requested \
748                     resolution {requested_resolution:e}: {verdict}"
749                )
750            }
751        }
752    }
753}
754
755impl<E: std::error::Error + 'static> std::error::Error for ScoreSearchError<E> {}
756
757#[derive(Clone, Copy)]
758struct SearchSample {
759    sample: ScoreSample,
760    point_enclosure: Option<DerivativeEnclosure>,
761}
762
763#[derive(Clone, Copy)]
764struct SearchNode {
765    left: SearchSample,
766    right: SearchSample,
767}
768
769#[derive(Clone, Copy)]
770struct TerminalScoreCandidate {
771    score: ScoreValueEnclosure,
772    /// Forward error of the rounded representative used to compare this
773    /// candidate with the selected representative. For a region certificate
774    /// this is kept separate from the exact range: the range bounds the
775    /// terminal maximum, while the error belongs to an actually evaluated
776    /// point.
777    comparison_error: f64,
778    /// Present only when the terminal maximum is the exact score at this
779    /// represented point. Region certificates deliberately carry `None` so
780    /// their possible improvement over a representative is retained.
781    point_x: Option<f64>,
782}
783
784impl TerminalScoreCandidate {
785    #[inline]
786    fn point(x: f64, score: ScoreValueEnclosure) -> Self {
787        Self {
788            score,
789            comparison_error: score.evaluation_error,
790            point_x: Some(x),
791        }
792    }
793
794    #[inline]
795    fn region(score: ScoreValueEnclosure, comparison_error: f64) -> Self {
796        Self {
797            score,
798            comparison_error,
799            point_x: None,
800        }
801    }
802}
803
804fn evaluate_sample<E, F>(x: f64, evaluate: &mut F) -> Result<SearchSample, ScoreSearchError<E>>
805where
806    F: FnMut(f64) -> Result<ScoreJet, E>,
807{
808    let jet = evaluate(x).map_err(|source| ScoreSearchError::PointEvaluation { x, source })?;
809    let sample = ScoreSample {
810        x,
811        value: jet.value,
812        derivative: jet.derivative,
813        curvature: jet.curvature,
814        third: jet.third,
815    };
816    if sample.value.is_finite()
817        && sample.derivative.is_finite()
818        && sample.curvature.is_finite()
819        && sample.third.is_finite()
820    {
821        Ok(SearchSample {
822            sample,
823            point_enclosure: None,
824        })
825    } else {
826        Err(ScoreSearchError::NonFiniteSample { sample })
827    }
828}
829
830fn checked_enclosure<E, F>(
831    left: ScoreSample,
832    right: ScoreSample,
833    enclose: &mut F,
834) -> Result<DerivativeEnclosure, ScoreSearchError<E>>
835where
836    F: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
837{
838    let lo = left.x;
839    let hi = right.x;
840    // The cell's endpoints are handed to the oracle as the SAMPLES the search
841    // already paid for, not as bare abscissae. An endpoint-anchored enclosure
842    // needs the endpoint jets and nothing else, so this is what makes it free:
843    // the oracle reads `left`/`right` instead of re-evaluating the criterion at
844    // two points it has already evaluated.
845    let enclosure = enclose(left, right)
846        .map_err(|source| ScoreSearchError::EnclosureEvaluation { lo, hi, source })?;
847    if !(enclosure.derivative.is_valid()
848        && enclosure.curvature.is_valid()
849        && enclosure.score.value.is_valid()
850        && enclosure.score.evaluation_error.is_finite()
851        && enclosure.score.evaluation_error >= 0.0)
852    {
853        return Err(ScoreSearchError::InvalidEnclosure { lo, hi, enclosure });
854    }
855    let score = enclosure.score;
856    let resolved_score = score.value.widen(score.evaluation_error);
857    for endpoint in [left, right] {
858        if !resolved_score.contains(endpoint.value) {
859            return Err(ScoreSearchError::ScoreValueEnclosureMissesEndpoint {
860                lo,
861                hi,
862                endpoint,
863                score,
864            });
865        }
866    }
867    Ok(enclosure)
868}
869
870/// Attach the oracle's exact score/derivative ranges at one represented point.
871///
872/// A nearest-rounded scalar jet is not required to lie inside an exact-real
873/// interval extension.  Instead, proof decisions use this degenerate-cell
874/// enclosure.  Both the point range and its parent-cell range contain the same
875/// exact endpoint derivative, so disjointness remains a valid contract check.
876fn certify_point<E, F>(
877    point: &mut SearchSample,
878    enclose: &mut F,
879) -> Result<DerivativeEnclosure, ScoreSearchError<E>>
880where
881    F: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
882{
883    let enclosure = match point.point_enclosure {
884        Some(enclosure) => enclosure,
885        None => {
886            let enclosure = checked_enclosure(point.sample, point.sample, enclose)?;
887            point.point_enclosure = Some(enclosure);
888            enclosure
889        }
890    };
891    Ok(enclosure)
892}
893
894fn certify_endpoint_derivative<E, F>(
895    point: &mut SearchSample,
896    cell_lo: f64,
897    cell_hi: f64,
898    cell: DerivativeEnclosure,
899    enclose: &mut F,
900) -> Result<ClosedInterval, ScoreSearchError<E>>
901where
902    F: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
903{
904    let endpoint_derivative = certify_point(point, enclose)?.derivative;
905    endpoint_derivative.intersection(cell.derivative).ok_or(
906        ScoreSearchError::DisjointEndpointEnclosure {
907            lo: cell_lo,
908            hi: cell_hi,
909            endpoint: point.sample,
910            endpoint_derivative,
911            enclosure: cell,
912        },
913    )
914}
915
916#[derive(Clone, Copy, PartialEq, Eq)]
917enum StrictSign {
918    Negative,
919    Positive,
920}
921
922#[inline]
923fn strict_sign(interval: ClosedInterval) -> Option<StrictSign> {
924    if interval.hi < 0.0 {
925        Some(StrictSign::Negative)
926    } else if interval.lo > 0.0 {
927        Some(StrictSign::Positive)
928    } else {
929        None
930    }
931}
932
933#[inline]
934fn is_exact_zero(interval: ClosedInterval) -> bool {
935    interval.lo == 0.0 && interval.hi == 0.0
936}
937
938fn certify_bracket_score<E, Eval, Enclose>(
939    bracket: ClosedInterval,
940    representative: SearchSample,
941    evaluate: &mut Eval,
942    enclose: &mut Enclose,
943) -> Result<ScoreValueEnclosure, ScoreSearchError<E>>
944where
945    Eval: FnMut(f64) -> Result<ScoreJet, E>,
946    Enclose: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
947{
948    if bracket.lo == bracket.hi {
949        let mut representative = representative;
950        return Ok(certify_point(&mut representative, enclose)?.score);
951    }
952    let left = if representative.sample.x == bracket.lo {
953        representative
954    } else {
955        evaluate_sample(bracket.lo, evaluate)?
956    };
957    let right = if representative.sample.x == bracket.hi {
958        representative
959    } else {
960        evaluate_sample(bracket.hi, evaluate)?
961    };
962    Ok(checked_enclosure(left.sample, right.sample, enclose)?.score)
963}
964
965enum UniqueRootRefinement {
966    Stationary(StationaryPoint),
967    ResolutionFlat {
968        region: ResolutionFlatRegion,
969        score: ScoreValueEnclosure,
970    },
971}
972
973/// Refine a UNIQUE derivative root.  The caller has already proved uniqueness
974/// by a curvature enclosure that excludes zero and supplied endpoint
975/// derivative enclosures of opposite sign.
976fn refine_unique_root<E, Eval, Enclose>(
977    mut left: SearchSample,
978    mut right: SearchSample,
979    resolution: f64,
980    enclosure: DerivativeEnclosure,
981    evaluate: &mut Eval,
982    enclose: &mut Enclose,
983) -> Result<UniqueRootRefinement, ScoreSearchError<E>>
984where
985    Eval: FnMut(f64) -> Result<ScoreJet, E>,
986    Enclose: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
987{
988    let bracket_lo = left.sample.x;
989    let bracket_hi = right.sample.x;
990    let mut left_derivative =
991        certify_endpoint_derivative(&mut left, bracket_lo, bracket_hi, enclosure, enclose)?;
992    let mut right_derivative =
993        certify_endpoint_derivative(&mut right, bracket_lo, bracket_hi, enclosure, enclose)?;
994    let curvature_sign =
995        strict_sign(enclosure.curvature).ok_or(ScoreSearchError::InvalidEnclosure {
996            lo: left.sample.x,
997            hi: right.sample.x,
998            enclosure,
999        })?;
1000    let increasing = curvature_sign == StrictSign::Positive;
1001    let expected_left_sign = if increasing {
1002        StrictSign::Negative
1003    } else {
1004        StrictSign::Positive
1005    };
1006    let expected_right_sign = if increasing {
1007        StrictSign::Positive
1008    } else {
1009        StrictSign::Negative
1010    };
1011    if strict_sign(left_derivative) != Some(expected_left_sign)
1012        || strict_sign(right_derivative) != Some(expected_right_sign)
1013    {
1014        return Err(ScoreSearchError::InvalidEnclosure {
1015            lo: left.sample.x,
1016            hi: right.sample.x,
1017            enclosure,
1018        });
1019    }
1020
1021    let mut force_midpoint = false;
1022    while right.sample.x - left.sample.x > resolution {
1023        let width = right.sample.x - left.sample.x;
1024        let midpoint = left.sample.x + 0.5 * width;
1025        if !(midpoint > left.sample.x && midpoint < right.sample.x) {
1026            return Err(ScoreSearchError::Unresolved {
1027                lo: left.sample.x,
1028                hi: right.sample.x,
1029                requested_resolution: resolution,
1030                enclosure,
1031            });
1032        }
1033
1034        // Newton is accepted only in the central half of the bracket.  Thus
1035        // every accepted point, Newton or midpoint, contracts the maintained
1036        // sign bracket by at least one quarter.  The loop has no iteration cap
1037        // because its geometric termination follows from this safeguard.
1038        // Point derivatives are refinement proposals, not proof currency. In
1039        // particular, a nonzero derivative can round to scalar zero. Rank the
1040        // Newton anchors by their certified point ranges so that false scalar
1041        // zeros cannot control either the refinement path or its eventual
1042        // endpoint representative.
1043        let base = if left_derivative.max_abs() <= right_derivative.max_abs() {
1044            left.sample
1045        } else {
1046            right.sample
1047        };
1048        let newton = if base.curvature != 0.0 {
1049            base.x - base.derivative / base.curvature
1050        } else {
1051            f64::NAN
1052        };
1053        let guard = 0.25 * width;
1054        let x = if !force_midpoint
1055            && newton.is_finite()
1056            && newton >= left.sample.x + guard
1057            && newton <= right.sample.x - guard
1058        {
1059            newton
1060        } else {
1061            midpoint
1062        };
1063        force_midpoint = false;
1064        if !(x > left.sample.x && x < right.sample.x) {
1065            return Err(ScoreSearchError::Unresolved {
1066                lo: left.sample.x,
1067                hi: right.sample.x,
1068                requested_resolution: resolution,
1069                enclosure,
1070            });
1071        }
1072        let mut sample = evaluate_sample(x, evaluate)?;
1073        let probe_x = sample.sample.x;
1074        let mut point_derivative = certify_endpoint_derivative(
1075            &mut sample,
1076            left.sample.x,
1077            right.sample.x,
1078            enclosure,
1079            enclose,
1080        )?;
1081        let mut root_curvature = enclosure.curvature;
1082        if !is_exact_zero(point_derivative) && strict_sign(point_derivative).is_none() {
1083            // A degenerate-cell derivative enclosure can remain wide when its
1084            // analytic formula contains cancellation. The two adjacent cell
1085            // extensions are independent exact evidence about their shared
1086            // endpoint. Intersect all three rather than discarding the cell
1087            // information after merely checking overlap.
1088            let left_cell = checked_enclosure(left.sample, sample.sample, enclose)?;
1089            let right_cell = checked_enclosure(sample.sample, right.sample, enclose)?;
1090            let left_probe_derivative = certify_endpoint_derivative(
1091                &mut sample,
1092                left.sample.x,
1093                probe_x,
1094                left_cell,
1095                enclose,
1096            )?;
1097            let right_probe_derivative = certify_endpoint_derivative(
1098                &mut sample,
1099                probe_x,
1100                right.sample.x,
1101                right_cell,
1102                enclose,
1103            )?;
1104            point_derivative = left_probe_derivative
1105                .intersection(right_probe_derivative)
1106                .ok_or(ScoreSearchError::DisjointEndpointEnclosure {
1107                    lo: left.sample.x,
1108                    hi: right.sample.x,
1109                    endpoint: sample.sample,
1110                    endpoint_derivative: left_probe_derivative,
1111                    enclosure: right_cell,
1112                })?;
1113            let child_curvature = left_cell.curvature.hull(right_cell.curvature);
1114            root_curvature = enclosure.curvature.intersection(child_curvature).ok_or(
1115                ScoreSearchError::InvalidEnclosure {
1116                    lo: left.sample.x,
1117                    hi: right.sample.x,
1118                    enclosure: right_cell,
1119                },
1120            )?;
1121        }
1122        if is_exact_zero(point_derivative) {
1123            let bracket = ClosedInterval::point(x);
1124            let score = certify_bracket_score(bracket, sample, evaluate, enclose)?;
1125            return Ok(UniqueRootRefinement::Stationary(StationaryPoint {
1126                sample: sample.sample,
1127                bracket,
1128                score,
1129                curvature: root_curvature,
1130            }));
1131        }
1132        if let Some(sign) = strict_sign(point_derivative) {
1133            match (increasing, sign) {
1134                (true, StrictSign::Negative) | (false, StrictSign::Positive) => {
1135                    left = sample;
1136                    left_derivative = point_derivative;
1137                }
1138                (true, StrictSign::Positive) | (false, StrictSign::Negative) => {
1139                    right = sample;
1140                    right_derivative = point_derivative;
1141                }
1142            }
1143            continue;
1144        }
1145
1146        // The point derivative is itself unresolved at f64 precision. The
1147        // mean-value theorem gives THREE independent interval-Newton images of
1148        // the same unique root: one from the point and one from each signed
1149        // endpoint. Intersect all three. Using only the cancellation-heavy
1150        // point image can leave the whole bracket unchanged even when the
1151        // endpoint images contract it decisively.
1152        //
1153        //   root = x₀ - f'(x₀) / f''(ξ),  ξ between x₀ and root.
1154        let bracket = ClosedInterval::new(left.sample.x, right.sample.x);
1155        let point_newton =
1156            ClosedInterval::point(x).sub(point_derivative.div_nonzero(root_curvature));
1157        let left_newton = ClosedInterval::point(left.sample.x)
1158            .sub(left_derivative.div_nonzero(enclosure.curvature));
1159        let right_newton = ClosedInterval::point(right.sample.x)
1160            .sub(right_derivative.div_nonzero(enclosure.curvature));
1161        let root = bracket
1162            .intersection(point_newton)
1163            .and_then(|root| root.intersection(left_newton))
1164            .and_then(|root| root.intersection(right_newton))
1165            .ok_or(ScoreSearchError::InconsistentRootEnclosure {
1166                lo: left.sample.x,
1167                hi: right.sample.x,
1168                left_derivative,
1169                right_derivative,
1170                curvature: enclosure.curvature,
1171                left_newton,
1172                right_newton,
1173                point_newton,
1174            })?;
1175        if root.hi - root.lo <= resolution {
1176            let score = certify_bracket_score(root, sample, evaluate, enclose)?;
1177            return Ok(UniqueRootRefinement::Stationary(StationaryPoint {
1178                sample: sample.sample,
1179                bracket: root,
1180                score,
1181                curvature: root_curvature,
1182            }));
1183        }
1184        if root.lo > left.sample.x || root.hi < right.sample.x {
1185            let mut new_left = if root.lo == sample.sample.x {
1186                sample
1187            } else {
1188                evaluate_sample(root.lo, evaluate)?
1189            };
1190            let mut new_right = if root.hi == sample.sample.x {
1191                sample
1192            } else {
1193                evaluate_sample(root.hi, evaluate)?
1194            };
1195            let contracted_enclosure =
1196                checked_enclosure(new_left.sample, new_right.sample, enclose)?;
1197            // The point certificate and the strict curvature range give a
1198            // second exact score extension over the contracted root image:
1199            //
1200            //   f(y) = f(x) + f'(x)(y-x) + 1/2 f''(ξ)(y-x)^2.
1201            //
1202            // Intersecting it with the endpoint-based cell extension removes
1203            // common cancellation noise from the score range. This does not
1204            // alter the evaluator error or invent a tolerance; it can only
1205            // reveal that the existing exact score diameter has reached that
1206            // existing comparison floor.
1207            let point_score = certify_point(&mut sample, enclose)?.score;
1208            let displacement = ClosedInterval::new(root.lo - x, root.hi - x);
1209            let taylor_score = point_score
1210                .value
1211                .add(point_derivative.mul(displacement))
1212                .add(root_curvature.mul(displacement.square()).scale(0.5));
1213            let tightened_score = contracted_enclosure
1214                .score
1215                .value
1216                .intersection(taylor_score)
1217                .ok_or(ScoreSearchError::InvalidEnclosure {
1218                    lo: root.lo,
1219                    hi: root.hi,
1220                    enclosure: contracted_enclosure,
1221                })?;
1222            let contracted_enclosure = DerivativeEnclosure {
1223                score: ScoreValueEnclosure {
1224                    value: tightened_score,
1225                    evaluation_error: contracted_enclosure.score.evaluation_error,
1226                },
1227                ..contracted_enclosure
1228            };
1229            if let Some(region) = resolution_flat_region(
1230                SearchNode {
1231                    left: new_left,
1232                    right: new_right,
1233                },
1234                contracted_enclosure,
1235            ) {
1236                return Ok(UniqueRootRefinement::ResolutionFlat {
1237                    region,
1238                    score: contracted_enclosure.score,
1239                });
1240            }
1241            let new_left_derivative = if new_left.sample.x == sample.sample.x {
1242                point_derivative
1243            } else {
1244                certify_endpoint_derivative(
1245                    &mut new_left,
1246                    root.lo,
1247                    root.hi,
1248                    contracted_enclosure,
1249                    enclose,
1250                )?
1251            };
1252            let new_right_derivative = if new_right.sample.x == sample.sample.x {
1253                point_derivative
1254            } else {
1255                certify_endpoint_derivative(
1256                    &mut new_right,
1257                    root.lo,
1258                    root.hi,
1259                    contracted_enclosure,
1260                    enclose,
1261                )?
1262            };
1263
1264            // A Newton image encloses the root; it does NOT prove that either
1265            // image boundary has a strict derivative sign. Retain each old
1266            // signed endpoint until its replacement independently certifies
1267            // the same oriented sign. This is the invariant that proves the
1268            // root unique on every subsequent iteration.
1269            let mut preserved_sign_contraction = false;
1270            if root.lo > left.sample.x {
1271                match strict_sign(new_left_derivative) {
1272                    Some(sign) if sign == expected_left_sign => {
1273                        left = new_left;
1274                        left_derivative = new_left_derivative;
1275                        preserved_sign_contraction = true;
1276                    }
1277                    Some(_) => {
1278                        return Err(ScoreSearchError::InvalidEnclosure {
1279                            lo: root.lo,
1280                            hi: root.hi,
1281                            enclosure: contracted_enclosure,
1282                        });
1283                    }
1284                    None => {}
1285                }
1286            }
1287            if root.hi < right.sample.x {
1288                match strict_sign(new_right_derivative) {
1289                    Some(sign) if sign == expected_right_sign => {
1290                        right = new_right;
1291                        right_derivative = new_right_derivative;
1292                        preserved_sign_contraction = true;
1293                    }
1294                    Some(_) => {
1295                        return Err(ScoreSearchError::InvalidEnclosure {
1296                            lo: root.lo,
1297                            hi: root.hi,
1298                            enclosure: contracted_enclosure,
1299                        });
1300                    }
1301                    None => {}
1302                }
1303            }
1304            if preserved_sign_contraction {
1305                continue;
1306            }
1307        }
1308        if x != midpoint {
1309            force_midpoint = true;
1310            continue;
1311        }
1312        return Err(ScoreSearchError::Unresolved {
1313            lo: left.sample.x,
1314            hi: right.sample.x,
1315            requested_resolution: resolution,
1316            enclosure,
1317        });
1318    }
1319
1320    let midpoint = left.sample.x + 0.5 * (right.sample.x - left.sample.x);
1321    let sample = if midpoint > left.sample.x && midpoint < right.sample.x {
1322        evaluate_sample(midpoint, evaluate)?.sample
1323    } else if left_derivative.max_abs() <= right_derivative.max_abs() {
1324        left.sample
1325    } else {
1326        right.sample
1327    };
1328    let bracket = ClosedInterval::new(left.sample.x, right.sample.x);
1329    let representative = SearchSample {
1330        sample,
1331        point_enclosure: None,
1332    };
1333    let score = certify_bracket_score(bracket, representative, evaluate, enclose)?;
1334    Ok(UniqueRootRefinement::Stationary(StationaryPoint {
1335        sample,
1336        bracket,
1337        score,
1338        curvature: enclosure.curvature,
1339    }))
1340}
1341
1342/// When subdivision lands exactly on a stationary abscissa, a rigorous point
1343/// interval can contain zero without proving the derivative is exactly zero.
1344/// Probe symmetrically within one requested-resolution bracket and accept the
1345/// shared endpoint only if those two certified derivative ranges have opposite
1346/// signs and the probe-cell curvature proves uniqueness.
1347fn isolate_shared_endpoint_root<E, Eval, Enclose>(
1348    endpoint: SearchSample,
1349    domain_lo: f64,
1350    domain_hi: f64,
1351    resolution: f64,
1352    evaluate: &mut Eval,
1353    enclose: &mut Enclose,
1354) -> Result<Option<StationaryPoint>, ScoreSearchError<E>>
1355where
1356    Eval: FnMut(f64) -> Result<ScoreJet, E>,
1357    Enclose: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
1358{
1359    let radius = 0.5 * resolution;
1360    let left_x = endpoint.sample.x - radius;
1361    let mut right_x = endpoint.sample.x + radius;
1362    if !(left_x >= domain_lo
1363        && right_x <= domain_hi
1364        && left_x < endpoint.sample.x
1365        && right_x > endpoint.sample.x)
1366    {
1367        return Ok(None);
1368    }
1369    while right_x - left_x > resolution {
1370        right_x = next_down(right_x);
1371    }
1372    if !(right_x > endpoint.sample.x && right_x - left_x <= resolution) {
1373        return Ok(None);
1374    }
1375
1376    let mut left = evaluate_sample(left_x, evaluate)?;
1377    let mut right = evaluate_sample(right_x, evaluate)?;
1378    let probe_enclosure = checked_enclosure(left.sample, right.sample, enclose)?;
1379    if probe_enclosure.curvature.contains_zero() {
1380        return Ok(None);
1381    }
1382    let left_derivative =
1383        certify_endpoint_derivative(&mut left, left_x, right_x, probe_enclosure, enclose)?;
1384    let right_derivative =
1385        certify_endpoint_derivative(&mut right, left_x, right_x, probe_enclosure, enclose)?;
1386    if strict_sign(left_derivative)
1387        .zip(strict_sign(right_derivative))
1388        .is_some_and(|(left_sign, right_sign)| left_sign != right_sign)
1389    {
1390        Ok(Some(StationaryPoint {
1391            sample: endpoint.sample,
1392            bracket: ClosedInterval::new(left_x, right_x),
1393            score: probe_enclosure.score,
1394            curvature: probe_enclosure.curvature,
1395        }))
1396    } else {
1397        Ok(None)
1398    }
1399}
1400
1401/// Prove that every score value in a cell is indistinguishable from one of its
1402/// endpoint samples at the point evaluator's certified f64 resolution.
1403///
1404/// If the exact score range is `[L, U]`, every pair of exact scores in the cell
1405/// differs by at most `U-L`. If each nearest-rounded point value has absolute
1406/// forward error at most `rho`, a comparison of two such values has uncertainty
1407/// at most `2 rho`. The cell is resolution-flat only when `U-L <= 2 rho`.
1408///
1409/// Both sides are expressed in score-value units and are invariant under
1410/// adding a constant to the objective. Derivative-evaluator error is
1411/// deliberately absent: integrating it would bound the error of a hypothetical
1412/// numerical quadrature, not the forward error of `ScoreJet::value`.
1413fn resolution_flat_region(
1414    node: SearchNode,
1415    enclosure: DerivativeEnclosure,
1416) -> Option<ResolutionFlatRegion> {
1417    let score = enclosure.score;
1418    let max_score_gap = if score.value.lo == score.value.hi {
1419        0.0
1420    } else {
1421        next_up(score.value.hi - score.value.lo)
1422    };
1423    let score_resolution = if score.evaluation_error == 0.0 {
1424        0.0
1425    } else {
1426        next_up(2.0 * score.evaluation_error)
1427    };
1428    if !(max_score_gap.is_finite() && score_resolution.is_finite()) {
1429        return None;
1430    }
1431    let sample = if node.right.sample.value > node.left.sample.value {
1432        node.right.sample
1433    } else {
1434        node.left.sample
1435    };
1436    (max_score_gap <= score_resolution).then_some(ResolutionFlatRegion {
1437        sample,
1438        bracket: ClosedInterval::new(node.left.sample.x, node.right.sample.x),
1439        score: score.value,
1440        max_score_gap,
1441        score_resolution,
1442    })
1443}
1444
1445/// Select a domain boundary only when one proof cell covers the whole domain
1446/// and its derivative has one strict sign throughout.
1447///
1448/// Rounded endpoint values may tie even when their exact-real ordering is
1449/// strict. A whole-domain monotonicity certificate resolves that ordering
1450/// directly. A proper subcell cannot select the global representative because
1451/// its endpoint has not been compared with maxima in the other cells.
1452fn certified_domain_boundary(
1453    node: &SearchNode,
1454    derivative_sign: StrictSign,
1455    domain_lo: f64,
1456    domain_hi: f64,
1457) -> Option<(ScoreSample, ScoreOptimumLocation)> {
1458    if node.left.sample.x != domain_lo || node.right.sample.x != domain_hi {
1459        return None;
1460    }
1461    Some(match derivative_sign {
1462        StrictSign::Positive => (node.right.sample, ScoreOptimumLocation::UpperBoundary),
1463        StrictSign::Negative => (node.left.sample, ScoreOptimumLocation::LowerBoundary),
1464    })
1465}
1466
1467/// Globally maximize a smooth score on `[lo, hi]` by certified stationary
1468/// isolation.
1469///
1470/// `evaluate` returns a nearest-rounded score jet at a point. `enclose(a, b)`
1471/// receives the cell's two ENDPOINT SAMPLES — the jets the search already
1472/// obtained from `evaluate` — and must return OUTER ranges containing the exact
1473/// first and second derivative at every point of `[a.x, b.x]`.
1474///
1475/// Handing the samples in (rather than the bare abscissae) is what keeps an
1476/// endpoint-anchored enclosure free: such an oracle is a Taylor pad around the
1477/// endpoint jets, so with the jets in hand it performs no criterion evaluation
1478/// of its own. An oracle whose enclosure is a genuine interval extension may
1479/// ignore the jets and use `a.x`/`b.x`.
1480///
1481/// The scalar derivatives are never treated as proofs: when an endpoint sign
1482/// matters, the search asks `enclose(a, a)` for its exact derivative range.
1483/// The point and parent-cell ranges must overlap, but the exact-real parent
1484/// range is intentionally not required to contain a separately rounded scalar
1485/// estimate.
1486///
1487/// A successful return means every cell was derivative-excluded, stationary-
1488/// isolated to `resolution`, proved score-flat at the local representable value
1489/// resolution, or proved exactly dominated by an already attained point score.
1490/// Any cell that satisfies none of those conditions produces
1491/// [`ScoreSearchError::Unresolved`].
1492///
1493/// The traversal is bounded by [`subdivision_budget`]. The per-cell resolution
1494/// floor bounds the DEPTH of the subdivision and never its BREADTH, and those
1495/// are different failures. A criterion that certifies NOTHING bottoms out on the
1496/// floor after `D` subdivisions and is already typed
1497/// [`ScoreSearchError::Unresolved`]. The unbounded case is the one where cells
1498/// DO certify, at widths far above the floor, and there are simply too many of
1499/// them: a criterion whose derivative and curvature enclosures both straddle
1500/// zero over a wide region excludes no cell by a sign and isolates no root, so
1501/// every cell it reaches is split until its score range collapses under the
1502/// evaluator's own error — and the leaf count of that tree is exponential in the
1503/// depth, 2^32 cells on a 58-wide log-λ domain at `sqrt(eps)` resolution, which
1504/// is non-termination rather than slowness (#2546). Exceeding the budget is
1505/// [`ScoreSearchError::SubdivisionBudget`], a statement about the CRITERION and
1506/// not about the machine: the search was asked to certify more cells than a
1507/// converging 1-D decomposition at this resolution consists of.
1508pub fn maximize_score_1d<E, Eval, Enclose>(
1509    lo: f64,
1510    hi: f64,
1511    resolution: f64,
1512    mut evaluate: Eval,
1513    mut enclose: Enclose,
1514) -> Result<ScoreSearchResult, ScoreSearchError<E>>
1515where
1516    Eval: FnMut(f64) -> Result<ScoreJet, E>,
1517    Enclose: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
1518{
1519    if !(lo.is_finite() && hi.is_finite() && lo <= hi && (hi - lo).is_finite()) {
1520        return Err(ScoreSearchError::InvalidDomain { lo, hi });
1521    }
1522    if !(resolution.is_finite() && resolution > 0.0) {
1523        return Err(ScoreSearchError::InvalidResolution { resolution });
1524    }
1525
1526    let mut lower_boundary = evaluate_sample(lo, &mut evaluate)?;
1527    if lo == hi {
1528        let score =
1529            checked_enclosure(lower_boundary.sample, lower_boundary.sample, &mut enclose)?.score;
1530        return Ok(ScoreSearchResult {
1531            optimum: lower_boundary.sample,
1532            location: ScoreOptimumLocation::LowerBoundary,
1533            lower_boundary: lower_boundary.sample,
1534            upper_boundary: lower_boundary.sample,
1535            stationary_points: Vec::new(),
1536            resolution_flat_regions: Vec::new(),
1537            dominated_regions: Vec::new(),
1538            value_certificate: GlobalScoreCertificate {
1539                selected: score.value,
1540                maximum: score.value,
1541                maximum_excess: 0.0,
1542                comparison_resolution: 0.0,
1543            },
1544        });
1545    }
1546    let mut upper_boundary = evaluate_sample(hi, &mut evaluate)?;
1547    let lower_boundary_score = certify_point(&mut lower_boundary, &mut enclose)?.score;
1548    let upper_boundary_score = certify_point(&mut upper_boundary, &mut enclose)?.score;
1549    let mut incumbent_lower = lower_boundary_score
1550        .value
1551        .lo
1552        .max(upper_boundary_score.value.lo);
1553    let (mut optimum, mut location) = if upper_boundary.sample.value > lower_boundary.sample.value {
1554        (upper_boundary.sample, ScoreOptimumLocation::UpperBoundary)
1555    } else {
1556        (lower_boundary.sample, ScoreOptimumLocation::LowerBoundary)
1557    };
1558
1559    let (budget, depth_bound) = subdivision_budget(lo, hi, resolution);
1560    let mut subdivisions = 0usize;
1561    let mut stationary_points = Vec::<StationaryPoint>::new();
1562    let mut resolution_flat_regions = Vec::<ResolutionFlatRegion>::new();
1563    let mut dominated_regions = Vec::<DominatedRegion>::new();
1564    // Boundary points are unconditional feasible incumbents. Keeping both in
1565    // the terminal ledger makes every later dominance decision independent of
1566    // which rounded boundary value happened to initialize `optimum`.
1567    let mut terminal_maxima = vec![
1568        TerminalScoreCandidate::point(lower_boundary.sample.x, lower_boundary_score),
1569        TerminalScoreCandidate::point(upper_boundary.sample.x, upper_boundary_score),
1570    ];
1571    let mut stack = vec![SearchNode {
1572        left: lower_boundary,
1573        right: upper_boundary,
1574    }];
1575    while let Some(mut node) = stack.pop() {
1576        let mathematical_enclosure =
1577            checked_enclosure(node.left.sample, node.right.sample, &mut enclose)?;
1578        let enclosure = mathematical_enclosure;
1579        if enclosure.score.value.hi < incumbent_lower {
1580            dominated_regions.push(DominatedRegion {
1581                bracket: ClosedInterval::new(node.left.sample.x, node.right.sample.x),
1582                score: enclosure.score,
1583                incumbent_lower,
1584            });
1585            continue;
1586        }
1587        if !enclosure.derivative.contains_zero() {
1588            let derivative_sign = if enclosure.derivative.lo > 0.0 {
1589                StrictSign::Positive
1590            } else {
1591                StrictSign::Negative
1592            };
1593            if let Some((proven_optimum, proven_location)) =
1594                certified_domain_boundary(&node, derivative_sign, lo, hi)
1595            {
1596                optimum = proven_optimum;
1597                location = proven_location;
1598            }
1599            let endpoint = match derivative_sign {
1600                StrictSign::Positive => &mut node.right,
1601                StrictSign::Negative => &mut node.left,
1602            };
1603            let endpoint_score = certify_point(endpoint, &mut enclose)?.score;
1604            incumbent_lower = incumbent_lower.max(endpoint_score.value.lo);
1605            terminal_maxima.push(TerminalScoreCandidate::point(
1606                endpoint.sample.x,
1607                endpoint_score,
1608            ));
1609            continue;
1610        }
1611
1612        let monotone = !enclosure.curvature.contains_zero();
1613        if monotone {
1614            let node_lo = node.left.sample.x;
1615            let node_hi = node.right.sample.x;
1616            let left_derivative = certify_endpoint_derivative(
1617                &mut node.left,
1618                node_lo,
1619                node_hi,
1620                enclosure,
1621                &mut enclose,
1622            )?;
1623            let right_derivative = certify_endpoint_derivative(
1624                &mut node.right,
1625                node_lo,
1626                node_hi,
1627                enclosure,
1628                &mut enclose,
1629            )?;
1630            let left_sign = strict_sign(left_derivative);
1631            let right_sign = strict_sign(right_derivative);
1632            let mut root_flat = None;
1633            let stationary = if is_exact_zero(left_derivative) {
1634                let score = certify_point(&mut node.left, &mut enclose)?.score;
1635                Some(StationaryPoint {
1636                    sample: node.left.sample,
1637                    bracket: ClosedInterval::point(node.left.sample.x),
1638                    score,
1639                    curvature: enclosure.curvature,
1640                })
1641            } else if is_exact_zero(right_derivative) {
1642                let score = certify_point(&mut node.right, &mut enclose)?.score;
1643                Some(StationaryPoint {
1644                    sample: node.right.sample,
1645                    bracket: ClosedInterval::point(node.right.sample.x),
1646                    score,
1647                    curvature: enclosure.curvature,
1648                })
1649            } else if left_sign
1650                .zip(right_sign)
1651                .is_some_and(|(left_sign, right_sign)| left_sign != right_sign)
1652            {
1653                match refine_unique_root(
1654                    node.left,
1655                    node.right,
1656                    resolution,
1657                    enclosure,
1658                    &mut evaluate,
1659                    &mut enclose,
1660                )? {
1661                    UniqueRootRefinement::Stationary(stationary) => Some(stationary),
1662                    UniqueRootRefinement::ResolutionFlat { region, score } => {
1663                        root_flat = Some((region, score));
1664                        None
1665                    }
1666                }
1667            } else if left_sign.is_none() {
1668                isolate_shared_endpoint_root(
1669                    node.left,
1670                    lo,
1671                    hi,
1672                    resolution,
1673                    &mut evaluate,
1674                    &mut enclose,
1675                )?
1676            } else if right_sign.is_none() {
1677                isolate_shared_endpoint_root(
1678                    node.right,
1679                    lo,
1680                    hi,
1681                    resolution,
1682                    &mut evaluate,
1683                    &mut enclose,
1684                )?
1685            } else {
1686                None
1687            };
1688
1689            if let Some((flat, score)) = root_flat {
1690                let index = resolution_flat_regions.len();
1691                if flat.sample.value > optimum.value {
1692                    optimum = flat.sample;
1693                    location = ScoreOptimumLocation::ResolutionFlat(index);
1694                }
1695                let mut representative = SearchSample {
1696                    sample: flat.sample,
1697                    point_enclosure: None,
1698                };
1699                let representative_score = certify_point(&mut representative, &mut enclose)?.score;
1700                incumbent_lower = incumbent_lower.max(representative_score.value.lo);
1701                terminal_maxima.push(TerminalScoreCandidate::region(
1702                    score,
1703                    representative_score
1704                        .evaluation_error
1705                        .max(score.evaluation_error),
1706                ));
1707                resolution_flat_regions.push(flat);
1708                continue;
1709            }
1710
1711            if let Some(stationary) = stationary {
1712                let mut representative = SearchSample {
1713                    sample: stationary.sample,
1714                    point_enclosure: None,
1715                };
1716                let representative_score = certify_point(&mut representative, &mut enclose)?.score;
1717                incumbent_lower = incumbent_lower.max(representative_score.value.lo);
1718                // Two adjacent certified cells can report the same exact root
1719                // when it lies on their common boundary.  Preserve one copy.
1720                let duplicate = stationary_points
1721                    .last()
1722                    .is_some_and(|previous| previous.sample.x == stationary.sample.x);
1723                if !duplicate {
1724                    let index = stationary_points.len();
1725                    if stationary.sample.value > optimum.value {
1726                        optimum = stationary.sample;
1727                        location = ScoreOptimumLocation::Stationary(index);
1728                    }
1729                    stationary_points.push(stationary);
1730                }
1731                if enclosure.curvature.hi < 0.0 {
1732                    let score = stationary.score;
1733                    terminal_maxima.push(if stationary.bracket.lo == stationary.bracket.hi {
1734                        TerminalScoreCandidate::point(stationary.sample.x, score)
1735                    } else {
1736                        TerminalScoreCandidate::region(
1737                            score,
1738                            representative_score
1739                                .evaluation_error
1740                                .max(score.evaluation_error),
1741                        )
1742                    });
1743                } else {
1744                    let left_score = certify_point(&mut node.left, &mut enclose)?.score;
1745                    let right_score = certify_point(&mut node.right, &mut enclose)?.score;
1746                    incumbent_lower = incumbent_lower
1747                        .max(left_score.value.lo)
1748                        .max(right_score.value.lo);
1749                    terminal_maxima.push(TerminalScoreCandidate::point(
1750                        node.left.sample.x,
1751                        left_score,
1752                    ));
1753                    terminal_maxima.push(TerminalScoreCandidate::point(
1754                        node.right.sample.x,
1755                        right_score,
1756                    ));
1757                }
1758                continue;
1759            }
1760
1761            // Definite equal endpoint signs plus strict monotonicity exclude a
1762            // root.  An endpoint range that straddles zero is not silently
1763            // replaced by the rounded point sign; it proceeds to the value-flat
1764            // proof or subdivision below.
1765            if let Some((left_sign, right_sign)) = left_sign.zip(right_sign)
1766                && left_sign == right_sign
1767            {
1768                if let Some((proven_optimum, proven_location)) =
1769                    certified_domain_boundary(&node, left_sign, lo, hi)
1770                {
1771                    optimum = proven_optimum;
1772                    location = proven_location;
1773                }
1774                let endpoint = match left_sign {
1775                    StrictSign::Positive => &mut node.right,
1776                    StrictSign::Negative => &mut node.left,
1777                };
1778                let endpoint_score = certify_point(endpoint, &mut enclose)?.score;
1779                incumbent_lower = incumbent_lower.max(endpoint_score.value.lo);
1780                terminal_maxima.push(TerminalScoreCandidate::point(
1781                    endpoint.sample.x,
1782                    endpoint_score,
1783                ));
1784                continue;
1785            }
1786        }
1787
1788        if let Some(flat) = resolution_flat_region(node, mathematical_enclosure) {
1789            let index = resolution_flat_regions.len();
1790            if flat.sample.value > optimum.value {
1791                optimum = flat.sample;
1792                location = ScoreOptimumLocation::ResolutionFlat(index);
1793            }
1794            let mut representative = SearchSample {
1795                sample: flat.sample,
1796                point_enclosure: None,
1797            };
1798            let representative_score = certify_point(&mut representative, &mut enclose)?.score;
1799            incumbent_lower = incumbent_lower.max(representative_score.value.lo);
1800            terminal_maxima.push(TerminalScoreCandidate::region(
1801                enclosure.score,
1802                representative_score
1803                    .evaluation_error
1804                    .max(enclosure.score.evaluation_error),
1805            ));
1806            resolution_flat_regions.push(flat);
1807            continue;
1808        }
1809
1810        let width = node.right.sample.x - node.left.sample.x;
1811        let midpoint = node.left.sample.x + 0.5 * width;
1812        if width <= resolution || !(midpoint > node.left.sample.x && midpoint < node.right.sample.x)
1813        {
1814            return Err(ScoreSearchError::Unresolved {
1815                lo: node.left.sample.x,
1816                hi: node.right.sample.x,
1817                requested_resolution: resolution,
1818                enclosure,
1819            });
1820        }
1821        subdivisions += 1;
1822        if subdivisions > budget {
1823            return Err(ScoreSearchError::SubdivisionBudget {
1824                lo,
1825                hi,
1826                cell_lo: node.left.sample.x,
1827                cell_hi: node.right.sample.x,
1828                requested_resolution: resolution,
1829                subdivisions,
1830                budget,
1831                depth_bound,
1832                enclosure,
1833            });
1834        }
1835        let middle = evaluate_sample(midpoint, &mut evaluate)?;
1836        // Right first, then left: the LIFO traversal emits stationary points
1837        // in ascending x, which makes exact-boundary de-duplication stable.
1838        stack.push(SearchNode {
1839            left: middle,
1840            right: node.right,
1841        });
1842        stack.push(SearchNode {
1843            left: node.left,
1844            right: middle,
1845        });
1846    }
1847
1848    let mut selected_sample = SearchSample {
1849        sample: optimum,
1850        point_enclosure: None,
1851    };
1852    let selected_score = certify_point(&mut selected_sample, &mut enclose)?.score;
1853    let global_lower = terminal_maxima
1854        .iter()
1855        .map(|candidate| candidate.score.value.lo)
1856        .fold(selected_score.value.lo, f64::max);
1857    let global_upper = terminal_maxima
1858        .iter()
1859        .map(|candidate| candidate.score.value.hi)
1860        .fold(selected_score.value.hi, f64::max);
1861    let candidate_evaluation_error = terminal_maxima
1862        .iter()
1863        .filter(|candidate| candidate.point_x != Some(optimum.x))
1864        .map(|candidate| candidate.comparison_error)
1865        .fold(0.0_f64, f64::max);
1866    let maximum_excess = terminal_maxima
1867        .iter()
1868        .filter(|candidate| candidate.point_x != Some(optimum.x))
1869        .map(|candidate| {
1870            if candidate.score.value.hi <= selected_score.value.lo {
1871                0.0
1872            } else {
1873                next_up(candidate.score.value.hi - selected_score.value.lo)
1874            }
1875        })
1876        .fold(0.0_f64, f64::max);
1877    let comparison_resolution =
1878        add_nonnegative_upward(selected_score.evaluation_error, candidate_evaluation_error);
1879
1880    Ok(ScoreSearchResult {
1881        optimum,
1882        location,
1883        lower_boundary: lower_boundary.sample,
1884        upper_boundary: upper_boundary.sample,
1885        stationary_points,
1886        resolution_flat_regions,
1887        dominated_regions,
1888        value_certificate: GlobalScoreCertificate {
1889            selected: selected_score.value,
1890            maximum: ClosedInterval::new(global_lower, global_upper),
1891            maximum_excess,
1892            comparison_resolution,
1893        },
1894    })
1895}
1896
1897/// Repeat a certified global score search until its exact winning value is
1898/// orderable at the evaluator's certified comparison resolution.
1899///
1900/// Location resolution and value resolution are different proof currencies:
1901/// isolating every stationary point to `initial_resolution` can still leave
1902/// the winning candidate's exact score range wider than the point evaluator's
1903/// forward-error comparison permits. Each pass here independently rebuilds
1904/// the complete global certificate at a smaller location target. The observed
1905/// ratio between maximum excess and comparison resolution is only a refinement
1906/// strategy; it is never used as acceptance evidence.
1907///
1908/// There is no retry cap or acceptance fallback. Each retry contracts the
1909/// target by at least one binary subdivision. If the next target is no longer
1910/// representable, or the oracle cannot resolve stationary structure at that
1911/// finer target, or the finer traversal exceeds its [`subdivision_budget`], the
1912/// last complete certificate is returned unchanged so the caller can issue its
1913/// domain-specific typed refusal.
1914pub fn maximize_score_1d_value_ordered<E, Eval, Enclose>(
1915    lo: f64,
1916    hi: f64,
1917    initial_resolution: f64,
1918    mut evaluate: Eval,
1919    mut enclose: Enclose,
1920) -> Result<ScoreSearchResult, ScoreSearchError<E>>
1921where
1922    Eval: FnMut(f64) -> Result<ScoreJet, E>,
1923    Enclose: FnMut(ScoreSample, ScoreSample) -> Result<DerivativeEnclosure, E>,
1924{
1925    let mut resolution = initial_resolution;
1926    let mut search = maximize_score_1d(lo, hi, resolution, &mut evaluate, &mut enclose)?;
1927    loop {
1928        let certificate = search.value_certificate;
1929        if certificate.maximum_excess <= certificate.comparison_resolution {
1930            return Ok(search);
1931        }
1932        let binary_refinement = 0.5 * resolution;
1933        let value_directed_refinement = if certificate.comparison_resolution > 0.0 {
1934            resolution * (certificate.comparison_resolution / certificate.maximum_excess)
1935        } else {
1936            binary_refinement
1937        };
1938        let next_resolution = binary_refinement.min(value_directed_refinement);
1939        if !(next_resolution.is_finite() && next_resolution > 0.0 && next_resolution < resolution) {
1940            return Ok(search);
1941        }
1942        match maximize_score_1d(lo, hi, next_resolution, &mut evaluate, &mut enclose) {
1943            Ok(refined) => {
1944                search = refined;
1945                resolution = next_resolution;
1946            }
1947            // A finer requested location is optional proof strengthening.
1948            // Preserve the last complete global certificate when the oracle
1949            // cannot resolve stationary structure at that finer currency; the
1950            // caller will still reject it if its values remain unordered.
1951            //
1952            // A retry that exhausts its subdivision budget is the same kind of
1953            // outcome and ENDS the loop rather than contracting again: each
1954            // retry's budget grows as its target shrinks, so continuing past
1955            // one exhaustion would pay a whole traversal per halving down to
1956            // the denormal floor — a second unbounded axis (#2546).
1957            Err(
1958                ScoreSearchError::Unresolved { .. } | ScoreSearchError::SubdivisionBudget { .. },
1959            ) => return Ok(search),
1960            Err(error) => return Err(error),
1961        }
1962    }
1963}
1964
1965/// Static validation or evaluation failure for [`AffineRemlProfile`].
1966#[derive(Clone, Copy, Debug, PartialEq)]
1967pub enum AffineRemlError {
1968    EmptyModes,
1969    EmptyResponses,
1970    ShapeMismatch {
1971        gram_modes: usize,
1972        penalty_modes: usize,
1973        projected_rhs_squared: usize,
1974        responses: usize,
1975    },
1976    InvalidMode {
1977        index: usize,
1978        gram: f64,
1979        penalty: f64,
1980    },
1981    InvalidProjectedSquare {
1982        index: usize,
1983        value: f64,
1984    },
1985    InvalidResponseEnergy {
1986        output: usize,
1987        value: f64,
1988    },
1989    ZeroLambdaResidualUnavailable {
1990        output: usize,
1991    },
1992    InvalidResidualDof {
1993        value: f64,
1994    },
1995    InvalidLogdetConstant {
1996        value: f64,
1997    },
1998    RankMismatch {
1999        supplied: usize,
2000        inferred: usize,
2001    },
2002    InvalidLogLambda {
2003        value: f64,
2004    },
2005    InvalidLogLambdaInterval {
2006        lo: f64,
2007        hi: f64,
2008    },
2009    ElementaryEnclosureUnavailable {
2010        function: &'static str,
2011        lo: f64,
2012        hi: f64,
2013    },
2014    NonPositiveMode {
2015        index: usize,
2016        log_lambda: f64,
2017        value: f64,
2018    },
2019    NonPositiveResidual {
2020        output: usize,
2021        log_lambda: f64,
2022        value: f64,
2023    },
2024    NonPositiveResidualInterval {
2025        output: usize,
2026        lo: f64,
2027        hi: f64,
2028        lower_bound: f64,
2029    },
2030    InconsistentResidualEnclosures {
2031        output: usize,
2032        lo: f64,
2033        hi: f64,
2034        direct: ClosedInterval,
2035        complement: ClosedInterval,
2036    },
2037    UnboundedScoreEvaluationError {
2038        lo: f64,
2039        hi: f64,
2040        error: f64,
2041    },
2042}
2043
2044impl fmt::Display for AffineRemlError {
2045    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2046        match self {
2047            Self::EmptyModes => write!(f, "affine REML profile has no modes"),
2048            Self::EmptyResponses => write!(f, "affine REML profile has no responses"),
2049            Self::ShapeMismatch {
2050                gram_modes,
2051                penalty_modes,
2052                projected_rhs_squared,
2053                responses,
2054            } => write!(
2055                f,
2056                "affine REML profile shape mismatch: gram {gram_modes}, penalty {penalty_modes}, projected squares {projected_rhs_squared}, responses {responses}"
2057            ),
2058            Self::InvalidMode {
2059                index,
2060                gram,
2061                penalty,
2062            } => write!(
2063                f,
2064                "affine REML mode {index} must have finite nonnegative (g,s), not both zero; got ({gram}, {penalty})"
2065            ),
2066            Self::InvalidProjectedSquare { index, value } => write!(
2067                f,
2068                "affine REML projected square {index} must be finite and nonnegative, got {value}"
2069            ),
2070            Self::InvalidResponseEnergy { output, value } => write!(
2071                f,
2072                "affine REML response energy {output} must be finite and nonnegative, got {value}"
2073            ),
2074            Self::ZeroLambdaResidualUnavailable { output } => write!(
2075                f,
2076                "affine REML could not certify the zero-smoothing residual for response {output}"
2077            ),
2078            Self::InvalidResidualDof { value } => {
2079                write!(
2080                    f,
2081                    "affine REML residual dof must be finite and positive, got {value}"
2082                )
2083            }
2084            Self::InvalidLogdetConstant { value } => write!(
2085                f,
2086                "affine REML log-determinant constant must be finite, got {value}"
2087            ),
2088            Self::RankMismatch { supplied, inferred } => write!(
2089                f,
2090                "affine REML determinant rank {supplied} disagrees with {inferred} positive penalty modes"
2091            ),
2092            Self::InvalidLogLambda { value } => {
2093                write!(f, "affine REML invalid log lambda {value}")
2094            }
2095            Self::InvalidLogLambdaInterval { lo, hi } => {
2096                write!(f, "affine REML invalid log-lambda interval [{lo}, {hi}]")
2097            }
2098            Self::ElementaryEnclosureUnavailable { function, lo, hi } => write!(
2099                f,
2100                "affine REML has no finite source-derived {function} enclosure on [{lo}, {hi}]"
2101            ),
2102            Self::NonPositiveMode {
2103                index,
2104                log_lambda,
2105                value,
2106            } => write!(
2107                f,
2108                "affine REML mode {index} is nonpositive at log lambda {log_lambda}: {value}"
2109            ),
2110            Self::NonPositiveResidual {
2111                output,
2112                log_lambda,
2113                value,
2114            } => write!(
2115                f,
2116                "affine REML residual {output} is nonpositive at log lambda {log_lambda}: {value}"
2117            ),
2118            Self::NonPositiveResidualInterval {
2119                output,
2120                lo,
2121                hi,
2122                lower_bound,
2123            } => write!(
2124                f,
2125                "affine REML residual {output} is not certified positive on [{lo}, {hi}] (lower bound {lower_bound})"
2126            ),
2127            Self::InconsistentResidualEnclosures {
2128                output,
2129                lo,
2130                hi,
2131                direct,
2132                complement,
2133            } => write!(
2134                f,
2135                "affine REML residual {output} has disjoint direct {direct:?} and zero-smoothing-complement {complement:?} enclosures on [{lo}, {hi}]"
2136            ),
2137            Self::UnboundedScoreEvaluationError { lo, hi, error } => write!(
2138                f,
2139                "affine REML score evaluator has no finite forward-error bound on [{lo}, {hi}] (bound {error})"
2140            ),
2141        }
2142    }
2143}
2144
2145impl std::error::Error for AffineRemlError {}
2146
2147/// Spectral REML/profile score with affine diagonal modes
2148/// `h_i(lambda) = g_i + lambda s_i`.
2149///
2150/// `projected_rhs_squared` is RESPONSE-MAJOR: entry `(d, i)` is stored at
2151/// `d * n_modes + i`.  The score is
2152///
2153/// `-1/2 { D [logdet_constant + sum log h_i - rank log(lambda)]
2154///          + residual_dof * sum_d log(R_d / residual_dof) }`,
2155///
2156/// where `R_d = response_energy[d] - sum_i q[d,i] / h_i`.
2157#[derive(Clone, Debug)]
2158pub struct AffineRemlProfile<'a> {
2159    gram_modes: &'a [f64],
2160    penalty_modes: &'a [f64],
2161    projected_rhs_squared: &'a [f64],
2162    response_energy: &'a [f64],
2163    /// Exact-real residuals on the finite part of the zero-smoothing face,
2164    ///
2165    /// `response_energy[d] - sum_{i:g_i>0} q[d,i] / g_i`.
2166    ///
2167    /// These invariants are computed once with an error-free leading sum and
2168    /// FMA-certified division corrections. Re-forming them independently in
2169    /// every interval evaluation loses the small Schur complement to the
2170    /// rounding scale of its O(energy) operands.
2171    zero_lambda_residual: Vec<ClosedInterval>,
2172    residual_dof: f64,
2173    logdet_constant: f64,
2174}
2175
2176/// O(n) exact-leading accumulator.
2177///
2178/// `leading + correction` encloses the exact sum of every value submitted so
2179/// far. `leading` follows the ordinary binary64 accumulation path. Knuth's
2180/// TwoSum identity moves each discarded low part into `correction`, whose
2181/// directed interval accumulation never again mixes it with an O(energy)
2182/// operand. This is the fixed-size analogue of a floating-point expansion:
2183/// exact proof information, without an O(n²) expansion walk or arbitrary
2184/// precision dependency.
2185struct CertifiedCompensatedSum {
2186    leading: f64,
2187    correction: ClosedInterval,
2188}
2189
2190impl CertifiedCompensatedSum {
2191    fn new(value: f64) -> Self {
2192        Self {
2193            leading: value,
2194            correction: ClosedInterval::point(0.0),
2195        }
2196    }
2197
2198    /// Add one exact binary64 value, retaining the exact TwoSum residual.
2199    fn add_exact(&mut self, value: f64) -> bool {
2200        let sum = self.leading + value;
2201        if !sum.is_finite() {
2202            return false;
2203        }
2204        let virtual_value = sum - self.leading;
2205        let virtual_leading = sum - virtual_value;
2206        let value_residual = value - virtual_value;
2207        let leading_residual = self.leading - virtual_leading;
2208        // Under round-to-nearest with gradual underflow, the two residuals and
2209        // their final sum are exact (Knuth/Møller TwoSum).
2210        let error = leading_residual + value_residual;
2211        self.leading = sum;
2212        self.correction = self.correction.add(ClosedInterval::point(error));
2213        self.correction.is_valid()
2214    }
2215
2216    fn subtract_interval(&mut self, value: ClosedInterval) -> bool {
2217        self.correction = self.correction.sub(value);
2218        self.correction.is_valid()
2219    }
2220
2221    fn enclosure(self) -> Option<ClosedInterval> {
2222        let enclosure = ClosedInterval::point(self.leading).add(self.correction);
2223        (enclosure.is_valid() && enclosure.lo.is_finite() && enclosure.hi.is_finite())
2224            .then_some(enclosure)
2225    }
2226}
2227
2228/// Split one exact-real positive quotient into a binary64 leading value and a
2229/// rigorous low correction:
2230///
2231/// `numerator / denominator ∈ leading + correction`.
2232///
2233/// The fused residual `numerator - leading*denominator` rounds only once.
2234/// Its two adjacent binary64 values therefore enclose the exact residual; a
2235/// directed division by the positive denominator transports that enclosure
2236/// into quotient units. The correction is normally O(u²) relative to the
2237/// quotient, rather than the O(u) width of independently directed division.
2238fn quotient_leading_and_correction(
2239    numerator: f64,
2240    denominator: f64,
2241) -> Option<(f64, ClosedInterval)> {
2242    if numerator == 0.0 {
2243        return Some((0.0, ClosedInterval::point(0.0)));
2244    }
2245    if !(numerator.is_finite() && numerator > 0.0 && denominator.is_finite() && denominator > 0.0) {
2246        return None;
2247    }
2248    let leading = numerator / denominator;
2249    if !(leading.is_finite() && leading >= 0.0) {
2250        return None;
2251    }
2252    if denominator == 1.0 {
2253        return Some((leading, ClosedInterval::point(0.0)));
2254    }
2255    let fused_residual = (-leading).mul_add(denominator, numerator);
2256    if !fused_residual.is_finite() {
2257        return None;
2258    }
2259    let exact_residual = ClosedInterval::new(next_down(fused_residual), next_up(fused_residual));
2260    let correction = exact_residual.div_positive(ClosedInterval::point(denominator));
2261    (correction.is_valid() && correction.lo.is_finite() && correction.hi.is_finite())
2262        .then_some((leading, correction))
2263}
2264
2265fn certified_zero_lambda_residual(
2266    energy: f64,
2267    gram_modes: &[f64],
2268    projected_squares: &[f64],
2269) -> Option<ClosedInterval> {
2270    let mut residual = CertifiedCompensatedSum::new(energy);
2271    for (&gram, &projected_square) in gram_modes.iter().zip(projected_squares) {
2272        if gram == 0.0 || projected_square == 0.0 {
2273            continue;
2274        }
2275        let (leading, correction) = quotient_leading_and_correction(projected_square, gram)?;
2276        if !(residual.add_exact(-leading) && residual.subtract_interval(correction)) {
2277            return None;
2278        }
2279    }
2280    residual.enclosure()
2281}
2282
2283// Operation counts in the scalar evaluator's per-mode accumulators.  They are
2284// kept beside the profile rather than written as anonymous roundoff factors:
2285// determinant value = at most exponential, multiply, divide, two logarithms,
2286// two additions/subtractions, and accumulator update;
2287// determinant first = fused h, the cancellation-free complement g/h, and sum;
2288// determinant second adds u and the product;
2289// residual value = at most two ratio divisions, scaling, and subtraction;
2290// residual first adds numerator product, division, and sum to the `u` path;
2291// residual second additionally forms `2u`, `1-2u`, and its product.
2292const DETERMINANT_VALUE_OPS_PER_MODE: usize = 8;
2293const RESIDUAL_VALUE_OPS_PER_MODE: usize = 4;
2294const RESIDUAL_LOG_OPS_PER_RESPONSE: usize = 3;
2295const SCORE_COMBINE_OPS: usize = 4;
2296
2297impl<'a> AffineRemlProfile<'a> {
2298    pub fn new(
2299        gram_modes: &'a [f64],
2300        penalty_modes: &'a [f64],
2301        projected_rhs_squared: &'a [f64],
2302        response_energy: &'a [f64],
2303        residual_dof: f64,
2304        determinant_rank: usize,
2305        logdet_constant: f64,
2306    ) -> Result<Self, AffineRemlError> {
2307        let modes = gram_modes.len();
2308        let responses = response_energy.len();
2309        if modes == 0 {
2310            return Err(AffineRemlError::EmptyModes);
2311        }
2312        if responses == 0 {
2313            return Err(AffineRemlError::EmptyResponses);
2314        }
2315        if penalty_modes.len() != modes
2316            || projected_rhs_squared.len() != modes.saturating_mul(responses)
2317        {
2318            return Err(AffineRemlError::ShapeMismatch {
2319                gram_modes: modes,
2320                penalty_modes: penalty_modes.len(),
2321                projected_rhs_squared: projected_rhs_squared.len(),
2322                responses,
2323            });
2324        }
2325        for (index, (&gram, &penalty)) in gram_modes.iter().zip(penalty_modes).enumerate() {
2326            if !(gram.is_finite()
2327                && penalty.is_finite()
2328                && gram >= 0.0
2329                && penalty >= 0.0
2330                && (gram > 0.0 || penalty > 0.0))
2331            {
2332                return Err(AffineRemlError::InvalidMode {
2333                    index,
2334                    gram,
2335                    penalty,
2336                });
2337            }
2338        }
2339        for (index, &value) in projected_rhs_squared.iter().enumerate() {
2340            if !(value.is_finite() && value >= 0.0) {
2341                return Err(AffineRemlError::InvalidProjectedSquare { index, value });
2342            }
2343        }
2344        for (output, &value) in response_energy.iter().enumerate() {
2345            if !(value.is_finite() && value >= 0.0) {
2346                return Err(AffineRemlError::InvalidResponseEnergy { output, value });
2347            }
2348        }
2349        if !(residual_dof.is_finite() && residual_dof > 0.0) {
2350            return Err(AffineRemlError::InvalidResidualDof {
2351                value: residual_dof,
2352            });
2353        }
2354        if !logdet_constant.is_finite() {
2355            return Err(AffineRemlError::InvalidLogdetConstant {
2356                value: logdet_constant,
2357            });
2358        }
2359        let inferred_rank = penalty_modes.iter().filter(|&&value| value > 0.0).count();
2360        if determinant_rank != inferred_rank {
2361            return Err(AffineRemlError::RankMismatch {
2362                supplied: determinant_rank,
2363                inferred: inferred_rank,
2364            });
2365        }
2366        let mut zero_lambda_residual = Vec::with_capacity(responses);
2367        for (output, &energy) in response_energy.iter().enumerate() {
2368            let start = output * modes;
2369            let end = start + modes;
2370            zero_lambda_residual.push(
2371                certified_zero_lambda_residual(
2372                    energy,
2373                    gram_modes,
2374                    &projected_rhs_squared[start..end],
2375                )
2376                .ok_or(AffineRemlError::ZeroLambdaResidualUnavailable { output })?,
2377            );
2378        }
2379        Ok(Self {
2380            gram_modes,
2381            penalty_modes,
2382            projected_rhs_squared,
2383            response_energy,
2384            zero_lambda_residual,
2385            residual_dof,
2386            logdet_constant,
2387        })
2388    }
2389
2390    #[inline]
2391    pub fn num_modes(&self) -> usize {
2392        self.gram_modes.len()
2393    }
2394
2395    #[inline]
2396    pub fn num_responses(&self) -> usize {
2397        self.response_energy.len()
2398    }
2399
2400    /// Nearest-rounded score value, first derivative, and second derivative in
2401    /// `log(lambda)`. [`Self::enclose`] supplies the proof-grade outer ranges.
2402    pub fn evaluate(&self, log_lambda: f64) -> Result<ScoreJet, AffineRemlError> {
2403        if !log_lambda.is_finite() {
2404            return Err(AffineRemlError::InvalidLogLambda { value: log_lambda });
2405        }
2406        let lambda = certified_exp_representative(log_lambda)
2407            .ok_or(AffineRemlError::InvalidLogLambda { value: log_lambda })?;
2408        if !(lambda.is_finite() && lambda > 0.0) {
2409            return Err(AffineRemlError::InvalidLogLambda { value: log_lambda });
2410        }
2411
2412        let mut normalized_logdet = self.logdet_constant;
2413        let mut determinant_derivative = 0.0;
2414        let mut determinant_curvature = 0.0;
2415        let exp_neg_log_lambda = if log_lambda >= 0.0 {
2416            certified_exp_representative(-log_lambda)
2417        } else {
2418            None
2419        };
2420        for (index, (&gram, &penalty)) in self.gram_modes.iter().zip(self.penalty_modes).enumerate()
2421        {
2422            // A gram-zero penalized mode is structurally
2423            //
2424            //   log(exp(rho) s) - rho = log(s),
2425            //
2426            // with first and second derivatives exactly zero. Do not form
2427            // `exp(rho) s`: its rounded product may be zero or infinity even
2428            // though every normalized determinant quantity is finite.
2429            if gram == 0.0 {
2430                normalized_logdet +=
2431                    certified_ln_value(penalty).ok_or(AffineRemlError::NonPositiveMode {
2432                        index,
2433                        log_lambda,
2434                        value: penalty,
2435                    })?;
2436                continue;
2437            }
2438            let h = lambda.mul_add(penalty, gram);
2439            if !(h.is_finite() && h > 0.0) {
2440                return Err(AffineRemlError::NonPositiveMode {
2441                    index,
2442                    log_lambda,
2443                    value: h,
2444                });
2445            }
2446            let u = lambda * penalty / h;
2447            // For a penalized mode,
2448            //
2449            //   d/d rho [log(g + exp(rho)s) - rho]
2450            //     = u - 1 = -g/h,
2451            //
2452            // and its second derivative is u*g/h. Accumulate in that
2453            // cancellation-free complement currency rather than adding u to a
2454            // separately rounded `-rank`; the latter loses the derivative's
2455            // sign when u rounds to one. An unpenalized mode has no `-rho`
2456            // normalization and contributes exactly zero.
2457            let determinant_complement = if penalty == 0.0 { 0.0 } else { gram / h };
2458            // Accumulate the determinant in the normalized per-mode form
2459            // instead of forming two O(rho) quantities and subtracting them
2460            // after the sum. Both branches keep their exponential in (0, 1]:
2461            //
2462            // log(g + exp(rho)s) - rho
2463            //   = log(s + g exp(-rho))                         rho >= 0
2464            //   = log(g) - rho + log1p(exp(rho)s/g)            g dominates
2465            //   = log(s) + log1p(g/(exp(rho)s))                s dominates.
2466            //
2467            // The selected log1p ratio is always in [0, 1], so neither tail
2468            // forms an overflowing exponential or divides by its small term.
2469            let normalized_mode = if penalty == 0.0 {
2470                certified_ln_value(gram)
2471            } else if log_lambda >= 0.0 {
2472                exp_neg_log_lambda
2473                    .and_then(|exp_neg_rho| certified_ln_value(penalty + gram * exp_neg_rho))
2474            } else if gram >= penalty * lambda {
2475                certified_ln_value(gram)
2476                    .zip(certified_ln_1p_value(penalty * lambda / gram))
2477                    .map(|(log_gram, correction)| log_gram - log_lambda + correction)
2478            } else {
2479                certified_ln_value(penalty)
2480                    .zip(certified_ln_1p_value(gram / (penalty * lambda)))
2481                    .map(|(log_penalty, correction)| log_penalty + correction)
2482            }
2483            .ok_or(AffineRemlError::NonPositiveMode {
2484                index,
2485                log_lambda,
2486                value: h,
2487            })?;
2488            normalized_logdet += normalized_mode;
2489            determinant_derivative -= determinant_complement;
2490            determinant_curvature += u * determinant_complement;
2491        }
2492
2493        let modes = self.num_modes();
2494        let mut residual_log_sum = 0.0;
2495        let mut residual_derivative_sum = 0.0;
2496        let mut residual_curvature_sum = 0.0;
2497        for (output, &energy) in self.response_energy.iter().enumerate() {
2498            let mut residual = energy;
2499            let mut first = 0.0;
2500            let mut second = 0.0;
2501            for i in 0..modes {
2502                let projected_square = self.projected_rhs_squared[output * modes + i];
2503                if projected_square == 0.0 {
2504                    continue;
2505                }
2506                if self.gram_modes[i] == 0.0 {
2507                    let fitted = positive_ratio_over_product(
2508                        projected_square,
2509                        self.penalty_modes[i],
2510                        lambda,
2511                    )
2512                    .ok_or(
2513                        AffineRemlError::ElementaryEnclosureUnavailable {
2514                            function: "gram-zero residual quotient",
2515                            lo: log_lambda,
2516                            hi: log_lambda,
2517                        },
2518                    )?;
2519                    residual -= fitted;
2520                    first += fitted;
2521                    second -= fitted;
2522                    continue;
2523                }
2524                let h = lambda.mul_add(self.penalty_modes[i], self.gram_modes[i]);
2525                let u = lambda * self.penalty_modes[i] / h;
2526                residual -= projected_square / h;
2527                first += projected_square * u / h;
2528                second += projected_square * u * (1.0 - 2.0 * u) / h;
2529            }
2530            if !(residual.is_finite() && residual > 0.0) {
2531                return Err(AffineRemlError::NonPositiveResidual {
2532                    output,
2533                    log_lambda,
2534                    value: residual,
2535                });
2536            }
2537            let log_derivative = first / residual;
2538            residual_log_sum += certified_ln_value(residual / self.residual_dof).ok_or(
2539                AffineRemlError::NonPositiveResidual {
2540                    output,
2541                    log_lambda,
2542                    value: residual,
2543                },
2544            )?;
2545            residual_derivative_sum += log_derivative;
2546            residual_curvature_sum += second / residual - log_derivative * log_derivative;
2547        }
2548
2549        let outputs = self.num_responses() as f64;
2550        Ok(ScoreJet {
2551            value: -0.5 * (outputs * normalized_logdet + self.residual_dof * residual_log_sum),
2552            derivative: -0.5
2553                * (outputs * determinant_derivative + self.residual_dof * residual_derivative_sum),
2554            curvature: -0.5
2555                * (outputs * determinant_curvature + self.residual_dof * residual_curvature_sum),
2556            // This profile's companion `enclose` builds its own ranges from the
2557            // mode kernels on an interval lambda and centres them on the cell
2558            // MIDPOINT, so it never reads an endpoint jet's third derivative --
2559            // the third derivative it centres the curvature on is an interval
2560            // one it accumulates itself. Nothing reads this field for this
2561            // profile, and a scalar third derivative of a score whose two blocks
2562            // cancel would be the least trustworthy number here, so it stays
2563            // exactly zero rather than being computed and quietly relied on.
2564            third: 0.0,
2565        })
2566    }
2567
2568    /// Outward enclosure of the score value and first two derivatives on a
2569    /// bounded log-lambda interval.
2570    ///
2571    /// # Two enclosures, intersected: the natural extension and the centred form
2572    ///
2573    /// `Self::enclose_direct` below is the NATURAL interval extension — each
2574    /// mode kernel evaluated on the interval lambda and summed. It is rigorous,
2575    /// and on the derivative and curvature it is also tight, because there the
2576    /// exact quantities are `O(1)` sums.
2577    ///
2578    /// On the score VALUE it is neither, and the reason is structural rather
2579    /// than incidental. The value is
2580    ///
2581    /// ```text
2582    ///     -0.5 * (D * normalized_logdet + residual_dof * sum_d log(R_d/dof))
2583    /// ```
2584    ///
2585    /// and near a REML optimum those two brackets cancel: each block's `d/drho`
2586    /// is `O(rank)` while their sum is not. Interval addition cannot see that
2587    /// the two variations are the same quantity with opposite signs, so the
2588    /// natural extension carries `rank * width` of slack the exact function does
2589    /// not have. Measured on a 33-mode profile over six decades of cell width,
2590    /// the value range came out at `33.0 * width` EXACTLY while the cell's own
2591    /// derivative enclosure bounded the score's variation across it by up to
2592    /// `7.4e5` times less — and the ratio DIVERGES as the cell shrinks, because
2593    /// one side is `O(w)` and the other `O(w^2)`.
2594    ///
2595    /// That is not a cosmetic loss. `maximize_score_1d` retires a cell as
2596    /// resolution-flat when its score range fits inside `2 * evaluation_error`;
2597    /// against an `O(w)` range that test needs a cell `rank/|f'|` times narrower
2598    /// than the function requires, so cells that ARE flat get subdivided, and a
2599    /// search that should finish in a handful of cells exhausts its subdivision
2600    /// budget and refuses a design it can certify.
2601    ///
2602    /// The cure is the standard one and needs nothing this routine does not
2603    /// already compute. For every `x` in `[a, b]` and `m` the midpoint, the mean
2604    /// value theorem gives
2605    ///
2606    /// ```text
2607    ///     f(x)  in  F({m})  + F'([a,b]) * [a-m, b-m]
2608    ///     f'(x) in  F'({m}) + F''([a,b]) * [a-m, b-m]
2609    /// ```
2610    ///
2611    /// with `F({m})` obtained by calling the SAME natural extension on the
2612    /// degenerate interval `[m, m]`. Both forms are outer enclosures of the same
2613    /// exact range, so their INTERSECTION is an outer enclosure too — this can
2614    /// only ever tighten, never widen, and it is never an acceptance tolerance.
2615    /// The centred form's overestimation is second order in the cell width,
2616    /// which is what makes the branch-and-bound converge.
2617    ///
2618    /// All three channels are centred, including the curvature: the profile's
2619    /// mode kernels are analytic, so `enclose_direct` also accumulates the exact
2620    /// third-derivative range (`t(1-4t+t^2)/(1+t)^4` per mode for the residual,
2621    /// `t(1-t)/(1+t)^3` for the determinant), and the curvature is centred on
2622    /// that. It matters: stationary isolation reads the curvature DIRECTLY and
2623    /// needs its sign, so a first-order-loose curvature is what stops a root
2624    /// being isolated rather than merely making a range wide.
2625    ///
2626    /// The `evaluation_error` is a property of the POINT evaluator over the
2627    /// cell, not of which enclosure form was tighter, so it is carried across
2628    /// unchanged from the whole-cell reading (the conservative one — the
2629    /// midpoint reading is taken over a degenerate interval and is never wider).
2630    ///
2631    /// # One consequence worth naming, because it points the other way
2632    ///
2633    /// `resolution_flat_region` retires a cell when its score range fits inside
2634    /// `2 * evaluation_error`, so a TIGHTER value range makes that verdict
2635    /// easier to reach — and a caller whose optimum lands in such a region gets
2636    /// a refusal (`ResidualCascadeError::RemlOptimumResolutionFlat`) rather than
2637    /// a fit. Tightening could in principle trade a subdivision-budget refusal
2638    /// for a resolution-flat one.
2639    ///
2640    /// It does not, because the flat test is the LAST thing a cell is offered:
2641    /// dominance, derivative exclusion and stationary isolation are all tried
2642    /// first, and centring strengthens each of them by more than it strengthens
2643    /// the flat test — the derivative and curvature ranges are what decide those
2644    /// three, and both are now centred too. Measured on the cascade design this
2645    /// was built for: the search returns `Stationary(0)` at every requested
2646    /// resolution from `1.49e-8` to `1e-3`, never `ResolutionFlat`, and
2647    /// `auto_reml_certifies_a_design_the_data_cannot_identify` asserts exactly
2648    /// that so the trade cannot creep in unnoticed.
2649    pub fn enclose(&self, lo: f64, hi: f64) -> Result<DerivativeEnclosure, AffineRemlError> {
2650        let (direct, direct_third) = self.enclose_direct(lo, hi)?;
2651        if lo == hi {
2652            return Ok(direct);
2653        }
2654        // Any point of the cell is a valid expansion centre; the midpoint
2655        // minimizes the worst-case `|x - m|` and so the width of the remainder
2656        // term. Clamped because `0.5*(lo+hi)` may round outside a cell whose
2657        // endpoints are adjacent floats, and a centre outside the cell would
2658        // make the mean value theorem inapplicable.
2659        let centre_point = (0.5 * (lo + hi)).clamp(lo, hi);
2660        let (centre, _) = self.enclose_direct(centre_point, centre_point)?;
2661        // `[a-m, b-m]`, rounded OUTWARD. Both subtractions are exact by
2662        // Sterbenz whenever the endpoints are within a factor of two of the
2663        // centre, which is the usual case; the directed widening costs one ulp
2664        // and removes the need to prove it.
2665        let offset = ClosedInterval::new(
2666            next_down(lo - centre_point).min(0.0),
2667            next_up(hi - centre_point).max(0.0),
2668        );
2669        // The three channels are centred in DERIVATIVE ORDER, each on the result
2670        // of the one above, because a mean value remainder is only as tight as
2671        // the range fed into it: the curvature's remainder is `F'''*offset`, the
2672        // derivative's is `F''*offset`, and the value's is `F'*offset`. Feeding
2673        // each the natural extension's range instead of the centred one leaves a
2674        // constant factor on the floor at every level — measured at 3.3x on the
2675        // value alone — and it is this cascade that makes
2676        // `width(F) <= width(F({m})) + max|F'| * w` hold BY CONSTRUCTION against
2677        // the ranges this function actually returns.
2678        let curvature = centred_or(direct.curvature, centre.curvature, direct_third, offset);
2679        let derivative = centred_or(direct.derivative, centre.derivative, curvature, offset);
2680        let value = centred_or(direct.score.value, centre.score.value, derivative, offset);
2681        Ok(DerivativeEnclosure {
2682            score: ScoreValueEnclosure {
2683                value,
2684                evaluation_error: direct.score.evaluation_error,
2685            },
2686            derivative,
2687            curvature,
2688        })
2689    }
2690
2691    /// The natural (direct) interval extension: every mode kernel evaluated on
2692    /// the interval lambda and accumulated.
2693    ///
2694    /// The interval kernels enclose the exact-real ranges. The score value uses
2695    /// the same cancellation-free normalized determinant identity as
2696    /// [`Self::evaluate`]. Its separate `evaluation_error` charges each
2697    /// source-derived elementary-function interval, error propagation through
2698    /// `log(residual)`, and Wilkinson `gamma_k * sum |term|` bounds for the
2699    /// actual sequential accumulators.
2700    ///
2701    /// [`Self::enclose`] is what callers want: this form alone is first-order
2702    /// loose on the value, for the reason documented there.
2703    fn enclose_direct(
2704        &self,
2705        lo: f64,
2706        hi: f64,
2707    ) -> Result<(DerivativeEnclosure, ClosedInterval), AffineRemlError> {
2708        if !(lo.is_finite() && hi.is_finite() && lo <= hi) {
2709            return Err(AffineRemlError::InvalidLogLambdaInterval { lo, hi });
2710        }
2711        let lambda = exp_interval(lo, hi)?;
2712        if !(lambda.lo.is_finite() && lambda.lo > 0.0 && lambda.hi.is_finite()) {
2713            return Err(AffineRemlError::InvalidLogLambdaInterval { lo, hi });
2714        }
2715        // Exp's range-reduction, arithmetic, and truncation errors are
2716        // multiplicative and must remain in relative currency across a wide
2717        // interval. Only gradual underflow is additive and is charged against
2718        // the certified positive lower endpoint. This avoids coupling an
2719        // upper-endpoint absolute error to the lower-endpoint scale.
2720        let lambda_relative_error =
2721            certified_exp_relative_forward_error(ClosedInterval::new(lo, hi), lambda);
2722        if !lambda_relative_error.is_finite() {
2723            return Err(AffineRemlError::UnboundedScoreEvaluationError {
2724                lo,
2725                hi,
2726                error: lambda_relative_error,
2727            });
2728        }
2729
2730        let mut normalized_logdet = ClosedInterval::point(self.logdet_constant);
2731        let mut normalized_logdet_magnitude = self.logdet_constant.abs();
2732        let mut normalized_logdet_error = 0.0;
2733        let mut determinant_first = ClosedInterval::point(0.0);
2734        let mut determinant_second = ClosedInterval::point(0.0);
2735        let mut determinant_third = ClosedInterval::point(0.0);
2736        for i in 0..self.num_modes() {
2737            let (normalized_mode, normalized_mode_error) =
2738                normalized_log_mode_enclosure(self.gram_modes[i], self.penalty_modes[i], lo, hi)?;
2739            normalized_logdet = normalized_logdet.add(normalized_mode);
2740            normalized_logdet_magnitude = add_nonnegative_upward(
2741                normalized_logdet_magnitude,
2742                add_nonnegative_upward(normalized_mode.max_abs(), normalized_mode_error),
2743            );
2744            normalized_logdet_error =
2745                add_nonnegative_upward(normalized_logdet_error, normalized_mode_error);
2746
2747            let ranges = mode_ranges(self.gram_modes[i], self.penalty_modes[i], 0.0, lambda)?;
2748            determinant_first = determinant_first.sub(ranges.c);
2749            determinant_second = determinant_second.add(ranges.w);
2750            determinant_third = determinant_third.add(ranges.determinant_third);
2751        }
2752
2753        let mut residual_first_sum = ClosedInterval::point(0.0);
2754        let mut residual_second_sum = ClosedInterval::point(0.0);
2755        let mut residual_third_sum = ClosedInterval::point(0.0);
2756        let mut residual_log_sum = ClosedInterval::point(0.0);
2757        let mut residual_log_magnitude = 0.0;
2758        let mut residual_log_error = 0.0;
2759        let modes = self.num_modes();
2760        for (output, &energy) in self.response_energy.iter().enumerate() {
2761            let mut fitted_quadratic = ClosedInterval::point(0.0);
2762            let mut smoothing_increment = ClosedInterval::point(0.0);
2763            let mut singular_fitted = ClosedInterval::point(0.0);
2764            let mut first = ClosedInterval::point(0.0);
2765            let mut second = ClosedInterval::point(0.0);
2766            let mut third = ClosedInterval::point(0.0);
2767            let mut fitted_magnitude = energy;
2768            for i in 0..modes {
2769                let ranges = mode_ranges(
2770                    self.gram_modes[i],
2771                    self.penalty_modes[i],
2772                    self.projected_rhs_squared[output * modes + i],
2773                    lambda,
2774                )?;
2775                fitted_quadratic = fitted_quadratic.add(ranges.v);
2776                smoothing_increment = smoothing_increment.add(ranges.smoothing_increment);
2777                singular_fitted = singular_fitted.add(ranges.singular_fitted);
2778                first = first.add(ranges.p);
2779                second = second.add(ranges.q);
2780                third = third.add(ranges.residual_third);
2781                fitted_magnitude = add_nonnegative_upward(fitted_magnitude, ranges.v.max_abs());
2782            }
2783            // Two exact identities describe the same residual:
2784            //
2785            //   R = E - sum_i q_i/(g_i + lambda*s_i)
2786            //
2787            // and, for every positive-Gram mode,
2788            //
2789            //   q_i/(g_i + lambda*s_i)
2790            //     = q_i/g_i - (q_i/g_i) * lambda*s_i/(g_i + lambda*s_i).
2791            //
2792            // The direct form is well-conditioned away from interpolation.
2793            // Near the zero-smoothing face it subtracts many independently
2794            // rounded near-one fitted fractions from `E`, even though their
2795            // deviations from one are perfectly correlated with lambda.  The
2796            // complement form carries that correlation explicitly as a
2797            // fixed zero-smoothing residual plus nonnegative smoothing
2798            // increments.  Both are rigorous outer enclosures, so their
2799            // intersection is rigorous and never an acceptance tolerance.
2800            let direct_residual = ClosedInterval::point(energy).sub(fitted_quadratic);
2801            let complement_residual = self.zero_lambda_residual[output]
2802                .add(smoothing_increment)
2803                .sub(singular_fitted);
2804            let residual = direct_residual.intersection(complement_residual).ok_or(
2805                AffineRemlError::InconsistentResidualEnclosures {
2806                    output,
2807                    lo,
2808                    hi,
2809                    direct: direct_residual,
2810                    complement: complement_residual,
2811                },
2812            )?;
2813            if !(residual.lo > 0.0 && residual.is_valid()) {
2814                return Err(AffineRemlError::NonPositiveResidualInterval {
2815                    output,
2816                    lo,
2817                    hi,
2818                    lower_bound: residual.lo,
2819                });
2820            }
2821            let first_ratio = first.div_positive(residual).nonnegative();
2822            let second_ratio = second.div_positive(residual);
2823            let third_ratio = third.div_positive(residual);
2824            residual_first_sum = residual_first_sum.add(first_ratio);
2825            residual_second_sum = residual_second_sum.add(second_ratio.sub(first_ratio.square()));
2826            // The third derivative of `log R`, from the same three ratios:
2827            //   (log R)''' = R'''/R - 3 (R''/R)(R'/R) + 2 (R'/R)^3.
2828            residual_third_sum = residual_third_sum.add(
2829                third_ratio
2830                    .sub(second_ratio.mul(first_ratio).scale(3.0))
2831                    .add(first_ratio.square().mul(first_ratio).scale(2.0)),
2832            );
2833
2834            let fitted_arithmetic_error = wilkinson_roundoff(
2835                fitted_magnitude,
2836                modes.saturating_mul(RESIDUAL_VALUE_OPS_PER_MODE),
2837            );
2838            // `first = d fitted/d rho`, so the MVT propagates the exp error in
2839            // rho-space without a condition-number guess.
2840            let fitted_exp_error = next_up(first.max_abs() * lambda_relative_error);
2841            let resolved_fitted_quadratic = fitted_quadratic.widen(add_nonnegative_upward(
2842                fitted_arithmetic_error,
2843                fitted_exp_error,
2844            ));
2845            let resolved_residual = ClosedInterval::point(energy).sub(resolved_fitted_quadratic);
2846            if !(resolved_residual.lo > 0.0 && resolved_residual.is_valid()) {
2847                return Err(AffineRemlError::NonPositiveResidualInterval {
2848                    output,
2849                    lo,
2850                    hi,
2851                    lower_bound: resolved_residual.lo,
2852                });
2853            }
2854            let residual_over_dof = residual.div_positive(ClosedInterval::point(self.residual_dof));
2855            if !(residual_over_dof.lo > 0.0 && residual_over_dof.hi.is_finite()) {
2856                return Err(AffineRemlError::ElementaryEnclosureUnavailable {
2857                    function: "ln",
2858                    lo: residual_over_dof.lo,
2859                    hi: residual_over_dof.hi,
2860                });
2861            }
2862            let residual_log = residual_over_dof.ln_positive();
2863            residual_log_sum = residual_log_sum.add(residual_log);
2864
2865            // `evaluate` first forms the residual and then takes
2866            // `ln(residual/dof)`. The residual forward error is already
2867            // represented by `resolved_residual`. On the strictly positive
2868            // resolved range, the mean-value theorem bounds its propagation
2869            // through log by `delta_R / min(R)`. The division and logarithm
2870            // each add one directed basic-operation contribution; the
2871            // source-derived logarithm error is absolute, so it remains valid
2872            // when the logarithm's result is near zero.
2873            let residual_error = enclosure_excess(residual, resolved_residual);
2874            let propagated_residual_error = next_up(residual_error / resolved_residual.lo);
2875            let elementary_error = certified_log_forward_error(
2876                residual.div_positive(ClosedInterval::point(self.residual_dof)),
2877            );
2878            let local_log_error = add_nonnegative_upward(
2879                propagated_residual_error,
2880                add_nonnegative_upward(
2881                    elementary_error,
2882                    wilkinson_roundoff(
2883                        add_nonnegative_upward(1.0, residual_log.max_abs()),
2884                        RESIDUAL_LOG_OPS_PER_RESPONSE,
2885                    ),
2886                ),
2887            );
2888            residual_log_error = add_nonnegative_upward(residual_log_error, local_log_error);
2889            residual_log_magnitude = add_nonnegative_upward(
2890                residual_log_magnitude,
2891                add_nonnegative_upward(residual_log.max_abs(), local_log_error),
2892            );
2893        }
2894
2895        let outputs = self.num_responses() as f64;
2896        let first_bracket = determinant_first
2897            .scale(outputs)
2898            .add(residual_first_sum.scale(self.residual_dof));
2899        let second_bracket = determinant_second
2900            .scale(outputs)
2901            .add(residual_second_sum.scale(self.residual_dof));
2902        let third_bracket = determinant_third
2903            .scale(outputs)
2904            .add(residual_third_sum.scale(self.residual_dof));
2905        let derivative = first_bracket.scale(-0.5);
2906        let curvature = second_bracket.scale(-0.5);
2907        let third = third_bracket.scale(-0.5);
2908        let score_value = normalized_logdet
2909            .scale(outputs)
2910            .add(residual_log_sum.scale(self.residual_dof))
2911            .scale(-0.5);
2912        let score_magnitude = add_nonnegative_upward(
2913            next_up(outputs * normalized_logdet_magnitude),
2914            next_up(self.residual_dof * residual_log_magnitude),
2915        );
2916        normalized_logdet_error = add_nonnegative_upward(
2917            normalized_logdet_error,
2918            wilkinson_roundoff(normalized_logdet_magnitude, self.num_modes()),
2919        );
2920        residual_log_error = add_nonnegative_upward(
2921            residual_log_error,
2922            wilkinson_roundoff(residual_log_magnitude, self.num_responses()),
2923        );
2924        let final_arithmetic_error = wilkinson_roundoff(score_magnitude, SCORE_COMBINE_OPS);
2925        let weighted_component_error = add_nonnegative_upward(
2926            next_up(outputs * normalized_logdet_error),
2927            next_up(self.residual_dof * residual_log_error),
2928        );
2929        let value_evaluation_error =
2930            next_up(0.5 * add_nonnegative_upward(weighted_component_error, final_arithmetic_error));
2931        if !(score_value.is_valid() && value_evaluation_error.is_finite()) {
2932            return Err(AffineRemlError::UnboundedScoreEvaluationError {
2933                lo,
2934                hi,
2935                error: value_evaluation_error,
2936            });
2937        }
2938        let score = ScoreValueEnclosure {
2939            value: score_value,
2940            evaluation_error: value_evaluation_error,
2941        };
2942        Ok((
2943            DerivativeEnclosure {
2944                score,
2945                derivative,
2946                curvature,
2947            },
2948            third,
2949        ))
2950    }
2951
2952    pub fn maximize(
2953        &self,
2954        lo: f64,
2955        hi: f64,
2956        resolution: f64,
2957    ) -> Result<ScoreSearchResult, ScoreSearchError<AffineRemlError>> {
2958        maximize_score_1d(
2959            lo,
2960            hi,
2961            resolution,
2962            |x| self.evaluate(x),
2963            |a, b| self.enclose(a.x, b.x),
2964        )
2965    }
2966
2967    /// Isolate every finite stationary candidate and tighten location
2968    /// resolution until the selected exact score is globally orderable at the
2969    /// point evaluator's certified comparison resolution.
2970    ///
2971    /// The first pass honors the caller's requested location resolution.  A
2972    /// successful root isolation can still leave a wider exact score range
2973    /// than the rounded point comparison can distinguish, because location and
2974    /// value are different currencies.  In that case this repeats the same
2975    /// exact search with a smaller location target.  The observed ratio between
2976    /// comparison resolution and maximum excess is only an iteration strategy,
2977    /// never proof currency; every pass independently rebuilds the complete
2978    /// global certificate and the loop exits only on its verdict.
2979    ///
2980    /// There is no retry cap or acceptance fallback.  Each retry contracts the
2981    /// target by at least one binary subdivision.  If the target can no longer
2982    /// be represented, or the oracle cannot resolve structure at that finer
2983    /// target, the last complete certificate is returned unchanged for the
2984    /// caller's existing typed refusal.
2985    pub fn maximize_value_ordered(
2986        &self,
2987        lo: f64,
2988        hi: f64,
2989        initial_resolution: f64,
2990    ) -> Result<ScoreSearchResult, ScoreSearchError<AffineRemlError>> {
2991        maximize_score_1d_value_ordered(
2992            lo,
2993            hi,
2994            initial_resolution,
2995            |x| self.evaluate(x),
2996            |a, b| self.enclose(a.x, b.x),
2997        )
2998    }
2999}
3000
3001#[derive(Clone, Copy)]
3002struct ModeRanges {
3003    /// Cancellation-free determinant complement `c = g/h` for a penalized
3004    /// mode. An unpenalized mode contributes exactly zero because its
3005    /// normalized log determinant has no `-rho` term.
3006    c: ClosedInterval,
3007    /// `u(1-u)`.
3008    w: ClosedInterval,
3009    /// `projected_square / h`.
3010    v: ClosedInterval,
3011    /// The nonnegative loss of fitted energy caused by smoothing,
3012    /// `(projected_square / gram) * lambda*penalty / h`, for a positive Gram
3013    /// mode.
3014    smoothing_increment: ClosedInterval,
3015    /// The complete fitted contribution of a Gram-zero mode. Such a mode
3016    /// cannot participate in the zero-smoothing complement identity.
3017    singular_fitted: ClosedInterval,
3018    /// First derivative of the residual contribution:
3019    /// `projected_square * lambda s / h^2`.
3020    p: ClosedInterval,
3021    /// Second derivative of the residual contribution:
3022    /// `projected_square * lambda s (g-lambda s) / h^3`.
3023    q: ClosedInterval,
3024    /// Third `rho`-derivative of this mode's normalized log determinant,
3025    /// `u(1-u)(1-2u) = t(1-t)/(1+t)^3`. Exactly the `k` kernel: the
3026    /// determinant's second derivative is `w` and its third is `k`, which is
3027    /// also the fitted fraction's second. Zero for an unpenalized mode (no
3028    /// `-rho` term) and for a Gram-zero mode (whose normalized determinant is
3029    /// exactly constant).
3030    determinant_third: ClosedInterval,
3031    /// Third derivative of the residual contribution.
3032    residual_third: ClosedInterval,
3033}
3034
3035/// Exact-real range and a uniform forward-error bound for the normalized
3036/// determinant contribution of one affine mode.
3037///
3038/// The exact function is monotone, so outward endpoint evaluation gives its
3039/// range. [`AffineRemlProfile::evaluate`] uses algebraically equivalent stable
3040/// sign/dominance branches whose exponential or `ln_1p` argument is in
3041/// `[0, 1]`. The elementary-function bounds come from the source-derived
3042/// range-reduced series above, not a platform-libm accuracy assumption;
3043/// Wilkinson's bound charges the surrounding IEEE basic operations and the
3044/// elementary input perturbation. The leading `1` is the analytic sensitivity
3045/// bound: the mode's rho derivative lies in `[-1, 0]`.
3046fn normalized_log_mode_enclosure(
3047    gram: f64,
3048    penalty: f64,
3049    lo: f64,
3050    hi: f64,
3051) -> Result<(ClosedInterval, f64), AffineRemlError> {
3052    if penalty == 0.0 {
3053        let range = ClosedInterval::point(gram).ln_positive();
3054        return Ok((
3055            range,
3056            certified_log_forward_error(ClosedInterval::point(gram)),
3057        ));
3058    }
3059    if gram == 0.0 {
3060        let range = ClosedInterval::point(penalty).ln_positive();
3061        return Ok((
3062            range,
3063            certified_log_forward_error(ClosedInterval::point(penalty)),
3064        ));
3065    }
3066
3067    let at_lo = normalized_log_mode_at(gram, penalty, lo)?;
3068    let at_hi = normalized_log_mode_at(gram, penalty, hi)?;
3069    // The normalized contribution has derivative `u - 1` in [-1, 0].
3070    let range = ClosedInterval::new(at_hi.lo, at_lo.hi);
3071    // In the negative branch the final subtraction can cancel `log(h)` and
3072    // `rho`; charge both pre-cancellation operands. Since
3073    // `log(h) = normalized_mode + rho`, `|mode| + 2|rho|` bounds their absolute
3074    // sum without evaluating a second logarithm.
3075    let negative_rho_abs = if lo < 0.0 { -lo } else { 0.0 };
3076    let arithmetic_scale = add_nonnegative_upward(
3077        add_nonnegative_upward(1.0, range.max_abs()),
3078        next_up(2.0 * negative_rho_abs),
3079    );
3080    let arithmetic_error = wilkinson_roundoff(arithmetic_scale, DETERMINANT_VALUE_OPS_PER_MODE);
3081    let mut exp_input_error = 0.0_f64;
3082    if hi >= 0.0 {
3083        let positive_lo = lo.max(0.0);
3084        let exp_neg_rho = exp_interval(-hi, -positive_lo)?;
3085        let argument_lo = ClosedInterval::point(penalty)
3086            .add(ClosedInterval::point(gram).mul(exp_neg_rho))
3087            .lo;
3088        if argument_lo > 0.0 {
3089            exp_input_error = exp_input_error.max(next_up(
3090                gram * certified_exp_forward_error(
3091                    ClosedInterval::new(-hi, -positive_lo),
3092                    exp_neg_rho,
3093                ) / argument_lo,
3094            ));
3095        } else {
3096            exp_input_error = f64::INFINITY;
3097        }
3098    }
3099    if lo < 0.0 {
3100        let negative_hi = hi.min(0.0);
3101        let exp_rho = exp_interval(lo, negative_hi)?;
3102        if exp_rho.lo > 0.0 {
3103            // The two stable negative-rho branches have log-lambda
3104            // sensitivities `u` and `1-u`, respectively. Both are at most one,
3105            // so the scale-safe relative exp error is a uniform bound even if
3106            // the dominance branch changes.
3107            exp_input_error = exp_input_error.max(certified_exp_relative_forward_error(
3108                ClosedInterval::new(lo, negative_hi),
3109                exp_rho,
3110            ));
3111        } else {
3112            exp_input_error = f64::INFINITY;
3113        }
3114    }
3115    let log_output_error =
3116        certified_log_error_from_output(at_lo).max(certified_log_error_from_output(at_hi));
3117    let log_gram_error = certified_log_forward_error(ClosedInterval::point(gram));
3118    let log_penalty_error = certified_log_forward_error(ClosedInterval::point(penalty));
3119    let log1p_error = certified_ln1p_forward_error();
3120    let elementary_error = add_nonnegative_upward(
3121        exp_input_error,
3122        add_nonnegative_upward(
3123            log_output_error,
3124            add_nonnegative_upward(
3125                log_gram_error,
3126                add_nonnegative_upward(log_penalty_error, log1p_error),
3127            ),
3128        ),
3129    );
3130    Ok((
3131        range,
3132        add_nonnegative_upward(arithmetic_error, elementary_error),
3133    ))
3134}
3135
3136fn normalized_log_mode_at(
3137    gram: f64,
3138    penalty: f64,
3139    rho: f64,
3140) -> Result<ClosedInterval, AffineRemlError> {
3141    if rho >= 0.0 {
3142        let exp_neg_rho = exp_interval(-rho, -rho)?;
3143        let argument =
3144            ClosedInterval::point(penalty).add(ClosedInterval::point(gram).mul(exp_neg_rho));
3145        if !(argument.lo > 0.0 && argument.hi.is_finite()) {
3146            return Err(AffineRemlError::ElementaryEnclosureUnavailable {
3147                function: "ln",
3148                lo: argument.lo,
3149                hi: argument.hi,
3150            });
3151        }
3152        Ok(argument.ln_positive())
3153    } else {
3154        let exp_rho = exp_interval(rho, rho)?;
3155        let argument = ClosedInterval::point(gram).add(ClosedInterval::point(penalty).mul(exp_rho));
3156        if !(argument.lo > 0.0 && argument.hi.is_finite()) {
3157            return Err(AffineRemlError::ElementaryEnclosureUnavailable {
3158                function: "ln",
3159                lo: argument.lo,
3160                hi: argument.hi,
3161            });
3162        }
3163        Ok(argument.ln_positive().sub(ClosedInterval::point(rho)))
3164    }
3165}
3166
3167fn exp_interval(lo: f64, hi: f64) -> Result<ClosedInterval, AffineRemlError> {
3168    let unavailable = || AffineRemlError::ElementaryEnclosureUnavailable {
3169        function: "exp",
3170        lo,
3171        hi,
3172    };
3173    if !(lo.is_finite() && hi.is_finite() && lo <= hi) {
3174        return Err(unavailable());
3175    }
3176    let lower = certified_exp(lo).ok_or_else(unavailable)?;
3177    let upper = certified_exp(hi).ok_or_else(unavailable)?;
3178    let enclosure = ClosedInterval::new(lower.lo.max(0.0), upper.hi).nonnegative();
3179    if !enclosure.is_valid() {
3180        return Err(unavailable());
3181    }
3182    Ok(enclosure)
3183}
3184
3185/// Directed division for a nonnegative numerator and a strictly positive
3186/// denominator without first materializing the reciprocal.
3187///
3188/// Forming `1 / denominator.lo` can overflow even when the final quotient is
3189/// finite because a correspondingly tiny numerator cancels that scale. Direct
3190/// endpoint quotients preserve that finite result. Invalid preconditions and a
3191/// nonfinite upper bound are typed refusals rather than assertions.
3192fn finite_nonnegative_quotient(
3193    numerator: ClosedInterval,
3194    denominator: ClosedInterval,
3195    function: &'static str,
3196) -> Result<ClosedInterval, AffineRemlError> {
3197    if !(numerator.is_valid()
3198        && numerator.lo >= 0.0
3199        && denominator.is_valid()
3200        && denominator.lo > 0.0)
3201    {
3202        return Err(AffineRemlError::ElementaryEnclosureUnavailable {
3203            function,
3204            lo: denominator.lo,
3205            hi: denominator.hi,
3206        });
3207    }
3208    let quotient = ClosedInterval::new(
3209        quotient_down(numerator.lo, denominator.hi).max(0.0),
3210        quotient_up(numerator.hi, denominator.lo),
3211    );
3212    if !(quotient.is_valid() && quotient.hi.is_finite()) {
3213        return Err(AffineRemlError::ElementaryEnclosureUnavailable {
3214            function,
3215            lo: quotient.lo,
3216            hi: quotient.hi,
3217        });
3218    }
3219    Ok(quotient.nonnegative())
3220}
3221
3222/// One channel of the centred (mean value) enclosure, intersected with the
3223/// natural extension — and never trusted over it when the remainder is not a
3224/// finite interval.
3225///
3226/// `f(x) in point + slope * offset` for every `x` in the cell, by the mean value
3227/// theorem, when `point` encloses `f` (or `f'`, or `f''`) at the expansion
3228/// centre and `slope` encloses the NEXT derivative over the whole cell. Both
3229/// forms are outer enclosures of one exact range, so the intersection is an
3230/// outer enclosure too: this can only tighten.
3231///
3232/// # What the finiteness guard is for, measured
3233///
3234/// `ClosedInterval::mul` reduces four endpoint products with `f64::min` and
3235/// `f64::max`, which IGNORE a NaN operand, so a NaN product drops out of the
3236/// reduction and the surviving endpoints describe a range strictly INSIDE the
3237/// true one — an unsound certificate, in the one direction that matters, with no
3238/// signal at all.
3239///
3240/// The obvious way in is `inf * 0`, and that way is already shut:
3241/// `product_down`/`product_up` treat a zero operand as exact and map the NaN to
3242/// `0.0`, and a sweep over every endpoint shape finds no narrowing from a
3243/// singly-infinite slope. The way that is NOT shut is a NaN arriving from
3244/// anywhere else — `[NaN, 1.0] * [-0.5, 0.5]` reduces to `[-0.5, 0.5]`, two
3245/// corners silently gone — because `enclose_direct` does not prove every
3246/// accumulator finite and `checked_enclosure` validates only the enclosure the
3247/// search receives, after this narrowing would already have happened.
3248///
3249/// So the guard excludes a non-finite slope and a non-finite remainder, and
3250/// keeps the natural extension, which is rigorous unconditionally. See
3251/// `the_centred_form_keeps_the_natural_extension_when_the_remainder_is_not_finite`
3252/// for both halves as assertions.
3253fn centred_or(
3254    direct: ClosedInterval,
3255    point: ClosedInterval,
3256    slope: ClosedInterval,
3257    offset: ClosedInterval,
3258) -> ClosedInterval {
3259    if !(slope.is_valid() && slope.lo.is_finite() && slope.hi.is_finite()) {
3260        return direct;
3261    }
3262    let remainder = slope.mul(offset);
3263    if !(remainder.is_valid() && remainder.lo.is_finite() && remainder.hi.is_finite()) {
3264        return direct;
3265    }
3266    let centred = point.add(remainder);
3267    if !centred.is_valid() {
3268        return direct;
3269    }
3270    // Two rigorous outer enclosures of the same nonempty exact range cannot be
3271    // disjoint, so this fallback is unreachable; it is written in the sound
3272    // direction rather than as a panic, because a refusal here would convert a
3273    // tightening into a failure.
3274    direct.intersection(centred).unwrap_or(direct)
3275}
3276
3277fn mode_ranges(
3278    gram: f64,
3279    penalty: f64,
3280    projected_square: f64,
3281    lambda: ClosedInterval,
3282) -> Result<ModeRanges, AffineRemlError> {
3283    if penalty == 0.0 {
3284        let v = ClosedInterval::point(projected_square)
3285            .div_positive(ClosedInterval::point(gram))
3286            .nonnegative();
3287        return Ok(ModeRanges {
3288            c: ClosedInterval::point(0.0),
3289            w: ClosedInterval::point(0.0),
3290            v,
3291            smoothing_increment: ClosedInterval::point(0.0),
3292            singular_fitted: ClosedInterval::point(0.0),
3293            p: ClosedInterval::point(0.0),
3294            q: ClosedInterval::point(0.0),
3295            determinant_third: ClosedInterval::point(0.0),
3296            residual_third: ClosedInterval::point(0.0),
3297        });
3298    }
3299    if gram == 0.0 {
3300        let zero = ClosedInterval::point(0.0);
3301        if projected_square == 0.0 {
3302            return Ok(ModeRanges {
3303                c: zero,
3304                w: zero,
3305                v: zero,
3306                smoothing_increment: zero,
3307                singular_fitted: zero,
3308                p: zero,
3309                q: zero,
3310                determinant_third: zero,
3311                residual_third: zero,
3312            });
3313        }
3314
3315        // The normalized determinant is exactly constant for g=0. For the
3316        // residual, v = A/(lambda*s). Use the direct product only when its
3317        // outward lower bound is strictly positive. If that lower bound rounds
3318        // to zero, cancel the exact scalar penalty first and divide the
3319        // resulting nonnegative interval directly by lambda. This preserves a
3320        // finite quotient such as min_subnormal/(0.01*lambda) without ever
3321        // asking `div_positive` to accept a denominator containing zero.
3322        let h = lambda.mul(ClosedInterval::point(penalty)).nonnegative();
3323        let projected = ClosedInterval::point(projected_square);
3324        let v = if h.lo > 0.0 {
3325            finite_nonnegative_quotient(projected, h, "gram-zero residual quotient")?
3326        } else {
3327            let scaled = finite_nonnegative_quotient(
3328                projected,
3329                ClosedInterval::point(penalty),
3330                "gram-zero residual quotient",
3331            )?;
3332            finite_nonnegative_quotient(scaled, lambda, "gram-zero residual quotient")?
3333        };
3334        return Ok(ModeRanges {
3335            c: ClosedInterval::point(0.0),
3336            w: ClosedInterval::point(0.0),
3337            v,
3338            smoothing_increment: zero,
3339            singular_fitted: v,
3340            p: v,
3341            q: v.neg(),
3342            // A Gram-zero mode's fitted fraction is `A/(lambda s)`, whose
3343            // rho-derivative is its own negative, so the residual's successive
3344            // derivatives alternate in sign at constant magnitude.
3345            determinant_third: zero,
3346            residual_third: v,
3347        });
3348    }
3349
3350    // Normalize by g: h = g(1+t), t = lambda*s/g.  The four kernels below
3351    // have known global critical points, so endpoint evaluation plus any
3352    // critical point contained by the t-window gives an exact real range;
3353    // interval arithmetic rounds every primitive outward.
3354    let t = lambda
3355        .mul(ClosedInterval::point(penalty))
3356        .div_positive(ClosedInterval::point(gram))
3357        .nonnegative();
3358    let scale = ClosedInterval::point(projected_square)
3359        .div_positive(ClosedInterval::point(gram))
3360        .nonnegative();
3361    let kernels = kernel_ranges(t);
3362    Ok(ModeRanges {
3363        c: kernels.v,
3364        w: kernels.w,
3365        v: scale.mul(kernels.v).nonnegative(),
3366        smoothing_increment: scale.mul(kernels.u).nonnegative(),
3367        singular_fitted: ClosedInterval::point(0.0),
3368        p: scale.mul(kernels.w).nonnegative(),
3369        q: scale.mul(kernels.k),
3370        determinant_third: kernels.k,
3371        residual_third: scale.mul(kernels.third),
3372    })
3373}
3374
3375#[derive(Clone, Copy)]
3376struct KernelRanges {
3377    /// `1/(1+t)`.
3378    v: ClosedInterval,
3379    /// `t/(1+t)`.
3380    u: ClosedInterval,
3381    /// `t/(1+t)^2`.
3382    w: ClosedInterval,
3383    /// `t(1-t)/(1+t)^3`.
3384    k: ClosedInterval,
3385    /// `t(1 - 4t + t^2)/(1+t)^4`, the rho-derivative of `k`.
3386    ///
3387    /// With `dt/drho = t`, differentiating `k` once more gives
3388    /// `t * dk/dt`, and `dk/dt = (1 - 4t + t^2)/(1+t)^4` because
3389    /// `k = (t - t^2)(1+t)^-3`. It is the third rho-derivative of a mode's
3390    /// fitted fraction (up to the scale `A/g`), which is what the residual
3391    /// block's `(log R)'''` is built from.
3392    ///
3393    /// Checked against finite differences of `q/(g + e^rho s)` in rho at
3394    /// `rho = -2, -0.5, 0.3, 1.7`: agreement to five significant figures at
3395    /// `h = 1e-2`, which is that FD's own `O(h^2)` truncation. The determinant's
3396    /// third derivative needed no new kernel at all — `u(1-u)(1-2u)` is
3397    /// `t(1-t)/(1+t)^3`, exactly `k` — and was checked the same way.
3398    third: ClosedInterval,
3399}
3400
3401fn kernel_at(t: ClosedInterval) -> KernelRanges {
3402    let one = ClosedInterval::point(1.0);
3403    let denom = one.add(t);
3404    let v = one.div_positive(denom).nonnegative();
3405    let u = t.mul(v).nonnegative();
3406    let w = u.mul(v).nonnegative();
3407    let k = w.mul(one.sub(t)).div_positive(denom);
3408    // `t(1 - 4t + t^2)/(1+t)^4 = w * (1 - 4t + t^2)/(1+t)^2`. The numerator is
3409    // signed, which `mul` handles; the denominator is a square of a strictly
3410    // positive interval.
3411    let third = w
3412        .mul(one.sub(t.scale(4.0)).add(t.square()))
3413        .div_positive(denom.square());
3414    KernelRanges { v, u, w, k, third }
3415}
3416
3417fn kernel_ranges(t: ClosedInterval) -> KernelRanges {
3418    let left = kernel_at(ClosedInterval::point(t.lo));
3419    let right = kernel_at(ClosedInterval::point(t.hi));
3420    let mut v = ClosedInterval::new(right.v.lo, left.v.hi).nonnegative();
3421    let u = ClosedInterval::new(left.u.lo, right.u.hi).nonnegative();
3422    let mut w = left.w.hull(right.w).nonnegative();
3423    let mut k = left.k.hull(right.k);
3424    let mut third = left.third.hull(right.third);
3425
3426    if t.contains(1.0) {
3427        let critical = kernel_at(ClosedInterval::point(1.0));
3428        w = w.hull(critical.w).nonnegative();
3429        // `d/dt [t(1-4t+t^2)/(1+t)^4] = (1 - 11t + 11t^2 - t^3)/(1+t)^5`, and
3430        // `t^3 - 11t^2 + 11t - 1 = (t-1)(t^2 - 10t + 1)`, so `t = 1` is one of
3431        // this kernel's three critical points as well.
3432        third = third.hull(critical.third);
3433    }
3434
3435    // k'(t) has its only positive roots at 2 +/- sqrt(3).  Enclose sqrt(3)
3436    // itself before subtraction/addition so the exact irrational critical
3437    // points are not lost to nearest-rounded scalar arithmetic.
3438    let sqrt_three =
3439        certified_sqrt_positive(3.0).expect("three is a finite positive square-root argument");
3440    let critical_points = [
3441        ClosedInterval::point(2.0).sub(sqrt_three),
3442        ClosedInterval::point(2.0).add(sqrt_three),
3443    ];
3444    for critical in critical_points {
3445        if critical.hi >= t.lo && critical.lo <= t.hi {
3446            k = k.hull(kernel_at(critical).k);
3447        }
3448    }
3449
3450    // The remaining two roots of `t^2 - 10t + 1` are `5 +/- 2 sqrt(6)`,
3451    // enclosed before the addition so the exact irrationals survive.
3452    let sqrt_six =
3453        certified_sqrt_positive(6.0).expect("six is a finite positive square-root argument");
3454    let two_sqrt_six = sqrt_six.scale(2.0);
3455    for critical in [
3456        ClosedInterval::point(5.0).sub(two_sqrt_six),
3457        ClosedInterval::point(5.0).add(two_sqrt_six),
3458    ] {
3459        if critical.hi >= t.lo && critical.lo <= t.hi {
3460            third = third.hull(kernel_at(critical).third);
3461        }
3462    }
3463
3464    // Monotonicity gives tighter endpoint ranges than a dependency-heavy
3465    // interval evaluation, but retain outward endpoint arithmetic.
3466    v.lo = v.lo.max(0.0);
3467    v.hi = v.hi.min(next_up(1.0));
3468    KernelRanges {
3469        v,
3470        u,
3471        w,
3472        k,
3473        third,
3474    }
3475}
3476
3477const LOG_SERIES_TERMS: usize = 18;
3478const EXP_SERIES_TERMS: usize = 18;
3479const EXP_RANGE_SQUARINGS: usize = 6;
3480
3481fn certified_sqrt_positive(value: f64) -> Option<ClosedInterval> {
3482    if !(value.is_finite() && value > 0.0) {
3483        return None;
3484    }
3485    // `sqrt` supplies only a starting guess. Directed squaring proves and, if
3486    // necessary, expands the two sides, so no platform sqrt accuracy contract
3487    // is a premise of the returned interval.
3488    let guess = value.sqrt();
3489    if !(guess.is_finite() && guess > 0.0) {
3490        return None;
3491    }
3492    let mut lo = next_down(guess);
3493    for _ in 0..8 {
3494        if ClosedInterval::point(lo).square().hi <= value {
3495            break;
3496        }
3497        lo = next_down(lo);
3498    }
3499    let mut hi = next_up(guess);
3500    for _ in 0..8 {
3501        if ClosedInterval::point(hi).square().lo >= value {
3502            break;
3503        }
3504        hi = next_up(hi);
3505    }
3506    (ClosedInterval::point(lo).square().hi <= value
3507        && ClosedInterval::point(hi).square().lo >= value)
3508        .then(|| ClosedInterval::new(lo, hi))
3509}
3510
3511/// `2·atanh(z)` by its positive odd-power series, with the omitted tail
3512/// bounded geometrically. The caller supplies `|z| <= 1/3`.
3513fn certified_log_from_atanh(z: ClosedInterval) -> ClosedInterval {
3514    let z_abs = z.max_abs();
3515    assert!(z_abs <= 1.0 / 3.0 + f64::EPSILON);
3516    let z2 = z.square();
3517    let mut power = z;
3518    let mut sum = z;
3519    for term in 1..LOG_SERIES_TERMS {
3520        power = power.mul(z2);
3521        sum = sum.add(power.div_positive(ClosedInterval::point((2 * term + 1) as f64)));
3522    }
3523    let next_power = power.mul(z2).max_abs();
3524    let first_denominator = (2 * LOG_SERIES_TERMS + 1) as f64;
3525    let geometric_denominator = next_down(1.0 - next_up(z_abs * z_abs));
3526    let tail = if geometric_denominator > 0.0 {
3527        next_up(next_up(2.0 * next_power) / next_down(first_denominator * geometric_denominator))
3528    } else {
3529        f64::INFINITY
3530    };
3531    sum.scale(2.0).widen(tail)
3532}
3533
3534fn certified_ln_two() -> ClosedInterval {
3535    static LN_TWO: OnceLock<ClosedInterval> = OnceLock::new();
3536    *LN_TWO.get_or_init(|| {
3537        // ln(2) = 2 atanh(1/3). Both the rational 1/3 and the series are
3538        // evaluated with directed IEEE basic operations; no platform libm
3539        // result participates in this constant.
3540        let third = ClosedInterval::point(1.0).div_positive(ClosedInterval::point(3.0));
3541        certified_log_from_atanh(third)
3542    })
3543}
3544
3545/// Exact decomposition `value = mantissa * 2^exponent` with
3546/// `mantissa in [1, 2)` for every positive finite binary64 value.
3547fn positive_binary64_parts(value: f64) -> Option<(f64, i32)> {
3548    if !(value.is_finite() && value > 0.0) {
3549        return None;
3550    }
3551    let bits = value.to_bits();
3552    let exponent_bits = ((bits >> 52) & 0x7ff) as i32;
3553    let fraction = bits & ((1_u64 << 52) - 1);
3554    if exponent_bits == 0 {
3555        // value = fraction*2^-1074. Normalize the integer significand into
3556        // [2^52,2^53), then install it under exponent zero.
3557        let highest = 63_i32 - fraction.leading_zeros() as i32;
3558        let normalized = fraction << (52 - highest);
3559        let mantissa_bits = (1023_u64 << 52) | (normalized - (1_u64 << 52));
3560        Some((f64::from_bits(mantissa_bits), highest - 1074))
3561    } else {
3562        let mantissa_bits = (1023_u64 << 52) | fraction;
3563        Some((f64::from_bits(mantissa_bits), exponent_bits - 1023))
3564    }
3565}
3566
3567/// Rigorous exact-real enclosure of `ln(value)` for every finite positive
3568/// binary64 input, including subnormals.
3569///
3570/// Bit decomposition writes `value = m·2^k` exactly with `m in [1,2)`.
3571/// `ln(m) = 2·atanh((m-1)/(m+1))` then has `z in [0,1/3]`, so the fixed
3572/// positive series above has a closed geometric remainder. Only directed
3573/// binary64 basic operations are used.
3574pub fn certified_ln_positive(value: f64) -> Option<ClosedInterval> {
3575    if !(value.is_finite() && value > 0.0) {
3576        return None;
3577    }
3578    if value == 1.0 {
3579        return Some(ClosedInterval::point(0.0));
3580    }
3581    let (mantissa, exponent) = positive_binary64_parts(value)?;
3582    let m = ClosedInterval::point(mantissa);
3583    let z = m
3584        .sub(ClosedInterval::point(1.0))
3585        .div_positive(m.add(ClosedInterval::point(1.0)));
3586    Some(certified_log_from_atanh(z).add(certified_ln_two().scale(exponent as f64)))
3587}
3588
3589/// Rigorous exact-real enclosure of `ln(1+value)`.
3590///
3591/// The nonnegative lane used by the affine score evaluates
3592/// `2·atanh(value/(2+value))` directly when `value <= 1`, preserving tiny
3593/// `value` without the rounded `1+value` cancellation. For larger values the
3594/// exact identity `ln(1+x) = ln(x) + ln(1+1/x)` keeps the atanh argument below
3595/// `1/3` and avoids overflow in `1+x`. Negative valid inputs route through the
3596/// certified positive logarithm of an outward `1+value` interval.
3597pub fn certified_ln_1p(value: f64) -> Option<ClosedInterval> {
3598    if !(value.is_finite() && value > -1.0) {
3599        return None;
3600    }
3601    if value == 0.0 {
3602        return Some(ClosedInterval::point(0.0));
3603    }
3604    if (0.0..=1.0).contains(&value) {
3605        let x = ClosedInterval::point(value);
3606        let z = x.div_positive(ClosedInterval::point(2.0).add(x));
3607        return Some(certified_log_from_atanh(z));
3608    }
3609    if value > 1.0 {
3610        let reciprocal = ClosedInterval::point(1.0)
3611            .div_positive(ClosedInterval::point(value))
3612            .nonnegative();
3613        let z = reciprocal
3614            .div_positive(ClosedInterval::point(2.0).add(reciprocal))
3615            .nonnegative();
3616        return Some(certified_ln_positive(value)?.add(certified_log_from_atanh(z)));
3617    }
3618    let argument = ClosedInterval::point(1.0).add(ClosedInterval::point(value));
3619    if !(argument.lo > 0.0) {
3620        return None;
3621    }
3622    let lo = certified_ln_positive(argument.lo)?;
3623    let hi = certified_ln_positive(argument.hi)?;
3624    Some(ClosedInterval::new(lo.lo, hi.hi))
3625}
3626
3627fn exact_power_of_two(exponent: i32) -> Option<f64> {
3628    match exponent {
3629        -1074..=-1023 => {
3630            let bit = (exponent + 1074) as u32;
3631            Some(f64::from_bits(1_u64 << bit))
3632        }
3633        -1022..=1023 => Some(f64::from_bits(((exponent + 1023) as u64) << 52)),
3634        _ => None,
3635    }
3636}
3637
3638/// Stable rounded representative of `numerator/(first*second)`.
3639///
3640/// Exact binary exponent extraction prevents the denominator product from
3641/// underflowing or overflowing before its scale cancels against the numerator.
3642/// Only two mantissa divisions and the final binary scaling round.
3643fn positive_ratio_over_product(
3644    numerator: f64,
3645    first_denominator: f64,
3646    second_denominator: f64,
3647) -> Option<f64> {
3648    if numerator == 0.0 {
3649        return Some(0.0);
3650    }
3651    let (numerator_mantissa, numerator_exponent) = positive_binary64_parts(numerator)?;
3652    let (first_mantissa, first_exponent) = positive_binary64_parts(first_denominator)?;
3653    let (second_mantissa, second_exponent) = positive_binary64_parts(second_denominator)?;
3654    let mut mantissa = numerator_mantissa / first_mantissa / second_mantissa;
3655    let mut exponent = numerator_exponent - first_exponent - second_exponent;
3656    if !(mantissa.is_finite() && mantissa > 0.0) {
3657        return None;
3658    }
3659    while mantissa < 1.0 {
3660        mantissa *= 2.0;
3661        exponent -= 1;
3662    }
3663    while mantissa >= 2.0 {
3664        mantissa *= 0.5;
3665        exponent += 1;
3666    }
3667    if exponent < -1075 {
3668        return Some(0.0);
3669    }
3670    if exponent > 1023 {
3671        return None;
3672    }
3673    let value = if exponent == -1075 {
3674        (0.5 * mantissa) * exact_power_of_two(-1074)?
3675    } else {
3676        mantissa * exact_power_of_two(exponent)?
3677    };
3678    (value.is_finite() && value >= 0.0).then_some(value)
3679}
3680
3681/// Rigorous exact-real enclosure of `exp(value)` for a finite binary64 input.
3682///
3683/// Range reduction uses the independently certified `ln(2)` interval:
3684/// `value = k ln(2) + r`. After six exact halvings, `|r/64| < 1/16`; a fixed
3685/// Taylor polynomial encloses `exp(r/64)` and a geometric bound encloses its
3686/// positive tail. Six interval squarings and multiplication by the exact
3687/// binary power `2^k` restore the result. Subnormal outputs remain intervals
3688/// with an absolute (possibly zero) lower endpoint instead of being forced
3689/// through an invalid relative-error model.
3690pub fn certified_exp(value: f64) -> Option<ClosedInterval> {
3691    if !value.is_finite() {
3692        return None;
3693    }
3694    if value == 0.0 {
3695        return Some(ClosedInterval::point(1.0));
3696    }
3697    // This quotient merely chooses an integer identity; its accuracy is not a
3698    // proof premise because `r = value-k·ln(2)` is subsequently enclosed using
3699    // the certified ln(2) interval and validated below.
3700    let mut exponent = (value / std::f64::consts::LN_2).round() as i32;
3701    exponent = exponent.clamp(-1074, 1023);
3702    let remainder = ClosedInterval::point(value).sub(certified_ln_two().scale(exponent as f64));
3703    if !(remainder.is_valid() && remainder.max_abs() < 4.0) {
3704        return None;
3705    }
3706    let reduction = (1_u64 << EXP_RANGE_SQUARINGS) as f64;
3707    let reduced = remainder.scale(1.0 / reduction);
3708    if !(reduced.max_abs() < 1.0 / 16.0) {
3709        return None;
3710    }
3711    let mut term = ClosedInterval::point(1.0);
3712    let mut sum = term;
3713    for degree in 1..=EXP_SERIES_TERMS {
3714        term = term
3715            .mul(reduced)
3716            .div_positive(ClosedInterval::point(degree as f64));
3717        sum = sum.add(term);
3718    }
3719    let z = reduced.max_abs();
3720    let first_omitted = next_up(term.max_abs() * z / (EXP_SERIES_TERMS + 1) as f64);
3721    // Every later term ratio is at most z, so a geometric majorant is valid.
3722    let tail = next_up(first_omitted / next_down(1.0 - z));
3723    let mut result = sum.widen(tail);
3724    for _ in 0..EXP_RANGE_SQUARINGS {
3725        result = result.square();
3726    }
3727    result = result.mul(ClosedInterval::point(exact_power_of_two(exponent)?));
3728    Some(result.nonnegative())
3729}
3730
3731#[inline]
3732fn certified_midpoint(interval: ClosedInterval) -> f64 {
3733    let midpoint = interval.lo + 0.5 * (interval.hi - interval.lo);
3734    midpoint.max(interval.lo).min(interval.hi)
3735}
3736
3737/// Deterministic representative of [`certified_exp`].
3738///
3739/// This midpoint is for downstream floating-point evaluation only; callers
3740/// needing a proof must retain the full enclosure returned by
3741/// [`certified_exp`].
3742#[inline]
3743pub fn certified_exp_representative(value: f64) -> Option<f64> {
3744    certified_exp(value).map(certified_midpoint)
3745}
3746
3747#[inline]
3748fn certified_ln_value(value: f64) -> Option<f64> {
3749    certified_ln_positive(value).map(certified_midpoint)
3750}
3751
3752#[inline]
3753fn certified_ln_1p_value(value: f64) -> Option<f64> {
3754    certified_ln_1p(value).map(certified_midpoint)
3755}
3756
3757fn interval_diameter(interval: ClosedInterval) -> f64 {
3758    if interval.lo == interval.hi {
3759        0.0
3760    } else {
3761        next_up(interval.hi - interval.lo)
3762    }
3763}
3764
3765fn log_series_tail_max() -> f64 {
3766    let z = next_up(1.0 / 3.0);
3767    let z2 = next_up(z * z);
3768    let mut power = z;
3769    for _ in 1..LOG_SERIES_TERMS {
3770        power = next_up(power * z2);
3771    }
3772    power = next_up(power * z2);
3773    let denominator = next_down((2 * LOG_SERIES_TERMS + 1) as f64 * next_down(1.0 - z2));
3774    next_up(next_up(2.0 * power) / denominator)
3775}
3776
3777/// Uniform absolute remainder of the reduced exponential Taylor series on
3778/// `[-1/16, 1/16]`, propagated through the six restoring squarings as a
3779/// relative error. This is computed only with outward basic arithmetic.
3780fn exp_series_relative_tail_max() -> f64 {
3781    let z = next_up(1.0 / 16.0);
3782    let mut term = 1.0;
3783    for degree in 1..=EXP_SERIES_TERMS {
3784        term = next_up(next_up(term * z) / degree as f64);
3785    }
3786    let first_omitted = next_up(next_up(term * z) / (EXP_SERIES_TERMS + 1) as f64);
3787    let absolute_tail = next_up(first_omitted / next_down(1.0 - z));
3788    // exp(reduced) >= exp(-1/16) > 1/2, hence its relative error is at most
3789    // twice the absolute Taylor tail. Raising the reduced result to 64 raises
3790    // the multiplicative error factor to the same power.
3791    let mut factor =
3792        ClosedInterval::point(1.0).add(ClosedInterval::point(next_up(2.0 * absolute_tail)));
3793    for _ in 0..EXP_RANGE_SQUARINGS {
3794        factor = factor.square();
3795    }
3796    next_up(factor.hi - 1.0).max(0.0)
3797}
3798
3799/// Uniform forward-error bound for the midpoint returned by
3800/// [`certified_ln_value`] over a positive input interval.
3801fn certified_log_forward_error(input: ClosedInterval) -> f64 {
3802    if !(input.lo > 0.0 && input.hi.is_finite()) {
3803        return f64::INFINITY;
3804    }
3805    let exponent_abs = [input.lo, input.hi]
3806        .into_iter()
3807        .map(|value| {
3808            let bits = value.to_bits();
3809            let exponent_bits = ((bits >> 52) & 0x7ff) as i32;
3810            if exponent_bits == 0 {
3811                let fraction = bits & ((1_u64 << 52) - 1);
3812                let highest = 63_i32 - fraction.leading_zeros() as i32;
3813                (highest - 1074).unsigned_abs() as f64
3814            } else {
3815                (exponent_bits - 1023).unsigned_abs() as f64
3816            }
3817        })
3818        .fold(0.0_f64, f64::max);
3819    let ln_two_uncertainty = next_up(exponent_abs * interval_diameter(certified_ln_two()));
3820    // Per term: power multiply, division, and accumulation, with two directed
3821    // endpoints; the remainder and range-combination path add 32 operations.
3822    let mantissa_ops = 6 * LOG_SERIES_TERMS + 32;
3823    let mantissa_error =
3824        add_nonnegative_upward(wilkinson_roundoff(1.0, mantissa_ops), log_series_tail_max());
3825    add_nonnegative_upward(ln_two_uncertainty, mantissa_error)
3826}
3827
3828fn certified_log_error_from_output(output: ClosedInterval) -> f64 {
3829    if !output.is_valid() {
3830        return f64::INFINITY;
3831    }
3832    // |ln(input)|/ln(2) bounds the binary exponent to one neighboring bin.
3833    let exponent_abs = next_up(output.max_abs() / certified_ln_two().lo.abs()).ceil() + 1.0;
3834    let ln_two_uncertainty = next_up(exponent_abs * interval_diameter(certified_ln_two()));
3835    let mantissa_ops = 6 * LOG_SERIES_TERMS + 32;
3836    add_nonnegative_upward(
3837        ln_two_uncertainty,
3838        add_nonnegative_upward(wilkinson_roundoff(1.0, mantissa_ops), log_series_tail_max()),
3839    )
3840}
3841
3842fn certified_ln1p_forward_error() -> f64 {
3843    let operations = 6 * LOG_SERIES_TERMS + 36;
3844    add_nonnegative_upward(wilkinson_roundoff(1.0, operations), log_series_tail_max())
3845}
3846
3847/// Uniform absolute forward-error bound for [`certified_exp_representative`] on an
3848/// input interval, including range-reduction uncertainty and gradual
3849/// underflow.
3850fn certified_exp_forward_error(input: ClosedInterval, output: ClosedInterval) -> f64 {
3851    if !(input.is_valid() && output.is_valid() && output.lo >= 0.0) {
3852        return f64::INFINITY;
3853    }
3854    let exponent_abs = next_up(input.max_abs() / certified_ln_two().lo).ceil() + 1.0;
3855    let reduction_error = next_up(exponent_abs * interval_diameter(certified_ln_two()));
3856    if !(reduction_error < 1.0) {
3857        return f64::INFINITY;
3858    }
3859    // exp(delta)-1 <= delta/(1-delta) for 0 <= delta < 1.
3860    let propagated_reduction =
3861        next_up(output.max_abs() * reduction_error / next_down(1.0 - reduction_error));
3862    // Taylor recurrence, remainder, six squarings, and final binary scaling;
3863    // count both directed endpoints of each basic operation.
3864    let operations = 6 * EXP_SERIES_TERMS + 4 * EXP_RANGE_SQUARINGS + 40;
3865    let arithmetic = wilkinson_roundoff(output.max_abs(), operations);
3866    let truncation = next_up(output.max_abs() * exp_series_relative_tail_max());
3867    add_nonnegative_upward(
3868        propagated_reduction,
3869        add_nonnegative_upward(arithmetic, truncation),
3870    )
3871}
3872
3873/// Uniform relative forward-error bound for
3874/// [`certified_exp_representative`] on an input interval whose exponential is
3875/// certified strictly positive.
3876///
3877/// The absolute bound above scales every multiplicative contribution by the
3878/// largest output in the interval. Dividing that result by the smallest output
3879/// couples opposite endpoints and can overflow on a wide interval even though
3880/// exp has a finite scale-independent relative error. Keep the range-reduction,
3881/// arithmetic, and truncation terms in relative currency instead. Only gradual
3882/// underflow is genuinely additive, so only that allowance is divided by the
3883/// certified positive lower output.
3884fn certified_exp_relative_forward_error(input: ClosedInterval, output: ClosedInterval) -> f64 {
3885    if !(input.is_valid() && output.is_valid() && output.lo > 0.0 && output.hi.is_finite()) {
3886        return f64::INFINITY;
3887    }
3888    let exponent_abs = next_up(input.max_abs() / certified_ln_two().lo).ceil() + 1.0;
3889    let reduction_error = next_up(exponent_abs * interval_diameter(certified_ln_two()));
3890    if !(reduction_error < 1.0) {
3891        return f64::INFINITY;
3892    }
3893    let relative_reduction = next_up(reduction_error / next_down(1.0 - reduction_error));
3894    let operations = 6 * EXP_SERIES_TERMS + 4 * EXP_RANGE_SQUARINGS + 40;
3895    let relative_arithmetic = wilkinson_roundoff(1.0, operations);
3896    let relative_underflow = next_up(wilkinson_roundoff(0.0, operations) / output.lo);
3897    add_nonnegative_upward(
3898        relative_reduction,
3899        add_nonnegative_upward(
3900            relative_arithmetic,
3901            add_nonnegative_upward(exp_series_relative_tail_max(), relative_underflow),
3902        ),
3903    )
3904}
3905
3906/// Upward-rounded accumulation of a nonnegative magnitude bound.
3907fn add_nonnegative_upward(accumulator: f64, term: f64) -> f64 {
3908    if accumulator == f64::INFINITY || term == f64::INFINITY {
3909        f64::INFINITY
3910    } else if term == 0.0 {
3911        accumulator
3912    } else {
3913        next_up(accumulator + term)
3914    }
3915}
3916
3917/// Symmetric absolute radius needed to widen `mathematical` until it contains
3918/// the already-computed `resolved` interval.
3919fn enclosure_excess(mathematical: ClosedInterval, resolved: ClosedInterval) -> f64 {
3920    let lower = if mathematical.lo == resolved.lo {
3921        0.0
3922    } else {
3923        next_up(mathematical.lo - resolved.lo)
3924    };
3925    let upper = if mathematical.hi == resolved.hi {
3926        0.0
3927    } else {
3928        next_up(resolved.hi - mathematical.hi)
3929    };
3930    lower.max(upper).max(0.0)
3931}
3932
3933/// Wilkinson forward-error bound for `k` round-to-nearest binary64
3934/// operations. The normal-range `gamma_k * magnitude` term is accompanied by
3935/// `k` minimum-subnormal units, covering gradual-underflow roundoff where a
3936/// purely relative model is invalid.
3937fn wilkinson_roundoff(magnitude: f64, operations: usize) -> f64 {
3938    if operations == 0 {
3939        return 0.0;
3940    }
3941    if !(magnitude.is_finite() && magnitude >= 0.0) {
3942        return f64::INFINITY;
3943    }
3944    // Convert the integer count upward before either product. For counts above
3945    // 2^53, `as f64` can round down; charging only one ulp after multiplication
3946    // would then combine two rounding steps into an unjustified one-step
3947    // bound.
3948    let operation_count = next_up(operations as f64);
3949    let underflow = next_up(operation_count * f64::from_bits(1));
3950    if magnitude == 0.0 {
3951        return underflow;
3952    }
3953    // IEEE-754 binary64 unit roundoff under round-to-nearest.
3954    let unit_roundoff = 0.5 * f64::EPSILON;
3955    let ku = next_up(operation_count * unit_roundoff);
3956    if !(ku < 1.0) {
3957        return f64::INFINITY;
3958    }
3959    let denominator = next_down(1.0 - ku);
3960    if !(denominator > 0.0) {
3961        return f64::INFINITY;
3962    }
3963    let gamma = next_up(ku / denominator);
3964    add_nonnegative_upward(next_up(gamma * magnitude), underflow)
3965}
3966
3967#[inline]
3968fn sum_down(left: f64, right: f64) -> f64 {
3969    let value = left + right;
3970    if sum_is_exact(left, right, value) {
3971        value
3972    } else {
3973        next_down(value)
3974    }
3975}
3976
3977#[inline]
3978fn sum_up(left: f64, right: f64) -> f64 {
3979    let value = left + right;
3980    if sum_is_exact(left, right, value) {
3981        value
3982    } else {
3983        next_up(value)
3984    }
3985}
3986
3987/// Whether binary64 addition produced the exact-real sum.
3988///
3989/// Knuth's `TwoSum` residual is itself exact under IEEE round-to-nearest with
3990/// gradual underflow. Besides avoiding needless interval inflation, retaining
3991/// exact cancellation is semantically important: structural zeros in diffuse
3992/// covariance recurrences must remain `[0, 0]`, not become artificial
3993/// minimum-subnormal uncertainty.
3994#[inline]
3995fn sum_is_exact(left: f64, right: f64, value: f64) -> bool {
3996    if left == 0.0 || right == 0.0 {
3997        return true;
3998    }
3999    if !(left.is_finite() && right.is_finite() && value.is_finite()) {
4000        return value == left || value == right;
4001    }
4002    let virtual_right = value - left;
4003    let virtual_left = value - virtual_right;
4004    let right_residual = right - virtual_right;
4005    let left_residual = left - virtual_left;
4006    left_residual + right_residual == 0.0
4007}
4008
4009#[inline]
4010fn product_is_exact(left: f64, right: f64) -> bool {
4011    left == 0.0 || right == 0.0 || left.abs() == 1.0 || right.abs() == 1.0
4012}
4013
4014#[inline]
4015fn product_down(left: f64, right: f64) -> f64 {
4016    let value = left * right;
4017    if product_is_exact(left, right) {
4018        if value.is_nan() { 0.0 } else { value }
4019    } else {
4020        next_down(value)
4021    }
4022}
4023
4024#[inline]
4025fn product_up(left: f64, right: f64) -> f64 {
4026    let value = left * right;
4027    if product_is_exact(left, right) {
4028        if value.is_nan() { 0.0 } else { value }
4029    } else {
4030        next_up(value)
4031    }
4032}
4033
4034#[inline]
4035fn quotient_down(numerator: f64, denominator: f64) -> f64 {
4036    let value = numerator / denominator;
4037    if numerator == 0.0 || denominator.abs() == 1.0 {
4038        value
4039    } else {
4040        next_down(value)
4041    }
4042}
4043
4044#[inline]
4045fn quotient_up(numerator: f64, denominator: f64) -> f64 {
4046    let value = numerator / denominator;
4047    if numerator == 0.0 || denominator.abs() == 1.0 {
4048        value
4049    } else {
4050        next_up(value)
4051    }
4052}
4053
4054/// Next representable number below `value`, used for directed outward
4055/// rounding of interval lower bounds.
4056fn next_down(value: f64) -> f64 {
4057    if value.is_nan() || value == f64::NEG_INFINITY {
4058        return value;
4059    }
4060    if value == 0.0 {
4061        return -f64::from_bits(1);
4062    }
4063    let bits = value.to_bits();
4064    f64::from_bits(if value > 0.0 { bits - 1 } else { bits + 1 })
4065}
4066
4067/// Next representable number above `value`, used for directed outward
4068/// rounding of interval upper bounds.
4069fn next_up(value: f64) -> f64 {
4070    if value.is_nan() || value == f64::INFINITY {
4071        return value;
4072    }
4073    if value == 0.0 {
4074        return f64::from_bits(1);
4075    }
4076    let bits = value.to_bits();
4077    f64::from_bits(if value > 0.0 { bits + 1 } else { bits - 1 })
4078}
4079
4080#[cfg(test)]
4081mod tests {
4082    use super::*;
4083
4084    fn polynomial_hidden_bump_jet(x: f64) -> ScoreJet {
4085        let p = x * (x - 0.5) * (x - 1.0);
4086        let dp = 3.0 * x * x - 3.0 * x + 0.5;
4087        let ddp = 6.0 * x - 3.0;
4088        ScoreJet {
4089            value: x + 1000.0 * p * p,
4090            derivative: 1.0 + 2000.0 * p * dp,
4091            curvature: 2000.0 * (dp * dp + p * ddp),
4092            third: 2000.0 * (3.0 * dp * ddp + p * 6.0),
4093        }
4094    }
4095
4096    fn polynomial_hidden_bump_enclosure(lo: f64, hi: f64) -> DerivativeEnclosure {
4097        let x = ClosedInterval::new(lo, hi);
4098        let p = x
4099            .mul(x.sub(ClosedInterval::point(0.5)))
4100            .mul(x.sub(ClosedInterval::point(1.0)));
4101        let dp = x
4102            .square()
4103            .scale(3.0)
4104            .sub(x.scale(3.0))
4105            .add(ClosedInterval::point(0.5));
4106        let ddp = x.scale(6.0).sub(ClosedInterval::point(3.0));
4107        let value = x.add(p.square().scale(1000.0));
4108        DerivativeEnclosure {
4109            score: ScoreValueEnclosure {
4110                value,
4111                evaluation_error: wilkinson_roundoff(value.max_abs(), 7),
4112            },
4113            derivative: ClosedInterval::point(1.0).add(p.mul(dp).scale(2000.0)),
4114            curvature: dp.square().add(p.mul(ddp)).scale(2000.0),
4115        }
4116    }
4117
4118    #[test]
4119    fn hidden_between_endpoint_and_midpoint_samples_is_found() {
4120        let result = maximize_score_1d(
4121            0.0,
4122            1.0,
4123            1.0e-9,
4124            |x| -> Result<_, String> { Ok(polynomial_hidden_bump_jet(x)) },
4125            |lo, hi| -> Result<_, String> { Ok(polynomial_hidden_bump_enclosure(lo.x, hi.x)) },
4126        )
4127        .expect("certified search");
4128
4129        // At x=0, 1/2, 1 both value and derivative agree exactly with f=x;
4130        // the former midpoint/Hermite heuristic therefore returned x=1.
4131        assert_eq!(polynomial_hidden_bump_jet(0.0).derivative, 1.0);
4132        assert_eq!(polynomial_hidden_bump_jet(0.5).derivative, 1.0);
4133        assert_eq!(polynomial_hidden_bump_jet(1.0).derivative, 1.0);
4134        assert!(result.optimum.x > 0.5 && result.optimum.x < 1.0);
4135        assert!(result.optimum.value > 2.9);
4136        assert!(
4137            result
4138                .stationary_points
4139                .iter()
4140                .any(|point| point.bracket.contains(result.optimum.x)),
4141            "the hidden global maximizer must have a retained root certificate"
4142        );
4143        assert!(
4144            result
4145                .dominated_regions
4146                .iter()
4147                .all(|region| region.score.value.hi < region.incumbent_lower),
4148            "every skipped stationary branch must carry a strict exact dominance proof"
4149        );
4150    }
4151
4152    fn quartic_jet(x: f64) -> ScoreJet {
4153        ScoreJet {
4154            value: -(x * x - 1.0).powi(2),
4155            derivative: 4.0 * x - 4.0 * x * x * x,
4156            curvature: 4.0 - 12.0 * x * x,
4157            third: -24.0 * x,
4158        }
4159    }
4160
4161    fn quartic_enclosure(lo: f64, hi: f64) -> DerivativeEnclosure {
4162        let x = ClosedInterval::new(lo, hi);
4163        let shifted_square = x.square().sub(ClosedInterval::point(1.0));
4164        let value = shifted_square.square().neg();
4165        if lo == hi && (lo == -1.0 || lo == 0.0 || lo == 1.0) {
4166            return DerivativeEnclosure {
4167                score: ScoreValueEnclosure {
4168                    value,
4169                    evaluation_error: wilkinson_roundoff(value.max_abs(), 4),
4170                },
4171                derivative: ClosedInterval::point(0.0),
4172                curvature: ClosedInterval::point(quartic_jet(lo).curvature),
4173            };
4174        }
4175        DerivativeEnclosure {
4176            score: ScoreValueEnclosure {
4177                value,
4178                evaluation_error: wilkinson_roundoff(value.max_abs(), 4),
4179            },
4180            derivative: x.scale(4.0).sub(x.mul(x).mul(x).scale(4.0)),
4181            curvature: ClosedInterval::point(4.0).sub(x.square().scale(12.0)),
4182        }
4183    }
4184
4185    #[test]
4186    fn globally_relevant_roots_are_isolated_and_dominated_structure_is_audited() {
4187        let result = maximize_score_1d(
4188            -2.0,
4189            2.0,
4190            1.0e-10,
4191            |x| -> Result<_, String> { Ok(quartic_jet(x)) },
4192            |lo, hi| -> Result<_, String> { Ok(quartic_enclosure(lo.x, hi.x)) },
4193        )
4194        .expect("certified search");
4195        assert_eq!(
4196            result.stationary_points.len(),
4197            2,
4198            "both equal global maxima must survive strict dominance"
4199        );
4200        for expected in [-1.0_f64, 1.0] {
4201            let point = result
4202                .stationary_points
4203                .iter()
4204                .find(|point| (point.sample.x - expected).abs() <= 1.0e-9)
4205                .unwrap_or_else(|| panic!("missing global maximum at {expected}"));
4206            assert!(point.bracket.hi - point.bracket.lo <= 1.0e-10);
4207        }
4208        assert!(
4209            result
4210                .dominated_regions
4211                .iter()
4212                .any(|region| region.bracket.contains(0.0)),
4213            "the strictly inferior stationary minimum must remain auditable as dominated"
4214        );
4215        assert!((result.optimum.x.abs() - 1.0).abs() <= 1.0e-9);
4216    }
4217
4218    #[test]
4219    fn exact_dominance_prunes_an_uninformative_saturated_tail() {
4220        let mut evaluations = 0_usize;
4221        let result = maximize_score_1d(
4222            -1.0,
4223            10.0,
4224            1.0e-9,
4225            |x| -> Result<_, String> {
4226                evaluations += 1;
4227                Ok(ScoreJet {
4228                    value: 1.0 - x * x,
4229                    derivative: -2.0 * x,
4230                    curvature: -2.0,
4231                    third: 0.0,
4232                })
4233            },
4234            |left, right| -> Result<_, String> {
4235                let x = ClosedInterval::new(left.x, right.x);
4236                let value = ClosedInterval::point(1.0).sub(x.square());
4237                let root_side_cell = right.x <= 1.0;
4238                Ok(DerivativeEnclosure {
4239                    score: ScoreValueEnclosure {
4240                        value,
4241                        evaluation_error: 1.0e-12,
4242                    },
4243                    derivative: if root_side_cell || left.x == right.x {
4244                        x.scale(-2.0)
4245                    } else {
4246                        // This deliberately dependency-heavy extension carries
4247                        // no stationary information in the low-score tail.
4248                        ClosedInterval::new(-100.0, 100.0)
4249                    },
4250                    curvature: if root_side_cell || left.x == right.x {
4251                        ClosedInterval::point(-2.0)
4252                    } else {
4253                        ClosedInterval::new(-100.0, 100.0)
4254                    },
4255                })
4256            },
4257        )
4258        .expect("the exact score incumbent must dominate the uninformative tail");
4259
4260        assert_eq!(result.optimum.x, 0.0);
4261        assert!(result.value_certificate.maximum.contains(1.0));
4262        assert!(
4263            !result.dominated_regions.is_empty(),
4264            "the fixture's saturated tail must be terminated by exact dominance"
4265        );
4266        assert!(
4267            result
4268                .dominated_regions
4269                .iter()
4270                .all(|region| region.score.value.hi < region.incumbent_lower),
4271            "every retained dominance decision must expose its strict exact ordering"
4272        );
4273        assert!(
4274            evaluations < 16,
4275            "the low-score tail was enumerated instead of pruned ({evaluations} evaluations)"
4276        );
4277    }
4278
4279    /// The abscissa at which this fixture's point oracle reports a derivative
4280    /// of exactly zero while the exact derivative is two.
4281    const ROUNDED_ZERO_ABSCISSA: f64 = 1.5;
4282
4283    /// A point derivative that rounds to zero cannot close its parent cell.
4284    ///
4285    /// The exact score is the concave quadratic `1 - (x - 2.5)^2` on `[0, 3]`.
4286    /// Its only stationary point and maximum is exactly representable at
4287    /// `x=2.5`.
4288    /// The point oracle deliberately loses the nonzero derivative at the
4289    /// safeguarded midpoint `x=1.5`, while the exact-real enclosure reports the
4290    /// true derivative range through interval arithmetic. The initial Newton
4291    /// proposal at `x=3` is `2.5`, outside the central-half guard, so the
4292    /// midpoint is exercised deterministically. Treating its rounded scalar
4293    /// zero as a root closes the left half, discards the real maximum, and
4294    /// leaves the rounded-value selection at boundary `x=3`, whose score is
4295    /// `0.75`. The point enclosure introduced by the exact-real repair
4296    /// distinguishes that false zero from the quadratic's exact zero at
4297    /// `x=2.5`.
4298    #[test]
4299    fn a_rounded_zero_at_a_cell_endpoint_does_not_close_the_cell() {
4300        let mut rounded_zeros = 0_usize;
4301        let result = maximize_score_1d(
4302            0.0,
4303            3.0,
4304            1.0e-9,
4305            |x| -> Result<_, String> {
4306                let shifted = x - 2.5;
4307                let derivative = if x == ROUNDED_ZERO_ABSCISSA {
4308                    rounded_zeros += 1;
4309                    0.0
4310                } else {
4311                    -2.0 * shifted
4312                };
4313                Ok(ScoreJet {
4314                    value: 1.0 - shifted * shifted,
4315                    derivative,
4316                    curvature: -2.0,
4317                    third: 0.0,
4318                })
4319            },
4320            |left, right| -> Result<_, String> {
4321                let x = ClosedInterval::new(left.x, right.x);
4322                let shifted = x.sub(ClosedInterval::point(2.5));
4323                let value = ClosedInterval::point(1.0).sub(shifted.square());
4324                Ok(DerivativeEnclosure {
4325                    score: ScoreValueEnclosure {
4326                        value,
4327                        evaluation_error: wilkinson_roundoff(value.max_abs(), 3),
4328                    },
4329                    // Preserve the quadratic's structural zero at x=2.5 instead
4330                    // of manufacturing cancellation through `5 - 2x`.
4331                    derivative: shifted.scale(-2.0),
4332                    curvature: ClosedInterval::point(-2.0),
4333                })
4334            },
4335        )
4336        .expect("certified search");
4337
4338        assert!(
4339            rounded_zeros > 0,
4340            "fixture premise unmet: the search never evaluated x = {ROUNDED_ZERO_ABSCISSA}"
4341        );
4342        assert!(
4343            (result.optimum.x - 2.5).abs() <= 1.0e-9,
4344            "reported the maximum at x={} (value {}) instead of x=2.5",
4345            result.optimum.x,
4346            result.optimum.value,
4347        );
4348        assert!(
4349            result.value_certificate.maximum.contains(1.0),
4350            "the exact maximum escaped the global score certificate: {:?}",
4351            result.value_certificate,
4352        );
4353        assert!(
4354            result
4355                .stationary_points
4356                .iter()
4357                .all(|point| point.sample.x != ROUNDED_ZERO_ABSCISSA),
4358            "a derivative that rounded to zero was reported as a stationary point",
4359        );
4360        let root = result
4361            .stationary_points
4362            .iter()
4363            .find(|point| point.bracket.contains(2.5))
4364            .expect("the exact quadratic root must be isolated");
4365        assert_eq!(
4366            root.bracket,
4367            ClosedInterval::point(2.5),
4368            "the cancellation-free point enclosure must preserve the exact dyadic root"
4369        );
4370    }
4371
4372    #[test]
4373    fn adjacent_cell_evidence_is_retained_when_point_derivative_is_uninformative() {
4374        let planted = 0.7_f64;
4375        let result = maximize_score_1d(
4376            0.0,
4377            1.0,
4378            1.0e-9,
4379            |x| -> Result<_, String> {
4380                let shifted = x - planted;
4381                Ok(ScoreJet {
4382                    value: 1.0 - shifted * shifted,
4383                    derivative: -2.0 * shifted,
4384                    curvature: -2.0,
4385                    third: 0.0,
4386                })
4387            },
4388            |left, right| -> Result<_, String> {
4389                let x = ClosedInterval::new(left.x, right.x);
4390                let shifted = x.sub(ClosedInterval::point(planted));
4391                let value = ClosedInterval::point(1.0).sub(shifted.square());
4392                let interior_point = left.x == right.x && left.x > 0.0 && left.x < 1.0;
4393                Ok(DerivativeEnclosure {
4394                    score: ScoreValueEnclosure {
4395                        value,
4396                        evaluation_error: wilkinson_roundoff(value.max_abs(), 3),
4397                    },
4398                    // Model a cancellation-heavy degenerate-cell formula: by
4399                    // itself it carries no sign. Each adjacent nondegenerate
4400                    // interval remains a tight exact extension, and their
4401                    // intersection at the shared endpoint isolates the root.
4402                    derivative: if interior_point {
4403                        ClosedInterval::new(-2.0, 2.0)
4404                    } else {
4405                        shifted.scale(-2.0)
4406                    },
4407                    curvature: ClosedInterval::point(-2.0),
4408                })
4409            },
4410        )
4411        .expect("adjacent exact cell evidence must isolate the unique root");
4412
4413        assert!(
4414            (result.optimum.x - planted).abs() <= 1.0e-9,
4415            "selected {}, expected {planted}",
4416            result.optimum.x
4417        );
4418        let stationary = result
4419            .stationary_points
4420            .iter()
4421            .find(|point| point.bracket.contains(planted))
4422            .expect("the planted stationary point must be certified");
4423        assert!(stationary.bracket.hi - stationary.bracket.lo <= 1.0e-9);
4424    }
4425
4426    #[test]
4427    fn signed_endpoint_newton_reaches_the_existing_score_resolution_floor() {
4428        let planted = 0.8_f64;
4429        let ambiguous_probe = 0.5_f64;
4430        let mut ambiguous_probe_calls = 0_usize;
4431        let result = maximize_score_1d(
4432            0.0,
4433            1.0,
4434            1.0e-9,
4435            |x| -> Result<_, String> {
4436                let shifted = x - planted;
4437                Ok(ScoreJet {
4438                    value: 1.0 - shifted * shifted,
4439                    derivative: -2.0 * shifted,
4440                    curvature: -2.0,
4441                    third: 0.0,
4442                })
4443            },
4444            |left, right| -> Result<_, String> {
4445                let x = ClosedInterval::new(left.x, right.x);
4446                let shifted = x.sub(ClosedInterval::point(planted));
4447                let value = ClosedInterval::point(1.0).sub(shifted.square());
4448                let derivative = if left.x == right.x {
4449                    if left.x == ambiguous_probe {
4450                        ambiguous_probe_calls += 1;
4451                        ClosedInterval::new(-2.0, 2.0)
4452                    } else {
4453                        ClosedInterval::point(-2.0 * (left.x - planted))
4454                    }
4455                } else {
4456                    // A deliberately dependency-heavy cell extension. It is
4457                    // valid, but neither it nor the ambiguous point image can
4458                    // contract the first midpoint probe.
4459                    ClosedInterval::new(-2.0, 2.0)
4460                };
4461                Ok(DerivativeEnclosure {
4462                    score: ScoreValueEnclosure {
4463                        value,
4464                        // The exact score motion on the first endpoint-Newton
4465                        // image is 0.04. A valid 0.021 point forward-error bound
4466                        // makes that information floor 0.042, while the initial
4467                        // domain's 0.64 score motion remains visibly nonflat.
4468                        evaluation_error: 0.021,
4469                    },
4470                    derivative,
4471                    // Strictly oriented but deliberately wider than the exact
4472                    // constant curvature -2.
4473                    curvature: ClosedInterval::new(-4.0, -1.0),
4474                })
4475            },
4476        )
4477        .expect("signed endpoint Newton images must reach a typed score-resolution proof");
4478
4479        assert!(
4480            ambiguous_probe_calls > 0,
4481            "fixture premise unmet: the cancellation-heavy midpoint was never certified"
4482        );
4483        let ScoreOptimumLocation::ResolutionFlat(index) = result.location else {
4484            panic!(
4485                "the unique root's location is below the declared information floor: {:?}",
4486                result.location
4487            );
4488        };
4489        let flat = result.resolution_flat_regions[index];
4490        assert!(
4491            flat.bracket.contains(planted),
4492            "contracted flat bracket {:?} lost the unique root",
4493            flat.bracket
4494        );
4495        assert!(
4496            flat.max_score_gap <= flat.score_resolution,
4497            "typed flat proof exceeded its existing evaluator floor: {flat:?}"
4498        );
4499        assert!(result.stationary_points.is_empty());
4500    }
4501
4502    #[test]
4503    fn monotone_score_selects_exact_boundary() {
4504        let result = maximize_score_1d(
4505            -4.0,
4506            9.0,
4507            1.0e-9,
4508            |x| -> Result<_, String> {
4509                Ok(ScoreJet {
4510                    value: 0.3 * x,
4511                    derivative: 0.3,
4512                    curvature: 0.0,
4513                    third: 0.0,
4514                })
4515            },
4516            |left, right| -> Result<_, String> {
4517                let value = ClosedInterval::new(left.x, right.x).scale(0.3);
4518                Ok(DerivativeEnclosure {
4519                    score: ScoreValueEnclosure {
4520                        value,
4521                        evaluation_error: wilkinson_roundoff(value.max_abs(), 1),
4522                    },
4523                    derivative: ClosedInterval::point(0.3),
4524                    curvature: ClosedInterval::point(0.0),
4525                })
4526            },
4527        )
4528        .expect("certified search");
4529        assert_eq!(result.location, ScoreOptimumLocation::UpperBoundary);
4530        assert_eq!(result.optimum.x, 9.0);
4531        assert!(result.stationary_points.is_empty());
4532        assert_eq!(
4533            result.value_certificate.maximum_excess, 0.0,
4534            "the exact same terminal point is not a competing uncertain value"
4535        );
4536    }
4537
4538    #[test]
4539    fn certified_increase_selects_upper_boundary_when_rounded_values_tie() {
4540        let result = maximize_score_1d(
4541            -1.0,
4542            1.0,
4543            1.0e-9,
4544            |_| -> Result<_, String> {
4545                Ok(ScoreJet {
4546                    value: 0.0,
4547                    derivative: 1.0,
4548                    curvature: 0.0,
4549                    third: 0.0,
4550                })
4551            },
4552            |left, right| -> Result<_, String> {
4553                Ok(DerivativeEnclosure {
4554                    score: ScoreValueEnclosure {
4555                        value: ClosedInterval::new(left.x, right.x),
4556                        evaluation_error: 1.0,
4557                    },
4558                    derivative: ClosedInterval::point(1.0),
4559                    curvature: ClosedInterval::point(0.0),
4560                })
4561            },
4562        )
4563        .expect("a whole-domain positive derivative orders tied rounded endpoints");
4564        assert_eq!(result.lower_boundary.value, result.upper_boundary.value);
4565        assert_eq!(result.location, ScoreOptimumLocation::UpperBoundary);
4566        assert_eq!(result.optimum.x, 1.0);
4567        assert_eq!(result.value_certificate.maximum_excess, 0.0);
4568    }
4569
4570    #[test]
4571    fn certified_decrease_selects_lower_boundary_when_rounded_values_tie() {
4572        let result = maximize_score_1d(
4573            -1.0,
4574            1.0,
4575            1.0e-9,
4576            |_| -> Result<_, String> {
4577                Ok(ScoreJet {
4578                    value: 0.0,
4579                    derivative: -1.0,
4580                    curvature: 0.0,
4581                    third: 0.0,
4582                })
4583            },
4584            |left, right| -> Result<_, String> {
4585                Ok(DerivativeEnclosure {
4586                    score: ScoreValueEnclosure {
4587                        value: ClosedInterval::new(-right.x, -left.x),
4588                        evaluation_error: 1.0,
4589                    },
4590                    derivative: ClosedInterval::point(-1.0),
4591                    curvature: ClosedInterval::point(0.0),
4592                })
4593            },
4594        )
4595        .expect("a whole-domain negative derivative orders tied rounded endpoints");
4596        assert_eq!(result.lower_boundary.value, result.upper_boundary.value);
4597        assert_eq!(result.location, ScoreOptimumLocation::LowerBoundary);
4598        assert_eq!(result.optimum.x, -1.0);
4599        assert_eq!(result.value_certificate.maximum_excess, 0.0);
4600    }
4601
4602    #[test]
4603    fn tangential_nonmaximum_structure_is_closed_by_exact_dominance() {
4604        let result = maximize_score_1d(
4605            -1.0,
4606            1.0,
4607            1.0e-8,
4608            |x| -> Result<_, String> {
4609                Ok(ScoreJet {
4610                    value: x * x * x,
4611                    derivative: 3.0 * x * x,
4612                    curvature: 6.0 * x,
4613                    third: 6.0,
4614                })
4615            },
4616            |lo, hi| -> Result<_, String> {
4617                let x = ClosedInterval::new(lo.x, hi.x);
4618                Ok(DerivativeEnclosure {
4619                    score: ScoreValueEnclosure {
4620                        value: x.mul(x).mul(x),
4621                        evaluation_error: f64::EPSILON,
4622                    },
4623                    derivative: x.square().scale(3.0),
4624                    curvature: x.scale(6.0),
4625                })
4626            },
4627        )
4628        .expect("the inferior inflection is immaterial by exact score ordering");
4629        assert_eq!(result.location, ScoreOptimumLocation::UpperBoundary);
4630        assert!(
4631            !result.dominated_regions.is_empty(),
4632            "the search must record the exact dominance proof instead of silently dropping the cell"
4633        );
4634        for region in result.dominated_regions {
4635            assert!(region.score.value.hi < region.incumbent_lower);
4636        }
4637    }
4638
4639    #[test]
4640    fn unresolved_nonflat_cell_remains_typed() {
4641        let error = maximize_score_1d(
4642            0.0,
4643            1.0e-8,
4644            1.0e-8,
4645            |x| -> Result<_, String> {
4646                Ok(ScoreJet {
4647                    value: x,
4648                    derivative: 0.0,
4649                    curvature: 0.0,
4650                    third: 0.0,
4651                })
4652            },
4653            |lo, hi| -> Result<_, String> {
4654                Ok(DerivativeEnclosure {
4655                    score: ScoreValueEnclosure {
4656                        value: ClosedInterval::new(lo.x, hi.x),
4657                        evaluation_error: 0.0,
4658                    },
4659                    derivative: ClosedInterval::new(-1.0, 1.0),
4660                    curvature: ClosedInterval::new(-1.0, 1.0),
4661                })
4662            },
4663        )
4664        .expect_err("a derivative enclosure admitting visible score motion is not flat");
4665        assert!(matches!(error, ScoreSearchError::Unresolved { .. }));
4666    }
4667
4668    /// BREADTH exhaustion, which is a different failure from the per-cell depth
4669    /// floor and was #2546's non-termination.
4670    ///
4671    /// The oracle's derivative and curvature enclosures always straddle zero, so
4672    /// no cell is ever excluded by a sign or isolated as a root; but its score
4673    /// range collapses with the cell against a FIXED evaluation error, so every
4674    /// cell does terminate — as resolution-flat — once it is narrower than
4675    /// `2 * evaluation_error`. That is the regime the cascade is in: cells
4676    /// certify, at widths far above `resolution`, and the traversal simply needs
4677    /// too many of them. The flat width here is 1e-3 of a 32-wide domain, so the
4678    /// decomposition is ~2^15 = 32 768 cells and no cell ever reaches the
4679    /// resolution floor — `ScoreSearchError::Unresolved` cannot fire, and
4680    /// without a breadth budget nothing else can either.
4681    ///
4682    /// Contrast `unresolved_nonflat_cell_remains_typed`, whose oracle certifies
4683    /// NOTHING at any width: that one bottoms out on the depth floor after `D`
4684    /// subdivisions and is already typed. The two are not interchangeable.
4685    #[test]
4686    fn undecomposable_criterion_exhausts_the_budget_instead_of_enumerating_the_domain() {
4687        let lo = 0.0;
4688        let hi = 32.0;
4689        let resolution = f64::EPSILON.sqrt();
4690        let flat_error = 5.0e-4;
4691        let (budget, depth_bound) = subdivision_budget(lo, hi, resolution);
4692        assert_eq!(depth_bound, 31, "log2(32 / sqrt(eps)) rounds up to 31");
4693        // Pins the shipped coefficient in `subdivision_budget`, whose doc
4694        // explains why it is 8 and why raising it further only converts a
4695        // budget refusal into a resolution refusal (#2614). This assertion is
4696        // deliberately a change-detector: if the constant moves, update BOTH,
4697        // and read that doc before deciding the move is a fix.
4698        assert_eq!(
4699            budget,
4700            8 * 31 * 31,
4701            "budget must track the 8 D^2 coefficient in subdivision_budget"
4702        );
4703        let error = maximize_score_1d(
4704            lo,
4705            hi,
4706            resolution,
4707            |_| -> Result<_, String> {
4708                Ok(ScoreJet {
4709                    value: 0.0,
4710                    derivative: 0.0,
4711                    curvature: 0.0,
4712                    third: 0.0,
4713                })
4714            },
4715            |left, right| -> Result<_, String> {
4716                let half_width = 0.5 * (right.x - left.x);
4717                Ok(DerivativeEnclosure {
4718                    score: ScoreValueEnclosure {
4719                        value: ClosedInterval::new(-half_width, half_width),
4720                        evaluation_error: flat_error,
4721                    },
4722                    derivative: ClosedInterval::new(-1.0, 1.0),
4723                    curvature: ClosedInterval::new(-1.0, 1.0),
4724                })
4725            },
4726        )
4727        .expect_err("a decomposition this large must refuse, not enumerate");
4728        let ScoreSearchError::SubdivisionBudget {
4729            subdivisions,
4730            budget: reported_budget,
4731            depth_bound: reported_depth,
4732            cell_lo,
4733            cell_hi,
4734            ..
4735        } = error
4736        else {
4737            panic!("expected a subdivision-budget refusal, got {error}");
4738        };
4739        assert_eq!(
4740            subdivisions,
4741            budget + 1,
4742            "the budget stops the split that exceeds it"
4743        );
4744        assert_eq!(reported_budget, budget);
4745        assert_eq!(reported_depth, depth_bound);
4746        assert!(
4747            cell_hi - cell_lo > 2.0 * flat_error,
4748            "the reported cell must be one the search could still have split and \
4749             had not yet certified ({cell_lo}, {cell_hi}); a narrower cell would \
4750             mean the depth floor, not the breadth budget, was binding"
4751        );
4752    }
4753
4754    /// The same budget must be invisible to a search that converges. A strictly
4755    /// concave criterion over the same wide domain isolates its stationary point
4756    /// in subdivisions proportional to the DEPTH, so the number of criterion
4757    /// evaluations stays far below a budget scaled by the depth SQUARED.
4758    #[test]
4759    fn a_converging_search_stays_far_under_the_subdivision_budget() {
4760        let lo = 0.0;
4761        let hi = 32.0;
4762        let resolution = f64::EPSILON.sqrt();
4763        let (budget, depth_bound) = subdivision_budget(lo, hi, resolution);
4764        let evaluations = std::cell::Cell::new(0usize);
4765        let result = maximize_score_1d(
4766            lo,
4767            hi,
4768            resolution,
4769            |x| -> Result<_, String> {
4770                evaluations.set(evaluations.get() + 1);
4771                let shifted = x - 7.0;
4772                Ok(ScoreJet {
4773                    value: -shifted * shifted,
4774                    derivative: -2.0 * shifted,
4775                    curvature: -2.0,
4776                    third: 0.0,
4777                })
4778            },
4779            |left, right| -> Result<_, String> {
4780                let x = ClosedInterval::new(left.x, right.x);
4781                let shifted = x.sub(ClosedInterval::point(7.0));
4782                Ok(DerivativeEnclosure {
4783                    score: ScoreValueEnclosure {
4784                        value: shifted.square().scale(-1.0),
4785                        evaluation_error: f64::EPSILON * 1024.0,
4786                    },
4787                    derivative: shifted.scale(-2.0),
4788                    curvature: ClosedInterval::point(-2.0),
4789                })
4790            },
4791        )
4792        .expect("a strictly concave criterion is decomposable");
4793        let ScoreOptimumLocation::Stationary(index) = result.location else {
4794            panic!("expected the interior maximum, got {:?}", result.location);
4795        };
4796        let bracket = result.stationary_points[index].bracket;
4797        assert!(
4798            bracket.lo <= 7.0 && bracket.hi >= 7.0,
4799            "certified bracket {bracket:?} must contain the planted maximum"
4800        );
4801        // Every subdivision costs one midpoint evaluation, so the evaluation
4802        // count bounds the subdivisions from above.
4803        assert!(
4804            evaluations.get() < budget / 8,
4805            "a converging search used {} evaluations against budget {budget} at depth \
4806             bound {depth_bound}; a budget within 8x of a converging search is a \
4807             tuning parameter, not a backstop",
4808            evaluations.get()
4809        );
4810    }
4811
4812    #[test]
4813    fn resolution_flatness_is_exactly_value_diameter_vs_pairwise_error() {
4814        let sample = SearchSample {
4815            sample: ScoreSample {
4816                x: 0.0,
4817                value: 7.0,
4818                derivative: 0.0,
4819                curvature: 0.0,
4820                third: 0.0,
4821            },
4822            point_enclosure: None,
4823        };
4824        let node = SearchNode {
4825            left: sample,
4826            right: SearchSample {
4827                sample: ScoreSample {
4828                    x: 1.0,
4829                    ..sample.sample
4830                },
4831                point_enclosure: None,
4832            },
4833        };
4834        let error = 0.125;
4835        for (upper, expected) in [(1024.25, true), (next_up(1024.25), false)] {
4836            let enclosure = DerivativeEnclosure {
4837                score: ScoreValueEnclosure {
4838                    // Translation by a large exactly represented constant must
4839                    // not change either side of the flatness comparison.
4840                    value: ClosedInterval::new(1024.0, upper),
4841                    evaluation_error: error,
4842                },
4843                derivative: ClosedInterval::new(-1.0, 1.0),
4844                curvature: ClosedInterval::new(-1.0, 1.0),
4845            };
4846            assert_eq!(
4847                resolution_flat_region(node, enclosure).is_some(),
4848                expected,
4849                "flatness must be equivalent to outward diameter <= outward 2*value error"
4850            );
4851        }
4852    }
4853
4854    #[test]
4855    fn resolution_flat_cells_remain_regions_instead_of_fake_points() {
4856        let resolution = 0.25;
4857        let result = maximize_score_1d(
4858            0.0,
4859            1.0,
4860            resolution,
4861            |_| -> Result<_, String> {
4862                Ok(ScoreJet {
4863                    value: 3.0,
4864                    derivative: 0.0,
4865                    curvature: 0.0,
4866                    third: 0.0,
4867                })
4868            },
4869            |_, _| -> Result<_, String> {
4870                Ok(DerivativeEnclosure {
4871                    score: ScoreValueEnclosure {
4872                        value: ClosedInterval::point(3.0),
4873                        evaluation_error: 0.0,
4874                    },
4875                    derivative: ClosedInterval::new(-1.0, 1.0),
4876                    curvature: ClosedInterval::new(-1.0, 1.0),
4877                })
4878            },
4879        )
4880        .expect("an exactly constant score is resolution-flat");
4881        assert_eq!(result.resolution_flat_regions.len(), 1);
4882        assert!(
4883            result.resolution_flat_regions[0].bracket.hi
4884                - result.resolution_flat_regions[0].bracket.lo
4885                > resolution,
4886            "value resolution may close a wide cell, so callers must not reinterpret it \
4887             as an abscissa-resolved stationary point"
4888        );
4889    }
4890
4891    #[test]
4892    fn directed_arithmetic_preserves_cancellation_and_subnormal_error() {
4893        assert_eq!(
4894            ClosedInterval::point(1.0).sub(ClosedInterval::point(1.0)),
4895            ClosedInterval::point(0.0),
4896            "an exact structural zero must not acquire artificial uncertainty"
4897        );
4898        let minimum_subnormal = f64::from_bits(1);
4899        let underflowing_product =
4900            ClosedInterval::point(minimum_subnormal).mul(ClosedInterval::point(0.5));
4901        assert!(
4902            underflowing_product.lo <= 0.5 * minimum_subnormal
4903                && underflowing_product.hi >= 0.5 * minimum_subnormal
4904                && underflowing_product.lo < 0.0
4905                && underflowing_product.hi > 0.0,
4906            "a nonzero exact product that rounds to zero needs additive subnormal width"
4907        );
4908        assert!(
4909            wilkinson_roundoff(0.0, 1) >= minimum_subnormal,
4910            "a zero-magnitude relative model must still charge additive underflow"
4911        );
4912    }
4913
4914    #[test]
4915    fn certified_elementary_intervals_cover_normal_and_subnormal_lanes() {
4916        for value in [
4917            f64::from_bits(1),
4918            f64::MIN_POSITIVE,
4919            0.5,
4920            1.0,
4921            2.0,
4922            f64::MAX,
4923        ] {
4924            let enclosure = certified_ln_positive(value).expect("certified positive log");
4925            assert!(enclosure.is_valid() && enclosure.lo.is_finite() && enclosure.hi.is_finite());
4926            assert!(
4927                enclosure.contains(value.ln()),
4928                "independent platform log sanity value {} escaped {:?}",
4929                value.ln(),
4930                enclosure
4931            );
4932        }
4933        for value in [-744.0_f64, -708.0, -1.0, 0.0, 1.0, 709.0] {
4934            let enclosure = certified_exp(value).expect("certified exponential");
4935            assert!(enclosure.is_valid() && enclosure.lo >= 0.0);
4936            assert!(
4937                enclosure.contains(value.exp()),
4938                "independent platform exp sanity value {} escaped {:?}",
4939                value.exp(),
4940                enclosure
4941            );
4942        }
4943        for value in [f64::from_bits(1), 1.0e-12, 0.25, 1.0] {
4944            let enclosure = certified_ln_1p(value).expect("certified log1p");
4945            assert!(
4946                enclosure.contains(value.ln_1p()),
4947                "independent platform log1p sanity value {} escaped {:?}",
4948                value.ln_1p(),
4949                enclosure
4950            );
4951        }
4952    }
4953
4954    #[test]
4955    fn exact_range_is_not_compared_to_a_separately_rounded_curvature() {
4956        let denormal = f64::from_bits(1);
4957        let result = maximize_score_1d(
4958            0.0,
4959            1.0,
4960            1.0e-8,
4961            |x| -> Result<_, String> {
4962                Ok(ScoreJet {
4963                    value: x,
4964                    derivative: 1.0,
4965                    // A real negative denormal rounds to signed zero in the
4966                    // point-jet arithmetic represented by this fixture.
4967                    curvature: -0.0,
4968                    third: 0.0,
4969                })
4970            },
4971            |left, right| -> Result<_, String> {
4972                Ok(DerivativeEnclosure {
4973                    score: ScoreValueEnclosure {
4974                        value: ClosedInterval::new(left.x, right.x),
4975                        evaluation_error: 0.0,
4976                    },
4977                    derivative: ClosedInterval::point(1.0),
4978                    curvature: ClosedInterval::point(-denormal),
4979                })
4980            },
4981        )
4982        .expect("an exact-real enclosure need not contain a separately rounded scalar jet");
4983        assert_eq!(result.location, ScoreOptimumLocation::UpperBoundary);
4984    }
4985
4986    fn affine_fixture() -> AffineRemlProfile<'static> {
4987        const G: &[f64] = &[2.0, 0.5, 0.0, 3.0];
4988        const S: &[f64] = &[1.0, 0.0, 2.0, 0.25];
4989        const Q: &[f64] = &[
4990            0.6, 0.1, 0.02, 0.3, // response 0
4991            0.2, 0.4, 0.01, 0.5, // response 1
4992        ];
4993        const Y2: &[f64] = &[8.0, 10.0];
4994        AffineRemlProfile::new(G, S, Q, Y2, 12.0, 3, 0.7).expect("valid fixture")
4995    }
4996
4997    #[test]
4998    fn affine_reml_jet_matches_test_only_differences() {
4999        let profile = affine_fixture();
5000        for x in [-2.0_f64, -0.4, 0.7, 2.0] {
5001            let h = 1.0e-5;
5002            let center = profile.evaluate(x).unwrap();
5003            let left = profile.evaluate(x - h).unwrap();
5004            let right = profile.evaluate(x + h).unwrap();
5005            let derivative = (right.value - left.value) / (2.0 * h);
5006            let curvature = (right.derivative - left.derivative) / (2.0 * h);
5007            assert!(
5008                (center.derivative - derivative).abs() <= 2.0e-8 * (1.0 + derivative.abs()),
5009                "first derivative mismatch at {x}: analytic {}, difference {derivative}",
5010                center.derivative
5011            );
5012            assert!(
5013                (center.curvature - curvature).abs() <= 2.0e-8 * (1.0 + curvature.abs()),
5014                "curvature mismatch at {x}: analytic {}, difference {curvature}",
5015                center.curvature
5016            );
5017        }
5018    }
5019
5020    #[test]
5021    fn affine_reml_enclosure_contains_value_jets() {
5022        let profile = affine_fixture();
5023        let enclosure = profile.enclose(-2.5, 1.75).expect("enclosure");
5024        let score = enclosure.score;
5025        let resolved_score = score.value.widen(score.evaluation_error);
5026        for x in [-2.5_f64, -1.7, -0.3, 0.0, 0.9, 1.75] {
5027            let jet = profile.evaluate(x).unwrap();
5028            let point = profile.enclose(x, x).expect("point enclosure");
5029            assert!(
5030                resolved_score.contains(jet.value),
5031                "score {} at {x} outside {:?} ± {}",
5032                jet.value,
5033                score.value,
5034                score.evaluation_error
5035            );
5036            assert!(
5037                enclosure
5038                    .derivative
5039                    .intersection(point.derivative)
5040                    .is_some(),
5041                "exact point gradient {:?} at {x} is disjoint from {:?}",
5042                point.derivative,
5043                enclosure.derivative
5044            );
5045            assert!(
5046                enclosure.curvature.intersection(point.curvature).is_some(),
5047                "exact point curvature {:?} at {x} is disjoint from {:?}",
5048                point.curvature,
5049                enclosure.curvature
5050            );
5051        }
5052    }
5053
5054    #[test]
5055    fn affine_reml_zero_smoothing_complement_retains_residual_correlation() {
5056        // With E = sum(q/g), the zero-smoothing residual is exactly zero and
5057        //
5058        //   R(lambda) = sum_i (q_i/g_i) * lambda/(1 + lambda).
5059        //
5060        // The determinant and profiled-residual derivatives then cancel
5061        // identically when residual_dof equals the mode count, so the exact
5062        // score derivative is zero. Forming R as
5063        // `E - sum q/(g + lambda*s)` loses the shared near-one factor once per
5064        // mode: at lambda=1e-10 its interval width is large enough to fabricate
5065        // a material derivative range even though every term has the same
5066        // analytic complement. The zero-smoothing form carries that
5067        // correlation explicitly.
5068        const MODES: usize = 64;
5069        let grams = [1.0; MODES];
5070        let penalties = [1.0; MODES];
5071        let projected = [1.0; MODES];
5072        let energies = [MODES as f64];
5073        let profile = AffineRemlProfile::new(
5074            &grams,
5075            &penalties,
5076            &projected,
5077            &energies,
5078            MODES as f64,
5079            MODES,
5080            0.0,
5081        )
5082        .expect("valid cancellation fixture");
5083        let rho = -23.025850929940457_f64; // nearest binary64 to ln(1e-10)
5084        let enclosure = profile
5085            .enclose(rho, rho)
5086            .expect("equivalent residual forms must retain their intersection");
5087
5088        assert!(
5089            enclosure.derivative.contains_zero(),
5090            "the analytically constant profile must contain zero derivative: {:?}",
5091            enclosure.derivative
5092        );
5093        assert!(
5094            enclosure.derivative.hi - enclosure.derivative.lo < 1.0e-6,
5095            "the residual complement must remove the independent near-one dependency: {:?}",
5096            enclosure.derivative
5097        );
5098    }
5099
5100    /// The score VALUE enclosure may never be looser than the bound its own
5101    /// DERIVATIVE enclosure certifies for the same cell.
5102    ///
5103    /// Both are enclosures of one function, so the mean value theorem ties
5104    /// them: across a cell of width `w` the score cannot move by more than
5105    /// `max|f'| * w`, hence
5106    ///
5107    /// ```text
5108    ///     width(F([a,b]))  <=  width(F({m}))  +  max|F'([a,b])| * w
5109    /// ```
5110    ///
5111    /// This is the invariant the natural interval extension broke, and it broke
5112    /// it in the regime the search lives in. The score is
5113    /// `-0.5 * (D*logdet_block + dof*deviance_block)` and near a REML optimum
5114    /// those two blocks cancel — each moves by `O(rank)` per unit of `rho`
5115    /// while their sum does not. Interval addition cannot see that the two
5116    /// movements are the same quantity with opposite signs, so the natural
5117    /// extension returned a range of width `rank * w` where the exact function
5118    /// has `|f'| * w`. Measured on a 33-mode cascade profile, that was a factor
5119    /// of `7.4e5` at `w = 2e-6`, and the factor DIVERGED as the cell shrank
5120    /// (`O(w)` against `O(w^2)`).
5121    ///
5122    /// `resolution_flat_region` reads the value range, so the consequence was
5123    /// not a loose number but a search that could retire no cell and refused
5124    /// designs it could certify. The centred form in [`AffineRemlProfile::enclose`]
5125    /// restores the invariant by construction; this gate is what stops the
5126    /// natural extension coming back.
5127    ///
5128    /// The fixture is built to CANCEL: `g_i = s_i = q_i = 1` with
5129    /// `E = modes = dof = rank`, whose analytic score is exactly constant in
5130    /// `rho`, so `|f'|` is zero to roundoff and any first-order slack in the
5131    /// value range shows up immediately.
5132    #[test]
5133    fn the_value_enclosure_never_exceeds_the_bound_its_own_derivative_certifies() {
5134        const MODES: usize = 33;
5135        let grams = [1.0; MODES];
5136        let penalties = [1.0; MODES];
5137        let projected = [1.0; MODES];
5138        let energies = [MODES as f64];
5139        let profile = AffineRemlProfile::new(
5140            &grams,
5141            &penalties,
5142            &projected,
5143            &energies,
5144            MODES as f64,
5145            MODES,
5146            0.0,
5147        )
5148        .expect("valid cancellation fixture");
5149
5150        let centre = -12.0_f64;
5151        let mut previous_width = f64::INFINITY;
5152        for exponent in [-1_i32, -2, -3, -4, -5, -6] {
5153            let half = 10.0_f64.powi(exponent);
5154            let (a, b) = (centre - half, centre + half);
5155            let width = b - a;
5156            let cell = profile.enclose(a, b).expect("cell enclosure");
5157            let point = profile.enclose(centre, centre).expect("point enclosure");
5158
5159            // Soundness first: the cell's ranges must CONTAIN the degenerate
5160            // cell's, which is what `certify_endpoint_derivative` relies on and
5161            // what an intersection of two enclosures could otherwise break.
5162            assert!(
5163                cell.score.value.lo <= point.score.value.lo
5164                    && point.score.value.hi <= cell.score.value.hi,
5165                "w={width:e}: the midpoint value range {:?} escaped the cell range {:?}",
5166                point.score.value,
5167                cell.score.value
5168            );
5169            assert!(
5170                cell.derivative.lo <= point.derivative.lo
5171                    && point.derivative.hi <= cell.derivative.hi,
5172                "w={width:e}: the midpoint derivative range {:?} escaped the cell range {:?}",
5173                point.derivative,
5174                cell.derivative
5175            );
5176
5177            let value_width = cell.score.value.hi - cell.score.value.lo;
5178            let point_width = point.score.value.hi - point.score.value.lo;
5179            let derivative_bound = cell.derivative.hi.abs().max(cell.derivative.lo.abs());
5180            let mean_value_bound = point_width + derivative_bound * width;
5181            assert!(
5182                value_width <= mean_value_bound * (1.0 + 1.0e-9),
5183                "w={width:e}: the value range is {value_width:e} wide but this cell's own \
5184                 derivative enclosure {:?} bounds the score's movement across it by \
5185                 {mean_value_bound:e} — the natural extension is back",
5186                cell.derivative
5187            );
5188
5189            println!(
5190                "[GATE] w={width:e} value_width={value_width:e} point_width={point_width:e} \
5191                 mvt={mean_value_bound:e} D={derivative_bound:e}"
5192            );
5193            // And it must actually CONVERGE. A first-order range falls by 10
5194            // per decade of cell width; this one falls by ~1000, because the
5195            // remainder is `max|F'| * w` and `max|F'|` is itself centred. The
5196            // gate asks for better than 50 per decade — enough to separate
5197            // `O(w)` from anything above it without pinning a rate — until the
5198            // range reaches the floor every enclosure has, the width of the
5199            // DEGENERATE-cell reading, below which there is nothing left to
5200            // win. Measured floor here: 8.98e-12 on a score of magnitude ~30.
5201            assert!(
5202                value_width <= previous_width / 50.0 || value_width <= 2.0 * point_width,
5203                "w={width:e}: the value range fell only {previous_width:e} -> \
5204                 {value_width:e}, and it is not at the point-enclosure floor \
5205                 {point_width:e} — that is first-order behaviour"
5206            );
5207            previous_width = value_width;
5208        }
5209    }
5210
5211    /// The centred form's degenerate and extreme cells.
5212    ///
5213    /// Centring introduces a second evaluation and an arithmetic that can
5214    /// produce an empty intersection or a non-finite remainder where the
5215    /// natural extension could not, so the cases where those are reachable are
5216    /// pinned rather than argued:
5217    ///
5218    /// * a POINT cell must return the natural extension untouched — the centred
5219    ///   form's remainder is exactly zero there and re-deriving it would only
5220    ///   add rounding;
5221    /// * a cell whose endpoints are ADJACENT binary64 values must still centre
5222    ///   at a point inside itself (`0.5*(lo+hi)` can round to either endpoint,
5223    ///   and a centre outside the cell would make the mean value theorem
5224    ///   inapplicable);
5225    /// * cells at the far ends of the representable `log lambda` domain, where
5226    ///   `lambda` is denormal at one end and near overflow at the other, must
5227    ///   stay sound: the centred range must contain the point range, and it may
5228    ///   never be wider than the natural extension it intersects.
5229    #[test]
5230    fn the_centred_enclosure_holds_on_degenerate_adjacent_and_extreme_cells() {
5231        let grams = [1.0, 4.0, 1.0e-9, 2.5e7];
5232        let penalties = [1.0, 1.0, 1.0, 1.0];
5233        let projected = [0.5, 0.25, 1.0e-3, 3.0];
5234        let energies = [8.0];
5235        let profile =
5236            AffineRemlProfile::new(&grams, &penalties, &projected, &energies, 6.0, 4, 0.25)
5237                .expect("valid fixture");
5238
5239        for &x in &[-600.0_f64, -37.5, -1.0, 0.0, 2.75, 600.0] {
5240            let Ok((direct, _)) = profile.enclose_direct(x, x) else {
5241                continue;
5242            };
5243            let centred = profile.enclose(x, x).expect("a point cell must enclose");
5244            assert_eq!(
5245                centred, direct,
5246                "a point cell must return the natural extension untouched at x={x}"
5247            );
5248
5249            // Adjacent binary64 endpoints: the tightest non-degenerate cell.
5250            let up = next_up(x);
5251            let Ok(cell) = profile.enclose(x, up) else {
5252                continue;
5253            };
5254            let point = profile.enclose(x, x).expect("point cell");
5255            assert!(
5256                cell.score.value.lo <= point.score.value.lo
5257                    && point.score.value.hi <= cell.score.value.hi,
5258                "adjacent-float cell at {x}: point value range {:?} escaped {:?}",
5259                point.score.value,
5260                cell.score.value
5261            );
5262            assert!(
5263                cell.derivative.lo <= point.derivative.lo
5264                    && point.derivative.hi <= cell.derivative.hi,
5265                "adjacent-float cell at {x}: point derivative range {:?} escaped {:?}",
5266                point.derivative,
5267                cell.derivative
5268            );
5269            assert!(
5270                cell.score.value.is_valid() && cell.derivative.is_valid(),
5271                "adjacent-float cell at {x} produced an invalid enclosure: {cell:?}"
5272            );
5273
5274            // Intersecting can only tighten: never wider than the natural form.
5275            let (wide, _) = profile.enclose_direct(x, up).expect("direct adjacent cell");
5276            assert!(
5277                cell.score.value.lo >= wide.score.value.lo
5278                    && cell.score.value.hi <= wide.score.value.hi,
5279                "the centred value range {:?} is not inside the natural extension {:?} at {x}",
5280                cell.score.value,
5281                wide.score.value
5282            );
5283            assert!(
5284                cell.derivative.lo >= wide.derivative.lo
5285                    && cell.derivative.hi <= wide.derivative.hi,
5286                "the centred derivative range {:?} is not inside the natural extension {:?} at {x}",
5287                cell.derivative,
5288                wide.derivative
5289            );
5290        }
5291    }
5292
5293    /// The 33 kept Schur modes and response energies of the cascade design in
5294    /// `gam_solve::residual_cascade`'s
5295    /// `auto_reml_certifies_a_design_the_data_cannot_identify` — 36 rows against
5296    /// 1725 columns — printed by that crate's `zz_probe_rank_deficient_` probe and
5297    /// carried here as literals so these gates need no design build and no
5298    /// dependency on gam-solve.
5299    ///
5300    /// A synthetic stand-in was tried first, twice, and neither reproduced the
5301    /// defect: it needs BOTH the multiscale spectrum and the near-interpolating
5302    /// response that makes the two score blocks cancel, and hand-built profiles
5303    /// kept landing on a monotone score the natural extension excludes by sign in
5304    /// a handful of cells. That is why these gates carry data rather than a
5305    /// formula.
5306    ///
5307    /// Returns `(gram_modes, penalty_modes, projected_rhs_squared, response_energy)`;
5308    /// the profile also takes `residual_dof = 33`, `determinant_rank = 33` and
5309    /// `logdet_constant = 9.226276711274537`, and its certified log-lambda domain
5310    /// is `[-21.860900258111, 18.75853229939662]`.
5311    fn cascade_profile_parts() -> (Vec<f64>, Vec<f64>, Vec<f64>, Vec<f64>) {
5312        let grams = vec![
5313            0.021513523027428847, 0.023421509558465926, 0.024477791743994424,
5314            0.03028760364561828, 0.03510108223379587, 0.040671848915996144,
5315            0.042394860646972565, 0.044208976267946384, 0.046980397477518414,
5316            0.051041787441650194, 0.053417305918114666, 0.05575657456312382,
5317            0.056982691606415704, 0.059623191536431024, 0.06072593823762461,
5318            0.061603808142128846, 0.0626306391548814, 0.06415989316153273, 0.06612727525342801,
5319            0.07201682707299777, 0.10499606046436369, 0.12037535776467499, 0.1486138626340859,
5320            0.1762399329554861, 0.19315924476245142, 0.26688703253550705, 0.2848266927054469,
5321            0.33232244706214037, 0.6015439556821448, 1.1406886269841172, 1.3973782387809837,
5322            1.8043547873076875, 2.0890420358314765,
5323        ];
5324        let penalties = vec![1.0_f64; 33];
5325        let projected = vec![
5326            0.0008447602450715568, 0.004744115853417025, 0.0013711877079256205,
5327            0.000556576229807026, 0.00032950514304538826, 0.00015869074743770514,
5328            0.004035749350652998, 0.002408288703125203, 0.0002161132863778849,
5329            0.0024599052556113317, 0.00028155268264135145, 9.068039769807838e-7,
5330            0.0004390033211936947, 0.004642257342083, 5.722227645019854e-6,
5331            0.003702111930202603, 0.003943553329808974, 0.0011808139994261783,
5332            1.490921408482301e-5, 0.001728436851442388, 0.00040290378245105683,
5333            0.0006710268119971442, 0.0032383572156905664, 0.00013742753101732549,
5334            6.681227329297447e-5, 0.054339495839186305, 0.018972176651153957,
5335            0.04535732957447296, 0.1129209190002305, 0.05428138627351111, 1.5501891913959478,
5336            0.14151749008562448, 0.11704548115908926,
5337        ];
5338        let energies = vec![2.7067510572921663_f64];
5339        (grams, penalties, projected, energies)
5340    }
5341
5342    /// The centred form's guard, and an honest account of what it is for.
5343    ///
5344    /// I wrote this guard for a hazard that turned out not to exist on the live
5345    /// path, so here is what is actually true, measured rather than argued.
5346    ///
5347    /// **The `inf * 0` story is closed already.** `ClosedInterval::mul` reduces
5348    /// four endpoint products with `f64::min`/`f64::max`, which IGNORE a NaN
5349    /// operand — so an `inf * 0` product would drop out of the reduction
5350    /// silently and leave a range strictly INSIDE the true one. But
5351    /// `product_down`/`product_up` treat a zero operand as exact and map the
5352    /// resulting NaN to `0.0`, so no NaN is ever produced that way, and
5353    /// `[-inf, -inf] * [-1, 0]` reduces to `[0, inf]` — correct. Enumerating
5354    /// every endpoint shape over `{-inf, -3, -1, 0, 1, 3, inf}` against a
5355    /// sampled product set finds no narrowing from any singly-infinite slope.
5356    ///
5357    /// **What is still open is a NaN arriving from elsewhere.** `product_is_exact`
5358    /// is false for a NaN against a non-unit, non-zero operand, so
5359    /// `[NaN, 1.0] * [-0.5, 0.5]` reduces to `[-0.5, 0.5]`: two of the four
5360    /// corners are dropped and a finite-looking, too-narrow range comes back with
5361    /// no signal at all. `enclose_direct` does not prove every accumulator finite,
5362    /// and `checked_enclosure` only validates the enclosure the search RECEIVES —
5363    /// by which point a NaN slope has already been used to narrow the value.
5364    ///
5365    /// So the guard excludes a non-finite slope and a non-finite remainder and
5366    /// keeps the natural extension, which is rigorous unconditionally. It is
5367    /// cheap, and it means a certified range does not rest on a case analysis of
5368    /// a rounding primitive three modules away that the next person to touch
5369    /// `mode_ranges` will not re-derive.
5370    #[test]
5371    fn the_centred_form_keeps_the_natural_extension_when_the_remainder_is_not_finite() {
5372        let direct = ClosedInterval::new(-10.0, 10.0);
5373        let point = ClosedInterval::new(-1.0, 1.0);
5374        let touching_zero = ClosedInterval::new(-0.5, 0.0);
5375        let straddling_zero = ClosedInterval::new(-0.5, 0.5);
5376
5377        // The hazard, on the record as a fact rather than as a worry: a NaN
5378        // endpoint reduces to a finite-looking range narrower than the truth.
5379        let narrowed = ClosedInterval::new(f64::NAN, 1.0).mul(straddling_zero);
5380        assert!(
5381            narrowed.lo.is_finite() && narrowed.hi.is_finite(),
5382            "premise: a NaN endpoint must reduce to a finite-LOOKING range ({narrowed:?}); if \
5383             `mul` stops dropping it this gate is about nothing"
5384        );
5385        // And the `inf * 0` path, which is NOT a hazard, asserted so a change to
5386        // `product_down`'s zero handling shows up here rather than silently.
5387        let infinite = ClosedInterval::new(f64::NEG_INFINITY, f64::NEG_INFINITY)
5388            .mul(ClosedInterval::new(-1.0, 0.0));
5389        assert!(
5390            infinite.lo <= 0.0 && infinite.hi.is_infinite(),
5391            "`inf * 0` must stay sound through `product_down`'s exact-zero mapping, got \
5392             {infinite:?}"
5393        );
5394
5395        for slope in [
5396            ClosedInterval::new(f64::NEG_INFINITY, 3.0),
5397            ClosedInterval::new(-3.0, f64::INFINITY),
5398            ClosedInterval::new(f64::NEG_INFINITY, f64::INFINITY),
5399            ClosedInterval::new(f64::NEG_INFINITY, f64::NEG_INFINITY),
5400            ClosedInterval::new(f64::NAN, 1.0),
5401            ClosedInterval::new(1.0, f64::NAN),
5402        ] {
5403            for offset in [touching_zero, straddling_zero, ClosedInterval::new(0.0, 0.5)] {
5404                assert_eq!(
5405                    centred_or(direct, point, slope, offset),
5406                    direct,
5407                    "a non-finite slope {slope:?} over offset {offset:?} must leave the natural \
5408                     extension in place"
5409                );
5410            }
5411        }
5412
5413        // And it still tightens when the remainder IS finite, so the guard has
5414        // not simply disabled the centred form.
5415        let tightened = centred_or(
5416            direct,
5417            point,
5418            ClosedInterval::new(-2.0, 2.0),
5419            straddling_zero,
5420        );
5421        assert!(
5422            tightened.lo > direct.lo && tightened.hi < direct.hi,
5423            "a finite remainder must still tighten: {tightened:?} against {direct:?}"
5424        );
5425    }
5426
5427    /// The centred ranges contain the function at EVERY interior point, not just
5428    /// at the centre they were expanded about.
5429    ///
5430    /// This is the gate on the riskiest thing centring introduces. Each channel
5431    /// is now a mean value form anchored on the one above it — the curvature on
5432    /// an interval THIRD derivative, the derivative on the curvature, the value
5433    /// on the derivative — so an error in the third-derivative kernel does not
5434    /// make a range wide, it makes it NARROW, and a narrow certified range is an
5435    /// unsound proof rather than a slow one.
5436    ///
5437    /// The check needs no finite differences and no reference implementation.
5438    /// `enclose(x, x)` is the natural extension on a degenerate cell, which
5439    /// encloses the exact value, derivative and curvature AT `x`; so for every
5440    /// `x` in `[a, b]` the cell's ranges must contain the point's. Sampling `x`
5441    /// away from the midpoint is what exercises the remainder terms: at the
5442    /// centre they vanish identically and prove nothing.
5443    ///
5444    /// Sampled across four decades of cell width so the remainder is the
5445    /// dominant term at the wide end and roundoff dominates at the narrow one.
5446    #[test]
5447    fn the_centred_ranges_contain_the_function_at_every_interior_point() {
5448        let (grams, penalties, projected, energies) = cascade_profile_parts();
5449        let profile = AffineRemlProfile::new(
5450            &grams,
5451            &penalties,
5452            &projected,
5453            &energies,
5454            33.0,
5455            33,
5456            9.226276711274537,
5457        )
5458        .expect("valid cascade profile");
5459
5460        // A containment check is only evidence if the range it checks was
5461        // actually NARROWED by the thing under test: if the intersection with
5462        // the natural extension were a no-op, every assertion below would hold
5463        // for any third-derivative kernel at all, including a wrong one.
5464        let mut curvature_tightened = false;
5465        // Spread over the design's own domain, including both saturated tails.
5466        for centre in [-20.0_f64, -12.5, -6.0, -1.679, 3.0, 11.0, 17.5] {
5467            for exponent in [0_i32, -1, -2, -3, -4] {
5468                let half = 10.0_f64.powi(exponent);
5469                let (a, b) = (centre - half, centre + half);
5470                let cell = profile.enclose(a, b).expect("cell enclosure");
5471                let (natural, _) = profile.enclose_direct(a, b).expect("natural extension");
5472                assert!(
5473                    cell.curvature.lo >= natural.curvature.lo
5474                        && cell.curvature.hi <= natural.curvature.hi,
5475                    "cell [{a}, {b}]: the centred curvature {:?} is not inside the natural \
5476                     extension {:?}",
5477                    cell.curvature,
5478                    natural.curvature
5479                );
5480                if cell.curvature.hi - cell.curvature.lo
5481                    < 0.5 * (natural.curvature.hi - natural.curvature.lo)
5482                {
5483                    curvature_tightened = true;
5484                }
5485                for step in 0..=8 {
5486                    let x = a + (b - a) * (step as f64 / 8.0);
5487                    let point = profile.enclose(x, x).expect("point enclosure");
5488                    assert!(
5489                        cell.score.value.lo <= point.score.value.lo
5490                            && point.score.value.hi <= cell.score.value.hi,
5491                        "cell [{a}, {b}] value range {:?} does not contain the exact value at \
5492                         x={x}, {:?}",
5493                        cell.score.value,
5494                        point.score.value
5495                    );
5496                    assert!(
5497                        cell.derivative.lo <= point.derivative.lo
5498                            && point.derivative.hi <= cell.derivative.hi,
5499                        "cell [{a}, {b}] derivative range {:?} does not contain the exact \
5500                         derivative at x={x}, {:?}",
5501                        cell.derivative,
5502                        point.derivative
5503                    );
5504                    assert!(
5505                        cell.curvature.lo <= point.curvature.lo
5506                            && point.curvature.hi <= cell.curvature.hi,
5507                        "cell [{a}, {b}] curvature range {:?} does not contain the exact \
5508                         curvature at x={x}, {:?} — the third-derivative kernel the curvature \
5509                         is centred on is wrong",
5510                        cell.curvature,
5511                        point.curvature
5512                    );
5513                }
5514            }
5515        }
5516        assert!(
5517            curvature_tightened,
5518            "the centred curvature never halved the natural extension's range anywhere in this \
5519             sweep, so the containment checks above would pass for a WRONG third-derivative \
5520             kernel too — this gate has gone vacuous"
5521        );
5522    }
5523
5524    /// The located optimum is the SAME under both enclosure forms, and it is
5525    /// accurate to the search's location contract and no better.
5526    ///
5527    /// Two claims, and the second is the one that catches misuse.
5528    ///
5529    /// Tightening an enclosure changes which cells the search visits, so it
5530    /// could in principle move the point it returns. On the profile
5531    /// `gam_sae::identifiability::ridge_reml_select_weight` builds for its
5532    /// one-eigendirection closed-form fixture it does not: both oracles return
5533    /// the same abscissa to the last bit, from the same stationary bracket. That
5534    /// is worth pinning, because a caller comparing the returned `lambda` to a
5535    /// closed form cannot tell "the enclosure moved the answer" from "the
5536    /// enclosure was always allowed to".
5537    ///
5538    /// And it was always allowed to. The search certifies a stationary point's
5539    /// LOCATION to the requested resolution in `rho`, and returns an evaluated
5540    /// SAMPLE from that bracket rather than the bracket's midpoint or a
5541    /// polished root. So `|rho_hat - rho*|` is bounded by the resolution and by
5542    /// nothing smaller — measured here at `4.17e-9` against a requested
5543    /// `1.49e-8`, from a bracket `1.13e-8` wide. A caller wanting more than that
5544    /// has to polish the root itself; the fixture's exact `lambda = 1.2` is
5545    /// reproduced to `2.5e-9`, which is inside the contract and outside a `1e-9`
5546    /// tolerance that no version of this search has ever guaranteed.
5547    #[test]
5548    fn the_located_optimum_is_enclosure_independent_and_accurate_to_the_contract() {
5549        // eigvals=[2.0], signal=[8.0], aux_norm_sq=10.0, n_obs=5, n_responses=3
5550        // => pairs = [(1.0, 4.0)] in u = lambda/gamma_max, repeated once per
5551        // response, with residual_dof = n_obs*n_responses = 15.
5552        let grams = [1.0_f64; 3];
5553        let penalties = [1.0_f64; 3];
5554        let projected = [4.0 / 3.0; 3];
5555        let energies = [10.0_f64];
5556        let profile =
5557            AffineRemlProfile::new(&grams, &penalties, &projected, &energies, 15.0, 3, 0.0)
5558                .expect("valid ridge profile");
5559        let lo = certified_ln_positive(f64::MIN_POSITIVE).expect("lo").lo;
5560        let hi = certified_ln_positive(f64::MAX / 2.0).expect("hi").hi;
5561        let resolution = f64::EPSILON.sqrt();
5562        // The closed-form stationary point: lambda_hat = 1.2, and the profile is
5563        // built in u = lambda/gamma_max with gamma_max = 2.
5564        let truth = 0.6_f64;
5565
5566        let natural = maximize_score_1d(
5567            lo,
5568            hi,
5569            resolution,
5570            |x| profile.evaluate(x),
5571            |a, b| profile.enclose_direct(a.x, b.x).map(|(e, _)| e),
5572        )
5573        .expect("the natural extension decomposes this domain");
5574        let centred = maximize_score_1d(lo, hi, resolution, |x| profile.evaluate(x), |a, b| {
5575            profile.enclose(a.x, b.x)
5576        })
5577        .expect("the centred form decomposes this domain");
5578
5579        assert_eq!(
5580            natural.optimum.x, centred.optimum.x,
5581            "the two enclosure forms located different optima ({} against {}); tightening may \
5582             change which cells are visited but must not move the certified root",
5583            natural.optimum.x, centred.optimum.x
5584        );
5585        for (label, search) in [("natural", &natural), ("centred", &centred)] {
5586            assert!(
5587                matches!(search.location, ScoreOptimumLocation::Stationary(_)),
5588                "{label}: this fixture has an interior stationary optimum, got {:?}",
5589                search.location
5590            );
5591            let offset = (search.optimum.x - truth.ln()).abs();
5592            assert!(
5593                offset <= resolution,
5594                "{label}: the located root is {offset:e} from the closed form in rho, outside \
5595                 the requested resolution {resolution:e} — that is a location-contract failure"
5596            );
5597            // And no better, which is the half a caller must not assume: the
5598            // returned point is a sample from the bracket, not a polished root.
5599            assert!(
5600                offset > 0.0,
5601                "{label}: an exactly-attained root would mean this gate has stopped measuring \
5602                 what it claims"
5603            );
5604        }
5605    }
5606
5607    /// COST. Centring doubles the per-cell work (one extra degenerate-cell
5608    /// evaluation), so the net is only a win if it removes more cells than that.
5609    /// This measures both oracles on the same searches and prints the ratio.
5610    ///
5611    /// Two shapes, because they pull in opposite directions: the cascade profile
5612    /// on its own 40.6-wide domain, where the natural extension cannot finish at
5613    /// all, and a well-conditioned profile on the FULL representable log-lambda
5614    /// domain (`ln(MIN_POSITIVE)` to `ln(MAX/2)`, 1417 wide) — which is what
5615    /// `gam_sae::identifiability::ridge_reml_select_weight` searches, and the
5616    /// case where a search that already succeeded cheaply could only get slower.
5617    #[test]
5618    fn zz_measure_centred_enclosure_search_cost() {
5619        let (grams, penalties, projected, energies) = cascade_profile_parts();
5620        let cascade = AffineRemlProfile::new(
5621            &grams,
5622            &penalties,
5623            &projected,
5624            &energies,
5625            33.0,
5626            33,
5627            9.226276711274537,
5628        )
5629        .expect("valid cascade profile");
5630
5631        let full_lo = certified_ln_positive(f64::MIN_POSITIVE).expect("domain lo").lo;
5632        let full_hi = certified_ln_positive(f64::MAX / 2.0).expect("domain hi").hi;
5633        let cases: [(&str, f64, f64); 3] = [
5634            // The domain the design declares, where the natural extension
5635            // cannot finish at all.
5636            ("cascade/40.6-wide", -21.860900258111, 18.75853229939662),
5637            // A narrow window around the optimum (-1.679), where the natural
5638            // extension already succeeds in a handful of cells. This is the
5639            // case centring could only make SLOWER, since there are no cells
5640            // left for it to remove.
5641            ("cascade/narrow-around-the-optimum", -3.0, 0.0),
5642            // The full representable log-lambda domain, 1417 wide, which is what
5643            // `gam_sae::identifiability::ridge_reml_select_weight` searches.
5644            ("cascade/full-representable-domain", full_lo, full_hi),
5645        ];
5646
5647        for (label, lo, hi) in cases {
5648            let profile = &cascade;
5649            let resolution = f64::EPSILON.sqrt();
5650            let started = std::time::Instant::now();
5651            let natural = maximize_score_1d(
5652                lo,
5653                hi,
5654                resolution,
5655                |x| profile.evaluate(x),
5656                |a, b| profile.enclose_direct(a.x, b.x).map(|(e, _)| e),
5657            );
5658            let natural_seconds = started.elapsed().as_secs_f64();
5659            let started = std::time::Instant::now();
5660            let centred = maximize_score_1d(
5661                lo,
5662                hi,
5663                resolution,
5664                |x| profile.evaluate(x),
5665                |a, b| profile.enclose(a.x, b.x),
5666            );
5667            let centred_seconds = started.elapsed().as_secs_f64();
5668            println!(
5669                "#COST {label}: natural {:.4}s ({}) centred {:.4}s ({}) speedup {:.2}x",
5670                natural_seconds,
5671                natural.as_ref().map_or("REFUSED", |_| "ok"),
5672                centred_seconds,
5673                centred.as_ref().map_or("REFUSED", |_| "ok"),
5674                natural_seconds / centred_seconds.max(f64::MIN_POSITIVE),
5675            );
5676            // A refusal is a legitimate outcome for some domains (the full
5677            // representable one reaches lambda values where the profiled
5678            // residual is not evaluable at all); what must never happen is the
5679            // centred oracle refusing where the natural one succeeds.
5680            assert!(
5681                centred.is_ok() || natural.is_err(),
5682                "{label}: the centred oracle refused ({centred:?}) where the natural extension \
5683                 succeeded — an intersection can only tighten, so this is impossible unless the \
5684                 centred form is unsound"
5685            );
5686            // The per-cell cost is at most 2x, so a search that certifies under
5687            // BOTH oracles must not lose more than that. A wider loss means the
5688            // centred form is provoking work rather than removing it.
5689            if natural.is_ok() {
5690                assert!(
5691                    centred_seconds <= natural_seconds * 2.5 + 1.0e-3,
5692                    "{label}: centring cost {centred_seconds:.4}s against the natural \
5693                     extension's {natural_seconds:.4}s — more than the doubled per-cell work \
5694                     can explain"
5695                );
5696            }
5697        }
5698    }
5699
5700    /// The capability the centred form buys, pinned by running the SAME search
5701    /// twice on the same profile with the two enclosure forms.
5702    ///
5703    /// Every other gate here measures a width. This one measures the only thing
5704    /// a width is for: whether the certified search can decompose the domain at
5705    /// all. The natural extension is not removed by the fix — it is still what
5706    /// the centred form is built from and intersected with — so it stays
5707    /// callable, and that makes the before/after a controlled comparison inside
5708    /// one test rather than a claim about a previous commit.
5709    ///
5710    /// The fixture is the cascade's shape rather than its data: modes spread
5711    /// over nine decades (what a multilevel frame's Schur complement looks
5712    /// like), response energy split across them, and `dof = rank = modes`, so
5713    /// the log-determinant and deviance blocks each move by `O(rank)` per unit
5714    /// of `rho` while the score does not — the cancellation that the natural
5715    /// extension cannot see.
5716    #[test]
5717    fn the_natural_extension_cannot_decompose_a_domain_the_centred_form_certifies() {
5718        let (grams, penalties, projected, energies) = cascade_profile_parts();
5719        let profile = AffineRemlProfile::new(
5720            &grams,
5721            &penalties,
5722            &projected,
5723            &energies,
5724            33.0,
5725            33,
5726            9.226276711274537,
5727        )
5728        .expect("valid cascade profile");
5729
5730        // The design's own certified log-lambda domain, 40.6 wide.
5731        let (lo, hi) = (-21.860900258111_f64, 18.75853229939662);
5732        let resolution = f64::EPSILON.sqrt();
5733
5734        let natural = maximize_score_1d(
5735            lo,
5736            hi,
5737            resolution,
5738            |x| profile.evaluate(x),
5739            |a, b| profile.enclose_direct(a.x, b.x).map(|(enclosure, _)| enclosure),
5740        );
5741        let centred = maximize_score_1d(
5742            lo,
5743            hi,
5744            resolution,
5745            |x| profile.evaluate(x),
5746            |a, b| profile.enclose(a.x, b.x),
5747        );
5748
5749        let centred = centred.unwrap_or_else(|error| {
5750            panic!(
5751                "the centred enclosure must decompose this 33-mode cascade domain: {error}"
5752            )
5753        });
5754        assert!(
5755            matches!(
5756                natural,
5757                Err(ScoreSearchError::SubdivisionBudget { .. } | ScoreSearchError::Unresolved { .. })
5758            ),
5759            "PREMISE LOST: the natural extension now decomposes this domain \
5760             ({natural:?}), so this fixture no longer exercises the defect and the \
5761             comparison below proves nothing — widen the mode spread or the domain \
5762             until it refuses again",
5763        );
5764
5765        // And the answer it reaches is a real one, not a shrug: a decided
5766        // location whose global value ordering closed.
5767        assert!(
5768            !matches!(centred.location, ScoreOptimumLocation::ResolutionFlat(_)),
5769            "the centred search must decide a location, got {:?}",
5770            centred.location
5771        );
5772        assert!(
5773            centred.value_certificate.maximum_excess
5774                <= centred.value_certificate.comparison_resolution,
5775            "the centred search's value ordering must close: excess {} against {}",
5776            centred.value_certificate.maximum_excess,
5777            centred.value_certificate.comparison_resolution
5778        );
5779        assert!(
5780            centred.optimum.x >= lo && centred.optimum.x <= hi && centred.optimum.x.is_finite(),
5781            "the selected log lambda must lie in the domain, got {}",
5782            centred.optimum.x
5783        );
5784    }
5785
5786    #[test]
5787    fn affine_reml_zero_smoothing_schur_residual_keeps_division_low_parts() {
5788        // Three exact-real quotients 1/3 sum to one, although no individual
5789        // quotient is representable in binary64. A directed interval around
5790        // each independently rounded quotient leaves an O(u) uncertainty in
5791        // `1 - 3*(1/3)`, larger than this profile's residual at lambda=1e-10.
5792        // The one-time TwoSum/FMA construction retains the division low parts,
5793        // so the exact zero Schur residual remains resolved near O(u²).
5794        let grams = [3.0; 3];
5795        let penalties = [1.0; 3];
5796        let projected = [1.0; 3];
5797        let energies = [1.0];
5798        let profile =
5799            AffineRemlProfile::new(&grams, &penalties, &projected, &energies, 3.0, 3, 0.0)
5800                .expect("valid nonrepresentable-quotient fixture");
5801
5802        let zero_residual = profile.zero_lambda_residual[0];
5803        assert!(
5804            zero_residual.contains_zero(),
5805            "the exact identity 1 - 3*(1/3) = 0 must be retained: {zero_residual:?}"
5806        );
5807        assert!(
5808            zero_residual.hi - zero_residual.lo < 1.0e-28,
5809            "division corrections must live below ordinary binary64 cancellation scale: \
5810             {zero_residual:?}"
5811        );
5812
5813        let rho = -23.025850929940457_f64;
5814        let enclosure = profile
5815            .enclose(rho, rho)
5816            .expect("the small positive smoothing residual must remain resolved");
5817        assert!(
5818            enclosure.derivative.contains_zero(),
5819            "determinant and residual derivatives cancel analytically: {:?}",
5820            enclosure.derivative
5821        );
5822        assert!(
5823            enclosure.derivative.hi - enclosure.derivative.lo < 1.0e-6,
5824            "the exact Schur residual must control the profiled derivative: {:?}",
5825            enclosure.derivative
5826        );
5827    }
5828
5829    #[test]
5830    fn affine_reml_saturated_tail_preserves_complement_signs() {
5831        let profile = AffineRemlProfile::new(&[1.0], &[1.0], &[0.0], &[1.0], 4.0, 1, 0.0)
5832            .expect("valid saturated-tail fixture");
5833        let log_lambda = 700.0;
5834        let jet = profile.evaluate(log_lambda).expect("point jet");
5835        let enclosure = profile
5836            .enclose(log_lambda, log_lambda)
5837            .expect("point enclosure");
5838
5839        assert!(
5840            jet.derivative > 0.0,
5841            "the point derivative must preserve +0.5/(1+exp(rho)), got {}",
5842            jet.derivative
5843        );
5844        assert!(
5845            jet.curvature < 0.0,
5846            "the point curvature must preserve its negative u*c sign, got {}",
5847            jet.curvature
5848        );
5849        assert!(
5850            enclosure.curvature.hi <= 0.0,
5851            "the exact saturated curvature remains nonpositive: {:?}",
5852            enclosure.curvature
5853        );
5854        assert!(
5855            enclosure.derivative.lo >= 0.0,
5856            "the exact saturated derivative remains nonnegative: {:?}",
5857            enclosure.derivative
5858        );
5859        let score = enclosure.score;
5860        assert!(score.evaluation_error.is_finite());
5861        assert!(
5862            score
5863                .value
5864                .widen(score.evaluation_error)
5865                .contains(jet.value),
5866            "the stable score evaluator must lie inside its exact value range plus forward error"
5867        );
5868    }
5869
5870    #[test]
5871    fn affine_reml_saturated_tail_uses_complement_sign_before_value_flatness() {
5872        let profile = AffineRemlProfile::new(&[1.0], &[1.0], &[0.0], &[1.0], 4.0, 1, 0.0)
5873            .expect("valid saturated-tail fixture");
5874        let result = profile
5875            .maximize(600.0, 700.0, f64::EPSILON.sqrt())
5876            .expect("the cancellation-free derivative proves the tail monotone");
5877        assert_eq!(result.location, ScoreOptimumLocation::UpperBoundary);
5878        assert_eq!(result.optimum.x, 700.0);
5879        assert!(
5880            result.resolution_flat_regions.is_empty(),
5881            "a strictly positive derivative should resolve before value-flat fallback"
5882        );
5883    }
5884
5885    #[test]
5886    fn affine_reml_extreme_domain_one_direction_encloses_and_maximizes_repeatably() {
5887        // The normalized one-direction ridge profile behind the gam-sae
5888        // regressions has
5889        //
5890        //   R(lambda) = 10 - 4/(1 + lambda),
5891        //
5892        // so its exact residual stays in [6, 10] over the complete finite
5893        // lambda domain. Repeating the direction three times reproduces the
5894        // response multiplicity of that caller and plants the stationary point
5895        // at lambda/gamma_max = 0.6.
5896        let gram_modes = [1.0, 1.0, 1.0];
5897        let penalty_modes = [1.0, 1.0, 1.0];
5898        let projected_rhs_squared = [4.0 / 3.0, 4.0 / 3.0, 4.0 / 3.0];
5899        let response_energy = [10.0];
5900        let profile = AffineRemlProfile::new(
5901            &gram_modes,
5902            &penalty_modes,
5903            &projected_rhs_squared,
5904            &response_energy,
5905            15.0,
5906            3,
5907            0.0,
5908        )
5909        .expect("valid normalized one-direction ridge profile");
5910        let rho_lo = certified_ln_positive(f64::MIN_POSITIVE)
5911            .expect("finite-domain lower log bound")
5912            .lo;
5913        let rho_hi = certified_ln_positive(f64::MAX / 2.0)
5914            .expect("finite-domain upper log bound")
5915            .hi;
5916
5917        let whole_domain = profile
5918            .enclose(rho_lo, rho_hi)
5919            .expect("scale-safe relative exp error keeps the full-domain residual finite");
5920        assert!(
5921            whole_domain.score.value.is_valid()
5922                && whole_domain.score.value.lo.is_finite()
5923                && whole_domain.score.value.hi.is_finite()
5924        );
5925        assert!(whole_domain.score.evaluation_error.is_finite());
5926        assert!(whole_domain.derivative.contains_zero());
5927
5928        let resolution = f64::EPSILON.sqrt();
5929        let first = profile
5930            .maximize_value_ordered(rho_lo, rho_hi, resolution)
5931            .expect("finite subdivision must certify the planted stationary optimum");
5932        let repeated = profile
5933            .maximize_value_ordered(rho_lo, rho_hi, resolution)
5934            .expect("the same exact search must be repeatable");
5935        assert_eq!(first, repeated);
5936        let ScoreOptimumLocation::Stationary(index) = first.location else {
5937            panic!(
5938                "the planted one-direction optimum must be stationary, got {:?}",
5939                first.location
5940            );
5941        };
5942        let stationary = first
5943            .stationary_points
5944            .get(index)
5945            .expect("stationary result index");
5946        let expected = certified_ln_positive(0.6).expect("analytic stationary log");
5947        assert!(
5948            stationary.bracket.lo <= expected.lo && stationary.bracket.hi >= expected.hi,
5949            "certified bracket {:?} must contain analytic log(0.6) {:?}",
5950            stationary.bracket,
5951            expected
5952        );
5953        assert!(
5954            first.value_certificate.maximum_excess <= first.value_certificate.comparison_resolution,
5955            "an isolated stationary root is not yet a globally ordered score candidate: \
5956             maximum excess {}, comparison resolution {}, bracket {:?}",
5957            first.value_certificate.maximum_excess,
5958            first.value_certificate.comparison_resolution,
5959            stationary.bracket,
5960        );
5961    }
5962
5963    #[test]
5964    fn affine_reml_gram_zero_subnormal_zero_projection_is_structural() {
5965        let minimum_subnormal = f64::from_bits(1);
5966        let log_lambda = -740.0;
5967        let lambda = exp_interval(log_lambda, log_lambda)
5968            .expect("the fixture needs a certified subnormal lambda");
5969        assert!(lambda.lo > 0.0 && lambda.hi < f64::MIN_POSITIVE);
5970        let raw_h = lambda.mul(ClosedInterval::point(minimum_subnormal));
5971        assert!(
5972            raw_h.lo < 0.0 && raw_h.hi > 0.0,
5973            "the raw outward product must cross rounded zero: {raw_h:?}"
5974        );
5975        let h = raw_h.nonnegative();
5976        assert_eq!(
5977            h.lo, 0.0,
5978            "known nonnegative product must clamp its outward lower bound to zero"
5979        );
5980
5981        let ranges = mode_ranges(0.0, minimum_subnormal, 0.0, lambda)
5982            .expect("the zero projection cancels before any residual division");
5983        assert_eq!(ranges.c, ClosedInterval::point(0.0));
5984        assert_eq!(ranges.w, ClosedInterval::point(0.0));
5985        assert_eq!(ranges.v, ClosedInterval::point(0.0));
5986        assert_eq!(ranges.p, ClosedInterval::point(0.0));
5987        assert_eq!(ranges.q, ClosedInterval::point(0.0));
5988
5989        let gram_modes = [0.0];
5990        let penalty_modes = [minimum_subnormal];
5991        let projected_rhs_squared = [0.0];
5992        let response_energy = [1.0];
5993        let profile = AffineRemlProfile::new(
5994            &gram_modes,
5995            &penalty_modes,
5996            &projected_rhs_squared,
5997            &response_energy,
5998            1.0,
5999            1,
6000            0.0,
6001        )
6002        .expect("valid gram-zero structural fixture");
6003        let jet = profile
6004            .evaluate(log_lambda)
6005            .expect("normalized determinant and zero residual projection stay finite");
6006        let enclosure = profile
6007            .enclose(log_lambda, log_lambda)
6008            .expect("the proof path must not divide by a zero-containing h interval");
6009        assert_eq!(jet.derivative, 0.0);
6010        assert_eq!(jet.curvature, 0.0);
6011        assert!(is_exact_zero(enclosure.derivative));
6012        assert!(is_exact_zero(enclosure.curvature));
6013        assert!(
6014            enclosure
6015                .score
6016                .value
6017                .widen(enclosure.score.evaluation_error)
6018                .contains(jet.value)
6019        );
6020    }
6021
6022    #[test]
6023    fn affine_reml_gram_zero_subnormal_nonzero_projection_stays_finite() {
6024        let minimum_subnormal = f64::from_bits(1);
6025        let log_lambda = -740.0;
6026        let lambda = exp_interval(log_lambda, log_lambda)
6027            .expect("the fixture needs a certified subnormal lambda");
6028        let penalty = 0.01;
6029        let h = lambda.mul(ClosedInterval::point(penalty)).nonnegative();
6030        assert_eq!(
6031            h.lo, 0.0,
6032            "the fixture must enter the structural quotient path"
6033        );
6034
6035        let ranges = mode_ranges(0.0, penalty, minimum_subnormal, lambda)
6036            .expect("the scaled quotient has a finite representable range");
6037        assert_eq!(ranges.c, ClosedInterval::point(0.0));
6038        assert_eq!(ranges.w, ClosedInterval::point(0.0));
6039        assert!(ranges.v.lo > 0.0 && ranges.v.hi.is_finite());
6040        assert_eq!(ranges.p, ranges.v);
6041        assert_eq!(ranges.q, ranges.v.neg());
6042
6043        let gram_modes = [0.0];
6044        let penalty_modes = [penalty];
6045        let projected_rhs_squared = [minimum_subnormal];
6046        let response_energy = [10.0];
6047        let profile = AffineRemlProfile::new(
6048            &gram_modes,
6049            &penalty_modes,
6050            &projected_rhs_squared,
6051            &response_energy,
6052            1.0,
6053            1,
6054            0.0,
6055        )
6056        .expect("valid gram-zero finite-ratio fixture");
6057        let jet = profile
6058            .evaluate(log_lambda)
6059            .expect("the point ratio must avoid the underflowing product");
6060        let enclosure = profile
6061            .enclose(log_lambda, log_lambda)
6062            .expect("the interval ratio must remain finite without a reciprocal overflow");
6063        assert!(
6064            enclosure
6065                .score
6066                .value
6067                .widen(enclosure.score.evaluation_error)
6068                .contains(jet.value)
6069        );
6070    }
6071
6072    #[test]
6073    fn affine_reml_gram_zero_unrepresentable_projection_is_typed() {
6074        let minimum_subnormal = f64::from_bits(1);
6075        let log_lambda = -740.0;
6076        let gram_modes = [0.0];
6077        let penalty_modes = [minimum_subnormal];
6078        let projected_rhs_squared = [1.0];
6079        let response_energy = [10.0];
6080        let profile = AffineRemlProfile::new(
6081            &gram_modes,
6082            &penalty_modes,
6083            &projected_rhs_squared,
6084            &response_energy,
6085            1.0,
6086            1,
6087            0.0,
6088        )
6089        .expect("valid gram-zero refusal fixture");
6090        assert!(matches!(
6091            profile.evaluate(log_lambda),
6092            Err(AffineRemlError::ElementaryEnclosureUnavailable {
6093                function: "gram-zero residual quotient",
6094                ..
6095            })
6096        ));
6097        assert!(matches!(
6098            profile.enclose(log_lambda, log_lambda),
6099            Err(AffineRemlError::ElementaryEnclosureUnavailable {
6100                function: "gram-zero residual quotient",
6101                ..
6102            })
6103        ));
6104    }
6105
6106    #[test]
6107    fn affine_reml_rejects_nonpositive_profile_residual() {
6108        let profile = AffineRemlProfile::new(&[1.0], &[1.0], &[2.0], &[1.0], 4.0, 1, 0.0)
6109            .expect("statically valid");
6110        assert!(matches!(
6111            profile.evaluate(-2.0),
6112            Err(AffineRemlError::NonPositiveResidual { .. })
6113        ));
6114    }
6115}