maths_traits/analysis/
ordered.rs

1//!
2//!Traits for ordered structures
3//!
4
5use crate::algebra::*;
6
7pub use core::cmp::{PartialOrd, Ord};
8
9///
10///A marker trait signifying that for `x > y`, `x+z > x+z` and `z+x > z+x` for all `z`
11///
12///Note that for [monoids](AddMonoid) with some negative or positive element `x` this
13///_automatically_ means that the magma is infinite, as otherwise, there would be a
14///maximum element `M` and minimum `m`, contradicting `M + x > M + 0 = M` (if `x > 0`)
15///or `m + x < m + 0 = m` (if `x < 0`). (Of course, the bitwise representations of these
16///structures size limited by size, but in practice, we treat them as infinite anyway.)
17///
18///Futhermore, for [monoids](AddMonoid) and [groups](AddGroup), this provides a way to embed the
19///[Naturals](Natural) and [Integers](Integer) into the structure respectively, and if the structure also is
20///an ordered semiring with [one](One), then there is even a canonical embedding following both addition
21///and multiplication rules
22///
23pub trait AddOrdered: PartialOrd {}
24
25///
26///A marker trait signifying that for `x > y`, `x*z > x*z` and `z*x > z*x` for all `z > 0`
27///
28///Like for [AddOrdered], for this also implies for non-trivial structures that they are infinite
29///and provides for embeddings of the [Naturals](Natural) and [Integers](Integer) in much the same
30///way.
31///
32pub trait MulOrdered: PartialOrd {}
33
34///Helpful methods for measuring an element's order relative to 0
35pub trait Signed: PartialOrd + Zero {
36    ///If this element is strictly greater than zero
37    fn positive(&self) -> bool;
38    ///If this element is strictly less than zero
39    fn negative(&self) -> bool;
40    ///If this element is greater than or equal to zero
41    fn non_negative(&self) -> bool;
42    ///If this element is less than or equal to zero
43    fn non_positive(&self) -> bool;
44}
45
46///Auto-implemented using `default` to allow for specialization if desired
47impl<G: PartialOrd + Zero> Signed for G {
48    #[inline] default fn positive(&self) -> bool { self > &Self::zero() }
49    #[inline] default fn negative(&self) -> bool { self < &Self::zero() }
50    #[inline] default fn non_negative(&self) -> bool { self >= &Self::zero() }
51    #[inline] default fn non_positive(&self) -> bool { self <= &Self::zero() }
52}
53
54///Helpful methods for manipulating an element's order relative to 0
55pub trait Sign: Signed {
56    ///Returns 1 if positive, -1 if negative, or itself (ie. 0 or NaN) if neither
57    fn signum(self) -> Self;
58    ///Returns this element's negative if less than 0 or itself otherwise
59    fn abs(self) -> Self;
60}
61
62///
63///The property that if `x < y`, there exists some natural `n` where `n*x = x*...*x > y`
64///
65///This is often interpreted as the structure having no "infinite" elements, since any element
66///can be reached from any other non-zero element (even the smallest of elements) through _only_
67///repeated addition.
68///
69///Now, it is worth noting that in practice, implementing structs _might_ still have some form
70///of infinite elements, so long as they aren't "distinguished" in some way. In particular,
71///IEEE floating points have INF, -INF, and NaN as standard values, all of which violate this property
72///however, in order to simplify the API and still have [f32] and [f64] be considered [reals](crate::analysis::Real),
73///these values are interpreted as errors. Of course, in general, new structs implementing this trait
74///should avoid this if possible.
75///
76pub trait ArchimedeanProperty: AddOrdered + AddAssociative {}
77
78///
79///Division with remainder using an ordering and the Archimedean Property
80///
81///In a sense, this is extremely similar to [Euclidean division](EuclideanDiv) and in certain
82///contexts (like the [Integers](Integer) and [Naturals](Natural)), this division satisfies the
83///same relevant axioms. However, they are not _always_ equivalent, the real numbers being a notable
84///exception.
85///
86pub trait ArchimedeanDiv: Sized + ArchimedeanProperty {
87
88    ///
89    ///Maps a natural number into this structure preserving addition and
90    ///using the relevant canonical representation
91    ///
92    ///For rings and semirings with [One], this representation should map the [Natural] 1 to 1 in
93    ///the structure and should also preserve multiplication
94    ///
95    fn embed_nat<N:Natural>(n:N) -> Self;
96
97    ///the unique integer `n` such that `n*rhs <= self` and `(n+1)*rhs > self`
98    fn div_arch(self, rhs: Self) -> Self;
99
100    ///the remaining difference after dividing by rhs (ie. `self - self.div_arch(rhs)*rhs`)
101    fn rem_arch(self, rhs: Self) -> Self;
102
103    ///
104    ///Divides `self` by `rhs` with remainder using the archimdean property
105    ///
106    ///Specifically, this function finds the unique Integer `n` and element `r` such that:
107    /// * `self = n*rhs + r`
108    /// * `n*rhs <= self`
109    /// * `(n+1)*rhs > self`
110    ///
111    ///Note that the meaning of "Integer" here refers to the canonical representation/mapping
112    ///of the Integers into this structure by nature of the [additive ordering](AddOrdered) on
113    ///this structure and _not_ the integers themselves. As such, the quotient returned must
114    ///be a possible output or [negation](Neg) a possibile output of
115    ///[embed_nat()](ArchimedeanDiv::embed_nat).
116    ///
117    ///Furthermore, because the choice of quotient, the remainder returned must _always_ be non-negative.
118    ///For this reason, for primitive types, this method corresponds to the div_euclid and
119    ///rem_euclid methods and _not_ the `/` and `%` operators.
120    ///
121    fn div_alg_arch(self, rhs: Self) -> (Self, Self);
122}
123
124///An additive magma with an ordered addition operation
125pub trait OrdMagma = AddMagma + AddOrdered;
126///An additive semigroup with an ordered addition operation
127pub trait OrdSemigroup = OrdMagma + AddSemigroup;
128///An additive loop with an ordered addition operation
129pub trait OrdLoop = OrdMagma + AddLoop;
130///An additive monoid with an ordered addition operation
131pub trait OrdMonoid = OrdSemigroup + AddMonoid + Signed;
132///An additive group with an ordered addition operation
133pub trait OrdGroup = OrdMonoid + AddGroup;
134///An additive abelian group with an ordered addition operation
135pub trait OrdAbelianGroup = OrdGroup + AddAbelianGroup;
136
137///A semiring with ordered addition and multiplication
138pub trait OrdSemiring = Semiring + OrdMonoid + MulOrdered;
139///A unitial semiring with ordered addition and multiplication
140pub trait OrdUnitalSemiring = OrdSemiring + UnitalSemiring;
141///A commutative semiring with ordered addition and multiplication
142pub trait OrdCommutativeSemiring = OrdUnitalSemiring + CommutativeSemiring;
143///A division semiring with ordered addition and multiplication
144pub trait OrdDivisionSemiring = OrdUnitalSemiring + DivisionSemiring;
145
146///A ring with ordered addition and multiplication
147pub trait OrdRing = Ring + OrdAbelianGroup + MulOrdered;
148///A unital ring with ordered addition and multiplication
149pub trait OrdUnitalRing = OrdRing + UnitalRing + Sign;
150///A commutative ring with ordered addition and multiplication
151pub trait OrdCommutativeRing = OrdUnitalRing + CommutativeRing;
152///A division ring with ordered addition and multiplication
153pub trait OrdDivisionRing = OrdCommutativeRing + DivisionRing;
154
155///A field with ordered addition and multiplication
156pub trait OrdField = OrdUnitalRing + Field;
157
158///An ordered semigroup with the Archimedean property
159pub trait ArchSemigroup = OrdSemigroup + ArchimedeanProperty;
160///An ordered monoid with the Archimedean property
161pub trait ArchMonoid = ArchSemigroup + OrdMonoid;
162///An ordered group with the Archimedean property
163pub trait ArchGroup = ArchMonoid + OrdGroup;
164///An ordered abeliean group with the Archimedean property
165pub trait ArchAbelianGroup = ArchMonoid + OrdAbelianGroup;
166
167///An ordered semiring with the Archimedean property
168pub trait ArchSemiring = ArchMonoid + OrdSemiring;
169///An ordered unital semiring with the Archimedean property and Archimedean division
170pub trait ArchUnitalSemiring = ArchSemiring + OrdUnitalSemiring + ArchimedeanDiv;
171///An ordered commutative semiring with the Archimedean property and Archimedean division
172pub trait ArchCommutativeSemiring = ArchUnitalSemiring + OrdCommutativeSemiring;
173///An ordered division semiring with the Archimedean property and Archimedean division
174pub trait ArchDivisionSemiring = ArchCommutativeSemiring + OrdDivisionSemiring;
175
176///An ordered ring with the Archimedean property
177pub trait ArchRing = ArchAbelianGroup + OrdRing;
178///An ordered unital ring with the Archimedean property and Archimedean division
179pub trait ArchUnitalRing = ArchRing + OrdUnitalRing + ArchimedeanDiv;
180///An ordered commutative ring with the Archimedean property and Archimedean division
181pub trait ArchCommutativeRing = ArchUnitalRing + OrdCommutativeRing;
182///An ordered division ring with the Archimedean property and Archimedean division
183pub trait ArchDivisionRing = ArchCommutativeRing + OrdDivisionRing;
184
185///An ordered field ring with the Archimedean property and Archimedean division
186pub trait ArchField = ArchUnitalRing + OrdField;
187
188macro_rules! impl_ordered_int {
189    ($($t:ident)*) => {$(
190
191        impl AddOrdered for $t {}
192        impl MulOrdered for $t {}
193        impl ArchimedeanProperty for $t {}
194
195        impl Sign for $t {
196            #[inline] fn signum(self) -> Self { $t::signum(self) }
197            #[inline] fn abs(self) -> Self { $t::abs(self) }
198        }
199        impl ArchimedeanDiv for $t {
200            #[inline] fn embed_nat<N:Natural>(n:N) -> Self { (1).mul_n(n) }
201            #[inline] fn div_arch(self, rhs:Self) -> Self {self.div_euclid(rhs)}
202            #[inline] fn rem_arch(self, rhs:Self) -> Self {self.rem_euclid(rhs)}
203            #[inline] fn div_alg_arch(self, rhs:Self) -> (Self, Self) {(self.div_arch(rhs), self.rem_arch(rhs))}
204        }
205    )*}
206}
207
208macro_rules! impl_ordered_uint {
209    ($($t:ty)*) => {$(
210
211        impl AddOrdered for $t {}
212        impl MulOrdered for $t {}
213        impl ArchimedeanProperty for $t {}
214
215        impl Sign for $t {
216            #[inline] fn signum(self) -> Self { if self==0 {0} else {1} }
217            #[inline] fn abs(self) -> Self { self }
218        }
219
220        impl ArchimedeanDiv for $t {
221            #[inline] fn embed_nat<N:Natural>(n:N) -> Self { (1).mul_n(n) }
222            #[inline] fn div_arch(self, rhs:Self) -> Self {self / rhs}
223            #[inline] fn rem_arch(self, rhs:Self) -> Self {self % rhs}
224            #[inline] fn div_alg_arch(self, rhs:Self) -> (Self, Self) {(self / rhs, self % rhs)}
225        }
226    )*}
227}
228
229macro_rules! impl_ordered_float {
230    ($($t:ident)*) => {$(
231
232        impl AddOrdered for $t {}
233        impl MulOrdered for $t {}
234        impl ArchimedeanProperty for $t {}
235
236        impl Sign for $t {
237            #[inline] fn signum(self) -> Self {
238                #[cfg(feature = "std")] {$t::signum(self)}
239                #[cfg(not(feature = "std"))] {if self<0.0 {-1.0} else if self>0.0 {1.0} else {0.0}}
240            }
241            #[inline] fn abs(self) -> Self {
242                #[cfg(feature = "std")] {$t::abs(self)}
243                #[cfg(not(feature = "std"))] {if self<0.0 {-self} else {self}}
244            }
245        }
246        impl ArchimedeanDiv for $t {
247            #[inline] fn embed_nat<N:Natural>(n:N) -> Self { (1.0).mul_n(n) }
248            #[inline] fn rem_arch(self, rhs:Self) -> Self {
249                let rem = self % rhs;
250                if rem < 0.0 { rem + rhs.abs() } else { rem }
251            }
252            #[inline] fn div_arch(self, rhs:Self) -> Self { self.div_alg_arch(rhs).0 }
253            #[inline] fn div_alg_arch(self, rhs:Self) -> (Self, Self) {
254                let rem = self.rem_arch(rhs);
255                ((self - rem) / rhs, rem)
256            }
257        }
258    )*}
259}
260
261// Necessary do to issue #60021
262mod impls {
263    use super::{ AddOrdered, MulOrdered, ArchimedeanProperty, Sign, ArchimedeanDiv, Natural, MulN };
264    impl_ordered_int!(i8 i16 i32 i64 i128 isize);
265    impl_ordered_uint!(u8 u16 u32 u64 u128 usize);
266    impl_ordered_float!(f32 f64);
267}