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}