use super::simplicity::simplest_in_cut;
use super::Surreal;
use crate::scalar::{Ordinal, Rational, Scalar};
use std::cmp::Ordering;
impl Surreal {
pub fn sign_expansion(&self) -> Option<Vec<bool>> {
if !self.is_dyadic() {
return None;
}
let x = self.as_rational().unwrap();
let (mut lo, mut hi): (Option<Rational>, Option<Rational>) = (None, None);
let mut signs = Vec::new();
loop {
let v = simplest_in_cut(&lo, &hi);
match x.cmp(&v) {
Ordering::Equal => break,
Ordering::Greater => {
signs.push(true);
lo = Some(v);
}
Ordering::Less => {
signs.push(false);
hi = Some(v);
}
}
}
Some(signs)
}
pub fn from_sign_expansion(signs: &[bool]) -> Surreal {
let (mut lo, mut hi): (Option<Rational>, Option<Rational>) = (None, None);
for &s in signs {
let v = simplest_in_cut(&lo, &hi);
if s {
lo = Some(v);
} else {
hi = Some(v);
}
}
Surreal::from_rational(simplest_in_cut(&lo, &hi))
}
pub fn as_ordinal(&self) -> Option<Ordinal> {
let mut result = Ordinal::zero();
for (e, c) in &self.terms {
if !c.is_integer() || c.sign() != Ordering::Greater {
return None; }
if e.sign() == Ordering::Less {
return None; }
let eord = e.as_ordinal()?; result = result.ord_add(&Ordinal::monomial(eord, c.numer() as u128));
}
Some(result)
}
pub fn from_ordinal(o: &Ordinal) -> Option<Surreal> {
let mut acc = Surreal::zero();
for (exp, c) in o.terms() {
let exp_s = Surreal::from_ordinal(exp)?; let c_i128 = i128::try_from(*c).ok()?;
acc = acc.add(&Surreal::monomial(exp_s, Rational::from_int(c_i128)));
}
Some(acc)
}
pub fn from_transfinite_sign_expansion(se: &SignExpansion) -> Option<Surreal> {
let runs = se.runs();
if runs.is_empty() {
return Some(Surreal::zero());
}
if let Some(signs) = se.as_finite() {
return Some(Surreal::from_sign_expansion(&signs));
}
if runs.len() == 1 {
let (sign, len) = &runs[0];
let s = Surreal::from_ordinal(len)?;
return Some(if *sign { s } else { s.neg() });
}
if runs.len() == 2 {
let ((s0, l0), (s1, l1)) = (&runs[0], &runs[1]);
if *s0 && !*s1 && *l0 == Ordinal::from_u128(1) && *l1 == Ordinal::omega() {
return Some(Surreal::epsilon());
}
}
None
}
pub fn transfinite_sign_expansion(&self) -> Option<SignExpansion> {
if self.is_zero() {
return Some(SignExpansion { runs: Vec::new() });
}
if let Some(signs) = self.sign_expansion() {
return Some(SignExpansion::from_finite(&signs));
}
if let Some(alpha) = self.as_ordinal() {
if !alpha.is_zero() {
return Some(SignExpansion {
runs: vec![(true, alpha)],
});
}
}
if let Some(alpha) = self.neg().as_ordinal() {
if !alpha.is_zero() {
return Some(SignExpansion {
runs: vec![(false, alpha)],
});
}
}
if *self == Surreal::epsilon() {
return Some(SignExpansion {
runs: vec![(true, Ordinal::from_u128(1)), (false, Ordinal::omega())],
});
}
None
}
pub fn birthday_ordinal(&self) -> Option<Ordinal> {
if let Some(b) = self.dyadic_birthday() {
return Some(Ordinal::from_u128(b));
}
Some(self.transfinite_sign_expansion()?.length())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SignExpansion {
runs: Vec<(bool, Ordinal)>,
}
impl SignExpansion {
pub fn from_runs(runs: Vec<(bool, Ordinal)>) -> Self {
let mut normalized: Vec<(bool, Ordinal)> = Vec::new();
for (sign, len) in runs {
if len.is_zero() {
continue;
}
if let Some(last) = normalized.last_mut() {
if last.0 == sign {
last.1 = last.1.ord_add(&len);
continue;
}
}
normalized.push((sign, len));
}
SignExpansion { runs: normalized }
}
pub fn runs(&self) -> &[(bool, Ordinal)] {
&self.runs
}
pub fn length(&self) -> Ordinal {
let mut len = Ordinal::zero();
for (_, l) in &self.runs {
len = len.ord_add(l);
}
len
}
pub fn from_finite(signs: &[bool]) -> Self {
let mut runs: Vec<(bool, Ordinal)> = Vec::new();
for &s in signs {
if let Some(last) = runs.last_mut() {
if last.0 == s {
last.1 = last.1.ord_add(&Ordinal::from_u128(1));
continue;
}
}
runs.push((s, Ordinal::from_u128(1)));
}
SignExpansion { runs }
}
pub fn as_finite(&self) -> Option<Vec<bool>> {
let mut out = Vec::new();
for (s, l) in &self.runs {
let n = l.as_finite()?;
for _ in 0..n {
out.push(*s);
}
}
Some(out)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn rat(n: i128, d: i128) -> Surreal {
Surreal::from_rational(Rational::new(n, d))
}
#[test]
fn from_ordinal_inverts_as_ordinal() {
let cases = [
Surreal::from_int(0),
Surreal::from_int(5),
Surreal::omega(), Surreal::omega().add(&Surreal::from_int(1)), Surreal::monomial(Surreal::from_int(1), Rational::from_int(3)), Surreal::omega_pow(Surreal::from_int(2)), Surreal::omega_pow(Surreal::omega()), ];
for s in &cases {
let o = s.as_ordinal().expect("ordinal-valued");
assert_eq!(
&Surreal::from_ordinal(&o).expect("representable coefficients"),
s,
"from_ordinal∘as_ordinal ≠ id: {s:?}"
);
}
}
#[test]
fn sign_expansion_from_runs_normalizes() {
let se = SignExpansion::from_runs(vec![
(true, Ordinal::from_u128(1)),
(true, Ordinal::zero()),
(true, Ordinal::from_u128(2)),
(false, Ordinal::from_u128(1)),
]);
assert_eq!(
se.runs(),
&[
(true, Ordinal::from_u128(3)),
(false, Ordinal::from_u128(1))
]
);
assert_eq!(se.as_finite(), Some(vec![true, true, true, false]));
}
#[test]
fn from_ordinal_rejects_coefficient_exceeding_i128() {
let large_coeff: u128 = (1u128 << 127) + 1;
let ord = Ordinal::monomial(Ordinal::from_u128(1), large_coeff);
assert_eq!(Surreal::from_ordinal(&ord), None);
}
#[test]
fn transfinite_sign_expansion_round_trips() {
let cases = [
Surreal::zero(),
Surreal::from_int(1),
Surreal::from_int(-1),
Surreal::from_int(2),
rat(1, 2),
rat(1, 2).neg(),
rat(3, 4),
rat(3, 4).neg(),
Surreal::omega(), Surreal::omega().add(&Surreal::from_int(1)), Surreal::monomial(Surreal::from_int(1), Rational::from_int(3)), Surreal::omega_pow(Surreal::from_int(2)), Surreal::omega_pow(Surreal::omega()), Surreal::omega().neg(), Surreal::epsilon(), ];
for s in &cases {
let se = s.transfinite_sign_expansion().expect("representable");
assert_eq!(
Surreal::from_transfinite_sign_expansion(&se).as_ref(),
Some(s),
"sign-expansion round trip failed: {s:?}"
);
assert_eq!(
se.length(),
s.birthday_ordinal().unwrap(),
"length ≠ birthday: {s:?}"
);
}
}
}