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