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}