1use std::alloc::{Allocator, Global};
2use std::cell::OnceCell;
3use std::fmt::{Debug, Formatter};
4use std::marker::PhantomData;
5use std::mem::replace;
6
7use feanor_serde::dependent_tuple::DeserializeSeedDependentTuple;
8use feanor_serde::newtype_struct::{DeserializeSeedNewtypeStruct, *};
9use feanor_serde::seq::*;
10use serde::de::DeserializeSeed;
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12
13use super::{FreeAlgebra, FreeAlgebraStore};
14use crate::algorithms::convolution::*;
15use crate::algorithms::extension_ops::create_multiplication_matrix;
16use crate::algorithms::linsolve::LinSolveRing;
17use crate::delegate::DelegateRing;
18use crate::divisibility::*;
19use crate::homomorphism::*;
20use crate::integer::{IntegerRingStore, *};
21use crate::iters::{MultiProduct, multi_cartesian_product};
22use crate::matrix::OwnedMatrix;
23use crate::primitive_int::StaticRing;
24use crate::ring::*;
25use crate::rings::finite::*;
26use crate::rings::poly::PolyRingStore;
27use crate::rings::poly::dense_poly::DensePolyRing;
28use crate::seq::sparse::SparseMapVector;
29use crate::seq::*;
30use crate::serialization::*;
31use crate::specialization::*;
32use crate::{
33 impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos, impl_localpir_wrap_unwrap_homs,
34 impl_localpir_wrap_unwrap_isos,
35};
36
37pub struct FreeAlgebraImplBase<R, V, A = Global, C = KaratsubaAlgorithm>
54where
55 R: RingStore,
56 V: VectorView<El<R>>,
57 A: Allocator + Clone,
58 C: ConvolutionAlgorithm<R::Type>,
59{
60 base_ring: R,
61 x_pow_rank: V,
62 element_allocator: A,
63 log2_padded_len: usize,
64 rank: usize,
65 gen_name: &'static str,
66 convolution: C,
67}
68
69pub type FreeAlgebraImpl<R, V, A = Global, C = KaratsubaAlgorithm> = RingValue<FreeAlgebraImplBase<R, V, A, C>>;
73
74impl<R, V> FreeAlgebraImpl<R, V>
75where
76 R: RingStore,
77 V: VectorView<El<R>>,
78{
79 pub fn new(base_ring: R, rank: usize, x_pow_rank: V) -> Self {
83 Self::new_with_convolution(base_ring, rank, x_pow_rank, "θ", Global, STANDARD_CONVOLUTION)
84 }
85}
86
87impl<R, V, A, C> Clone for FreeAlgebraImplBase<R, V, A, C>
88where
89 R: RingStore + Clone,
90 V: VectorView<El<R>> + Clone,
91 A: Allocator + Clone,
92 C: ConvolutionAlgorithm<R::Type> + Clone,
93{
94 fn clone(&self) -> Self {
95 Self {
96 base_ring: self.base_ring.clone(),
97 x_pow_rank: self.x_pow_rank.clone(),
98 element_allocator: self.element_allocator.clone(),
99 log2_padded_len: self.log2_padded_len,
100 rank: self.rank,
101 convolution: self.convolution.clone(),
102 gen_name: self.gen_name,
103 }
104 }
105}
106
107impl<R, V, A, C> Copy for FreeAlgebraImplBase<R, V, A, C>
108where
109 R: RingStore + Copy,
110 V: VectorView<El<R>> + Copy,
111 A: Allocator + Copy,
112 C: ConvolutionAlgorithm<R::Type> + Copy,
113 El<R>: Copy,
114{
115}
116
117pub struct FreeAlgebraImplEl<R, A = Global>
119where
120 R: RingStore,
121 A: Allocator,
122{
123 values: Box<[El<R>], A>,
124}
125
126impl<R, A> Debug for FreeAlgebraImplEl<R, A>
127where
128 R: RingStore,
129 A: Allocator,
130 El<R>: Debug,
131{
132 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", &self.values) }
133}
134
135impl<R, V, A, C> FreeAlgebraImpl<R, V, A, C>
136where
137 R: RingStore,
138 V: VectorView<El<R>>,
139 A: Allocator + Clone,
140 C: ConvolutionAlgorithm<R::Type>,
141{
142 #[stability::unstable(feature = "enable")]
143 pub fn new_with_convolution(
144 base_ring: R,
145 rank: usize,
146 x_pow_rank: V,
147 gen_name: &'static str,
148 element_allocator: A,
149 convolution: C,
150 ) -> Self {
151 assert!(rank >= 1);
152 assert!(x_pow_rank.len() <= rank);
153 let log2_padded_len = StaticRing::<i64>::RING
154 .abs_log2_ceil(&rank.try_into().unwrap())
155 .unwrap();
156 RingValue::from(FreeAlgebraImplBase {
157 base_ring,
158 gen_name,
159 x_pow_rank,
160 element_allocator,
161 rank,
162 log2_padded_len,
163 convolution,
164 })
165 }
166}
167
168impl<R, V, A, C> FreeAlgebraImplBase<R, V, A, C>
169where
170 R: RingStore,
171 V: VectorView<El<R>>,
172 A: Allocator + Clone,
173 C: ConvolutionAlgorithm<R::Type>,
174{
175 #[stability::unstable(feature = "enable")]
176 pub fn set_convolution<C_new: ConvolutionAlgorithm<R::Type>>(
177 self,
178 new_convolution: C_new,
179 ) -> FreeAlgebraImpl<R, V, A, C_new> {
180 RingValue::from(FreeAlgebraImplBase {
181 base_ring: self.base_ring,
182 x_pow_rank: self.x_pow_rank,
183 element_allocator: self.element_allocator,
184 log2_padded_len: self.log2_padded_len,
185 rank: self.rank,
186 convolution: new_convolution,
187 gen_name: self.gen_name,
188 })
189 }
190
191 #[stability::unstable(feature = "enable")]
192 pub fn allocator(&self) -> &A { &self.element_allocator }
193
194 #[stability::unstable(feature = "enable")]
195 pub fn gen_name(&self) -> &'static str { self.gen_name }
196
197 #[stability::unstable(feature = "enable")]
198 pub fn x_pow_rank(&self) -> &V { &self.x_pow_rank }
199
200 #[stability::unstable(feature = "enable")]
201 pub fn convolution(&self) -> &C { &self.convolution }
202
203 fn reduce_mod_poly(&self, data: &mut [El<R>]) {
204 struct ReduceModulo<'a, R>
205 where
206 R: RingStore,
207 {
208 rank: usize,
209 base_ring: &'a R,
210 data: &'a mut [El<R>],
211 }
212
213 impl<'a, R> SparseVectorViewOperation<El<R>> for ReduceModulo<'a, R>
214 where
215 R: RingStore,
216 {
217 type Output<'b>
218 = ()
219 where
220 Self: 'b;
221
222 fn execute<'b, V: 'b + VectorViewSparse<El<R>>>(self, vector: V) {
223 for i in (self.rank..(2 * self.rank)).rev() {
224 for (j, c) in vector.nontrivial_entries() {
225 let add = self.base_ring.mul_ref(c, &self.data[i]);
226 self.base_ring.add_assign(&mut self.data[i - self.rank + j], add);
227 }
228 }
229 }
230 }
231
232 let was_sparse = self.x_pow_rank.specialize_sparse(ReduceModulo {
233 rank: self.rank,
234 base_ring: self.base_ring(),
235 data,
236 });
237 if was_sparse.is_none() {
238 for i in (self.rank()..(2 * self.rank())).rev() {
239 for j in 0..self.x_pow_rank.len() {
240 let add = self.base_ring.mul_ref(self.x_pow_rank.at(j), &data[i]);
241 self.base_ring.add_assign(&mut data[i - self.rank() + j], add);
242 }
243 }
244 }
245 }
246}
247
248impl<R, V, A, C> PartialEq for FreeAlgebraImplBase<R, V, A, C>
249where
250 R: RingStore,
251 V: VectorView<El<R>>,
252 A: Allocator + Clone,
253 C: ConvolutionAlgorithm<R::Type>,
254{
255 fn eq(&self, other: &Self) -> bool {
256 self.base_ring().get_ring() == other.base_ring().get_ring()
257 && self.rank() == other.rank()
258 && (0..self.rank()).all(|i| {
259 (i >= self.x_pow_rank.len() && i >= other.x_pow_rank.len())
260 || (i >= self.x_pow_rank.len() && self.base_ring().is_zero(other.x_pow_rank.at(i)))
261 || (i >= other.x_pow_rank.len() && self.base_ring().is_zero(self.x_pow_rank.at(i)))
262 || self.base_ring().eq_el(self.x_pow_rank.at(i), other.x_pow_rank.at(i))
263 })
264 }
265}
266
267impl<R, V, A, C> RingBase for FreeAlgebraImplBase<R, V, A, C>
268where
269 R: RingStore,
270 V: VectorView<El<R>>,
271 A: Allocator + Clone,
272 C: ConvolutionAlgorithm<R::Type>,
273{
274 type Element = FreeAlgebraImplEl<R, A>;
275
276 fn clone_el(&self, val: &Self::Element) -> Self::Element {
277 debug_assert_eq!(1 << self.log2_padded_len, val.values.len());
278 let mut result_values = Vec::with_capacity_in(val.values.len(), self.element_allocator.clone());
279 result_values.extend(val.values.iter().map(|x| self.base_ring().clone_el(x)));
280 return FreeAlgebraImplEl {
281 values: result_values.into_boxed_slice(),
282 };
283 }
284
285 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
286 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
287 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
288 for i in 0..self.rank() {
289 self.base_ring().add_assign_ref(&mut lhs.values[i], &rhs.values[i]);
290 }
291 }
292
293 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
294 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
295 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
296 for (i, x) in (0..self.rank()).zip(rhs.values.iter()) {
297 self.base_ring().add_assign_ref(&mut lhs.values[i], x);
298 }
299 }
300
301 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
302 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
303 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
304 for i in 0..self.rank() {
305 self.base_ring().sub_assign_ref(&mut lhs.values[i], &rhs.values[i]);
306 }
307 }
308
309 fn negate_inplace(&self, lhs: &mut Self::Element) {
310 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
311 for i in 0..self.rank() {
312 self.base_ring().negate_inplace(&mut lhs.values[i]);
313 }
314 }
315
316 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
317 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
318 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
319 self.mul_assign_ref(lhs, &rhs)
320 }
321
322 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { *lhs = self.fma(lhs, rhs, self.zero()); }
323
324 fn fma(&self, lhs: &Self::Element, rhs: &Self::Element, summand: Self::Element) -> Self::Element {
325 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
326 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
327 debug_assert_eq!(1 << self.log2_padded_len, summand.values.len());
328 let mut tmp = summand.values.into_vec();
329 tmp.resize_with(2 << self.log2_padded_len, || self.base_ring.zero());
330 self.convolution
331 .compute_convolution(&lhs.values[..], &rhs.values[..], &mut tmp[..], self.base_ring());
332 self.reduce_mod_poly(&mut tmp);
333 tmp.truncate(1 << self.log2_padded_len);
334 for i in self.rank()..(1 << self.log2_padded_len) {
335 tmp[i] = self.base_ring().zero();
336 }
337 return FreeAlgebraImplEl {
338 values: tmp.into_boxed_slice(),
339 };
340 }
341
342 fn from_int(&self, value: i32) -> Self::Element { self.from(self.base_ring().int_hom().map(value)) }
343
344 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
345 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
346 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
347 (0..self.rank()).all(|i| self.base_ring().eq_el(&lhs.values[i], &rhs.values[i]))
348 }
349
350 fn is_zero(&self, value: &Self::Element) -> bool {
351 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
352 (0..self.rank()).all(|i| self.base_ring.is_zero(&value.values[i]))
353 }
354
355 fn is_one(&self, value: &Self::Element) -> bool {
356 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
357 self.base_ring().is_one(&value.values[0]) && (1..self.rank()).all(|i| self.base_ring.is_zero(&value.values[i]))
358 }
359
360 fn is_neg_one(&self, value: &Self::Element) -> bool {
361 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
362 self.base_ring().is_neg_one(&value.values[0])
363 && (1..self.rank()).all(|i| self.base_ring.is_zero(&value.values[i]))
364 }
365
366 fn is_commutative(&self) -> bool { self.base_ring().is_commutative() }
367
368 fn is_noetherian(&self) -> bool { self.base_ring().is_noetherian() }
369
370 fn is_approximate(&self) -> bool { self.base_ring().get_ring().is_approximate() }
371
372 fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
373 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
374 self.dbg_within(value, out, EnvBindingStrength::Weakest)
375 }
376
377 fn dbg_within<'a>(
378 &self,
379 value: &Self::Element,
380 out: &mut std::fmt::Formatter<'a>,
381 env: EnvBindingStrength,
382 ) -> std::fmt::Result {
383 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
384 let poly_ring = DensePolyRing::new(self.base_ring(), self.gen_name);
385 poly_ring.get_ring().dbg_within(
386 &RingRef::new(self).poly_repr(&poly_ring, value, &self.base_ring().identity()),
387 out,
388 env,
389 )
390 }
391
392 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
393 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
394 for i in 0..self.rank() {
395 self.base_ring().int_hom().mul_assign_map(&mut lhs.values[i], rhs);
396 }
397 }
398
399 fn fma_int(&self, lhs: &Self::Element, rhs: i32, summand: Self::Element) -> Self::Element {
400 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
401 debug_assert_eq!(1 << self.log2_padded_len, summand.values.len());
402 let mut result = Vec::new_in(self.allocator().clone());
403 result.extend(
404 summand
405 .values
406 .into_iter()
407 .enumerate()
408 .map(|(i, x)| self.base_ring().int_hom().fma_map(&lhs.values[i], &rhs, x)),
409 );
410 return FreeAlgebraImplEl {
411 values: result.into_boxed_slice(),
412 };
413 }
414
415 fn characteristic<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
416 where
417 I::Type: IntegerRing,
418 {
419 self.base_ring().characteristic(ZZ)
420 }
421
422 fn square(&self, value: &mut Self::Element) {
423 let mut tmp = Vec::with_capacity_in(2 << self.log2_padded_len, self.element_allocator.clone());
424 tmp.resize_with(2 << self.log2_padded_len, || self.base_ring().zero());
425 let x_prepared =
426 self.convolution
427 .prepare_convolution_operand(&value.values[..], Some(2 * self.rank()), self.base_ring());
428 self.convolution.compute_convolution_prepared(
429 &value.values[..],
430 Some(&x_prepared),
431 &value.values[..],
432 Some(&x_prepared),
433 &mut tmp,
434 self.base_ring(),
435 );
436 self.reduce_mod_poly(&mut tmp);
437 for i in 0..self.rank() {
438 value.values[i] = std::mem::replace(&mut tmp[i], self.base_ring().zero());
439 }
440 }
441}
442
443impl<R, V, A, C> RingExtension for FreeAlgebraImplBase<R, V, A, C>
444where
445 R: RingStore,
446 V: VectorView<El<R>>,
447 A: Allocator + Clone,
448 C: ConvolutionAlgorithm<R::Type>,
449{
450 type BaseRing = R;
451
452 fn base_ring(&self) -> &Self::BaseRing { &self.base_ring }
453
454 fn from(&self, x: El<Self::BaseRing>) -> Self::Element {
455 let mut result_values = Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone());
456 result_values.push(x);
457 result_values.extend((0..((1 << self.log2_padded_len) - 1)).map(|_| self.base_ring().zero()));
458 return FreeAlgebraImplEl {
459 values: result_values.into_boxed_slice(),
460 };
461 }
462
463 fn mul_assign_base(&self, lhs: &mut Self::Element, rhs: &El<Self::BaseRing>) {
464 for i in 0..self.rank() {
465 self.base_ring().mul_assign_ref(&mut lhs.values[i], rhs);
466 }
467 }
468
469 fn fma_base(&self, lhs: &Self::Element, rhs: &El<Self::BaseRing>, summand: Self::Element) -> Self::Element {
470 let mut new = Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone());
471 new.extend(
472 summand
473 .values
474 .into_iter()
475 .take(self.rank())
476 .enumerate()
477 .map(|(i, x)| self.base_ring.fma(&lhs.values[i], rhs, x)),
478 );
479 new.resize_with(1 << self.log2_padded_len, || self.base_ring().zero());
480 return FreeAlgebraImplEl {
481 values: new.into_boxed_slice(),
482 };
483 }
484}
485
486impl<R, V, A, C> DivisibilityRing for FreeAlgebraImplBase<R, V, A, C>
497where
498 R: RingStore,
499 R::Type: LinSolveRing,
500 V: VectorView<El<R>>,
501 A: Allocator + Clone,
502 C: ConvolutionAlgorithm<R::Type>,
503{
504 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
505 let mut mul_matrix: OwnedMatrix<_, _> =
506 create_multiplication_matrix(RingRef::new(self), rhs, self.allocator().clone());
507 let mut lhs_matrix: OwnedMatrix<_, _> =
508 OwnedMatrix::zero_in(self.rank(), 1, self.base_ring(), self.allocator().clone());
509 let data = self.wrt_canonical_basis(lhs);
510 for j in 0..self.rank() {
511 *lhs_matrix.at_mut(j, 0) = data.at(j);
512 }
513 let mut solution: OwnedMatrix<_, _> =
514 OwnedMatrix::zero_in(self.rank(), 1, self.base_ring(), self.allocator().clone());
515 let has_sol = self.base_ring().get_ring().solve_right(
516 mul_matrix.data_mut(),
517 lhs_matrix.data_mut(),
518 solution.data_mut(),
519 Global,
520 );
521 if has_sol.is_solved() {
522 return Some(
523 self.from_canonical_basis((0..self.rank()).map(|i| self.base_ring().clone_el(solution.at(i, 0)))),
524 );
525 } else {
526 return None;
527 }
528 }
529
530 fn balance_factor<'a, I>(&self, elements: I) -> Option<Self::Element>
531 where
532 I: Iterator<Item = &'a Self::Element>,
533 Self: 'a,
534 {
535 self.base_ring()
536 .get_ring()
537 .balance_factor(elements.flat_map(|x| x.values.iter()))
538 .map(|c| RingRef::new(self).inclusion().map(c))
539 }
540
541 default fn invert(&self, el: &Self::Element) -> Option<Self::Element> { self.checked_left_div(&self.one(), el) }
542}
543
544impl<R, V, A, C> Debug for FreeAlgebraImplBase<R, V, A, C>
545where
546 R: RingStore + Debug,
547 V: VectorView<El<R>>,
548 A: Allocator + Clone,
549 C: ConvolutionAlgorithm<R::Type>,
550{
551 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
552 let poly_ring = DensePolyRing::new(self.base_ring(), self.gen_name);
553 f.debug_struct("FreeAlgebraImplBase")
554 .field("base_ring", &self.base_ring)
555 .field(
556 "modulus",
557 &poly_ring.format(&RingRef::new(self).generating_poly(&poly_ring, self.base_ring.identity())),
558 )
559 .finish()
560 }
561}
562
563impl<R, V> Serialize for FreeAlgebraImplBase<R, V, Global, KaratsubaAlgorithm>
564where
565 R: RingStore + Serialize,
566 R::Type: SerializableElementRing,
567 V: VectorView<El<R>>,
568{
569 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
570 where
571 S: Serializer,
572 {
573 let poly_ring = DensePolyRing::new(self.base_ring(), "X");
574 SerializableNewtypeStruct::new(
575 "FreeAlgebraImpl",
576 (
577 self.base_ring(),
578 SerializeOwnedWithRing::new(
579 RingRef::new(self).generating_poly(&poly_ring, self.base_ring().identity()),
580 poly_ring,
581 ),
582 ),
583 )
584 .serialize(serializer)
585 }
586}
587
588impl<'de, R> Deserialize<'de> for FreeAlgebraImplBase<R, SparseMapVector<R>, Global, KaratsubaAlgorithm>
589where
590 R: RingStore + Deserialize<'de> + Clone,
591 R::Type: SerializableElementRing,
592{
593 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
594 where
595 D: Deserializer<'de>,
596 {
597 let ring_cell = OnceCell::new();
598 let poly = <_ as DeserializeSeed<'de>>::deserialize(
599 DeserializeSeedNewtypeStruct::new(
600 "FreeAlgebraImpl",
601 DeserializeSeedDependentTuple::new(PhantomData::<R>, |ring| {
602 let poly_ring = DensePolyRing::new(ring, "X");
603 ring_cell.set(poly_ring).ok().unwrap();
604 DeserializeWithRing::new(ring_cell.get().unwrap())
605 }),
606 ),
607 deserializer,
608 )?;
609 let poly_ring = ring_cell.into_inner().unwrap();
610 assert!(poly_ring.base_ring().is_one(poly_ring.lc(&poly).unwrap()));
611 let rank = poly_ring.degree(&poly).unwrap();
612 let mut x_pow_rank = SparseMapVector::new(rank, (*poly_ring.base_ring()).clone());
613 for (c, i) in poly_ring.terms(&poly) {
614 *x_pow_rank.at_mut(i) = poly_ring.base_ring().negate(poly_ring.base_ring().clone_el(c));
615 }
616 _ = x_pow_rank.at_mut(0);
617 return Ok(FreeAlgebraImpl::new_with_convolution(
618 poly_ring.into().into_base_ring(),
619 rank,
620 x_pow_rank,
621 "θ",
622 Global,
623 STANDARD_CONVOLUTION,
624 )
625 .into());
626 }
627}
628
629impl<'de, R> Deserialize<'de> for FreeAlgebraImplBase<R, Vec<El<R>>, Global, KaratsubaAlgorithm>
630where
631 R: RingStore + Deserialize<'de>,
632 R::Type: SerializableElementRing,
633{
634 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
635 where
636 D: Deserializer<'de>,
637 {
638 let ring_cell = OnceCell::new();
639 let poly = <_ as DeserializeSeed<'de>>::deserialize(
640 DeserializeSeedNewtypeStruct::new(
641 "FreeAlgebraImpl",
642 DeserializeSeedDependentTuple::new(PhantomData::<R>, |ring| {
643 let poly_ring = DensePolyRing::new(ring, "X");
644 ring_cell.set(poly_ring).ok().unwrap();
645 DeserializeWithRing::new(ring_cell.get().unwrap())
646 }),
647 ),
648 deserializer,
649 )?;
650 let poly_ring = ring_cell.into_inner().unwrap();
651 assert!(poly_ring.base_ring().is_one(poly_ring.lc(&poly).unwrap()));
652 let rank = poly_ring.degree(&poly).unwrap();
653 let x_pow_rank = (0..rank)
654 .map(|i| {
655 poly_ring
656 .base_ring()
657 .negate(poly_ring.base_ring().clone_el(poly_ring.coefficient_at(&poly, i)))
658 })
659 .collect::<Vec<_>>();
660 return Ok(FreeAlgebraImpl::new_with_convolution(
661 poly_ring.into().into_base_ring(),
662 rank,
663 x_pow_rank,
664 "θ",
665 Global,
666 STANDARD_CONVOLUTION,
667 )
668 .into());
669 }
670}
671
672impl<R, V, A, C> SerializableElementRing for FreeAlgebraImplBase<R, V, A, C>
673where
674 R: RingStore,
675 V: VectorView<El<R>>,
676 A: Allocator + Clone,
677 C: ConvolutionAlgorithm<R::Type>,
678 R::Type: SerializableElementRing,
679{
680 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
681 where
682 D: Deserializer<'de>,
683 {
684 DeserializeSeedNewtypeStruct::new(
686 "ExtensionRingEl",
687 DeserializeSeedSeq::new(
688 std::iter::repeat_n(DeserializeWithRing::new(self.base_ring()), self.rank() + 1),
689 Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone()),
690 |mut current, next| {
691 current.push(next);
692 current
693 },
694 ),
695 )
696 .deserialize(deserializer)
697 .map(|mut values| {
698 values.resize_with(1 << self.log2_padded_len, || self.base_ring().zero());
699 FreeAlgebraImplEl {
700 values: values.into_boxed_slice(),
701 }
702 })
703 }
704
705 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
706 where
707 S: Serializer,
708 {
709 debug_assert_eq!(1 << self.log2_padded_len, el.values.len());
710 SerializableNewtypeStruct::new(
711 "ExtensionRingEl",
712 SerializableSeq::new_with_len(
713 (0..self.rank()).map(|i| SerializeWithRing::new(&el.values[i], self.base_ring())),
714 self.rank(),
715 ),
716 )
717 .serialize(serializer)
718 }
719}
720
721impl<R, V, A, C> FreeAlgebra for FreeAlgebraImplBase<R, V, A, C>
722where
723 R: RingStore,
724 V: VectorView<El<R>>,
725 A: Allocator + Clone,
726 C: ConvolutionAlgorithm<R::Type>,
727{
728 type VectorRepresentation<'a>
729 = CloneElFn<&'a [El<R>], El<R>, CloneRingEl<&'a R>>
730 where
731 Self: 'a;
732
733 fn canonical_gen(&self) -> Self::Element {
734 if self.rank() == 1 {
735 if self.x_pow_rank.len() == 1 {
736 self.from_canonical_basis([self.base_ring.clone_el(self.x_pow_rank.at(0))])
737 } else {
738 assert!(self.x_pow_rank.len() == 0);
739 self.zero()
740 }
741 } else {
742 self.from_canonical_basis((0..self.rank()).map(|i| {
743 if i == 1 {
744 self.base_ring.one()
745 } else {
746 self.base_ring.zero()
747 }
748 }))
749 }
750 }
751
752 fn wrt_canonical_basis<'a>(&'a self, el: &'a Self::Element) -> Self::VectorRepresentation<'a> {
753 el.values[..self.rank].clone_ring_els(self.base_ring())
754 }
755
756 fn from_canonical_basis<W>(&self, vec: W) -> Self::Element
757 where
758 W: IntoIterator<Item = El<Self::BaseRing>>,
759 W::IntoIter: DoubleEndedIterator,
760 {
761 let mut given_len = 0;
762 let mut vec_it = vec.into_iter().inspect(|_| given_len += 1);
763 let mut result = Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone());
764 result.extend(vec_it.by_ref());
765 result.extend((0..((1 << self.log2_padded_len) - self.rank())).map(|_| self.base_ring().zero()));
766 assert!(vec_it.next().is_none());
767 assert_eq!(given_len, self.rank());
768 FreeAlgebraImplEl {
769 values: result.into_boxed_slice(),
770 }
771 }
772
773 fn rank(&self) -> usize { self.rank }
774
775 fn mul_assign_gen_power(&self, el: &mut Self::Element, power: usize) {
776 let mut gen_pow_d = Vec::new_in(self.allocator().clone());
777 gen_pow_d.extend(self.x_pow_rank.as_iter().map(|c| self.base_ring.clone_el(c)));
778 gen_pow_d.resize_with(1 << self.log2_padded_len, || self.base_ring.zero());
779
780 if !power.is_multiple_of(self.rank()) {
781 let mut gen_pow_rem = Vec::new_in(self.allocator().clone());
782 gen_pow_rem.extend((0..((power % self.rank()) - 1)).map(|_| self.base_ring.zero()));
783 gen_pow_rem.push(self.base_ring.one());
784 gen_pow_rem.resize_with(1 << self.log2_padded_len, || self.base_ring.zero());
785 *el = self.prod([
786 FreeAlgebraImplEl {
787 values: replace(&mut el.values, Box::new_in([], self.allocator().clone())),
788 },
789 RingValue::from_ref(self).pow(
790 FreeAlgebraImplEl {
791 values: gen_pow_d.into_boxed_slice(),
792 },
793 power / self.rank,
794 ),
795 FreeAlgebraImplEl {
796 values: gen_pow_rem.into_boxed_slice(),
797 },
798 ]);
799 } else {
800 self.mul_assign(
801 el,
802 RingValue::from_ref(self).pow(
803 FreeAlgebraImplEl {
804 values: gen_pow_d.into_boxed_slice(),
805 },
806 power / self.rank,
807 ),
808 );
809 }
810 }
811}
812
813impl<R, V, A, C> HashableElRing for FreeAlgebraImplBase<R, V, A, C>
814where
815 R: RingStore,
816 R::Type: HashableElRing,
817 V: VectorView<El<R>>,
818 A: Allocator + Clone,
819 C: ConvolutionAlgorithm<R::Type>,
820{
821 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
822 for x in &el.values[..self.rank()] {
830 self.base_ring().get_ring().hash(x, h)
831 }
832 }
833}
834
835pub struct WRTCanonicalBasisElementCreator<'a, R, V, A, C>
840where
841 R: RingStore,
842 R::Type: FiniteRing,
843 V: VectorView<El<R>>,
844 A: Allocator + Clone,
845 C: ConvolutionAlgorithm<R::Type>,
846{
847 base_ring: &'a FreeAlgebraImplBase<R, V, A, C>,
848}
849
850impl<'a, R, V, A, C> Clone for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
851where
852 R: RingStore,
853 R::Type: FiniteRing,
854 V: VectorView<El<R>>,
855 A: Allocator + Clone,
856 C: ConvolutionAlgorithm<R::Type>,
857{
858 fn clone(&self) -> Self { *self }
859}
860
861impl<'a, 'b, R, V, A, C> FnOnce<(&'b [El<R>],)> for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
862where
863 R: RingStore,
864 R::Type: FiniteRing,
865 V: VectorView<El<R>>,
866 A: Allocator + Clone,
867 C: ConvolutionAlgorithm<R::Type>,
868{
869 type Output = El<FreeAlgebraImpl<R, V, A, C>>;
870
871 extern "rust-call" fn call_once(mut self, args: (&'b [El<R>],)) -> Self::Output { self.call_mut(args) }
872}
873
874impl<'a, 'b, R, V, A, C> FnMut<(&'b [El<R>],)> for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
875where
876 R: RingStore,
877 R::Type: FiniteRing,
878 V: VectorView<El<R>>,
879 A: Allocator + Clone,
880 C: ConvolutionAlgorithm<R::Type>,
881{
882 extern "rust-call" fn call_mut(&mut self, args: (&'b [El<R>],)) -> Self::Output {
883 self.base_ring
884 .from_canonical_basis(args.0.iter().map(|x| self.base_ring.base_ring().clone_el(x)))
885 }
886}
887
888impl<'a, R, V, A, C> Copy for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
889where
890 R: RingStore,
891 R::Type: FiniteRing,
892 V: VectorView<El<R>>,
893 A: Allocator + Clone,
894 C: ConvolutionAlgorithm<R::Type>,
895{
896}
897
898impl<R, V, A, C> FiniteRingSpecializable for FreeAlgebraImplBase<R, V, A, C>
899where
900 R: RingStore,
901 R::Type: FiniteRingSpecializable,
902 V: VectorView<El<R>>,
903 A: Allocator + Clone,
904 C: ConvolutionAlgorithm<R::Type>,
905{
906 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
907 struct OpWrapper<R, V, A, C, O>
908 where
909 R: RingStore,
910 R::Type: FiniteRingSpecializable,
911 V: VectorView<El<R>>,
912 A: Allocator + Clone,
913 C: ConvolutionAlgorithm<R::Type>,
914 O: FiniteRingOperation<FreeAlgebraImplBase<R, V, A, C>>,
915 {
916 operation: O,
917 ring: PhantomData<FreeAlgebraImpl<R, V, A, C>>,
918 }
919
920 impl<R, V, A, C, O> FiniteRingOperation<R::Type> for OpWrapper<R, V, A, C, O>
921 where
922 R: RingStore,
923 R::Type: FiniteRingSpecializable,
924 V: VectorView<El<R>>,
925 A: Allocator + Clone,
926 C: ConvolutionAlgorithm<R::Type>,
927 O: FiniteRingOperation<FreeAlgebraImplBase<R, V, A, C>>,
928 {
929 type Output = O::Output;
930 fn execute(self) -> Self::Output
931 where
932 R::Type: FiniteRing,
933 {
934 self.operation.execute()
935 }
936 fn fallback(self) -> Self::Output { self.operation.fallback() }
937 }
938
939 <R::Type as FiniteRingSpecializable>::specialize(OpWrapper {
940 operation: op,
941 ring: PhantomData,
942 })
943 }
944}
945
946impl<R, V, A, C> FiniteRing for FreeAlgebraImplBase<R, V, A, C>
947where
948 R: RingStore,
949 R::Type: FiniteRing,
950 V: VectorView<El<R>>,
951 A: Allocator + Clone,
952 C: ConvolutionAlgorithm<R::Type>,
953{
954 type ElementsIter<'a>
955 = MultiProduct<
956 <R::Type as FiniteRing>::ElementsIter<'a>,
957 WRTCanonicalBasisElementCreator<'a, R, V, A, C>,
958 CloneRingEl<&'a R>,
959 Self::Element,
960 >
961 where
962 Self: 'a;
963
964 fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
965 multi_cartesian_product(
966 (0..self.rank()).map(|_| self.base_ring().elements()),
967 WRTCanonicalBasisElementCreator { base_ring: self },
968 CloneRingEl(self.base_ring()),
969 )
970 }
971
972 fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
973 where
974 I::Type: IntegerRing,
975 {
976 let base_ring_size = self.base_ring().size(ZZ)?;
977 if ZZ.get_ring().representable_bits().is_none()
978 || ZZ.abs_log2_ceil(&base_ring_size).unwrap() * self.rank() < ZZ.get_ring().representable_bits().unwrap()
979 {
980 Some(ZZ.pow(base_ring_size, self.rank()))
981 } else {
982 None
983 }
984 }
985
986 fn random_element<G: FnMut() -> u64>(&self, mut rng: G) -> <Self as RingBase>::Element {
987 self.from_canonical_basis((0..self.rank()).map(|_| self.base_ring().random_element(&mut rng)))
988 }
989}
990
991impl_field_wrap_unwrap_homs! {
992 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
993 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
994 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
995 R2::Type: CanHomFrom<R1::Type>
996}
997
998impl_field_wrap_unwrap_isos! {
999 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
1000 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
1001 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
1002 R2::Type: CanIsoFromTo<R1::Type>
1003}
1004
1005impl_localpir_wrap_unwrap_homs! {
1006 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
1007 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
1008 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
1009 R2::Type: CanHomFrom<R1::Type>
1010}
1011
1012impl_localpir_wrap_unwrap_isos! {
1013 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
1014 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
1015 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
1016 R2::Type: CanIsoFromTo<R1::Type>
1017}
1018
1019impl<R1, V1, A1, C1, R2, V2, A2, C2> CanHomFrom<FreeAlgebraImplBase<R1, V1, A1, C1>>
1020 for FreeAlgebraImplBase<R2, V2, A2, C2>
1021where
1022 R1: RingStore,
1023 V1: VectorView<El<R1>>,
1024 A1: Allocator + Clone,
1025 C1: ConvolutionAlgorithm<R1::Type>,
1026 R2: RingStore,
1027 V2: VectorView<El<R2>>,
1028 A2: Allocator + Clone,
1029 C2: ConvolutionAlgorithm<R2::Type>,
1030 R2::Type: CanHomFrom<R1::Type>,
1031{
1032 type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
1033
1034 fn has_canonical_hom(&self, from: &FreeAlgebraImplBase<R1, V1, A1, C1>) -> Option<Self::Homomorphism> {
1035 if self.rank() == from.rank() {
1036 let hom = self.base_ring.get_ring().has_canonical_hom(from.base_ring.get_ring())?;
1037 if (0..self.rank()).all(|i| {
1038 (i >= self.x_pow_rank.len() && i >= from.x_pow_rank.len())
1039 || (i >= self.x_pow_rank.len() && from.base_ring().is_zero(from.x_pow_rank.at(i)))
1040 || (i >= from.x_pow_rank.len() && self.base_ring().is_zero(self.x_pow_rank.at(i)))
1041 || self.base_ring.eq_el(
1042 self.x_pow_rank.at(i),
1043 &self
1044 .base_ring
1045 .get_ring()
1046 .map_in_ref(from.base_ring.get_ring(), from.x_pow_rank.at(i), &hom),
1047 )
1048 }) {
1049 Some(hom)
1050 } else {
1051 None
1052 }
1053 } else {
1054 None
1055 }
1056 }
1057
1058 fn map_in(
1059 &self,
1060 from: &FreeAlgebraImplBase<R1, V1, A1, C1>,
1061 el: <FreeAlgebraImplBase<R1, V1, A1> as RingBase>::Element,
1062 hom: &Self::Homomorphism,
1063 ) -> Self::Element {
1064 self.from_canonical_basis((0..self.rank()).map(|i| {
1065 self.base_ring
1066 .get_ring()
1067 .map_in_ref(from.base_ring.get_ring(), &el.values[i], hom)
1068 }))
1069 }
1070}
1071
1072impl<R1, V1, A1, C1, R2, V2, A2, C2> CanIsoFromTo<FreeAlgebraImplBase<R1, V1, A1, C1>>
1073 for FreeAlgebraImplBase<R2, V2, A2, C2>
1074where
1075 R1: RingStore,
1076 V1: VectorView<El<R1>>,
1077 A1: Allocator + Clone,
1078 C1: ConvolutionAlgorithm<R1::Type>,
1079 R2: RingStore,
1080 V2: VectorView<El<R2>>,
1081 A2: Allocator + Clone,
1082 C2: ConvolutionAlgorithm<R2::Type>,
1083 R2::Type: CanIsoFromTo<R1::Type>,
1084{
1085 type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
1086
1087 fn has_canonical_iso(&self, from: &FreeAlgebraImplBase<R1, V1, A1, C1>) -> Option<Self::Isomorphism> {
1088 if self.rank() == from.rank() {
1089 let iso = self.base_ring.get_ring().has_canonical_iso(from.base_ring.get_ring())?;
1090 if (0..self.rank()).all(|i| {
1091 (i >= self.x_pow_rank.len() && i >= from.x_pow_rank.len())
1092 || (i >= self.x_pow_rank.len() && from.base_ring().is_zero(from.x_pow_rank.at(i)))
1093 || (i >= from.x_pow_rank.len() && self.base_ring().is_zero(self.x_pow_rank.at(i)))
1094 || from.base_ring.eq_el(
1095 &self.base_ring.get_ring().map_out(
1096 from.base_ring.get_ring(),
1097 self.base_ring.clone_el(self.x_pow_rank.at(i)),
1098 &iso,
1099 ),
1100 from.x_pow_rank.at(i),
1101 )
1102 }) {
1103 Some(iso)
1104 } else {
1105 None
1106 }
1107 } else {
1108 None
1109 }
1110 }
1111
1112 fn map_out(
1113 &self,
1114 from: &FreeAlgebraImplBase<R1, V1, A1, C1>,
1115 el: <FreeAlgebraImplBase<R2, V2, A2> as RingBase>::Element,
1116 iso: &Self::Isomorphism,
1117 ) -> <FreeAlgebraImplBase<R1, V1, A1, C1> as RingBase>::Element {
1118 from.from_canonical_basis((0..self.rank()).map(|i| {
1119 self.base_ring
1120 .get_ring()
1121 .map_out(from.base_ring.get_ring(), self.base_ring.clone_el(&el.values[i]), iso)
1122 }))
1123 }
1124}
1125
1126#[cfg(test)]
1127use crate::algorithms::convolution::fft::FFTConvolution;
1128#[cfg(test)]
1129use crate::rings::zn::ZnRingStore;
1130#[cfg(test)]
1131use crate::rings::zn::zn_64::{Zn, ZnEl};
1132#[cfg(test)]
1133use crate::rings::zn::zn_static;
1134
1135#[cfg(test)]
1136fn test_ring0_and_elements() -> (FreeAlgebraImpl<Zn, Vec<ZnEl>>, Vec<FreeAlgebraImplEl<Zn>>) {
1137 let R = FreeAlgebraImpl::new(Zn::new(7), 1, vec![Zn::new(7).neg_one()]);
1138 let elements = R.elements().collect();
1139 return (R, elements);
1140}
1141
1142#[cfg(test)]
1143fn test_ring1_and_elements() -> (
1144 FreeAlgebraImpl<StaticRing<i64>, [i64; 2]>,
1145 Vec<FreeAlgebraImplEl<StaticRing<i64>>>,
1146) {
1147 let ZZ = StaticRing::<i64>::RING;
1148 let R = FreeAlgebraImpl::new(ZZ, 2, [1, 1]);
1149 let mut elements = Vec::new();
1150 for a in -3..=3 {
1151 for b in -3..=3 {
1152 elements.push(R.from_canonical_basis([a, b]));
1153 }
1154 }
1155 return (R, elements);
1156}
1157
1158#[cfg(test)]
1159fn test_ring2_and_elements() -> (
1160 FreeAlgebraImpl<StaticRing<i64>, Vec<i64>>,
1161 Vec<FreeAlgebraImplEl<StaticRing<i64>>>,
1162) {
1163 let ZZ = StaticRing::<i64>::RING;
1164 let R = FreeAlgebraImpl::new(ZZ, 3, vec![1, -1, 1]);
1165 let mut elements = Vec::new();
1166 for a in [-2, 0, 1, 2] {
1167 for b in [-2, 0, 2] {
1168 for c in [-2, 0, 2] {
1169 elements.push(R.from_canonical_basis([a, b, c]));
1170 }
1171 }
1172 }
1173 return (R, elements);
1174}
1175
1176#[cfg(test)]
1177fn test_ring3_and_elements() -> (
1178 FreeAlgebraImpl<StaticRing<i64>, Vec<i64>>,
1179 Vec<FreeAlgebraImplEl<StaticRing<i64>>>,
1180) {
1181 let ZZ = StaticRing::<i64>::RING;
1182 let R = FreeAlgebraImpl::new(ZZ, 3, vec![1]);
1183 let mut elements = Vec::new();
1184 for a in [-2, 0, 1, 2] {
1185 for b in [-2, 0, 2] {
1186 for c in [-2, 0, 2] {
1187 elements.push(R.from_canonical_basis([a, b, c]));
1188 }
1189 }
1190 }
1191 return (R, elements);
1192}
1193
1194#[cfg(test)]
1195fn test_ring4_and_elements() -> (
1196 FreeAlgebraImpl<StaticRing<i64>, SparseMapVector<StaticRing<i64>>>,
1197 Vec<FreeAlgebraImplEl<StaticRing<i64>>>,
1198) {
1199 let ZZ = StaticRing::<i64>::RING;
1200 let mut modulus = SparseMapVector::new(3, StaticRing::<i64>::RING);
1202 *modulus.at_mut(1) = 1;
1203 let R = FreeAlgebraImpl::new(ZZ, 3, modulus);
1204 let mut elements = Vec::new();
1205 for a in [-2, 0, 1, 2] {
1206 for b in [-2, 0, 2] {
1207 for c in [-2, 0, 2] {
1208 elements.push(R.from_canonical_basis([a, b, c]));
1209 }
1210 }
1211 }
1212 return (R, elements);
1213}
1214
1215#[test]
1216fn test_sparse() {
1217 let (ring, _) = test_ring4_and_elements();
1218 assert_el_eq!(ring, ring.canonical_gen(), ring.pow(ring.canonical_gen(), 3));
1219}
1220
1221#[test]
1222fn test_ring_axioms() {
1223 let (ring, els) = test_ring2_and_elements();
1228 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
1229 let (ring, els) = test_ring3_and_elements();
1230 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
1231 let (ring, els) = test_ring4_and_elements();
1232 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
1233
1234 let (ring, els) = test_ring2_and_elements();
1235 let ring = ring.into().set_convolution(FFTConvolution::new_with_alloc(Global));
1236 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
1237
1238 let base_ring = zn_static::Fp::<257>::RING;
1239 let x_pow_rank = vec![base_ring.neg_one(); 64];
1240 let ring = FreeAlgebraImpl::new(base_ring, 64, x_pow_rank);
1241 let mut rng = oorandom::Rand64::new(1);
1242 let els =
1243 (0..10).map(|_| ring.from_canonical_basis((0..64).map(|_| ring.base_ring().random_element(|| rng.rand_u64()))));
1244 crate::ring::generic_tests::test_ring_axioms(&ring, els);
1245}
1246
1247#[test]
1248fn test_rank_1_ring() {
1249 let base_ring = Zn::new(5).as_field().ok().unwrap();
1250 let ring = FreeAlgebraImpl::new(base_ring, 1, [base_ring.int_hom().map(1)])
1251 .as_field()
1252 .ok()
1253 .unwrap();
1254 crate::field::generic_tests::test_field_axioms(&ring, ring.elements());
1255
1256 assert_el_eq!(ring, ring.one(), ring.canonical_gen());
1257}
1258
1259#[test]
1260fn test_free_algebra_axioms() {
1261 let (ring, _) = test_ring0_and_elements();
1262 super::generic_tests::test_free_algebra_axioms(ring);
1263 let (ring, _) = test_ring1_and_elements();
1264 super::generic_tests::test_free_algebra_axioms(ring);
1265 let (ring, _) = test_ring2_and_elements();
1266 super::generic_tests::test_free_algebra_axioms(ring);
1267 let (ring, _) = test_ring3_and_elements();
1268 super::generic_tests::test_free_algebra_axioms(ring);
1269 let (ring, _) = test_ring4_and_elements();
1270 super::generic_tests::test_free_algebra_axioms(ring);
1271}
1272
1273#[test]
1274fn test_division() {
1275 let base_ring = Zn::new(4);
1276 let i = base_ring.int_hom();
1277 let ring = FreeAlgebraImpl::new(base_ring, 2, [i.map(-1), i.map(-1)]);
1278
1279 assert_el_eq!(
1280 ring,
1281 &ring.from_canonical_basis([i.map(1), i.map(3)]),
1282 &ring
1283 .checked_div(&ring.one(), &ring.from_canonical_basis([i.map(2), i.map(3)]))
1284 .unwrap()
1285 );
1286
1287 let a = ring.from_canonical_basis([i.map(2), i.map(2)]);
1288 let b = ring.from_canonical_basis([i.map(0), i.map(2)]);
1289 assert_el_eq!(ring, a, ring.mul(ring.checked_div(&a, &b).unwrap(), b));
1290
1291 assert!(ring.checked_div(&ring.one(), &a).is_none());
1292}
1293
1294#[test]
1295fn test_division_ring_of_integers() {
1296 let base_ring = StaticRing::<i64>::RING;
1297 let ring = FreeAlgebraImpl::new(base_ring, 2, [11, 0]);
1298
1299 let u = ring.from_canonical_basis([10, 3]);
1301 let u_inv = ring.from_canonical_basis([10, -3]);
1302
1303 assert_el_eq!(ring, u_inv, ring.checked_div(&ring.one(), &u).unwrap());
1304 assert_el_eq!(
1305 ring,
1306 ring.pow(u_inv, 3),
1307 &ring.checked_div(&ring.one(), &ring.pow(u, 3)).unwrap()
1308 );
1309
1310 assert!(
1311 ring.checked_div(&ring.from_canonical_basis([2, 0]), &ring.from_canonical_basis([3, 0]))
1312 .is_none()
1313 );
1314}
1315
1316#[test]
1317fn test_divisibility_axioms() {
1318 let (ring, els) = test_ring0_and_elements();
1319 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1320 let (ring, els) = test_ring1_and_elements();
1321 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1322 let (ring, els) = test_ring2_and_elements();
1323 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1324 let (ring, els) = test_ring3_and_elements();
1325 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1326 let (ring, els) = test_ring4_and_elements();
1327 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1328}
1329
1330#[test]
1331fn test_cubic_mul() {
1332 let base_ring = zn_static::Zn::<256>::RING;
1333 let modulo = base_ring.int_hom();
1334 let ring = FreeAlgebraImpl::new(base_ring, 3, [modulo.map(-1), modulo.map(-1), modulo.map(-1)]);
1335 let a = ring.from_canonical_basis([modulo.map(0), modulo.map(-1), modulo.map(-1)]);
1336 let b = ring.from_canonical_basis([modulo.map(-1), modulo.map(-2), modulo.map(-1)]);
1337 assert_el_eq!(ring, b, ring.pow(a, 2));
1338}
1339
1340#[test]
1341fn test_as_field() {
1342 let base_ring = Zn::new(5).as_field().ok().unwrap();
1343 let ring = FreeAlgebraImpl::new(base_ring, 1, [base_ring.int_hom().map(1)])
1344 .as_field()
1345 .ok()
1346 .unwrap();
1347 crate::field::generic_tests::test_field_axioms(&ring, ring.elements());
1348
1349 let base_ring = Zn::new(3).as_field().ok().unwrap();
1350 let ring = FreeAlgebraImpl::new(base_ring, 2, [base_ring.int_hom().map(2)])
1351 .as_field()
1352 .ok()
1353 .unwrap();
1354 crate::field::generic_tests::test_field_axioms(&ring, ring.elements());
1355
1356 assert!(
1357 FreeAlgebraImpl::new(base_ring, 2, [base_ring.int_hom().map(1)])
1358 .as_field()
1359 .is_err()
1360 );
1361}
1362
1363#[test]
1364fn test_serialization() {
1365 let (ring, els) = test_ring0_and_elements();
1366 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1367 let (ring, els) = test_ring1_and_elements();
1368 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1369 let (ring, els) = test_ring2_and_elements();
1370 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1371 let (ring, els) = test_ring3_and_elements();
1372 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1373 let (ring, els) = test_ring4_and_elements();
1374 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1375}
1376
1377#[test]
1378#[should_panic]
1379fn test_from_canonical_basis_enforce_len() {
1380 let (ring, _) = test_ring1_and_elements();
1381 _ = ring.from_canonical_basis([0, 1, 2]);
1382}
1383
1384#[test]
1385fn test_serialize_deserialize() {
1386 crate::serialization::generic_tests::test_serialize_deserialize(test_ring0_and_elements().0.into());
1387 crate::serialization::generic_tests::test_serialize_deserialize(test_ring2_and_elements().0.into());
1388 crate::serialization::generic_tests::test_serialize_deserialize(test_ring3_and_elements().0.into());
1389}