Skip to main content

fp_library/classes/
semiring.rs

1//! Types that form a semiring with addition and multiplication operations.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::classes::Semiring;
7//!
8//! assert_eq!(i32::add(2, 3), 5);
9//! assert_eq!(i32::multiply(2, 3), 6);
10//! assert_eq!(i32::zero(), 0);
11//! assert_eq!(i32::one(), 1);
12//! ```
13
14#[fp_macros::document_module]
15mod inner {
16	use fp_macros::*;
17
18	/// A type class for types that form a semiring.
19	///
20	/// A semiring provides two binary operations (addition and multiplication)
21	/// with their respective identity elements (zero and one).
22	///
23	/// ### Laws
24	///
25	/// * Commutative monoid under addition:
26	///   - `add(a, add(b, c)) = add(add(a, b), c)` (associativity)
27	///   - `add(zero, a) = a` and `add(a, zero) = a` (identity)
28	///   - `add(a, b) = add(b, a)` (commutativity)
29	/// * Monoid under multiplication:
30	///   - `multiply(a, multiply(b, c)) = multiply(multiply(a, b), c)` (associativity)
31	///   - `multiply(one, a) = a` and `multiply(a, one) = a` (identity)
32	/// * Left distributivity: `multiply(a, add(b, c)) = add(multiply(a, b), multiply(a, c))`
33	/// * Right distributivity: `multiply(add(a, b), c) = add(multiply(a, c), multiply(b, c))`
34	/// * Annihilation: `multiply(zero, a) = multiply(a, zero) = zero`
35	///
36	/// **Note:** Integer types do not strictly satisfy these laws due to overflow.
37	#[document_examples]
38	///
39	/// ```
40	/// use fp_library::classes::Semiring;
41	///
42	/// // Distributivity: multiply(a, add(b, c)) = add(multiply(a, b), multiply(a, c))
43	/// let a = 2i32;
44	/// let b = 3i32;
45	/// let c = 4i32;
46	/// assert_eq!(
47	/// 	i32::multiply(a, i32::add(b, c)),
48	/// 	i32::add(i32::multiply(a, b), i32::multiply(a, c)),
49	/// );
50	/// ```
51	pub trait Semiring {
52		/// Adds two values.
53		#[document_signature]
54		///
55		#[document_parameters("The first value.", "The second value.")]
56		///
57		#[document_returns("The sum of the two values.")]
58		#[document_examples]
59		///
60		/// ```
61		/// use fp_library::classes::Semiring;
62		///
63		/// assert_eq!(i32::add(2, 3), 5);
64		/// ```
65		fn add(
66			a: Self,
67			b: Self,
68		) -> Self;
69
70		/// Returns the additive identity element.
71		#[document_signature]
72		///
73		#[document_returns("The additive identity (zero).")]
74		#[document_examples]
75		///
76		/// ```
77		/// use fp_library::classes::Semiring;
78		///
79		/// assert_eq!(i32::zero(), 0);
80		/// ```
81		fn zero() -> Self;
82
83		/// Multiplies two values.
84		#[document_signature]
85		///
86		#[document_parameters("The first value.", "The second value.")]
87		///
88		#[document_returns("The product of the two values.")]
89		#[document_examples]
90		///
91		/// ```
92		/// use fp_library::classes::Semiring;
93		///
94		/// assert_eq!(i32::multiply(2, 3), 6);
95		/// ```
96		fn multiply(
97			a: Self,
98			b: Self,
99		) -> Self;
100
101		/// Returns the multiplicative identity element.
102		#[document_signature]
103		///
104		#[document_returns("The multiplicative identity (one).")]
105		#[document_examples]
106		///
107		/// ```
108		/// use fp_library::classes::Semiring;
109		///
110		/// assert_eq!(i32::one(), 1);
111		/// ```
112		fn one() -> Self;
113	}
114
115	/// Adds two values.
116	///
117	/// Free function version that dispatches to [`Semiring::add`].
118	#[document_signature]
119	///
120	#[document_type_parameters("The semiring type.")]
121	///
122	#[document_parameters("The first value.", "The second value.")]
123	///
124	#[document_returns("The sum of the two values.")]
125	#[document_examples]
126	///
127	/// ```
128	/// use fp_library::classes::semiring::add;
129	///
130	/// assert_eq!(add(2i32, 3), 5);
131	/// ```
132	pub fn add<S: Semiring>(
133		a: S,
134		b: S,
135	) -> S {
136		S::add(a, b)
137	}
138
139	/// Returns the additive identity element.
140	///
141	/// Free function version that dispatches to [`Semiring::zero`].
142	#[document_signature]
143	///
144	#[document_type_parameters("The semiring type.")]
145	///
146	#[document_returns("The additive identity (zero).")]
147	#[document_examples]
148	///
149	/// ```
150	/// use fp_library::classes::semiring::zero;
151	///
152	/// assert_eq!(zero::<i32>(), 0);
153	/// ```
154	pub fn zero<S: Semiring>() -> S {
155		S::zero()
156	}
157
158	/// Multiplies two values.
159	///
160	/// Free function version that dispatches to [`Semiring::multiply`].
161	#[document_signature]
162	///
163	#[document_type_parameters("The semiring type.")]
164	///
165	#[document_parameters("The first value.", "The second value.")]
166	///
167	#[document_returns("The product of the two values.")]
168	#[document_examples]
169	///
170	/// ```
171	/// use fp_library::classes::semiring::multiply;
172	///
173	/// assert_eq!(multiply(2i32, 3), 6);
174	/// ```
175	pub fn multiply<S: Semiring>(
176		a: S,
177		b: S,
178	) -> S {
179		S::multiply(a, b)
180	}
181
182	/// Returns the multiplicative identity element.
183	///
184	/// Free function version that dispatches to [`Semiring::one`].
185	#[document_signature]
186	///
187	#[document_type_parameters("The semiring type.")]
188	///
189	#[document_returns("The multiplicative identity (one).")]
190	#[document_examples]
191	///
192	/// ```
193	/// use fp_library::classes::semiring::one;
194	///
195	/// assert_eq!(one::<i32>(), 1);
196	/// ```
197	pub fn one<S: Semiring>() -> S {
198		S::one()
199	}
200
201	macro_rules! impl_semiring_int {
202		($($t:ty),+) => {
203			$(
204				impl Semiring for $t {
205					/// Adds two values using wrapping addition.
206					#[document_signature]
207					///
208					#[document_parameters("The first value.", "The second value.")]
209					///
210					#[document_returns("The sum (wrapping on overflow).")]
211					#[document_examples]
212					///
213					/// ```
214					#[doc = concat!("use fp_library::classes::Semiring;")]
215					///
216					#[doc = concat!("assert_eq!(<", stringify!($t), ">::add(2 as ", stringify!($t), ", 3 as ", stringify!($t), "), 5 as ", stringify!($t), ");")]
217					/// ```
218					fn add(
219						a: Self,
220						b: Self,
221					) -> Self {
222						a.wrapping_add(b)
223					}
224
225					/// Returns the additive identity (`0`).
226					#[document_signature]
227					///
228					#[document_returns("Zero.")]
229					#[document_examples]
230					///
231					/// ```
232					#[doc = concat!("use fp_library::classes::Semiring;")]
233					///
234					#[doc = concat!("assert_eq!(<", stringify!($t), ">::zero(), 0 as ", stringify!($t), ");")]
235					/// ```
236					fn zero() -> Self {
237						0
238					}
239
240					/// Multiplies two values using wrapping multiplication.
241					#[document_signature]
242					///
243					#[document_parameters("The first value.", "The second value.")]
244					///
245					#[document_returns("The product (wrapping on overflow).")]
246					#[document_examples]
247					///
248					/// ```
249					#[doc = concat!("use fp_library::classes::Semiring;")]
250					///
251					#[doc = concat!("assert_eq!(<", stringify!($t), ">::multiply(2 as ", stringify!($t), ", 3 as ", stringify!($t), "), 6 as ", stringify!($t), ");")]
252					/// ```
253					fn multiply(
254						a: Self,
255						b: Self,
256					) -> Self {
257						a.wrapping_mul(b)
258					}
259
260					/// Returns the multiplicative identity (`1`).
261					#[document_signature]
262					///
263					#[document_returns("One.")]
264					#[document_examples]
265					///
266					/// ```
267					#[doc = concat!("use fp_library::classes::Semiring;")]
268					///
269					#[doc = concat!("assert_eq!(<", stringify!($t), ">::one(), 1 as ", stringify!($t), ");")]
270					/// ```
271					fn one() -> Self {
272						1
273					}
274				}
275			)+
276		};
277	}
278
279	impl_semiring_int!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
280
281	macro_rules! impl_semiring_float {
282		($($t:ty),+) => {
283			$(
284				impl Semiring for $t {
285					/// Adds two values using the `+` operator.
286					#[document_signature]
287					///
288					#[document_parameters("The first value.", "The second value.")]
289					///
290					#[document_returns("The sum.")]
291					#[document_examples]
292					///
293					/// ```
294					#[doc = concat!("use fp_library::classes::Semiring;")]
295					///
296					#[doc = concat!("assert_eq!(<", stringify!($t), ">::add(2.0 as ", stringify!($t), ", 3.0 as ", stringify!($t), "), 5.0 as ", stringify!($t), ");")]
297					/// ```
298					fn add(
299						a: Self,
300						b: Self,
301					) -> Self {
302						a + b
303					}
304
305					/// Returns the additive identity (`0.0`).
306					#[document_signature]
307					///
308					#[document_returns("Zero.")]
309					#[document_examples]
310					///
311					/// ```
312					#[doc = concat!("use fp_library::classes::Semiring;")]
313					///
314					#[doc = concat!("assert_eq!(<", stringify!($t), ">::zero(), 0.0 as ", stringify!($t), ");")]
315					/// ```
316					fn zero() -> Self {
317						0.0
318					}
319
320					/// Multiplies two values using the `*` operator.
321					#[document_signature]
322					///
323					#[document_parameters("The first value.", "The second value.")]
324					///
325					#[document_returns("The product.")]
326					#[document_examples]
327					///
328					/// ```
329					#[doc = concat!("use fp_library::classes::Semiring;")]
330					///
331					#[doc = concat!("assert_eq!(<", stringify!($t), ">::multiply(2.0 as ", stringify!($t), ", 3.0 as ", stringify!($t), "), 6.0 as ", stringify!($t), ");")]
332					/// ```
333					fn multiply(
334						a: Self,
335						b: Self,
336					) -> Self {
337						a * b
338					}
339
340					/// Returns the multiplicative identity (`1.0`).
341					#[document_signature]
342					///
343					#[document_returns("One.")]
344					#[document_examples]
345					///
346					/// ```
347					#[doc = concat!("use fp_library::classes::Semiring;")]
348					///
349					#[doc = concat!("assert_eq!(<", stringify!($t), ">::one(), 1.0 as ", stringify!($t), ");")]
350					/// ```
351					fn one() -> Self {
352						1.0
353					}
354				}
355			)+
356		};
357	}
358
359	impl_semiring_float!(f32, f64);
360}
361
362pub use inner::*;