alga/general/one_operator.rs
1#[cfg(feature = "decimal")]
2use decimal::d128;
3use num::Num;
4use num_complex::Complex;
5use std::ops::{Add, Mul};
6
7use approx::RelativeEq;
8
9use crate::general::{Additive, ClosedNeg, Identity, Multiplicative, Operator, TwoSidedInverse};
10
11/// A magma is an algebraic structure which consists of a set equipped with a binary operation, ∘,
12/// which must be closed.
13///
14/// # Closed binary operation
15///
16/// ~~~notrust
17/// a, b ∈ Self ⇒ a ∘ b ∈ Self
18/// ~~~
19pub trait AbstractMagma<O: Operator>: Sized + Clone {
20 /// Performs an operation.
21 fn operate(&self, right: &Self) -> Self;
22
23 /// Performs specific operation.
24 #[inline]
25 fn op(&self, _: O, lhs: &Self) -> Self {
26 self.operate(lhs)
27 }
28}
29
30/// A quasigroup is a magma which that has the **divisibility property** (or Latin square property).
31/// *A set with a closed binary operation with the divisibility property.*
32///
33/// Divisibility is a weak form of right and left invertibility.
34///
35/// # Divisibility or Latin square property
36///
37/// ```notrust
38/// ∀ a, b ∈ Self, ∃! r, l ∈ Self such that l ∘ a = b and a ∘ r = b
39/// ```
40///
41/// The solution to these equations can be written as
42///
43/// ```notrust
44/// r = a \ b and l = b / a
45/// ```
46///
47/// where "\" and "/" are respectively the **left** and **right** division.
48pub trait AbstractQuasigroup<O: Operator>:
49 PartialEq + AbstractMagma<O> + TwoSidedInverse<O>
50{
51 /// Returns `true` if latin squareness holds for the given arguments. Approximate
52 /// equality is used for verifications.
53 ///
54 /// ```notrust
55 /// a ~= a / b ∘ b && a ~= a ∘ b / b
56 /// ```
57 fn prop_inv_is_latin_square_approx(args: (Self, Self)) -> bool
58 where
59 Self: RelativeEq,
60 {
61 let (a, b) = args;
62 relative_eq!(a, a.operate(&b.two_sided_inverse()).operate(&b))
63 && relative_eq!(a, a.operate(&b.operate(&b.two_sided_inverse())))
64
65 // TODO: pseudo inverse?
66 }
67
68 /// Returns `true` if latin squareness holds for the given arguments.
69 ///
70 /// ```notrust
71 /// a == a / b * b && a == a * b / b
72 /// ```
73 fn prop_inv_is_latin_square(args: (Self, Self)) -> bool
74 where
75 Self: Eq,
76 {
77 let (a, b) = args;
78 a == a.operate(&b.two_sided_inverse()).operate(&b)
79 && a == a.operate(&b.operate(&b.two_sided_inverse()))
80
81 // TODO: pseudo inverse?
82 }
83}
84
85/// Implements the quasigroup trait for types provided.
86/// # Examples
87///
88/// ```
89/// # #[macro_use]
90/// # extern crate alga;
91/// # use alga::general::{AbstractMagma, AbstractQuasigroup, Additive, TwoSidedInverse};
92/// # fn main() {}
93/// #[derive(PartialEq, Clone)]
94/// struct Wrapper<T>(T);
95///
96/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
97/// fn operate(&self, right: &Self) -> Self {
98/// Wrapper(self.0.operate(&right.0))
99/// }
100/// }
101///
102/// impl<T: TwoSidedInverse<Additive>> TwoSidedInverse<Additive> for Wrapper<T> {
103/// fn two_sided_inverse(&self) -> Self {
104/// Wrapper(self.0.two_sided_inverse())
105/// }
106/// }
107///
108/// impl_quasigroup!(<Additive> for Wrapper<T> where T: AbstractQuasigroup<Additive>);
109/// ```
110macro_rules! impl_quasigroup(
111 (<$M:ty> for $($T:tt)+) => {
112 impl_marker!($crate::general::AbstractQuasigroup<$M>; $($T)+);
113 }
114);
115
116/// A semigroup is a quasigroup that is **associative**.
117///
118/// *A semigroup is a set equipped with a closed associative binary operation and that has the divisibility property.*
119///
120/// # Associativity
121///
122/// ~~~notrust
123/// ∀ a, b, c ∈ Self, (a ∘ b) ∘ c = a ∘ (b ∘ c)
124/// ~~~
125pub trait AbstractSemigroup<O: Operator>: PartialEq + AbstractMagma<O> {
126 /// Returns `true` if associativity holds for the given arguments. Approximate equality is used
127 /// for verifications.
128 fn prop_is_associative_approx(args: (Self, Self, Self)) -> bool
129 where
130 Self: RelativeEq,
131 {
132 let (a, b, c) = args;
133 relative_eq!(a.operate(&b).operate(&c), a.operate(&b.operate(&c)))
134 }
135
136 /// Returns `true` if associativity holds for the given arguments.
137 fn prop_is_associative(args: (Self, Self, Self)) -> bool
138 where
139 Self: Eq,
140 {
141 let (a, b, c) = args;
142 a.operate(&b).operate(&c) == a.operate(&b.operate(&c))
143 }
144}
145
146/// Implements the semigroup trait for types provided.
147/// # Examples
148///
149/// ```
150/// # #[macro_use]
151/// # extern crate alga;
152/// # use alga::general::{AbstractMagma, AbstractSemigroup, Additive};
153/// # fn main() {}
154/// #[derive(PartialEq, Clone)]
155/// struct Wrapper<T>(T);
156///
157/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
158/// fn operate(&self, right: &Self) -> Self {
159/// Wrapper(self.0.operate(&right.0))
160/// }
161/// }
162///
163/// impl_semigroup!(<Additive> for Wrapper<T> where T: AbstractSemigroup<Additive>);
164/// ```
165macro_rules! impl_semigroup(
166 (<$M:ty> for $($T:tt)+) => {
167 impl_marker!($crate::general::AbstractSemigroup<$M>; $($T)+);
168 }
169);
170
171/// A loop is a quasigroup with an unique **identity element**, e.
172///
173/// *A set equipped with a closed binary operation possessing the divisibility property
174/// and a unique identity element.*
175///
176/// # Identity element
177///
178/// ~~~notrust
179/// ∃! e ∈ Self, ∀ a ∈ Self, ∃ r, l ∈ Self such that l ∘ a = a ∘ r = e.
180/// ~~~
181///
182/// The left inverse `r` and right inverse `l` are not required to be equal.
183///
184/// This property follows from
185///
186/// ~~~notrust
187/// ∀ a ∈ Self, ∃ e ∈ Self, such that e ∘ a = a ∘ e = a.
188/// ~~~
189pub trait AbstractLoop<O: Operator>: AbstractQuasigroup<O> + Identity<O> {}
190
191/// Implements the loop trait for types provided.
192/// # Examples
193///
194/// ```
195/// # #[macro_use]
196/// # extern crate alga;
197/// # use alga::general::{AbstractMagma, AbstractLoop, Additive, TwoSidedInverse, Identity};
198/// # fn main() {}
199/// #[derive(PartialEq, Clone)]
200/// struct Wrapper<T>(T);
201///
202/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
203/// fn operate(&self, right: &Self) -> Self {
204/// Wrapper(self.0.operate(&right.0))
205/// }
206/// }
207///
208/// impl<T: TwoSidedInverse<Additive>> TwoSidedInverse<Additive> for Wrapper<T> {
209/// fn two_sided_inverse(&self) -> Self {
210/// Wrapper(self.0.two_sided_inverse())
211/// }
212/// }
213///
214/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
215/// fn identity() -> Self {
216/// Wrapper(T::identity())
217/// }
218/// }
219///
220/// impl_loop!(<Additive> for Wrapper<T> where T: AbstractLoop<Additive>);
221/// ```
222macro_rules! impl_loop(
223 (<$M:ty> for $($T:tt)+) => {
224 impl_quasigroup!(<$M> for $($T)+);
225 impl_marker!($crate::general::AbstractLoop<$M>; $($T)+);
226 }
227);
228
229/// A monoid is a semigroup equipped with an identity element, e.
230///
231/// *A set equipped with a closed associative binary operation with the divisibility property and
232/// an identity element.*
233///
234/// # Identity element
235///
236/// ~~~notrust
237/// ∃ e ∈ Self, ∀ a ∈ Self, e ∘ a = a ∘ e = a
238/// ~~~
239pub trait AbstractMonoid<O: Operator>: AbstractSemigroup<O> + Identity<O> {
240 /// Checks whether operating with the identity element is a no-op for the given
241 /// argument. Approximate equality is used for verifications.
242 fn prop_operating_identity_element_is_noop_approx(args: (Self,)) -> bool
243 where
244 Self: RelativeEq,
245 {
246 let (a,) = args;
247 relative_eq!(a.operate(&Self::identity()), a)
248 && relative_eq!(Self::identity().operate(&a), a)
249 }
250
251 /// Checks whether operating with the identity element is a no-op for the given
252 /// argument.
253 fn prop_operating_identity_element_is_noop(args: (Self,)) -> bool
254 where
255 Self: Eq,
256 {
257 let (a,) = args;
258 a.operate(&Self::identity()) == a && Self::identity().operate(&a) == a
259 }
260}
261
262/// Implements the monoid trait for types provided.
263/// # Examples
264///
265/// ```
266/// # #[macro_use]
267/// # extern crate alga;
268/// # use alga::general::{AbstractMagma, AbstractMonoid, Additive, Identity};
269/// # fn main() {}
270/// #[derive(PartialEq, Clone)]
271/// struct Wrapper<T>(T);
272///
273/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
274/// fn operate(&self, right: &Self) -> Self {
275/// Wrapper(self.0.operate(&right.0))
276/// }
277/// }
278///
279/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
280/// fn identity() -> Self {
281/// Wrapper(T::identity())
282/// }
283/// }
284///
285/// impl_monoid!(<Additive> for Wrapper<T> where T: AbstractMonoid<Additive>);
286/// ```
287macro_rules! impl_monoid(
288 (<$M:ty> for $($T:tt)+) => {
289 impl_semigroup!(<$M> for $($T)+);
290 impl_marker!($crate::general::AbstractMonoid<$M>; $($T)+);
291 }
292);
293
294/// A group is a loop and a monoid at the same time.
295///
296/// *A groups is a set with a closed associative binary operation with the divisibility property and an identity element.*
297pub trait AbstractGroup<O: Operator>: AbstractLoop<O> + AbstractMonoid<O> {}
298
299/// Implements the group trait for types provided.
300/// # Examples
301///
302/// ```
303/// # #[macro_use]
304/// # extern crate alga;
305/// # use alga::general::{AbstractMagma, AbstractGroup, Additive, TwoSidedInverse, Identity};
306/// # fn main() {}
307/// #[derive(PartialEq, Clone)]
308/// struct Wrapper<T>(T);
309///
310/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
311/// fn operate(&self, right: &Self) -> Self {
312/// Wrapper(self.0.operate(&right.0))
313/// }
314/// }
315///
316/// impl<T: TwoSidedInverse<Additive>> TwoSidedInverse<Additive> for Wrapper<T> {
317/// fn two_sided_inverse(&self) -> Self {
318/// Wrapper(self.0.two_sided_inverse())
319/// }
320/// }
321///
322/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
323/// fn identity() -> Self {
324/// Wrapper(T::identity())
325/// }
326/// }
327///
328/// impl_group!(<Additive> for Wrapper<T> where T: AbstractGroup<Additive>);
329/// ```
330macro_rules! impl_group(
331 (<$M:ty> for $($T:tt)+) => {
332 impl_monoid!(<$M> for $($T)+);
333 impl_marker!($crate::general::AbstractQuasigroup<$M>; $($T)+);
334 impl_marker!($crate::general::AbstractLoop<$M>; $($T)+);
335 impl_marker!($crate::general::AbstractGroup<$M>; $($T)+);
336 }
337);
338
339/// An Abelian group is a **commutative** group.
340///
341/// *An commutative group is a set with a closed commutative and associative binary operation with the divisibility property and an identity element.*
342///
343/// # Commutativity
344///
345/// ```notrust
346/// ∀ a, b ∈ Self, a ∘ b = b ∘ a
347/// ```
348pub trait AbstractGroupAbelian<O: Operator>: AbstractGroup<O> {
349 /// Returns `true` if the operator is commutative for the given argument tuple. Approximate
350 /// equality is used for verifications.
351 fn prop_is_commutative_approx(args: (Self, Self)) -> bool
352 where
353 Self: RelativeEq,
354 {
355 let (a, b) = args;
356 relative_eq!(a.operate(&b), b.operate(&a))
357 }
358
359 /// Returns `true` if the operator is commutative for the given argument tuple.
360 fn prop_is_commutative(args: (Self, Self)) -> bool
361 where
362 Self: Eq,
363 {
364 let (a, b) = args;
365 a.operate(&b) == b.operate(&a)
366 }
367}
368
369/// Implements the Abelian group trait for types provided.
370/// # Examples
371///
372/// ```
373/// # #[macro_use]
374/// # extern crate alga;
375/// # use alga::general::{AbstractMagma, AbstractGroupAbelian, Additive, TwoSidedInverse, Identity};
376/// # fn main() {}
377/// #[derive(PartialEq, Clone)]
378/// struct Wrapper<T>(T);
379///
380/// impl<T: AbstractMagma<Additive>> AbstractMagma<Additive> for Wrapper<T> {
381/// fn operate(&self, right: &Self) -> Self {
382/// Wrapper(self.0.operate(&right.0))
383/// }
384/// }
385///
386/// impl<T: TwoSidedInverse<Additive>> TwoSidedInverse<Additive> for Wrapper<T> {
387/// fn two_sided_inverse(&self) -> Self {
388/// Wrapper(self.0.two_sided_inverse())
389/// }
390/// }
391///
392/// impl<T: Identity<Additive>> Identity<Additive> for Wrapper<T> {
393/// fn identity() -> Self {
394/// Wrapper(T::identity())
395/// }
396/// }
397///
398/// impl_abelian!(<Additive> for Wrapper<T> where T: AbstractGroupAbelian<Additive>);
399/// ```
400macro_rules! impl_abelian(
401 (<$M:ty> for $($T:tt)+) => {
402 impl_group!(<$M> for $($T)+);
403 impl_marker!($crate::general::AbstractGroupAbelian<$M>; $($T)+);
404 }
405);
406
407/*
408 *
409 *
410 * Implementations.
411 *
412 *
413 *
414 */
415macro_rules! impl_magma(
416 ($M:ty; $op: ident; $($T:ty),* $(,)*) => {
417 $(impl AbstractMagma<$M> for $T {
418 #[inline]
419 fn operate(&self, lhs: &Self) -> Self {
420 self.$op(*lhs)
421 }
422 })*
423 }
424);
425
426impl_magma!(Additive; add; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);
427#[cfg(feature = "decimal")]
428impl_magma!(Additive; add; d128);
429impl_magma!(Multiplicative; mul; u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);
430#[cfg(feature = "decimal")]
431impl_magma!(Multiplicative; mul; d128);
432
433impl_monoid!(<Additive> for u8; u16; u32; u64; u128; usize);
434impl_monoid!(<Multiplicative> for u8; u16; u32; u64; u128; usize);
435
436impl<N: AbstractMagma<Additive>> AbstractMagma<Additive> for Complex<N> {
437 #[inline]
438 fn operate(&self, lhs: &Self) -> Self {
439 Complex {
440 re: self.re.operate(&lhs.re),
441 im: self.im.operate(&lhs.im),
442 }
443 }
444}
445
446impl<N: Num + Clone> AbstractMagma<Multiplicative> for Complex<N> {
447 #[inline]
448 fn operate(&self, lhs: &Self) -> Self {
449 self * lhs
450 }
451}
452
453impl_abelian!(<Multiplicative> for Complex<N> where N: Num + Clone + ClosedNeg);
454impl_abelian!(<Additive> for Complex<N> where N: AbstractGroupAbelian<Additive>);