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