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// 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//
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> {}