Skip to main content

the_q/
ext.rs

1//! The extended [`Q`]: a `Rat`, or an explicit non-representable state.
2//!
3//! A layer over the kernel, not a rewrite: `Rat` keeps its invariant and every
4//! kernel obligation keeps its statement. Special values carry no `num`/`den`,
5//! so no operation can read one as a number and an omitted case is a compile
6//! error. There is no `is_finite()`: `PosSat` denotes finite reals above the
7//! budget. Issue #26 holds the design and the propagation tables, which
8//! `tests/extended_q.rs` pins by exhaustive enumeration.
9
10use verus_builtin_macros::verus;
11
12#[allow(unused_imports)]
13use verus_builtin::*;
14#[allow(unused_imports)]
15use vstd::prelude::*;
16
17use crate::types::{Dir, Rat};
18
19verus! {
20
21/// The sign of a value that has one; `signum(Nan)` is `None`.
22#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
23pub enum Sign {
24    /// Strictly less than zero.
25    Negative,
26    /// Exactly zero.
27    Zero,
28    /// Strictly greater than zero.
29    Positive,
30}
31
32/// A bounded rational, or an explicit statement that the value is not one.
33///
34/// | variant | denotes |
35/// |---|---|
36/// | `Number(x)` | `{x}` |
37/// | `PosSat` / `NegSat` | `(MAX_MAG, +∞)` / `(-∞, -MAX_MAG)`, reals only |
38/// | `PosInf` / `NegInf` | `{+∞}` / `{-∞}` |
39/// | `Nan` | no information |
40///
41/// Saturation denotes reals, so `Number(0) · PosSat == Number(0)`. `PartialEq`
42/// is derived and `Nan == Nan`, which keeps `Eq`, `Hash` and the total `Ord`
43/// lawful. `Ord` is hand-written: variant order is not value order.
44#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
45pub enum Q {
46    /// A representable rational.
47    Number(Rat),
48    /// The true magnitude exceeds `MAX_MAG` and the value is positive.
49    PosSat,
50    /// The true magnitude exceeds `MAX_MAG` and the value is negative.
51    NegSat,
52    /// Exactly `+∞`.
53    PosInf,
54    /// Exactly `-∞`.
55    NegInf,
56    /// No information about the value.
57    Nan,
58}
59
60impl Q {
61    /// The invariant: a `Number` payload is `wf`; specials carry nothing.
62    pub open spec fn wf(self) -> bool {
63        match self {
64            Q::Number(x) => x.wf(),
65            _ => true,
66        }
67    }
68
69    // -----------------------------------------------------------------------
70    // Classification
71    //
72    // These four `ensures` clauses restate their own bodies. A discriminant
73    // test has no content beyond the variant that it accepts, thus the
74    // specification and the implementation are the same statement. The clauses
75    // prove nothing. They exist so that a caller in verified code can reason
76    // about the result.
77    //
78    // The predicates below (`is_zero`, `signum` and others) are different. They
79    // have content, and they delegate to the verified kernel.
80    // -----------------------------------------------------------------------
81
82    /// Whether this is a representable rational.
83    pub open spec fn spec_is_number(self) -> bool {
84        match self {
85            Q::Number(_) => true,
86            _ => false,
87        }
88    }
89
90    /// Whether this is a saturation state.
91    pub open spec fn spec_is_saturated(self) -> bool {
92        match self {
93            Q::PosSat => true,
94            Q::NegSat => true,
95            _ => false,
96        }
97    }
98
99    /// Whether this is an infinity.
100    pub open spec fn spec_is_infinite(self) -> bool {
101        match self {
102            Q::PosInf => true,
103            Q::NegInf => true,
104            _ => false,
105        }
106    }
107
108    /// Whether this is `Nan`.
109    pub open spec fn spec_is_nan(self) -> bool {
110        match self {
111            Q::Nan => true,
112            _ => false,
113        }
114    }
115
116    /// The sign of this value in specifications. `Nan` is the only state with
117    /// no sound sign.
118    pub open spec fn spec_signum(self) -> Option<Sign> {
119        match self {
120            Q::Number(x) => {
121                if x.n() < 0 {
122                    Some(Sign::Negative)
123                } else if x.n() > 0 {
124                    Some(Sign::Positive)
125                } else {
126                    Some(Sign::Zero)
127                }
128            },
129            Q::PosSat => Some(Sign::Positive),
130            Q::NegSat => Some(Sign::Negative),
131            Q::PosInf => Some(Sign::Positive),
132            Q::NegInf => Some(Sign::Negative),
133            Q::Nan => None,
134        }
135    }
136
137    /// Whether this is a representable rational.
138    ///
139    /// The four classification predicates are mutually exclusive and jointly
140    /// exhaustive. See `theorem_classification_partitions`.
141    ///
142    /// ```
143    /// use the_q::{Q, Rat};
144    ///
145    /// assert!(Q::number(Rat::one()).is_number());
146    /// assert!(!Q::PosSat.is_number());
147    /// assert!(!Q::Nan.is_number());
148    /// ```
149    pub fn is_number(self) -> (r: bool)
150        ensures
151            r == self.spec_is_number(),
152    {
153        matches!(self, Q::Number(_))
154    }
155
156    /// Whether the true magnitude is known to exceed `MAX_MAG`.
157    ///
158    /// This predicate is not the negation of `is_number`. It separates an
159    /// overflow from a division by zero. That distinction is the purpose of the
160    /// saturation states.
161    ///
162    /// ```
163    /// use the_q::Q;
164    ///
165    /// assert!(Q::PosSat.is_saturated());
166    /// assert!(Q::NegSat.is_saturated());
167    /// assert!(!Q::PosInf.is_saturated());
168    /// ```
169    pub fn is_saturated(self) -> (r: bool)
170        ensures
171            r == self.spec_is_saturated(),
172    {
173        matches!(self, Q::PosSat | Q::NegSat)
174    }
175
176    /// Whether this is exactly `±∞`.
177    ///
178    /// ```
179    /// use the_q::Q;
180    ///
181    /// assert!(Q::PosInf.is_infinite());
182    /// assert!(Q::NegInf.is_infinite());
183    /// assert!(!Q::PosSat.is_infinite());
184    /// ```
185    pub fn is_infinite(self) -> (r: bool)
186        ensures
187            r == self.spec_is_infinite(),
188    {
189        matches!(self, Q::PosInf | Q::NegInf)
190    }
191
192    /// Whether this carries no information about the value.
193    ///
194    /// ```
195    /// use the_q::Q;
196    ///
197    /// assert!(Q::Nan.is_nan());
198    /// assert!(!Q::zero().is_nan());
199    /// ```
200    pub fn is_nan(self) -> (r: bool)
201        ensures
202            r == self.spec_is_nan(),
203    {
204        matches!(self, Q::Nan)
205    }
206
207    // -----------------------------------------------------------------------
208    // Constructors
209    //
210    // Each constructor establishes `wf`. A special value establishes `wf`
211    // trivially. There is no malformed special value, thus these constructors
212    // cannot fail and need no `Option`.
213    // -----------------------------------------------------------------------
214
215    /// Lift a kernel rational into the extended type.
216    ///
217    /// ```
218    /// use the_q::{Q, Rat};
219    ///
220    /// let half = Rat::new(1, 2).unwrap();
221    /// assert_eq!(Q::number(half), Q::Number(half));
222    /// ```
223    pub fn number(x: Rat) -> (r: Q)
224        requires
225            x.wf(),
226        ensures
227            r.wf(),
228            r == Q::Number(x),
229            r.spec_is_number(),
230    {
231        Q::Number(x)
232    }
233
234    /// `0`.
235    ///
236    /// ```
237    /// use the_q::Q;
238    ///
239    /// assert!(Q::zero().is_zero());
240    /// assert!(Q::zero().is_number());
241    /// ```
242    pub fn zero() -> (r: Q)
243        ensures
244            r.wf(),
245            r.spec_is_number(),
246            r.spec_is_value(0, 1),
247            r.spec_is_zero(),
248            r == Q::Number(Rat::from_raw_spec(0, 1)),
249    {
250        Q::Number(Rat::zero())
251    }
252
253    /// `1`.
254    ///
255    /// ```
256    /// use the_q::Q;
257    ///
258    /// assert!(Q::one().is_one());
259    /// ```
260    pub fn one() -> (r: Q)
261        ensures
262            r.wf(),
263            r.spec_is_number(),
264            r.spec_is_value(1, 1),
265            r.spec_is_one(),
266            r == Q::Number(Rat::from_raw_spec(1, 1)),
267    {
268        Q::Number(Rat::one())
269    }
270
271    /// `-1`.
272    ///
273    /// ```
274    /// use the_q::{Q, Rat};
275    ///
276    /// assert_eq!(Q::neg_one(), Q::Number(Rat::new(-1, 1).unwrap()));
277    /// ```
278    pub fn neg_one() -> (r: Q)
279        ensures
280            r.wf(),
281            r.spec_is_number(),
282            r.spec_is_value(-1, 1),
283    {
284        Q::Number(Rat::neg_one())
285    }
286
287    /// The rational `num / den`, total: `x/0` is `±Inf`, `0/0` is `Nan`.
288    /// Saturation is decided on the *value* (`magnitude_fits`), not on the
289    /// components: `1 / i64::MIN` is small and rounds, it does not saturate.
290    /// Where [`Rat::new`] succeeds this returns the same value.
291    ///
292    /// ```
293    /// use the_q::{Q, Rat};
294    ///
295    /// assert_eq!(Q::new(1, 2), Q::Number(Rat::new(1, 2).unwrap()));
296    /// assert_eq!(Q::new(1, 0), Q::PosInf);
297    /// assert_eq!(Q::new(0, 0), Q::Nan);
298    /// ```
299    pub fn new(num: i64, den: i64) -> (r: Q)
300        ensures
301            r.wf(),
302            // Division by zero, per #26 §4, applied uniformly.
303            (den == 0 && num == 0) ==> r == Q::Nan,
304            (den == 0 && num > 0) ==> r == Q::PosInf,
305            (den == 0 && num < 0) ==> r == Q::NegInf,
306            // Away from a zero denominator the result is never an infinity or a
307            // `Nan`: a ratio of two integers is a real number, and the only
308            // question is whether it fits.
309            den != 0 ==> (!r.spec_is_nan() && !r.spec_is_infinite()),
310            // Saturation happens exactly when the *value* leaves the budget...
311            den != 0 ==> (r.spec_is_saturated() <==> !crate::model::magnitude_fits(
312                crate::q::signed_den_num(num as int, den as int),
313                crate::model::abs_int(den as int),
314            )),
315            // ...and when it does, it carries the correct sign.
316            (den != 0 && r == Q::PosSat) ==> crate::q::signed_den_num(
317                num as int,
318                den as int,
319            ) > 0,
320            (den != 0 && r == Q::NegSat) ==> crate::q::signed_den_num(
321                num as int,
322                den as int,
323            ) < 0,
324            // Otherwise the value is pinned completely, to the same nearest-mode
325            // rounding of the same sign-normalised pair that `new_rounded` uses.
326            (den != 0 && crate::model::magnitude_fits(
327                crate::q::signed_den_num(num as int, den as int),
328                crate::model::abs_int(den as int),
329            )) ==> r == Q::Number(
330                crate::round::round_frac(
331                    crate::q::signed_den_num(num as int, den as int),
332                    crate::model::abs_int(den as int),
333                    Dir::Nearest,
334                ),
335            ),
336    {
337        if den == 0 {
338            if num == 0 {
339                Q::Nan
340            } else if num > 0 {
341                Q::PosInf
342            } else {
343                Q::NegInf
344            }
345        } else {
346            // Normalise the sign onto the numerator first, matching
347            // `new_rounded`'s convention, so that the magnitude test and the
348            // rounding agree about which value they are talking about.
349            // `0 - (i64::MIN as i128)` is `2^63`, comfortably inside `i128`.
350            let n: i128 = if den < 0 {
351                0 - (num as i128)
352            } else {
353                num as i128
354            };
355            let d: i128 = if den < 0 {
356                0 - (den as i128)
357            } else {
358                den as i128
359            };
360            proof {
361                // `|n| <= 2^63 < 2^126 = num_input_bound()`, which is
362                // `magnitude_fits_exec`'s precondition.
363                crate::model::lemma_pow2_64();
364                crate::model::lemma_pow2_126();
365                crate::model::lemma_pow2_mono(64, 126);
366            }
367            if crate::q::magnitude_fits_exec(n, d) {
368                match Rat::new_rounded(num, den, Dir::Nearest) {
369                    Some(x) => Q::Number(x),
370                    // Unreachable: `new_rounded` is `None` iff `den == 0`.
371                    None => Q::Nan,
372                }
373            } else if n > 0 {
374                Q::PosSat
375            } else {
376                Q::NegSat
377            }
378        }
379    }
380
381    // -----------------------------------------------------------------------
382    // Value predicates (issue #26 §5)
383    //
384    // Each predicate is `false` on `Nan`. The design states that result.
385    // `Nan` denotes every value, thus no non-trivial predicate holds of it.
386    //
387    // Delegate to the kernel predicates: a reimplementation would mirror its own
388    // postcondition and verify with a shared defect.
389
390    /// Whether this is exactly zero.
391    pub open spec fn spec_is_zero(self) -> bool {
392        match self {
393            Q::Number(x) => x.n() == 0,
394            _ => false,
395        }
396    }
397
398    /// Whether this is exactly one.
399    pub open spec fn spec_is_one(self) -> bool {
400        match self {
401            Q::Number(x) => x.n() == x.d(),
402            _ => false,
403        }
404    }
405
406    /// Whether this is `Number(x)` with `x` the exact rational `n / d`.
407    ///
408    /// A constructor states its result with this predicate and does not name a
409    /// kernel constructor. `Rat::zero()` and the other kernel constructors are
410    /// `exec` functions and thus cannot appear in a specification.
411    pub open spec fn spec_is_value(self, n: int, d: int) -> bool {
412        match self {
413            Q::Number(x) => x.n() == n && x.d() == d,
414            _ => false,
415        }
416    }
417
418    /// Whether this lies in `[0, 1]`.
419    pub open spec fn spec_in_unit_interval(self) -> bool {
420        match self {
421            Q::Number(x) => x.n() >= 0 && x.n() <= x.d(),
422            _ => false,
423        }
424    }
425
426    /// `self == 0`.
427    ///
428    /// The result is false for each special value. `PosSat` denotes
429    /// `(MAX_MAG, +∞)`, which does not contain zero, thus false is the true
430    /// answer there. For `Nan` the result is a convention from the design.
431    ///
432    /// ```
433    /// use the_q::Q;
434    ///
435    /// assert!(Q::zero().is_zero());
436    /// assert!(!Q::PosSat.is_zero());
437    /// assert!(!Q::Nan.is_zero());
438    /// ```
439    pub fn is_zero(self) -> (r: bool)
440        requires
441            self.wf(),
442        ensures
443            r == self.spec_is_zero(),
444    {
445        match self {
446            Q::Number(x) => x.is_zero(),
447            _ => false,
448        }
449    }
450
451    /// `self == 1`.
452    ///
453    /// ```
454    /// use the_q::Q;
455    ///
456    /// assert!(Q::one().is_one());
457    /// assert!(!Q::PosSat.is_one());
458    /// ```
459    pub fn is_one(self) -> (r: bool)
460        requires
461            self.wf(),
462        ensures
463            r == self.spec_is_one(),
464    {
465        match self {
466            Q::Number(x) => x.is_one(),
467            _ => false,
468        }
469    }
470
471    /// `0 <= self <= 1`.
472    ///
473    /// The result is false for each special value. For the saturations false is
474    /// the true answer, because both saturation ranges are outside `[0, 1]`.
475    ///
476    /// ```
477    /// use the_q::{Q, Rat};
478    ///
479    /// assert!(Q::number(Rat::new(1, 2).unwrap()).in_unit_interval());
480    /// assert!(!Q::PosSat.in_unit_interval());
481    /// ```
482    pub fn in_unit_interval(self) -> (r: bool)
483        requires
484            self.wf(),
485        ensures
486            r == self.spec_in_unit_interval(),
487    {
488        match self {
489            Q::Number(x) => x.in_unit_interval(),
490            _ => false,
491        }
492    }
493
494    /// The sign, where one exists.
495    ///
496    /// The result is `None` for `Nan` only. Both saturations and both
497    /// infinities have a definite sign and give `Some`. The discriminant
498    /// carries that sign for this purpose.
499    ///
500    /// ```
501    /// use the_q::{Q, Sign};
502    ///
503    /// assert_eq!(Q::one().signum(), Some(Sign::Positive));
504    /// assert_eq!(Q::zero().signum(), Some(Sign::Zero));
505    /// assert_eq!(Q::PosSat.signum(), Some(Sign::Positive));
506    /// assert_eq!(Q::Nan.signum(), None);
507    /// ```
508    pub fn signum(self) -> (r: Option<Sign>)
509        requires
510            self.wf(),
511        ensures
512            r == self.spec_signum(),
513    {
514        match self {
515            Q::Number(x) => {
516                let s = x.signum();
517                if s < 0 {
518                    Some(Sign::Negative)
519                } else if s > 0 {
520                    Some(Sign::Positive)
521                } else {
522                    Some(Sign::Zero)
523                }
524            },
525            Q::PosSat => Some(Sign::Positive),
526            Q::NegSat => Some(Sign::Negative),
527            Q::PosInf => Some(Sign::Positive),
528            Q::NegInf => Some(Sign::Negative),
529            Q::Nan => None,
530        }
531    }
532}
533
534/// The sign classification is total away from `Nan`, and zero is recognized
535/// exactly rather than merely implied in one direction.
536pub proof fn theorem_signum_complete(q: Q)
537    requires
538        q.wf(),
539    ensures
540        (q.spec_signum() == Some(Sign::Zero)) <==> q.spec_is_zero(),
541        q.spec_signum().is_none() <==> q.spec_is_nan(),
542        !(q.spec_signum() == Some(Sign::Positive)
543            && q.spec_signum() == Some(Sign::Negative)),
544{
545    match q {
546        Q::Number(x) => {
547            if x.n() < 0 {
548            } else if x.n() > 0 {
549            } else {
550            }
551        },
552        _ => {},
553    }
554}
555
556// ---------------------------------------------------------------------------
557// N-ary folds (issue #26 §10.5)
558//
559// The kernel folds `nary::sum`, `nary::product` and `nary::weighted_mean`
560// clamp. For example, `sum(&[M, M, -M])` clamps to `M`, then subtracts, and
561// returns `0`, but the true total is `M`. The folds below use the operations of
562// this enum, thus an overflow at any point in the chain is reported and not
563// absorbed.
564//
565// After a partial fold saturates, `PosSat + Number(-M)` is `Nan` and the fold
566// does not recover; check `is_number()` on the result for the exact-path
567// guarantee.
568
569/// Every element satisfies the type invariant.
570pub open spec fn all_wf_q(s: Seq<Q>) -> bool {
571    forall|i: int| 0 <= i < s.len() ==> (#[trigger] s[i]).wf()
572}
573
574/// Every component of every pair satisfies the type invariant.
575pub open spec fn all_wf_q_pairs(s: Seq<(Q, Q)>) -> bool {
576    forall|i: int|
577        0 <= i < s.len() ==> (#[trigger] s[i]).0.wf() && s[i].1.wf()
578}
579
580impl Q {
581    /// `xs[0] + xs[1] + ...`, left to right. An empty slice gives `0`.
582    ///
583    /// The left-to-right order is part of the contract and not an
584    /// implementation detail. With rounding, addition is not associative, thus
585    /// the order fixes the answer and makes the result reproducible.
586    ///
587    /// ```
588    /// use the_q::Q;
589    ///
590    /// let xs = [Q::one(), Q::one(), Q::one()];
591    /// assert_eq!(Q::sum(&xs), Q::number(the_q::Rat::new(3, 1).unwrap()));
592    /// assert!(Q::sum(&[]).is_zero());
593    /// ```
594    pub fn sum(xs: &[Q]) -> (r: Q)
595        requires
596            all_wf_q(xs@),
597        ensures
598            r.wf(),
599            xs@.len() == 0 ==> r.spec_is_zero(),
600    {
601        let mut acc = Q::zero();
602        let mut i: usize = 0;
603        while i < xs.len()
604            invariant
605                acc.wf(),
606                all_wf_q(xs@),
607                i <= xs.len(),
608                i == 0 ==> acc.spec_is_zero(),
609            decreases xs.len() - i,
610        {
611            acc = Q::add(acc, xs[i]);
612            i = i + 1;
613        }
614        acc
615    }
616
617    /// `xs[0] * xs[1] * ...`, left to right. An empty slice gives `1`.
618    ///
619    /// ```
620    /// use the_q::{Q, Rat};
621    ///
622    /// let xs = [Q::number(Rat::new(2, 1).unwrap()), Q::number(Rat::new(3, 1).unwrap())];
623    /// assert_eq!(Q::product(&xs), Q::number(Rat::new(6, 1).unwrap()));
624    /// assert!(Q::product(&[]).is_one());
625    /// ```
626    pub fn product(xs: &[Q]) -> (r: Q)
627        requires
628            all_wf_q(xs@),
629        ensures
630            r.wf(),
631            xs@.len() == 0 ==> r.spec_is_one(),
632    {
633        let mut acc = Q::one();
634        let mut i: usize = 0;
635        while i < xs.len()
636            invariant
637                acc.wf(),
638                all_wf_q(xs@),
639                i <= xs.len(),
640                i == 0 ==> acc.spec_is_one(),
641            decreases xs.len() - i,
642        {
643            acc = Q::mul(acc, xs[i]);
644            i = i + 1;
645        }
646        acc
647    }
648
649    /// `sum(w_i · x_i) / sum(w_i)`, total: a zero weight sum gives `Nan` (`0/0`)
650    /// or a signed infinity, and an empty slice gives `Nan` the same way.
651    ///
652    /// ```
653    /// use the_q::{Q, Rat};
654    ///
655    /// let one = Q::one();
656    /// let two = Q::number(Rat::new(2, 1).unwrap());
657    /// // weight 1 on `1`, weight 3 on `2`: (1*1 + 3*2) / (1 + 3) == 7/4
658    /// let three = Q::number(Rat::new(3, 1).unwrap());
659    /// let pairs = [(one, one), (three, two)];
660    /// assert_eq!(Q::weighted_mean(&pairs), Q::number(Rat::new(7, 4).unwrap()));
661    /// assert!(Q::weighted_mean(&[]).is_nan());
662    /// ```
663    pub fn weighted_mean(pairs: &[(Q, Q)]) -> (r: Q)
664        requires
665            all_wf_q_pairs(pairs@),
666        ensures
667            r.wf(),
668    {
669        let mut acc_num = Q::zero();
670        let mut acc_w = Q::zero();
671        let mut i: usize = 0;
672        while i < pairs.len()
673            invariant
674                acc_num.wf(),
675                acc_w.wf(),
676                all_wf_q_pairs(pairs@),
677                i <= pairs.len(),
678            decreases pairs.len() - i,
679        {
680            let (w, x) = pairs[i];
681            acc_num = Q::add(acc_num, Q::mul(w, x));
682            acc_w = Q::add(acc_w, w);
683            i = i + 1;
684        }
685        Q::div(acc_num, acc_w)
686    }
687}
688
689// ---------------------------------------------------------------------------
690// Addition, subtraction, multiplication (issue #26 §10.3)
691//
692// Saturation becomes visible in the enum here. The kernel returns `±MAX_MAG/1`
693// when a sum or a product leaves the budget. For example, `Rat::add(M, M)` is
694// `M`, which is wrong by a factor of two and looks like a true result. This
695// layer reports `PosSat` or `NegSat` instead.
696//
697// The precision cliffs below are option (A) from §6. The lattice has no element
698// for "sign known, magnitude unknown", thus some cells give `Nan` where a
699// `PosUnknown` or `NegUnknown` state gives a precise answer. A cliff affects
700// only a computation that continues after an overflow.
701// ---------------------------------------------------------------------------
702
703impl Q {
704    /// Ghost mirror of [`Q::add_numbers`]. Exists only so `Q::add`'s result is
705    /// *nameable* in ghost code, the same role `round_frac` plays for
706    /// `round_frac_exec` (V4): it lets `add`'s `ensures` pin `r ==
707    /// Q::spec_add(a, b)`, which is what makes the algebraic-law theorems in
708    /// `laws_q.rs` statable at all.
709    ///
710    /// This is *not* the specification of soundness. It is shaped like the
711    /// implementation on purpose, because its only job is to *equal* the
712    /// implementation. `denote.rs`'s `denotes`/`add_sound`/`add_honest` are
713    /// the specification, and by construction they never call this function
714    /// (checked by `scripts/check-no-spec-mirror-in-denote.sh`) — a spec
715    /// shaped like the table it specifies verifies with a shared mistake
716    /// (the scar this crate already carries once, noted at `recip` below).
717    pub open spec fn spec_add_numbers(x: Rat, y: Rat) -> Q {
718        let n = crate::q::add_n(x, y);
719        let d = crate::q::prod_d(x, y);
720        if crate::model::magnitude_fits(n, d) {
721            Q::Number(crate::round::round_frac(n, d, Dir::Nearest))
722        } else if n > 0 {
723            Q::PosSat
724        } else {
725            Q::NegSat
726        }
727    }
728
729    /// `x + y` for two representable rationals, saturating rather than clamping.
730    fn add_numbers(x: Rat, y: Rat) -> (r: Q)
731        requires
732            x.wf(),
733            y.wf(),
734        ensures
735            r.wf(),
736            !r.spec_is_nan(),
737            !r.spec_is_infinite(),
738            r == Q::spec_add_numbers(x, y),
739    {
740        let n: i128 = crate::q::add_n_exec(x, y);
741        let d: i128 = crate::q::prod_d_exec(x, y);
742        proof {
743            crate::q::lemma_op_widths(x, y);
744            crate::model::lemma_pow2_126();
745        }
746        if crate::q::magnitude_fits_exec(n, d) {
747            Q::Number(Rat::add(x, y))
748        } else if n > 0 {
749            Q::PosSat
750        } else {
751            Q::NegSat
752        }
753    }
754
755    /// Ghost mirror of [`Q::mul_numbers`]. See [`Q::spec_add_numbers`].
756    pub open spec fn spec_mul_numbers(x: Rat, y: Rat) -> Q {
757        let n = crate::q::mul_n(x, y);
758        let d = crate::q::prod_d(x, y);
759        if crate::model::magnitude_fits(n, d) {
760            Q::Number(crate::round::round_frac(n, d, Dir::Nearest))
761        } else if n > 0 {
762            Q::PosSat
763        } else {
764            Q::NegSat
765        }
766    }
767
768    /// `x * y` for two representable rationals, saturating rather than clamping.
769    fn mul_numbers(x: Rat, y: Rat) -> (r: Q)
770        requires
771            x.wf(),
772            y.wf(),
773        ensures
774            r.wf(),
775            !r.spec_is_nan(),
776            !r.spec_is_infinite(),
777            r == Q::spec_mul_numbers(x, y),
778    {
779        let n: i128 = crate::q::mul_n_exec(x, y);
780        let d: i128 = crate::q::prod_d_exec(x, y);
781        proof {
782            crate::q::lemma_op_widths(x, y);
783            crate::model::lemma_pow2_126();
784        }
785        if crate::q::magnitude_fits_exec(n, d) {
786            Q::Number(Rat::mul(x, y))
787        } else if n > 0 {
788            Q::PosSat
789        } else {
790            Q::NegSat
791        }
792    }
793
794    /// Ghost mirror of [`Q::number_plus_sat`]. See [`Q::spec_add_numbers`].
795    pub open spec fn spec_number_plus_sat(x: Rat, sat_pos: bool) -> Q {
796        if sat_pos {
797            if x.n() >= 0 {
798                Q::PosSat
799            } else {
800                Q::Nan
801            }
802        } else {
803            if x.n() <= 0 {
804                Q::NegSat
805            } else {
806                Q::Nan
807            }
808        }
809    }
810
811    /// `Number(x) + Sat`: sound for `x` on the saturation's side; for the other
812    /// sign the image reaches inside the budget and the result is `Nan`.
813    fn number_plus_sat(x: Rat, sat_pos: bool) -> (r: Q)
814        requires
815            x.wf(),
816        ensures
817            r.wf(),
818            !r.spec_is_infinite(),
819            !r.spec_is_number(),
820            r == Q::spec_number_plus_sat(x, sat_pos),
821    {
822        let s = x.signum();
823        if sat_pos {
824            if s >= 0 {
825                Q::PosSat
826            } else {
827                Q::Nan
828            }
829        } else {
830            if s <= 0 {
831                Q::NegSat
832            } else {
833                Q::Nan
834            }
835        }
836    }
837
838    /// `Number(x) * Sat`. Saturated for `|x| >= 1` (inclusive: `one() * PosSat`
839    /// must stay `PosSat`), `Nan` for `0 < |x| < 1` where the image reaches
840    /// below `MAX_MAG`, and exactly `Number(0)` at zero.
841    /// Ghost mirror of [`Q::number_times_sat`]. See [`Q::spec_add_numbers`].
842    pub open spec fn spec_number_times_sat(x: Rat, sat_pos: bool) -> Q {
843        if x.n() == 0 {
844            Q::Number(Rat::from_raw_spec(0, 1))
845        } else if !(x.n() >= x.d() || x.n() <= 0 - x.d()) {
846            Q::Nan
847        } else if (x.n() > 0) == sat_pos {
848            Q::PosSat
849        } else {
850            Q::NegSat
851        }
852    }
853
854    fn number_times_sat(x: Rat, sat_pos: bool) -> (r: Q)
855        requires
856            x.wf(),
857        ensures
858            r.wf(),
859            !r.spec_is_infinite(),
860            r == Q::spec_number_times_sat(x, sat_pos),
861    {
862        if x.is_zero() {
863            return Q::zero();
864        }
865        let n = x.numerator();
866        let d = x.denominator();
867        // `|x| >= 1` without division: `|n| >= d`, and `d > 0` by the invariant.
868        let at_least_one = n >= d || n <= 0 - d;
869        if !at_least_one {
870            return Q::Nan;
871        }
872        // Sign of the product of a sign-definite saturation and a nonzero `x`.
873        let positive = (n > 0) == sat_pos;
874        if positive {
875            Q::PosSat
876        } else {
877            Q::NegSat
878        }
879    }
880
881    /// Ghost mirror of [`Q::add`]'s match, cell for cell. This is *not* the
882    /// specification of `add`'s correctness — `denote.rs`'s
883    /// `add_sound`/`add_honest`/`add_nan_is_necessary` are, and none of them
884    /// call this function. Its only job is to make `add`'s result nameable in
885    /// ghost code (`r == Q::spec_add(a, b)`), which is the prerequisite the
886    /// commutativity/associativity/distributivity/monotonicity theorems in
887    /// `laws_q.rs` need: none of those properties are even statable against a
888    /// return value that only classification `ensures` clauses constrain.
889    pub open spec fn spec_add(a: Q, b: Q) -> Q {
890        match (a, b) {
891            (Q::Nan, _) => Q::Nan,
892            (_, Q::Nan) => Q::Nan,
893            (Q::Number(x), Q::Number(y)) => Q::spec_add_numbers(x, y),
894            (Q::Number(x), Q::PosSat) => Q::spec_number_plus_sat(x, true),
895            (Q::Number(x), Q::NegSat) => Q::spec_number_plus_sat(x, false),
896            (Q::PosSat, Q::Number(y)) => Q::spec_number_plus_sat(y, true),
897            (Q::NegSat, Q::Number(y)) => Q::spec_number_plus_sat(y, false),
898            (Q::PosSat, Q::PosSat) => Q::PosSat,
899            (Q::NegSat, Q::NegSat) => Q::NegSat,
900            (Q::PosSat, Q::NegSat) => Q::Nan,
901            (Q::NegSat, Q::PosSat) => Q::Nan,
902            (Q::PosInf, Q::NegInf) => Q::Nan,
903            (Q::NegInf, Q::PosInf) => Q::Nan,
904            (Q::PosInf, _) => Q::PosInf,
905            (Q::NegInf, _) => Q::NegInf,
906            (_, Q::PosInf) => Q::PosInf,
907            (_, Q::NegInf) => Q::NegInf,
908        }
909    }
910
911    /// `a + b`, total. Replaces the kernel `add`, which clamps silently.
912    ///
913    /// ```
914    /// use the_q::{Q, Rat, MAX_MAG};
915    ///
916    /// assert_eq!(Q::add(Q::one(), Q::one()), Q::number(Rat::new(2, 1).unwrap()));
917    /// // Two representable rationals overflowing the budget saturate, they do
918    /// // not become infinite.
919    /// let m = Q::number(Rat::new(MAX_MAG, 1).unwrap());
920    /// assert_eq!(Q::add(m, m), Q::PosSat);
921    /// assert!(Q::add(Q::Nan, Q::one()).is_nan());
922    /// ```
923    pub fn add(a: Q, b: Q) -> (r: Q)
924        requires
925            a.wf(),
926            b.wf(),
927        ensures
928            r.wf(),
929            r == Q::spec_add(a, b),
930            a.spec_is_nan() ==> r.spec_is_nan(),
931            b.spec_is_nan() ==> r.spec_is_nan(),
932            // Two representable rationals can only overflow, never become
933            // infinite and never lose all information.
934            (a.spec_is_number() && b.spec_is_number()) ==> (r.spec_is_number()
935                || r.spec_is_saturated()),
936            // An infinite result needs an infinite operand. Addition cannot
937            // create one. `is_infinite()` thus keeps the meaning "a division by
938            // zero occurred upstream".
939            r.spec_is_infinite() ==> (a.spec_is_infinite() || b.spec_is_infinite()),
940            // ...and conversely an infinite operand always survives, so no
941            // representable sum can come out of one.
942            (a.spec_is_infinite() || b.spec_is_infinite()) ==> !r.spec_is_number(),
943    {
944        match (a, b) {
945            (Q::Nan, _) => Q::Nan,
946            (_, Q::Nan) => Q::Nan,
947            (Q::Number(x), Q::Number(y)) => Q::add_numbers(x, y),
948            (Q::Number(x), Q::PosSat) => Q::number_plus_sat(x, true),
949            (Q::Number(x), Q::NegSat) => Q::number_plus_sat(x, false),
950            (Q::PosSat, Q::Number(y)) => Q::number_plus_sat(y, true),
951            (Q::NegSat, Q::Number(y)) => Q::number_plus_sat(y, false),
952            // Same-signed saturations reinforce; opposite-signed ones cancel to
953            // something entirely unknown.
954            (Q::PosSat, Q::PosSat) => Q::PosSat,
955            (Q::NegSat, Q::NegSat) => Q::NegSat,
956            (Q::PosSat, Q::NegSat) => Q::Nan,
957            (Q::NegSat, Q::PosSat) => Q::Nan,
958            // An infinity dominates anything finite, saturated or not.
959            (Q::PosInf, Q::NegInf) => Q::Nan,
960            (Q::NegInf, Q::PosInf) => Q::Nan,
961            (Q::PosInf, _) => Q::PosInf,
962            (Q::NegInf, _) => Q::NegInf,
963            (_, Q::PosInf) => Q::PosInf,
964            (_, Q::NegInf) => Q::NegInf,
965        }
966    }
967
968    /// `a - b`, total.
969    ///
970    /// The definition is `a + (-b)`, as §5 specifies. The two operations thus
971    /// agree for an overflowing difference.
972    ///
973    /// ```
974    /// use the_q::{Q, Rat};
975    ///
976    /// assert_eq!(Q::sub(Q::one(), Q::one()), Q::zero());
977    /// assert!(Q::sub(Q::Nan, Q::zero()).is_nan());
978    /// ```
979    pub fn sub(a: Q, b: Q) -> (r: Q)
980        requires
981            a.wf(),
982            b.wf(),
983        ensures
984            r.wf(),
985            r == Q::spec_add(a, Q::spec_neg(b)),
986            a.spec_is_nan() ==> r.spec_is_nan(),
987            b.spec_is_nan() ==> r.spec_is_nan(),
988    {
989        Q::add(a, b.neg())
990    }
991
992    /// Ghost mirror of [`Q::mul`]'s match. See [`Q::spec_add`].
993    pub open spec fn spec_mul(a: Q, b: Q) -> Q {
994        match (a, b) {
995            (Q::Nan, _) => Q::Nan,
996            (_, Q::Nan) => Q::Nan,
997            (Q::Number(x), Q::Number(y)) => Q::spec_mul_numbers(x, y),
998            (Q::Number(x), Q::PosSat) => Q::spec_number_times_sat(x, true),
999            (Q::Number(x), Q::NegSat) => Q::spec_number_times_sat(x, false),
1000            (Q::PosSat, Q::Number(y)) => Q::spec_number_times_sat(y, true),
1001            (Q::NegSat, Q::Number(y)) => Q::spec_number_times_sat(y, false),
1002            (Q::Number(x), Q::PosInf) => Q::spec_number_times_inf(x, true),
1003            (Q::Number(x), Q::NegInf) => Q::spec_number_times_inf(x, false),
1004            (Q::PosInf, Q::Number(y)) => Q::spec_number_times_inf(y, true),
1005            (Q::NegInf, Q::Number(y)) => Q::spec_number_times_inf(y, false),
1006            (Q::PosSat, Q::PosSat) => Q::PosSat,
1007            (Q::PosSat, Q::NegSat) => Q::NegSat,
1008            (Q::NegSat, Q::PosSat) => Q::NegSat,
1009            (Q::NegSat, Q::NegSat) => Q::PosSat,
1010            (Q::PosSat, Q::PosInf) => Q::PosInf,
1011            (Q::PosSat, Q::NegInf) => Q::NegInf,
1012            (Q::NegSat, Q::PosInf) => Q::NegInf,
1013            (Q::NegSat, Q::NegInf) => Q::PosInf,
1014            (Q::PosInf, Q::PosSat) => Q::PosInf,
1015            (Q::PosInf, Q::NegSat) => Q::NegInf,
1016            (Q::NegInf, Q::PosSat) => Q::NegInf,
1017            (Q::NegInf, Q::NegSat) => Q::PosInf,
1018            (Q::PosInf, Q::PosInf) => Q::PosInf,
1019            (Q::PosInf, Q::NegInf) => Q::NegInf,
1020            (Q::NegInf, Q::PosInf) => Q::NegInf,
1021            (Q::NegInf, Q::NegInf) => Q::PosInf,
1022        }
1023    }
1024
1025    /// `a * b`, total.
1026    ///
1027    /// ```
1028    /// use the_q::Q;
1029    ///
1030    /// // Saturation denotes a finite real, so zero times it is exactly zero...
1031    /// assert_eq!(Q::mul(Q::zero(), Q::PosSat), Q::zero());
1032    /// // ...but zero times a true infinity is the classic indeterminate.
1033    /// assert!(Q::mul(Q::zero(), Q::PosInf).is_nan());
1034    /// ```
1035    pub fn mul(a: Q, b: Q) -> (r: Q)
1036        requires
1037            a.wf(),
1038            b.wf(),
1039        ensures
1040            r.wf(),
1041            r == Q::spec_mul(a, b),
1042            a.spec_is_nan() ==> r.spec_is_nan(),
1043            b.spec_is_nan() ==> r.spec_is_nan(),
1044            (a.spec_is_number() && b.spec_is_number()) ==> (r.spec_is_number()
1045                || r.spec_is_saturated()),
1046            r.spec_is_infinite() ==> (a.spec_is_infinite() || b.spec_is_infinite()),
1047            // An infinite operand gives an infinity or `Nan`, and never a
1048            // representable product. Against zero the result is `Nan`.
1049            (a.spec_is_infinite() || b.spec_is_infinite()) ==> !r.spec_is_number(),
1050    {
1051        match (a, b) {
1052            (Q::Nan, _) => Q::Nan,
1053            (_, Q::Nan) => Q::Nan,
1054            (Q::Number(x), Q::Number(y)) => Q::mul_numbers(x, y),
1055            (Q::Number(x), Q::PosSat) => Q::number_times_sat(x, true),
1056            (Q::Number(x), Q::NegSat) => Q::number_times_sat(x, false),
1057            (Q::PosSat, Q::Number(y)) => Q::number_times_sat(y, true),
1058            (Q::NegSat, Q::Number(y)) => Q::number_times_sat(y, false),
1059            // `0 · ±∞` is indeterminate. `0 · Sat` is exactly zero.
1060            (Q::Number(x), Q::PosInf) => Q::number_times_inf(x, true),
1061            (Q::Number(x), Q::NegInf) => Q::number_times_inf(x, false),
1062            (Q::PosInf, Q::Number(y)) => Q::number_times_inf(y, true),
1063            (Q::NegInf, Q::Number(y)) => Q::number_times_inf(y, false),
1064            // Two saturations give a saturation with the product sign. A
1065            // product of two magnitudes above MAX_MAG is far above MAX_MAG.
1066            (Q::PosSat, Q::PosSat) => Q::PosSat,
1067            (Q::PosSat, Q::NegSat) => Q::NegSat,
1068            (Q::NegSat, Q::PosSat) => Q::NegSat,
1069            (Q::NegSat, Q::NegSat) => Q::PosSat,
1070            (Q::PosSat, Q::PosInf) => Q::PosInf,
1071            (Q::PosSat, Q::NegInf) => Q::NegInf,
1072            (Q::NegSat, Q::PosInf) => Q::NegInf,
1073            (Q::NegSat, Q::NegInf) => Q::PosInf,
1074            (Q::PosInf, Q::PosSat) => Q::PosInf,
1075            (Q::PosInf, Q::NegSat) => Q::NegInf,
1076            (Q::NegInf, Q::PosSat) => Q::NegInf,
1077            (Q::NegInf, Q::NegSat) => Q::PosInf,
1078            (Q::PosInf, Q::PosInf) => Q::PosInf,
1079            (Q::PosInf, Q::NegInf) => Q::NegInf,
1080            (Q::NegInf, Q::PosInf) => Q::NegInf,
1081            (Q::NegInf, Q::NegInf) => Q::PosInf,
1082        }
1083    }
1084
1085    /// `self^e`, total. `pow_u32(a, 0)` is `1` for every `a` including `Nan`, as
1086    /// IEEE `NaN^0`. A left fold of [`Q::mul`], associating like the kernel.
1087    ///
1088    /// ```
1089    /// use the_q::{Q, Rat};
1090    ///
1091    /// let two = Q::number(Rat::new(2, 1).unwrap());
1092    /// assert_eq!(two.pow_u32(3), Q::number(Rat::new(8, 1).unwrap()));
1093    /// assert!(Q::Nan.pow_u32(0).is_one());
1094    /// ```
1095    pub fn pow_u32(self, e: u32) -> (r: Q)
1096        requires
1097            self.wf(),
1098        ensures
1099            r.wf(),
1100            e == 0 ==> r.spec_is_one(),
1101    {
1102        let mut acc = Q::one();
1103        let mut i: u32 = 0;
1104        while i < e
1105            invariant
1106                acc.wf(),
1107                self.wf(),
1108                i <= e,
1109                i == 0 ==> acc.spec_is_one(),
1110            decreases e - i,
1111        {
1112            acc = Q::mul(acc, self);
1113            i = i + 1;
1114        }
1115        acc
1116    }
1117
1118    /// `a + b` as a `Rat`, `None` otherwise. A view over [`Q::add`]; cannot panic.
1119    ///
1120    /// ```
1121    /// use the_q::{Q, Rat};
1122    ///
1123    /// assert_eq!(Q::checked_add(Q::one(), Q::one()), Some(Rat::new(2, 1).unwrap()));
1124    /// assert_eq!(Q::checked_add(Q::PosInf, Q::one()), None);
1125    /// ```
1126    pub fn checked_add(a: Q, b: Q) -> (r: Option<Rat>)
1127        requires
1128            a.wf(),
1129            b.wf(),
1130        ensures
1131            r.is_some() ==> r.unwrap().wf(),
1132            (a.spec_is_nan() || b.spec_is_nan()) ==> r.is_none(),
1133            (a.spec_is_infinite() || b.spec_is_infinite()) ==> r.is_none(),
1134    {
1135        match Q::add(a, b) {
1136            Q::Number(f) => Some(f),
1137            _ => None,
1138        }
1139    }
1140
1141    /// `a - b` when the result is a representable rational. See
1142    /// [`Q::checked_add`].
1143    ///
1144    /// ```
1145    /// use the_q::{Q, Rat};
1146    ///
1147    /// assert_eq!(Q::checked_sub(Q::one(), Q::one()), Some(Rat::zero()));
1148    /// assert_eq!(Q::checked_sub(Q::Nan, Q::one()), None);
1149    /// ```
1150    pub fn checked_sub(a: Q, b: Q) -> (r: Option<Rat>)
1151        requires
1152            a.wf(),
1153            b.wf(),
1154        ensures
1155            r.is_some() ==> r.unwrap().wf(),
1156            (a.spec_is_nan() || b.spec_is_nan()) ==> r.is_none(),
1157    {
1158        match Q::sub(a, b) {
1159            Q::Number(f) => Some(f),
1160            _ => None,
1161        }
1162    }
1163
1164    /// `a * b` as a `Rat`, `None` otherwise. Can succeed on a saturated operand:
1165    /// `Number(0) * PosSat` is `0`.
1166    ///
1167    /// ```
1168    /// use the_q::{Q, Rat};
1169    ///
1170    /// assert_eq!(Q::checked_mul(Q::zero(), Q::PosSat), Some(Rat::zero()));
1171    /// assert_eq!(Q::checked_mul(Q::one(), Q::PosSat), None);
1172    /// ```
1173    pub fn checked_mul(a: Q, b: Q) -> (r: Option<Rat>)
1174        requires
1175            a.wf(),
1176            b.wf(),
1177        ensures
1178            r.is_some() ==> r.unwrap().wf(),
1179            (a.spec_is_nan() || b.spec_is_nan()) ==> r.is_none(),
1180            (a.spec_is_infinite() || b.spec_is_infinite()) ==> r.is_none(),
1181    {
1182        match Q::mul(a, b) {
1183            Q::Number(f) => Some(f),
1184            _ => None,
1185        }
1186    }
1187
1188    /// Ghost mirror of [`Q::number_times_inf`]. See [`Q::spec_add_numbers`].
1189    pub open spec fn spec_number_times_inf(x: Rat, inf_pos: bool) -> Q {
1190        if x.n() == 0 {
1191            Q::Nan
1192        } else if (x.n() > 0) == inf_pos {
1193            Q::PosInf
1194        } else {
1195            Q::NegInf
1196        }
1197    }
1198
1199    /// `Number(x) * ±∞`. Zero times an infinity is the classic indeterminate.
1200    fn number_times_inf(x: Rat, inf_pos: bool) -> (r: Q)
1201        requires
1202            x.wf(),
1203        ensures
1204            r.wf(),
1205            !r.spec_is_number(),
1206            !r.spec_is_saturated(),
1207            r == Q::spec_number_times_inf(x, inf_pos),
1208    {
1209        let s = x.signum();
1210        if s == 0 {
1211            Q::Nan
1212        } else if (s > 0) == inf_pos {
1213            Q::PosInf
1214        } else {
1215            Q::NegInf
1216        }
1217    }
1218}
1219
1220// ---------------------------------------------------------------------------
1221// Negation and absolute value (issue #26 §5)
1222//
1223// These two operations are the only entries in the design that are exact and
1224// total and have no precision cliff. Negation is a bijection on each state.
1225// Absolute value maps the two sign-definite pairs onto their positive halves.
1226// ---------------------------------------------------------------------------
1227
1228impl Q {
1229    /// Ghost mirror of [`Q::neg`]'s match. See [`Q::spec_add`]. The `Number`
1230    /// arm reconstructs the negated pair through `from_raw_spec` rather than
1231    /// calling the exec-only [`Rat::neg`], which cannot appear in a spec
1232    /// position.
1233    pub open spec fn spec_neg(a: Q) -> Q {
1234        match a {
1235            Q::Number(x) => Q::Number(Rat::from_raw_spec((0 - x.n()) as i64, x.d() as i64)),
1236            Q::PosSat => Q::NegSat,
1237            Q::NegSat => Q::PosSat,
1238            Q::PosInf => Q::NegInf,
1239            Q::NegInf => Q::PosInf,
1240            Q::Nan => Q::Nan,
1241        }
1242    }
1243
1244    /// `spec_neg` preserves `wf`, proven independently of the exec `neg`
1245    /// (which a `proof fn` cannot call): the `Number` arm's reconstructed
1246    /// pair carries the same `gcd` and budget as `x`'s, negation changing
1247    /// neither.
1248    pub proof fn lemma_spec_neg_wf(a: Q)
1249        requires
1250            a.wf(),
1251        ensures
1252            Q::spec_neg(a).wf(),
1253    {
1254        match a {
1255            Q::Number(x) => {
1256                let nx = Rat::from_raw_spec((0 - x.n()) as i64, x.d() as i64);
1257                Rat::lemma_from_raw_spec_components((0 - x.n()) as i64, x.d() as i64);
1258                assert(((0 - x.n()) as i64) as int == 0 - x.n());
1259                assert((x.d() as i64) as int == x.d());
1260                assert(crate::model::gcd_int(nx.n(), nx.d()) == crate::model::gcd_int(x.n(), x.d()));
1261            },
1262            _ => {},
1263        }
1264    }
1265
1266    /// `-self`, exact and total; saturations and infinities negate onto each other.
1267    ///
1268    /// ```
1269    /// use the_q::Q;
1270    ///
1271    /// assert_eq!(Q::one().neg(), Q::neg_one());
1272    /// assert_eq!(Q::PosSat.neg(), Q::NegSat);
1273    /// assert_eq!(Q::PosInf.neg(), Q::NegInf);
1274    /// assert!(Q::Nan.neg().is_nan());
1275    /// ```
1276    pub fn neg(self) -> (r: Q)
1277        requires
1278            self.wf(),
1279        ensures
1280            r.wf(),
1281            r == Q::spec_neg(self),
1282            // Negation permutes the classes rather than collapsing any of them.
1283            r.spec_is_number() == self.spec_is_number(),
1284            r.spec_is_saturated() == self.spec_is_saturated(),
1285            r.spec_is_infinite() == self.spec_is_infinite(),
1286            r.spec_is_nan() == self.spec_is_nan(),
1287            r.spec_is_zero() == self.spec_is_zero(),
1288    {
1289        match self {
1290            Q::Number(x) => {
1291                let nx = x.neg();
1292                proof {
1293                    assert(((0 - x.n()) as i64) as int == 0 - x.n());
1294                    assert((x.d() as i64) as int == x.d());
1295                    Rat::lemma_from_raw_spec_components((0 - x.n()) as i64, x.d() as i64);
1296                    Rat::lemma_extensional(nx, Rat::from_raw_spec((0 - x.n()) as i64, x.d() as i64));
1297                }
1298                Q::Number(nx)
1299            },
1300            Q::PosSat => Q::NegSat,
1301            Q::NegSat => Q::PosSat,
1302            Q::PosInf => Q::NegInf,
1303            Q::NegInf => Q::PosInf,
1304            Q::Nan => Q::Nan,
1305        }
1306    }
1307
1308    /// `|self|`, exact and total. Not injective on the specials, which is why
1309    /// `neg` carries class-preservation postconditions and this does not.
1310    ///
1311    /// ```
1312    /// use the_q::Q;
1313    ///
1314    /// assert_eq!(Q::neg_one().abs(), Q::one());
1315    /// assert_eq!(Q::NegSat.abs(), Q::PosSat);
1316    /// assert_eq!(Q::NegInf.abs(), Q::PosInf);
1317    /// ```
1318    pub fn abs(self) -> (r: Q)
1319        requires
1320            self.wf(),
1321        ensures
1322            r.wf(),
1323            r.spec_is_number() == self.spec_is_number(),
1324            r.spec_is_saturated() == self.spec_is_saturated(),
1325            r.spec_is_infinite() == self.spec_is_infinite(),
1326            r.spec_is_nan() == self.spec_is_nan(),
1327            // The result is never negative: a `Number` payload is `>= 0`, and
1328            // the only special that survives is the positive one of each pair.
1329            r.spec_is_number() ==> r->Number_0.n() >= 0,
1330            !r.spec_is_nan() ==> r != Q::NegSat && r != Q::NegInf,
1331    {
1332        match self {
1333            Q::Number(x) => Q::Number(x.abs()),
1334            Q::PosSat => Q::PosSat,
1335            Q::NegSat => Q::PosSat,
1336            Q::PosInf => Q::PosInf,
1337            Q::NegInf => Q::PosInf,
1338            Q::Nan => Q::Nan,
1339        }
1340    }
1341}
1342
1343// ---------------------------------------------------------------------------
1344// Selection: min, max, clamp (issue #26 §5)
1345//
1346// These operations propagate `Nan`. They are thus not the `Ord`-based selection
1347// that `slice.iter().min()` performs. A selection that comes from the order is
1348// a defect: `Ord`-based selection gives `min(Nan, Number(5)) == Number(5)`,
1349// which asserts that the true value is exactly 5 when the value can be
1350// anything.
1351//
1352// IEEE 754-2019 withdrew the NaN-ignoring `minNum`/`maxNum`; these follow the
1353// NaN-propagating `minimum`/`maximum`.
1354
1355impl Q {
1356    /// The smaller of `a` and `b`, propagating `Nan`; not `Ord`-based selection.
1357    ///
1358    /// ```
1359    /// use the_q::Q;
1360    ///
1361    /// assert_eq!(Q::min(Q::zero(), Q::one()), Q::zero());
1362    /// // Unlike `Ord::min`, a `Nan` operand makes the result `Nan`.
1363    /// assert!(Q::min(Q::Nan, Q::one()).is_nan());
1364    /// ```
1365    pub fn min(a: Q, b: Q) -> (r: Q)
1366        requires
1367            a.wf(),
1368            b.wf(),
1369        ensures
1370            r.wf(),
1371            (a.spec_is_nan() || b.spec_is_nan()) ==> r.spec_is_nan(),
1372            !(a.spec_is_nan() || b.spec_is_nan()) ==> {
1373                &&& (r == a || r == b)
1374                &&& Q::spec_le(r, a)
1375                &&& Q::spec_le(r, b)
1376                // ...and which argument. The contract thus names the result
1377                // and does not only constrain it.
1378                //
1379                // The three clauses above fix the answer uniquely, which is
1380                // `theorem_min_spec_categorical`. That uniqueness is a property
1381                // of the contract. These two clauses connect it to the output
1382                // of this function, thus the postcondition determines the
1383                // result for each input.
1384                &&& Q::spec_le(a, b) ==> r == a
1385                &&& !Q::spec_le(a, b) ==> r == b
1386            },
1387    {
1388        if a.is_nan() || b.is_nan() {
1389            Q::Nan
1390        } else if Q::le(a, b) {
1391            a
1392        } else {
1393            b
1394        }
1395    }
1396
1397    /// The larger of `a` and `b`, propagating `Nan`. See [`Q::min`].
1398    ///
1399    /// ```
1400    /// use the_q::Q;
1401    ///
1402    /// assert_eq!(Q::max(Q::zero(), Q::one()), Q::one());
1403    /// assert!(Q::max(Q::Nan, Q::one()).is_nan());
1404    /// ```
1405    pub fn max(a: Q, b: Q) -> (r: Q)
1406        requires
1407            a.wf(),
1408            b.wf(),
1409        ensures
1410            r.wf(),
1411            (a.spec_is_nan() || b.spec_is_nan()) ==> r.spec_is_nan(),
1412            !(a.spec_is_nan() || b.spec_is_nan()) ==> {
1413                &&& (r == a || r == b)
1414                &&& Q::spec_le(a, r)
1415                &&& Q::spec_le(b, r)
1416                // See `Q::min`: these name the result rather than bounding it.
1417                &&& Q::spec_le(a, b) ==> r == b
1418                &&& !Q::spec_le(a, b) ==> r == a
1419            },
1420    {
1421        if a.is_nan() || b.is_nan() {
1422            Q::Nan
1423        } else if Q::le(a, b) {
1424            b
1425        } else {
1426            a
1427        }
1428    }
1429
1430    /// `a` clamped into `[lo, hi]`; `Nan` in any argument, or an inverted range,
1431    /// gives `Nan` rather than an endpoint that asserts a false value.
1432    ///
1433    /// ```
1434    /// use the_q::{Q, Rat};
1435    ///
1436    /// let half = Q::number(Rat::new(1, 2).unwrap());
1437    /// assert_eq!(Q::clamp(half, Q::zero(), Q::one()), half);
1438    /// let two = Q::number(Rat::new(2, 1).unwrap());
1439    /// assert_eq!(Q::clamp(two, Q::zero(), Q::one()), Q::one());
1440    /// // An inverted range has no consistent answer.
1441    /// assert!(Q::clamp(half, Q::one(), Q::zero()).is_nan());
1442    /// ```
1443    pub fn clamp(a: Q, lo: Q, hi: Q) -> (r: Q)
1444        requires
1445            a.wf(),
1446            lo.wf(),
1447            hi.wf(),
1448        ensures
1449            r.wf(),
1450            (a.spec_is_nan() || lo.spec_is_nan() || hi.spec_is_nan()) ==> r.spec_is_nan(),
1451            (!a.spec_is_nan() && !lo.spec_is_nan() && !hi.spec_is_nan() && Q::spec_le(lo, hi)) ==> {
1452                &&& (r == a || r == lo || r == hi)
1453                &&& Q::spec_le(lo, r)
1454                &&& Q::spec_le(r, hi)
1455                // ...and which of the three values. Without these three
1456                // clauses a `clamp` that always returns `lo` satisfies the
1457                // contract above: for `lo < a < hi`, `r == lo` is one of the
1458                // three permitted values and lies in `[lo, hi]`.
1459                //
1460                // A postcondition that is wide enough to admit a wrong answer
1461                // is not a specification. A proof that the contract is
1462                // categorical finds this class of weakness.
1463                &&& (Q::spec_le(lo, a) && Q::spec_le(a, hi)) ==> r == a
1464                &&& !Q::spec_le(lo, a) ==> r == lo
1465                &&& !Q::spec_le(a, hi) ==> r == hi
1466            },
1467    {
1468        if a.is_nan() || lo.is_nan() || hi.is_nan() {
1469            Q::Nan
1470        } else if Q::lt(hi, lo) {
1471            // An inverted range has no consistent answer. `Nan` states that
1472            // condition. An endpoint result does not.
1473            Q::Nan
1474        } else if Q::lt(a, lo) {
1475            proof {
1476                // `a < lo <= hi` gives `a <= hi`, which makes the "returns
1477                // `hi`" clause vacuously true on this branch. Transitivity is
1478                // not free: the prover has `!spec_le(lo, a)` and needs totality
1479                // to turn it into `spec_le(a, lo)` first.
1480                theorem_order_total(lo, a);
1481                theorem_order_transitive(a, lo, hi);
1482            }
1483            lo
1484        } else if Q::lt(hi, a) {
1485            hi
1486        } else {
1487            a
1488        }
1489    }
1490}
1491
1492// ---------------------------------------------------------------------------
1493// Total division (issue #26 §10.2)
1494//
1495// This section closes the three defects that open #26. The kernel now fails
1496// loudly on each of them, and this layer answers with a value instead:
1497//
1498//   * `Rat::zero().recip()` panics. It once returned `Rat { num: -1, den: 0 }`,
1499//     which violates the type invariant and fails later, far from the cause.
1500//   * `Rat::div(x, 0)` panics.
1501//   * `Rat::checked_div(x, 0)` is `None`, as `std` and `num-traits` are for
1502//     this case.
1503//
1504// Each cell below comes from the denotations in §2. The result is the smallest
1505// state whose denotation contains the true image
1506// `{ x/y : x ∈ ⟦a⟧, y ∈ ⟦b⟧ }`. `Nan` is always sound, because it denotes
1507// every value. Precision is thus the only property to argue.
1508// ---------------------------------------------------------------------------
1509
1510impl Q {
1511    /// Ghost mirror of [`Q::div_numbers`]. See [`Q::spec_add_numbers`].
1512    pub open spec fn spec_div_numbers(x: Rat, y: Rat) -> Q {
1513        let n = crate::q::div_n(x, y);
1514        let d = crate::q::div_d(x, y);
1515        if crate::model::magnitude_fits(n, d) {
1516            Q::Number(crate::round::round_frac(n, d, Dir::Nearest))
1517        } else if n > 0 {
1518            Q::PosSat
1519        } else {
1520            Q::NegSat
1521        }
1522    }
1523
1524    /// `x / y` for representable `x`, `y != 0`; saturates rather than clamps.
1525    fn div_numbers(x: Rat, y: Rat) -> (r: Q)
1526        requires
1527            x.wf(),
1528            y.wf(),
1529            y.n() != 0,
1530        ensures
1531            r.wf(),
1532            !r.spec_is_nan(),
1533            !r.spec_is_infinite(),
1534            r == Q::spec_div_numbers(x, y),
1535    {
1536        let n: i128 = crate::q::div_n_exec(x, y);
1537        let d: i128 = crate::q::div_d_exec(x, y);
1538        proof {
1539            crate::q::lemma_op_widths(x, y);
1540            crate::model::lemma_pow2_126();
1541        }
1542        if crate::q::magnitude_fits_exec(n, d) {
1543            Q::Number(Rat::div(x, y))
1544        } else if n > 0 {
1545            Q::PosSat
1546        } else {
1547            Q::NegSat
1548        }
1549    }
1550
1551    /// Ghost mirror of [`Q::sat_div_number`]. See [`Q::spec_add_numbers`].
1552    pub open spec fn spec_sat_div_number(pos: bool, y: Rat) -> Q {
1553        if y.n() == 0 {
1554            if pos {
1555                Q::PosInf
1556            } else {
1557                Q::NegInf
1558            }
1559        } else if y.n() > 0 {
1560            if y.n() <= y.d() {
1561                if pos {
1562                    Q::PosSat
1563                } else {
1564                    Q::NegSat
1565                }
1566            } else {
1567                Q::Nan
1568            }
1569        } else {
1570            if y.n() >= 0 - y.d() {
1571                if pos {
1572                    Q::NegSat
1573                } else {
1574                    Q::PosSat
1575                }
1576            } else {
1577                Q::Nan
1578            }
1579        }
1580    }
1581
1582    /// `Sat / y`. Sound while `|y| <= 1` (inclusive); above that the image
1583    /// contains representable values and the result is `Nan`.
1584    fn sat_div_number(pos: bool, y: Rat) -> (r: Q)
1585        requires
1586            y.wf(),
1587        ensures
1588            r.wf(),
1589            // A saturation is finite, so the quotient can only become infinite
1590            // by dividing by zero. `div` needs this to prove that an infinity in
1591            // its result always points at a zero divisor.
1592            r.spec_is_infinite() ==> y.n() == 0,
1593            // ...and conversely, a zero divisor always produces one, so no
1594            // representable quotient can survive it.
1595            y.n() == 0 ==> r.spec_is_infinite(),
1596            r == Q::spec_sat_div_number(pos, y),
1597    {
1598        let s = y.signum();
1599        if s == 0 {
1600            // A saturation has a definite sign and is nonzero, thus this case
1601            // is `x/0` with `x != 0`. The IEEE convention of §4 gives a signed
1602            // infinity.
1603            if pos {
1604                Q::PosInf
1605            } else {
1606                Q::NegInf
1607            }
1608        } else if s > 0 {
1609            if y.numerator() <= y.denominator() {
1610                if pos {
1611                    Q::PosSat
1612                } else {
1613                    Q::NegSat
1614                }
1615            } else {
1616                Q::Nan
1617            }
1618        } else {
1619            if y.numerator() >= 0 - y.denominator() {
1620                if pos {
1621                    Q::NegSat
1622                } else {
1623                    Q::PosSat
1624                }
1625            } else {
1626                Q::Nan
1627            }
1628        }
1629    }
1630
1631    /// Ghost mirror of [`Q::div`]'s match. See [`Q::spec_add`].
1632    pub open spec fn spec_div(a: Q, b: Q) -> Q {
1633        match (a, b) {
1634            (Q::Nan, _) => Q::Nan,
1635            (_, Q::Nan) => Q::Nan,
1636            (Q::Number(x), Q::Number(y)) => {
1637                if y.n() == 0 {
1638                    if x.n() == 0 {
1639                        Q::Nan
1640                    } else if x.n() > 0 {
1641                        Q::PosInf
1642                    } else {
1643                        Q::NegInf
1644                    }
1645                } else {
1646                    Q::spec_div_numbers(x, y)
1647                }
1648            },
1649            (Q::Number(x), Q::PosSat) => if x.n() == 0 {
1650                Q::Number(Rat::from_raw_spec(0, 1))
1651            } else {
1652                Q::Nan
1653            },
1654            (Q::Number(x), Q::NegSat) => if x.n() == 0 {
1655                Q::Number(Rat::from_raw_spec(0, 1))
1656            } else {
1657                Q::Nan
1658            },
1659            (Q::Number(_), Q::PosInf) => Q::Number(Rat::from_raw_spec(0, 1)),
1660            (Q::Number(_), Q::NegInf) => Q::Number(Rat::from_raw_spec(0, 1)),
1661            (Q::PosSat, Q::Number(y)) => Q::spec_sat_div_number(true, y),
1662            (Q::NegSat, Q::Number(y)) => Q::spec_sat_div_number(false, y),
1663            (Q::PosSat, Q::PosSat) => Q::Nan,
1664            (Q::PosSat, Q::NegSat) => Q::Nan,
1665            (Q::NegSat, Q::PosSat) => Q::Nan,
1666            (Q::NegSat, Q::NegSat) => Q::Nan,
1667            (Q::PosSat, Q::PosInf) => Q::Number(Rat::from_raw_spec(0, 1)),
1668            (Q::PosSat, Q::NegInf) => Q::Number(Rat::from_raw_spec(0, 1)),
1669            (Q::NegSat, Q::PosInf) => Q::Number(Rat::from_raw_spec(0, 1)),
1670            (Q::NegSat, Q::NegInf) => Q::Number(Rat::from_raw_spec(0, 1)),
1671            (Q::PosInf, Q::Number(y)) => if y.n() < 0 {
1672                Q::NegInf
1673            } else {
1674                Q::PosInf
1675            },
1676            (Q::NegInf, Q::Number(y)) => if y.n() < 0 {
1677                Q::PosInf
1678            } else {
1679                Q::NegInf
1680            },
1681            (Q::PosInf, Q::PosSat) => Q::PosInf,
1682            (Q::PosInf, Q::NegSat) => Q::NegInf,
1683            (Q::NegInf, Q::PosSat) => Q::NegInf,
1684            (Q::NegInf, Q::NegSat) => Q::PosInf,
1685            (Q::PosInf, Q::PosInf) => Q::Nan,
1686            (Q::PosInf, Q::NegInf) => Q::Nan,
1687            (Q::NegInf, Q::PosInf) => Q::Nan,
1688            (Q::NegInf, Q::NegInf) => Q::Nan,
1689        }
1690    }
1691
1692    /// `a / b`, total. Division by zero follows IEEE 754 uniformly, so that
1693    /// `recip(x) == div(one, x)` holds at zero. `Sat / Inf` is exactly `0` and
1694    /// `Inf / Sat` a signed infinity, because saturation denotes finite reals.
1695    ///
1696    /// ```
1697    /// use the_q::{Q, Rat};
1698    ///
1699    /// assert_eq!(Q::div(Q::one(), Q::one()), Q::one());
1700    /// // Division by zero follows IEEE 754: a signed infinity, and `0/0` is `Nan`.
1701    /// assert_eq!(Q::div(Q::one(), Q::zero()), Q::PosInf);
1702    /// assert!(Q::div(Q::zero(), Q::zero()).is_nan());
1703    /// ```
1704    pub fn div(a: Q, b: Q) -> (r: Q)
1705        requires
1706            a.wf(),
1707            b.wf(),
1708        ensures
1709            r.wf(),
1710            r == Q::spec_div(a, b),
1711            // `Nan` is absorbing on both sides — no information in, none out.
1712            a.spec_is_nan() ==> r.spec_is_nan(),
1713            b.spec_is_nan() ==> r.spec_is_nan(),
1714            // Dividing two representable rationals by a nonzero divisor yields a
1715            // rational or an overflow, never an infinity and never `Nan`. This
1716            // is what makes the `checked_div` sugar below meaningful.
1717            (a.spec_is_number() && b.spec_is_number() && !b.spec_is_zero()) ==> (r.spec_is_number()
1718                || r.spec_is_saturated()),
1719            // An infinite result means a zero divisor or an infinite
1720            // numerator, and never an overflow. This property keeps
1721            // `is_infinite()` usable as a diagnostic. It reports a division by
1722            // zero, and an overflow reports `is_saturated()` instead.
1723            r.spec_is_infinite() ==> (a.spec_is_infinite() || b.spec_is_zero()),
1724            // No representable quotient survives a zero divisor or an infinite
1725            // numerator. Together with the clauses above this is what makes
1726            // `checked_div` a faithful `Option` view of the discriminant.
1727            b.spec_is_zero() ==> !r.spec_is_number(),
1728            a.spec_is_infinite() ==> !r.spec_is_number(),
1729    {
1730        match (a, b) {
1731            (Q::Nan, _) => Q::Nan,
1732            (_, Q::Nan) => Q::Nan,
1733            // --- a representable numerator ---
1734            (Q::Number(x), Q::Number(y)) => {
1735                if y.is_zero() {
1736                    if x.is_zero() {
1737                        // 0/0 carries no information at all.
1738                        Q::Nan
1739                    } else if x.signum() > 0 {
1740                        Q::PosInf
1741                    } else {
1742                        Q::NegInf
1743                    }
1744                } else {
1745                    Q::div_numbers(x, y)
1746                }
1747            },
1748            // `x / Sat`: the image is `(0, x/M)`, which contains representable
1749            // values. Only `x == 0` thus has a sound answer, and that answer is
1750            // exact, because `Sat` cannot be infinite.
1751            (Q::Number(x), Q::PosSat) => if x.is_zero() {
1752                Q::zero()
1753            } else {
1754                Q::Nan
1755            },
1756            (Q::Number(x), Q::NegSat) => if x.is_zero() {
1757                Q::zero()
1758            } else {
1759                Q::Nan
1760            },
1761            (Q::Number(_), Q::PosInf) => Q::zero(),
1762            (Q::Number(_), Q::NegInf) => Q::zero(),
1763            // --- a saturated numerator ---
1764            (Q::PosSat, Q::Number(y)) => Q::sat_div_number(true, y),
1765            (Q::NegSat, Q::Number(y)) => Q::sat_div_number(false, y),
1766            // `Sat / Sat` covers `(0, ∞)` or its mirror. The sign is known and
1767            // the magnitude is unknown. This lattice has no state for that.
1768            (Q::PosSat, Q::PosSat) => Q::Nan,
1769            (Q::PosSat, Q::NegSat) => Q::Nan,
1770            (Q::NegSat, Q::PosSat) => Q::Nan,
1771            (Q::NegSat, Q::NegSat) => Q::Nan,
1772            // `Sat / Inf` — exact, see the doc comment.
1773            (Q::PosSat, Q::PosInf) => Q::zero(),
1774            (Q::PosSat, Q::NegInf) => Q::zero(),
1775            (Q::NegSat, Q::PosInf) => Q::zero(),
1776            (Q::NegSat, Q::NegInf) => Q::zero(),
1777            // --- an infinite numerator ---
1778            // Including `y == 0`: §4 makes `±∞/0` sign-preserving, not `Nan`.
1779            (Q::PosInf, Q::Number(y)) => if y.signum() < 0 {
1780                Q::NegInf
1781            } else {
1782                Q::PosInf
1783            },
1784            (Q::NegInf, Q::Number(y)) => if y.signum() < 0 {
1785                Q::PosInf
1786            } else {
1787                Q::NegInf
1788            },
1789            (Q::PosInf, Q::PosSat) => Q::PosInf,
1790            (Q::PosInf, Q::NegSat) => Q::NegInf,
1791            (Q::NegInf, Q::PosSat) => Q::NegInf,
1792            (Q::NegInf, Q::NegSat) => Q::PosInf,
1793            // `∞/∞` is the classic indeterminate.
1794            (Q::PosInf, Q::PosInf) => Q::Nan,
1795            (Q::PosInf, Q::NegInf) => Q::Nan,
1796            (Q::NegInf, Q::PosInf) => Q::Nan,
1797            (Q::NegInf, Q::NegInf) => Q::Nan,
1798        }
1799    }
1800
1801    /// `1 / self`, total, defined as `div(one, self)` (`theorem_recip_is_div_one`).
1802    /// Exact on a nonzero `Number`: swapping a canonical pair cannot round.
1803    ///
1804    /// ```
1805    /// use the_q::{Q, Rat};
1806    ///
1807    /// let two = Q::number(Rat::new(2, 1).unwrap());
1808    /// assert_eq!(two.recip(), Q::number(Rat::new(1, 2).unwrap()));
1809    /// assert_eq!(Q::zero().recip(), Q::PosInf);
1810    /// ```
1811    pub fn recip(self) -> (r: Q)
1812        requires
1813            self.wf(),
1814        ensures
1815            r.wf(),
1816            self.spec_is_nan() ==> r.spec_is_nan(),
1817            // theorem_q_recip_is_div_one: true by definition, not derived —
1818            // recip's only body is this call.
1819            r == Q::spec_div(Q::Number(Rat::from_raw_spec(1, 1)), self),
1820    {
1821        // The cell-by-cell table is deliberately not restated in ghost form: a spec
1822        // shaped like the table verifies with a shared mistake.
1823        Q::div(Q::one(), self)
1824    }
1825
1826    /// `a / b` as a `Rat`, `None` otherwise, including a zero divisor.
1827    ///
1828    /// ```
1829    /// use the_q::{Q, Rat};
1830    ///
1831    /// assert_eq!(Q::checked_div(Q::one(), Q::one()), Some(Rat::one()));
1832    /// assert_eq!(Q::checked_div(Q::one(), Q::zero()), None);
1833    /// ```
1834    pub fn checked_div(a: Q, b: Q) -> (r: Option<Rat>)
1835        requires
1836            a.wf(),
1837            b.wf(),
1838        ensures
1839            r.is_some() ==> r.unwrap().wf(),
1840            // `None` for each case with no representable quotient: a zero
1841            // divisor, an operand with no information, or an infinite
1842            // numerator. The remaining `None` case is an overflow, which the
1843            // kernel `checked_div` also reports. This function is thus an
1844            // extension of the kernel function and not a change of meaning.
1845            (b.spec_is_zero() || a.spec_is_nan() || b.spec_is_nan() || a.spec_is_infinite())
1846                ==> r.is_none(),
1847    {
1848        match Q::div(a, b) {
1849            Q::Number(f) => Some(f),
1850            _ => None,
1851        }
1852    }
1853}
1854
1855// ---------------------------------------------------------------------------
1856// The classification really is a partition
1857//
1858// This property is stated and proven, and not assumed. The four predicates are
1859// the only supported case split on the type from outside the module. A caller
1860// that handles all four cases thus handles each state.
1861// ---------------------------------------------------------------------------
1862
1863/// The four classification predicates are mutually exclusive and jointly
1864/// exhaustive.
1865pub proof fn theorem_classification_partitions(q: Q)
1866    ensures
1867// exactly one holds
1868
1869        (if q.spec_is_number() { 1int } else { 0int }) + (if q.spec_is_saturated() {
1870            1int
1871        } else {
1872            0int
1873        }) + (if q.spec_is_infinite() { 1int } else { 0int }) + (if q.spec_is_nan() {
1874            1int
1875        } else {
1876            0int
1877        }) == 1,
1878{
1879    match q {
1880        Q::Number(_) => {},
1881        Q::PosSat => {},
1882        Q::NegSat => {},
1883        Q::PosInf => {},
1884        Q::NegInf => {},
1885        Q::Nan => {},
1886    }
1887}
1888
1889/// A saturation is never a number, an infinity or a `Nan` — the fact callers
1890/// most often want when reading `is_saturated` as an overflow diagnostic.
1891pub proof fn theorem_saturated_excludes_rest(q: Q)
1892    requires
1893        q.spec_is_saturated(),
1894    ensures
1895        !q.spec_is_number(),
1896        !q.spec_is_infinite(),
1897        !q.spec_is_nan(),
1898{
1899}
1900
1901// ---------------------------------------------------------------------------
1902// The total order (issue #26 §5)
1903//
1904//     NegInf  <  NegSat  <  Number(...)  <  PosSat  <  PosInf  <  Nan
1905//
1906// This order applies to representations and not to denoted values. Outside
1907// `Number` that difference is visible: `PosSat == PosSat` compares `Equal`
1908// while the two true values can differ. Inside `Number` the order is the order
1909// on rationals.
1910//
1911// `NegSat < Number < PosSat` strictly, by I2; the position of `Nan` is a free
1912// choice.
1913
1914impl Q {
1915    /// The position of a variant in the order above.
1916    ///
1917    /// The order uses this rank and not the declaration order. A change to the
1918    /// variant order thus cannot change the order on values. For the same
1919    /// reason `Ord` is hand-written and not derived.
1920    pub open spec fn spec_rank(self) -> int {
1921        match self {
1922            Q::NegInf => 0,
1923            Q::NegSat => 1,
1924            Q::Number(_) => 2,
1925            Q::PosSat => 3,
1926            Q::PosInf => 4,
1927            Q::Nan => 5,
1928        }
1929    }
1930
1931    /// The ghost order: `a <= b`.
1932    pub open spec fn spec_le(a: Q, b: Q) -> bool {
1933        if a.spec_rank() != b.spec_rank() {
1934            a.spec_rank() < b.spec_rank()
1935        } else {
1936            match (a, b) {
1937                (Q::Number(x), Q::Number(y)) => crate::model::q_le(x, y),
1938                // Every other equal-rank pair is the same payload-free variant,
1939                // so the two representations are identical.
1940                _ => true,
1941            }
1942        }
1943    }
1944
1945    /// The ghost order: `a == b`, as representations.
1946    pub open spec fn spec_eq(a: Q, b: Q) -> bool {
1947        Q::spec_le(a, b) && Q::spec_le(b, a)
1948    }
1949}
1950
1951impl Q {
1952    /// Three-way comparison: negative, zero or positive as `a < b`, `a == b` or
1953    /// `a > b` in the order above.
1954    ///
1955    /// The comparison is total. There is no incomparable pair, because `Nan`
1956    /// has a definite position.
1957    ///
1958    /// ```
1959    /// use the_q::Q;
1960    ///
1961    /// assert_eq!(Q::compare(Q::zero(), Q::one()), -1);
1962    /// assert_eq!(Q::compare(Q::one(), Q::one()), 0);
1963    /// // `Nan` sorts last, above every other state.
1964    /// assert_eq!(Q::compare(Q::PosInf, Q::Nan), -1);
1965    /// ```
1966    pub fn compare(a: Q, b: Q) -> (r: i32)
1967        requires
1968            a.wf(),
1969            b.wf(),
1970        ensures
1971            r <= 0 <==> Q::spec_le(a, b),
1972            r >= 0 <==> Q::spec_le(b, a),
1973            r == 0 <==> Q::spec_eq(a, b),
1974    {
1975        match (a, b) {
1976            // This is the only case with a payload. It delegates to the
1977            // verified kernel comparison and does not cross-multiply again.
1978            (Q::Number(x), Q::Number(y)) => Rat::compare(x, y),
1979            _ => {
1980                let ra = Q::rank_exec(a);
1981                let rb = Q::rank_exec(b);
1982                if ra < rb {
1983                    -1
1984                } else if ra > rb {
1985                    1
1986                } else {
1987                    0
1988                }
1989            },
1990        }
1991    }
1992
1993    /// Exec mirror of [`Q::spec_rank`].
1994    fn rank_exec(q: Q) -> (r: i32)
1995        ensures
1996            r == q.spec_rank(),
1997    {
1998        match q {
1999            Q::NegInf => 0,
2000            Q::NegSat => 1,
2001            Q::Number(_) => 2,
2002            Q::PosSat => 3,
2003            Q::PosInf => 4,
2004            Q::Nan => 5,
2005        }
2006    }
2007
2008    /// `a < b`.
2009    ///
2010    /// ```
2011    /// use the_q::Q;
2012    ///
2013    /// assert!(Q::lt(Q::zero(), Q::one()));
2014    /// assert!(!Q::lt(Q::one(), Q::one()));
2015    /// ```
2016    pub fn lt(a: Q, b: Q) -> (r: bool)
2017        requires
2018            a.wf(),
2019            b.wf(),
2020        ensures
2021            r <==> !Q::spec_le(b, a),
2022    {
2023        Q::compare(a, b) < 0
2024    }
2025
2026    /// `a <= b`.
2027    ///
2028    /// ```
2029    /// use the_q::Q;
2030    ///
2031    /// assert!(Q::le(Q::one(), Q::one()));
2032    /// assert!(!Q::le(Q::one(), Q::zero()));
2033    /// ```
2034    pub fn le(a: Q, b: Q) -> (r: bool)
2035        requires
2036            a.wf(),
2037            b.wf(),
2038        ensures
2039            r <==> Q::spec_le(a, b),
2040    {
2041        Q::compare(a, b) <= 0
2042    }
2043
2044    /// `a > b`.
2045    ///
2046    /// ```
2047    /// use the_q::Q;
2048    ///
2049    /// assert!(Q::gt(Q::one(), Q::zero()));
2050    /// assert!(!Q::gt(Q::zero(), Q::zero()));
2051    /// ```
2052    pub fn gt(a: Q, b: Q) -> (r: bool)
2053        requires
2054            a.wf(),
2055            b.wf(),
2056        ensures
2057            r <==> !Q::spec_le(a, b),
2058    {
2059        Q::compare(a, b) > 0
2060    }
2061
2062    /// `a >= b`.
2063    ///
2064    /// ```
2065    /// use the_q::Q;
2066    ///
2067    /// assert!(Q::ge(Q::one(), Q::one()));
2068    /// assert!(!Q::ge(Q::zero(), Q::one()));
2069    /// ```
2070    pub fn ge(a: Q, b: Q) -> (r: bool)
2071        requires
2072            a.wf(),
2073            b.wf(),
2074        ensures
2075            r <==> Q::spec_le(b, a),
2076    {
2077        Q::compare(a, b) >= 0
2078    }
2079}
2080
2081/// The order is total: every pair is comparable, `Nan` included.
2082pub proof fn theorem_order_total(a: Q, b: Q)
2083    requires
2084        a.wf(),
2085        b.wf(),
2086    ensures
2087        Q::spec_le(a, b) || Q::spec_le(b, a),
2088{
2089}
2090
2091/// Antisymmetry against *structural* equality: `a <= b <= a` gives `a == b`,
2092/// not merely `spec_eq`. This is what makes the derived `Eq`/`Hash` sound
2093/// beside the hand-written `Ord`; the `Number` case is kernel canonicality.
2094pub proof fn theorem_order_antisymmetric(a: Q, b: Q)
2095    requires
2096        a.wf(),
2097        b.wf(),
2098        Q::spec_le(a, b),
2099        Q::spec_le(b, a),
2100    ensures
2101        a == b,
2102{
2103    match (a, b) {
2104        (Q::Number(x), Q::Number(y)) => {
2105            crate::laws::lemma_canonical_eq(x, y);
2106        },
2107        _ => {},
2108    }
2109}
2110
2111/// `spec_eq` and the derived `PartialEq` are the same relation.
2112///
2113/// This theorem is the other direction of the theorem above. Together they
2114/// give the equivalence that `Ord`/`Eq` consistency needs.
2115pub proof fn theorem_spec_eq_is_structural_eq(a: Q, b: Q)
2116    requires
2117        a.wf(),
2118        b.wf(),
2119    ensures
2120        Q::spec_eq(a, b) <==> a == b,
2121{
2122    if Q::spec_eq(a, b) {
2123        theorem_order_antisymmetric(a, b);
2124    }
2125    match (a, b) {
2126        (Q::Number(x), Q::Number(y)) => {
2127            crate::laws::lemma_canonical_eq(x, y);
2128        },
2129        _ => {},
2130    }
2131}
2132
2133/// The order is transitive.
2134///
2135/// The cross-rank cases are integer transitivity on the rank. The all-`Number`
2136/// case uses the transitivity lemma of the kernel.
2137pub proof fn theorem_order_transitive(a: Q, b: Q, c: Q)
2138    requires
2139        a.wf(),
2140        b.wf(),
2141        c.wf(),
2142        Q::spec_le(a, b),
2143        Q::spec_le(b, c),
2144    ensures
2145        Q::spec_le(a, c),
2146{
2147    match (a, b, c) {
2148        (Q::Number(x), Q::Number(y), Q::Number(z)) => {
2149            crate::q::lemma_le_trans(x, y, z);
2150        },
2151        _ => {},
2152    }
2153}
2154
2155/// Saturation sits strictly outside the numbers, on the correct side.
2156///
2157/// This fact makes the placement sound. It states that the order on
2158/// representations agrees with the order on denoted values wherever both are
2159/// defined.
2160pub proof fn theorem_sat_separates_numbers(x: Rat)
2161    requires
2162        x.wf(),
2163    ensures
2164        Q::spec_le(Q::NegSat, Q::Number(x)),
2165        Q::spec_le(Q::Number(x), Q::PosSat),
2166        !Q::spec_le(Q::Number(x), Q::NegSat),
2167        !Q::spec_le(Q::PosSat, Q::Number(x)),
2168{
2169}
2170
2171/// `NegInf` is strictly below and `Nan` strictly above every other value, so
2172/// folds can start there and the extremes are unique.
2173pub proof fn theorem_order_extremes(q: Q)
2174    ensures
2175        Q::spec_le(Q::NegInf, q),
2176        Q::spec_le(q, Q::Nan),
2177        q != Q::NegInf ==> !Q::spec_le(q, Q::NegInf),
2178        q != Q::Nan ==> !Q::spec_le(Q::Nan, q),
2179{
2180}
2181
2182/// Trichotomy: exactly one of `a < b`, `a == b`, `b < a` holds.
2183pub proof fn theorem_order_trichotomy(a: Q, b: Q)
2184    requires
2185        a.wf(),
2186        b.wf(),
2187    ensures
2188        (if !Q::spec_le(b, a) {
2189            1int
2190        } else {
2191            0int
2192        }) + (if a == b {
2193            1int
2194        } else {
2195            0int
2196        }) + (if !Q::spec_le(a, b) {
2197            1int
2198        } else {
2199            0int
2200        }) == 1,
2201{
2202    theorem_order_total(a, b);
2203    if Q::spec_le(a, b) && Q::spec_le(b, a) {
2204        theorem_order_antisymmetric(a, b);
2205    }
2206}
2207
2208/// `min`'s contract admits exactly one answer; on a tie, canonicality makes the
2209/// two representations one.
2210pub proof fn theorem_min_spec_categorical(a: Q, b: Q, r1: Q, r2: Q)
2211    requires
2212        a.wf(),
2213        b.wf(),
2214        r1 == a || r1 == b,
2215        Q::spec_le(r1, a),
2216        Q::spec_le(r1, b),
2217        r2 == a || r2 == b,
2218        Q::spec_le(r2, a),
2219        Q::spec_le(r2, b),
2220    ensures
2221        r1 == r2,
2222{
2223    // r1 <= r2 because r2 is one of {a, b}, and symmetrically; antisymmetry
2224    // then forces structural equality.
2225    theorem_order_antisymmetric(r1, r2);
2226}
2227
2228/// **`max`'s postcondition pins its result uniquely.** This theorem is the dual
2229/// of [`theorem_min_spec_categorical`]. It is a separate theorem, because the
2230/// `max` contract is its own statement and not a rewriting of the `min`
2231/// contract.
2232pub proof fn theorem_max_spec_categorical(a: Q, b: Q, r1: Q, r2: Q)
2233    requires
2234        a.wf(),
2235        b.wf(),
2236        r1 == a || r1 == b,
2237        Q::spec_le(a, r1),
2238        Q::spec_le(b, r1),
2239        r2 == a || r2 == b,
2240        Q::spec_le(a, r2),
2241        Q::spec_le(b, r2),
2242    ensures
2243        r1 == r2,
2244{
2245    theorem_order_antisymmetric(r1, r2);
2246}
2247
2248/// `clamp`'s contract admits exactly one answer. Without its last three clauses
2249/// a `clamp` that always returned `lo` would verify.
2250pub proof fn theorem_clamp_spec_categorical(a: Q, lo: Q, hi: Q, r1: Q, r2: Q)
2251    requires
2252        a.wf(),
2253        lo.wf(),
2254        hi.wf(),
2255        Q::spec_le(lo, hi),
2256        (Q::spec_le(lo, a) && Q::spec_le(a, hi)) ==> r1 == a,
2257        !Q::spec_le(lo, a) ==> r1 == lo,
2258        !Q::spec_le(a, hi) ==> r1 == hi,
2259        (Q::spec_le(lo, a) && Q::spec_le(a, hi)) ==> r2 == a,
2260        !Q::spec_le(lo, a) ==> r2 == lo,
2261        !Q::spec_le(a, hi) ==> r2 == hi,
2262    ensures
2263        r1 == r2,
2264{
2265    // The three guards are exhaustive once `lo <= hi`: if `a` is below `lo` it
2266    // is below `hi` too, and symmetrically above. Totality supplies the
2267    // trichotomy that makes the case split complete.
2268    theorem_order_total(lo, a);
2269    theorem_order_total(a, hi);
2270}
2271
2272/// `(min(a, b), max(a, b))` is `(a, b)` or `(b, a)`: a two-element sort.
2273pub proof fn theorem_min_max_exchange(a: Q, b: Q, rmin: Q, rmax: Q)
2274    requires
2275        a.wf(),
2276        b.wf(),
2277        rmin == a || rmin == b,
2278        Q::spec_le(rmin, a),
2279        Q::spec_le(rmin, b),
2280        rmax == a || rmax == b,
2281        Q::spec_le(a, rmax),
2282        Q::spec_le(b, rmax),
2283    ensures
2284        (rmin == a && rmax == b) || (rmin == b && rmax == a),
2285{
2286    if rmin == a && rmax == a {
2287        // a <= b from min's bound, b <= a from max's: the arguments coincide.
2288        theorem_order_antisymmetric(a, b);
2289    }
2290    if rmin == b && rmax == b {
2291        theorem_order_antisymmetric(a, b);
2292    }
2293}
2294
2295/// `min` is the greatest lower bound: `q <= min(a, b)` iff `q <= a` and `q <= b`.
2296pub proof fn theorem_min_is_glb(a: Q, b: Q, r: Q, q: Q)
2297    requires
2298        a.wf(),
2299        b.wf(),
2300        q.wf(),
2301        r == a || r == b,
2302        Q::spec_le(r, a),
2303        Q::spec_le(r, b),
2304    ensures
2305        Q::spec_le(q, r) <==> (Q::spec_le(q, a) && Q::spec_le(q, b)),
2306{
2307    if Q::spec_le(q, r) {
2308        theorem_order_transitive(q, r, a);
2309        theorem_order_transitive(q, r, b);
2310    }
2311}
2312
2313/// **`max` computes the least upper bound** — the dual of
2314/// [`theorem_min_is_glb`].
2315pub proof fn theorem_max_is_lub(a: Q, b: Q, r: Q, q: Q)
2316    requires
2317        a.wf(),
2318        b.wf(),
2319        q.wf(),
2320        r == a || r == b,
2321        Q::spec_le(a, r),
2322        Q::spec_le(b, r),
2323    ensures
2324        Q::spec_le(r, q) <==> (Q::spec_le(a, q) && Q::spec_le(b, q)),
2325{
2326    if Q::spec_le(r, q) {
2327        theorem_order_transitive(a, r, q);
2328        theorem_order_transitive(b, r, q);
2329    }
2330}
2331
2332/// The component-wise `spec_in_unit_interval` agrees with the order-based
2333/// `0 <= q <= 1` on a `Number`; no special is in `[0, 1]`.
2334pub proof fn theorem_unit_interval_agrees_with_order(q: Q)
2335    requires
2336        q.wf(),
2337    ensures
2338        q.spec_in_unit_interval() <==> (q.spec_is_number() && Q::spec_le(
2339            Q::Number(Rat::from_raw_spec(0, 1)),
2340            q,
2341        ) && Q::spec_le(q, Q::Number(Rat::from_raw_spec(1, 1)))),
2342{
2343    Rat::lemma_from_raw_spec_components(0, 1);
2344    Rat::lemma_from_raw_spec_components(1, 1);
2345}
2346
2347/// `spec_is_zero` holds only of `Number(0/1)` and `spec_is_one` only of
2348/// `Number(1/1)`: the enum-level form of canonicality.
2349pub proof fn theorem_zero_one_unique_repr(q: Q)
2350    requires
2351        q.wf(),
2352    ensures
2353        q.spec_is_zero() <==> q == Q::Number(Rat::from_raw_spec(0, 1)),
2354        q.spec_is_one() <==> q == Q::Number(Rat::from_raw_spec(1, 1)),
2355{
2356    Rat::lemma_from_raw_spec_components(0, 1);
2357    Rat::lemma_from_raw_spec_components(1, 1);
2358    match q {
2359        Q::Number(x) => {
2360            if x.n() == 0 {
2361                assert(x.d() == 1);
2362                Rat::lemma_extensional(x, Rat::from_raw_spec(0, 1));
2363            }
2364            if x.n() == x.d() {
2365                // n == d > 0, so gcd_int(n, d) == gcd_nat(nn, nn) with nn > 0.
2366                let nn = x.n() as nat;
2367                assert(crate::model::abs_int(x.n()) == x.n());
2368                // One definitional unfold: gcd(nn, nn) == gcd(nn, nn % nn).
2369                assert(nn % nn == 0) by (nonlinear_arith)
2370                    requires
2371                        nn > 0,
2372                ;
2373                crate::gcd::lemma_gcd_zero(nn);
2374                assert(crate::model::gcd_nat(nn, nn) == nn);
2375                // wf says that gcd is 1, so n == d == 1.
2376                assert(x.n() == 1);
2377                assert(x.d() == 1);
2378                Rat::lemma_extensional(x, Rat::from_raw_spec(1, 1));
2379            }
2380        },
2381        _ => {},
2382    }
2383}
2384
2385} // verus!
2386
2387// ---------------------------------------------------------------------------
2388// Standard trait impls
2389//
2390// These implementations are total delegations to the verified functions above,
2391// in the pattern that `Rat` uses. Verus does not model the `core` comparison
2392// traits, thus these implementations are `external`. Verified code cannot call
2393// them and does not need them.
2394// ---------------------------------------------------------------------------
2395
2396#[cfg_attr(verus_keep_ghost, verifier::external)]
2397impl PartialOrd for Q {
2398    fn partial_cmp(&self, other: &Q) -> Option<core::cmp::Ordering> {
2399        Some(<Q as Ord>::cmp(self, other))
2400    }
2401}
2402
2403#[cfg_attr(verus_keep_ghost, verifier::external)]
2404impl Ord for Q {
2405    /// Delegates to the verified [`Q::compare`]. Do not use for selection:
2406    /// `Ord`-based `min(Nan, Number(5))` asserts the value 5.
2407    fn cmp(&self, other: &Q) -> core::cmp::Ordering {
2408        Q::compare(*self, *other).cmp(&0)
2409    }
2410}
2411
2412// ---------------------------------------------------------------------------
2413// Operator traits
2414//
2415// These implementations are total delegations, in the pattern that `Rat` uses.
2416// Verus does not model the `core::ops` traits, thus these implementations are
2417// `external` and add no assumption to a proof.
2418//
2419// This type implements `Div`, and `Rat` does not. Division on `Rat` has the
2420// precondition `!b.is_zero()`, which an operator cannot express, thus `a / b`
2421// on `Rat` can panic. `Q::div` is total, thus each input to `a / b` gives a
2422// value.
2423// ---------------------------------------------------------------------------
2424
2425#[cfg_attr(verus_keep_ghost, verifier::external)]
2426impl core::ops::Add for Q {
2427    type Output = Q;
2428
2429    fn add(self, rhs: Q) -> Q {
2430        Q::add(self, rhs)
2431    }
2432}
2433
2434#[cfg_attr(verus_keep_ghost, verifier::external)]
2435impl core::ops::Sub for Q {
2436    type Output = Q;
2437
2438    fn sub(self, rhs: Q) -> Q {
2439        Q::sub(self, rhs)
2440    }
2441}
2442
2443#[cfg_attr(verus_keep_ghost, verifier::external)]
2444impl core::ops::Mul for Q {
2445    type Output = Q;
2446
2447    fn mul(self, rhs: Q) -> Q {
2448        Q::mul(self, rhs)
2449    }
2450}
2451
2452/// Total division. The note above states why this operator exists here and not
2453/// on `Rat`.
2454#[cfg_attr(verus_keep_ghost, verifier::external)]
2455impl core::ops::Div for Q {
2456    type Output = Q;
2457
2458    fn div(self, rhs: Q) -> Q {
2459        Q::div(self, rhs)
2460    }
2461}
2462
2463#[cfg_attr(verus_keep_ghost, verifier::external)]
2464impl core::ops::Neg for Q {
2465    type Output = Q;
2466
2467    fn neg(self) -> Q {
2468        Q::neg(self)
2469    }
2470}
2471
2472/// `Q::zero()` — the additive identity, and the identity `Sum` folds from.
2473#[cfg_attr(verus_keep_ghost, verifier::external)]
2474impl Default for Q {
2475    fn default() -> Q {
2476        Q::zero()
2477    }
2478}