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>);