From 01c273fcc7b61e575fe18440bd1345cdd8955f03 Mon Sep 17 00:00:00 2001 From: amatgil Date: Thu, 26 Jun 2025 03:24:45 +0200 Subject: [PATCH 1/3] Start implementing rationals (backed by num::BigRational) --- Cargo.lock | 26 ++++ Cargo.toml | 1 + src/array.rs | 69 +++++++++ src/grid_fmt.rs | 14 ++ src/lib.rs | 1 + src/rational.rs | 403 ++++++++++++++++++++++++++++++++++++++++++++++++ src/value.rs | 2 + 7 files changed, 516 insertions(+) create mode 100644 src/rational.rs diff --git a/Cargo.lock b/Cargo.lock index 7c82719ae..8a63b672d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4022,6 +4022,20 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -4068,6 +4082,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -6542,6 +6567,7 @@ dependencies = [ "native-dialog", "nokhwa", "notify", + "num", "num-complex", "num_cpus", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 2fe7b2729..2d30ce601 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,7 @@ web-sys = {version = "0.3.60", optional = true} eframe = {version = "0.29.1", optional = true, features = ["persistence"]} native-dialog = {version = "0.7.0", optional = true} rmp-serde = {version = "1.3.0", optional = true} +num = "0.4.3" [features] apng = ["dep:png"] diff --git a/src/array.rs b/src/array.rs index d1971682b..2ececd970 100644 --- a/src/array.rs +++ b/src/array.rs @@ -9,6 +9,7 @@ use std::{ use bitflags::bitflags; use ecow::{EcoString, EcoVec}; +use num::BigRational; use rayon::prelude::*; use serde::{de::DeserializeOwned, *}; @@ -1172,6 +1173,26 @@ impl ArrayValue for Complex { } } +impl ArrayValue for BigRational { + const NAME: &'static str = "rational"; + const SYMBOL: char = 'ℚ'; + const TYPE_ID: u8 = 4; + fn get_scalar_fill(fill: &Fill) -> Result, &'static str> { + fill.complex_scalar() + } + fn get_array_fill(fill: &Fill) -> Result>, &'static str> { + fill.complex_array() + } + fn array_hash(&self, hasher: &mut H) { + for n in [self.re, self.im] { + n.array_hash(hasher); + } + } + fn proxy() -> Self { + Complex::new(0.0, 0.0) + } +} + /// Trait for [`ArrayValue`]s that are real numbers pub trait RealArrayValue: ArrayValue + Copy { /// Whether the value is an integer @@ -1198,6 +1219,28 @@ impl RealArrayValue for u8 { } } +impl RealArrayValue for BigRational { + fn is_int(&self) -> bool { + self.denom.len() == 1 && self.denom[0] == 1 + } + + fn to_f64(&self) -> f64 { + let num = self + .numer + .iter() + .enumerate() + .map(|(i, n)| n as f64 * u8::MAX.pow(i) as f64) + .sum(); + let den = self + .denom + .iter() + .enumerate() + .map(|(i, n)| n as f64 * u8::MAX.pow(i) as f64) + .sum(); + num / den + } +} + /// Trait for comparing array elements pub trait ArrayCmp { /// Compare two elements @@ -1254,6 +1297,12 @@ impl ArrayCmp for Boxed { } } +impl ArrayCmp for BigRational { + fn array_cmp(&self, other: &Self) -> Ordering { + todo!() + } +} + impl ArrayCmp for u8 { fn array_cmp(&self, other: &f64) -> Ordering { (*self as f64).array_cmp(other) @@ -1447,6 +1496,26 @@ impl ArrayValueSer for f64 { } } +#[derive(Debug, Clone, Serialize, Deserialize)] +enum BigRatCollection { + #[serde(rename = "empty_rat")] + Empty([BigRational; 0]), + #[serde(untagged)] + List(CowSlice), +} + +impl ArrayValueSer for BigRational { + type Scalar = BigRational; + type Collection = BigRatCollection; + fn make_collection(data: CowSlice) -> Self::Collection { + data.iter().map(|&n| n.into()).collect() + } + + fn make_data(collection: Self::Collection) -> CowSlice { + collection.into_iter().map(f64::from).collect() + } +} + impl ArrayValueSer for char { type Scalar = char; type Collection = String; diff --git a/src/grid_fmt.rs b/src/grid_fmt.rs index 6c2a6b211..de352c3be 100644 --- a/src/grid_fmt.rs +++ b/src/grid_fmt.rs @@ -8,6 +8,7 @@ use std::{ }; use ecow::EcoString; +use num::BigRational; use crate::{ algorithm::map::{EMPTY_CHAR, EMPTY_NAN, TOMBSTONE_CHAR, TOMBSTONE_NAN}, @@ -392,6 +393,18 @@ impl GridFmt for Complex { } } +impl GridFmt for BigRational { + fn fmt_grid(&self, params: GridFmtParams) -> Grid { + todo!() + } + fn empty_list_inner() -> &'static str { + todo!() + } + fn summarize(elems: &[Self]) -> String { + todo!() + } +} + impl GridFmt for Value { fn fmt_grid(&self, params: GridFmtParams) -> Grid { if params.depth > 100 { @@ -402,6 +415,7 @@ impl GridFmt for Value { Value::Byte(b) => b.fmt_grid(params), Value::Complex(c) => c.fmt_grid(params), Value::Char(c) => c.fmt_grid(params), + Value::Rational(r) => r.fmt_grid(params), Value::Box(v) => { let max_boxed_rank = v.data.iter().map(|Boxed(v)| v.rank()).max().unwrap_or(0); v.fmt_grid(GridFmtParams { diff --git a/src/lib.rs b/src/lib.rs index 461672214..48531999d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,6 +161,7 @@ mod impl_prim; pub mod lsp; #[doc(hidden)] pub mod profile; +mod rational; mod run; mod run_prim; mod shape; diff --git a/src/rational.rs b/src/rational.rs new file mode 100644 index 000000000..2a3a1e5fe --- /dev/null +++ b/src/rational.rs @@ -0,0 +1,403 @@ +//! The [`Rational`] type's details + +use num::BigRational; + +/* +impl Rational { + /// The rational number 0 + pub const ZERO: Self = Self { + is_positive: true, + numer: vec![0], + denom: vec![1], + }; + /// The complex number 1 + pub const ONE: Self = Self { + is_positive: true, + numer: vec![1], + denom: vec![1], + }; + /// Get the minimum following standard Total Order + pub fn min(self, rhs: impl Into) -> Self { + let rhs = rhs.into(); + Self { + re: self.re.min(rhs.re), + im: self.im.min(rhs.im), + } + } + /// Get the maximum of the real and imaginary parts of two complex numbers, ignoring NaN + pub fn max(self, rhs: impl Into) -> Self { + let rhs = rhs.into(); + Self { + re: self.re.max(rhs.re), + im: self.im.max(rhs.im), + } + } + /// Get the floor of the real and imaginary parts of a complex number + pub fn floor(self) -> Self { + Self { + re: self.re.floor(), + im: self.im.floor(), + } + } + /// Get the ceiling of the real and imaginary parts of a complex number + pub fn ceil(self) -> Self { + Self { + re: self.re.ceil(), + im: self.im.ceil(), + } + } + /// Round the real and imaginary parts of a complex number + pub fn round(self) -> Self { + Self { + re: self.re.round(), + im: self.im.round(), + } + } + /// Get the absolute value of a complex number + pub fn abs(self) -> f64 { + // Do not use `self.re.hypot(self.im)` because it is slower, especially on WASM + (self.re * self.re + self.im * self.im).sqrt() + } + /// Get the arctangent of a complex number + pub fn atan2(self, x: impl Into) -> Complex { + let y = self; + let x = x.into(); + -Complex::I * ((x + Complex::I * y) / (y * y + x * x).sqrt()).ln() + } + /// Normalize a complex number + pub fn normalize(self) -> Self { + let len = self.abs(); + if len == 0.0 { + Self::ZERO + } else { + self / len + } + } + /// Calculate the principal value of the complex number + pub fn arg(self) -> f64 { + self.im.atan2(self.re) + } + /// Convert a complex number to polar coordinates + pub fn to_polar(self) -> (f64, f64) { + (self.abs(), self.arg()) + } + /// Convert polar coordinates to a complex number + pub fn from_polar(r: f64, theta: f64) -> Self { + r * Self::new(theta.cos(), theta.sin()) + } + /// Raise a complex number to a complex power + pub fn powc(self, power: impl Into) -> Self { + let power = power.into(); + if power.im == 0.0 { + return self.powf(power.re); + } + let (r, theta) = self.to_polar(); + ((r.ln() + Self::I * theta) * power).exp() + } + /// Raise a complex number to a real power + pub fn powf(self, power: f64) -> Self { + if power == 0.0 { + return Self::ONE; + } + if power.fract() == 0.0 && self.im == 0.0 { + return self.re.powf(power).into(); + } + let (r, theta) = self.to_polar(); + Self::from_polar(r.powf(power), theta * power) + } + /// Calculate the exponential of a complex number + pub fn exp(self) -> Self { + Self::from_polar(E.powf(self.re), self.im) + } + /// Calculate the natural logarithm of a complex number + pub fn ln(self) -> Self { + let (r, theta) = self.to_polar(); + Self::new(r.ln(), theta) + } + /// Calculate the logarithm of a complex number + pub fn log(self, base: impl Into) -> Self { + let base = base.into(); + Self::new(self.abs().ln(), self.arg()) / (Self::new(base.abs().ln(), base.arg())) + } + /// Calculate the square root of a complex number + pub fn sqrt(self) -> Self { + if self.im == 0.0 { + return if self.re >= 0.0 { + Self::new(self.re.sqrt(), 0.0) + } else { + Self::new(0.0, self.re.abs().sqrt()) + }; + } + let (r, theta) = self.to_polar(); + Self::from_polar(r.sqrt(), theta / 2.0) + } + /// Calculate the sine of a complex number + pub fn sin(self) -> Self { + Self::new( + self.re.sin() * self.im.cosh(), + self.re.cos() * self.im.sinh(), + ) + } + /// Calculate the cosine of a complex number + pub fn cos(self) -> Self { + Self::new( + self.re.cos() * self.im.cosh(), + -self.re.sin() * self.im.sinh(), + ) + } + /// Calculate the arc sine of a complex number + pub fn asin(self) -> Self { + -Self::I * ((Self::ONE - self * self).sqrt() + Self::I * self).ln() + } + /// Calculate the arc cosine of a complex number + pub fn acos(self) -> Self { + -Self::I * (Self::I * (Self::ONE - self * self).sqrt() + self).ln() + } + /// Check if either real or imaginary part is NaN + pub fn is_nan(&self) -> bool { + self.re.is_nan() || self.im.is_nan() + } + /// Get the complex number as a real number + pub fn into_real(self) -> Option { + if self.im.abs() < f64::EPSILON { + Some(self.re) + } else { + None + } + } + /// Multiply by another complex number, with 0 × ∞ = 0 + pub fn safe_mul(self, rhs: impl Into) -> Self { + let rhs = rhs.into(); + Self { + re: safe_mul(self.re, rhs.re) - safe_mul(self.im, rhs.im), + im: safe_mul(self.re, rhs.im) + safe_mul(self.im, rhs.re), + } + } +} + +fn safe_mul(a: f64, b: f64) -> f64 { + if a.is_infinite() && b == 0.0 || a == 0.0 && b.is_infinite() { + 0.0 + } else { + a * b + } +} + +impl From for Complex { + fn from(re: f64) -> Self { + Self { re, im: 0.0 } + } +} + +impl From for Complex { + fn from(value: u8) -> Self { + f64::from(value).into() + } +} + +impl fmt::Display for Complex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.im == 0.0 { + self.re.fmt(f) + } else { + write!(f, "{}r{}i", self.re, self.im) + } + } +} + +impl Add for Complex { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self { + re: self.re + rhs.re, + im: self.im + rhs.im, + } + } +} + +impl Add for Complex { + type Output = Self; + fn add(self, rhs: f64) -> Self::Output { + Self { + re: self.re + rhs, + im: self.im, + } + } +} + +impl Add for f64 { + type Output = Complex; + fn add(self, rhs: Complex) -> Self::Output { + Complex { + re: self + rhs.re, + im: rhs.im, + } + } +} + +impl Sub for Complex { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + Self { + re: self.re - rhs.re, + im: self.im - rhs.im, + } + } +} + +impl Sub for Complex { + type Output = Self; + fn sub(self, rhs: f64) -> Self::Output { + Self { + re: self.re - rhs, + im: self.im, + } + } +} + +impl Sub for f64 { + type Output = Complex; + fn sub(self, rhs: Complex) -> Self::Output { + Complex { + re: self - rhs.re, + im: -rhs.im, + } + } +} + +impl Mul for Complex { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + Self { + re: self.re * rhs.re - self.im * rhs.im, + im: self.re * rhs.im + self.im * rhs.re, + } + } +} + +impl Mul for Complex { + type Output = Self; + fn mul(self, rhs: f64) -> Self::Output { + Self { + re: self.re * rhs, + im: self.im * rhs, + } + } +} + +impl Mul for f64 { + type Output = Complex; + fn mul(self, rhs: Complex) -> Self::Output { + Complex { + re: self * rhs.re, + im: self * rhs.im, + } + } +} + +impl Div for Complex { + type Output = Self; + fn div(self, rhs: Self) -> Self::Output { + let denom = rhs.re * rhs.re + rhs.im * rhs.im; + Self { + re: (self.re * rhs.re + self.im * rhs.im) / denom, + im: (self.im * rhs.re - self.re * rhs.im) / denom, + } + } +} + +impl Div for Complex { + type Output = Self; + fn div(self, rhs: f64) -> Self::Output { + Self { + re: self.re / rhs, + im: self.im / rhs, + } + } +} + +impl Div for f64 { + type Output = Complex; + fn div(self, rhs: Complex) -> Self::Output { + let denom = rhs.re * rhs.re + rhs.im * rhs.im; + Complex { + re: self * rhs.re / denom, + im: -self * rhs.im / denom, + } + } +} + +impl Rem for Complex { + type Output = Self; + fn rem(self, rhs: Self) -> Self::Output { + self - (self / rhs).floor() * rhs + } +} + +impl Rem for Complex { + type Output = Self; + fn rem(self, rhs: f64) -> Self::Output { + Self { + re: self.re.rem_euclid(rhs), + im: self.im.rem_euclid(rhs), + } + } +} + +impl Rem for f64 { + type Output = Complex; + fn rem(self, rhs: Complex) -> Self::Output { + Complex { + re: self % rhs.re, + im: self % rhs.im, + } + } +} + +impl Neg for Complex { + type Output = Self; + fn neg(self) -> Self::Output { + Self { + re: -self.re, + im: -self.im, + } + } +} + +impl AddAssign for Complex +where + Complex: Add, +{ + fn add_assign(&mut self, rhs: T) { + *self = *self + rhs; + } +} + +impl SubAssign for Complex +where + Complex: Sub, +{ + fn sub_assign(&mut self, rhs: T) { + *self = *self - rhs; + } +} + +impl MulAssign for Complex +where + Complex: Mul, +{ + fn mul_assign(&mut self, rhs: T) { + *self = *self * rhs; + } +} + +impl DivAssign for Complex +where + Complex: Div, +{ + fn div_assign(&mut self, rhs: T) { + *self = *self / rhs; + } +} + +*/ diff --git a/src/value.rs b/src/value.rs index 75c24f8d3..8c821d7b5 100644 --- a/src/value.rs +++ b/src/value.rs @@ -34,6 +34,8 @@ pub enum Value { Complex(Array), /// Common character array Char(Array), + /// Common big rational array + Rational(Array), /// Common box array Box(Array), } From 47d1180e6eb9f4705a96a5987992db6852a7e732 Mon Sep 17 00:00:00 2001 From: amatgil Date: Thu, 26 Jun 2025 03:44:55 +0200 Subject: [PATCH 2/3] Much traiting --- src/array.rs | 50 ++---- src/grid_fmt.rs | 4 +- src/rational.rs | 409 +++--------------------------------------------- src/value.rs | 8 +- 4 files changed, 42 insertions(+), 429 deletions(-) diff --git a/src/array.rs b/src/array.rs index 2ececd970..edf1ed325 100644 --- a/src/array.rs +++ b/src/array.rs @@ -9,7 +9,6 @@ use std::{ use bitflags::bitflags; use ecow::{EcoString, EcoVec}; -use num::BigRational; use rayon::prelude::*; use serde::{de::DeserializeOwned, *}; @@ -21,6 +20,7 @@ use crate::{ cowslice::{cowslice, CowSlice}, fill::{Fill, FillValue}, grid_fmt::GridFmt, + rational::Rational, Boxed, Complex, ExactDoubleIterator, HandleKind, Shape, Value, WILDCARD_CHAR, WILDCARD_NAN, }; @@ -1173,23 +1173,21 @@ impl ArrayValue for Complex { } } -impl ArrayValue for BigRational { +impl ArrayValue for Rational { const NAME: &'static str = "rational"; const SYMBOL: char = 'ℚ'; const TYPE_ID: u8 = 4; fn get_scalar_fill(fill: &Fill) -> Result, &'static str> { - fill.complex_scalar() + todo!() } fn get_array_fill(fill: &Fill) -> Result>, &'static str> { - fill.complex_array() + todo!() } fn array_hash(&self, hasher: &mut H) { - for n in [self.re, self.im] { - n.array_hash(hasher); - } + todo!() } fn proxy() -> Self { - Complex::new(0.0, 0.0) + todo!() } } @@ -1219,28 +1217,6 @@ impl RealArrayValue for u8 { } } -impl RealArrayValue for BigRational { - fn is_int(&self) -> bool { - self.denom.len() == 1 && self.denom[0] == 1 - } - - fn to_f64(&self) -> f64 { - let num = self - .numer - .iter() - .enumerate() - .map(|(i, n)| n as f64 * u8::MAX.pow(i) as f64) - .sum(); - let den = self - .denom - .iter() - .enumerate() - .map(|(i, n)| n as f64 * u8::MAX.pow(i) as f64) - .sum(); - num / den - } -} - /// Trait for comparing array elements pub trait ArrayCmp { /// Compare two elements @@ -1297,7 +1273,7 @@ impl ArrayCmp for Boxed { } } -impl ArrayCmp for BigRational { +impl ArrayCmp for Rational { fn array_cmp(&self, other: &Self) -> Ordering { todo!() } @@ -1499,20 +1475,20 @@ impl ArrayValueSer for f64 { #[derive(Debug, Clone, Serialize, Deserialize)] enum BigRatCollection { #[serde(rename = "empty_rat")] - Empty([BigRational; 0]), + Empty([Rational; 0]), #[serde(untagged)] - List(CowSlice), + List(CowSlice), } -impl ArrayValueSer for BigRational { - type Scalar = BigRational; +impl ArrayValueSer for Rational { + type Scalar = Rational; type Collection = BigRatCollection; fn make_collection(data: CowSlice) -> Self::Collection { - data.iter().map(|&n| n.into()).collect() + todo!() } fn make_data(collection: Self::Collection) -> CowSlice { - collection.into_iter().map(f64::from).collect() + todo!() } } diff --git a/src/grid_fmt.rs b/src/grid_fmt.rs index de352c3be..67d049a1e 100644 --- a/src/grid_fmt.rs +++ b/src/grid_fmt.rs @@ -8,12 +8,12 @@ use std::{ }; use ecow::EcoString; -use num::BigRational; use crate::{ algorithm::map::{EMPTY_CHAR, EMPTY_NAN, TOMBSTONE_CHAR, TOMBSTONE_NAN}, array::{Array, ArrayValue}, boxed::Boxed, + rational::Rational, terminal_size, val_as_arr, value::Value, Complex, Primitive, WILDCARD_CHAR, WILDCARD_NAN, @@ -393,7 +393,7 @@ impl GridFmt for Complex { } } -impl GridFmt for BigRational { +impl GridFmt for Rational { fn fmt_grid(&self, params: GridFmtParams) -> Grid { todo!() } diff --git a/src/rational.rs b/src/rational.rs index 2a3a1e5fe..51f887af8 100644 --- a/src/rational.rs +++ b/src/rational.rs @@ -1,403 +1,34 @@ //! The [`Rational`] type's details -use num::BigRational; - -/* -impl Rational { - /// The rational number 0 - pub const ZERO: Self = Self { - is_positive: true, - numer: vec![0], - denom: vec![1], - }; - /// The complex number 1 - pub const ONE: Self = Self { - is_positive: true, - numer: vec![1], - denom: vec![1], - }; - /// Get the minimum following standard Total Order - pub fn min(self, rhs: impl Into) -> Self { - let rhs = rhs.into(); - Self { - re: self.re.min(rhs.re), - im: self.im.min(rhs.im), - } - } - /// Get the maximum of the real and imaginary parts of two complex numbers, ignoring NaN - pub fn max(self, rhs: impl Into) -> Self { - let rhs = rhs.into(); - Self { - re: self.re.max(rhs.re), - im: self.im.max(rhs.im), - } - } - /// Get the floor of the real and imaginary parts of a complex number - pub fn floor(self) -> Self { - Self { - re: self.re.floor(), - im: self.im.floor(), - } - } - /// Get the ceiling of the real and imaginary parts of a complex number - pub fn ceil(self) -> Self { - Self { - re: self.re.ceil(), - im: self.im.ceil(), - } - } - /// Round the real and imaginary parts of a complex number - pub fn round(self) -> Self { - Self { - re: self.re.round(), - im: self.im.round(), - } - } - /// Get the absolute value of a complex number - pub fn abs(self) -> f64 { - // Do not use `self.re.hypot(self.im)` because it is slower, especially on WASM - (self.re * self.re + self.im * self.im).sqrt() - } - /// Get the arctangent of a complex number - pub fn atan2(self, x: impl Into) -> Complex { - let y = self; - let x = x.into(); - -Complex::I * ((x + Complex::I * y) / (y * y + x * x).sqrt()).ln() - } - /// Normalize a complex number - pub fn normalize(self) -> Self { - let len = self.abs(); - if len == 0.0 { - Self::ZERO - } else { - self / len - } - } - /// Calculate the principal value of the complex number - pub fn arg(self) -> f64 { - self.im.atan2(self.re) - } - /// Convert a complex number to polar coordinates - pub fn to_polar(self) -> (f64, f64) { - (self.abs(), self.arg()) - } - /// Convert polar coordinates to a complex number - pub fn from_polar(r: f64, theta: f64) -> Self { - r * Self::new(theta.cos(), theta.sin()) - } - /// Raise a complex number to a complex power - pub fn powc(self, power: impl Into) -> Self { - let power = power.into(); - if power.im == 0.0 { - return self.powf(power.re); - } - let (r, theta) = self.to_polar(); - ((r.ln() + Self::I * theta) * power).exp() - } - /// Raise a complex number to a real power - pub fn powf(self, power: f64) -> Self { - if power == 0.0 { - return Self::ONE; - } - if power.fract() == 0.0 && self.im == 0.0 { - return self.re.powf(power).into(); - } - let (r, theta) = self.to_polar(); - Self::from_polar(r.powf(power), theta * power) - } - /// Calculate the exponential of a complex number - pub fn exp(self) -> Self { - Self::from_polar(E.powf(self.re), self.im) - } - /// Calculate the natural logarithm of a complex number - pub fn ln(self) -> Self { - let (r, theta) = self.to_polar(); - Self::new(r.ln(), theta) - } - /// Calculate the logarithm of a complex number - pub fn log(self, base: impl Into) -> Self { - let base = base.into(); - Self::new(self.abs().ln(), self.arg()) / (Self::new(base.abs().ln(), base.arg())) - } - /// Calculate the square root of a complex number - pub fn sqrt(self) -> Self { - if self.im == 0.0 { - return if self.re >= 0.0 { - Self::new(self.re.sqrt(), 0.0) - } else { - Self::new(0.0, self.re.abs().sqrt()) - }; - } - let (r, theta) = self.to_polar(); - Self::from_polar(r.sqrt(), theta / 2.0) - } - /// Calculate the sine of a complex number - pub fn sin(self) -> Self { - Self::new( - self.re.sin() * self.im.cosh(), - self.re.cos() * self.im.sinh(), - ) - } - /// Calculate the cosine of a complex number - pub fn cos(self) -> Self { - Self::new( - self.re.cos() * self.im.cosh(), - -self.re.sin() * self.im.sinh(), - ) - } - /// Calculate the arc sine of a complex number - pub fn asin(self) -> Self { - -Self::I * ((Self::ONE - self * self).sqrt() + Self::I * self).ln() - } - /// Calculate the arc cosine of a complex number - pub fn acos(self) -> Self { - -Self::I * (Self::I * (Self::ONE - self * self).sqrt() + self).ln() - } - /// Check if either real or imaginary part is NaN - pub fn is_nan(&self) -> bool { - self.re.is_nan() || self.im.is_nan() - } - /// Get the complex number as a real number - pub fn into_real(self) -> Option { - if self.im.abs() < f64::EPSILON { - Some(self.re) - } else { - None - } - } - /// Multiply by another complex number, with 0 × ∞ = 0 - pub fn safe_mul(self, rhs: impl Into) -> Self { - let rhs = rhs.into(); - Self { - re: safe_mul(self.re, rhs.re) - safe_mul(self.im, rhs.im), - im: safe_mul(self.re, rhs.im) + safe_mul(self.im, rhs.re), - } - } -} - -fn safe_mul(a: f64, b: f64) -> f64 { - if a.is_infinite() && b == 0.0 || a == 0.0 && b.is_infinite() { - 0.0 - } else { - a * b - } -} - -impl From for Complex { - fn from(re: f64) -> Self { - Self { re, im: 0.0 } - } -} - -impl From for Complex { - fn from(value: u8) -> Self { - f64::from(value).into() - } -} - -impl fmt::Display for Complex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.im == 0.0 { - self.re.fmt(f) - } else { - write!(f, "{}r{}i", self.re, self.im) - } - } -} - -impl Add for Complex { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - Self { - re: self.re + rhs.re, - im: self.im + rhs.im, - } - } -} - -impl Add for Complex { - type Output = Self; - fn add(self, rhs: f64) -> Self::Output { - Self { - re: self.re + rhs, - im: self.im, - } - } -} +use std::fmt::Display; -impl Add for f64 { - type Output = Complex; - fn add(self, rhs: Complex) -> Self::Output { - Complex { - re: self + rhs.re, - im: rhs.im, - } - } -} - -impl Sub for Complex { - type Output = Self; - fn sub(self, rhs: Self) -> Self::Output { - Self { - re: self.re - rhs.re, - im: self.im - rhs.im, - } - } -} - -impl Sub for Complex { - type Output = Self; - fn sub(self, rhs: f64) -> Self::Output { - Self { - re: self.re - rhs, - im: self.im, - } - } -} - -impl Sub for f64 { - type Output = Complex; - fn sub(self, rhs: Complex) -> Self::Output { - Complex { - re: self - rhs.re, - im: -rhs.im, - } - } -} - -impl Mul for Complex { - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - Self { - re: self.re * rhs.re - self.im * rhs.im, - im: self.re * rhs.im + self.im * rhs.re, - } - } -} - -impl Mul for Complex { - type Output = Self; - fn mul(self, rhs: f64) -> Self::Output { - Self { - re: self.re * rhs, - im: self.im * rhs, - } - } -} - -impl Mul for f64 { - type Output = Complex; - fn mul(self, rhs: Complex) -> Self::Output { - Complex { - re: self * rhs.re, - im: self * rhs.im, - } - } -} - -impl Div for Complex { - type Output = Self; - fn div(self, rhs: Self) -> Self::Output { - let denom = rhs.re * rhs.re + rhs.im * rhs.im; - Self { - re: (self.re * rhs.re + self.im * rhs.im) / denom, - im: (self.im * rhs.re - self.re * rhs.im) / denom, - } - } -} - -impl Div for Complex { - type Output = Self; - fn div(self, rhs: f64) -> Self::Output { - Self { - re: self.re / rhs, - im: self.im / rhs, - } - } -} - -impl Div for f64 { - type Output = Complex; - fn div(self, rhs: Complex) -> Self::Output { - let denom = rhs.re * rhs.re + rhs.im * rhs.im; - Complex { - re: self * rhs.re / denom, - im: -self * rhs.im / denom, - } - } -} - -impl Rem for Complex { - type Output = Self; - fn rem(self, rhs: Self) -> Self::Output { - self - (self / rhs).floor() * rhs - } -} - -impl Rem for Complex { - type Output = Self; - fn rem(self, rhs: f64) -> Self::Output { - Self { - re: self.re.rem_euclid(rhs), - im: self.im.rem_euclid(rhs), - } - } -} +use num::BigRational; -impl Rem for f64 { - type Output = Complex; - fn rem(self, rhs: Complex) -> Self::Output { - Complex { - re: self % rhs.re, - im: self % rhs.im, - } - } -} +#[derive(Debug, Clone, Default)] +pub struct Rational(BigRational); -impl Neg for Complex { - type Output = Self; - fn neg(self) -> Self::Output { - Self { - re: -self.re, - im: -self.im, - } - } -} +use serde::{Deserialize, Deserializer, Serialize, Serializer}; -impl AddAssign for Complex -where - Complex: Add, -{ - fn add_assign(&mut self, rhs: T) { - *self = *self + rhs; +impl<'de> Deserialize<'de> for Rational { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + todo!() } } -impl SubAssign for Complex -where - Complex: Sub, -{ - fn sub_assign(&mut self, rhs: T) { - *self = *self - rhs; +impl Serialize for Rational { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + todo!() } } -impl MulAssign for Complex -where - Complex: Mul, -{ - fn mul_assign(&mut self, rhs: T) { - *self = *self * rhs; +impl Display for Rational { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() } } - -impl DivAssign for Complex -where - Complex: Div, -{ - fn div_assign(&mut self, rhs: T) { - *self = *self / rhs; - } -} - -*/ diff --git a/src/value.rs b/src/value.rs index 8c821d7b5..409fec14d 100644 --- a/src/value.rs +++ b/src/value.rs @@ -16,6 +16,7 @@ use crate::{ array::*, cowslice::CowSlice, grid_fmt::GridFmt, + rational::Rational, Boxed, Complex, Shape, Uiua, UiuaResult, }; @@ -35,7 +36,7 @@ pub enum Value { /// Common character array Char(Array), /// Common big rational array - Rational(Array), + Rational(Array), /// Common box array Box(Array), } @@ -66,6 +67,7 @@ macro_rules! val_as_arr { Value::Byte($arr) => $body, Value::Complex($arr) => $body, Value::Char($arr) => $body, + Value::Rational($arr) => $body, Value::Box($arr) => $body, } }; @@ -75,6 +77,7 @@ macro_rules! val_as_arr { Value::Byte(arr) => $f(arr), Value::Complex(arr) => $f(arr), Value::Char(arr) => $f(arr), + Value::Rational(arr) => $f(arr), Value::Box(arr) => $f(arr), } }; @@ -84,6 +87,7 @@ macro_rules! val_as_arr { Value::Byte(arr) => $f(arr, $env), Value::Complex(arr) => $f(arr, $env), Value::Char(arr) => $f(arr, $env), + Value::Rational(arr) => $f(arr, $env), Value::Box(arr) => $f(arr, $env), } }; @@ -105,6 +109,7 @@ impl Value { Self::Byte(_) => u8::TYPE_ID, Self::Complex(_) => Complex::TYPE_ID, Self::Char(_) => char::TYPE_ID, + Self::Rational(_) => Rational::TYPE_ID, Self::Box(_) => Boxed::TYPE_ID, } } @@ -1647,6 +1652,7 @@ value_from!(u8, Byte); value_from!(char, Char); value_from!(Boxed, Box); value_from!(Complex, Complex); +value_from!(Rational, Rational); impl FromIterator for Value { fn from_iter>(iter: I) -> Self { From 52ce486428378055a3db6ac97648f867630d378c Mon Sep 17 00:00:00 2001 From: amatgil Date: Thu, 26 Jun 2025 04:00:17 +0200 Subject: [PATCH 3/3] Compiler errors have become TODOs --- src/algorithm/dyadic/combine.rs | 7 +++++++ src/algorithm/dyadic/mod.rs | 6 ++++++ src/algorithm/dyadic/structure.rs | 2 ++ src/algorithm/encode.rs | 2 ++ src/algorithm/map.rs | 7 +++++++ src/algorithm/mod.rs | 2 ++ src/algorithm/monadic/mod.rs | 4 ++++ src/algorithm/tuples.rs | 1 + src/fill.rs | 2 ++ src/grid_fmt.rs | 3 +++ src/types.rs | 1 + src/value.rs | 11 +++++++++++ 12 files changed, 48 insertions(+) diff --git a/src/algorithm/dyadic/combine.rs b/src/algorithm/dyadic/combine.rs index bbe808262..917e2f010 100644 --- a/src/algorithm/dyadic/combine.rs +++ b/src/algorithm/dyadic/combine.rs @@ -1128,6 +1128,9 @@ impl Value { Value::Char(arr) } } + Value::Rational(_) => { + todo!() + } Value::Box(_) => { row_values = values.into_iter(); row_values.next().unwrap() @@ -1175,6 +1178,7 @@ impl Value { )))) } }, + Value::Rational(_) => todo!(), Value::Box(arr) => match ctx.scalar_fill::() { Ok(fill) => arr.fill_to_shape(&max_shape, fill), Err(e) => { @@ -1243,6 +1247,9 @@ impl Value { } a.into() } + Value::Rational(_) => { + todo!() + } Value::Box(mut a) => { for val in row_values { match val { diff --git a/src/algorithm/dyadic/mod.rs b/src/algorithm/dyadic/mod.rs index 5587b8a4c..62fb38c43 100644 --- a/src/algorithm/dyadic/mod.rs +++ b/src/algorithm/dyadic/mod.rs @@ -530,6 +530,7 @@ impl Value { Value::Byte(a) => a.convert::().keep_scalar_real(counts[0], env)?.into(), Value::Complex(a) => a.keep_scalar_real(counts[0], env)?.into(), Value::Char(a) => a.keep_scalar_real(counts[0], env)?.into(), + Value::Rational(_) => todo!(), Value::Box(a) => a.keep_scalar_real(counts[0], env)?.into(), } } else { @@ -551,6 +552,7 @@ impl Value { Value::Byte(a) => a.convert::().keep_scalar_real(count, env)?.into(), Value::Complex(a) => a.keep_scalar_real(count, env)?.into(), Value::Char(a) => a.keep_scalar_real(count, env)?.into(), + Value::Rational(_) => todo!(), Value::Box(a) => a.keep_scalar_real(count, env)?.into(), } } else { @@ -1076,6 +1078,7 @@ impl Value { rot.rotate_depth(val, 0, forward, env)?; } } + Value::Rational(_) => todo!(), Value::Box(a) => a.rotate_depth(by_ints()?, depth, forward, env)?, } rotated.meta.take_sorted_flags(); @@ -2155,6 +2158,7 @@ impl Value { let whole = Array::new(arr.shape.clone(), arr.data); (frac.into(), whole.into()) } + Value::Rational(_) => todo!(), Value::Box(arr) => { let mut whole_data = EcoVec::with_capacity(arr.element_count()); let mut frac_data = EcoVec::with_capacity(arr.element_count()); @@ -2215,6 +2219,8 @@ impl Value { let abs = Array::new(arr.shape.clone(), abs_data); (arr.into(), abs.into()) } + + Value::Rational(_) => todo!(), Value::Box(arr) => { let mut sign_data = EcoVec::with_capacity(arr.element_count()); let mut mag_data = EcoVec::with_capacity(arr.element_count()); diff --git a/src/algorithm/dyadic/structure.rs b/src/algorithm/dyadic/structure.rs index fc3925a84..c398c40ef 100644 --- a/src/algorithm/dyadic/structure.rs +++ b/src/algorithm/dyadic/structure.rs @@ -140,6 +140,7 @@ impl Value { Value::Byte(a) => Value::Byte(a.pick(index_shape, &index_data, env)?), Value::Complex(a) => Value::Complex(a.pick(index_shape, &index_data, env)?), Value::Char(a) => Value::Char(a.pick(index_shape, &index_data, env)?), + Value::Rational(_) => todo!(), Value::Box(a) => Value::Box(a.pick(index_shape, &index_data, env)?), }) } @@ -1211,6 +1212,7 @@ impl Value { Value::Complex(a.anti_select(indices_shape, &indices_data, env)?) } Value::Char(a) => Value::Char(a.anti_select(indices_shape, &indices_data, env)?), + Value::Rational(_) => todo!(), Value::Box(a) => Value::Box(a.anti_select(indices_shape, &indices_data, env)?), }) } diff --git a/src/algorithm/encode.rs b/src/algorithm/encode.rs index 36e2815f7..810dae988 100644 --- a/src/algorithm/encode.rs +++ b/src/algorithm/encode.rs @@ -220,6 +220,7 @@ impl Value { Value::Byte(b) => sheet_row.add_cell(b.data[0] as f64), Value::Char(c) => sheet_row.add_cell(c.data[0].to_string()), Value::Complex(c) => sheet_row.add_cell(c.data[0].to_string()), + Value::Rational(_) => todo!(), Value::Box(b) => { let Boxed(b) = &b.data[0]; if b.row_count() == 0 { @@ -688,6 +689,7 @@ impl Value { bytes.extend(im.to_le_bytes()); } } + Value::Rational(_) => todo!(), } Ok(()) } diff --git a/src/algorithm/map.rs b/src/algorithm/map.rs index 86cc54593..e85fc3175 100644 --- a/src/algorithm/map.rs +++ b/src/algorithm/map.rs @@ -371,6 +371,7 @@ impl MapKeys { Value::Num(a) => Self::grow_impl(a, &mut self.indices, new_capacity), Value::Complex(a) => Self::grow_impl(a, &mut self.indices, new_capacity), Value::Char(a) => Self::grow_impl(a, &mut self.indices, new_capacity), + Value::Rational(_) => todo!(), Value::Box(a) => Self::grow_impl(a, &mut self.indices, new_capacity), Value::Byte(_) => unreachable!(), } @@ -659,6 +660,7 @@ impl MapKeys { Value::Complex(keys) => set_tombstones(keys, dropped), Value::Char(keys) => set_tombstones(keys, dropped), Value::Box(keys) => set_tombstones(keys, dropped), + Value::Rational(_) => todo!(), Value::Byte(keys) => { let mut nums = keys.convert_ref(); set_tombstones(&mut nums, dropped); @@ -678,6 +680,7 @@ impl MapKeys { Value::Num(keys) => set_tombstones(keys, not_taken), Value::Complex(keys) => set_tombstones(keys, not_taken), Value::Char(keys) => set_tombstones(keys, not_taken), + Value::Rational(_) => todo!(), Value::Box(keys) => set_tombstones(keys, not_taken), Value::Byte(keys) => { let mut nums = keys.convert_ref(); @@ -959,6 +962,7 @@ impl MapItem for Value { Value::Byte(_) => false, Value::Complex(num) => num.data.iter().any(|v| v.is_any_empty_cell()), Value::Char(num) => num.data.iter().any(|v| v.is_any_empty_cell()), + Value::Rational(_) => todo!(), Value::Box(num) => num.data.iter().any(|v| v.is_any_empty_cell()), } } @@ -968,6 +972,7 @@ impl MapItem for Value { Value::Byte(_) => false, Value::Complex(num) => num.data.iter().any(|v| v.is_any_tombstone()), Value::Char(num) => num.data.iter().any(|v| v.is_any_tombstone()), + Value::Rational(_) => todo!(), Value::Box(num) => num.data.iter().any(|v| v.is_any_tombstone()), } } @@ -977,6 +982,7 @@ impl MapItem for Value { Value::Byte(_) => false, Value::Complex(num) => num.data.iter().all(|v| v.is_any_empty_cell()), Value::Char(num) => num.data.iter().all(|v| v.is_any_empty_cell()), + Value::Rational(_) => todo!(), Value::Box(num) => num.data.iter().all(|v| v.is_any_empty_cell()), } } @@ -986,6 +992,7 @@ impl MapItem for Value { Value::Byte(_) => false, Value::Complex(num) => num.data.iter().all(|v| v.is_any_tombstone()), Value::Char(num) => num.data.iter().all(|v| v.is_any_tombstone()), + Value::Rational(_) => todo!(), Value::Box(num) => num.data.iter().all(|v| v.is_any_tombstone()), } } diff --git a/src/algorithm/mod.rs b/src/algorithm/mod.rs index bfdf21249..89d10ca08 100644 --- a/src/algorithm/mod.rs +++ b/src/algorithm/mod.rs @@ -276,6 +276,7 @@ pub trait FillContext: ErrorContext { Value::Byte(_) => self.scalar_fill::().is_ok(), Value::Complex(_) => self.scalar_fill::().is_ok(), Value::Char(_) => self.scalar_fill::().is_ok(), + Value::Rational(_) => todo!(), Value::Box(_) => self.scalar_fill::().is_ok(), } } @@ -363,6 +364,7 @@ where Value::Byte(arr) => fill_array_shape(arr, target, expand_fixed, ctx), Value::Complex(arr) => fill_array_shape(arr, target, expand_fixed, ctx), Value::Char(arr) => fill_array_shape(arr, target, expand_fixed, ctx), + Value::Rational(_) => todo!(), Value::Box(arr) => fill_array_shape(arr, target, expand_fixed, ctx), } } diff --git a/src/algorithm/monadic/mod.rs b/src/algorithm/monadic/mod.rs index d9b6a5cfe..575f7381d 100644 --- a/src/algorithm/monadic/mod.rs +++ b/src/algorithm/monadic/mod.rs @@ -934,6 +934,7 @@ impl Value { Value::Byte(b) => b.transpose_depth(depth, amnt), Value::Complex(c) => c.transpose_depth(depth, amnt), Value::Char(c) => c.transpose_depth(depth, amnt), + Value::Rational(_) => todo!(), Value::Box(b) => { if depth == b.rank() { for b in b.data.as_mut_slice() { @@ -952,6 +953,7 @@ impl Value { Value::Byte(b) => b.retropose_depth(depth), Value::Complex(c) => c.retropose_depth(depth), Value::Char(c) => c.retropose_depth(depth), + Value::Rational(_) => todo!(), Value::Box(b) => { if depth == b.rank() { for b in b.data.as_mut_slice() { @@ -1139,6 +1141,7 @@ impl Value { Value::Byte(arr) => arr.data.iter().all(|&b| b == 1), Value::Char(_) => false, Value::Box(arr) => arr.data.iter().all(|Boxed(val)| val.all_true()), + Value::Rational(_) => todo!(), Value::Complex(arr) => arr.data.iter().all(|&c| c.re == 1.0 && c.im == 1.0), } } @@ -2189,6 +2192,7 @@ impl Value { c => c.grid_string(false), } } + Value::Rational(_) => todo!(), Value::Box(arr) => format!("□{}", arr.data[0].0.representation()), }, 1 => match self { diff --git a/src/algorithm/tuples.rs b/src/algorithm/tuples.rs index 8cd5739c3..1741a0498 100644 --- a/src/algorithm/tuples.rs +++ b/src/algorithm/tuples.rs @@ -296,6 +296,7 @@ fn tuple2(f: SigNode, env: &mut Uiua) -> UiuaResult { Value::Byte(a) => inner(a, k, f, is_scalar, scalar, env)?, Value::Complex(a) => inner(a, k, f, is_scalar, scalar, env)?, Value::Char(a) => inner(a, k, f, is_scalar, scalar, env)?, + Value::Rational(_) => todo!(), Value::Box(a) => inner(a, k, f, is_scalar, scalar, env)?, }; } diff --git a/src/fill.rs b/src/fill.rs index 57bcb2448..7561d6f9b 100644 --- a/src/fill.rs +++ b/src/fill.rs @@ -175,6 +175,7 @@ impl<'a> Fill<'a> { Some(Value::Num(_)) => ". A number fill is set, but it is not a scalar.", Some(Value::Byte(_)) => ". A number fill is set, but it is not a scalar.", Some(Value::Char(_)) => ". A character fill is set, but it is not a scalar.", + Some(Value::Rational(_)) => todo!(), Some(Value::Complex(_)) => ". A complex fill is set, but it is not a scalar.", Some(Value::Box(_)) => ". A box fill is set, but it is not a scalar.", None => { @@ -195,6 +196,7 @@ impl<'a> Fill<'a> { Some(Value::Complex(_)) => { ". A complex fill is set, but the array is not complex numbers." } + Some(Value::Rational(_)) => todo!(), Some(Value::Box(_)) => ". A box fill is set, but the array is not boxed values.", None => { if (self.other_value_fill)(self.env).is_some() { diff --git a/src/grid_fmt.rs b/src/grid_fmt.rs index 67d049a1e..a1816d5f3 100644 --- a/src/grid_fmt.rs +++ b/src/grid_fmt.rs @@ -688,6 +688,7 @@ impl GridFmt for Array { Value::Byte(_) => u8::alignment(), Value::Complex(_) => Complex::alignment(), Value::Char(_) => char::alignment(), + Value::Rational(_) => todo!(), Value::Box(_) => Boxed::alignment(), }); let metagrid = metagrid.get_or_insert_with(Metagrid::new); @@ -704,6 +705,7 @@ impl GridFmt for Array { Value::Byte(_) => shape_row::(&keys_row_shape), Value::Complex(_) => shape_row::(&keys_row_shape), Value::Char(_) => shape_row::(&keys_row_shape), + Value::Rational(_) => todo!(), Value::Box(_) => shape_row::(&keys_row_shape), }; row.extend([' ', '→', ' ']); @@ -1073,6 +1075,7 @@ impl Array { Value::Byte(_) => shape_row::(&keys_shape), Value::Complex(_) => shape_row::(&keys_shape), Value::Char(_) => shape_row::(&keys_shape), + Value::Rational(_) => todo!(), Value::Box(_) => shape_row::(&keys_shape), } .into_iter() diff --git a/src/types.rs b/src/types.rs index 9386bc046..a19c17189 100644 --- a/src/types.rs +++ b/src/types.rs @@ -20,6 +20,7 @@ impl Value { Value::Byte(_) => ScalarType::Real, Value::Complex(_) => ScalarType::Complex, Value::Char(_) => ScalarType::Char, + Value::Rational(_) => todo!(), Value::Box(arr) => ScalarType::Box(if arr.data.is_empty() { None } else if (arr.data.windows(2)).all(|w| w[0].0.row_ty() == w[1].0.row_ty()) { diff --git a/src/value.rs b/src/value.rs index 409fec14d..caa8ebcf5 100644 --- a/src/value.rs +++ b/src/value.rs @@ -206,6 +206,7 @@ impl Value { Self::Byte(_) => "number", Self::Complex(_) => "complex", Self::Char(_) => "character", + Value::Rational(_) => todo!(), Self::Box(_) => "box", } } @@ -216,6 +217,7 @@ impl Value { Self::Byte(_) => "numbers", Self::Complex(_) => "complexes", Self::Char(_) => "characters", + Value::Rational(_) => todo!(), Self::Box(_) => "boxes", } } @@ -243,6 +245,7 @@ impl Value { Self::Char(_) => (env.scalar_fill().map(|fv| fv.value)) .unwrap_or_else(|_| char::proxy()) .into(), + Value::Rational(_) => todo!(), Self::Box(_) => (env.scalar_fill().map(|fv| fv.value)) .unwrap_or_else(|_| Boxed::proxy()) .into(), @@ -295,6 +298,7 @@ impl Value { ), ) .into(), + Value::Rational(_) => todo!(), Self::Box(_) => Array::new( shape, CowSlice::from_elem( @@ -317,6 +321,7 @@ impl Value { .map(|fv| fv.value) .map(Into::into), Value::Char(_) => env.array_fill::().map(|fv| fv.value).map(Into::into), + Value::Rational(_) => todo!(), Value::Box(_) => env.array_fill::().map(|fv| fv.value).map(Into::into), } } @@ -337,6 +342,7 @@ impl Value { Self::Byte(_) => size_of::(), Self::Complex(_) => size_of::(), Self::Char(_) => size_of::(), + Value::Rational(_) => todo!(), Self::Box(_) => size_of::(), } } @@ -463,6 +469,7 @@ impl Value { Self::Byte(array) => b(array), Self::Complex(array) => co(array), Self::Char(array) => ch(array), + Value::Rational(_) => todo!(), Self::Box(array) => { if let Some(Boxed(value)) = array.as_scalar_mut() { value.generic_mut_deep(n, b, co, ch, f) @@ -1483,6 +1490,7 @@ impl Value { Value::Byte(arr) => arr.convert_with(|v| Boxed(Value::from(v))), Value::Complex(arr) => arr.convert_with(|v| Boxed(Value::from(v))), Value::Char(arr) => arr.convert_with(|v| Boxed(Value::from(v))), + Value::Rational(_) => todo!(), Value::Box(arr) => arr, } } @@ -1499,6 +1507,7 @@ impl Value { Value::Byte(arr) => Cow::Owned(arr.convert_ref_with(|v| Boxed(Value::from(v)))), Value::Complex(arr) => Cow::Owned(arr.convert_ref_with(|v| Boxed(Value::from(v)))), Value::Char(arr) => Cow::Owned(arr.convert_ref_with(|v| Boxed(Value::from(v)))), + Value::Rational(_) => todo!(), Value::Box(arr) => Cow::Borrowed(arr), } } @@ -2368,6 +2377,8 @@ impl Ord for Value { (_, Value::Complex(_)) => Ordering::Greater, (Value::Char(_), _) => Ordering::Less, (_, Value::Char(_)) => Ordering::Greater, + (Value::Rational(_), _) => todo!(), + (_, Value::Rational(_)) => todo!(), } } }