maths_traits/algebra/
group_like.rs

1//!
2//!Traits for sets with a single binary operation and various properties of that operation
3//!
4//!Currently, the group operation is interpreted as being either the [`Add`] or [`Mul`] operation,
5//!and each of the group properties in this module have both an additive and multiplicative variant.
6//!
7//!As it stands currently, there is no real difference between the two, so it is ultimately up
8//!to the implementor's preference which one (or both) to use. Obviously though, addition and multiplication
9//!carry difference connotations in different contexts, so for clarity and consistency it is
10//!suggested to try to follow the general mathematical or programming conventions whenever possible.
11//!In particular:
12//!* Try to use multiplication for structures with a single operation
13//!except when convention dictates otherwise (such as the case of string concatenation).
14//!* While the option does exist, avoid implementing a non-commutative or especially a non-associative
15//!addition operation unless convention dictates otherwise.
16//!* Avoid implementing both an addition and multiplication where the multiplication *doesn't* distrubute
17//!or where the addition distributes instead.
18//!
19//!# Implementation
20//!
21//!To implement a struct as a group-like structure, the various group-like trait aliases will be usable
22//!according to which and how the following properties are implemented:
23//!* An additive or multiplicative binary operation:
24//!    * Has some function taking any pair of elements from `Self` and outputing any other member of `Self`
25//!    * Represented with either [`Add`] and [`AddAssign`] or [`Mul`] and [`MulAssign`] from [`core::ops`]
26//!    * (Note that for the auto-implementing categorization traits to work, the corresponding
27//!      "Assign" traits must be implemented.)
28//!* An identity element:
29//!    * Contains a unique element `0` or `1` such that `0+x=x` and `x+0=x` or
30//!     `1*x=x`,`x*1=x` for all `x`
31//!    * Represented with either [`Zero`] or [`One`] from [`num_traits`]
32//!* Invertibility:
33//!    * For every `x` in the set, there exists some other `y` in the struct such that
34//!     `x*y=1` and `y*x=1` (or `x+y=0` and `y+x=0` if additive), and there exists
35//!     a corresponding inverse operation.
36//!    * Represented with either [`Neg`], [`Sub`], and [`SubAssign`] or [`Inv`], [`Div`], and [`DivAssign`]
37//!      from [`core::ops`] and [`num_traits`]
38//!    * Note, again, that the "Assign" variants are required
39//!* Commutative:
40//!    * If the operation is order invariant, ie `x+y=y+x` or `x*y=y*x` for all `x` and `y`.
41//!    * Represented with [`AddCommutative`] or [`MulCommutative`]
42//!* Associative:
43//!    * If operation sequences are _evaluation_ order invariant, ie `x+(y+z)=(x+y)+z` or `x*(y*z)=(x*y)*z`
44//!     for all `x`, `y`, and `z`.
45//!    * Represented with [`AddAssociative`] or [`MulAssociative`]
46//!
47//!# Exponentiation
48//!
49//!In addition to these traits, it may be desirable to implement a [multiplication](Mul) or
50//![exponentiation](num_traits::Pow) operation with particular [integer](crate::algebra::Integer)
51//!or [natural](crate::algebra::Natural) type. See [`MulN`], [`MulZ`], [`PowN`], and [`PowZ`] for more details.
52//!
53//!# Usage
54//!
55//!Structs with the above properties implemented will be automatically usable under a number of trait
56//!aliases for particular group-like structures. These structures follow standard mathematical
57//!convention and roughly correspond to a heirarchy varying levels of "niceness" of each
58//!binary operation.
59//!
60//!These structures can be diagrammed as follows:
61//!```text
62//!    ---Magma---
63//!    |         |
64//!    |     Semigroup
65//!   Loop       |
66//!    |      Monoid
67//!    |         |
68//!    ---Group---
69//!         |
70//!   Abelian Group
71//!```
72//!where:
73//!* A [Magma](MulMagma) is a set with any binary operation
74//!* A [Semigroup](MulSemigroup) is an [associative](MulAssociative) Magma
75//!* A [Monoid](MulMonoid) is a Semigroup with an [identity](One) element
76//!* A [Loop](MulLoop) is a Magma with an [identity](One) element and [inverses](Invertable)
77//!* A [Group](MulGroup) is a Monoid with [inverses](Invertable), or alternatively, an [associative](MulAssociative) Loop
78//!* An [Abelian Group](MulAbelianGroup) is a [commutative](MulCommutative) Group
79//!
80//!For more information, see Wikipedia's article on
81//![algebraic structures](https://en.wikipedia.org/wiki/Outline_of_algebraic_structures)
82//!
83//!# Additional Notes
84//!
85//!It is worth noting that this particular system is certainly non-exhaustive and is missing a number
86//!of group-like structures. In particular, it is missing the Category-like structures and Quasigroups
87//!
88//!In the case of categories, this is because as it stands currently, there are few uses for partial
89//!operations while including them would add noticeable complexity.
90//!
91//!In the case of quasigroups however, the reason is because with the way the primitive types are
92//!designed, the only way to determine if an addition or subtraction operation is *truely* invertible
93//!is to check against the [Neg] or [Inv] traits, as the unsigned integers implement **both** division
94//!and subtraction even though technically those operations are not valid on all natural numbers.
95//!So seeing as quasigroups aren't particularly useful anyway, the decision was made to omit them.
96//!
97//!
98
99pub use self::additive::*;
100pub use self::multiplicative::*;
101
102///Traits for group-like structures using addition
103pub mod additive {
104    pub use core::ops::{Add, Sub, Neg, AddAssign, SubAssign};
105    pub use num_traits::{Zero};
106    use core::convert::{From};
107    use core::ops::{Mul};
108
109    use super::{repeated_doubling, repeated_doubling_neg};
110    use crate::algebra::{Natural, IntegerSubset, Semiring, Ring};
111
112    #[allow(unused_imports)] use crate::algebra::Integer;
113
114    ///
115    ///A marker trait for stucts whose addition operation is evaluation order independent,
116    ///ie `x+(y+z)=(x+y)+z` for all `x`, `y`, and `z`.
117    ///
118    ///This is an extremely common property, and _most_ commonly used algebraic systems have it.
119    ///Nonetheless, there are some algebraic constructions like loop concatenation, the cross product,
120    ///lie algebras, and octonions that do not have this property, so the option to _not_ implement it exists.
121    ///
122    ///Note however, it is _highly_ recommended to implement non-associative structs as multiplicative
123    ///to be consistent with convention.
124    ///
125    pub trait AddAssociative {}
126
127    ///
128    ///A marker trait for stucts whose addition operation is order independent,
129    ///ie `x+y=y+x` for all `x`, `y`, and `z`.
130    ///
131    ///This is an extremely common property, and _most_ commonly used algebraic systems have it.
132    ///Nonetheless, there are also a fairly number of algebraic constructions do not, such as
133    ///matrix multiplication, most finite groups, and in particular, string concatenation.
134    ///
135    ///Note however, it is _highly_ recommended to implement non-commutative structs
136    ///(except string concatentation) as multiplicative to be consistent with convention.
137    ///
138    pub trait AddCommutative {}
139
140    ///
141    ///An auto-implemented trait for multiplication by [natural numbers](Natural) with
142    ///[associative](AddAssociative) types using repeated addition
143    ///
144    ///This is intended as a simple and easy way to compute object multiples in abstract algebraic
145    ///algorithms without resorting to explicitly applying addition repeatedly. For this reason, the
146    ///trait is automatically implemented for any relevant associative algebraic structure and
147    ///the supplied function is generic over the [`Natural`] type.
148    ///
149    ///```
150    ///# use maths_traits::algebra::*;
151    ///
152    /// assert_eq!(2.5f32.mul_n(4u8), 10.0);
153    /// assert_eq!(2.5f32.mul_n(4u16), 10.0);
154    /// assert_eq!(2.5f32.mul_n(4u128), 10.0);
155    /// assert_eq!(2.5f64.mul_n(4u8), 10.0);
156    /// assert_eq!(2.5f64.mul_n(4u16), 10.0);
157    /// assert_eq!(2.5f64.mul_n(4u128), 10.0);
158    ///
159    ///```
160    ///
161    ///# Usage Notes
162    ///
163    ///This trait is intended for use with *small* integers and can make no guarrantee that the
164    ///mathematical output will actually fit in the valid range for the output type. As such,
165    ///it is possible for the method to panic, overflow, or return an NaN or error value, so if this
166    ///is an expected possibility, it is recommended to use [TryInto](core::convert::TryInto) or
167    ///a different to perform the operation.
168    ///
169    ///It is worth noting that this particular design was chosen over returning a [Result]
170    ///or [Option] since this general behavior is already the default for primitive types
171    ///despite the relative ease with which it can happen.
172    ///
173    ///# Implementation Notes
174    ///
175    ///Note that while multiplication by natural numbers is very simply defined using
176    ///repeated addition, in order to add flexibility in implementation and the possibility for
177    ///proper optimization, the automatic implmentation of this trait will first try to use other
178    ///traits as a base before defaulting to the general [repeated_doubling] algorithm
179    ///
180    ///Specifically, for a given [Natural] type `N`, the auto-impl will first attempt to use
181    ///[`Mul<N>`](Mul), if implemented. If that fails, it will then try to convert using [`From<N>`](From)
182    ///and multiplying if if it implemented and the struct is a [Semiring].
183    ///Finally, in the general case, it will use the [repeated_doubling] function.
184    ///
185    pub trait MulN: AddSemigroup + Zero {
186        #[inline]
187        fn mul_n<N:Natural>(self, n:N) -> Self {
188
189            trait Helper1<Z:Natural>: AddSemigroup + Zero { fn _mul1(self, n:Z) -> Self; }
190            impl<H: AddSemigroup + Zero, Z:Natural> Helper1<Z> for H {
191                #[inline] default fn _mul1(self, n:Z) -> Self {self._mul2(n)}
192            }
193            impl<H: AddSemigroup + Zero + Mul<Z,Output=H>, Z:Natural> Helper1<Z> for H {
194                #[inline] fn _mul1(self, n:Z) -> Self {self * n}
195            }
196
197            trait Helper2<Z:Natural>: AddSemigroup + Zero { fn _mul2(self, n:Z) -> Self; }
198            impl<H: AddSemigroup + Zero, Z:Natural> Helper2<Z> for H {
199                #[inline] default fn _mul2(self, n:Z) -> Self {repeated_doubling(self, n)}
200            }
201            impl<H: Semiring + From<Z>, Z:Natural> Helper2<Z> for H {
202                #[inline] fn _mul2(self, n:Z) -> Self {H::from(n) * self}
203            }
204
205            self._mul1(n)
206        }
207    }
208
209    impl<G:AddSemigroup + Zero> MulN for G {}
210
211    ///
212    ///An auto-implemented trait for multiplication by [integers](Integer) with
213    ///[associative](AddAssociative) and [negatable](Negatable) types using
214    ///negation and repeated addition
215    ///
216    ///This is intended as a simple and easy way to compute object multiples in abstract algebraic
217    ///algorithms without resorting to explicitly applying addition repeatedly. For this reason, the
218    ///trait is automatically implemented for any relevant associative and negatable algebraic structure and
219    ///the supplied function is generic over the [`Integer`] type.
220    ///
221    ///```
222    ///# use maths_traits::algebra::*;
223    ///
224    /// assert_eq!(2.5f32.mul_z(5u8), 12.5);
225    /// assert_eq!(2.5f32.mul_z(5u128), 12.5);
226    /// assert_eq!(2.5f64.mul_z(5u8), 12.5);
227    /// assert_eq!(2.5f64.mul_z(5u128), 12.5);
228    /// assert_eq!(2.5f32.mul_z(-5i8), -12.5);
229    /// assert_eq!(2.5f32.mul_z(-5i64), -12.5);
230    ///
231    ///```
232    ///
233    ///# Usage Notes
234    ///
235    ///This trait is intended for use with *small* integers and can make no guarrantee that the
236    ///mathematical output will actually fit in the valid range for the output type. As such,
237    ///it is possible for the method to panic, overflow, or return an NaN or error value, so if this
238    ///is an expected possibility, it is recommended to use [TryInto](core::convert::TryInto) or
239    ///a different to perform the operation.
240    ///
241    ///It is worth noting that this particular design was chosen over returning a [Result]
242    ///or [Option] since this general behavior is already the default for primitive types
243    ///despite the relative ease with which it can happen.
244    ///
245    ///# Implementation Notes
246    ///
247    ///Note that while multiplication by integers is very simply defined using
248    ///repeated addition and subtraction, in order to add flexibility in implementation and the possibility for
249    ///proper optimization, the automatic implmentation of this trait will first try to use other
250    ///traits as a base before defaulting to the general [repeated_doubling_neg] algorithm
251    ///
252    ///Specifically, for a given [Integer] type `Z`, the auto-impl will first attempt to use
253    ///[`Mul<Z>`](Mul), if implemented. If that fails, it will then try to convert using [`From<Z>`](From)
254    ///and multiplying if if it implemented and the struct is a [Ring].
255    ///Finally, in the general case, it will use the [repeated_doubling_neg] function.
256    ///
257    pub trait MulZ: AddMonoid + Negatable {
258        #[inline]
259        fn mul_z<N:IntegerSubset>(self, n:N) -> Self {
260
261            trait Helper1<Z:IntegerSubset>: AddMonoid + Negatable { fn _mul1(self, n:Z) -> Self; }
262            impl<H: AddMonoid + Negatable, Z:IntegerSubset> Helper1<Z> for H {
263                #[inline] default fn _mul1(self, n:Z) -> Self {self._mul2(n)}
264            }
265            impl<H: AddMonoid + Negatable + Mul<Z,Output=H>, Z:IntegerSubset> Helper1<Z> for H {
266                #[inline] fn _mul1(self, n:Z) -> Self {self * n}
267            }
268
269            trait Helper2<Z:IntegerSubset>: AddSemigroup + Zero { fn _mul2(self, n:Z) -> Self; }
270            impl<H: AddMonoid + Negatable, Z:IntegerSubset> Helper2<Z> for H {
271                #[inline] default fn _mul2(self, n:Z) -> Self {repeated_doubling_neg(self, n)}
272            }
273            impl<H: Ring + From<Z>, Z:IntegerSubset> Helper2<Z> for H {
274                #[inline] fn _mul2(self, n:Z) -> Self {H::from(n) * self}
275            }
276
277            self._mul1(n)
278        }
279    }
280
281    impl<G:AddMonoid + Negatable> MulZ for G {}
282
283    ///A set with an fully described additive inverse
284    pub trait Negatable = Sized + Clone + Neg<Output=Self> + Sub<Self, Output=Self> + SubAssign<Self>;
285
286    ///A set with an addition operation
287    pub trait AddMagma = Sized + Clone + Add<Self,Output=Self> + AddAssign<Self>;
288    ///An associative additive magma
289    pub trait AddSemigroup = AddMagma + AddAssociative;
290    ///An additive semigroup with an identity element
291    pub trait AddMonoid = AddSemigroup + Zero + MulN;
292    ///An additive magma with an inverse operation and identity
293    pub trait AddLoop = AddMagma + Negatable + Zero;
294    ///An additive monoid with an inverse operation
295    pub trait AddGroup = AddMagma + AddAssociative + Negatable + Zero + MulZ;
296    ///A commutative additive group
297    pub trait AddAbelianGroup = AddGroup + AddCommutative;
298
299}
300
301///Traits for group-like structures using Multiplication
302pub mod multiplicative {
303    pub use core::ops::{Mul, Div, MulAssign, DivAssign};
304    pub use num_traits::{Inv, One};
305    use num_traits::Pow;
306
307    use super::{repeated_squaring, repeated_squaring_inv};
308    use crate::algebra::{Natural, IntegerSubset};
309
310    #[allow(unused_imports)] use crate::algebra::Integer;
311
312    ///
313    ///A marker trait for stucts whose multiplication operation is evaluation order independent,
314    ///ie `x*(y*z)=(x*y)*z` for all `x`, `y`, and `z`.
315    ///
316    ///This is an extremely common property, and _most_ commonly used algebraic systems have it.
317    ///Nonetheless, there are some algebraic constructions like loop concatenation, the cross product,
318    ///lie algebras, and octonions that do not have this property, so the option to _not_ implement it exists.
319    ///
320    pub trait MulAssociative: {}
321
322    ///
323    ///A marker trait for stucts whose addition operation is order independent,
324    ///ie `x+y=y+x` for all `x`, `y`, and `z`.
325    ///
326    ///This is an extremely common property, and _most_ commonly used algebraic systems have it.
327    ///Nonetheless, there are also a fairly number of algebraic constructions do not, such as
328    ///matrix multiplication and most finite groups.
329    ///
330    pub trait MulCommutative {}
331
332    ///
333    ///An auto-implemented trait for exponentiation by [natural numbers](Natural) with
334    ///[associative](MulAssociative) types using repeated multiplication
335    ///
336    ///This is intended as a simple and easy way to compute object powers in abstract algebraic
337    ///algorithms without resorting to explicitly applying multiplication repeatedly. For this reason, the
338    ///trait is automatically implemented for any relevant associative algebraic structure and
339    ///the supplied function is generic over the [`Natural`] type.
340    ///
341    ///```
342    ///# use maths_traits::algebra::*;
343    ///
344    /// assert_eq!(2.0f32.pow_n(4u8), 16.0);
345    /// assert_eq!(2.0f32.pow_n(4u16), 16.0);
346    /// assert_eq!(2.0f32.pow_n(4u128), 16.0);
347    /// assert_eq!(2.0f64.pow_n(4u8), 16.0);
348    /// assert_eq!(2.0f64.pow_n(4u16), 16.0);
349    /// assert_eq!(2.0f64.pow_n(4u128), 16.0);
350    ///
351    ///```
352    ///# Usage Notes
353    ///
354    ///This trait is intended for use with *small* integers and can make no guarrantee that the
355    ///mathematical output will actually fit in the valid range for the output type. As such,
356    ///it is possible for the method to panic, overflow, or return an NaN or error value, so if this
357    ///is an expected possibility, it is recommended to use [TryInto](core::convert::TryInto) or
358    ///a different to perform the operation.
359    ///
360    ///It is worth noting that this particular design was chosen over returning a [Result]
361    ///or [Option] since this general behavior is already the default for primitive types
362    ///despite the relative ease with which it can happen.
363    ///
364    ///# Implementation Notes
365    ///
366    ///Note that while exponentiation by natural numbers is very simply defined using
367    ///repeated multiplication, in order to add flexibility in implementation and the possibility for
368    ///proper optimization, the automatic implmentation of this trait will first try to use other
369    ///traits as a base before defaulting to the general [repeated_squaring] algorithm
370    ///
371    ///Specifically, for a given [Natural] type `N`, the auto-impl will first attempt to use
372    ///[`Pow<N>`](Pow), if implemented, then if that fails, it will use the general
373    ///[repeated_squaring] algorithm
374    ///
375    pub trait PowN: MulSemigroup + One {
376        #[inline]
377        fn pow_n<N:Natural>(self, n:N) -> Self {
378            trait Helper<Z:Natural>: MulSemigroup + One { fn _pow_n(self, n:Z) -> Self; }
379            impl<G:MulSemigroup+One, Z:Natural> Helper<Z> for G {
380                #[inline] default fn _pow_n(self, n:Z) -> Self {repeated_squaring(self, n)}
381            }
382            impl<G:MulSemigroup+One+Pow<Z,Output=Self>, Z:Natural> Helper<Z> for G {
383                #[inline] fn _pow_n(self, n:Z) -> Self {self.pow(n)}
384            }
385
386            self._pow_n(n)
387        }
388    }
389    impl<G:MulSemigroup+One> PowN for G {}
390
391    ///
392    ///An auto-implemented trait for exponentiation by [integers](Integer) with
393    ///[associative](MulAssociative) and [invertable](Invertable) types using
394    ///inversion and repeated multiplication
395    ///
396    ///This is intended as a simple and easy way to compute object powers in abstract algebraic
397    ///algorithms without resorting to explicitly applying multiplication repeatedly. For this reason, the
398    ///trait is automatically implemented for any relevant associative and invertable algebraic structure and
399    ///the supplied function is generic over the [`Integer`] type.
400    ///
401    ///```
402    ///# use maths_traits::algebra::*;
403    ///
404    /// assert_eq!(2.0f32.pow_z(3u8), 8.0);
405    /// assert_eq!(2.0f32.pow_z(3u128), 8.0);
406    /// assert_eq!(2.0f64.pow_z(3u8), 8.0);
407    /// assert_eq!(2.0f64.pow_z(3u128), 8.0);
408    /// assert_eq!(2.0f32.pow_z(-3i8), 0.125);
409    /// assert_eq!(2.0f32.pow_z(-3i64), 0.125);
410    ///
411    ///```
412    ///# Usage Notes
413    ///
414    ///This trait is intended for use with *small* integers and can make no guarrantee that the
415    ///mathematical output will actually fit in the valid range for the output type. As such,
416    ///it is possible for the method to panic, overflow, or return an NaN or error value, so if this
417    ///is an expected possibility, it is recommended to use [TryInto](core::convert::TryInto) or
418    ///a different to perform the operation.
419    ///
420    ///It is worth noting that this particular design was chosen over returning a [Result]
421    ///or [Option] since this general behavior is already the default for primitive types
422    ///despite the relative ease with which it can happen.
423    ///
424    ///# Implementation Notes
425    ///
426    ///Note that while exponentiation by integers is very simply defined using
427    ///repeated multiplication and inversion, in order to add flexibility in implementation and the possibility for
428    ///proper optimization, the automatic implmentation of this trait will first try to use other
429    ///traits as a base before defaulting to the general [repeated_squaring_inv] algorithm
430    ///
431    ///Specifically, for a given [Natural] type `N`, the auto-impl will first attempt to use
432    ///[`Pow<N>`](Pow), if implemented, then if that fails, it will use the general
433    ///[repeated_squaring_inv] algorithm
434    ///
435    pub trait PowZ: MulMonoid + Invertable {
436        #[inline]
437        fn pow_z<Z:IntegerSubset>(self, n:Z) -> Self {
438            trait Helper<N:IntegerSubset>: MulMonoid + Invertable { fn _pow_z(self, n:N) -> Self; }
439            impl<G:MulMonoid+Invertable, N:IntegerSubset> Helper<N> for G {
440                #[inline] default fn _pow_z(self, n:N) -> Self {repeated_squaring_inv(self, n)}
441            }
442            impl<G:MulMonoid+Invertable+Pow<N,Output=Self>, N:IntegerSubset> Helper<N> for G {
443                #[inline] fn _pow_z(self, n:N) -> Self {self.pow(n)}
444            }
445
446            self._pow_z(n)
447        }
448    }
449    impl<G:MulMonoid+Invertable> PowZ for G {}
450
451
452    ///A set with an fully described multiplicative inverse
453    pub trait Invertable = Sized + Clone + Inv<Output=Self> + Div<Self, Output=Self> + DivAssign<Self>;
454    ///A set with a multiplication operation
455    pub trait MulMagma = Sized + Clone + Mul<Self, Output=Self> + MulAssign<Self>;
456    ///An associative multiplicative magma
457    pub trait MulSemigroup = MulMagma + MulAssociative;
458    ///A multiplicative semigroup with an identity element
459    pub trait MulMonoid = MulSemigroup + One + PowN;
460    ///A multiplicative magma with an inverse operation and identity
461    pub trait MulLoop = MulMagma + Invertable + One;
462    ///A multiplicative monoid with an inverse operation
463    pub trait MulGroup = MulMagma + MulAssociative + Invertable + One + PowZ;
464    ///A commutative multiplicative group
465    pub trait MulAbelianGroup = MulGroup + MulCommutative;
466}
467
468use crate::algebra::{Natural, IntegerSubset};
469
470trait IsZero:Sized { fn _is_zero(&self) -> bool; }
471impl<Z> IsZero for Z { #[inline(always)] default fn _is_zero(&self) -> bool {false} }
472impl<Z:Zero> IsZero for Z { #[inline(always)] fn _is_zero(&self) -> bool {self.is_zero()} }
473
474fn mul_pow_helper<E:Natural, R:Clone, Op: Fn(R,R) -> R>(mut b: R, mut p: E, op: Op) -> R {
475    //repeated squaring/doubling
476    let mut res = b.clone();
477    p -= E::one();
478    while !p.is_zero() {
479        if p.even() {
480            //if the exponent (or multiple) is even, we can factor out the two
481            //ie b^2p = (b^2)^p or 2p*b = p*2b
482            b = op(b.clone(), b);
483            p = p.div_two();
484        } else {
485            //else b^(p+1)=(b^p)*b or (p+1)*b = p*b + b
486            res = op(res, b.clone());
487            p -= E::one();
488        }
489    }
490    res
491}
492
493///
494///Raises a [monoid](MulMonoid) element to a integral power using inversion and repeated squaring
495///
496///# Panics
497///If both the base and power are `0`
498///
499#[inline]
500pub fn repeated_squaring_inv<E:IntegerSubset, R:MulGroup+Clone>(b: R, p: E) -> R {
501    if p.negative() {
502        repeated_squaring(b, p.abs_unsigned()).inv()
503    } else {
504        repeated_squaring(b, p.as_unsigned())
505    }
506}
507
508///
509///Raises a [monoid](MulMonoid) element to a positive integer power using the repeated squaring algorithm
510///
511///# Panics
512///If both the base and power are `0`
513///
514#[inline]
515pub fn repeated_squaring<E:Natural, R:MulMonoid+Clone>(b: R, p: E) -> R {
516    if p.is_zero() {
517        if b._is_zero() { panic!("Attempted to raise 0^0") }
518        R::one()
519    } else {
520        mul_pow_helper(b, p, R::mul)
521    }
522}
523
524
525///Multiplies a [monoid](AddMonoid) by a positive integer using negation and repeated doublings
526#[inline]
527pub fn repeated_doubling_neg<E:IntegerSubset, R:AddGroup>(b: R, p: E) -> R {
528    if p.negative() {
529        -repeated_doubling(b, p.abs_unsigned())
530    } else {
531        repeated_doubling(b, p.as_unsigned())
532    }
533}
534
535///Multiplies a [monoid](AddMonoid) by a positive integer using repeated doublings
536#[inline]
537pub fn repeated_doubling<E:Natural, R:AddMonoid>(b: R, p: E) -> R {
538    if p.is_zero() {
539        R::zero()
540    } else {
541        mul_pow_helper(b, p, R::add)
542    }
543}
544
545macro_rules! impl_props {
546    ($($z:ty)*; $($f:ty)*) => {
547        $(impl_props!(@int $z);)*
548        $(impl_props!(@float $f);)*
549    };
550
551    (@int $z:ty) => {
552        impl_props!(@props $z);
553        impl_props!(@props core::num::Wrapping<$z>);
554    };
555    (@float $f:ty) => {impl_props!(@props $f);};
556    (@props $t:ty) => {
557
558        impl AddAssociative for $t {}
559        impl AddCommutative for $t {}
560        impl MulAssociative for $t {}
561        impl MulCommutative for $t {}
562    };
563}
564
565impl_props!{ usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128; f32 f64 }
566
567#[cfg(std)] impl<'a> AddAssociative for ::std::borrow::Cow<'a,str> {}