maths_traits/algebra/ring_like.rs
1//!
2//!Traits for structures with both an addition and multiplication operation
3//!
4//!While ring-like structures can technically apply to any pair of operations, for ease of use
5//!and to stick with mathematical convention, these operations are taken to be specifically addition
6//!and multiplication where multiplication distributes over addition.
7//!
8//!# Implementation
9//!
10//!This module build upon and behaves in a way similar to the [group-like](crate::algebra::group_like)
11//!structures. However, in addition to the basic group traits, the following properties are also considered:
12//! * Distributivity:
13//! * Multiplication can act on summed elements independently,
14//! ie`z*(x+y)=z*x+z*y` and `(x+y)*z=x*z+y*z` for all `x`, `y`, and `z`.
15//! * Represented by the [`Distributive`] trait
16//! * Note that unlike other marker traits, this one takes a type parameter so that
17//! multiplication between types can also be marked
18//! (such as scalar-vector or matrix-vector multiplication)
19//! * The Exponentiation and Logarthm operations:
20//! * Unary operations that map between addition and multiplication
21//! * Represented with the [`Exponential`] trait
22//! * Properties regarding partial divisibility and factoring
23//! * These traits _essentially_ measure how "integer-like" a particular ring is by abstracting
24//! many properties and operations commonly associated with integers and natural numbers
25//! * These include, but are not limited to:
26//! * [Divisibility]
27//! * [Primality]
28//! * [GCD]
29//! * [Euclidean Division](EuclideanDiv)
30//! * [Factorizability](Factorizable)
31//! * For more information, see each individual trait's documentation
32//!
33//!# Usage
34//!
35//!Similarly to the [group-like](crate::algebra::group_like) module, there are a number of
36//!trait aliases corresponding to a system of ring-like algebraic structures that form a heirarchy
37//!as represented in the following diagram:
38//!
39//!```text
40//!
41//! Add Abelian Group Mul Semigroup
42//! | |
43//! -------Ring--------
44//! |
45//! ----------Unital Ring-------------------------
46//! | | | |
47//! | Commutative Ring Domain |
48//! | | | |
49//! | --------------- |
50//! | | |
51//! | Integral Domain |
52//! | | |
53//!Division Ring ---GCD Domain--- |
54//! | | | |
55//! | UFD Bezout Domain |
56//! | | | |
57//! | ------PID------- |
58//! | | |
59//! | Euclidean Domain |
60//! | | |
61//! -------------Field----------- Exponential Ring
62//! | |
63//! ------Exponential Field--------
64//!
65//!```
66//!
67//!Note also that in addition to the above system, there is a complementary system of "Semirings"
68//!that follows almost the same exact structure but doesn't require a subtraction operation.
69//!
70//!For more information, see each structure's documentation
71//!
72//!# Naming
73//!
74//!It is worth noting that in mathematical literature, there is some leniency in what certain
75//!structures are called, so some trait aliases may be named differently than what some are used to.
76//!
77//!In particular:
78//! * Some mathematicians and literature use the term "Ring" to refer to what is called a "Unital Ring"
79//! here, instead preferring the term "Rng" for Rings without a multiplicative identity. In fact,
80//! this convention is _probably_ the majority considering how little use there is for non-unital rings.
81//! However, the choice was made against using the "Rng" system for the simple reason that it is
82//! obviously highly prone to typesetting errors and is arguably pretty unintuitive for those learning
83//! the terminology.
84//! * The term "Semiring" doesn't really have an established meaning in mathematical convention, so
85//! the use here reflects a particular design choice more than a particular standard.
86//!
87
88use crate::algebra::*;
89use core::iter::Iterator;
90
91///A marker trait for stucts whose multiplication operation preserves addition,
92///ie `z*(x+y)=z*x+z*y` and `(x+y)*z=x*z+y*z` for all `x`, `y`, and `z`.
93pub trait Distributive<T=Self> {}
94
95///
96///Common methods regarding multiplicative inverses in a ring or semiring
97///
98///Do note that while for some rings these methods are relatively quick (like the integers),
99///for others, such as polynomials, this test might actually be relatively expensive
100pub trait Divisibility: Sized {
101 ///Determines if there exists an element `x` such that `self*x` = `rhs`
102 fn divides(self, rhs: Self) -> bool;
103
104 ///Finds an element `x` such that `self*x` = `rhs` if such an element exists
105 fn divide(self, rhs: Self) -> Option<Self>;
106
107 ///Determines if this element has a multiplicative inverse
108 fn unit(&self) -> bool;
109
110 ///Finds this element's multiplicative inverse if it exists
111 fn inverse(self) -> Option<Self>;
112}
113
114///
115///Methods for testing irreduciblity and primality
116///
117///Do note that for obvious reasons these methods should be assumed to be expensive by default.
118///Furthermore, given the difficulty of checking irreduciblity or primality for general rings,
119///it is entirely possible that there is simply no good algorithm for doing so, and as such, this
120///trait is _not_ a requirement for any of the ring categorization traits.
121///
122///Furthermore, it is important to note that in general, while all primes are irreducible,
123///the notions are **not** synonymous. In particular, in Z[sqrt(5)], 3 is irreducible
124///but is not prime. However, if all pairs of elements have a [GCD],
125///then all irreducibles are prime as well.
126pub trait Primality: Divisibility {
127
128 ///Determines if this element cannot be produced from the product of two other non-invertible elements
129 fn irreducible(&self) -> bool;
130
131 ///
132 ///Determines if this element is prime
133 ///
134 ///An element `x` is prime if when `y` is a multiple of `x`, `a*b=y` implies that `x` divides
135 ///_either_ `a` _or_ `b`. Do note that this implies irreduciblity.
136 ///
137 fn prime(&self) -> bool;
138}
139
140///
141///A marker trait for [semirings](Semiring) where there are no nonzero elements that multiply to zero
142///
143///ie. for all `x` and `y` where `x!=0` and `y!=0`, `x*y!=0`
144///
145pub trait NoZeroDivisors {}
146
147///A trait for finding the greatest common divisor and least common multiple of two elements
148pub trait GCD: Sized {
149 ///
150 ///Finds the greatest common divisor of two elements
151 ///
152 ///An element `d` is a GCD of `x` and `y` if for all `z` where `z` divides both `x` and `y`,
153 ///`z` also divides `d`.
154 ///
155 ///Do note that this element will often not be _entirely_ unique. However, it _is_ the case that
156 ///any two GCDs in a [GCDDomain] will always differ by only multiplication by an invertible element.
157 ///For example, while _both_ -4 and 4 are GCDs of 12 and 8 (as Integers), -4 can be
158 ///transformed into 4 and vice versa by multiplying by -1
159 ///
160 fn gcd(self, rhs: Self) -> Self;
161
162 ///
163 ///Finds the least common multiple of two elements
164 ///
165 ///An element `m` is a LCM of `x` and `y` if for all `z` where `x` and `y` both divide `z`,
166 ///`m` also divides `z`. This element is also not always unique in the same way as the gcd.
167 ///
168 ///Additionally, the GCD and LCM can always be computed from each other
169 ///by LCM(x,y) = (x*y)/GCD(x,y), so the existence of one always implies the existence of
170 ///the other
171 ///
172 fn lcm(self, rhs: Self) -> Self;
173}
174
175///A trait for finding the Bezout coefficients of a pair of elements
176pub trait Bezout: GCD {
177
178 ///
179 ///Bezout coefficients of a pair of elements
180 ///
181 ///The Bezout coefficients for `x` and `y` are a pair of elements `a` and `b` such that
182 ///`a*x + b*y = GCD(x,y)`. Note that like with the [GCD], these are only unique up to units.
183 ///However, the coefficients returned by this function must satisfy the defining identity for
184 ///the _particular_ GCD as returned by [GCD::gcd()]
185 ///
186 #[inline]
187 fn bezout_coefficients(self, rhs: Self) -> (Self, Self) {
188 let (a,b,_) = self.bezout_with_gcd(rhs);
189 (a,b)
190 }
191
192 ///
193 ///Computes the [GCD](GCD::gcd()) and the [bezout coefficients](Bezout::bezout_coefficients)
194 ///in one function call
195 ///
196 fn bezout_with_gcd(self, rhs: Self) -> (Self, Self, Self);
197}
198
199///
200///A marker trait for [semirings](Semiring) where each element's set of irreducible divisors is unique
201///
202///Note that this trait is independent of [`Factorizable`] and doesn't contain its own
203///`factors()` method since there are a number of notable examples of rings
204///where unique factorization is provable, but no known algorithm to find the factors is known.
205///This is the case for integer polynomials for example.
206///
207pub trait UniquelyFactorizable: Sized {}
208
209///
210///For [semirings](Semiring) that have a _known_ algorithm for decomposing elements into a set
211///of irreducible factors
212///
213///# Notes on "Irreduciblity"
214///
215///An irreducible factor as defined here is any element that cannot be written as a product of two
216///or more non-invertible elements. Note that this is technically, but not usually, different than
217///a "prime" element. For more information, see [`Divisibility`].
218///
219///# Uniqueness and Ordering
220///
221///This trait on its own makes **no guarantees** that the returned factors are unique or ordered
222/// in **any** way. The only requirements are that:
223///* The product of the factors must be the original number
224///* No factors of `1` are included
225///* `0` returns `[0]`
226///* Only *one* invertible element can be included and must be the first factor
227/// * For example, `-6` might return `[-1, 2, 3]` or `[-1, 3, 2]`, but not `[2, -1, 3]`
228///
229///Importantly, this means does that some structures **can** return different sets of factors
230///at different times. For example, in ℤ[√5], `6 = 2*3 = (1+√5)*(1-√5)` are both valid irreducible
231///factorizations.
232///
233///_However_, if the [`UniquelyFactorizable`] trait is _also_ implemented, this is restricted somewhat,
234///but only up to ordering and units.
235///
236///In particular, given two lists of factors for an element:
237///* There is still no guaranteed ordering, so the lists could be permuted somehow
238///* Some factors in the second might be multiplied by some invertible element from the first
239/// or return an extra invertible element in the list.
240/// * For instance, `-10` might return `[-5, 2]` or `[5,-2]` or `[2,-5]` or even `[-1,5,2]`
241///
242///Furthermore, there is no requirement for any sort of ordering, as the wide range of possible
243///implementing structures gives no obvious standard as to what that would be.
244///
245///_However_, implementors are highly encouraged to guarantee some sort of ordering and uniqueness
246///themselves using their particular properties. For instance, the implementation on the primitive integers
247///return all non-negative factors in order of increasing absolute magnitude with a `-1` at the beginning
248///for negative numbers, or a polynomial could factor as monic polynomials of increasing degree.
249///
250pub trait Factorizable: Sized {
251 type Factors: Iterator<Item=Self>;
252 fn factors(self) -> Self::Factors;
253}
254
255///A trait for performing division with with remainder
256pub trait EuclideanDiv: Sized {
257 ///The specific type used for the Euclidean Norm
258 type Naturals: Natural;
259
260 ///
261 ///A measure of the "degree" of a given element.
262 ///
263 ///This function must satisfy the following restrictions:
264 /// * `a.euclid_norm() <= (a*b).euclid_norm()` for all `a`,`b`
265 /// * for `(q,r) = div_alg()`, `r.euclid_norm() < q.euclid_norm()`
266 ///
267 ///Beyond these, there are no other restrictions. In particular, the Euclidean Norm need not be unique.
268 ///For example, the Euclidean norm of a polynomial is usually taken as the non-unique degree.
269 ///
270 fn euclid_norm(&self) -> Self::Naturals;
271
272 ///The quotient from [Euclidean division](EuclideanDiv::div_alg)
273 fn div_euc(self, rhs: Self) -> Self;
274
275 ///The remainder from the [Euclidean division](EuclideanDiv::div_alg)
276 fn rem_euc(self, rhs: Self) -> Self;
277
278 ///
279 ///Divides a pair of elements with remainder
280 ///
281 ///Given inputs `a` and `b`, this produces a quotient-remainder pair `(q,r)` such that:
282 /// * `a = q*b + r`
283 /// * `r.euclid_norm() < q.euclid_norm()`
284 ///
285 ///Do note that in general, this result is **not** unique, the most striking example
286 ///simply being the Integers, for which **every** division with a remainder has the choice
287 ///of a positive or negative remainder. (Take `13 = 4*3 + 1 = 5*3 - 2` for example) Furthermore,
288 ///other rings, like the Guassian Integers, can have even more options, and others, like polynomials,
289 ///can have _infinite_ possible options.
290 ///
291 ///As such, it is up to the implementor to decide what the canonical form of this result is
292 ///and to communicate it as such, and this trait makes no guarantees that this has happened
293 ///
294 fn div_alg(self, rhs: Self) -> (Self, Self);
295}
296
297///
298///A unary operation mapping addition into multiplication
299///
300///Rigourously, and exponential operation is a mapping `E:R->R` such that:
301/// * `E(x+y) = E(x)*E(y)` whenever `x*y = y*x`
302/// * `E(x) != 0`
303///
304///In addition to these base properties, this trait also stipulates that this function _not_ map
305///every element to 1, so as to rule out the trivial case.
306///
307///Furthmore, to clear up ambiguity, it is important to note that different variations on this
308///definition exists. For instance:
309/// * As already mentioned, some may allow the mapping to be non-trivial
310/// * Some may also allow `E(x) = 0`
311/// * For the [Real](crate::analysis::Real) and [Complex](crate::analysis::Complex) exponentials,
312/// there are a [multitude][1] of equivalent definitions that have no true effect on the mapping
313///
314///More importantly though, most authors specify that the `E(x+y) = E(x)*E(y)` for _all_ `x` and `y`
315///(such as on [Wikipedia][2])
316///However, doing so disallows both the Matrix exponential and Quaternion exponential as well
317///as the Clifford Algebra exponential, all of which are, frankly, the only reason to make the exponential
318///its own separate trait.
319///
320/// # Effects on Ring structure
321///
322///It is worth noting that _any_ ring that has a non-trivial exponential operation must automatically
323///have a characteristic of 0 (that is, `1+1+1+...+1` will never equal zero) and hence, has an
324///embedding of the Integers within it.
325///
326///This fact is easily proven as follows:
327/// * assume `char(R) = n != 0`
328/// * then, for any `x` in `R`, `nx = x+...+x = 0`, and,
329/// the [Frobenious automorphism][3] gives that `(x+y)ⁿ = xⁿ + yⁿ`
330/// * Hence, `(E(x) - 1)ⁿ = E(x)ⁿ - 1 = E(nx) - 1 = E(0) - 1 = 0`
331/// * Thus, we have that that `E(x) = 1` contradicting our assumtions
332///
333///Additionally, any element that is the output of the expoenential _must_ be an invertible element,
334///since <br> `1 = E(0) = E(x-x) = E(x)*E(-x)` implying `E(x) = E(x)⁻¹`
335///
336/// # Uniqueness
337///
338///In general, this characterization of the exponential function is *not* unique. However, in the
339///vast majority of cases, there is a canonical version that all others derive from _or_ there is only
340///one non-trivial case.
341///
342///For example, most real-algebras have infinitely many exponentials, but we get a canonical form
343///stipulating that the function satisfy the classic differential equation `E'(x) = E(x)` or some
344///variant.
345///
346/// [1]: https://en.wikipedia.org/wiki/Characterizations_of_the_exponential_function
347/// [2]: https://en.wikipedia.org/wiki/Exponential_field
348/// [3]: https://en.wikipedia.org/wiki/Frobenius_endomorphism
349///
350pub trait Exponential: Sized {
351 ///
352 ///The exponential of this ring element
353 ///
354 ///Here, `exp(x)` is defined such that:
355 /// * `exp(x+y) = exp(x)*exp(y)` for all `x` and `y` where `x*y=y*x`
356 /// * `exp(x) != 0`
357 /// * `exp(x)` is continuous (if applicable)
358 /// * `d/dx exp(x)|ₓ₌₁ = 1` (if applicable)
359 ///
360 ///For most structures, this function is equivalent to the infinite series Σ x<sup>n</sup>/n!
361 ///
362 fn exp(self) -> Self;
363
364 ///
365 ///An inverse of [exp(x)](Exponential::exp) where `ln(1) = 0`
366 ///
367 ///This returns a `None` value whenever the inverse does not exist for the given input.
368 ///
369 /// ## Uniqueness and Continuity
370 ///
371 ///Do note, however, that for almost all non-[Real](crate::analysis::Real) structures, this function
372 ///is not unique and can **never** be continuous. Of course, some of this ambiguity is resolved by
373 ///stipulating that `ln(1) = 0`, but even so, some remains,
374 ///and so, it is entirely up to the implementor to any specific canonical form if applicable.
375 ///
376 ///For example, the [Complex](crate::analysis::Complex) numbers, the natural logarithm *must* be discontinuous somewhere,
377 ///and there are infinitely many choices as to where that is. However, usually, this ambiguity
378 ///is removed by taking the imaginary component of the result between -π and π and setting
379 ///the discontinuity to be on the negative real axis
380 ///
381 fn try_ln(self) -> Option<Self>;
382}
383
384///A commutative and additive monoid with a distributive and associative multiplication operation
385pub trait Semiring = Distributive + AddMonoid + AddCommutative + MulSemigroup;
386///A semiring with an identity element
387pub trait UnitalSemiring = Semiring + MulMonoid;
388///A unital semiring where multiplication is commutative
389pub trait CommutativeSemiring = UnitalSemiring + MulCommutative;
390///A semiring with a multiplicative inverse
391pub trait DivisionSemiring = UnitalSemiring + MulGroup;
392
393///An additive abelian group with a distributive and associative multiplication operation
394pub trait Ring = Distributive + AddAbelianGroup + MulSemigroup;
395///A ring with an identity element
396pub trait UnitalRing = Ring + MulMonoid;
397///A unital ring where multiplication is commutative
398pub trait CommutativeRing = UnitalRing + MulCommutative;
399///A ring with a multiplicative inverse
400pub trait DivisionRing = UnitalRing + MulGroup;
401///A ring with an exponential operation
402pub trait ExponentialRing = UnitalRing + Exponential;
403
404///A unital semiring with no pairs of nonzero elements that multiply to zero
405pub trait Semidomain = UnitalSemiring + Divisibility + NoZeroDivisors;
406///A semidomain that is commutative
407pub trait IntegralSemidomain = Semidomain + MulCommutative;
408///An integral semidomain where every pair of elements has a greatest common divisor
409pub trait GCDSemidomain = IntegralSemidomain + GCD;
410///A GCD semidomain where every pair of elements is uniquely factorizable into irreducible elements (up to units)
411pub trait UFSemidomain = GCDSemidomain + UniquelyFactorizable;
412///A UF semidomain with a division algorithm for dividing with a remainder
413pub trait EuclideanSemidomain = UFSemidomain + EuclideanDiv;
414
415///A unital ring with no pairs of nonzero elements that multiply to zero
416pub trait Domain = UnitalRing + Divisibility + NoZeroDivisors;
417///A domain that is commutative
418pub trait IntegralDomain = Domain + MulCommutative;
419///A commutative ring where every pair of elements has a greatest common divisor
420pub trait GCDDomain = IntegralDomain + GCD;
421///A commutative ring where every pair of elements has a weighted sum to their GCD
422pub trait BezoutDomain = GCDDomain + Bezout;
423///A commutative ring that is uniquely factorizable into irreducible (up to units)
424pub trait UFD = GCDDomain + UniquelyFactorizable;
425///
426///An integral domain where every ideal is generated by one element
427///
428///ie. a UFD that is Bezout
429///
430pub trait PID = UFD + BezoutDomain;
431///A commutative ring with a division algorithm for dividing with a remainder
432pub trait EuclideanDomain = PID + EuclideanDiv;
433
434///A set that is both an additive and multiplicative abelian group where multiplication distributes
435pub trait Field = CommutativeRing + MulGroup;
436///A field with an exponential operation
437pub trait ExponentialField = Field + Exponential;
438
439//
440//Implementation for primitives
441//
442
443macro_rules! impl_dist {
444 ($($t:ty)*) => {
445 $(
446 impl Distributive for $t{}
447 impl Distributive for ::core::num::Wrapping<$t>{}
448 )*
449 };
450}
451impl_dist!(usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64);
452
453macro_rules! impl_for_field {
454 ($($t:ty)*) => {
455 $(
456 impl Divisibility for $t {
457 #[inline(always)] fn divides(self, _rhs: Self) -> bool {true}
458 #[inline(always)] fn divide(self, rhs: Self) -> Option<Self> {Some(rhs / self)}
459 #[inline(always)] fn unit(&self) -> bool {true}
460 #[inline(always)] fn inverse(self) -> Option<Self> {Some(self.inv())}
461 }
462
463 impl NoZeroDivisors for $t {}
464 impl UniquelyFactorizable for $t {}
465
466 )*
467 }
468}
469
470impl_for_field!(f32 f64);
471
472///Uses the [Euclidean Algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm)
473///to find the [GCD] of two ring elements using [division with remainder](EuclideanDiv)
474pub fn euclidean<T>(lhs: T, rhs: T) -> T where T:CommutativeSemiring+EuclideanDiv {
475
476 fn euclid<U>(a: U, b: U) -> U where U:CommutativeSemiring+EuclideanDiv
477 {
478 let r = a.rem_euc(b.clone());
479 if r.is_zero() {
480 b
481 }else{
482 euclid(b, r)
483 }
484 }
485
486 if lhs.is_zero() || rhs.is_zero() {return T::zero()}
487
488 if lhs.euclid_norm() >= rhs.euclid_norm() {
489 euclid(lhs, rhs)
490 } else {
491 euclid(rhs, lhs)
492 }
493
494}
495
496///
497///Uses the [Extended Euclidean Algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)
498///to find the [GCD] of two ring elements _and_ their [bezout coefficients](Bezout) using
499///[division with remainder](EuclideanDiv)
500///
501pub fn extended_euclidean<T>(lhs: T, rhs: T) -> (T, T, T) where T:CommutativeRing+EuclideanDiv {
502
503 fn euclid<U>(a: U, b: U) -> (U, U, U) where U:CommutativeRing+EuclideanDiv
504 {
505 let (q, r) = a.div_alg(b.clone());
506 if r.is_zero() {
507 (U::zero(), U::one(), b)
508 }else{
509 let (x1, y1, g) = euclid(b, r);
510 (y1.clone(), x1 - q * y1, g)
511 }
512 }
513
514 if lhs.is_zero() || rhs.is_zero() {
515 return (T::zero(), T::zero(), T::zero())
516 }
517
518 if lhs.euclid_norm() >= rhs.euclid_norm() {
519 euclid(lhs, rhs)
520 } else {
521 let (y, x, g) = euclid(rhs, lhs);
522 (x, y, g)
523 }
524
525}
526
527///
528///Determines if a given Natural number is [prime](Primality) using the
529///[Miller-Rabin primality test](https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test)
530///
531///The algorithm works in essence by searching for counter-examples to Fermat's Little theorem, ie,
532///that `a^(p-1) = 1` for all `a` in `Z/pZ` when `p` is prime. In general, this tactic only gives a
533///way to prove a number is _not_ prime, but with a few modifications to the check and by picking
534///the right examples, it is possible to turn this into a deterministic test. \*
535///
536///Furthermore, this particular algorithm has the surprising benefit of having a runtime that is
537///polynomial in the number of bits in the input. Of course, this does not guarantee that this function
538///is particularly "fast" per se, but in testing, the algorithm runs reasonable fast for all primitive
539///integer types.
540///
541///\* It is important to note that the particular method used to achieve a Deterministic Miller Robin
542///algorithm in polynomial time, _technically_ depends on the Generalized Riemann Hypothesis. So I
543///guess that means that for super huge numbers, this technically _could_ give a false positive... ¯\\\_(ツ)\_/¯
544///But hey, what _else_ is there? The AKS Primality Test?
545///
546pub fn miller_rabin<Z:Natural>(n:Z) -> bool {
547 //trivial cases
548 if n <= Z::one() { return false; }
549 if n == Z::two() { return true; }
550 if n.even() { return false; }
551
552 //decompose n-1 (ie. -1 in Z/nZ) into a product of the form d*2^s
553 let mut d = n.clone() - Z::one();
554 let mut s = Z::zero();
555 while d.even() {
556 s = s + Z::one();
557 d = d.div_two();
558 }
559
560 #[inline]
561 fn witness<N:Natural>(witness:u128, d:N, s:N, n:N) -> bool {
562 _witness(N::try_from(witness).unwrap_or(N::zero()), d, s, n)
563 }
564
565 fn _witness<N:Natural>(mut a:N, mut d:N, mut s:N, n:N) -> bool {
566 let mut r = a.clone();
567 d = d - N::one();
568 while d > N::zero() {
569 if d.even() {
570 d = d.div_two();
571 a = (a.clone() * a) % n.clone();
572 } else {
573 d = d - N::one();
574 r = (r * a.clone()) % n.clone();
575 }
576 }
577
578 if r.is_one() {
579 true
580 } else {
581 loop {
582
583 if r == n.clone() - N::one() { return true; }
584
585 if s.is_zero() {
586 break;
587 } else {
588 s = s - N::one();
589 r = (r.clone() * r) % n.clone();
590 }
591 }
592 false
593 }
594
595 }
596
597 //the breakpoints for each set of sufficient witnesses
598 let b1 = Z::from_u32(2047u32);
599 let b2 = Z::from_u32(1373653u32);
600 let b3 = Z::from_u32(9080191u32);
601 let b4 = Z::from_u32(25326001u32);
602 let b5 = Z::from_u64(3215031751u64);
603 let b6 = Z::from_u64(4759123141u64);
604 let b7 = Z::from_u64(1122004669633u64);
605 let b8 = Z::from_u64(2152302898747u64);
606 let b9 = Z::from_u64(3474749660383u64);
607 let b10 = Z::from_u64(341550071728321u64);
608 let b11 = Z::from_u64(3825123056546413051u64);
609 let b12 = Z::from_u128(318665857834031151167461u128);
610 let b13 = Z::from_u128(3317044064679887385961981u128);
611
612 if b1.map_or(true, |x| n < x) {
613 witness(2, d.clone(), s.clone(), n.clone())
614 } else if b2.map_or(true, |x| n < x) {
615 witness(2, d.clone(), s.clone(), n.clone()) &&
616 witness(3, d.clone(), s.clone(), n.clone())
617 } else if b3.map_or(true, |x| n < x) {
618 witness(31, d.clone(), s.clone(), n.clone()) &&
619 witness(73, d.clone(), s.clone(), n.clone())
620 } else if b4.map_or(true, |x| n < x) {
621 witness(2, d.clone(), s.clone(), n.clone()) &&
622 witness(3, d.clone(), s.clone(), n.clone()) &&
623 witness(5, d.clone(), s.clone(), n.clone())
624 } else if b5.map_or(true, |x| n < x) {
625 witness(2, d.clone(), s.clone(), n.clone()) &&
626 witness(3, d.clone(), s.clone(), n.clone()) &&
627 witness(5, d.clone(), s.clone(), n.clone()) &&
628 witness(7, d.clone(), s.clone(), n.clone())
629 } else if b6.map_or(true, |x| n < x) {
630 witness(2, d.clone(), s.clone(), n.clone()) &&
631 witness(7, d.clone(), s.clone(), n.clone()) &&
632 witness(61, d.clone(), s.clone(), n.clone())
633 } else if b7.map_or(true, |x| n < x) {
634 witness(2, d.clone(), s.clone(), n.clone()) &&
635 witness(13, d.clone(), s.clone(), n.clone()) &&
636 witness(23, d.clone(), s.clone(), n.clone()) &&
637 witness(1662803, d.clone(), s.clone(), n.clone())
638 } else if b13.map_or(true, |x| n < x) {
639 witness(2, d.clone(), s.clone(), n.clone()) &&
640 witness(3, d.clone(), s.clone(), n.clone()) &&
641 witness(5, d.clone(), s.clone(), n.clone()) &&
642 witness(7, d.clone(), s.clone(), n.clone()) &&
643 witness(11, d.clone(), s.clone(), n.clone()) &&
644 if b8.map_or(false, |x| n >= x) { witness(13, d.clone(), s.clone(), n.clone()) } else {true} &&
645 if b9.map_or(false, |x| n >= x) { witness(17, d.clone(), s.clone(), n.clone()) } else {true} &&
646 if b10.map_or(false, |x| n >= x) {
647 witness(19, d.clone(), s.clone(), n.clone()) &&
648 witness(23, d.clone(), s.clone(), n.clone())
649 } else {true} &&
650 if b11.map_or(false, |x| n >= x) {
651 witness(29, d.clone(), s.clone(), n.clone()) &&
652 witness(31, d.clone(), s.clone(), n.clone()) &&
653 witness(37, d.clone(), s.clone(), n.clone())
654 } else {true} &&
655 if b12.map_or(false, |x| n >= x) { witness(41, d.clone(), s.clone(), n.clone()) } else {true}
656 } else {
657
658 //in general, we need to check every witness below 2*ln(n)^2
659 let mut a = Z::two();
660 while Z::try_from(3.pow_n(a.clone().div_two())).unwrap_or(n.clone()) < n.clone().mul_two() {
661 if !_witness(a.clone(), d.clone(), s.clone(), n.clone()) {return false}
662 a = a + Z::one();
663 }
664 true
665 }
666
667}
668
669#[cfg(test)]
670mod tests {
671 use crate::algebra::*;
672
673 //TODO: add tests for euclidean and extended_euclidean
674
675 #[test]
676 fn primality() {
677
678 assert!(18446744073709551557u64.prime());
679 assert!(!18446744073709551559u64.prime());
680 assert!(!18446744073709551555u64.prime());
681
682 assert!(2147483647u32.prime());
683 assert!(!2147483649u32.prime());
684 assert!(!2147483645u32.prime());
685
686 assert!(65521u16.prime());
687 assert!(65519u16.prime());
688 assert!(!65523u16.prime());
689
690 assert!(251u8.prime());
691 assert!(!253u8.prime());
692 assert!(!249u8.prime());
693
694 assert!(13u8.prime());
695 assert!(!15u8.prime());
696 }
697
698 #[test]
699 fn factor() {
700
701 #[cfg(feature = "std")] {
702 assert_eq!(91u8.factors().collect::<Vec<_>>(), vec![7,13] );
703 assert_eq!((-91i8).factors().collect::<Vec<_>>(), vec![-1,7,13] );
704
705 assert_eq!(360u16.factors().collect::<Vec<_>>(), vec![2,2,2,3,3,5] );
706 assert_eq!((-360i16).factors().collect::<Vec<_>>(), vec![-1,2,2,2,3,3,5] );
707
708 assert_eq!(1971813u32.factors().collect::<Vec<_>>(), vec![3,17,23,41,41] );
709 assert_eq!((-1971813i32).factors().collect::<Vec<_>>(), vec![-1,3,17,23,41,41] );
710
711 assert_eq!(1971813u32.factors().collect::<Vec<_>>(), vec![3,17,23,41,41] );
712 assert_eq!((-1971813i32).factors().collect::<Vec<_>>(), vec![-1,3,17,23,41,41] );
713
714 assert_eq!(0x344CAF57AB24A9u64.factors().collect::<Vec<_>>(), vec![101,101,103,103,107,107,109,109]);
715 assert_eq!((-0x344CAF57AB24A9i64).factors().collect::<Vec<_>>(), vec![-1,101,101,103,103,107,107,109,109]);
716 }
717
718 fn factors_slice<Z:IntegerSubset+Factorizable>(x:Z, dest: &mut [Z]) -> usize {
719 let mut i = 0;
720 for f in x.factors() {
721 if i<dest.len() {
722 dest[i] = f;
723 i += 1;
724 } else {
725 return i;
726 }
727 }
728 return i;
729 }
730
731 let mut factors = [0xFF; 3];
732
733 //test 0 returns 0
734 assert_eq!(factors_slice(0u8, &mut factors), 1);
735 assert_eq!(&factors, &[0,0xFF,0xFF]);
736
737 //test 1 returns 1
738 assert_eq!(factors_slice(1u8, &mut factors), 0);
739 assert_eq!(&factors, &[0,0xFF,0xFF]);
740
741 //test the algorithm stopping at the end of the array
742 assert_eq!(factors_slice(210u8, &mut factors), 3);
743 assert_eq!(&factors, &[2,3,5]);//skips 7
744
745 let mut factors = [0;10];
746
747 //test -1 giving -1
748 assert_eq!(factors_slice(-1i64, &mut factors), 1);
749 assert_eq!(&factors, &[-1,0,0,0,0,0,0,0,0,0]);
750
751 assert_eq!(factors_slice(-0x344CAF57AB24A9i64, &mut factors), 9);
752 assert_eq!(&factors, &[-1,101,101,103,103,107,107,109,109,0]);
753
754 assert_eq!(factors_slice(0x344CAF57AB24A9i64, &mut factors), 8);
755 assert_eq!(&factors, &[101,101,103,103,107,107,109,109,109,0]);
756
757
758 }
759
760}