algae_rs/magma.rs
1use crate::algaeset::AlgaeSet;
2use crate::mapping::{binop_has_invertible_identity, binop_is_invertible};
3use crate::mapping::{BinaryOperation, PropertyError, PropertyType};
4
5pub trait Magmoid<T: Copy + PartialEq> {
6 fn binop(&mut self) -> &mut dyn BinaryOperation<T>;
7
8 fn with(&mut self, left: T, right: T) -> Result<T, PropertyError> {
9 self.binop().with(left, right)
10 }
11}
12
13/// A set with an associated binary operation.
14///
15/// This is a representation of the simplest algebraic structure: the magma.
16/// There are no specific properties required of its components, so its
17/// construction involves nothing more than a set (specifically an
18/// [`AlgaeSet`] and a binary operation (anything implementing
19/// [`BinaryOperation`]).
20///
21/// # Examples
22///
23/// ```
24/// use algae_rs::algaeset::AlgaeSet;
25/// use algae_rs::mapping::{BinaryOperation, AbelianOperation};
26/// use algae_rs::magma::{Magmoid, Magma};
27///
28/// let mut add = AbelianOperation::new(&|a, b| a + b);
29/// let mut magma = Magma::new(
30/// AlgaeSet::<i32>::all(),
31/// &mut add
32/// );
33///
34/// let magma_sum = magma.with(1, 2);
35/// assert!(magma_sum.is_ok());
36/// assert!(magma_sum.unwrap() == 3);
37/// ```
38pub struct Magma<'a, T> {
39 aset: AlgaeSet<T>,
40 binop: &'a mut dyn BinaryOperation<T>,
41}
42
43impl<'a, T> Magma<'a, T> {
44 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>) -> Self {
45 Self { aset, binop }
46 }
47}
48
49impl<'a, T: Copy + PartialEq> Magmoid<T> for Magma<'a, T> {
50 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
51 self.binop
52 }
53}
54
55/// A set equipped with a binary operation and a specified identity element.
56///
57/// [`UnitalMagma`] is a representation of the abstract algebraic unital magma.
58/// The existence of an identity element is all that is required of its
59/// binary operation. Its construction requires a set (specifically an
60/// [`AlgaeSet`]) and an identity-preserving [`BinaryOperation`].
61///
62/// # Examples
63///
64/// ```
65/// use algae_rs::algaeset::AlgaeSet;
66/// use algae_rs::mapping::{BinaryOperation, IdentityOperation};
67/// use algae_rs::magma::{Magmoid, UnitalMagma};
68///
69/// let mut add = IdentityOperation::new(&|a, b| a + b, 0);
70/// let mut magma = UnitalMagma::new(
71/// AlgaeSet::<i32>::all(),
72/// &mut add,
73/// 0
74/// );
75///
76/// let sum = magma.with(1, 2);
77/// assert!(sum.is_ok());
78/// assert!(sum.unwrap() == 3);
79///
80/// let mut bad_add = IdentityOperation::new(&|a, b| a + b, 3);
81/// let mut bad_magma = UnitalMagma::new(
82/// AlgaeSet::<i32>::all(),
83/// &mut bad_add,
84/// 3
85/// );
86///
87/// let bad_sum = bad_magma.with(2, 3);
88/// assert!(bad_sum.is_err());
89/// ```
90pub struct UnitalMagma<'a, T> {
91 aset: AlgaeSet<T>,
92 binop: &'a mut dyn BinaryOperation<T>,
93 identity: T,
94}
95
96impl<'a, T: Copy + PartialEq> UnitalMagma<'a, T> {
97 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>, identity: T) -> Self {
98 assert!(binop.is(PropertyType::WithIdentity(identity)));
99 Self {
100 aset,
101 binop,
102 identity,
103 }
104 }
105}
106
107impl<'a, T: Copy + PartialEq> Magmoid<T> for UnitalMagma<'a, T> {
108 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
109 self.binop
110 }
111}
112
113impl<'a, T> From<UnitalMagma<'a, T>> for Magma<'a, T> {
114 fn from(magma: UnitalMagma<'a, T>) -> Magma<'a, T> {
115 Magma::new(magma.aset, magma.binop)
116 }
117}
118
119/// A set equipped with an associative binary operation.
120///
121/// [`Groupoid`] is a representation of the abstract algebraic groupoid.
122/// Associativity is all that is required of its binary operation: its
123/// construction involves a set (specifically an [`AlgaeSet`]) and an
124/// associative [`BinaryOperation`].
125///
126/// # Examples
127///
128/// ```
129/// use algae_rs::algaeset::AlgaeSet;
130/// use algae_rs::mapping::{BinaryOperation, AssociativeOperation};
131/// use algae_rs::magma::{Magmoid, Groupoid};
132///
133/// let mut add = AssociativeOperation::new(&|a, b| a + b);
134/// let mut groupoid = Groupoid::new(
135/// AlgaeSet::<i32>::all(),
136/// &mut add
137/// );
138///
139/// let groupoid_sum = groupoid.with(1, 2);
140/// assert!(groupoid_sum.is_ok());
141/// assert!(groupoid_sum.unwrap() == 3);
142///
143/// let mut div = AssociativeOperation::new(&|a, b| a / b);
144/// let mut bad_groupoid = Groupoid::new(
145/// AlgaeSet::<f32>::all(),
146/// &mut div,
147/// );
148///
149/// let ok_dividend = bad_groupoid.with(1.0, 2.0);
150/// assert!(ok_dividend.is_ok());
151/// assert!(ok_dividend.unwrap() == 0.5);
152/// let err_dividend = bad_groupoid.with(3.0, 6.0);
153/// assert!(err_dividend.is_err());
154/// ```
155pub struct Groupoid<'a, T> {
156 aset: AlgaeSet<T>,
157 binop: &'a mut dyn BinaryOperation<T>,
158}
159
160impl<'a, T: Copy + PartialEq> Groupoid<'a, T> {
161 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>) -> Self {
162 assert!(binop.is(PropertyType::Associative));
163 Self { aset, binop }
164 }
165}
166
167impl<'a, T: Copy + PartialEq> Magmoid<T> for Groupoid<'a, T> {
168 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
169 self.binop
170 }
171}
172
173impl<'a, T> From<Groupoid<'a, T>> for Magma<'a, T> {
174 fn from(groupoid: Groupoid<'a, T>) -> Magma<'a, T> {
175 Magma::new(groupoid.aset, groupoid.binop)
176 }
177}
178
179/// A set equipped with a cancellative binary operation.
180///
181/// [`Quasigroup`] is a representation of the abstract algebraic quasigroup.
182/// Cancellativity (ie. the Latin Square property) is required of its binary
183/// operation. Its construction involves a set (specifically an [`AlgaeSet`])
184/// and a [`BinaryOperation`] with the aforementioned properties.
185///
186/// # Examples
187///
188/// ```
189/// use algae_rs::algaeset::AlgaeSet;
190/// use algae_rs::mapping::{BinaryOperation, CancellativeOperation};
191/// use algae_rs::magma::{Magmoid, Quasigroup};
192///
193/// let mut add = CancellativeOperation::new(&|a, b| a + b);
194/// let mut quasigroup = Quasigroup::new(
195/// AlgaeSet::<i32>::all(),
196/// &mut add
197/// );
198/// let sum = quasigroup.with(1, 2);
199/// assert!(sum.is_ok());
200/// assert!(sum.unwrap() == 3);
201/// ```
202pub struct Quasigroup<'a, T> {
203 aset: AlgaeSet<T>,
204 binop: &'a mut dyn BinaryOperation<T>,
205}
206
207impl<'a, T: Copy + PartialEq> Quasigroup<'a, T> {
208 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>) -> Self {
209 assert!(binop.is(PropertyType::Cancellative));
210 Self { aset, binop }
211 }
212}
213
214impl<'a, T: Copy + PartialEq> Magmoid<T> for Quasigroup<'a, T> {
215 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
216 self.binop
217 }
218}
219
220impl<'a, T> From<Quasigroup<'a, T>> for Magma<'a, T> {
221 fn from(quasi: Quasigroup<'a, T>) -> Magma<'a, T> {
222 Magma::new(quasi.aset, quasi.binop)
223 }
224}
225
226/// A set equipped with an associative binary operation with identity.
227///
228/// [`Monoid`] is a representation of the abstract algebraic monoid.
229/// Associativity and identity are required of its binary operation. Its
230/// construction involves a set (specifically an [`AlgaeSet`] and a
231/// [`BinaryOperation`] with the aforementioned properties.
232///
233/// # Examples
234///
235/// ```
236/// use algae_rs::algaeset::AlgaeSet;
237/// use algae_rs::mapping::{BinaryOperation, MonoidOperation};
238/// use algae_rs::magma::{Magmoid, Monoid};
239///
240/// let mut add = MonoidOperation::new(&|a, b| a + b, 0);
241/// let mut monoid = Monoid::new(
242/// AlgaeSet::<i32>::all(),
243/// &mut add,
244/// 0
245/// );
246///
247/// let monoid_sum = monoid.with(1, 2);
248/// assert!(monoid_sum.is_ok());
249/// assert!(monoid_sum.unwrap() == 3);
250///
251/// let mut bad_add = MonoidOperation::new(&|a, b| a + b, 1);
252/// let mut bad_monoid = Monoid::new(
253/// AlgaeSet::<i32>::all(),
254/// &mut bad_add,
255/// 1
256/// );
257///
258/// let bad_monoid_sum = bad_monoid.with(1, 2);
259/// assert!(bad_monoid_sum.is_err());
260/// ```
261pub struct Monoid<'a, T> {
262 aset: AlgaeSet<T>,
263 binop: &'a mut dyn BinaryOperation<T>,
264 identity: T,
265}
266
267impl<'a, T: Copy + PartialEq> Monoid<'a, T> {
268 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>, identity: T) -> Self {
269 assert!(binop.is(PropertyType::Associative));
270 assert!(binop.is(PropertyType::WithIdentity(identity)));
271 Self {
272 aset,
273 binop,
274 identity,
275 }
276 }
277}
278
279impl<'a, T: Copy + PartialEq> Magmoid<T> for Monoid<'a, T> {
280 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
281 self.binop
282 }
283}
284
285impl<'a, T: Copy + PartialEq> From<Monoid<'a, T>> for Magma<'a, T> {
286 fn from(monoid: Monoid<'a, T>) -> Magma<'a, T> {
287 Magma::new(monoid.aset, monoid.binop)
288 }
289}
290
291impl<'a, T: Copy + PartialEq> From<Monoid<'a, T>> for Groupoid<'a, T> {
292 fn from(monoid: Monoid<'a, T>) -> Groupoid<'a, T> {
293 Groupoid::new(monoid.aset, monoid.binop)
294 }
295}
296
297impl<'a, T: Copy + PartialEq> From<Monoid<'a, T>> for UnitalMagma<'a, T> {
298 fn from(monoid: Monoid<'a, T>) -> UnitalMagma<'a ,T> {
299 UnitalMagma::new(monoid.aset, monoid.binop, monoid.identity)
300 }
301}
302
303/// A quasigroup with identity
304///
305/// [`Loop`] is a representation of the abstract algebraic loop. Cancellativity
306/// (ie. the Latin Square property) and identity preservation are both required
307/// of its binary operation. Its construction involves a set (specifically an
308/// [`AlgaeSet`]) and a [`BinaryOperation`] with the aforementioned properties.
309///
310/// # Examples
311///
312/// ```
313/// use algae_rs::algaeset::AlgaeSet;
314/// use algae_rs::mapping::{BinaryOperation, LoopOperation};
315/// use algae_rs::magma::{Magmoid, Loop};
316///
317/// let mut add = LoopOperation::new(&|a, b| a + b, 0);
318/// let mut quasigroup = Loop::new(
319/// AlgaeSet::<i32>::all(),
320/// &mut add,
321/// 0
322/// );
323/// let sum = quasigroup.with(1, 2);
324/// assert!(sum.is_ok());
325/// assert!(sum.unwrap() == 3);
326/// ```
327pub struct Loop<'a, T> {
328 aset: AlgaeSet<T>,
329 binop: &'a mut dyn BinaryOperation<T>,
330 identity: T,
331}
332
333impl<'a, T: Copy + PartialEq> Loop<'a, T> {
334 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>, identity: T) -> Self {
335 assert!(binop.is(PropertyType::Cancellative));
336 assert!(binop.is(PropertyType::WithIdentity(identity)));
337 Self {
338 aset,
339 binop,
340 identity,
341 }
342 }
343}
344
345impl<'a, T: Copy + PartialEq> Magmoid<T> for Loop<'a, T> {
346 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
347 self.binop
348 }
349}
350
351impl<'a, T: Copy + PartialEq> From<Loop<'a, T>> for Magma<'a, T> {
352 fn from(loop_: Loop<'a, T>) -> Magma<'a, T> {
353 Magma::new(loop_.aset, loop_.binop)
354 }
355}
356
357impl<'a, T: Copy + PartialEq> From<Loop<'a, T>> for UnitalMagma<'a, T> {
358 fn from(loop_: Loop<'a, T>) -> UnitalMagma<'a, T> {
359 UnitalMagma::new(loop_.aset, loop_.binop, loop_.identity)
360 }
361}
362
363impl<'a, T: Copy + PartialEq> From<Loop<'a, T>> for Quasigroup<'a, T> {
364 fn from(loop_: Loop<'a, T>) -> Quasigroup<'a, T> {
365 Quasigroup::new(loop_.aset, loop_.binop)
366 }
367}
368
369/// A monoid with inverses.
370///
371/// [`Group`] is a representation of the abstract algebraic group.
372/// Associativity, invertibility, and identity preservation are all required
373/// of its binary operation. Its construction involves a set (specifically an
374/// [`AlgaeSet`]) and a [`BinaryOperation`] with the aforementioned properties.
375///
376/// # Examples
377///
378/// ```
379/// use algae_rs::algaeset::AlgaeSet;
380/// use algae_rs::mapping::{BinaryOperation, GroupOperation};
381/// use algae_rs::magma::{Magmoid, Group};
382///
383/// let mut add = GroupOperation::new(&|a, b| a + b, &|a, b| a - b, 0);
384/// let mut group = Group::new(AlgaeSet::<i32>::all(), &mut add, 0);
385///
386/// let sum = group.with(1, 2);
387/// assert!(sum.is_ok());
388/// assert!(sum.unwrap() == 3);
389///
390/// let difference = group.with(1, -1);
391/// assert!(difference.is_ok());
392/// assert!(difference.unwrap() == 0);
393///
394/// let mut bad_add = GroupOperation::new(&|a, b| a + b, &|a, b| a * b, 0);
395/// let mut bad_group = Group::new(AlgaeSet::<i32>::all(), &mut bad_add, 0);
396///
397/// let bad_sum = bad_group.with(3, 2);
398/// assert!(bad_sum.is_err());
399///
400/// let bad_difference = bad_group.with(1, -1);
401/// assert!(bad_difference.is_err());
402/// ```
403pub struct Group<'a, T> {
404 aset: AlgaeSet<T>,
405 binop: &'a mut dyn BinaryOperation<T>,
406 identity: T,
407}
408
409impl<'a, T: Copy + PartialEq> Group<'a, T> {
410 pub fn new(aset: AlgaeSet<T>, binop: &'a mut dyn BinaryOperation<T>, identity: T) -> Self {
411 assert!(binop.is(PropertyType::Associative));
412 assert!(binop.is(PropertyType::WithIdentity(identity)));
413 assert!(binop_is_invertible(binop));
414 assert!(binop_has_invertible_identity(binop, identity));
415 Self {
416 aset,
417 binop,
418 identity,
419 }
420 }
421}
422
423impl<'a, T: Copy + PartialEq> Magmoid<T> for Group<'a, T> {
424 fn binop(&mut self) -> &mut dyn BinaryOperation<T> {
425 self.binop
426 }
427}
428
429impl<'a, T> From<Group<'a, T>> for Magma<'a, T> {
430 fn from(group: Group<'a, T>) -> Magma<'a, T> {
431 Magma::new(group.aset, group.binop)
432 }
433}
434
435impl<'a, T: Copy + PartialEq> From<Group<'a, T>> for UnitalMagma<'a, T> {
436 fn from(group: Group<'a, T>) -> UnitalMagma<'a, T> {
437 UnitalMagma::new(group.aset, group.binop, group.identity)
438 }
439}
440
441impl<'a, T: Copy + PartialEq> From<Group<'a, T>> for Quasigroup<'a, T> {
442 fn from(group: Group<'a, T>) -> Quasigroup<'a, T> {
443 Quasigroup::new(group.aset, group.binop)
444 }
445}