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