1use serde::de::DeserializeSeed;
2use serde::{Deserializer, Serialize, Serializer};
3
4use crate::algorithms::convolution::*;
5use crate::algorithms::interpolate::interpolate;
6use crate::algorithms::poly_div::{poly_div_rem, poly_rem};
7use crate::algorithms::poly_gcd::PolyTFracGCDRing;
8use crate::computation::no_error;
9use crate::compute_locally::{EvaluatePolyLocallyRing, InterpolationBaseRing, ToExtRingMap};
10use crate::divisibility::*;
11use crate::integer::*;
12use crate::pid::*;
13use crate::field::Field;
14use crate::primitive_int::StaticRing;
15use crate::ring::*;
16use crate::algorithms;
17use crate::rings::poly::*;
18use crate::seq::*;
19use crate::serialization::*;
20
21use std::alloc::{Allocator, Global};
22use std::cmp::min;
23
24pub struct DensePolyRingBase<R: RingStore, A: Allocator + Clone = Global, C: ConvolutionAlgorithm<R::Type> = KaratsubaAlgorithm<Global>> {
61 base_ring: R,
62 unknown_name: &'static str,
63 zero: El<R>,
64 element_allocator: A,
65 convolution_algorithm: C
66}
67
68impl<R: RingStore + Clone, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type> + Clone> Clone for DensePolyRingBase<R, A, C> {
69
70 fn clone(&self) -> Self {
71 DensePolyRingBase {
72 base_ring: <R as Clone>::clone(&self.base_ring),
73 unknown_name: self.unknown_name,
74 zero: self.base_ring.zero() ,
75 element_allocator: self.element_allocator.clone(),
76 convolution_algorithm: self.convolution_algorithm.clone()
77 }
78 }
79}
80
81pub type DensePolyRing<R, A = Global, C = KaratsubaAlgorithm> = RingValue<DensePolyRingBase<R, A, C>>;
86
87impl<R: RingStore> DensePolyRing<R> {
88
89 pub fn new(base_ring: R, unknown_name: &'static str) -> Self {
90 Self::new_with(base_ring, unknown_name, Global, STANDARD_CONVOLUTION)
91 }
92}
93
94impl<R: RingStore, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> DensePolyRing<R, A, C> {
95
96 #[stability::unstable(feature = "enable")]
97 pub fn new_with(base_ring: R, unknown_name: &'static str, element_allocator: A, convolution_algorithm: C) -> Self {
98 let zero = base_ring.zero();
99 RingValue::from(DensePolyRingBase {
100 base_ring,
101 unknown_name,
102 zero,
103 element_allocator,
104 convolution_algorithm
105 })
106 }
107}
108
109pub struct DensePolyRingEl<R: RingStore, A: Allocator + Clone = Global> {
113 data: Vec<El<R>, A>
114}
115
116impl<R: RingStore, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> RingBase for DensePolyRingBase<R, A, C> {
117
118 type Element = DensePolyRingEl<R, A>;
119
120 fn clone_el(&self, val: &Self::Element) -> Self::Element {
121 let mut data = Vec::with_capacity_in(val.data.len(), self.element_allocator.clone());
122 data.extend((0..val.data.len()).map(|i| (self.base_ring.clone_el(&val.data.at(i)))));
123 DensePolyRingEl { data }
124 }
125
126 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
127 for i in 0..min(lhs.data.len(), rhs.data.len()) {
128 self.base_ring.add_assign_ref(&mut lhs.data[i], &rhs.data[i]);
129 }
130 for i in min(lhs.data.len(), rhs.data.len())..rhs.data.len() {
131 lhs.data.push(self.base_ring().clone_el(&rhs.data[i]));
132 }
133 }
134
135 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
136 self.add_assign_ref(lhs, &rhs);
137 }
138
139 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
140 for i in 0..min(lhs.data.len(), rhs.data.len()) {
141 self.base_ring.sub_assign_ref(&mut lhs.data[i], &rhs.data[i]);
142 }
143 for i in min(lhs.data.len(), rhs.data.len())..rhs.data.len() {
144 lhs.data.push(self.base_ring().negate(self.base_ring().clone_el(&rhs.data[i])));
145 }
146 }
147
148 fn negate_inplace(&self, lhs: &mut Self::Element) {
149 for i in 0..lhs.data.len() {
150 self.base_ring.negate_inplace(&mut lhs.data[i]);
151 }
152 }
153
154 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
155 self.mul_assign_ref(lhs, &rhs);
156 }
157
158 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
159 *lhs = self.mul_ref(lhs, rhs);
160 }
161
162 fn zero(&self) -> Self::Element {
163 DensePolyRingEl {
164 data: Vec::new_in(self.element_allocator.clone())
165 }
166 }
167
168 fn from_int(&self, value: i32) -> Self::Element {
169 let mut result = self.zero();
170 result.data.push(self.base_ring().get_ring().from_int(value));
171 return result;
172 }
173
174 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
175 for i in 0..min(lhs.data.len(), rhs.data.len()) {
176 if !self.base_ring.eq_el(&lhs.data[i], &rhs.data[i]) {
177 return false;
178 }
179 }
180 let longer = if lhs.data.len() > rhs.data.len() { lhs } else { rhs };
181 for i in min(lhs.data.len(), rhs.data.len())..longer.data.len() {
182 if !self.base_ring.is_zero(&longer.data[i]) {
183 return false;
184 }
185 }
186 return true;
187 }
188
189 fn is_commutative(&self) -> bool {
190 self.base_ring.is_commutative()
191 }
192
193 fn is_noetherian(&self) -> bool {
194 self.base_ring.is_noetherian()
196 }
197
198 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, env: EnvBindingStrength) -> std::fmt::Result {
199 super::generic_impls::dbg_poly(self, value, out, self.unknown_name, env)
200 }
201
202 fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
203 self.dbg_within(value, out, EnvBindingStrength::Weakest)
204 }
205
206 fn square(&self, value: &mut Self::Element) {
207 *value = self.mul_ref(&value, &value);
208 }
209
210 fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
211 let lhs_len = if self.base_ring().get_ring().is_approximate() { lhs.data.len() } else { self.degree(lhs).map(|i| i + 1).unwrap_or(0) };
212 let rhs_len = if self.base_ring().get_ring().is_approximate() { rhs.data.len() } else { self.degree(rhs).map(|i| i + 1).unwrap_or(0) };
213 let mut result = Vec::with_capacity_in(lhs_len + rhs_len, self.element_allocator.clone());
214 result.extend((0..(lhs_len + rhs_len)).map(|_| self.base_ring().zero()));
215 self.convolution_algorithm.compute_convolution(
216 &lhs.data[0..lhs_len],
217 &rhs.data[0..rhs_len],
218 &mut result[..],
219 self.base_ring()
220 );
221 return DensePolyRingEl {
222 data: result
223 };
224 }
225
226 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
227 for i in 0..lhs.data.len() {
228 self.base_ring().int_hom().mul_assign_map(lhs.data.at_mut(i), rhs);
229 }
230 }
231
232 fn characteristic<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
233 where I::Type: IntegerRing
234 {
235 self.base_ring().characteristic(ZZ)
236 }
237
238 fn prod<I>(&self, els: I) -> Self::Element
239 where I: IntoIterator<Item = Self::Element>
240 {
241 let mut elements = els.into_iter().collect::<Vec<_>>();
242 if elements.len() == 0 {
243 return self.one();
244 }
245 elements.sort_unstable_by_key(|f| self.degree(f).unwrap_or(0));
246 for i in 0..StaticRing::<i64>::RING.abs_log2_ceil(&(elements.len() as i64)).unwrap() {
249 let step = 1 << i;
250 for j in (0..(elements.len() - step)).step_by(2 * step) {
251 let (a, b) = (&mut elements[j..(j + step + 1)]).split_at_mut(step);
252 self.mul_assign_ref(&mut a[0], &b[0]);
253 }
254 }
255 return elements.into_iter().next().unwrap();
256 }
257
258 fn is_approximate(&self) -> bool {
259 self.base_ring().get_ring().is_approximate()
260 }
261}
262
263impl<R, A, C> PartialEq for DensePolyRingBase<R, A, C>
264 where R: RingStore, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>
265{
266 fn eq(&self, other: &Self) -> bool {
267 self.base_ring.get_ring() == other.base_ring.get_ring()
268 }
269}
270
271pub trait ImplGenericCanIsoFromToMarker: PolyRing {}
281
282impl<R> ImplGenericCanIsoFromToMarker for sparse_poly::SparsePolyRingBase<R>
283 where R: RingStore
284{}
285
286impl<R, P, A, C> CanHomFrom<P> for DensePolyRingBase<R, A, C>
287 where R: RingStore, R::Type: CanHomFrom<<P::BaseRing as RingStore>::Type>, P: ImplGenericCanIsoFromToMarker, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>
288{
289 type Homomorphism = super::generic_impls::Homomorphism<P, DensePolyRingBase<R, A, C>>;
290
291 fn has_canonical_hom(&self, from: &P) -> Option<Self::Homomorphism> {
292 super::generic_impls::has_canonical_hom(from, self)
293 }
294
295 fn map_in(&self, from: &P, el: P::Element, hom: &Self::Homomorphism) -> Self::Element {
296 super::generic_impls::map_in(from, self, el, hom)
297 }
298}
299
300impl<R1, A1, R2, A2, C1, C2> CanHomFrom<DensePolyRingBase<R1, A1, C1>> for DensePolyRingBase<R2, A2, C2>
301 where R1: RingStore, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
302 R2: RingStore, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
303 R2::Type: CanHomFrom<R1::Type>
304{
305 type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
306
307 fn has_canonical_hom(&self, from: &DensePolyRingBase<R1, A1, C1>) -> Option<Self::Homomorphism> {
308 self.base_ring().get_ring().has_canonical_hom(from.base_ring().get_ring())
309 }
310
311 fn map_in_ref(&self, from: &DensePolyRingBase<R1, A1, C1>, el: &DensePolyRingEl<R1, A1>, hom: &Self::Homomorphism) -> Self::Element {
312 RingRef::new(self).from_terms((0..el.data.len()).map(|i| (self.base_ring().get_ring().map_in_ref(from.base_ring().get_ring(), &el.data[i], hom), i)))
313 }
314
315 fn map_in(&self, from: &DensePolyRingBase<R1, A1, C1>, el: DensePolyRingEl<R1, A1>, hom: &Self::Homomorphism) -> Self::Element {
316 self.map_in_ref(from, &el, hom)
317 }
318}
319
320impl<R1, A1, R2, A2, C1, C2> CanIsoFromTo<DensePolyRingBase<R1, A1, C1>> for DensePolyRingBase<R2, A2, C2>
321 where R1: RingStore, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
322 R2: RingStore, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
323 R2::Type: CanIsoFromTo<R1::Type>
324{
325 type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
326
327 fn has_canonical_iso(&self, from: &DensePolyRingBase<R1, A1, C1>) -> Option<Self::Isomorphism> {
328 self.base_ring().get_ring().has_canonical_iso(from.base_ring().get_ring())
329 }
330
331 fn map_out(&self, from: &DensePolyRingBase<R1, A1, C1>, el: DensePolyRingEl<R2, A2>, hom: &Self::Isomorphism) -> DensePolyRingEl<R1, A1> {
332 RingRef::new(from).from_terms((0..el.data.len()).map(|i| (self.base_ring().get_ring().map_out(from.base_ring().get_ring(), self.base_ring().clone_el(&el.data[i]), hom), i)))
333 }
334}
335
336impl<R, P, A, C> CanIsoFromTo<P> for DensePolyRingBase<R, A, C>
337 where R: RingStore, R::Type: CanIsoFromTo<<P::BaseRing as RingStore>::Type>, P: ImplGenericCanIsoFromToMarker, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>
338{
339 type Isomorphism = super::generic_impls::Isomorphism<P, Self>;
340
341 fn has_canonical_iso(&self, from: &P) -> Option<Self::Isomorphism> {
342 self.base_ring().get_ring().has_canonical_iso(from.base_ring().get_ring())
343 }
344
345 fn map_out(&self, from: &P, el: Self::Element, iso: &Self::Isomorphism) -> P::Element {
346 super::generic_impls::map_out(from, self, el, iso)
347 }
348}
349
350impl<R: RingStore, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> RingExtension for DensePolyRingBase<R, A, C> {
351
352 type BaseRing = R;
353
354 fn base_ring<'a>(&'a self) -> &'a Self::BaseRing {
355 &self.base_ring
356 }
357
358 fn from(&self, x: El<Self::BaseRing>) -> Self::Element {
359 let mut result = self.zero();
360 result.data.push(x);
361 return result;
362 }
363}
364
365pub struct TermIterator<'a, R>
369 where R: RingStore
370{
371 iter: std::iter::Enumerate<std::slice::Iter<'a, El<R>>>,
372 ring: &'a R
373}
374
375impl<'a, R> Clone for TermIterator<'a, R>
376 where R: RingStore
377{
378 fn clone(&self) -> Self {
379 TermIterator {
380 iter: self.iter.clone(),
381 ring: self.ring
382 }
383 }
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 while let Some((i, c)) = self.iter.next() {
393 if self.ring.get_ring().is_approximate() || !self.ring.is_zero(c) {
394 return Some((c, i));
395 }
396 }
397 return None;
398 }
399}
400
401impl<R, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> HashableElRing for DensePolyRingBase<R, A, C>
402 where R: RingStore,
403 R::Type: HashableElRing
404{
405 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
406 for i in 0..self.degree(el).map(|d| d + 1).unwrap_or(0) {
407 self.base_ring().get_ring().hash(self.coefficient_at(el, i), h);
408 }
409 }
410}
411
412impl<R, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> SerializableElementRing for DensePolyRingBase<R, A, C>
413 where R: RingStore,
414 R::Type: SerializableElementRing
415{
416 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
417 where D: Deserializer<'de>
418 {
419 DeserializeSeedNewtype::new("DensePoly", DeserializeSeedSeq::new(
420 std::iter::repeat(DeserializeWithRing::new(self.base_ring())),
421 Vec::new_in(self.element_allocator.clone()),
422 |mut current, next| { current.push(next); current }
423 )).deserialize(deserializer).map(|data| DensePolyRingEl { data })
424 }
425
426 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
427 where S: Serializer
428 {
429 let len = self.degree(el).map(|d| d + 1).unwrap_or(0);
430 SerializableNewtype::new(
431 "DensePoly",
432 SerializableSeq::new((0..len).map_fn(|i| SerializeWithRing::new(self.coefficient_at(el, i), self.base_ring())))
433 ).serialize(serializer)
434 }
435}
436
437impl<R, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> PolyRing for DensePolyRingBase<R, A, C>
438 where R: RingStore
439{
440 type TermsIterator<'a> = TermIterator<'a, R>
441 where Self: 'a;
442
443 fn indeterminate(&self) -> Self::Element {
444 let mut result = self.zero();
445 result.data.extend([self.base_ring().zero(), self.base_ring().one()].into_iter());
446 return result;
447 }
448
449 fn terms<'a>(&'a self, f: &'a Self::Element) -> TermIterator<'a, R> {
450 TermIterator {
451 iter: f.data.iter().enumerate(),
452 ring: self.base_ring()
453 }
454 }
455
456 fn add_assign_from_terms<I>(&self, lhs: &mut Self::Element, rhs: I)
457 where I: IntoIterator<Item = (El<Self::BaseRing>, usize)>
458 {
459 for (c, i) in rhs {
460 if lhs.data.len() <= i {
461 lhs.data.resize_with(i + 1, || self.base_ring().zero());
462 }
463 self.base_ring().add_assign(&mut lhs.data[i], c);
464 }
465 }
466
467 fn coefficient_at<'a>(&'a self, f: &'a Self::Element, i: usize) -> &'a El<Self::BaseRing> {
468 if i < f.data.len() {
469 return &f.data[i];
470 } else {
471 return &self.zero;
472 }
473 }
474
475 fn mul_assign_monomial(&self, lhs: &mut Self::Element, rhs_power: usize) {
476 _ = lhs.data.splice(0..0, (0..rhs_power).map(|_| self.base_ring().zero()));
477 }
478
479 fn degree(&self, f: &Self::Element) -> Option<usize> {
480 for i in (0..f.data.len()).rev() {
481 if !self.base_ring().is_zero(&f.data[i]) {
482 return Some(i);
483 }
484 }
485 return None;
486 }
487
488 fn div_rem_monic(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
489 assert!(self.base_ring().is_one(self.coefficient_at(rhs, self.degree(rhs).unwrap())));
490 let (quo, rem) = poly_div_rem(RingRef::new(self), lhs, rhs, |x| Ok(self.base_ring().clone_el(x))).unwrap_or_else(no_error);
491 return (quo, rem);
492 }
493
494 fn evaluate<S, H>(&self, f: &Self::Element, value: &S::Element, hom: H) -> S::Element
495 where S: ?Sized + RingBase,
496 H: Homomorphism<R::Type, S>
497 {
498 let d = if self.base_ring().get_ring().is_approximate() { f.data.len().saturating_sub(1) } else { self.degree(f).unwrap_or(0) };
499 let mut current = hom.map_ref(self.coefficient_at(f, d));
500 for i in (0..d).rev() {
501 hom.codomain().mul_assign_ref(&mut current, value);
502 hom.codomain().add_assign(&mut current, hom.map_ref(self.coefficient_at(f, i)));
503 }
504 return current;
505 }
506}
507
508impl<R, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> EvaluatePolyLocallyRing for DensePolyRingBase<R, A, C>
509 where R: RingStore,
510 R::Type: InterpolationBaseRing
511{
512 type LocalRing<'ring> = <R::Type as InterpolationBaseRing>::ExtendedRing<'ring>
513 where Self: 'ring;
514
515 type LocalRingBase<'ring> = <R::Type as InterpolationBaseRing>::ExtendedRingBase<'ring>
516 where Self: 'ring;
517
518 type LocalComputationData<'ring> = (ToExtRingMap<'ring, R::Type>, Vec<El<<R::Type as InterpolationBaseRing>::ExtendedRing<'ring>>>)
519 where Self: 'ring;
520
521 fn ln_pseudo_norm(&self, el: &Self::Element) -> f64 {
522 if let Some(d) = self.degree(el) {
523 return d as f64;
524 } else {
525 return 0.;
526 }
527 }
528
529 fn local_computation<'ring>(&'ring self, ln_pseudo_norm: f64) -> Self::LocalComputationData<'ring> {
530 let required_points = ln_pseudo_norm.ceil() as usize + 1;
531 ToExtRingMap::for_interpolation(self.base_ring().get_ring(), required_points)
532 }
533
534 fn local_ring_count<'ring>(&self, data: &Self::LocalComputationData<'ring>) -> usize
535 where Self: 'ring
536 {
537 data.1.len()
538 }
539
540 fn local_ring_at<'ring>(&self, data: &Self::LocalComputationData<'ring>, i: usize) -> Self::LocalRing<'ring>
541 where Self: 'ring
542 {
543 assert!(i < self.local_ring_count(data));
544 data.0.codomain().clone()
545 }
546
547 fn reduce<'ring>(&self, data: &Self::LocalComputationData<'ring>, el: &Self::Element) -> Vec<<Self::LocalRingBase<'ring> as RingBase>::Element>
548 where Self: 'ring
549 {
550 return data.1.iter().map(|x| self.evaluate(el, x, &data.0)).collect::<Vec<_>>();
551 }
552
553 fn lift_combine<'ring>(&self, data: &Self::LocalComputationData<'ring>, els: &[<Self::LocalRingBase<'ring> as RingBase>::Element]) -> Self::Element
554 where Self: 'ring
555 {
556 let base_ring = RingRef::new(data.0.codomain().get_ring());
557 let new_ring = DensePolyRing::new(base_ring, self.unknown_name);
558 let result_in_extension = interpolate(&new_ring, (&data.1).into_clone_ring_els(data.0.codomain()), els.into_clone_ring_els(data.0.codomain()), &self.element_allocator).unwrap();
559 return RingRef::new(self).from_terms(new_ring.terms(&result_in_extension).map(|(c, i)| (data.0.as_base_ring_el(base_ring.clone_el(c)), i)));
560 }
561}
562
563impl<R, A: Allocator + Clone, C: ConvolutionAlgorithm<R::Type>> Domain for DensePolyRingBase<R, A, C>
564 where R: RingStore, R::Type: Domain
565{}
566
567impl<R, A: Allocator + Clone, C> DivisibilityRing for DensePolyRingBase<R, A, C>
568 where R: RingStore,
569 R::Type: DivisibilityRing + Domain,
570 C: ConvolutionAlgorithm<R::Type>
571{
572 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
573 if let Some(d) = self.degree(rhs) {
574 if d == 0 {
575 let rhs = self.coefficient_at(rhs, 0);
576 return RingRef::new(self).try_from_terms(self.terms(lhs).map(|(c, i)| (self.base_ring().checked_left_div(c, rhs).map(|c| (c, i)).ok_or(())))).ok();
577 } else {
578 let lc = &rhs.data[d];
579 let (quo, rem) = poly_div_rem(RingRef::new(self), self.clone_el(lhs), rhs, |x| self.base_ring().checked_left_div(&x, lc).ok_or(())).ok()?;
580 if self.is_zero(&rem) {
581 Some(quo)
582 } else {
583 None
584 }
585 }
586 } else if self.is_zero(lhs) {
587 Some(self.zero())
588 } else {
589 None
590 }
591 }
592
593 fn divides_left(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
594 if let Some(d) = self.degree(rhs) {
595 if d == 0 {
596 true
597 } else {
598 let lc = &rhs.data[d];
599 if let Ok(rem) = poly_rem(RingRef::new(self), self.clone_el(lhs), rhs, |x| self.base_ring().checked_left_div(&x, lc).ok_or(())) {
600 if self.is_zero(&rem) {
601 true
602 } else {
603 false
604 }
605 } else {
606 false
607 }
608 }
609 } else if self.is_zero(lhs) {
610 true
611 } else {
612 false
613 }
614 }
615
616 fn balance_factor<'a, I>(&self, elements: I) -> Option<Self::Element>
617 where I: Iterator<Item = &'a Self::Element>,
618 Self: 'a
619 {
620 self.base_ring().get_ring().balance_factor(elements.flat_map(|f| self.terms(f).map(|(c, _)| c))).map(|c| RingRef::new(self).inclusion().map(c))
621 }
622}
623
624impl<R, A, C> PrincipalIdealRing for DensePolyRingBase<R, A, C>
625 where A: Allocator + Clone, R: RingStore, R::Type: Field + PolyTFracGCDRing, C: ConvolutionAlgorithm<R::Type>
626{
627 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
628 if self.is_zero(rhs) && self.is_zero(lhs) {
630 return Some(self.one());
631 } else if self.is_zero(rhs) {
632 return None;
633 }
634 let (quo, rem) = self.euclidean_div_rem(self.clone_el(lhs), rhs);
635 if self.is_zero(&rem) {
636 return Some(quo);
637 } else {
638 return None;
639 }
640 }
641
642 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
643 algorithms::eea::eea(self.clone_el(lhs), self.clone_el(rhs), &RingRef::new(self))
644 }
645
646 fn ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
647 <_ as PolyTFracGCDRing>::gcd(RingRef::new(self), lhs, rhs)
648 }
649}
650
651impl<R, A, C> EuclideanRing for DensePolyRingBase<R, A, C>
652 where A: Allocator + Clone, R: RingStore, R::Type: Field + PolyTFracGCDRing, C: ConvolutionAlgorithm<R::Type>
653{
654 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
655 let lc_inv = self.base_ring.invert(&rhs.data[self.degree(rhs).unwrap()]).unwrap();
656 let (quo, rem) = poly_div_rem(RingRef::new(self), lhs, rhs, |x| Ok(self.base_ring().mul_ref(&x, &lc_inv))).unwrap_or_else(no_error);
657 return (quo, rem);
658 }
659
660 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
661 return Some(self.degree(val).map(|x| x + 1).unwrap_or(0));
662 }
663}
664
665#[cfg(test)]
666use crate::rings::zn::*;
667#[cfg(test)]
668use crate::rings::zn::zn_static::{Zn, Fp};
669#[cfg(test)]
670use crate::rings::finite::FiniteRingStore;
671#[cfg(test)]
672use super::sparse_poly::SparsePolyRing;
673#[cfg(test)]
674use crate::rings::extension::FreeAlgebraStore;
675#[cfg(test)]
676use crate::iters::multiset_combinations;
677#[cfg(test)]
678use crate::rings::extension::galois_field::GaloisField;
679#[cfg(test)]
680use std::time::Instant;
681#[cfg(test)]
682use crate::rings::float_real::Real64;
683#[cfg(test)]
684use crate::ordered::OrderedRingStore;
685#[cfg(test)]
686use test::Bencher;
687#[cfg(test)]
688use crate::algorithms::cyclotomic::cyclotomic_polynomial;
689
690#[cfg(test)]
691fn edge_case_elements<P: PolyRingStore>(poly_ring: P) -> impl Iterator<Item = El<P>>
692 where P::Type: PolyRing
693{
694 let base_ring = poly_ring.base_ring();
695 vec![
696 poly_ring.from_terms([].into_iter()),
697 poly_ring.from_terms([(base_ring.int_hom().map(1), 0)].into_iter()),
698 poly_ring.from_terms([(base_ring.int_hom().map(1), 1)].into_iter()),
699 poly_ring.from_terms([(base_ring.int_hom().map(1), 0), (base_ring.int_hom().map(1), 1)].into_iter()),
700 poly_ring.from_terms([(base_ring.int_hom().map(-1), 0)].into_iter()),
701 poly_ring.from_terms([(base_ring.int_hom().map(-1), 1)].into_iter()),
702 poly_ring.from_terms([(base_ring.int_hom().map(-1), 0), (base_ring.int_hom().map(1), 1)].into_iter()),
703 poly_ring.from_terms([(base_ring.int_hom().map(1), 0), (base_ring.int_hom().map(-1), 1)].into_iter())
704 ].into_iter()
705}
706
707#[test]
708fn test_prod() {
709 let poly_ring = DensePolyRing::new(StaticRing::<i64>::RING, "X");
710 assert_el_eq!(&poly_ring, poly_ring.one(), poly_ring.prod([].into_iter()));
711
712 let product = poly_ring.prod((0..10).map(|n| poly_ring.add(poly_ring.indeterminate(), poly_ring.inclusion().map(n))));
713 assert_eq!(Some(10), poly_ring.degree(&product));
714 for i in 0..10 {
715 let expected = multiset_combinations(&[1; 10], 10 - i, |indices| {
716 indices.iter().enumerate().filter(|(_, count)| **count > 0).map(|(n, _)| n).product::<usize>()
717 }).sum::<usize>();
718 assert_eq!(expected as i64, *poly_ring.coefficient_at(&product, i));
719 }
720}
721
722#[test]
723fn test_ring_axioms() {
724 let poly_ring = DensePolyRing::new(Zn::<7>::RING, "X");
725 crate::ring::generic_tests::test_ring_axioms(&poly_ring, edge_case_elements(&poly_ring));
726}
727
728#[test]
729fn test_hash_axioms() {
730 let poly_ring = DensePolyRing::new(Zn::<7>::RING, "X");
731 crate::ring::generic_tests::test_hash_axioms(&poly_ring, edge_case_elements(&poly_ring));
732}
733
734#[test]
735fn test_poly_ring_axioms() {
736 let poly_ring = DensePolyRing::new(Zn::<7>::RING, "X");
737 super::generic_tests::test_poly_ring_axioms(poly_ring, Zn::<7>::RING.elements());
738}
739
740#[test]
741fn test_divisibility_ring_axioms() {
742 let poly_ring = DensePolyRing::new(Fp::<7>::RING, "X");
743 crate::divisibility::generic_tests::test_divisibility_axioms(&poly_ring, edge_case_elements(&poly_ring));
744}
745
746#[test]
747fn test_euclidean_ring_axioms() {
748 let poly_ring = DensePolyRing::new(Fp::<7>::RING, "X");
749 crate::pid::generic_tests::test_euclidean_ring_axioms(&poly_ring, edge_case_elements(&poly_ring));
750}
751
752#[test]
753fn test_principal_ideal_ring_axioms() {
754 let poly_ring = DensePolyRing::new(Fp::<7>::RING, "X");
755 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&poly_ring, edge_case_elements(&poly_ring));
756}
757
758#[test]
759fn test_canonical_iso_axioms_different_base_ring() {
760 let poly_ring1 = DensePolyRing::new(zn_big::Zn::new(StaticRing::<i128>::RING, 7), "X");
761 let poly_ring2 = DensePolyRing::new(zn_64::Zn::new(7), "X");
762 crate::ring::generic_tests::test_hom_axioms(&poly_ring1, &poly_ring2, edge_case_elements(&poly_ring1));
763 crate::ring::generic_tests::test_iso_axioms(&poly_ring1, &poly_ring2, edge_case_elements(&poly_ring1));
764}
765
766#[test]
767fn test_canonical_iso_sparse_poly_ring() {
768 let poly_ring1 = SparsePolyRing::new(zn_64::Zn::new(7), "X");
769 let poly_ring2 = DensePolyRing::new(zn_64::Zn::new(7), "X");
770 crate::ring::generic_tests::test_hom_axioms(&poly_ring1, &poly_ring2, edge_case_elements(&poly_ring1));
771 crate::ring::generic_tests::test_iso_axioms(&poly_ring1, &poly_ring2, edge_case_elements(&poly_ring1));
772}
773
774#[test]
775fn test_print() {
776 let base_poly_ring = DensePolyRing::new(StaticRing::<i64>::RING, "X");
777 let poly_ring = DensePolyRing::new(&base_poly_ring, "Y");
778
779 let poly = poly_ring.from_terms([
780 (base_poly_ring.from_terms([(1, 0), (2, 2)].into_iter()), 0),
781 (base_poly_ring.from_terms([(3, 0), (4, 2)].into_iter()), 2)
782 ].into_iter());
783 assert_eq!("1 + 2X^2 + (3 + 4X^2)Y^2", format!("{}", poly_ring.format(&poly)));
784
785 let poly = poly_ring.from_terms([
786 (base_poly_ring.zero(), 0),
787 (base_poly_ring.from_terms([(4, 2)].into_iter()), 2)
788 ].into_iter());
789 assert_eq!("(4X^2)Y^2", format!("{}", poly_ring.format(&poly)));
790}
791
792#[test]
793#[ignore]
794fn test_expensive_prod() {
795 let ring = GaloisField::new(17, 2048);
796 let poly_ring = DensePolyRing::new(&ring, "X");
797 let mut rng = oorandom::Rand64::new(1);
798 let a = ring.random_element(|| rng.rand_u64());
799
800 let start = Instant::now();
801 let product = poly_ring.prod(
802 (0..2048).scan(ring.clone_el(&a), |current, _| {
803 let result = poly_ring.sub(poly_ring.indeterminate(), poly_ring.inclusion().map_ref(¤t));
804 *current = ring.pow(std::mem::replace(current, ring.zero()), 17);
805 return Some(result);
806 })
807 );
808 let end = Instant::now();
809
810 println!("Computed product in {} ms", (end - start).as_millis());
811 for i in 0..2048 {
812 let coeff_wrt_basis = ring.wrt_canonical_basis(poly_ring.coefficient_at(&product, i));
813 assert!((1..2028).all(|j| ring.base_ring().is_zero(&coeff_wrt_basis.at(j))));
814 }
815}
816
817#[test]
818fn test_serialize() {
819 let poly_ring = DensePolyRing::new(Zn::<7>::RING, "X");
820 crate::serialization::generic_tests::test_serialization(&poly_ring, edge_case_elements(&poly_ring));
821}
822
823#[test]
824fn test_evaluate_approximate_ring() {
825 let ring = DensePolyRing::new(Real64::RING, "X");
826 let [f] = ring.with_wrapped_indeterminate(|X| [X * X * X - X + 1]);
827 let x = 0.47312;
828 assert!(Real64::RING.abs((x * x * x - x + 1.) - ring.evaluate(&f, &x, &Real64::RING.identity())) <= 0.000000001);
829}
830
831#[bench]
832fn bench_div_rem_monic(bencher: &mut Bencher) {
833 let ZZ = BigIntRing::RING;
834 let ring = DensePolyRing::new(ZZ, "X");
835 let phi_n = 30 * 40;
836 let n = 31 * 41;
837 let cyclotomic_poly = cyclotomic_polynomial(&ring, n);
838 assert!(ring.degree(&cyclotomic_poly).unwrap() == phi_n);
839 bencher.iter(|| {
840 let mut current = ring.pow(ring.indeterminate(), phi_n - 1);
841 for _ in phi_n..=n {
842 ring.mul_assign_monomial(&mut current, 1);
843 current = ring.div_rem_monic(current, &cyclotomic_poly).1;
844 }
845 assert_el_eq!(&ring, &ring.one(), ¤t);
846 });
847}