1use std::alloc::{Allocator, Global};
2use std::fmt::{Debug, Formatter};
3use std::marker::PhantomData;
4use std::cell::OnceCell;
5
6use feanor_serde::dependent_tuple::DeserializeSeedDependentTuple;
7use feanor_serde::newtype_struct::DeserializeSeedNewtypeStruct;
8use feanor_serde::seq::*;
9use feanor_serde::newtype_struct::*;
10use serde::de::DeserializeSeed;
11use serde::{Deserializer, Serialize, Serializer, Deserialize};
12
13use crate::algorithms::convolution::*;
14use crate::algorithms::extension_ops::create_multiplication_matrix;
15use crate::algorithms::linsolve::LinSolveRing;
16use crate::divisibility::*;
17use crate::{impl_localpir_wrap_unwrap_homs, impl_localpir_wrap_unwrap_isos, impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos};
18use crate::integer::*;
19use crate::iters::multi_cartesian_product;
20use crate::iters::MultiProduct;
21use crate::rings::poly::PolyRingStore;
22use crate::matrix::OwnedMatrix;
23use crate::primitive_int::StaticRing;
24use crate::rings::finite::*;
25use crate::specialization::*;
26use crate::rings::poly::dense_poly::DensePolyRing;
27use crate::seq::*;
28use crate::ring::*;
29use crate::integer::IntegerRingStore;
30use crate::delegate::DelegateRing;
31use crate::homomorphism::*;
32use crate::serialization::*;
33use crate::seq::sparse::SparseMapVector;
34
35use super::FreeAlgebra;
36use super::FreeAlgebraStore;
37
38pub struct FreeAlgebraImplBase<R, V, A = Global, C = KaratsubaAlgorithm>
57 where R: RingStore,
58 V: VectorView<El<R>>,
59 A: Allocator + Clone,
60 C: ConvolutionAlgorithm<R::Type>
61{
62 base_ring: R,
63 x_pow_rank: V,
64 element_allocator: A,
65 log2_padded_len: usize,
66 rank: usize,
67 gen_name: &'static str,
68 convolution: C
69}
70
71pub type FreeAlgebraImpl<R, V, A = Global, C = KaratsubaAlgorithm> = RingValue<FreeAlgebraImplBase<R, V, A, C>>;
77
78impl<R, V> FreeAlgebraImpl<R, V>
79 where R: RingStore, V: VectorView<El<R>>
80{
81 pub fn new(base_ring: R, rank: usize, x_pow_rank: V) -> Self {
87 Self::new_with_convolution(base_ring, rank, x_pow_rank, "θ", Global, STANDARD_CONVOLUTION)
88 }
89}
90
91impl<R, V, A, C> Clone for FreeAlgebraImplBase<R, V, A, C>
92 where R: RingStore + Clone,
93 V: VectorView<El<R>> + Clone,
94 A: Allocator + Clone,
95 C: ConvolutionAlgorithm<R::Type> + Clone
96{
97 fn clone(&self) -> Self {
98 Self {
99 base_ring: self.base_ring.clone(),
100 x_pow_rank: self.x_pow_rank.clone(),
101 element_allocator: self.element_allocator.clone(),
102 log2_padded_len: self.log2_padded_len,
103 rank: self.rank,
104 convolution: self.convolution.clone(),
105 gen_name: self.gen_name
106 }
107 }
108}
109
110impl<R, V, A, C> Copy for FreeAlgebraImplBase<R, V, A, C>
111 where R: RingStore + Copy,
112 V: VectorView<El<R>> + Copy,
113 A: Allocator + Copy,
114 C: ConvolutionAlgorithm<R::Type> + Copy,
115 El<R>: Copy
116{}
117
118pub struct FreeAlgebraImplEl<R, A = Global>
122 where R: RingStore, A: Allocator
123{
124 values: Box<[El<R>], A>
125}
126
127impl<R, A> Debug for FreeAlgebraImplEl<R, A>
128 where R: RingStore, A: Allocator,
129 El<R>: Debug
130{
131 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
132 write!(f, "{:?}", &self.values)
133 }
134}
135
136impl<R, V, A, C> FreeAlgebraImpl<R, V, A, C>
137 where 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(base_ring: R, rank: usize, x_pow_rank: V, gen_name: &'static str, element_allocator: A, convolution: C) -> Self {
144 assert!(rank >= 1);
145 assert!(x_pow_rank.len() <= rank);
146 let log2_padded_len = StaticRing::<i64>::RING.abs_log2_ceil(&rank.try_into().unwrap()).unwrap();
147 RingValue::from(FreeAlgebraImplBase {
148 base_ring, gen_name, x_pow_rank, element_allocator, rank, log2_padded_len, convolution
149 })
150 }
151}
152
153impl<R, V, A, C> FreeAlgebraImplBase<R, V, A, C>
154 where R: RingStore,
155 V: VectorView<El<R>>,
156 A: Allocator + Clone,
157 C: ConvolutionAlgorithm<R::Type>
158{
159 #[stability::unstable(feature = "enable")]
160 pub fn set_convolution<C_new: ConvolutionAlgorithm<R::Type>>(self, new_convolution: C_new) -> FreeAlgebraImpl<R, V, A, C_new> {
161 RingValue::from(FreeAlgebraImplBase {
162 base_ring: self.base_ring,
163 x_pow_rank: self.x_pow_rank,
164 element_allocator: self.element_allocator,
165 log2_padded_len: self.log2_padded_len,
166 rank: self.rank,
167 convolution: new_convolution,
168 gen_name: self.gen_name
169 })
170 }
171
172 #[stability::unstable(feature = "enable")]
173 pub fn allocator(&self) -> &A {
174 &self.element_allocator
175 }
176
177 #[stability::unstable(feature = "enable")]
178 pub fn gen_name(&self) -> &'static str {
179 self.gen_name
180 }
181
182 #[stability::unstable(feature = "enable")]
183 pub fn x_pow_rank(&self) -> &V {
184 &self.x_pow_rank
185 }
186
187 #[stability::unstable(feature = "enable")]
188 pub fn convolution(&self) -> &C {
189 &self.convolution
190 }
191
192 fn reduce_mod_poly(&self, data: &mut [El<R>]) {
193 struct ReduceModulo<'a, R>
194 where R: RingStore
195 {
196 rank: usize,
197 base_ring: &'a R,
198 data: &'a mut [El<R>]
199 }
200
201 impl<'a, R> SparseVectorViewOperation<El<R>> for ReduceModulo<'a, R>
202 where R: RingStore
203 {
204 type Output<'b> = ()
205 where Self: 'b;
206
207 fn execute<'b, V: 'b + VectorViewSparse<El<R>>>(self, vector: V) -> () {
208 for i in (self.rank..(2 * self.rank)).rev() {
209 for (j, c) in vector.nontrivial_entries() {
210 let add = self.base_ring.mul_ref(c, &mut self.data[i]);
211 self.base_ring.add_assign(&mut self.data[i - self.rank + j], add);
212 }
213 }
214 }
215 }
216
217 let was_sparse = self.x_pow_rank.specialize_sparse(ReduceModulo {
218 rank: self.rank,
219 base_ring: self.base_ring(),
220 data: data
221 });
222 if was_sparse.is_err() {
223 for i in (self.rank()..(2 * self.rank())).rev() {
224 for j in 0..self.x_pow_rank.len() {
225 let add = self.base_ring.mul_ref(self.x_pow_rank.at(j), &data[i]);
226 self.base_ring.add_assign(&mut data[i - self.rank() + j], add);
227 }
228 }
229 }
230 }
231}
232
233impl<R, V, A, C> PartialEq for FreeAlgebraImplBase<R, V, A, C>
234 where R: RingStore,
235 V: VectorView<El<R>>,
236 A: Allocator + Clone,
237 C: ConvolutionAlgorithm<R::Type>
238{
239 fn eq(&self, other: &Self) -> bool {
240 self.base_ring().get_ring() == other.base_ring().get_ring() && self.rank() == other.rank() &&
241 (0..self.rank()).all(|i| (i >= self.x_pow_rank.len() && i >= other.x_pow_rank.len()) ||
242 (i >= self.x_pow_rank.len() && self.base_ring().is_zero(other.x_pow_rank.at(i))) ||
243 (i >= other.x_pow_rank.len() && self.base_ring().is_zero(self.x_pow_rank.at(i))) ||
244 self.base_ring().eq_el(self.x_pow_rank.at(i), other.x_pow_rank.at(i)))
245 }
246}
247
248impl<R, V, A, C> RingBase for FreeAlgebraImplBase<R, V, A, C>
249 where R: RingStore,
250 V: VectorView<El<R>>,
251 A: Allocator + Clone,
252 C: ConvolutionAlgorithm<R::Type>
253{
254 type Element = FreeAlgebraImplEl<R, A>;
255
256 fn clone_el(&self, val: &Self::Element) -> Self::Element {
257 debug_assert_eq!(1 << self.log2_padded_len, val.values.len());
258 let mut result_values = Vec::with_capacity_in(val.values.len(), self.element_allocator.clone());
259 result_values.extend(val.values.iter().map(|x| self.base_ring().clone_el(x)));
260 return FreeAlgebraImplEl {
261 values: result_values.into_boxed_slice()
262 };
263 }
264
265 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
266 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
267 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
268 for i in 0..self.rank() {
269 self.base_ring().add_assign_ref(&mut lhs.values[i], &rhs.values[i]);
270 }
271 }
272
273 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
274 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
275 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
276 for (i, x) in (0..self.rank()).zip(rhs.values.iter()) {
277 self.base_ring().add_assign_ref(&mut lhs.values[i], x);
278 }
279 }
280
281 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
282 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
283 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
284 for i in 0..self.rank() {
285 self.base_ring().sub_assign_ref(&mut lhs.values[i], &rhs.values[i]);
286 }
287 }
288
289 fn negate_inplace(&self, lhs: &mut Self::Element) {
290 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
291 for i in 0..self.rank() {
292 self.base_ring().negate_inplace(&mut lhs.values[i]);
293 }
294 }
295
296 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
297 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
298 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
299 self.mul_assign_ref(lhs, &rhs)
300 }
301
302 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
303 *lhs = self.fma(lhs, rhs, self.zero());
304 }
305
306 fn fma(&self, lhs: &Self::Element, rhs: &Self::Element, summand: Self::Element) -> Self::Element {
307 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
308 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
309 debug_assert_eq!(1 << self.log2_padded_len, summand.values.len());
310 let mut tmp = summand.values.into_vec();
311 tmp.resize_with(2 << self.log2_padded_len, || self.base_ring.zero());
312 self.convolution.compute_convolution(&lhs.values[..], &rhs.values[..], &mut tmp[..], self.base_ring());
313 self.reduce_mod_poly(&mut tmp);
314 tmp.truncate(1 << self.log2_padded_len);
315 for i in self.rank()..(1 << self.log2_padded_len) {
316 tmp[i] = self.base_ring().zero();
317 }
318 return FreeAlgebraImplEl {
319 values: tmp.into_boxed_slice()
320 };
321 }
322
323 fn from_int(&self, value: i32) -> Self::Element {
324 self.from(self.base_ring().int_hom().map(value))
325 }
326
327 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
328 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
329 debug_assert_eq!(1 << self.log2_padded_len, rhs.values.len());
330 (0..self.rank()).all(|i| self.base_ring().eq_el(&lhs.values[i], &rhs.values[i]))
331 }
332
333 fn is_zero(&self, value: &Self::Element) -> bool {
334 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
335 (0..self.rank()).all(|i| self.base_ring.is_zero(&value.values[i]))
336 }
337
338 fn is_one(&self, value: &Self::Element) -> bool {
339 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
340 self.base_ring().is_one(&value.values[0]) && (1..self.rank()).all(|i| self.base_ring.is_zero(&value.values[i]))
341 }
342
343 fn is_neg_one(&self, value: &Self::Element) -> bool {
344 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
345 self.base_ring().is_neg_one(&value.values[0]) && (1..self.rank()).all(|i| self.base_ring.is_zero(&value.values[i]))
346 }
347
348 fn is_commutative(&self) -> bool {
349 self.base_ring().is_commutative()
350 }
351
352 fn is_noetherian(&self) -> bool {
353 self.base_ring().is_noetherian()
354 }
355
356 fn is_approximate(&self) -> bool {
357 self.base_ring().get_ring().is_approximate()
358 }
359
360 fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
361 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
362 self.dbg_within(value, out, EnvBindingStrength::Weakest)
363 }
364
365 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, env: EnvBindingStrength) -> std::fmt::Result {
366 debug_assert_eq!(1 << self.log2_padded_len, value.values.len());
367 let poly_ring = DensePolyRing::new(self.base_ring(), self.gen_name);
368 poly_ring.get_ring().dbg_within(&RingRef::new(self).poly_repr(&poly_ring, value, &self.base_ring().identity()), out, env)
369 }
370
371 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
372 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
373 for i in 0..self.rank() {
374 self.base_ring().int_hom().mul_assign_map(&mut lhs.values[i], rhs);
375 }
376 }
377
378 fn fma_int(&self, lhs: &Self::Element, rhs: i32, summand: Self::Element) -> Self::Element {
379 debug_assert_eq!(1 << self.log2_padded_len, lhs.values.len());
380 debug_assert_eq!(1 << self.log2_padded_len, summand.values.len());
381 let mut result = Vec::new_in(self.allocator().clone());
382 result.extend(summand.values.into_iter().enumerate().map(|(i, x)| self.base_ring().int_hom().fma_map(&lhs.values[i], &rhs, x)));
383 return FreeAlgebraImplEl {
384 values: result.into_boxed_slice()
385 };
386 }
387
388 fn characteristic<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
389 where I::Type: IntegerRing
390 {
391 self.base_ring().characteristic(ZZ)
392 }
393
394 fn square(&self, value: &mut Self::Element) {
395 let mut tmp = Vec::with_capacity_in(2 << self.log2_padded_len, self.element_allocator.clone());
396 tmp.resize_with(2 << self.log2_padded_len, || self.base_ring().zero());
397 let x_prepared = self.convolution.prepare_convolution_operand(&value.values[..], Some(2 * self.rank()), self.base_ring());
398 self.convolution.compute_convolution_prepared(&value.values[..], Some(&x_prepared), &value.values[..], Some(&x_prepared), &mut tmp, self.base_ring());
399 self.reduce_mod_poly(&mut tmp);
400 for i in 0..self.rank() {
401 value.values[i] = std::mem::replace(&mut tmp[i], self.base_ring().zero());
402 }
403 }
404}
405
406impl<R, V, A, C> RingExtension for FreeAlgebraImplBase<R, V, A, C>
407 where R: RingStore,
408 V: VectorView<El<R>>,
409 A: Allocator + Clone,
410 C: ConvolutionAlgorithm<R::Type>
411{
412 type BaseRing = R;
413
414 fn base_ring<'a>(&'a self) -> &'a Self::BaseRing {
415 &self.base_ring
416 }
417
418 fn from(&self, x: El<Self::BaseRing>) -> Self::Element {
419 let mut result_values = Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone());
420 result_values.push(x);
421 result_values.extend((0..((1 << self.log2_padded_len) - 1)).map(|_| self.base_ring().zero()));
422 return FreeAlgebraImplEl {
423 values: result_values.into_boxed_slice()
424 };
425 }
426
427 fn mul_assign_base(&self, lhs: &mut Self::Element, rhs: &El<Self::BaseRing>) {
428 for i in 0..self.rank() {
429 self.base_ring().mul_assign_ref(&mut lhs.values[i], rhs);
430 }
431 }
432
433 fn fma_base(&self, lhs: &Self::Element, rhs: &El<Self::BaseRing>, summand: Self::Element) -> Self::Element {
434 let mut new = Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone());
435 new.extend(summand.values.into_iter().take(self.rank()).enumerate().map(|(i, x)| self.base_ring.fma(&lhs.values[i], rhs, x)));
436 new.resize_with(1 << self.log2_padded_len, || self.base_ring().zero());
437 return FreeAlgebraImplEl {
438 values: new.into_boxed_slice()
439 };
440 }
441}
442
443impl<R, V, A, C> DivisibilityRing for FreeAlgebraImplBase<R, V, A, C>
456 where R: RingStore,
457 R::Type: LinSolveRing,
458 V: VectorView<El<R>>,
459 A: Allocator + Clone,
460 C: ConvolutionAlgorithm<R::Type>
461{
462 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
463 let mut mul_matrix: OwnedMatrix<_, _> = create_multiplication_matrix(RingRef::new(self), rhs, self.allocator().clone());
464 let mut lhs_matrix: OwnedMatrix<_, _> = OwnedMatrix::zero_in(self.rank(), 1, self.base_ring(), self.allocator().clone());
465 let data = self.wrt_canonical_basis(&lhs);
466 for j in 0..self.rank() {
467 *lhs_matrix.at_mut(j, 0) = data.at(j);
468 }
469 let mut solution: OwnedMatrix<_, _> = OwnedMatrix::zero_in(self.rank(), 1, self.base_ring(), self.allocator().clone());
470 let has_sol = self.base_ring().get_ring().solve_right(mul_matrix.data_mut(), lhs_matrix.data_mut(), solution.data_mut(), Global);
471 if has_sol.is_solved() {
472 return Some(self.from_canonical_basis((0..self.rank()).map(|i| self.base_ring().clone_el(solution.at(i, 0)))));
473 } else {
474 return None;
475 }
476 }
477
478 fn balance_factor<'a, I>(&self, elements: I) -> Option<Self::Element>
479 where I: Iterator<Item = &'a Self::Element>,
480 Self: 'a
481 {
482 self.base_ring().get_ring().balance_factor(elements.flat_map(|x| x.values.iter())).map(|c| RingRef::new(self).inclusion().map(c))
483 }
484
485 default fn invert(&self, el: &Self::Element) -> Option<Self::Element> {
486 self.checked_left_div(&self.one(), el)
487 }
488}
489
490impl<R, V, A, C> Debug for FreeAlgebraImplBase<R, V, A, C>
491 where R: RingStore + Debug,
492 V: VectorView<El<R>>,
493 A: Allocator + Clone,
494 C: ConvolutionAlgorithm<R::Type>
495{
496 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
497 let poly_ring = DensePolyRing::new(self.base_ring(), self.gen_name);
498 f.debug_struct("FreeAlgebraImplBase")
499 .field("base_ring", &self.base_ring)
500 .field("modulus", &poly_ring.format(&RingRef::new(self).generating_poly(&poly_ring, self.base_ring.identity())))
501 .finish()
502 }
503}
504
505impl<R, V> Serialize for FreeAlgebraImplBase<R, V, Global, KaratsubaAlgorithm>
506 where R: RingStore + Serialize,
507 R::Type: SerializableElementRing,
508 V: VectorView<El<R>>,
509{
510 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
511 where S: Serializer
512 {
513 let poly_ring = DensePolyRing::new(self.base_ring(), "X");
514 SerializableNewtypeStruct::new("FreeAlgebraImpl", (self.base_ring(), SerializeOwnedWithRing::new(RingRef::new(self).generating_poly(&poly_ring, self.base_ring().identity()), poly_ring))).serialize(serializer)
515 }
516}
517
518impl<'de, R> Deserialize<'de> for FreeAlgebraImplBase<R, SparseMapVector<R>, Global, KaratsubaAlgorithm>
519 where R: RingStore + Deserialize<'de> + Clone,
520 R::Type: SerializableElementRing,
521{
522 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
523 where D: Deserializer<'de>
524 {
525 let ring_cell = OnceCell::new();
526 let poly = <_ as DeserializeSeed<'de>>::deserialize(DeserializeSeedNewtypeStruct::new("FreeAlgebraImpl", DeserializeSeedDependentTuple::new(PhantomData::<R>, |ring| {
527 let poly_ring = DensePolyRing::new(ring, "X");
528 ring_cell.set(poly_ring).ok().unwrap();
529 DeserializeWithRing::new(ring_cell.get().unwrap())
530 })), deserializer)?;
531 let poly_ring = ring_cell.into_inner().unwrap();
532 assert!(poly_ring.base_ring().is_one(poly_ring.lc(&poly).unwrap()));
533 let rank = poly_ring.degree(&poly).unwrap();
534 let mut x_pow_rank = SparseMapVector::new(rank, (*poly_ring.base_ring()).clone());
535 for (c, i) in poly_ring.terms(&poly) {
536 *x_pow_rank.at_mut(i) = poly_ring.base_ring().negate(poly_ring.base_ring().clone_el(c));
537 }
538 _ = x_pow_rank.at_mut(0);
539 return Ok(FreeAlgebraImpl::new_with_convolution(poly_ring.into().into_base_ring(), rank, x_pow_rank, "θ", Global, STANDARD_CONVOLUTION).into());
540 }
541}
542
543impl<'de, R> Deserialize<'de> for FreeAlgebraImplBase<R, Vec<El<R>>, Global, KaratsubaAlgorithm>
544 where R: RingStore + Deserialize<'de>,
545 R::Type: SerializableElementRing
546{
547 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
548 where D: Deserializer<'de>
549 {
550 let ring_cell = OnceCell::new();
551 let poly = <_ as DeserializeSeed<'de>>::deserialize(DeserializeSeedNewtypeStruct::new("FreeAlgebraImpl", DeserializeSeedDependentTuple::new(PhantomData::<R>, |ring| {
552 let poly_ring = DensePolyRing::new(ring, "X");
553 ring_cell.set(poly_ring).ok().unwrap();
554 DeserializeWithRing::new(ring_cell.get().unwrap())
555 })), deserializer)?;
556 let poly_ring = ring_cell.into_inner().unwrap();
557 assert!(poly_ring.base_ring().is_one(poly_ring.lc(&poly).unwrap()));
558 let rank = poly_ring.degree(&poly).unwrap();
559 let x_pow_rank = (0..rank).map(|i| poly_ring.base_ring().negate(poly_ring.base_ring().clone_el(poly_ring.coefficient_at(&poly, i)))).collect::<Vec<_>>();
560 return Ok(FreeAlgebraImpl::new_with_convolution(poly_ring.into().into_base_ring(), rank, x_pow_rank, "θ", Global, STANDARD_CONVOLUTION).into());
561 }
562}
563
564impl<R, V, A, C> SerializableElementRing for FreeAlgebraImplBase<R, V, A, C>
565 where R: RingStore,
566 V: VectorView<El<R>>,
567 A: Allocator + Clone,
568 C: ConvolutionAlgorithm<R::Type>,
569 R::Type: SerializableElementRing
570{
571 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
572 where D: Deserializer<'de>
573 {
574 DeserializeSeedNewtypeStruct::new("ExtensionRingEl", DeserializeSeedSeq::new(
576 std::iter::repeat(DeserializeWithRing::new(self.base_ring())).take(self.rank() + 1),
577 Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone()),
578 |mut current, next| { current.push(next); current }
579 )).deserialize(deserializer).map(|mut values| {
580 values.resize_with(1 << self.log2_padded_len, || self.base_ring().zero());
581 FreeAlgebraImplEl { values: values.into_boxed_slice() }
582 })
583 }
584
585 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
586 where S: Serializer
587 {
588 debug_assert_eq!(1 << self.log2_padded_len, el.values.len());
589 SerializableNewtypeStruct::new("ExtensionRingEl", SerializableSeq::new_with_len(
590 (0..self.rank()).map(|i| SerializeWithRing::new(&el.values[i], self.base_ring())), self.rank()
591 )).serialize(serializer)
592 }
593}
594
595impl<R, V, A, C> FreeAlgebra for FreeAlgebraImplBase<R, V, A, C>
596 where R: RingStore,
597 V: VectorView<El<R>>,
598 A: Allocator + Clone,
599 C: ConvolutionAlgorithm<R::Type>
600{
601 type VectorRepresentation<'a> = CloneElFn<&'a [El<R>], El<R>, CloneRingEl<&'a R>>
602 where Self: 'a;
603
604 fn canonical_gen(&self) -> Self::Element {
605 if self.rank() == 1 {
606 if self.x_pow_rank.len() == 1 {
607 self.from_canonical_basis([self.base_ring.clone_el(self.x_pow_rank.at(0))])
608 } else {
609 assert!(self.x_pow_rank.len() == 0);
610 self.zero()
611 }
612 } else {
613 self.from_canonical_basis((0..self.rank()).map(|i| if i == 1 { self.base_ring.one() } else { self.base_ring.zero() }))
614 }
615 }
616
617 fn wrt_canonical_basis<'a>(&'a self, el: &'a Self::Element) -> Self::VectorRepresentation<'a> {
618 (&el.values[..self.rank]).clone_ring_els(self.base_ring())
619 }
620
621 fn from_canonical_basis<W>(&self, vec: W) -> Self::Element
622 where W: IntoIterator<Item = El<Self::BaseRing>>,
623 W::IntoIter: DoubleEndedIterator
624 {
625 let mut given_len = 0;
626 let mut vec_it = vec.into_iter().inspect(|_| given_len += 1);
627 let mut result = Vec::with_capacity_in(1 << self.log2_padded_len, self.element_allocator.clone());
628 result.extend(vec_it.by_ref());
629 result.extend((0..((1 << self.log2_padded_len) - self.rank())).map(|_| self.base_ring().zero()));
630 assert!(vec_it.next().is_none());
631 assert_eq!(given_len, self.rank());
632 FreeAlgebraImplEl { values: result.into_boxed_slice() }
633 }
634
635 fn rank(&self) -> usize {
636 self.rank
637 }
638}
639
640impl<R, V, A, C> HashableElRing for FreeAlgebraImplBase<R, V, A, C>
641 where R: RingStore,
642 R::Type: HashableElRing,
643 V: VectorView<El<R>>,
644 A: Allocator + Clone,
645 C: ConvolutionAlgorithm<R::Type>
646{
647 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
648 for x in &el.values[..self.rank()] {
656 self.base_ring().get_ring().hash(x, h)
657 }
658 }
659}
660
661pub struct WRTCanonicalBasisElementCreator<'a, R, V, A, C>
668 where R: RingStore,
669 R::Type: FiniteRing,
670 V: VectorView<El<R>>,
671 A: Allocator + Clone,
672 C: ConvolutionAlgorithm<R::Type>
673{
674 base_ring: &'a FreeAlgebraImplBase<R, V, A, C>
675}
676
677impl<'a, R, V, A, C> Clone for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
678 where R: RingStore,
679 R::Type: FiniteRing,
680 V: VectorView<El<R>>,
681 A: Allocator + Clone,
682 C: ConvolutionAlgorithm<R::Type>
683{
684 fn clone(&self) -> Self { *self }
685}
686
687impl<'a, 'b, R, V, A, C> FnOnce<(&'b [El<R>], )> for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
688 where R: RingStore,
689 R::Type: FiniteRing,
690 V: VectorView<El<R>>,
691 A: Allocator + Clone,
692 C: ConvolutionAlgorithm<R::Type>
693{
694 type Output = El<FreeAlgebraImpl<R, V, A, C>>;
695
696 extern "rust-call" fn call_once(mut self, args: (&'b [El<R>], )) -> Self::Output {
697 self.call_mut(args)
698 }
699}
700
701impl<'a, 'b, R, V, A, C> FnMut<(&'b [El<R>], )> for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
702 where R: RingStore,
703 R::Type: FiniteRing,
704 V: VectorView<El<R>>,
705 A: Allocator + Clone,
706 C: ConvolutionAlgorithm<R::Type>
707{
708 extern "rust-call" fn call_mut(&mut self, args: (&'b [El<R>], )) -> Self::Output {
709 self.base_ring.from_canonical_basis(args.0.iter().map(|x| self.base_ring.base_ring().clone_el(x)))
710 }
711}
712
713impl<'a, R, V, A, C> Copy for WRTCanonicalBasisElementCreator<'a, R, V, A, C>
714 where R: RingStore,
715 R::Type: FiniteRing,
716 V: VectorView<El<R>>,
717 A: Allocator + Clone,
718 C: ConvolutionAlgorithm<R::Type>
719{}
720
721impl<R, V, A, C> FiniteRingSpecializable for FreeAlgebraImplBase<R, V, A, C>
722 where R: RingStore,
723 R::Type: FiniteRingSpecializable,
724 V: VectorView<El<R>>,
725 A: Allocator + Clone,
726 C: ConvolutionAlgorithm<R::Type>
727{
728 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
729 struct OpWrapper<R, V, A, C, O>
730 where R: RingStore,
731 R::Type: FiniteRingSpecializable,
732 V: VectorView<El<R>>,
733 A: Allocator + Clone,
734 C: ConvolutionAlgorithm<R::Type>,
735 O: FiniteRingOperation<FreeAlgebraImplBase<R, V, A, C>>
736 {
737 operation: O,
738 ring: PhantomData<FreeAlgebraImpl<R, V, A, C>>
739 }
740
741 impl<R, V, A, C, O> FiniteRingOperation<R::Type> for OpWrapper<R, V, A, C, O>
742 where R: RingStore,
743 R::Type: FiniteRingSpecializable,
744 V: VectorView<El<R>>,
745 A: Allocator + Clone,
746 C: ConvolutionAlgorithm<R::Type>,
747 O: FiniteRingOperation<FreeAlgebraImplBase<R, V, A, C>>
748 {
749 type Output = O::Output;
750 fn execute(self) -> Self::Output where R::Type:FiniteRing {
751 self.operation.execute()
752 }
753 fn fallback(self) -> Self::Output {
754 self.operation.fallback()
755 }
756 }
757
758 <R::Type as FiniteRingSpecializable>::specialize(OpWrapper { operation: op, ring: PhantomData })
759 }
760}
761
762impl<R, V, A, C> FiniteRing for FreeAlgebraImplBase<R, V, A, C>
763 where R: RingStore,
764 R::Type: FiniteRing,
765 V: VectorView<El<R>>,
766 A: Allocator + Clone,
767 C: ConvolutionAlgorithm<R::Type>
768{
769 type ElementsIter<'a> = MultiProduct<<R::Type as FiniteRing>::ElementsIter<'a>, WRTCanonicalBasisElementCreator<'a, R, V, A, C>, CloneRingEl<&'a R>, Self::Element>
770 where Self: 'a;
771
772 fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
773 multi_cartesian_product((0..self.rank()).map(|_| self.base_ring().elements()), WRTCanonicalBasisElementCreator { base_ring: self }, CloneRingEl(self.base_ring()))
774 }
775
776 fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
777 where I::Type: IntegerRing
778 {
779 let base_ring_size = self.base_ring().size(ZZ)?;
780 if ZZ.get_ring().representable_bits().is_none() || ZZ.abs_log2_ceil(&base_ring_size).unwrap() * self.rank() < ZZ.get_ring().representable_bits().unwrap() {
781 Some(ZZ.pow(base_ring_size, self.rank()))
782 } else {
783 None
784 }
785 }
786
787 fn random_element<G: FnMut() -> u64>(&self, mut rng: G) -> <Self as RingBase>::Element {
788 self.from_canonical_basis((0..self.rank()).map(|_| self.base_ring().random_element(&mut rng)))
789 }
790}
791
792impl_field_wrap_unwrap_homs!{
793 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
794 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
795 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
796 R2::Type: CanHomFrom<R1::Type>
797}
798
799impl_field_wrap_unwrap_isos!{
800 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
801 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
802 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
803 R2::Type: CanIsoFromTo<R1::Type>
804}
805
806impl_localpir_wrap_unwrap_homs!{
807 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
808 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
809 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
810 R2::Type: CanHomFrom<R1::Type>
811}
812
813impl_localpir_wrap_unwrap_isos!{
814 <{R1, V1, A1, C1, R2, V2, A2, C2}> FreeAlgebraImplBase<R1, V1, A1, C1>, FreeAlgebraImplBase<R2, V2, A2, C2>
815 where R1: RingStore, R1::Type: LinSolveRing, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
816 R2: RingStore, R2::Type: LinSolveRing, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
817 R2::Type: CanIsoFromTo<R1::Type>
818}
819
820impl<R1, V1, A1, C1, R2, V2, A2, C2> CanHomFrom<FreeAlgebraImplBase<R1, V1, A1, C1>> for FreeAlgebraImplBase<R2, V2, A2, C2>
821 where R1: RingStore, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
822 R2: RingStore, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
823 R2::Type: CanHomFrom<R1::Type>
824{
825 type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
826
827 fn has_canonical_hom(&self, from: &FreeAlgebraImplBase<R1, V1, A1, C1>) -> Option<Self::Homomorphism> {
828 if self.rank() == from.rank() {
829 let hom = self.base_ring.get_ring().has_canonical_hom(from.base_ring.get_ring())?;
830 if (0..self.rank()).all(|i| (i >= self.x_pow_rank.len() && i >= from.x_pow_rank.len()) ||
831 (i >= self.x_pow_rank.len() && from.base_ring().is_zero(from.x_pow_rank.at(i))) ||
832 (i >= from.x_pow_rank.len() && self.base_ring().is_zero(self.x_pow_rank.at(i))) ||
833 self.base_ring.eq_el(self.x_pow_rank.at(i), &self.base_ring.get_ring().map_in_ref(from.base_ring.get_ring(), from.x_pow_rank.at(i), &hom))
834 ) {
835 Some(hom)
836 } else {
837 None
838 }
839 } else {
840 None
841 }
842 }
843
844 fn map_in(&self, from: &FreeAlgebraImplBase<R1, V1, A1, C1>, el: <FreeAlgebraImplBase<R1, V1, A1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
845 self.from_canonical_basis((0..self.rank()).map(|i| self.base_ring.get_ring().map_in_ref(from.base_ring.get_ring(), &el.values[i], hom)))
846 }
847}
848
849impl<R1, V1, A1, C1, R2, V2, A2, C2> CanIsoFromTo<FreeAlgebraImplBase<R1, V1, A1, C1>> for FreeAlgebraImplBase<R2, V2, A2, C2>
850 where R1: RingStore, V1: VectorView<El<R1>>, A1: Allocator + Clone, C1: ConvolutionAlgorithm<R1::Type>,
851 R2: RingStore, V2: VectorView<El<R2>>, A2: Allocator + Clone, C2: ConvolutionAlgorithm<R2::Type>,
852 R2::Type: CanIsoFromTo<R1::Type>
853{
854 type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
855
856 fn has_canonical_iso(&self, from: &FreeAlgebraImplBase<R1, V1, A1, C1>) -> Option<Self::Isomorphism> {
857 if self.rank() == from.rank() {
858 let iso = self.base_ring.get_ring().has_canonical_iso(from.base_ring.get_ring())?;
859 if (0..self.rank()).all(|i|(i >= self.x_pow_rank.len() && i >= from.x_pow_rank.len()) ||
860 (i >= self.x_pow_rank.len() && from.base_ring().is_zero(from.x_pow_rank.at(i))) ||
861 (i >= from.x_pow_rank.len() && self.base_ring().is_zero(self.x_pow_rank.at(i))) ||
862 from.base_ring.eq_el(&self.base_ring.get_ring().map_out(from.base_ring.get_ring(), self.base_ring.clone_el(self.x_pow_rank.at(i)), &iso), from.x_pow_rank.at(i))
863 ) {
864 Some(iso)
865 } else {
866 None
867 }
868 } else {
869 None
870 }
871 }
872
873 fn map_out(&self, from: &FreeAlgebraImplBase<R1, V1, A1, C1>, el: <FreeAlgebraImplBase<R2, V2, A2> as RingBase>::Element, iso: &Self::Isomorphism) -> <FreeAlgebraImplBase<R1, V1, A1, C1> as RingBase>::Element {
874 from.from_canonical_basis((0..self.rank()).map(|i| self.base_ring.get_ring().map_out(from.base_ring.get_ring(), self.base_ring.clone_el(&el.values[i]), iso)))
875 }
876}
877
878#[cfg(test)]
879use crate::rings::zn::zn_64::{Zn, ZnEl};
880#[cfg(test)]
881use crate::rings::zn::ZnRingStore;
882#[cfg(test)]
883use crate::rings::zn::zn_static;
884#[cfg(test)]
885use crate::algorithms::convolution::fft::FFTConvolution;
886
887#[cfg(test)]
888fn test_ring0_and_elements() -> (FreeAlgebraImpl<Zn, Vec<ZnEl>>, Vec<FreeAlgebraImplEl<Zn>>) {
889 let R = FreeAlgebraImpl::new(Zn::new(7), 1, vec![Zn::new(7).neg_one()]);
890 let elements = R.elements().collect();
891 return (R, elements);
892}
893
894#[cfg(test)]
895fn test_ring1_and_elements() -> (FreeAlgebraImpl<StaticRing::<i64>, [i64; 2]>, Vec<FreeAlgebraImplEl<StaticRing<i64>>>) {
896 let ZZ = StaticRing::<i64>::RING;
897 let R = FreeAlgebraImpl::new(ZZ, 2, [1, 1]);
898 let mut elements = Vec::new();
899 for a in -3..=3 {
900 for b in -3..=3 {
901 elements.push(R.from_canonical_basis([a, b]));
902 }
903 }
904 return (R, elements);
905}
906
907#[cfg(test)]
908fn test_ring2_and_elements() -> (FreeAlgebraImpl<StaticRing::<i64>, Vec<i64>>, Vec<FreeAlgebraImplEl<StaticRing<i64>>>) {
909 let ZZ = StaticRing::<i64>::RING;
910 let R = FreeAlgebraImpl::new(ZZ, 3, vec![1, -1, 1]);
911 let mut elements = Vec::new();
912 for a in [-2, 0, 1, 2] {
913 for b in [-2, 0, 2] {
914 for c in [-2, 0, 2] {
915 elements.push(R.from_canonical_basis([a, b, c]));
916 }
917 }
918 }
919 return (R, elements);
920}
921
922#[cfg(test)]
923fn test_ring3_and_elements() -> (FreeAlgebraImpl<StaticRing::<i64>, Vec<i64>>, Vec<FreeAlgebraImplEl<StaticRing<i64>>>) {
924 let ZZ = StaticRing::<i64>::RING;
925 let R = FreeAlgebraImpl::new(ZZ, 3, vec![1]);
926 let mut elements = Vec::new();
927 for a in [-2, 0, 1, 2] {
928 for b in [-2, 0, 2] {
929 for c in [-2, 0, 2] {
930 elements.push(R.from_canonical_basis([a, b, c]));
931 }
932 }
933 }
934 return (R, elements);
935}
936
937#[cfg(test)]
938fn test_ring4_and_elements() -> (FreeAlgebraImpl<StaticRing::<i64>, SparseMapVector<StaticRing<i64>>>, Vec<FreeAlgebraImplEl<StaticRing<i64>>>) {
939 let ZZ = StaticRing::<i64>::RING;
940 let mut modulus = SparseMapVector::new(3, StaticRing::<i64>::RING);
942 *modulus.at_mut(1) = 1;
943 let R = FreeAlgebraImpl::new(ZZ, 3, modulus);
944 let mut elements = Vec::new();
945 for a in [-2, 0, 1, 2] {
946 for b in [-2, 0, 2] {
947 for c in [-2, 0, 2] {
948 elements.push(R.from_canonical_basis([a, b, c]));
949 }
950 }
951 }
952 return (R, elements);
953}
954
955#[test]
956fn test_sparse() {
957 let (ring, _) = test_ring4_and_elements();
958 assert_el_eq!(ring, ring.canonical_gen(), ring.pow(ring.canonical_gen(), 3));
959}
960
961#[test]
962fn test_ring_axioms() {
963 let (ring, els) = test_ring2_and_elements();
968 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
969 let (ring, els) = test_ring3_and_elements();
970 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
971 let (ring, els) = test_ring4_and_elements();
972 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
973
974 let (ring, els) = test_ring2_and_elements();
975 let ring = ring.into().set_convolution(FFTConvolution::new_with_alloc(Global));
976 crate::ring::generic_tests::test_ring_axioms(ring, els.into_iter());
977
978 let base_ring = zn_static::Fp::<257>::RING;
979 let x_pow_rank = vec![base_ring.neg_one(); 64];
980 let ring = FreeAlgebraImpl::new(base_ring, 64, x_pow_rank);
981 let mut rng = oorandom::Rand64::new(1);
982 let els = (0..10).map(|_| ring.from_canonical_basis((0..64).map(|_| ring.base_ring().random_element(|| rng.rand_u64()))));
983 crate::ring::generic_tests::test_ring_axioms(&ring, els);
984}
985
986#[test]
987fn test_rank_1_ring() {
988 let base_ring = Zn::new(5).as_field().ok().unwrap();
989 let ring = FreeAlgebraImpl::new(base_ring, 1, [base_ring.int_hom().map(1)]).as_field().ok().unwrap();
990 crate::field::generic_tests::test_field_axioms(&ring, ring.elements());
991
992 assert_el_eq!(ring, ring.one(), ring.canonical_gen());
993}
994
995#[test]
996fn test_free_algebra_axioms() {
997 let (ring, _) = test_ring0_and_elements();
998 super::generic_tests::test_free_algebra_axioms(ring);
999 let (ring, _) = test_ring1_and_elements();
1000 super::generic_tests::test_free_algebra_axioms(ring);
1001 let (ring, _) = test_ring2_and_elements();
1002 super::generic_tests::test_free_algebra_axioms(ring);
1003 let (ring, _) = test_ring3_and_elements();
1004 super::generic_tests::test_free_algebra_axioms(ring);
1005 let (ring, _) = test_ring4_and_elements();
1006 super::generic_tests::test_free_algebra_axioms(ring);
1007}
1008
1009#[test]
1010fn test_division() {
1011 let base_ring = Zn::new(4);
1012 let i = base_ring.int_hom();
1013 let ring = FreeAlgebraImpl::new(base_ring, 2, [i.map(-1), i.map(-1)]);
1014
1015 assert_el_eq!(ring,
1016 &ring.from_canonical_basis([i.map(1), i.map(3)]),
1017 &ring.checked_div(&ring.one(), &ring.from_canonical_basis([i.map(2), i.map(3)])).unwrap()
1018 );
1019
1020 let a = ring.from_canonical_basis([i.map(2), i.map(2)]);
1021 let b = ring.from_canonical_basis([i.map(0), i.map(2)]);
1022 assert_el_eq!(ring, a, ring.mul(ring.checked_div(&a, &b).unwrap(), b));
1023
1024 assert!(ring.checked_div(&ring.one(), &a).is_none());
1025}
1026
1027#[test]
1028fn test_division_ring_of_integers() {
1029 let base_ring = StaticRing::<i64>::RING;
1030 let ring = FreeAlgebraImpl::new(base_ring, 2, [11, 0]);
1031
1032 let u = ring.from_canonical_basis([10, 3]);
1034 let u_inv = ring.from_canonical_basis([10, -3]);
1035
1036 assert_el_eq!(ring, u_inv, ring.checked_div(&ring.one(), &u).unwrap());
1037 assert_el_eq!(ring, ring.pow(u_inv, 3), &ring.checked_div(&ring.one(), &ring.pow(u, 3)).unwrap());
1038
1039 assert!(ring.checked_div(&ring.from_canonical_basis([2, 0]), &ring.from_canonical_basis([3, 0])).is_none());
1040}
1041
1042#[test]
1043fn test_divisibility_axioms() {
1044 let (ring, els) = test_ring0_and_elements();
1045 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1046 let (ring, els) = test_ring1_and_elements();
1047 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1048 let (ring, els) = test_ring2_and_elements();
1049 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1050 let (ring, els) = test_ring3_and_elements();
1051 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1052 let (ring, els) = test_ring4_and_elements();
1053 crate::divisibility::generic_tests::test_divisibility_axioms(ring, els.into_iter());
1054}
1055
1056#[test]
1057fn test_cubic_mul() {
1058 let base_ring = zn_static::Zn::<256>::RING;
1059 let modulo = base_ring.int_hom();
1060 let ring = FreeAlgebraImpl::new(base_ring, 3, [modulo.map(-1), modulo.map(-1), modulo.map(-1)]);
1061 let a = ring.from_canonical_basis([modulo.map(0), modulo.map(-1), modulo.map(-1)]);
1062 let b = ring.from_canonical_basis([modulo.map(-1), modulo.map(-2), modulo.map(-1)]);
1063 assert_el_eq!(ring, b, ring.pow(a, 2));
1064}
1065
1066#[test]
1067fn test_as_field() {
1068 let base_ring = Zn::new(5).as_field().ok().unwrap();
1069 let ring = FreeAlgebraImpl::new(base_ring, 1, [base_ring.int_hom().map(1)]).as_field().ok().unwrap();
1070 crate::field::generic_tests::test_field_axioms(&ring, ring.elements());
1071
1072 let base_ring = Zn::new(3).as_field().ok().unwrap();
1073 let ring = FreeAlgebraImpl::new(base_ring, 2, [base_ring.int_hom().map(2)]).as_field().ok().unwrap();
1074 crate::field::generic_tests::test_field_axioms(&ring, ring.elements());
1075
1076 assert!(FreeAlgebraImpl::new(base_ring, 2, [base_ring.int_hom().map(1)]).as_field().is_err());
1077}
1078
1079#[test]
1080fn test_serialization() {
1081 let (ring, els) = test_ring0_and_elements();
1082 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1083 let (ring, els) = test_ring1_and_elements();
1084 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1085 let (ring, els) = test_ring2_and_elements();
1086 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1087 let (ring, els) = test_ring3_and_elements();
1088 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1089 let (ring, els) = test_ring4_and_elements();
1090 crate::serialization::generic_tests::test_serialization(ring, els.into_iter());
1091}
1092
1093#[test]
1094#[should_panic]
1095fn test_from_canonical_basis_enforce_len() {
1096 let (ring, _) = test_ring1_and_elements();
1097 _ = ring.from_canonical_basis([0, 1, 2]);
1098}
1099
1100#[test]
1101fn test_serialize_deserialize() {
1102 crate::serialization::generic_tests::test_serialize_deserialize(test_ring0_and_elements().0.into());
1103 crate::serialization::generic_tests::test_serialize_deserialize(test_ring2_and_elements().0.into());
1104 crate::serialization::generic_tests::test_serialize_deserialize(test_ring3_and_elements().0.into());
1105}