feanor_math/ring.rs
1use std::ops::Deref;
2
3use crate::homomorphism::*;
4use crate::ordered::OrderedRingStore;
5use crate::primitive_int::StaticRing;
6use crate::integer::*;
7use crate::algorithms;
8
9use serde::{Serialize, Deserialize};
10
11///
12/// Describes the context in which to print an algebraic expression.
13/// It is usually used to determine when to use parenthesis during printing.
14///
15/// # Example
16/// ```rust
17/// # use feanor_math::ring::*;
18/// # use feanor_math::rings::poly::*;
19/// # use feanor_math::primitive_int::*;
20/// # use feanor_math::rings::poly::dense_poly::*;
21/// struct CustomDisplay<'a>(&'a DensePolyRing<StaticRing<i64>>, &'a El<DensePolyRing<StaticRing<i64>>>, EnvBindingStrength);
22/// impl<'a> std::fmt::Display for CustomDisplay<'a> {
23/// fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
24/// self.0.get_ring().dbg_within(self.1, formatter, self.2)
25/// }
26/// }
27/// let poly_ring = DensePolyRing::new(StaticRing::<i64>::RING, "X");
28/// let f = poly_ring.add(poly_ring.one(), poly_ring.indeterminate());
29/// assert_eq!("X + 1", format!("{}", CustomDisplay(&poly_ring, &f, EnvBindingStrength::Weakest)));
30/// assert_eq!("X + 1", format!("{}", CustomDisplay(&poly_ring, &f, EnvBindingStrength::Sum)));
31/// assert_eq!("(X + 1)", format!("{}", CustomDisplay(&poly_ring, &f, EnvBindingStrength::Product)));
32/// assert_eq!("(X + 1)", format!("{}", CustomDisplay(&poly_ring, &f, EnvBindingStrength::Power)));
33/// assert_eq!("(X + 1)", format!("{}", CustomDisplay(&poly_ring, &f, EnvBindingStrength::Strongest)));
34/// ```
35///
36#[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
37pub enum EnvBindingStrength {
38 ///
39 /// The weakest possible binding strength, i.e. never add parenthesis.
40 ///
41 Weakest,
42 ///
43 /// Binding strength of addition (and subtraction), i.e. only add parenthesis
44 /// if the expression includes an operation that binds weaker than `+` (I cannot
45 /// think of any example, this seems to be a rare situation).
46 ///
47 Sum,
48 ///
49 /// Binding strength of multiplication (and division), i.e. only add parenthesis if
50 /// the expression includes an operation that binds weaker than `*` (Standard example
51 /// would be `+`).
52 ///
53 Product,
54 ///
55 /// Binding strength of powering, i.e. only add parenthesis if the expression
56 /// includes an operation that binds weaker than exponentiation (Standard examples would
57 /// be `+` or `*`).
58 ///
59 Power,
60 ///
61 /// The strongest possible binding strength, i.e. always add parenthesis.
62 ///
63 Strongest
64}
65
66///
67/// Basic trait for objects that have a ring structure. This trait is
68/// implementor-facing, so designed to be used for implementing new
69/// rings.
70///
71/// Implementors of this trait should provide the basic ring operations,
72/// and additionally operators for displaying and equality testing. If
73/// a performance advantage can be achieved by accepting some arguments by
74/// reference instead of by value, the default-implemented functions for
75/// ring operations on references should be overwritten.
76///
77/// # Relationship with [`RingStore`]
78///
79/// Note that usually, this trait will not be used directly, but always
80/// through a [`RingStore`]. In more detail, while this trait
81/// defines the functionality, [`RingStore`] allows abstracting
82/// the storage - everything that allows access to a ring then is a
83/// [`RingStore`], as for example, references or shared pointers
84/// to rings. If you want to use rings directly by value, some technical
85/// details make it necessary to use the no-op container [`RingStore`].
86/// For more detail, see the documentation of [`RingStore`].
87///
88/// # A note on equality
89///
90/// Generally speaking, the notion of being canonically isomorphic
91/// (given by [`CanIsoFromTo`] is often more useful for rings than
92/// equality (defined by [`PartialEq`]).
93///
94/// In particular, being canonically isomorphic means that that there
95/// is a bidirectional mapping of elements `a in Ring1 <-> b in Ring2`
96/// such that `a` and `b` behave exactly the same. This mapping is provided
97/// by the functions of [`CanIsoFromTo`]. Note that every ring is supposed
98/// to be canonically isomorphic to itself, via the identiy mapping.
99///
100/// The notion of equality is stronger than that. In particular, implementors
101/// of [`PartialEq`] must ensure that if rings `R` and `S` are equal, then
102/// they are canonically isomorphic and the canonical isomorphism is given
103/// by bitwise identity map. In particular, elements of `R` and `S` must have
104/// the same type.
105///
106/// Hence, be careful to not mix up elements of different rings, even if they
107/// have the same type. This can easily lead to nasty errors. For example,
108/// consider the following code
109/// ```rust
110/// # use feanor_math::ring::*;
111/// # use feanor_math::homomorphism::*;
112/// # use feanor_math::primitive_int::*;
113/// # use feanor_math::rings::zn::*;
114/// let Z7 = zn_big::Zn::new(StaticRing::<i64>::RING, 7);
115/// let Z11 = zn_big::Zn::new(StaticRing::<i64>::RING, 11);
116/// assert!(Z11.get_ring() != Z7.get_ring());
117/// let neg_one = Z7.int_hom().map(-1);
118/// assert!(!Z11.is_neg_one(&neg_one));
119/// ```
120/// It is even allowed that both rings are isomorphic, and might be expected
121/// to be intuitively "the same", but still they are considered unequal, and
122/// swapping elements leads to incorrect results.
123///
124/// However, swapping elements between rings is well-defined and correct if they are "equal"
125/// as given by `PartialEq` (not just canonically isomorphic)
126/// ```rust
127/// # use feanor_math::ring::*;
128/// # use feanor_math::homomorphism::*;
129/// # use feanor_math::primitive_int::*;
130/// # use feanor_math::rings::zn::*;
131/// let Z11_fst = zn_big::Zn::new(StaticRing::<i64>::RING, 7);
132/// let Z11_snd = Z11_fst.clone();
133/// assert!(Z11_fst.get_ring() == Z11_snd.get_ring());
134/// let neg_one = Z11_fst.int_hom().map(-1);
135/// assert!(Z11_fst.is_neg_one(&neg_one));
136/// ```
137///
138/// # Example
139///
140/// An example implementation of a new, very useless ring type that represents
141/// 32-bit integers stored on the heap.
142/// ```rust
143/// # use feanor_math::ring::*;
144/// # use feanor_math::homomorphism::*;
145/// # use feanor_math::integer::*;
146///
147/// #[derive(PartialEq)]
148/// struct MyRingBase;
149///
150/// impl RingBase for MyRingBase {
151///
152/// type Element = Box<i32>;
153///
154/// fn clone_el(&self, val: &Self::Element) -> Self::Element { val.clone() }
155///
156/// fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { **lhs += *rhs; }
157///
158/// fn negate_inplace(&self, lhs: &mut Self::Element) { **lhs = -**lhs; }
159///
160/// fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { **lhs *= *rhs; }
161///
162/// fn from_int(&self, value: i32) -> Self::Element { Box::new(value) }
163///
164/// fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool { **lhs == **rhs }
165///
166/// fn is_commutative(&self) -> bool { true }
167/// fn is_noetherian(&self) -> bool { true }
168/// fn is_approximate(&self) -> bool { false }
169///
170/// fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
171/// write!(out, "{}", **value)
172/// }
173///
174/// fn characteristic<I>(&self, ZZ: I) -> Option<El<I>>
175/// where I: RingStore + Copy, I::Type: IntegerRing
176/// {
177/// Some(ZZ.zero())
178/// }
179/// }
180///
181/// // To use the ring through a RingStore, it is also required to implement CanHomFrom<Self>
182/// // and CanIsoFromTo<Self>.
183///
184/// impl CanHomFrom<MyRingBase> for MyRingBase {
185///
186/// type Homomorphism = ();
187///
188/// fn has_canonical_hom(&self, _from: &MyRingBase) -> Option<()> { Some(()) }
189///
190/// fn map_in(&self, _from: &MyRingBase, el: Self::Element, _: &()) -> Self::Element { el }
191/// }
192///
193/// impl CanIsoFromTo<MyRingBase> for MyRingBase {
194///
195/// type Isomorphism = ();
196///
197/// fn has_canonical_iso(&self, _from: &MyRingBase) -> Option<()> { Some(()) }
198///
199/// fn map_out(&self, _from: &MyRingBase, el: Self::Element, _: &()) -> Self::Element { el }
200/// }
201///
202/// // A type alias for the simple, by-value RingStore.
203/// pub type MyRing = RingValue<MyRingBase>;
204///
205/// impl MyRingBase {
206///
207/// pub const RING: MyRing = RingValue::from(MyRingBase);
208/// }
209///
210/// let ring = MyRingBase::RING;
211/// assert!(ring.eq_el(
212/// &ring.int_hom().map(6),
213/// &ring.mul(ring.int_hom().map(3), ring.int_hom().map(2))
214/// ));
215/// ```
216///
217/// TODO: on next breaking release restrict with `: Debug`
218///
219#[allow(missing_docs)]
220pub trait RingBase: PartialEq {
221
222 ///
223 /// Type of elements of the ring
224 ///
225 type Element: Sized;
226
227 fn clone_el(&self, val: &Self::Element) -> Self::Element;
228 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { self.add_assign(lhs, self.clone_el(rhs)) }
229 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element);
230 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { self.sub_assign(lhs, self.clone_el(rhs)) }
231 fn negate_inplace(&self, lhs: &mut Self::Element);
232 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element);
233 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { self.mul_assign(lhs, self.clone_el(rhs)) }
234 fn zero(&self) -> Self::Element { self.from_int(0) }
235 fn one(&self) -> Self::Element { self.from_int(1) }
236 fn neg_one(&self) -> Self::Element { self.from_int(-1) }
237 fn from_int(&self, value: i32) -> Self::Element;
238 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool;
239 fn is_zero(&self, value: &Self::Element) -> bool { self.eq_el(value, &self.zero()) }
240 fn is_one(&self, value: &Self::Element) -> bool { self.eq_el(value, &self.one()) }
241 fn is_neg_one(&self, value: &Self::Element) -> bool { self.eq_el(value, &self.neg_one()) }
242
243 ///
244 /// Fused-multiply-add. This computes `summand + lhs * rhs`.
245 ///
246 fn fma(&self, lhs: &Self::Element, rhs: &Self::Element, summand: Self::Element) -> Self::Element {
247 self.add(summand, self.mul_ref(lhs, rhs))
248 }
249
250 ///
251 /// Returns whether the ring is commutative, i.e. `a * b = b * a` for all elements `a, b`.
252 /// Note that addition is assumed to be always commutative.
253 ///
254 fn is_commutative(&self) -> bool;
255
256 ///
257 /// Returns whether the ring is noetherian, i.e. every ideal is finitely generated.
258 ///
259 /// Rings for which this is not the case are a exceptional situation in computer
260 /// algebra, since they are usually "very large" and hard to work with. Examples for
261 /// non-noetherian rings could be the polynomial ring in infinitely many variables
262 /// `Z[X1, X2, X3, ...]` or the ring of algebraic integers.
263 ///
264 fn is_noetherian(&self) -> bool;
265
266 ///
267 /// Returns whether this ring computes with approximations to elements.
268 /// This would usually be the case for rings that are based on `f32` or
269 /// `f64`, to represent real or complex numbers.
270 ///
271 /// Note that these rings cannot provide implementations for [`RingBase::eq_el()`],
272 /// [`RingBase::is_zero()`] etc, and hence are of limited use in this crate.
273 /// Currently, the only way how approximate rings are used is a complex-valued
274 /// fast Fourier transform, via [`crate::rings::float_complex::Complex64`].
275 ///
276 fn is_approximate(&self) -> bool;
277
278 ///
279 /// Writes a human-readable representation of `value` to `out`.
280 ///
281 /// Used by [`RingStore::format()`], [`RingStore::println()`] and the implementations of [`std::fmt::Debug`]
282 /// and [`std::fmt::Display`] of [`crate::wrapper::RingElementWrapper`].
283 ///
284 fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
285 self.dbg_within(value, out, EnvBindingStrength::Weakest)
286 }
287
288 ///
289 /// Writes a human-readable representation of `value` to `out`, taking into account the possible context
290 /// to place parenthesis as needed.
291 ///
292 /// See also [`RingBase::dbg()`] and [`EnvBindingStrength`].
293 ///
294 /// Used by [`RingStore::format()`], [`RingStore::println()`] and the implementations of [`std::fmt::Debug`]
295 /// and [`std::fmt::Display`] of [`crate::wrapper::RingElementWrapper`].
296 ///
297 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _env: EnvBindingStrength) -> std::fmt::Result;
298
299 fn square(&self, value: &mut Self::Element) {
300 self.mul_assign(value, self.clone_el(value));
301 }
302
303 fn negate(&self, mut value: Self::Element) -> Self::Element {
304 self.negate_inplace(&mut value);
305 return value;
306 }
307
308 fn sub_assign(&self, lhs: &mut Self::Element, mut rhs: Self::Element) {
309 self.negate_inplace(&mut rhs);
310 self.add_assign(lhs, rhs);
311 }
312
313 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
314 self.mul_assign(lhs, self.from_int(rhs));
315 }
316
317 fn mul_int(&self, mut lhs: Self::Element, rhs: i32) -> Self::Element {
318 self.mul_assign_int(&mut lhs, rhs);
319 return lhs;
320 }
321
322 fn mul_int_ref(&self, lhs: &Self::Element, rhs: i32) -> Self::Element {
323 self.mul_int(self.clone_el(lhs), rhs)
324 }
325
326 ///
327 /// Fused-multiply-add with an integer. This computes `summand + lhs * rhs`.
328 ///
329 fn fma_int(&self, lhs: &Self::Element, rhs: i32, summand: Self::Element) -> Self::Element {
330 self.add(summand, self.mul_int_ref(lhs, rhs))
331 }
332
333 ///
334 /// Computes `lhs := rhs - lhs`.
335 ///
336 fn sub_self_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
337 self.negate_inplace(lhs);
338 self.add_assign(lhs, rhs);
339 }
340
341 ///
342 /// Computes `lhs := rhs - lhs`.
343 ///
344 fn sub_self_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
345 self.negate_inplace(lhs);
346 self.add_assign_ref(lhs, rhs);
347 }
348
349 fn add_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
350 let mut result = self.clone_el(lhs);
351 self.add_assign_ref(&mut result, rhs);
352 return result;
353 }
354
355 fn add_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
356 self.add_assign_ref(&mut rhs, lhs);
357 return rhs;
358 }
359
360 fn add_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
361 self.add_assign_ref(&mut lhs, rhs);
362 return lhs;
363 }
364
365 fn add(&self, mut lhs: Self::Element, rhs: Self::Element) -> Self::Element {
366 self.add_assign(&mut lhs, rhs);
367 return lhs;
368 }
369
370 fn sub_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
371 let mut result = self.clone_el(lhs);
372 self.sub_assign_ref(&mut result, rhs);
373 return result;
374 }
375
376 fn sub_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
377 self.sub_assign_ref(&mut rhs, lhs);
378 self.negate_inplace(&mut rhs);
379 return rhs;
380 }
381
382 fn sub_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
383 self.sub_assign_ref(&mut lhs, rhs);
384 return lhs;
385 }
386
387 fn sub(&self, mut lhs: Self::Element, rhs: Self::Element) -> Self::Element {
388 self.sub_assign(&mut lhs, rhs);
389 return lhs;
390 }
391
392 fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
393 let mut result = self.clone_el(lhs);
394 self.mul_assign_ref(&mut result, rhs);
395 return result;
396 }
397
398 fn mul_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
399 if self.is_commutative() {
400 self.mul_assign_ref(&mut rhs, lhs);
401 return rhs;
402 } else {
403 let mut result = self.clone_el(lhs);
404 self.mul_assign(&mut result, rhs);
405 return result;
406 }
407 }
408
409 fn mul_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
410 self.mul_assign_ref(&mut lhs, rhs);
411 return lhs;
412 }
413
414 fn mul(&self, mut lhs: Self::Element, rhs: Self::Element) -> Self::Element {
415 self.mul_assign(&mut lhs, rhs);
416 return lhs;
417 }
418
419 ///
420 /// Raises `x` to the power of an arbitrary, nonnegative integer given by
421 /// a custom integer ring implementation.
422 ///
423 /// Unless overriden by implementors, this uses a square-and-multiply approach
424 /// to achieve running time O(log(power)).
425 ///
426 /// # Panic
427 ///
428 /// This may panic if `power` is negative.
429 ///
430 fn pow_gen<R: RingStore>(&self, x: Self::Element, power: &El<R>, integers: R) -> Self::Element
431 where R::Type: IntegerRing
432 {
433 assert!(!integers.is_neg(power));
434 algorithms::sqr_mul::generic_pow_shortest_chain_table(
435 x,
436 power,
437 &integers,
438 |a| {
439 let mut a_copy = self.clone_el(a);
440 self.square(&mut a_copy);
441 Ok(a_copy)
442 },
443 |a, b| Ok(self.mul_ref(a, b)),
444 |a| self.clone_el(a),
445 self.one()
446 ).unwrap_or_else(|x| x)
447 }
448
449 ///
450 /// Sums the elements given by the iterator.
451 ///
452 /// The implementation might be as simple as `els.fold(self.zero(), |a, b| self.add(a, b))`, but
453 /// can be more efficient than that in some cases.
454 ///
455 fn sum<I>(&self, els: I) -> Self::Element
456 where I: IntoIterator<Item = Self::Element>
457 {
458 els.into_iter().fold(self.zero(), |a, b| self.add(a, b))
459 }
460
461 ///
462 /// Computes the product of the elements given by the iterator.
463 ///
464 /// The implementation might be as simple as `els.fold(self.one(), |a, b| self.mul(a, b))`, but
465 /// can be more efficient than that in some cases.
466 ///
467 fn prod<I>(&self, els: I) -> Self::Element
468 where I: IntoIterator<Item = Self::Element>
469 {
470 els.into_iter().fold(self.one(), |a, b| self.mul(a, b))
471 }
472
473 ///
474 /// Returns the characteristic of this ring as an element of the given
475 /// implementation of `ZZ`.
476 ///
477 /// If `None` is returned, this means the given integer ring might not be able
478 /// to represent the characteristic. This must never happen if the given implementation
479 /// of `ZZ` allows for unbounded integers (like [`crate::integer::BigIntRing`]).
480 /// In other cases however, we allow to perform the size check heuristically only,
481 /// so this might return `None` even in some cases where the integer ring would in
482 /// fact be able to represent the characteristic.
483 ///
484 /// # Example
485 /// ```rust
486 /// # use feanor_math::ring::*;
487 /// # use feanor_math::primitive_int::*;
488 /// # use feanor_math::rings::zn::*;
489 /// let ZZ = StaticRing::<i16>::RING;
490 /// assert_eq!(Some(0), StaticRing::<i64>::RING.characteristic(&ZZ));
491 /// assert_eq!(None, zn_64::Zn::new(i16::MAX as u64 + 1).characteristic(&ZZ));
492 /// assert_eq!(Some(i16::MAX), zn_64::Zn::new(i16::MAX as u64).characteristic(&ZZ));
493 /// ```
494 ///
495 fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
496 where I::Type: IntegerRing;
497}
498
499///
500/// Used to easily implement functions in the trait definition of
501/// [`RingStore`] and its subtraits to delegate the call to the same
502/// function of the underlying [`RingBase`].
503///
504/// # Example
505/// ```rust
506/// # use feanor_math::ring::*;
507/// # #[macro_use] use feanor_math::delegate;
508///
509/// trait WeirdRingBase: RingBase {
510/// fn foo(&self) -> Self::Element;
511/// }
512///
513/// trait WeirdRingStore: RingStore
514/// where Self::Type: WeirdRingBase
515/// {
516/// delegate!{ WeirdRingBase, fn foo(&self) -> El<Self> }
517/// }
518/// ```
519///
520/// # Limitations
521///
522/// This macro does not work if the function takes generic parameters.
523/// In this case, write the delegation manually.
524///
525#[macro_export]
526macro_rules! delegate {
527 ($base_trait:ty, fn $name:ident (&self, $($pname:ident: $ptype:ty),*) -> $rtype:ty) => {
528 #[doc = concat!(" See [`", stringify!($base_trait), "::", stringify!($name), "()`]")]
529 fn $name (&self, $($pname: $ptype),*) -> $rtype {
530 <Self::Type as $base_trait>::$name(self.get_ring(), $($pname),*)
531 }
532 };
533 ($base_trait:ty, fn $name:ident (&self) -> $rtype:ty) => {
534 #[doc = concat!(" See [`", stringify!($base_trait), "::", stringify!($name), "()`]")]
535 fn $name (&self) -> $rtype {
536 <Self::Type as $base_trait>::$name(self.get_ring())
537 }
538 };
539}
540
541///
542/// Variant of `assert_eq!` for ring elements, i.e. assert that two ring elements are equal.
543/// Frequently used in tests
544///
545/// # Example
546/// ```rust
547/// # use feanor_math::ring::*;
548/// # use feanor_math::primitive_int::*;
549/// # use feanor_math::assert_el_eq;
550///
551/// assert_el_eq!(StaticRing::<i32>::RING, 3, 3);
552/// // is equivalent to
553/// assert_eq!(3, 3);
554/// ```
555/// If the ring elements are not comparable on their own, this is really useful
556/// ```rust
557/// # use feanor_math::ring::*;
558/// # use feanor_math::homomorphism::*;
559/// # use feanor_math::integer::*;
560/// # use feanor_math::assert_el_eq;
561/// // this does not have an equivalent representation with assert_eq!
562/// assert_el_eq!(BigIntRing::RING, BigIntRing::RING.int_hom().map(3), BigIntRing::RING.int_hom().map(3));
563/// ```
564///
565#[macro_export]
566macro_rules! assert_el_eq {
567 ($ring:expr, $lhs:expr, $rhs:expr) => {
568 match (&$ring, &$lhs, &$rhs) {
569 (ring_val, lhs_val, rhs_val) => {
570 assert!(<_ as $crate::ring::RingStore>::eq_el(ring_val, lhs_val, rhs_val), "Assertion failed: {} != {}", <_ as $crate::ring::RingStore>::format(ring_val, lhs_val), <_ as $crate::ring::RingStore>::format(ring_val, rhs_val));
571 }
572 }
573 }
574}
575
576///
577/// Basic trait for objects that store (in some sense) a ring. It can also
578/// be considered the user-facing trait for rings, so rings are always supposed
579/// to be used through a `RingStore`-object.
580///
581/// This can be a ring-by-value, a reference to a ring, or really any object that
582/// provides access to a [`RingBase`] object.
583///
584/// As opposed to [`RingBase`], which is responsible for the
585/// functionality and ring operations, this trait is solely responsible for
586/// the storage. The two basic implementors are [`RingValue`] and [`RingRef`],
587/// which just wrap a value resp. reference to a [`RingBase`] object.
588/// Building on that, every object that wraps a [`RingStore`] object can implement
589/// again [`RingStore`]. This applies in particular to implementors of
590/// `Deref<Target: RingStore>`, for whom there is a blanket implementation.
591///
592/// # Example
593///
594/// ```rust
595/// # use feanor_math::assert_el_eq;
596/// # use feanor_math::ring::*;
597/// # use feanor_math::primitive_int::*;
598/// # use std::rc::Rc;
599/// fn add_in_ring<R: RingStore>(ring: R, a: El<R>, b: El<R>) -> El<R> {
600/// ring.add(a, b)
601/// }
602///
603/// let ring: RingValue<StaticRingBase<i64>> = StaticRing::<i64>::RING;
604/// assert_el_eq!(ring, 7, add_in_ring(ring, 3, 4));
605/// assert_el_eq!(ring, 7, add_in_ring(&ring, 3, 4));
606/// assert_el_eq!(ring, 7, add_in_ring(Rc::new(ring), 3, 4));
607/// ```
608///
609/// # What does this do?
610///
611/// We need a framework that allows nesting rings, e.g. to provide a polynomial ring
612/// over a finite field - say `PolyRing<FiniteRing + Field>`. However, the simplest
613/// implementation
614/// ```rust,ignore
615/// struct PolyRing<BaseRing: Ring> { /* omitted */ }
616/// ```
617/// would have the effect that `PolyRing<FiniteRing + Field>` and `PolyRing<&FiniteRing + Field>`
618/// are entirely different types. While implementing relationships between them
619/// is possible, the approach does not scale well when we consider many rings and
620/// multiple layers of nesting.
621///
622/// # Note for implementors
623///
624/// Generally speaking it is not recommended to overwrite any of the default-implementations
625/// of ring functionality, as this is against the spirit of this trait. Instead,
626/// just provide an implementation of `get_ring()` and put ring functionality in
627/// a custom implementation of [`RingBase`].
628///
629pub trait RingStore: Sized {
630
631 ///
632 /// The type of the stored ring.
633 ///
634 type Type: RingBase + ?Sized;
635
636 ///
637 /// Returns a reference to the stored ring.
638 ///
639 fn get_ring<'a>(&'a self) -> &'a Self::Type;
640
641 delegate!{ RingBase, fn clone_el(&self, val: &El<Self>) -> El<Self> }
642 delegate!{ RingBase, fn add_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
643 delegate!{ RingBase, fn add_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
644 delegate!{ RingBase, fn sub_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
645 delegate!{ RingBase, fn sub_self_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
646 delegate!{ RingBase, fn sub_self_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
647 delegate!{ RingBase, fn negate_inplace(&self, lhs: &mut El<Self>) -> () }
648 delegate!{ RingBase, fn mul_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
649 delegate!{ RingBase, fn mul_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
650 delegate!{ RingBase, fn zero(&self) -> El<Self> }
651 delegate!{ RingBase, fn one(&self) -> El<Self> }
652 delegate!{ RingBase, fn neg_one(&self) -> El<Self> }
653 delegate!{ RingBase, fn eq_el(&self, lhs: &El<Self>, rhs: &El<Self>) -> bool }
654 delegate!{ RingBase, fn is_zero(&self, value: &El<Self>) -> bool }
655 delegate!{ RingBase, fn is_one(&self, value: &El<Self>) -> bool }
656 delegate!{ RingBase, fn is_neg_one(&self, value: &El<Self>) -> bool }
657 delegate!{ RingBase, fn is_commutative(&self) -> bool }
658 delegate!{ RingBase, fn is_noetherian(&self) -> bool }
659 delegate!{ RingBase, fn negate(&self, value: El<Self>) -> El<Self> }
660 delegate!{ RingBase, fn sub_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
661 delegate!{ RingBase, fn add_ref(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
662 delegate!{ RingBase, fn add_ref_fst(&self, lhs: &El<Self>, rhs: El<Self>) -> El<Self> }
663 delegate!{ RingBase, fn add_ref_snd(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
664 delegate!{ RingBase, fn add(&self, lhs: El<Self>, rhs: El<Self>) -> El<Self> }
665 delegate!{ RingBase, fn sub_ref(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
666 delegate!{ RingBase, fn sub_ref_fst(&self, lhs: &El<Self>, rhs: El<Self>) -> El<Self> }
667 delegate!{ RingBase, fn sub_ref_snd(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
668 delegate!{ RingBase, fn sub(&self, lhs: El<Self>, rhs: El<Self>) -> El<Self> }
669 delegate!{ RingBase, fn mul_ref(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
670 delegate!{ RingBase, fn mul_ref_fst(&self, lhs: &El<Self>, rhs: El<Self>) -> El<Self> }
671 delegate!{ RingBase, fn mul_ref_snd(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
672 delegate!{ RingBase, fn mul(&self, lhs: El<Self>, rhs: El<Self>) -> El<Self> }
673 delegate!{ RingBase, fn square(&self, value: &mut El<Self>) -> () }
674 delegate!{ RingBase, fn fma(&self, lhs: &El<Self>, rhs: &El<Self>, summand: El<Self>) -> El<Self> }
675
676 ///
677 /// Tries to map the given element into this ring.
678 ///
679 /// This will internally construct a homomorphism between the rings, using
680 /// [`CanHomFrom`]. Note that if you want to map many elements between the
681 /// same rings, it may be faster to construct the homomorphism only once using
682 /// [`RingStore::can_hom()`].
683 ///
684 fn coerce<S>(&self, from: &S, el: El<S>) -> El<Self>
685 where S: RingStore, Self::Type: CanHomFrom<S::Type>
686 {
687 self.get_ring().map_in(from.get_ring(), el, &self.get_ring().has_canonical_hom(from.get_ring()).unwrap())
688 }
689
690 ///
691 /// Returns the identity map `self -> self`.
692 ///
693 fn into_identity(self) -> Identity<Self> {
694 Identity::new(self)
695 }
696
697 ///
698 /// Returns the identity map `self -> self`.
699 ///
700 fn identity<'a>(&'a self) -> Identity<&'a Self> {
701 self.into_identity()
702 }
703
704 ///
705 /// Returns the canonical homomorphism `from -> self`, if it exists,
706 /// moving both rings into the [`CanHom`] object.
707 ///
708 fn into_can_hom<S>(self, from: S) -> Result<CanHom<S, Self>, (S, Self)>
709 where Self: Sized, S: RingStore, Self::Type: CanHomFrom<S::Type>
710 {
711 CanHom::new(from, self)
712 }
713
714 ///
715 /// Returns the canonical isomorphism `from -> self`, if it exists,
716 /// moving both rings into the [`CanHom`] object.
717 ///
718 fn into_can_iso<S>(self, from: S) -> Result<CanIso<S, Self>, (S, Self)>
719 where Self: Sized, S: RingStore, Self::Type: CanIsoFromTo<S::Type>
720 {
721 CanIso::new(from, self)
722 }
723
724 ///
725 /// Returns the canonical homomorphism `from -> self`, if it exists.
726 ///
727 fn can_hom<'a, S>(&'a self, from: &'a S) -> Option<CanHom<&'a S, &'a Self>>
728 where S: RingStore, Self::Type: CanHomFrom<S::Type>
729 {
730 self.into_can_hom(from).ok()
731 }
732
733 ///
734 /// Returns the canonical isomorphism `from -> self`, if it exists.
735 ///
736 fn can_iso<'a, S>(&'a self, from: &'a S) -> Option<CanIso<&'a S, &'a Self>>
737 where S: RingStore, Self::Type: CanIsoFromTo<S::Type>
738 {
739 self.into_can_iso(from).ok()
740 }
741
742 ///
743 /// Returns the homomorphism `Z -> self` that exists for any ring.
744 ///
745 fn into_int_hom(self) -> IntHom<Self> {
746 IntHom::new(self)
747 }
748
749 ///
750 /// Returns the homomorphism `Z -> self` that exists for any ring.
751 ///
752 fn int_hom<'a>(&'a self) -> IntHom<&'a Self> {
753 self.into_int_hom()
754 }
755
756 ///
757 /// Computes the sum of all elements returned by the iterator.
758 ///
759 /// This is equivalent to
760 /// ```rust
761 /// # use feanor_math::ring::*;
762 /// # use feanor_math::primitive_int::*;
763 /// # use feanor_math::assert_el_eq;
764 /// fn sum<R, I>(ring: R, els: I) -> El<R>
765 /// where R: RingStore,
766 /// I: IntoIterator<Item = El<R>>
767 /// {
768 /// els.into_iter().fold(ring.zero(), |a, b| ring.add(a, b))
769 /// }
770 /// # assert_el_eq!(StaticRing::<i64>::RING, StaticRing::<i64>::RING.sum([1, 2, 5]), sum(StaticRing::<i64>::RING, [1, 2, 5]))
771 /// ```
772 /// but may be faster.
773 ///
774 fn sum<I>(&self, els: I) -> El<Self>
775 where I: IntoIterator<Item = El<Self>>
776 {
777 self.get_ring().sum(els)
778 }
779
780 ///
781 /// Equivalent of [`RingStore::sum()`] if the producer of the ring elements
782 /// can fail, in which case summation is aborted and the error returned.
783 ///
784 #[stability::unstable(feature = "enable")]
785 fn try_sum<I, E>(&self, els: I) -> Result<El<Self>, E>
786 where I: IntoIterator<Item = Result<El<Self>, E>>
787 {
788 let mut error = None;
789 let result = self.get_ring().sum(els.into_iter().map_while(|el| match el {
790 Ok(el) => Some(el),
791 Err(err) => {
792 error = Some(err);
793 None
794 }
795 }));
796 if let Some(err) = error {
797 return Err(err);
798 } else {
799 return Ok(result);
800 }
801 }
802
803 ///
804 /// Computes the product of all elements returned by the iterator.
805 ///
806 /// This is equivalent to
807 /// ```rust
808 /// # use feanor_math::ring::*;
809 /// # use feanor_math::primitive_int::*;
810 /// # use feanor_math::assert_el_eq;
811 /// fn prod<R, I>(ring: R, els: I) -> El<R>
812 /// where R: RingStore,
813 /// I: IntoIterator<Item = El<R>>
814 /// {
815 /// els.into_iter().fold(ring.one(), |a, b| ring.mul(a, b))
816 /// }
817 /// # assert_el_eq!(StaticRing::<i64>::RING, StaticRing::<i64>::RING.prod([1, 2, 5]), prod(StaticRing::<i64>::RING, [1, 2, 5]))
818 /// ```
819 /// but may be faster.
820 ///
821 fn prod<I>(&self, els: I) -> El<Self>
822 where I: IntoIterator<Item = El<Self>>
823 {
824 self.get_ring().prod(els)
825 }
826
827 ///
828 /// Raises the given element to the given power.
829 ///
830 fn pow(&self, mut x: El<Self>, power: usize) -> El<Self> {
831 // special cases to increase performance
832 if power == 0 {
833 return self.one();
834 } else if power == 1 {
835 return x;
836 } else if power == 2 {
837 self.square(&mut x);
838 return x;
839 }
840 self.pow_gen(x, &power.try_into().unwrap(), StaticRing::<i64>::RING)
841 }
842
843 ///
844 /// Raises the given element to the given power, which should be a positive integer
845 /// belonging to an arbitrary [`IntegerRing`].
846 ///
847 /// This can in particular be used to compute exponentiation when the exponent does
848 /// not fit in a `usize`.
849 ///
850 fn pow_gen<R: RingStore>(&self, x: El<Self>, power: &El<R>, integers: R) -> El<Self>
851 where R::Type: IntegerRing
852 {
853 self.get_ring().pow_gen(x, power, integers)
854 }
855
856 ///
857 /// Returns an object that represents the given ring element and implements
858 /// [`std::fmt::Display`], to use as formatting parameter.
859 ///
860 /// # Example
861 /// ```rust
862 /// # use feanor_math::ring::*;
863 /// # use feanor_math::homomorphism::*;
864 /// # use feanor_math::integer::*;
865 /// let ring = BigIntRing::RING;
866 /// let element = ring.int_hom().map(3);
867 /// assert_eq!("3", format!("{}", ring.format(&element)));
868 /// ```
869 ///
870 fn format<'a>(&'a self, value: &'a El<Self>) -> RingElementDisplayWrapper<'a, Self> {
871 self.format_within(value, EnvBindingStrength::Weakest)
872 }
873
874 ///
875 /// Returns an object that represents the given ring element and implements
876 /// [`std::fmt::Display`], to use as formatting parameter. As opposed to
877 /// [`RingStore::format()`], this function takes an additional argument to
878 /// specify the context the result is printed in, which is used to determine
879 /// whether to put the value in parenthesis or not.
880 ///
881 /// # Example
882 /// ```rust
883 /// # use feanor_math::ring::*;
884 /// # use feanor_math::homomorphism::*;
885 /// # use feanor_math::integer::*;
886 /// # use feanor_math::rings::poly::dense_poly::*;
887 /// # use feanor_math::primitive_int::*;
888 /// # use feanor_math::rings::poly::*;
889 /// let ring = DensePolyRing::new(StaticRing::<i64>::RING, "X");
890 /// let [f, g] = ring.with_wrapped_indeterminate(|X| [X.clone(), X + 1]);
891 /// assert_eq!("X", format!("{}", ring.format_within(&f, EnvBindingStrength::Sum)));
892 /// assert_eq!("X", format!("{}", ring.format_within(&f, EnvBindingStrength::Product)));
893 /// assert_eq!("X + 1", format!("{}", ring.format_within(&g, EnvBindingStrength::Sum)));
894 /// assert_eq!("(X + 1)", format!("{}", ring.format_within(&g, EnvBindingStrength::Product)));
895 /// ```
896 ///
897 fn format_within<'a>(&'a self, value: &'a El<Self>, within: EnvBindingStrength) -> RingElementDisplayWrapper<'a, Self> {
898 RingElementDisplayWrapper { ring: self, element: value, within: within }
899 }
900
901 ///
902 /// Prints the given element. Use for quick & dirty debugging.
903 ///
904 fn println(&self, value: &El<Self>) {
905 println!("{}", self.format(value));
906 }
907
908 ///
909 /// See [`RingBase::characteristic()`].
910 ///
911 fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
912 where I::Type: IntegerRing
913 {
914 self.get_ring().characteristic(ZZ)
915 }
916}
917
918///
919/// [`RingStore`] for [`RingExtension`]s
920///
921pub trait RingExtensionStore: RingStore
922 where Self::Type: RingExtension
923{
924 delegate!{ RingExtension, fn base_ring(&self) -> &<Self::Type as RingExtension>::BaseRing }
925
926 ///
927 /// Returns the inclusion map of the base ring `R -> self`.
928 ///
929 fn into_inclusion(self) -> Inclusion<Self> {
930 Inclusion::new(self)
931 }
932
933 ///
934 /// Returns the inclusion map of the base ring `R -> self`.
935 ///
936 fn inclusion<'a>(&'a self) -> Inclusion<&'a Self> {
937 self.into_inclusion()
938 }
939
940}
941
942impl<R: RingStore> RingExtensionStore for R
943 where R::Type: RingExtension
944{}
945
946///
947/// Wrapper around a ring and one of its elements that implements [`std::fmt::Display`]
948/// and will print the element. Used by [`RingStore::format()`].
949///
950pub struct RingElementDisplayWrapper<'a, R: RingStore + ?Sized> {
951 ring: &'a R,
952 element: &'a El<R>,
953 within: EnvBindingStrength
954}
955
956impl<'a, R: RingStore + ?Sized> std::fmt::Display for RingElementDisplayWrapper<'a, R> {
957
958 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
959 self.ring.get_ring().dbg_within(self.element, f, self.within)
960 }
961}
962
963impl<'a, R: RingStore + ?Sized> std::fmt::Debug for RingElementDisplayWrapper<'a, R> {
964
965 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
966 self.ring.get_ring().dbg_within(self.element, f, self.within)
967 }
968}
969
970///
971/// Trait for rings that are an extension ring of a base ring.
972/// This does not have to be a proper extension in the mathematical
973/// sense, but is in some cases implemented for a wrapper of a ring
974/// object that represents the same ring.
975///
976/// Hence, this is technically just a ring `R` with an injective homomorphism
977/// `BaseRing -> R`, but unlike [`CanHomFrom`], implementors must provide
978/// a reference to `BaseRing` via [`RingExtension::base_ring()`].
979///
980/// # Overlap with [`CanHomFrom`]
981///
982/// There is a certain amount of functionality overlap with [`CanHomFrom`], and
983/// in a perfect world, this trait would also be a subtrait of `CanHomFrom<<Self::BaseRing as RingStore>::Type>`.
984/// However, due to the issue with multiple blanket implementations for [`CanHomFrom`] (see
985/// the docs), this is not the case and in fact there are ring extensions that do not implement
986/// `CanHomFrom<<Self::BaseRing as RingStore>::Type>`.
987///
988pub trait RingExtension: RingBase {
989
990 ///
991 /// Type of the base ring;
992 ///
993 /// This is bounded by [`RingStore`] to encourage implementations of [`RingExtension`]
994 /// to store their base ring as a [`RingStore`] ([`RingStore`] is designed exactly for
995 /// this use case). Additionally, it makes using the base ring easier.
996 ///
997 type BaseRing: RingStore;
998
999 ///
1000 /// Returns a reference to the base ring.
1001 ///
1002 fn base_ring<'a>(&'a self) -> &'a Self::BaseRing;
1003
1004 ///
1005 /// Maps an element of the base ring into this ring.
1006 ///
1007 /// This should realize an injective ring homomorphism.
1008 /// Instead of calling it directly, consider using it through
1009 /// [`RingExtensionStore::inclusion()`].
1010 ///
1011 fn from(&self, x: El<Self::BaseRing>) -> Self::Element;
1012
1013 ///
1014 /// Maps an element of the base ring (given as reference) into this ring.
1015 ///
1016 fn from_ref(&self, x: &El<Self::BaseRing>) -> Self::Element {
1017 self.from(self.base_ring().get_ring().clone_el(x))
1018 }
1019
1020 ///
1021 /// Computes `lhs := lhs * rhs`, where `rhs` is mapped into this
1022 /// ring via [`RingExtension::from_ref()`]. Note that this may be
1023 /// faster than `self.mul_assign(lhs, self.from_ref(rhs))`.
1024 ///
1025 fn mul_assign_base(&self, lhs: &mut Self::Element, rhs: &El<Self::BaseRing>) {
1026 self.mul_assign(lhs, self.from_ref(rhs));
1027 }
1028
1029 fn fma_base(&self, lhs: &Self::Element, rhs: &El<Self::BaseRing>, summand: Self::Element) -> Self::Element {
1030 let mut tmp = self.clone_el(lhs);
1031 self.mul_assign_base(&mut tmp, rhs);
1032 return self.add(summand, tmp);
1033 }
1034
1035 ///
1036 /// Computes `lhs := lhs * rhs`, where `rhs` is mapped into this ring
1037 /// via the given homomorphism, followed by the inclusion (as specified by
1038 /// [`RingExtension::from_ref()`]).
1039 ///
1040 /// This is designed for the case that an extension ring element is represented
1041 /// as a vector of base ring elements, in which case this function can make
1042 /// use of an optimized [`Homomorphism::mul_assign_map()`] implementation.
1043 ///
1044 #[stability::unstable(feature = "enable")]
1045 fn mul_assign_base_through_hom<S: ?Sized + RingBase, H: Homomorphism<S, <Self::BaseRing as RingStore>::Type>>(&self, lhs: &mut Self::Element, rhs: &S::Element, hom: H) {
1046 self.mul_assign_base(lhs, &hom.map_ref(rhs));
1047 }
1048}
1049
1050///
1051/// Trait for rings that can compute hashes for their elements.
1052/// This should be compatible with [`RingBase::eq_el`] in the usual way.
1053///
1054pub trait HashableElRing: RingBase {
1055
1056 ///
1057 /// Hashes the given ring element.
1058 ///
1059 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H);
1060}
1061
1062///
1063/// [`RingStore`] for [`HashableElRing`]s
1064///
1065pub trait HashableElRingStore: RingStore
1066 where Self::Type: HashableElRing
1067{
1068 ///
1069 /// See [`HashableElRing::hash()`].
1070 ///
1071 fn hash<H: std::hash::Hasher>(&self, el: &El<Self>, h: &mut H) {
1072 self.get_ring().hash(el, h)
1073 }
1074
1075 ///
1076 /// Computes a hash of the given element using some default hasher.
1077 ///
1078 /// This may not be the same in different versions of `feanor-math`.
1079 ///
1080 fn default_hash(&self, el: &El<Self>) -> u64 {
1081 let mut hasher = std::collections::hash_map::DefaultHasher::new();
1082 self.hash(el, &mut hasher);
1083 return <std::collections::hash_map::DefaultHasher as std::hash::Hasher>::finish(&hasher);
1084 }
1085}
1086
1087impl<R> HashableElRingStore for R
1088 where R: RingStore,
1089 R::Type: HashableElRing
1090{}
1091
1092///
1093/// Alias for `<<Self as RingStore>::Type as RingBase>::Element`.
1094///
1095pub type El<R> = <<R as RingStore>::Type as RingBase>::Element;
1096
1097///
1098/// The most fundamental [`crate::ring::RingStore`]. It is basically
1099/// a no-op container, i.e. stores a [`crate::ring::RingBase`] object
1100/// by value, and allows accessing it.
1101///
1102/// # Why is this necessary?
1103///
1104/// In fact, that we need this trait is just the result of a technical
1105/// detail. We cannot implement
1106/// ```rust,ignore
1107/// impl<R: RingBase> RingStore for R {}
1108/// impl<'a, R: RingStore> RingStore for &'a R {}
1109/// ```
1110/// since this might cause conflicting implementations.
1111/// Instead, we implement
1112/// ```rust,ignore
1113/// impl<R: RingBase> RingStore for RingValue<R> {}
1114/// impl<'a, R: RingStore> RingStore for &'a R {}
1115/// ```
1116/// This causes some inconvenience, as now we cannot chain
1117/// [`crate::ring::RingStore`] in the case of [`crate::ring::RingValue`].
1118/// Furthermore, this trait will be necessary everywhere -
1119/// to define a reference to a ring of type `A`, we now have to
1120/// write `&RingValue<A>`.
1121///
1122/// To simplify this, we propose to use the following simple pattern:
1123/// Create your ring type as
1124/// ```rust,ignore
1125/// struct ABase { ... }
1126/// impl RingBase for ABase { ... }
1127/// ```
1128/// and then provide a type alias
1129/// ```rust,ignore
1130/// type A = RingValue<ABase>;
1131/// ```
1132///
1133#[repr(transparent)]
1134#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
1135pub struct RingValue<R: RingBase> {
1136 ring: R
1137}
1138
1139impl<R: RingBase> RingValue<R> {
1140
1141 ///
1142 /// Wraps the given [`RingBase`] in a [`RingValue`].
1143 ///
1144 /// This is a dedicated function instead of an implementation
1145 /// of [`std::convert::From`] so that we can declare it `const`.
1146 ///
1147 pub const fn from(value: R) -> Self {
1148 RingValue { ring: value }
1149 }
1150
1151 ///
1152 /// Creates a reference to a [`RingValue`] from a reference
1153 /// to the [`RingBase`].
1154 ///
1155 pub fn from_ref<'a>(value: &'a R) -> &'a Self {
1156 unsafe { std::mem::transmute(value) }
1157 }
1158
1159 ///
1160 /// Unwraps the [`RingBase`].
1161 ///
1162 /// The more common case would be to get a reference, which can
1163 /// be done with [`RingStore::get_ring()`].
1164 ///
1165 pub fn into(self) -> R {
1166 self.ring
1167 }
1168}
1169
1170impl<R: RingBase> RingStore for RingValue<R> {
1171
1172 type Type = R;
1173
1174 fn get_ring(&self) -> &R {
1175 &self.ring
1176 }
1177}
1178
1179impl<R: RingBase + Default> Default for RingValue<R> {
1180
1181 fn default() -> Self {
1182 Self::from(R::default())
1183 }
1184}
1185
1186///
1187/// The second most basic [`crate::ring::RingStore`]. Similarly to
1188/// [`crate::ring::RingValue`] it is just a no-op container.
1189///
1190/// # Why do we need this in addition to [`crate::ring::RingValue`]?
1191///
1192/// Before [`RingValue::from_ref()`] was added, this was important to
1193/// allow using a reference to a [`RingBase`] as [`RingStore`]. Since then,
1194/// it indeed has only a marginal importance, but note that it is currently
1195/// the only way of working with unsized rings (an admittedly pretty exotic
1196/// case).
1197///
1198#[repr(transparent)]
1199#[derive(Debug)]
1200pub struct RingRef<'a, R: RingBase + ?Sized> {
1201 ring: &'a R
1202}
1203
1204impl<'a, R: RingBase + ?Sized> Clone for RingRef<'a, R> {
1205
1206 fn clone(&self) -> Self {
1207 *self
1208 }
1209}
1210
1211impl<'a, R: RingBase + ?Sized> Copy for RingRef<'a, R> {}
1212
1213impl<'a, R: RingBase + ?Sized> RingRef<'a, R> {
1214
1215 ///
1216 /// Creates a new [`RingRef`] from a reference to a [`RingBase`].
1217 ///
1218 pub const fn new(value: &'a R) -> Self {
1219 RingRef { ring: value }
1220 }
1221
1222 ///
1223 /// Returns the stored reference to the [`RingBase`].
1224 ///
1225 /// This is almost the same as [`RingStore::get_ring()`], except for
1226 /// that the lifetime of the returned reference is not bounded to the
1227 /// lifetime of the [`RingRef`].
1228 ///
1229 pub fn into(self) -> &'a R {
1230 self.ring
1231 }
1232}
1233
1234impl<'a, R: RingBase + ?Sized> RingStore for RingRef<'a, R> {
1235
1236 type Type = R;
1237
1238 fn get_ring(&self) -> &R {
1239 self.ring
1240 }
1241}
1242
1243impl<'a, S: Deref> RingStore for S
1244 where S::Target: RingStore
1245{
1246 type Type = <<S as Deref>::Target as RingStore>::Type;
1247
1248 fn get_ring<'b>(&'b self) -> &'b Self::Type {
1249 (**self).get_ring()
1250 }
1251}
1252
1253#[cfg(test)]
1254use std::rc::Rc;
1255#[cfg(test)]
1256use crate::impl_eq_based_self_iso;
1257
1258#[test]
1259fn test_ring_rc_lifetimes() {
1260 let ring = Rc::new(StaticRing::<i32>::RING);
1261 let mut ring_ref = None;
1262 assert!(ring_ref.is_none());
1263 {
1264 ring_ref = Some(ring.get_ring());
1265 }
1266 assert!(ring.get_ring().is_commutative());
1267 assert!(ring_ref.is_some());
1268}
1269
1270#[test]
1271fn test_internal_wrappings_dont_matter() {
1272
1273 #[derive(Clone, PartialEq)]
1274 pub struct ABase;
1275
1276 #[allow(unused)]
1277 #[derive(Clone)]
1278 pub struct BBase<R: RingStore> {
1279 base: R
1280 }
1281
1282 impl<R: RingStore> PartialEq for BBase<R> {
1283 fn eq(&self, other: &Self) -> bool {
1284 self.base.get_ring() == other.base.get_ring()
1285 }
1286 }
1287
1288 impl RingBase for ABase {
1289 type Element = i32;
1290
1291 fn clone_el(&self, val: &Self::Element) -> Self::Element {
1292 *val
1293 }
1294
1295 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
1296 *lhs += rhs;
1297 }
1298
1299 fn negate_inplace(&self, lhs: &mut Self::Element) {
1300 *lhs = -*lhs;
1301 }
1302
1303 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
1304 *lhs == *rhs
1305 }
1306
1307 fn is_commutative(&self) -> bool {
1308 true
1309 }
1310
1311 fn is_noetherian(&self) -> bool {
1312 true
1313 }
1314
1315 fn from_int(&self, value: i32) -> Self::Element {
1316 value
1317 }
1318
1319 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
1320 *lhs *= rhs;
1321 }
1322
1323 fn dbg_within<'a>(&self, _: &Self::Element, _: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
1324 Ok(())
1325 }
1326
1327 fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
1328 where I::Type: IntegerRing
1329 {
1330 Some(ZZ.zero())
1331 }
1332
1333 fn is_approximate(&self) -> bool { false }
1334 }
1335
1336 impl_eq_based_self_iso!{ ABase }
1337
1338 impl<R: RingStore> RingBase for BBase<R> {
1339 type Element = i32;
1340
1341 fn clone_el(&self, val: &Self::Element) -> Self::Element {
1342 *val
1343 }
1344
1345 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
1346 *lhs += rhs;
1347 }
1348 fn negate_inplace(&self, lhs: &mut Self::Element) {
1349 *lhs = -*lhs;
1350 }
1351
1352 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
1353 *lhs == *rhs
1354 }
1355
1356 fn is_commutative(&self) -> bool {
1357 true
1358 }
1359
1360 fn is_noetherian(&self) -> bool {
1361 true
1362 }
1363
1364 fn from_int(&self, value: i32) -> Self::Element {
1365 value
1366 }
1367
1368 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
1369 *lhs *= rhs;
1370 }
1371
1372 fn dbg_within<'a>(&self, _: &Self::Element, _: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
1373 Ok(())
1374 }
1375
1376 fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
1377 where I::Type: IntegerRing
1378 {
1379 Some(ZZ.zero())
1380 }
1381
1382 fn is_approximate(&self) -> bool { false }
1383 }
1384
1385 impl<R: RingStore> CanHomFrom<ABase> for BBase<R> {
1386
1387 type Homomorphism = ();
1388
1389 fn has_canonical_hom(&self, _: &ABase) -> Option<()> {
1390 Some(())
1391 }
1392
1393 fn map_in(&self, _: &ABase, el: <ABase as RingBase>::Element, _: &()) -> Self::Element {
1394 el
1395 }
1396 }
1397
1398 impl<R: RingStore, S: RingStore> CanHomFrom<BBase<S>> for BBase<R>
1399 where R::Type: CanHomFrom<S::Type>
1400 {
1401 type Homomorphism = ();
1402
1403 fn has_canonical_hom(&self, _: &BBase<S>) -> Option<()> {
1404 Some(())
1405 }
1406
1407 fn map_in(&self, _: &BBase<S>, el: <BBase<S> as RingBase>::Element, _: &()) -> Self::Element {
1408 el
1409 }
1410 }
1411
1412 impl<R: RingStore> CanIsoFromTo<BBase<R>> for BBase<R>
1413 where R::Type: CanHomFrom<R::Type>
1414 {
1415 type Isomorphism = ();
1416
1417 fn has_canonical_iso(&self, _: &BBase<R>) -> Option<()> {
1418 Some(())
1419 }
1420
1421 fn map_out(&self, _: &BBase<R>, el: <BBase<R> as RingBase>::Element, _: &()) -> Self::Element {
1422 el
1423 }
1424 }
1425
1426 type A = RingValue<ABase>;
1427 type B<R> = RingValue<BBase<R>>;
1428
1429 let a: A = RingValue { ring: ABase };
1430 let b1: B<A> = RingValue { ring: BBase { base: a.clone() } };
1431 let b2: B<&B<A>> = RingValue { ring: BBase { base: &b1 } };
1432 let b3: B<&A> = RingValue { ring: BBase { base: &a } };
1433 _ = b1.coerce(&a, 0);
1434 _ = b2.coerce(&a, 0);
1435 _ = b2.coerce(&b1, 0);
1436 _ = b2.coerce(&b3, 0);
1437 _ = (&b2).coerce(&b3, 0);
1438 _ = (&b2).coerce(&&&b3, 0);
1439}
1440
1441#[allow(missing_docs)]
1442#[cfg(any(test, feature = "generic_tests"))]
1443pub mod generic_tests {
1444
1445 use crate::integer::{int_cast, BigIntRing};
1446 use std::cmp::min;
1447
1448 use super::*;
1449
1450 pub fn test_hom_axioms<R: RingStore, S: RingStore, I: Iterator<Item = El<R>>>(from: R, to: S, edge_case_elements: I)
1451 where S::Type: CanHomFrom<R::Type>
1452 {
1453 let hom = to.can_hom(&from).unwrap();
1454 crate::homomorphism::generic_tests::test_homomorphism_axioms(hom, edge_case_elements);
1455 }
1456
1457 pub fn test_iso_axioms<R: RingStore, S: RingStore, I: Iterator<Item = El<R>>>(from: R, to: S, edge_case_elements: I)
1458 where S::Type: CanIsoFromTo<R::Type>
1459 {
1460 let hom = to.get_ring().has_canonical_hom(from.get_ring()).unwrap();
1461 let iso = to.get_ring().has_canonical_iso(from.get_ring()).unwrap();
1462 let elements = edge_case_elements.collect::<Vec<_>>();
1463
1464 for a in &elements {
1465 let map_in = to.get_ring().map_in_ref(from.get_ring(), a, &hom);
1466 let map_in_out = to.get_ring().map_out(from.get_ring(), to.clone_el(&map_in), &iso);
1467 assert!(from.eq_el(&map_in_out, &a), "Bijectivity failed: {} != {} = hom^-1({}) = hom^-1(hom({}))", from.format(a), from.format(&map_in_out), to.format(&map_in), from.format(a));
1468 }
1469 }
1470
1471 pub fn test_self_iso<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
1472 where R::Type: SelfIso
1473 {
1474 let hom = ring.get_ring().has_canonical_hom(ring.get_ring()).unwrap();
1475 let iso = ring.get_ring().has_canonical_iso(ring.get_ring()).unwrap();
1476 let elements = edge_case_elements.collect::<Vec<_>>();
1477
1478 test_hom_axioms(&ring, &ring, elements.iter().map(|x| ring.clone_el(x)));
1479 test_iso_axioms(&ring, &ring, elements.iter().map(|x| ring.clone_el(x)));
1480
1481 for a in &elements {
1482 assert_el_eq!(ring, a, ring.get_ring().map_in_ref(ring.get_ring(), a, &hom));
1483 assert_el_eq!(ring, a, ring.get_ring().map_out(ring.get_ring(), ring.clone_el(a), &iso));
1484 }
1485 }
1486
1487 pub fn test_hash_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
1488 where R::Type: HashableElRing
1489 {
1490 let elements = edge_case_elements.collect::<Vec<_>>();
1491
1492 // technically not required, but we should test hash inequality and this really should be true
1493 assert_ne!(ring.default_hash(&ring.one()), ring.default_hash(&ring.zero()));
1494
1495 for a in &elements {
1496 for b in &elements {
1497 assert!(!ring.eq_el(a, b) || ring.default_hash(a) == ring.default_hash(b));
1498 }
1499 }
1500
1501 for a in &elements {
1502 for b in &elements {
1503 let expr = ring.sub(ring.mul_ref_fst(a, ring.add_ref_fst(b, ring.one())), ring.mul_ref(a, b));
1504 assert!(ring.default_hash(a) == ring.default_hash(&expr));
1505 }
1506 }
1507 }
1508
1509 pub fn test_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I) {
1510 let elements = edge_case_elements.collect::<Vec<_>>();
1511 let zero = ring.zero();
1512 let one = ring.one();
1513
1514 assert!(ring.is_zero(&zero));
1515 assert!(ring.is_one(&one));
1516 assert!(ring.is_neg_one(&ring.neg_one()));
1517 assert!(ring.eq_el(&ring.neg_one(), &ring.get_ring().from_int(-1)));
1518 assert!(ring.eq_el(&zero, &ring.get_ring().from_int(0)));
1519 assert!(ring.eq_el(&one, &ring.get_ring().from_int(1)));
1520
1521 // check self-subtraction
1522 for a in &elements {
1523 let a_minus_a = ring.sub(ring.clone_el(a), ring.clone_el(a));
1524 assert!(ring.eq_el(&zero, &a_minus_a), "Additive inverse failed: {} - {} = {} != {}", ring.format_within(a, EnvBindingStrength::Sum), ring.format_within(a, EnvBindingStrength::Product), ring.format(&a_minus_a), ring.format(&zero));
1525 }
1526
1527 // check identity elements
1528 for a in &elements {
1529 let a_plus_zero = ring.add(ring.clone_el(a), ring.clone_el(&zero));
1530 assert!(ring.eq_el(a, &a_plus_zero), "Additive neutral element failed: {} + {} = {} != {}", ring.format_within(a, EnvBindingStrength::Sum), ring.format(&zero), ring.format(&a_plus_zero), ring.format(a));
1531
1532 let a_times_one = ring.mul(ring.clone_el(a), ring.clone_el(&one));
1533 assert!(ring.eq_el(a, &a_times_one), "Multiplicative neutral element failed: {} * {} = {} != {}", ring.format_within(a, EnvBindingStrength::Product), ring.format(&one), ring.format(&a_times_one), ring.format(a));
1534 }
1535
1536 // check commutativity
1537 for a in &elements {
1538 for b in &elements {
1539 {
1540 let ab = ring.add_ref(a, b);
1541 let ba = ring.add_ref(b, a);
1542 assert!(ring.eq_el(&ab, &ba), "Additive commutativity failed: {} + {} = {} != {} = {} + {}", ring.format_within(a, EnvBindingStrength::Sum), ring.format_within(b, EnvBindingStrength::Sum), ring.format(&ab), ring.format(&ba), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(a, EnvBindingStrength::Sum));
1543 }
1544
1545 if ring.is_commutative() {
1546 let ab = ring.mul_ref(a, b);
1547 let ba = ring.mul_ref(b, a);
1548 assert!(ring.eq_el(&ab, &ba), "Multiplicative commutativity failed: {} * {} = {} != {} = {} * {}", ring.format_within(a, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Product), ring.format(&ab), ring.format(&ba), ring.format_within(b, EnvBindingStrength::Product), ring.format_within(a, EnvBindingStrength::Product));
1549 }
1550 }
1551 }
1552
1553 // check associativity
1554 for a in &elements {
1555 for b in &elements {
1556 for c in &elements {
1557 {
1558 let ab_c = ring.add_ref_snd(ring.add_ref(a, b), c);
1559 let a_bc = ring.add_ref_fst(c, ring.add_ref(b, a));
1560 assert!(ring.eq_el(&ab_c, &a_bc), "Additive associativity failed: ({} + {}) + {} = {} != {} = {} + ({} + {})", ring.format_within(a, EnvBindingStrength::Sum), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(c, EnvBindingStrength::Sum), ring.format(&ab_c), ring.format(&a_bc), ring.format_within(a, EnvBindingStrength::Sum), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(c, EnvBindingStrength::Sum));
1561 }
1562 {
1563 let ab_c = ring.mul_ref_snd(ring.mul_ref(a, b), c);
1564 let a_bc = ring.mul_ref_fst(c, ring.mul_ref(b, a));
1565 assert!(ring.eq_el(&ab_c, &a_bc), "Multiplicative associativity failed: ({} * {}) * {} = {} != {} = {} * ({} * {})", ring.format_within(a, EnvBindingStrength::Sum), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(c, EnvBindingStrength::Sum), ring.format(&ab_c), ring.format(&a_bc), ring.format_within(a, EnvBindingStrength::Sum), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(c, EnvBindingStrength::Sum));
1566 }
1567 }
1568 }
1569 }
1570
1571 // check distributivity
1572 for a in &elements {
1573 for b in &elements {
1574 for c in &elements {
1575 let ab_c = ring.mul_ref_snd(ring.add_ref(a, b), c);
1576 let ac_bc = ring.add(ring.mul_ref(a, c), ring.mul_ref(b, c));
1577 assert!(ring.eq_el(&ab_c, &ac_bc), "Distributivity failed: ({} + {}) * {} = {} != {} = {} * {} + {} * {}", ring.format_within(a, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(c, EnvBindingStrength::Sum), ring.format(&ab_c), ring.format(&ac_bc), ring.format_within(a, EnvBindingStrength::Product), ring.format_within(c, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Product), ring.format_within(c, EnvBindingStrength::Product));
1578
1579 let a_bc = ring.mul_ref_fst(a, ring.add_ref(b, c));
1580 let ab_ac = ring.add(ring.mul_ref(a, b), ring.mul_ref(a, c));
1581 assert!(ring.eq_el(&a_bc, &ab_ac), "Distributivity failed: {} * ({} + {}) = {} != {} = {} * {} + {} * {}", ring.format_within(a, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Sum), ring.format_within(c, EnvBindingStrength::Sum), ring.format(&a_bc), ring.format(&ab_ac), ring.format_within(a, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Product), ring.format_within(a, EnvBindingStrength::Product), ring.format_within(c, EnvBindingStrength::Product));
1582 }
1583 }
1584 }
1585
1586 // check fma
1587 for a in &elements {
1588 for b in &elements {
1589 for c in &elements {
1590 let actual = ring.fma(a, b, ring.clone_el(c));
1591 let expected = ring.add(ring.mul_ref(a, b), ring.clone_el(c));
1592 assert!(ring.eq_el(&expected, &actual), "FMA failed: fma({}, {}, {}) = {} != {} = ({} * {}) + {}", ring.format(a), ring.format(b), ring.format(c), ring.format(&actual), ring.format(&expected), ring.format_within(a, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Product), ring.format_within(c, EnvBindingStrength::Sum));
1593 }
1594
1595 let actual = ring.get_ring().fma_int(a, 2, ring.clone_el(b));
1596 let expected = ring.get_ring().add(ring.get_ring().add_ref(a, a), ring.clone_el(b));
1597 assert!(ring.eq_el(&expected, &actual), "Int-FMA failed: int-fma({}, 2, {}) = {} != {} = ({} * 2) + {}", ring.format(a), ring.format(b), ring.format(&actual), ring.format(&expected), ring.format_within(a, EnvBindingStrength::Product), ring.format_within(b, EnvBindingStrength::Sum));
1598 }
1599 }
1600
1601 // check powering
1602 for a in &elements {
1603 for n in [0, 1, 2, 3, 7, 8] {
1604 let expected = (0..n).map(|_| a).fold(ring.one(), |x, y| ring.mul_ref_snd(x, y));
1605 let actual = ring.pow(ring.clone_el(a), n);
1606 assert!(ring.eq_el(&expected, &actual), "Powering failed: {} * ... * {} = {} != {} = {}^{}", ring.format_within(a, EnvBindingStrength::Product), ring.format_within(a, EnvBindingStrength::Product), ring.format(&expected), ring.format(&actual), ring.format_within(a, EnvBindingStrength::Power), n);
1607 }
1608 }
1609
1610 // check characteristic
1611 let ZZbig = BigIntRing::RING;
1612 let char = ring.characteristic(&ZZbig).unwrap();
1613
1614 if ZZbig.is_geq(&char, &ZZbig.power_of_two(7)) {
1615 assert_eq!(None, ring.characteristic(&StaticRing::<i8>::RING));
1616 }
1617 if ZZbig.is_geq(&char, &ZZbig.power_of_two(15)) {
1618 assert_eq!(None, ring.characteristic(&StaticRing::<i16>::RING));
1619 }
1620 if ZZbig.is_geq(&char, &ZZbig.power_of_two(31)) {
1621 assert_eq!(None, ring.characteristic(&StaticRing::<i32>::RING));
1622 }
1623 if ZZbig.is_geq(&char, &ZZbig.power_of_two(63)) {
1624 assert_eq!(None, ring.characteristic(&StaticRing::<i64>::RING));
1625 }
1626 if ZZbig.is_geq(&char, &ZZbig.power_of_two(127)) {
1627 assert_eq!(None, ring.characteristic(&StaticRing::<i128>::RING));
1628 }
1629 if ZZbig.is_lt(&char, &ZZbig.power_of_two(31)) {
1630 let char = int_cast(char, &StaticRing::<i32>::RING, &ZZbig);
1631
1632 assert_el_eq!(ring, ring.zero(), ring.get_ring().from_int(char));
1633
1634 if char == 0 {
1635 for i in 1..(1 << 10) {
1636 assert!(!ring.is_zero(&ring.get_ring().from_int(i)));
1637 }
1638 } else {
1639 for i in 1..min(1 << 10, char) {
1640 assert!(!ring.is_zero(&ring.get_ring().from_int(i)));
1641 }
1642 }
1643 }
1644
1645 }
1646}
1647
1648#[test]
1649fn test_environment_binding() {
1650 assert!(EnvBindingStrength::Strongest > EnvBindingStrength::Power);
1651 assert!(EnvBindingStrength::Power > EnvBindingStrength::Product);
1652 assert!(EnvBindingStrength::Product > EnvBindingStrength::Sum);
1653 assert!(EnvBindingStrength::Sum > EnvBindingStrength::Weakest);
1654}