1use crate::algorithms;
2use crate::algorithms::convolution::ConvolutionAlgorithm;
3use crate::algorithms::poly_gcd::PolyTFracGCDRing;
4use crate::divisibility::*;
5use crate::integer::IntegerRing;
6use crate::integer::IntegerRingStore;
7use crate::pid::*;
8use crate::field::Field;
9use crate::seq::VectorViewMut;
10use crate::ring::*;
11use crate::rings::poly::*;
12use crate::seq::*;
13use crate::seq::sparse::*;
14
15use std::alloc::Allocator;
16use std::cmp::max;
17use std::fmt::Debug;
18use std::fmt::{Formatter, Result};
19use std::sync::Arc;
20
21pub struct SparsePolyRingBase<R: RingStore> {
60 base_ring: Arc<R>,
61 unknown_name: &'static str,
62 zero: El<R>
63}
64
65impl<R: RingStore + Clone> Clone for SparsePolyRingBase<R> {
66
67 fn clone(&self) -> Self {
68 SparsePolyRingBase {
69 base_ring: self.base_ring.clone(),
70 unknown_name: self.unknown_name,
71 zero: self.base_ring.zero()
72 }
73 }
74}
75
76impl<R: RingStore> Debug for SparsePolyRingBase<R>
77 where R::Type: Debug
78{
79 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
80 f.debug_struct("SparsePolyRingBase")
81 .field("base_ring", &self.base_ring.get_ring())
82 .finish()
83 }
84}
85
86#[allow(type_alias_bounds)]
91pub type SparsePolyRing<R: RingStore> = RingValue<SparsePolyRingBase<R>>;
92
93impl<R: RingStore> SparsePolyRing<R> {
94
95 pub fn new(base_ring: R, unknown_name: &'static str) -> Self {
99 let zero = base_ring.zero();
100 Self::from(SparsePolyRingBase {
101 base_ring: Arc::new(base_ring),
102 unknown_name: unknown_name,
103 zero: zero
104 })
105 }
106}
107
108impl<R: RingStore> SparsePolyRingBase<R> {
109
110 fn degree_truncate(&self, el: &mut SparseMapVector<Arc<R>>) {
111 for i in (0..el.len()).rev() {
112 if !self.base_ring.is_zero(&el.at(i)) {
113 el.set_len(i + 1);
114 return;
115 }
116 }
117 el.set_len(0);
118 }
119
120 fn poly_div<F>(&self, lhs: &mut <Self as RingBase>::Element, rhs: &<Self as RingBase>::Element, mut left_div_lc: F) -> Option<<Self as RingBase>::Element>
121 where F: FnMut(El<R>) -> Option<El<R>>
122 {
123 let lhs_val = std::mem::replace(lhs, self.zero());
124 let (quo, rem) = algorithms::poly_div::poly_div_rem(
125 RingRef::new(self),
126 lhs_val,
127 rhs,
128 |x| left_div_lc(self.base_ring().clone_el(x)).ok_or(())
129 ).ok()?;
130 *lhs = rem;
131 return Some(quo);
132 }
133}
134
135pub struct SparsePolyRingEl<R: RingStore> {
139 data: SparseMapVector<Arc<R>>
140}
141
142impl<R: RingStore> Debug for SparsePolyRingEl<R>
143 where El<R>: Debug
144{
145 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
146 self.data.fmt(f)
147 }
148}
149
150impl<R: RingStore> RingBase for SparsePolyRingBase<R> {
151
152 type Element = SparsePolyRingEl<R>;
153
154 fn clone_el(&self, val: &Self::Element) -> Self::Element {
155 SparsePolyRingEl {
156 data: val.data.clone()
157 }
158 }
159
160 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
161 lhs.data.set_len(max(lhs.data.len(), rhs.data.len()));
162 for (i, c) in rhs.data.nontrivial_entries() {
163 self.base_ring.add_assign_ref(lhs.data.at_mut(i), c);
164 }
165 self.degree_truncate(&mut lhs.data);
166 }
167
168 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
169 self.add_assign_ref(lhs, &rhs);
170 }
171
172 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
173 lhs.data.set_len(max(lhs.data.len(), rhs.data.len()));
174 for (i, c) in rhs.data.nontrivial_entries() {
175 self.base_ring.sub_assign_ref(lhs.data.at_mut(i), c);
176 }
177 self.degree_truncate(&mut lhs.data);
178 }
179
180 fn negate_inplace(&self, lhs: &mut Self::Element) {
181 lhs.data.scan(|_, c| self.base_ring.negate_inplace(c));
182 }
183
184 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
185 self.mul_assign_ref(lhs, &rhs);
186 }
187
188 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
189 *lhs = self.mul_ref(lhs, rhs);
190 }
191
192 fn zero(&self) -> Self::Element {
193 SparsePolyRingEl {
194 data: SparseMapVector::new(0, self.base_ring.clone())
195 }
196 }
197
198 fn from_int(&self, value: i32) -> Self::Element {
199 self.from(self.base_ring().get_ring().from_int(value))
200 }
201
202 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
203 if lhs.data.len() != rhs.data.len() {
204 return false;
205 }
206 for (i, c) in lhs.data.nontrivial_entries() {
207 if !self.base_ring.eq_el(rhs.data.at(i), c) {
208 return false;
209 }
210 }
211 for (i, c) in rhs.data.nontrivial_entries() {
212 if !self.base_ring.eq_el(lhs.data.at(i), c) {
213 return false;
214 }
215 }
216 return true;
217 }
218
219 fn is_commutative(&self) -> bool {
220 self.base_ring.is_commutative()
221 }
222
223 fn is_noetherian(&self) -> bool {
224 self.base_ring.is_noetherian()
226 }
227
228 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut Formatter<'a>, env: EnvBindingStrength) -> Result {
229 super::generic_impls::dbg_poly(self, value, out, self.unknown_name, env)
230 }
231
232 fn dbg<'a>(&self, value: &Self::Element, out: &mut Formatter<'a>) -> Result {
233 self.dbg_within(value, out, EnvBindingStrength::Weakest)
234 }
235
236 fn square(&self, value: &mut Self::Element) {
237 *value = self.mul_ref(&value, &value);
238 }
239
240 fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
241 if lhs.data.len() == 0 || rhs.data.len() == 0 {
242 return self.zero();
243 }
244 let mut result = SparseMapVector::new(lhs.data.len() + rhs.data.len() - 1, self.base_ring.clone());
245 for (i, c1) in lhs.data.nontrivial_entries() {
246 for (j, c2) in rhs.data.nontrivial_entries() {
247 self.base_ring.add_assign(result.at_mut(i + j), self.base_ring.mul_ref(c1, c2));
248 }
249 }
250 self.degree_truncate(&mut result);
252 return SparsePolyRingEl {
253 data: result
254 };
255 }
256
257 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
258 if rhs == 0 {
259 *lhs = self.zero();
260 } else {
261 lhs.data.scan(|_, c| self.base_ring.int_hom().mul_assign_map(c, rhs));
262 }
263 }
264
265 fn characteristic<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
266 where I::Type: IntegerRing
267 {
268 self.base_ring().characteristic(ZZ)
269 }
270
271 fn is_approximate(&self) -> bool {
272 self.base_ring().get_ring().is_approximate()
273 }
274}
275
276impl<R> PartialEq for SparsePolyRingBase<R>
277 where R: RingStore
278{
279 fn eq(&self, other: &Self) -> bool {
280 self.base_ring.get_ring() == other.base_ring.get_ring()
281 }
282}
283
284impl<R: RingStore> RingExtension for SparsePolyRingBase<R> {
285
286 type BaseRing = R;
287
288 fn base_ring<'a>(&'a self) -> &'a Self::BaseRing {
289 &self.base_ring
290 }
291
292 fn from(&self, x: El<Self::BaseRing>) -> Self::Element {
293 let mut result = self.zero();
294 if !self.base_ring().is_zero(&x) {
295 result.data.set_len(1);
296 *result.data.at_mut(0) = x;
297 }
298 return result;
299 }
300}
301
302pub trait ImplGenericCanIsoFromToMarker: PolyRing {}
303
304impl<R, A, C> ImplGenericCanIsoFromToMarker for dense_poly::DensePolyRingBase<R, A, C>
305 where R: RingStore, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>
306{}
307
308impl<R, P> CanHomFrom<P> for SparsePolyRingBase<R>
309 where R: RingStore, R::Type: CanHomFrom<<P::BaseRing as RingStore>::Type>, P: ImplGenericCanIsoFromToMarker
310{
311 type Homomorphism = super::generic_impls::Homomorphism<P, Self>;
312
313 fn has_canonical_hom(&self, from: &P) -> Option<Self::Homomorphism> {
314 super::generic_impls::has_canonical_hom(from, self)
315 }
316
317 fn map_in(&self, from: &P, el: P::Element, hom: &Self::Homomorphism) -> Self::Element {
318 super::generic_impls::map_in(from, self, el, hom)
319 }
320}
321
322impl<R1, R2> CanHomFrom<SparsePolyRingBase<R1> > for SparsePolyRingBase<R2>
323 where R1: RingStore, R2: RingStore, R2::Type: CanHomFrom<R1::Type>
324{
325 type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
326
327 fn has_canonical_hom(&self, from: &SparsePolyRingBase<R1>) -> Option<Self::Homomorphism> {
328 self.base_ring().get_ring().has_canonical_hom(from.base_ring().get_ring())
329 }
330
331 fn map_in_ref(&self, from: &SparsePolyRingBase<R1> , el: &SparsePolyRingEl<R1>, hom: &Self::Homomorphism) -> Self::Element {
332 let mut result = SparseMapVector::new(el.data.len(), self.base_ring.clone());
333 for (j, c) in el.data.nontrivial_entries() {
334 *result.at_mut(j) = self.base_ring().get_ring().map_in_ref(from.base_ring().get_ring(), c, hom);
335 }
336 return SparsePolyRingEl {
337 data: result
338 };
339 }
340
341 fn map_in(&self, from: &SparsePolyRingBase<R1>, el: <SparsePolyRingBase<R1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
342 self.map_in_ref(from, &el, hom)
343 }
344}
345
346impl<R, P> CanIsoFromTo<P> for SparsePolyRingBase<R>
347 where R: RingStore, R::Type: CanIsoFromTo<<P::BaseRing as RingStore>::Type>, P: ImplGenericCanIsoFromToMarker
348{
349 type Isomorphism = super::generic_impls::Isomorphism<P, Self>;
350
351 fn has_canonical_iso(&self, from: &P) -> Option<Self::Isomorphism> {
352 self.base_ring().get_ring().has_canonical_iso(from.base_ring().get_ring())
353 }
354
355 fn map_out(&self, from: &P, el: Self::Element, iso: &Self::Isomorphism) -> P::Element {
356 super::generic_impls::map_out(from, self, el, iso)
357 }
358}
359
360impl<R1, R2> CanIsoFromTo<SparsePolyRingBase<R1>> for SparsePolyRingBase<R2>
361 where R1: RingStore, R2: RingStore, R2::Type: CanIsoFromTo<R1::Type>
362{
363 type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
364
365 fn has_canonical_iso(&self, from: &SparsePolyRingBase<R1>) -> Option<Self::Isomorphism> {
366 self.base_ring().get_ring().has_canonical_iso(from.base_ring().get_ring())
367 }
368
369 fn map_out(&self, from: &SparsePolyRingBase<R1>, el: Self::Element, iso: &Self::Isomorphism) -> SparsePolyRingEl<R1> {
370 let mut result = SparseMapVector::new(el.data.len(), from.base_ring.clone());
371 for (j, c) in el.data.nontrivial_entries() {
372 *result.at_mut(j) = self.base_ring().get_ring().map_out(from.base_ring().get_ring(), self.base_ring().clone_el(c), iso);
373 }
374 return SparsePolyRingEl {
375 data: result
376 };
377 }
378}
379
380pub struct TermIterator<'a, R>
381 where R: RingStore
382{
383 iter: SparseMapVectorIter<'a, Arc<R>>
384}
385
386impl<'a, R> Iterator for TermIterator<'a, R>
387 where R: RingStore
388{
389 type Item = (&'a El<R>, usize);
390
391 fn next(&mut self) -> Option<Self::Item> {
392 if let Some((i, c)) = self.iter.next() {
393 Some((c, i))
394 } else {
395 None
396 }
397 }
398}
399
400impl<R> PolyRing for SparsePolyRingBase<R>
401 where R: RingStore
402{
403 type TermsIterator<'a> = TermIterator<'a, R>
404 where Self: 'a;
405
406 fn indeterminate(&self) -> Self::Element {
407 let mut result = self.zero();
408 result.data.set_len(2);
409 *result.data.at_mut(1) = self.base_ring.one();
410 return result;
411 }
412
413 fn terms<'a>(&'a self, f: &'a Self::Element) -> TermIterator<'a, R> {
414 TermIterator {
415 iter: f.data.nontrivial_entries()
416 }
417 }
418
419 fn add_assign_from_terms<I>(&self, lhs: &mut Self::Element, rhs: I)
420 where I: IntoIterator<Item = (El<Self::BaseRing>, usize)>
421 {
422 for (c, i) in rhs {
423 lhs.data.set_len(max(lhs.data.len(), i + 1));
424 self.base_ring().add_assign(lhs.data.at_mut(i), c);
425 }
426 self.degree_truncate(&mut lhs.data);
428 }
429
430 fn coefficient_at<'a>(&'a self, f: &'a Self::Element, i: usize) -> &'a El<Self::BaseRing> {
431 if i < f.data.len() {
432 return f.data.at(i);
433 } else {
434 return &self.zero;
435 }
436 }
437
438 fn degree(&self, f: &Self::Element) -> Option<usize> {
439 f.data.len().checked_sub(1)
440 }
441
442 fn div_rem_monic(&self, mut lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
443 assert!(self.base_ring().is_one(self.coefficient_at(rhs, self.degree(rhs).unwrap())));
444 let quo = self.poly_div(&mut lhs, rhs, |x| Some(x)).unwrap();
445 return (quo, lhs);
446 }
447}
448
449impl<R> Domain for SparsePolyRingBase<R>
450 where R: RingStore, R::Type: Domain
451{}
452
453impl<R,> DivisibilityRing for SparsePolyRingBase<R>
454 where R: RingStore,
455 R::Type: DivisibilityRing + Domain
456{
457 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
458 if let Some(d) = self.degree(rhs) {
459 let lc = rhs.data.at(d);
460 let mut lhs_copy = self.clone_el(&lhs);
461 let quo = self.poly_div(&mut lhs_copy, rhs, |x| self.base_ring().checked_left_div(&x, lc))?;
462 if self.is_zero(&lhs_copy) {
463 Some(quo)
464 } else {
465 None
466 }
467 } else if self.is_zero(lhs) {
468 Some(self.zero())
469 } else {
470 None
471 }
472 }
473}
474
475impl<R> PrincipalIdealRing for SparsePolyRingBase<R>
476 where R: RingStore, R::Type: Field + PolyTFracGCDRing
477{
478 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
479 if self.is_zero(rhs) && self.is_zero(lhs) {
481 return Some(self.one());
482 } else if self.is_zero(rhs) {
483 return None;
484 }
485 let (quo, rem) = self.euclidean_div_rem(self.clone_el(lhs), rhs);
486 if self.is_zero(&rem) {
487 return Some(quo);
488 } else {
489 return None;
490 }
491 }
492
493 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
494 algorithms::eea::eea(self.clone_el(lhs), self.clone_el(rhs), RingRef::new(self))
495 }
496
497 fn ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
498 <_ as PolyTFracGCDRing>::gcd(RingRef::new(self), lhs, rhs)
499 }
500}
501
502impl<R> EuclideanRing for SparsePolyRingBase<R>
503 where R: RingStore, R::Type: Field + PolyTFracGCDRing
504{
505 fn euclidean_div_rem(&self, mut lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
506 let lc_inv = self.base_ring.invert(rhs.data.at(self.degree(rhs).unwrap())).unwrap();
507 let quo = self.poly_div(&mut lhs, rhs, |x| Some(self.base_ring().mul_ref_snd(x, &lc_inv))).unwrap();
508 return (quo, lhs);
509 }
510
511 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
512 return Some(self.degree(val).map(|x| x + 1).unwrap_or(0));
513 }
514}
515
516#[cfg(test)]
517use crate::rings::zn::*;
518#[cfg(test)]
519use crate::rings::zn::zn_static::{Zn, Fp};
520#[cfg(test)]
521use crate::rings::finite::FiniteRingStore;
522#[cfg(test)]
523use super::dense_poly::DensePolyRing;
524#[cfg(test)]
525use crate::primitive_int::StaticRing;
526
527#[cfg(test)]
528fn edge_case_elements<P: PolyRingStore>(poly_ring: P) -> impl Iterator<Item = El<P>>
529 where P::Type: PolyRing
530{
531 let base_ring = poly_ring.base_ring();
532 vec![
533 poly_ring.from_terms([].into_iter()),
534 poly_ring.from_terms([(base_ring.int_hom().map(1), 0)].into_iter()),
535 poly_ring.from_terms([(base_ring.int_hom().map(1), 1)].into_iter()),
536 poly_ring.from_terms([(base_ring.int_hom().map(1), 0), (base_ring.int_hom().map(1), 1)].into_iter()),
537 poly_ring.from_terms([(base_ring.int_hom().map(-1), 0)].into_iter()),
538 poly_ring.from_terms([(base_ring.int_hom().map(-1), 1)].into_iter()),
539 poly_ring.from_terms([(base_ring.int_hom().map(-1), 0), (base_ring.int_hom().map(1), 1)].into_iter()),
540 poly_ring.from_terms([(base_ring.int_hom().map(1), 0), (base_ring.int_hom().map(-1), 1)].into_iter()),
541 poly_ring.from_terms([(base_ring.int_hom().map(-1), 0), (base_ring.int_hom().map(1), 2)].into_iter()),
542 poly_ring.from_terms([(base_ring.int_hom().map(1), 0), (base_ring.int_hom().map(-1), 2)].into_iter()),
543 poly_ring.from_terms([(base_ring.int_hom().map(1), 0), (base_ring.int_hom().map(-1), 2), (base_ring.int_hom().map(0), 2)].into_iter())
544 ].into_iter()
545}
546
547#[test]
548fn test_ring_axioms() {
549 let poly_ring = SparsePolyRing::new(Zn::<7>::RING, "X");
550 crate::ring::generic_tests::test_ring_axioms(&poly_ring, edge_case_elements(&poly_ring));
551}
552
553#[test]
554fn test_poly_ring_axioms() {
555 let poly_ring = SparsePolyRing::new(Zn::<7>::RING, "X");
556 super::generic_tests::test_poly_ring_axioms(poly_ring, Zn::<7>::RING.elements());
557}
558
559#[test]
560fn test_canonical_iso_axioms_different_base_ring() {
561 let poly_ring1 = SparsePolyRing::new(zn_big::Zn::new(StaticRing::<i128>::RING, 7), "X");
562 let poly_ring2 = SparsePolyRing::new(zn_64::Zn::new(7), "X");
563 crate::ring::generic_tests::test_hom_axioms(&poly_ring1, &poly_ring2, edge_case_elements(&poly_ring1));
564 crate::ring::generic_tests::test_iso_axioms(&poly_ring1, &poly_ring2, edge_case_elements(&poly_ring1));
565}
566
567#[test]
568fn test_canonical_iso_dense_poly_ring() {
569 let poly_ring1 = SparsePolyRing::new(zn_64::Zn::new(7), "X");
570 let poly_ring2 = DensePolyRing::new(zn_64::Zn::new(7), "X");
571 crate::ring::generic_tests::test_hom_axioms(&poly_ring2, &poly_ring1, edge_case_elements(&poly_ring2));
572 crate::ring::generic_tests::test_iso_axioms(&poly_ring2, &poly_ring1, edge_case_elements(&poly_ring2));
573}
574
575#[test]
576fn test_divisibility_ring_axioms() {
577 let poly_ring = SparsePolyRing::new(Fp::<7>::RING, "X");
578 crate::divisibility::generic_tests::test_divisibility_axioms(&poly_ring, edge_case_elements(&poly_ring));
579}
580
581#[test]
582fn test_euclidean_ring_axioms() {
583 let poly_ring = SparsePolyRing::new(Fp::<7>::RING, "X");
584 crate::pid::generic_tests::test_euclidean_ring_axioms(&poly_ring, edge_case_elements(&poly_ring));
585}
586
587#[test]
588fn test_principal_ideal_ring_axioms() {
589 let poly_ring = SparsePolyRing::new(Fp::<7>::RING, "X");
590 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&poly_ring, edge_case_elements(&poly_ring));
591}