//! Exact numeric foundation for analysis; no model, expression, or package resolver. //! //! Values use reduced rational coordinates. All nontrivial arithmetic takes one //! request-local [WorkMeter]. The future evaluator must also charge *expanded* //! expression/call/property/list/target visits and retain the same logical walk on //! cache hits. Stored AST size is not a dynamic execution limit. //! //! Approximate engineering functions/irrational unit scales require a subsequent //! explicit numeric profile; rationals do not implement degree/radian conversion //! or transcendental mathematics. mod dimension; mod exact; mod meter; mod quantity; pub use dimension::{Dimension, DimensionAxis}; pub use exact::{Exact, ExactWire}; pub use meter::{ EvaluationStep, NumericOperation, WorkExhaustion, WorkLimits, WorkMeter, WorkResource, WorkSite, WorkUsage, }; pub use quantity::{NumericType, NumericValue, ResolvedKind, Unit}; use serde::{Deserialize, Serialize}; use thiserror::Error; /// Profile identity includes the accounting rules, not crate-internal timing. pub const WORK_PROFILE: &str = "Q1-logical-work-1"; pub const MAX_COMPONENT_BITS: u64 = 4096; /// Cross products require 8192 bits; their sum can require one additional bit. pub const MAX_INTERMEDIATE_BITS: u64 = 8193; pub const MAX_COMPONENT_DIGITS: usize = 1234; pub const MAX_DECIMAL_EXPONENT: i32 = 128; pub const MAX_INTEGER_POWER: i8 = 16; /// Includes ratio punctuation/whitespace without permitting unbounded scanning. pub const MAX_LITERAL_BYTES: usize = 2 * MAX_COMPONENT_DIGITS + 32; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum NumberComponent { Numerator, Denominator, } #[derive(Debug, Clone, PartialEq, Eq, Error, Serialize, Deserialize)] pub enum NumericLimit { #[error("request work exhausted: {0}")] Work(WorkExhaustion), #[error("{component:?} uses {bits} bits, above the {limit}-bit {stage} limit")] Bits { component: NumberComponent, bits: u64, limit: u64, stage: String, }, } #[derive(Debug, Clone, PartialEq, Eq, Error, Serialize, Deserialize)] pub enum NumericError { #[error("numeric limit: {0}")] Limit(NumericLimit), #[error("invalid numeric literal")] InvalidLiteral, #[error("numeric literal exceeds its digit or byte limit")] LiteralTooLong, #[error("decimal exponent is outside -128 through 128")] DecimalExponent, #[error("wire rational is not in canonical reduced form")] NonCanonicalWire, #[error("rational denominator is zero")] ZeroDenominator, #[error("division by zero")] DivisionByZero, #[error("zero to the power zero is undefined in this profile")] ZeroPowerZero, #[error("integer power is outside -16 through 16")] IntegerPower, #[error("dimension exponent at {axis:?} is outside -32 through 32: {value}")] DimensionExponent { axis: DimensionAxis, value: i32 }, #[error("unit scale must be strictly positive")] UnitScale, #[error("a linear unit must have zero offset")] LinearOffset, #[error("an affine point must have a distinct linear difference kind")] DifferenceKind, #[error("numeric kinds or dimensions are incompatible")] IncompatibleTypes, #[error("operation is not defined for affine points")] AffineOperation, #[error("AsKind requires an anonymous matching dimension and a linear target")] KindAssertion, #[error("request work limits exceed the provisional reference ceilings")] InvalidWorkLimits, } impl NumericError { pub fn is_terminal_work_exhaustion(&self) -> bool { matches!(self, Self::Limit(NumericLimit::Work(_))) } } #[cfg(test)] mod tests;