feanor_math/
divisibility.rs

1
2use std::fmt::Debug;
3
4use crate::ring::*;
5
6///
7/// Trait for rings that support checking divisibility, i.e.
8/// whether for `x, y` there is `k` such that `x = ky`.
9/// 
10pub trait DivisibilityRing: RingBase {
11
12    ///
13    /// Additional data associated to a fixed ring element that can be used
14    /// to speed up division by this ring element. 
15    /// 
16    /// See also [`DivisibilityRing::prepare_divisor()`].
17    /// 
18    #[stability::unstable(feature = "enable")]
19    type PreparedDivisorData = ();
20
21    ///
22    /// Checks whether there is an element `x` such that `rhs * x = lhs`, and
23    /// returns it if it exists. 
24    /// 
25    /// Note that this does not have to be unique, if rhs is a left zero-divisor. 
26    /// In particular, this function will return any element in the ring if `lhs = rhs = 0`.
27    /// In rings with many zero-divisors, this can sometimes lead to unintuitive behavior.
28    /// See also [`crate::pid::PrincipalIdealRing::checked_div_min()`] for a function that,
29    /// if available, might sometimes behave more intuitively.
30    /// 
31    /// # Example
32    /// ```
33    /// # use feanor_math::ring::*;
34    /// # use feanor_math::primitive_int::*;
35    /// # use feanor_math::divisibility::*;
36    /// let ZZ = StaticRing::<i64>::RING;
37    /// assert_eq!(Some(3), ZZ.checked_left_div(&6, &2));
38    /// assert_eq!(None, ZZ.checked_left_div(&6, &4));
39    /// ```
40    /// In rings that have zero-divisors, there are usually multiple possible results.
41    /// ```
42    /// # use feanor_math::ring::*;
43    /// # use feanor_math::divisibility::*;
44    /// # use feanor_math::homomorphism::*;
45    /// # use feanor_math::rings::zn::zn_64::*;
46    /// let ring = Zn::new(6);
47    /// let four_over_four = ring.checked_left_div(&ring.int_hom().map(4), &ring.int_hom().map(4)).unwrap();
48    /// assert!(ring.eq_el(&four_over_four, &ring.int_hom().map(1)) || ring.eq_el(&four_over_four, &ring.int_hom().map(4)));
49    /// // note that the output 4 might be unexpected, since it is a zero-divisor itself!
50    /// ```
51    /// 
52    fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element>;
53
54    ///
55    /// Returns whether there is an element `x` such that `rhs * x = lhs`.
56    /// If you need such an element, consider using [`DivisibilityRing::checked_left_div()`].
57    /// 
58    /// # Example
59    /// ```
60    /// # use feanor_math::ring::*;
61    /// # use feanor_math::primitive_int::*;
62    /// # use feanor_math::divisibility::*;
63    /// let ZZ = StaticRing::<i64>::RING;
64    /// assert_eq!(true, ZZ.divides_left(&6, &2));
65    /// assert_eq!(false, ZZ.divides_left(&6, &4));
66    /// ```
67    /// 
68    fn divides_left(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
69        self.checked_left_div(lhs, rhs).is_some()
70    }
71
72    ///
73    /// Same as [`DivisibilityRing::divides_left()`], but requires a commutative ring.
74    /// 
75    fn divides(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
76        assert!(self.is_commutative());
77        self.divides_left(lhs, rhs)
78    }
79
80    ///
81    /// Same as [`DivisibilityRing::checked_left_div()`], but requires a commutative ring.
82    /// 
83    fn checked_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
84        assert!(self.is_commutative());
85        self.checked_left_div(lhs, rhs)
86    }
87
88    ///
89    /// Returns whether the given element is a unit, i.e. has an inverse.
90    /// 
91    fn is_unit(&self, x: &Self::Element) -> bool {
92        self.checked_left_div(&self.one(), x).is_some()
93    }
94
95    ///
96    /// Function that computes a "balancing" factor of a sequence of ring elements.
97    /// The only use of the balancing factor is to increase performance, in particular,
98    /// dividing all elements in the sequence by this factor should make them 
99    /// "smaller" resp. cheaper to process.
100    /// 
101    /// Note that the balancing factor must always be a non-zero divisor.
102    /// 
103    /// Standard cases are reducing fractions (where the sequence would be exactly two
104    /// elements), or polynomials over fields (where we often want to scale the polynomial
105    /// to make all denominators 1).
106    /// 
107    /// If balancing does not make sense (as in the case of finite fields) or is not
108    /// supported by the implementation, it is valid to return `None`.
109    /// 
110    fn balance_factor<'a, I>(&self, _elements: I) -> Option<Self::Element>
111        where I: Iterator<Item = &'a Self::Element>,
112            Self: 'a
113    {
114        None
115    }
116
117    ///
118    /// "Prepares" an element of this ring for division.
119    /// 
120    /// The returned [`DivisibilityRing::PreparedDivisor`] can then be used in calls
121    /// to [`DivisibilityRing::checked_left_div_prepared()`] and other "prepared" division
122    /// functions, which can be faster than for an "unprepared" element.
123    /// 
124    /// See also [`DivisibilityRingBase::prepare_divisor()`].
125    /// 
126    /// # Caveat
127    /// 
128    /// Previously, this was its own trait, but that caused problems, since using this properly 
129    /// would require fully-fledged specialization. Hence, we now inlude it in [`DivisibilityRing`]
130    /// but provide defaults for all `*_prepared()` functions. 
131    /// 
132    /// This is not perfect, and in particular, if you specialize [`DivisibilityRing::PreparedDivisorData`]
133    /// and not [`DivisibilityRing::prepare_divisor()`], this will currently not cause a compile error, but 
134    /// panic at runtime when calling [`DivisibilityRing::prepare_divisor()`] (unfortunately). However,
135    /// it seems like the most usable solution, and does not require unsafe code.
136    /// 
137    /// TODO: at the next breaking release, remove default implementation of `prepare_divisor()`.
138    /// 
139    /// # Example
140    /// 
141    /// Assume we want to go through all positive integers `<= 1000` that are divisible by `257`. The naive 
142    /// way would be the following
143    /// ```
144    /// # use feanor_math::ring::*;
145    /// # use feanor_math::divisibility::*;
146    /// # use feanor_math::primitive_int::*;
147    /// let ring = StaticRing::<i128>::RING;
148    /// for integer in 0..1000 {
149    ///     if ring.divides(&integer, &257) {
150    ///         assert!(integer == 0 || integer == 257 || integer == 514 || integer == 771);
151    ///     }
152    /// }
153    /// ```
154    /// It can be faster to instead prepare the divisor `257` once and use this "prepared" divisor for
155    /// all checks (of course, it will be much faster to iterate over `(0..10000).step_by(257)`, but
156    /// for the sake of this example, let's use individual divisibility checks).
157    /// ```
158    /// # use feanor_math::ring::*;
159    /// # use feanor_math::divisibility::*;
160    /// # use feanor_math::primitive_int::*;
161    /// # let ring = StaticRing::<i128>::RING;
162    /// let prepared_257 = ring.get_ring().prepare_divisor(257);
163    /// for integer in 0..1000 {
164    ///     if ring.get_ring().divides_left_prepared(&integer, &prepared_257) {
165    ///         assert!(integer == 0 || integer == 257 || integer == 514 || integer == 771);
166    ///     }
167    /// }
168    /// ```
169    /// 
170    #[stability::unstable(feature = "enable")]
171    fn prepare_divisor(&self, x: Self::Element) -> PreparedDivisor<Self> {
172        struct ProduceUnitType;
173        trait ProduceValue<T> {
174            fn produce() -> T;
175        }
176        impl<T> ProduceValue<T> for ProduceUnitType {
177            default fn produce() -> T {
178                panic!("if you specialize DivisibilityRing::PreparedDivisorData, you must also specialize DivisibilityRing::prepare_divisor()")
179            }
180        }
181        impl ProduceValue<()> for ProduceUnitType {
182            fn produce() -> () {}
183        }
184        PreparedDivisor {
185            element: x,
186            data: <ProduceUnitType as ProduceValue<Self::PreparedDivisorData>>::produce()
187        }
188    }
189
190    ///
191    /// Same as [`DivisibilityRing::checked_left_div()`] but for a prepared divisor.
192    /// 
193    /// See also [`DivisibilityRing::prepare_divisor()`].
194    /// 
195    #[stability::unstable(feature = "enable")]
196    fn checked_left_div_prepared(&self, lhs: &Self::Element, rhs: &PreparedDivisor<Self>) -> Option<Self::Element> {
197        self.checked_left_div(lhs, &rhs.element)
198    }
199
200    ///
201    /// Same as [`DivisibilityRing::divides_left()`] but for a prepared divisor.
202    /// 
203    /// See also [`DivisibilityRing::prepare_divisor()`].
204    /// 
205    #[stability::unstable(feature = "enable")]
206    fn divides_left_prepared(&self, lhs: &Self::Element, rhs: &PreparedDivisor<Self>) -> bool {
207        self.divides_left(lhs, &rhs.element)
208    }
209
210    ///
211    /// Same as [`DivisibilityRing::is_unit()`] but for a prepared divisor.
212    /// 
213    /// See also [`DivisibilityRing::prepare_divisor()`].
214    /// 
215    #[stability::unstable(feature = "enable")]
216    fn is_unit_prepared(&self, x: &PreparedDivisor<Self>) -> bool {
217        self.is_unit(&x.element)
218    }
219
220    ///
221    /// If the given element is a unit, returns its inverse, otherwise `None`.
222    /// 
223    /// This is equivalent (but possibly faster) than `ring.checked_div(ring.one(), el)`.
224    /// 
225    fn invert(&self, el: &Self::Element) -> Option<Self::Element> {
226        self.checked_div(&self.one(), el)
227    }
228}
229
230///
231/// Struct for ring elements that are stored with associated data to
232/// enable faster divisions.
233/// 
234/// For details, see [`DivisibilityRing::prepare_divisor()`].
235/// 
236pub struct PreparedDivisor<R>
237    where R: ?Sized + RingBase + DivisibilityRing
238{
239    pub element: R::Element,
240    pub data: R::PreparedDivisorData
241}
242
243impl<R> Debug for PreparedDivisor<R>
244    where R: ?Sized + RingBase + DivisibilityRing,
245        R::Element: Debug,
246        R::PreparedDivisorData: Debug
247{
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        write!(f, "PreparedDivisor {{ element: {:?}, data: {:?} }}", &self.element, &self.data)
250    }
251}
252
253impl<R> Clone for PreparedDivisor<R>
254    where R: ?Sized + RingBase + DivisibilityRing,
255        R::Element: Clone,
256        R::PreparedDivisorData: Clone
257{
258    fn clone(&self) -> Self {
259        Self {
260            element: self.element.clone(),
261            data: self.data.clone()
262        }
263    }
264}
265
266impl<R> Copy for PreparedDivisor<R>
267    where R: ?Sized + RingBase + DivisibilityRing,
268        R::Element: Copy,
269        R::PreparedDivisorData: Copy
270{}
271
272///
273/// Trait for rings that are integral, i.e. have no zero divisors.
274/// 
275/// A zero divisor is a nonzero element `a` such that there is a nonzero
276/// element `b` with `ab = 0`.
277/// 
278pub trait Domain: DivisibilityRing {}
279
280///
281/// Trait for [`RingStore`]s that store [`DivisibilityRing`]s. Mainly used
282/// to provide a convenient interface to the `DivisibilityRing`-functions.
283/// 
284pub trait DivisibilityRingStore: RingStore
285    where Self::Type: DivisibilityRing
286{
287    delegate!{ DivisibilityRing, fn checked_left_div(&self, lhs: &El<Self>, rhs: &El<Self>) -> Option<El<Self>> }
288    delegate!{ DivisibilityRing, fn divides_left(&self, lhs: &El<Self>, rhs: &El<Self>) -> bool }
289    delegate!{ DivisibilityRing, fn is_unit(&self, x: &El<Self>) -> bool }
290    delegate!{ DivisibilityRing, fn checked_div(&self, lhs: &El<Self>, rhs: &El<Self>) -> Option<El<Self>> }
291    delegate!{ DivisibilityRing, fn divides(&self, lhs: &El<Self>, rhs: &El<Self>) -> bool }
292    delegate!{ DivisibilityRing, fn invert(&self, lhs: &El<Self>) -> Option<El<Self>> }
293
294}
295
296impl<R> DivisibilityRingStore for R
297    where R: RingStore, R::Type: DivisibilityRing
298{}
299
300#[cfg(any(test, feature = "generic_tests"))]
301pub mod generic_tests {
302
303    use crate::ring::El;
304    use super::*;
305
306    pub fn test_divisibility_axioms<R: DivisibilityRingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
307        where R::Type: DivisibilityRing
308    {
309        let elements = edge_case_elements.collect::<Vec<_>>();
310
311        for a in &elements {
312            for b in &elements {
313                let ab = ring.mul(ring.clone_el(a), ring.clone_el(b));
314                let c = ring.checked_left_div(&ab, &a);
315                assert!(c.is_some(), "Divisibility existence failed: there should exist b = {} such that {} = b * {}, but none was found", ring.format(b), ring.format(&ab), ring.format(&a));
316                assert!(ring.eq_el(&ab, &ring.mul_ref_snd(ring.clone_el(a), c.as_ref().unwrap())), "Division failed: {} * {} != {} but {} = checked_div({}, {})", ring.format(a), ring.format(c.as_ref().unwrap()), ring.format(&ab), ring.format(c.as_ref().unwrap()), ring.format(&ab), ring.format(&a));
317
318                if !ring.is_unit(a) {
319                    let ab_plus_one = ring.add(ring.clone_el(&ab), ring.one());
320                    let c = ring.checked_left_div(&ab_plus_one, &a);
321                    assert!(c.is_none(), "Unit check failed: is_unit({}) is false but checked_div({}, {}) = {}", ring.format(a), ring.format(&ab_plus_one), ring.format(a), ring.format(c.as_ref().unwrap()));
322
323                    let ab_minus_one = ring.sub(ring.clone_el(&ab), ring.one());
324                    let c = ring.checked_left_div(&ab_minus_one, &a);
325                    assert!(c.is_none(), "Unit check failed: is_unit({}) is false but checked_div({}, {}) = {}", ring.format(a), ring.format(&ab_minus_one), ring.format(a), ring.format(c.as_ref().unwrap()));
326                } else {
327                    let inv = ring.checked_left_div(&ring.one(), a);
328                    assert!(inv.is_some(), "Unit check failed: is_unit({}) is true but checked_div({}, {}) is None", ring.format(a), ring.format(&ring.one()), ring.format(&a));
329                    let prod = ring.mul_ref(a, inv.as_ref().unwrap());
330                    assert!(ring.eq_el(&ring.one(), &prod), "Division failed: {} != {} * {} but checked_div({}, {}) = {}", ring.format(&ring.one()), ring.format(a), ring.format(inv.as_ref().unwrap()), ring.format(&ring.one()), ring.format(a), ring.format(c.as_ref().unwrap()));
331                }
332            }
333        }
334
335        for a in &elements {
336            let a_prepared_divisor = ring.get_ring().prepare_divisor(ring.clone_el(a));
337            for b in &elements {
338                let ab = ring.mul(ring.clone_el(a), ring.clone_el(b));
339                let c = ring.get_ring().checked_left_div_prepared(&ab, &a_prepared_divisor);
340                assert!(c.is_some(), "Divisibility existence failed for prepared divisor: there should exist b = {} such that {} = b * {}, but none was found", ring.format(b), ring.format(&ab), ring.format(&a));
341                assert!(ring.eq_el(&ab, &ring.mul_ref_snd(ring.clone_el(a), c.as_ref().unwrap())), "Division failed: {} * {} != {} but {} = checked_div({}, {})", ring.format(a), ring.format(c.as_ref().unwrap()), ring.format(&ab), ring.format(c.as_ref().unwrap()), ring.format(&ab), ring.format(&a));
342
343                if !ring.get_ring().is_unit_prepared(&a_prepared_divisor) {
344                    let ab_plus_one = ring.add(ring.clone_el(&ab), ring.one());
345                    let c = ring.get_ring().checked_left_div_prepared(&ab_plus_one, &a_prepared_divisor);
346                    assert!(c.is_none(), "Unit check failed for prepared divisor: is_unit({}) is false but checked_div({}, {}) = {}", ring.format(a), ring.format(&ab_plus_one), ring.format(a), ring.format(c.as_ref().unwrap()));
347
348                    let ab_minus_one = ring.sub(ring.clone_el(&ab), ring.one());
349                    let c = ring.get_ring().checked_left_div_prepared(&ab_minus_one, &a_prepared_divisor);
350                    assert!(c.is_none(), "Unit check failed for prepared divisor: is_unit({}) is false but checked_div({}, {}) = {}", ring.format(a), ring.format(&ab_minus_one), ring.format(a), ring.format(c.as_ref().unwrap()));
351                } else {
352                    let inv = ring.get_ring().checked_left_div_prepared(&ring.one(), &a_prepared_divisor);
353                    assert!(inv.is_some(), "Unit check failed for prepared divisor: is_unit({}) is true but checked_div({}, {}) is None", ring.format(a), ring.format(&ring.one()), ring.format(&a));
354                    let prod = ring.mul_ref(a, inv.as_ref().unwrap());
355                    assert!(ring.eq_el(&ring.one(), &prod), "Division failed for prepared divisor: {} != {} * {} but checked_div({}, {}) = {}", ring.format(&ring.one()), ring.format(a), ring.format(inv.as_ref().unwrap()), ring.format(&ring.one()), ring.format(a), ring.format(c.as_ref().unwrap()));
356                }
357            }
358        }
359    }
360}