1use std::alloc::Allocator;
2use std::cmp::min;
3
4use crate::algorithms::linsolve::SolveResult;
5use crate::divisibility::*;
6use crate::matrix::*;
7use crate::matrix::transform::{TransformCols, TransformRows, TransformTarget};
8use crate::ring::*;
9use crate::pid::{PrincipalIdealRing, PrincipalIdealRingStore};
10
11use transform::TransformList;
12
13#[stability::unstable(feature = "enable")]
37pub fn pre_smith<R, TL, TR, V>(ring: R, L: &mut TL, R: &mut TR, mut A: SubmatrixMut<V, El<R>>)
38 where R: RingStore + Copy,
39 R::Type: PrincipalIdealRing,
40 TL: TransformTarget<R::Type>,
41 TR: TransformTarget<R::Type>,
42 V: AsPointerToSlice<El<R>>
43{
44 assert!(ring.is_noetherian());
46 assert!(ring.is_commutative());
47
48 for k in 0..min(A.row_count(), A.col_count()) {
49 let mut changed_row = true;
50 while changed_row {
51 changed_row = false;
52
53 for i in (k + 1)..A.row_count() {
55 if ring.is_zero(A.at(i, k)) {
56 continue;
57 } else if let Some(quo) = ring.checked_div(A.at(i, k), A.at(k, k)) {
58 TransformRows(A.reborrow(), ring.get_ring()).subtract(ring, k, i, &quo);
59 L.subtract(ring, k, i, &quo);
60 } else {
61 let (transform, _) = ring.get_ring().create_elimination_matrix(A.at(k, k), A.at(i, k));
62 TransformRows(A.reborrow(), ring.get_ring()).transform(ring, k, i, &transform);
63 L.transform(ring, k, i, &transform);
64 }
65 }
66
67 for j in (k + 1)..A.col_count() {
69 if ring.is_zero(A.at(k, j)) {
70 continue;
71 } else if let Some(quo) = ring.checked_div(A.at(k, j), A.at(k, k)) {
72 changed_row = true;
73 TransformCols(A.reborrow(), ring.get_ring()).subtract(ring, k, j, &quo);
74 R.subtract(ring, k, j, &quo);
75 } else {
76 changed_row = true;
77 let (transform, _) = ring.get_ring().create_elimination_matrix(A.at(k, k), A.at(k, j));
78 TransformCols(A.reborrow(), ring.get_ring()).transform(ring, k, j, &transform);
79 R.transform(ring, k, j, &transform);
80 }
81 }
82 }
83 }
84}
85
86#[stability::unstable(feature = "enable")]
93pub fn solve_right_using_pre_smith<R, V1, V2, V3, A>(ring: R, mut lhs: SubmatrixMut<V1, El<R>>, mut rhs: SubmatrixMut<V2, El<R>>, mut out: SubmatrixMut<V3, El<R>>, _allocator: A) -> SolveResult
94 where R: RingStore + Copy,
95 R::Type: PrincipalIdealRing,
96 V1: AsPointerToSlice<El<R>>, V2: AsPointerToSlice<El<R>>, V3: AsPointerToSlice<El<R>>,
97 A: Allocator
98{
99 assert_eq!(lhs.row_count(), rhs.row_count());
100 assert_eq!(lhs.col_count(), out.row_count());
101 assert_eq!(rhs.col_count(), out.col_count());
102
103 let mut R = TransformList::new(lhs.col_count());
104 pre_smith(ring, &mut TransformRows(rhs.reborrow(), ring.get_ring()), &mut R, lhs.reborrow());
105
106 for i in out.row_count()..rhs.row_count() {
107 for j in 0..rhs.col_count() {
108 if !ring.is_zero(rhs.at(i, j)) {
109 return SolveResult::NoSolution;
110 }
111 }
112 }
113 let mut solution_unique = true;
117
118 for i in 0..min(lhs.row_count(), lhs.col_count()) {
119 let pivot = lhs.at(i, i);
120 for j in 0..rhs.col_count() {
121 if let Some(quo) = ring.checked_left_div(rhs.at(i, j), pivot) {
122 solution_unique &= ring.is_zero(&ring.annihilator(&pivot));
123 *out.at_mut(i, j) = quo;
124 } else {
125 return SolveResult::NoSolution;
126 }
127 }
128 }
129
130 R.replay_transposed(ring, TransformRows(out, ring.get_ring()));
131 return if solution_unique {
132 SolveResult::FoundUniqueSolution
133 } else {
134 SolveResult::FoundSomeSolution
135 };
136}
137
138#[stability::unstable(feature = "enable")]
154pub fn kernel_basis_using_pre_smith<R, V, A>(ring: R, mut A: SubmatrixMut<V, El<R>>, allocator: A) -> OwnedMatrix<El<R>, A>
155 where R: RingStore + Copy,
156 R::Type: PrincipalIdealRing,
157 V: AsPointerToSlice<El<R>>,
158 A: Allocator
159{
160 let mut R = TransformList::new(A.col_count());
161 pre_smith(ring, &mut (), &mut R, A.reborrow());
162
163 let annihilators = (0..A.col_count()).map(|i| if i < A.row_count() { ring.annihilator(A.at(i, i)) } else { ring.one() }).collect::<Vec<_>>();
164 let annihilators = annihilators.iter().enumerate().filter(|(_, a)| !ring.is_zero(a)).enumerate();
165 let mut B = OwnedMatrix::zero_in(A.col_count(), annihilators.clone().count(), ring, allocator);
166 for (i, (j, a)) in annihilators {
167 *B.at_mut(i, j) = ring.clone_el(a);
168 }
169 R.replay_transposed(ring, &mut TransformRows(B.data_mut(), ring.get_ring()));
170 return B;
171}
172
173#[stability::unstable(feature = "enable")]
174pub fn determinant_using_pre_smith<R, V, A>(ring: R, mut matrix: SubmatrixMut<V, El<R>>, _allocator: A) -> El<R>
175 where R: RingStore + Copy,
176 R::Type: PrincipalIdealRing,
177 V:AsPointerToSlice<El<R>>,
178 A: Allocator
179{
180 assert_eq!(matrix.row_count(), matrix.col_count());
181 let mut unit_part_rows = ring.one();
182 let mut unit_part_cols = ring.one();
183 pre_smith(ring, &mut DetUnit { current_unit: &mut unit_part_rows }, &mut DetUnit { current_unit: &mut unit_part_cols }, matrix.reborrow());
184 return ring.checked_div(
185 &ring.prod((0..matrix.row_count()).map(|i| ring.clone_el(matrix.at(i, i)))),
186 &ring.prod([unit_part_rows, unit_part_cols])
187 ).unwrap();
188}
189
190struct DetUnit<'a, R: ?Sized + RingBase> {
191 current_unit: &'a mut R::Element
192}
193
194impl<'a, R> TransformTarget<R> for DetUnit<'a, R>
195 where R: ?Sized + RingBase
196{
197 fn subtract<S: Copy + RingStore<Type = R>>(&mut self, _ring: S, _src: usize, _dst: usize, _factor: &<R as RingBase>::Element) {
198 }
200
201 fn swap<S: Copy + RingStore<Type = R>>(&mut self, ring: S, _i: usize, _j: usize) {
202 ring.negate_inplace(&mut self.current_unit)
203 }
204
205 fn transform<S: Copy + RingStore<Type = R>>(&mut self, ring: S, _i: usize, _j: usize, transform: &[<R as RingBase>::Element; 4]) {
206 let unit = ring.sub(ring.mul_ref(&transform[0], &transform[3]), ring.mul_ref(&transform[1], &transform[2]));
207 ring.mul_assign(&mut self.current_unit, unit);
208 }
209}
210
211#[cfg(test)]
212use crate::primitive_int::StaticRing;
213#[cfg(test)]
214use crate::rings::extension::extension_impl::FreeAlgebraImpl;
215#[cfg(test)]
216use crate::rings::extension::galois_field::GaloisField;
217#[cfg(test)]
218use crate::rings::extension::FreeAlgebraStore;
219#[cfg(test)]
220use crate::rings::zn::zn_64::Zn;
221#[cfg(test)]
222use crate::rings::zn::zn_static;
223#[cfg(test)]
224use crate::assert_matrix_eq;
225#[cfg(test)]
226use crate::rings::zn::ZnRingStore;
227#[cfg(test)]
228use crate::seq::VectorView;
229#[cfg(test)]
230use crate::algorithms::matmul::ComputeInnerProduct;
231#[cfg(test)]
232use std::alloc::Global;
233#[cfg(test)]
234use test::Bencher;
235#[cfg(test)]
236use crate::homomorphism::Homomorphism;
237#[cfg(test)]
238use crate::algorithms::linsolve::LinSolveRing;
239#[cfg(test)]
240use std::ptr::Alignment;
241#[cfg(test)]
242use std::rc::Rc;
243#[cfg(test)]
244use std::time::Instant;
245#[cfg(test)]
246use crate::algorithms::convolution::STANDARD_CONVOLUTION;
247#[cfg(test)]
248use crate::algorithms::linsolve::extension::solve_right_over_extension;
249#[cfg(test)]
250use crate::algorithms::matmul::*;
251
252#[cfg(test)]
253fn multiply<'a, R: RingStore, V: AsPointerToSlice<El<R>>, I: IntoIterator<Item = Submatrix<'a, V, El<R>>>>(matrices: I, ring: R) -> OwnedMatrix<El<R>>
254 where R::Type: 'a,
255 V: 'a
256{
257 let mut it = matrices.into_iter();
258 let fst = it.next().unwrap();
259 let snd = it.next().unwrap();
260 let mut new_result = OwnedMatrix::zero(fst.row_count(), snd.col_count(), &ring);
261 STANDARD_MATMUL.matmul(TransposableSubmatrix::from(fst), TransposableSubmatrix::from(snd), TransposableSubmatrixMut::from(new_result.data_mut()), &ring);
262 let mut result = new_result;
263
264 for m in it {
265 let mut new_result = OwnedMatrix::zero(result.row_count(), m.col_count(), &ring);
266 STANDARD_MATMUL.matmul(TransposableSubmatrix::from(result.data()), TransposableSubmatrix::from(m), TransposableSubmatrixMut::from(new_result.data_mut()), &ring);
267 result = new_result;
268 }
269 return result;
270}
271
272#[test]
273fn test_smith_integers() {
274 let ring = StaticRing::<i64>::RING;
275 let mut A = OwnedMatrix::new(
276 vec![ 1, 2, 3, 4,
277 2, 3, 4, 5,
278 3, 4, 5, 6 ],
279 4
280 );
281 let original_A = A.clone_matrix(&ring);
282 let mut L: OwnedMatrix<i64> = OwnedMatrix::identity(3, 3, StaticRing::<i64>::RING);
283 let mut R: OwnedMatrix<i64> = OwnedMatrix::identity(4, 4, StaticRing::<i64>::RING);
284 pre_smith(ring, &mut TransformRows(L.data_mut(), ring.get_ring()), &mut TransformCols(R.data_mut(), ring.get_ring()), A.data_mut());
285
286 assert_matrix_eq!(&ring, &[
287 [1, 0, 0, 0],
288 [0,-1, 0, 0],
289 [0, 0, 0, 0]], &A);
290
291 assert_matrix_eq!(&ring, &multiply([L.data(), original_A.data(), R.data()], ring), &A);
292}
293
294#[test]
295fn test_smith_zn() {
296 let ring = zn_static::Zn::<45>::RING;
297 let mut A = OwnedMatrix::new(
298 vec![ 8, 3, 5, 8,
299 0, 9, 0, 9,
300 5, 9, 5, 14,
301 8, 3, 5, 23,
302 3,39, 0, 39 ],
303 4
304 );
305 let original_A = A.clone_matrix(&ring);
306 let mut L: OwnedMatrix<u64> = OwnedMatrix::identity(5, 5, ring);
307 let mut R: OwnedMatrix<u64> = OwnedMatrix::identity(4, 4, ring);
308 pre_smith(ring, &mut TransformRows(L.data_mut(), ring.get_ring()), &mut TransformCols(R.data_mut(), ring.get_ring()), A.data_mut());
309
310 assert_matrix_eq!(&ring, &[
311 [8, 0, 0, 0],
312 [0, 3, 0, 0],
313 [0, 0, 0, 0],
314 [0, 0, 0, 15],
315 [0, 0, 0, 0]], &A);
316
317 assert_matrix_eq!(&ring, &multiply([L.data(), original_A.data(), R.data()], ring), &A);
318}
319
320#[test]
321fn test_solve_zn() {
322 let ring = zn_static::Zn::<45>::RING;
323 let A = OwnedMatrix::new(
324 vec![ 8, 3, 5, 8,
325 0, 9, 0, 9,
326 5, 9, 5, 14,
327 8, 3, 5, 23,
328 3,39, 0, 39 ],
329 4
330 );
331 let B = OwnedMatrix::new(
332 vec![11, 43, 10, 22,
333 18, 9, 27, 27,
334 8, 34, 7, 22,
335 41, 13, 40, 37,
336 3, 9, 3, 0],
337 4
338 );
339 let mut solution: OwnedMatrix<_> = OwnedMatrix::zero(4, 4, ring);
340 ring.get_ring().solve_right(A.clone_matrix(ring).data_mut(), B.clone_matrix(ring).data_mut(), solution.data_mut(), Global).assert_solved();
341
342 assert_matrix_eq!(&ring, &multiply([A.data(), solution.data()], ring), &B);
343}
344
345#[test]
346fn test_unique_solution_correct() {
347 let ring = zn_static::Zn::<45>::RING;
348 let A = OwnedMatrix::new(
349 vec![ 1, 0, 0, 0,
350 0, 1, 0, 0,
351 0, 0, 1, 0,
352 0, 0, 0, 1 ],
353 4
354 );
355 let B = OwnedMatrix::new(vec![ 1, 1, 0, 0 ], 1);
356 let mut solution: OwnedMatrix<_> = OwnedMatrix::zero(4, 1, ring);
357 assert_eq!(SolveResult::FoundUniqueSolution, ring.get_ring().solve_right(A.clone_matrix(ring).data_mut(), B.clone_matrix(ring).data_mut(), solution.data_mut(), Global));
358 assert_matrix_eq!(&ring, &multiply([A.data(), solution.data()], ring), &B);
359
360 let A = OwnedMatrix::new(
361 vec![ 1, 0, 0, 0,
362 0, 1, 0, 0,
363 0, 0, 1, 0,
364 0, 0, 0, 0 ],
365 4
366 );
367 let B = OwnedMatrix::new(vec![ 1, 1, 0, 0 ], 1);
368 let mut solution: OwnedMatrix<_> = OwnedMatrix::zero(4, 1, ring);
369 assert_eq!(SolveResult::FoundSomeSolution, ring.get_ring().solve_right(A.clone_matrix(ring).data_mut(), B.clone_matrix(ring).data_mut(), solution.data_mut(), Global));
370 assert_matrix_eq!(&ring, &multiply([A.data(), solution.data()], ring), &B);
371
372 let A = OwnedMatrix::new(
373 vec![ 1, 0, 0, 0,
374 0, 1, 0, 0,
375 0, 0, 1, 0,
376 0, 0, 0, 3 ],
377 4
378 );
379 let B = OwnedMatrix::new(vec![ 1, 1, 0, 0 ], 1);
380 let mut solution: OwnedMatrix<_> = OwnedMatrix::zero(4, 1, ring);
381 assert_eq!(SolveResult::FoundSomeSolution, ring.get_ring().solve_right(A.clone_matrix(ring).data_mut(), B.clone_matrix(ring).data_mut(), solution.data_mut(), Global));
382 assert_matrix_eq!(&ring, &multiply([A.data(), solution.data()], ring), &B);
383}
384
385#[test]
386fn test_solve_int() {
387 let ring = StaticRing::<i64>::RING;
388 let A = OwnedMatrix::new(
389 vec![3, 6, 2, 0, 4, 7,
390 5, 5, 4, 5, 5, 5],
391 6
392 );
393 let B: OwnedMatrix<i64> = OwnedMatrix::identity(2, 2, ring);
394 let mut solution: OwnedMatrix<i64> = OwnedMatrix::zero(6, 2, ring);
395 ring.get_ring().solve_right(A.clone_matrix(ring).data_mut(), B.clone_matrix(ring).data_mut(), solution.data_mut(), Global).assert_solved();
396
397 assert_matrix_eq!(&ring, &multiply([A.data(), solution.data()], &ring), &B);
398}
399
400#[test]
401fn test_large() {
402 let ring = zn_static::Zn::<16>::RING;
403 let data_A = [
404 [0, 0, 0, 0, 0, 0, 0, 0,11, 0, 0],
405 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
406 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10],
407 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
408 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8],
409 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
410 ];
411 let mut A: OwnedMatrix<u64> = OwnedMatrix::zero(6, 11, &ring);
412 for i in 0..6 {
413 for j in 0..11 {
414 *A.at_mut(i, j) = data_A[i][j];
415 }
416 }
417 let mut solution: OwnedMatrix<_> = OwnedMatrix::zero(11, 11, ring);
418 assert!(ring.get_ring().solve_right(A.clone_matrix(&ring).data_mut(), A.data_mut(), solution.data_mut(), Global).is_solved());
419}
420
421#[test]
422fn test_determinant() {
423 let ring = StaticRing::<i64>::RING;
424 let A = OwnedMatrix::new(
425 vec![1, 0, 3,
426 2, 1, 0,
427 9, 8, 7],
428 3
429 );
430 assert_el_eq!(ring, (7 + 48 - 27), determinant_using_pre_smith(ring, A.clone_matrix(&ring).data_mut(), Global));
431
432 #[derive(PartialEq, Clone, Copy)]
435 struct TestRing;
436 use crate::delegate::DelegateRing;
437 impl DelegateRing for TestRing {
438 type Base = zn_static::ZnBase<45, false>;
439 type Element = u64;
440
441 fn get_delegate(&self) -> &Self::Base { zn_static::Zn::RING.get_ring() }
442 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
443 fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
444 fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
445 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
446 }
447 impl PrincipalIdealRing for TestRing {
448
449 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
450 self.get_delegate().extended_ideal_gen(lhs, rhs)
451 }
452
453 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
454 self.get_delegate().checked_div_min(lhs, rhs)
455 }
456
457 fn create_elimination_matrix(&self, a: &Self::Element, b: &Self::Element) -> ([Self::Element; 4], Self::Element) {
458 assert_eq!(9, *a);
459 assert_eq!(15, *b);
460 assert_eq!(3, self.add(self.mul(42, *a), self.mul(2, *b)));
461 assert_eq!(0, self.add(self.mul(5, *a), self.mul(3, *b)));
462 return ([42, 2, 10, 6], 3);
463 }
464 }
465
466 let ring = RingValue::from(TestRing);
467 let A = OwnedMatrix::new(vec![9, 0, 15, 3], 2);
468 assert_el_eq!(ring, 27, determinant_using_pre_smith(ring, A.clone_matrix(&ring).data_mut(), Global));
469}
470
471#[test]
472fn test_kernel_basis() {
473 let ring = StaticRing::<i64>::RING;
474 let mut A = OwnedMatrix::identity(2, 2, ring);
475 assert_matrix_eq!(ring, [[], []], kernel_basis_using_pre_smith(ring, A.data_mut(), Global));
476
477 let mut A = OwnedMatrix::zero(2, 2, ring);
478 assert_matrix_eq!(ring, [[1, 0], [0, 1]], kernel_basis_using_pre_smith(ring, A.data_mut(), Global));
479
480 let A = OwnedMatrix::new(vec![1, 1, 2, 3, 2, 1], 3);
481 let B = kernel_basis_using_pre_smith(ring, A.clone_matrix(ring).data_mut(), Global);
482 assert_eq!(1, B.col_count());
483 assert!(!ring.is_zero(B.at(0, 0)));
484 let mut product = OwnedMatrix::zero(2, 1, ring);
485 STANDARD_MATMUL.matmul(TransposableSubmatrix::from(A.data()), TransposableSubmatrix::from(B.data()), TransposableSubmatrixMut::from(product.data_mut()), ring);
486 assert_matrix_eq!(ring, [[0], [0]], product);
487
488 let A = OwnedMatrix::new(vec![1, 1, 1, 1, 1, 1], 2);
489 let B = kernel_basis_using_pre_smith(ring, A.clone_matrix(ring).data_mut(), Global);
490 assert_eq!(1, B.col_count());
491 assert!(!ring.is_zero(B.at(0, 0)));
492 let mut product = OwnedMatrix::zero(3, 1, ring);
493 STANDARD_MATMUL.matmul(TransposableSubmatrix::from(A.data()), TransposableSubmatrix::from(B.data()), TransposableSubmatrixMut::from(product.data_mut()), ring);
494 assert_matrix_eq!(ring, [[0], [0], [0]], product);
495
496 let ring = Zn::new(6);
497 let A = OwnedMatrix::new(vec![ring.int_hom().map(2)], 1);
498 let B = kernel_basis_using_pre_smith(ring, A.clone_matrix(ring).data_mut(), Global);
499 assert_eq!(1, B.col_count());
500 assert_matrix_eq!(ring, [[ring.int_hom().map(3)]], B);
501}
502
503#[test]
504#[ignore]
505fn time_solve_right_using_pre_smith_galois_field() {
506 let n = 100;
507 let base_field = Zn::new(257).as_field().ok().unwrap();
508 let allocator = feanor_mempool::AllocRc(Rc::new(feanor_mempool::dynsize::DynLayoutMempool::new_global(Alignment::of::<u64>())));
509 let field = GaloisField::new_with_convolution(base_field, 21, allocator, STANDARD_CONVOLUTION);
510 let matrix = OwnedMatrix::from_fn(n, n, |i, j| field.pow(field.int_hom().mul_map(field.canonical_gen(), i as i32 + 1), j));
511
512 let mut inv = OwnedMatrix::zero(n, n, &field);
513 let mut copy = matrix.clone_matrix(&field);
514 let start = Instant::now();
515 solve_right_using_pre_smith(&field, copy.data_mut(), OwnedMatrix::identity(n, n, &field).data_mut(), inv.data_mut(), Global).assert_solved();
516 let end = Instant::now();
517 assert_el_eq!(&field, field.one(), <_ as ComputeInnerProduct>::inner_product_ref(field.get_ring(), inv.data().col_at(4).as_iter().zip(matrix.data().row_at(4).as_iter())));
518
519 println!("total: {} us", (end - start).as_micros());
520}
521
522#[test]
523#[ignore]
524fn time_solve_right_using_extension() {
525 let n = 126;
526 let base_field = Zn::new(257).as_field().ok().unwrap();
527 let allocator = feanor_mempool::AllocRc(Rc::new(feanor_mempool::dynsize::DynLayoutMempool::new_global(Alignment::of::<u64>())));
528 let field = GaloisField::new_with_convolution(base_field, 21, allocator, STANDARD_CONVOLUTION);
529 let matrix = OwnedMatrix::from_fn(n, n, |i, j| field.pow(field.int_hom().mul_map(field.canonical_gen(), i as i32 + 1), j));
530
531 let mut inv = OwnedMatrix::zero(n, n, &field);
532 let mut copy = matrix.clone_matrix(&field);
533 let start = Instant::now();
534 solve_right_over_extension(&field, copy.data_mut(), OwnedMatrix::identity(n, n, &field).data_mut(), inv.data_mut(), Global).assert_solved();
535 let end = Instant::now();
536 assert_el_eq!(&field, field.one(), <_ as ComputeInnerProduct>::inner_product_ref(field.get_ring(), inv.data().col_at(4).as_iter().zip(matrix.data().row_at(4).as_iter())));
537
538 println!("total: {} us", (end - start).as_micros());
539}
540
541#[bench]
542fn bench_solve_right_using_pre_smith_galois_field(bencher: &mut Bencher) {
543 let base_field = Zn::new(257).as_field().ok().unwrap();
544 let allocator = feanor_mempool::AllocRc(Rc::new(feanor_mempool::dynsize::DynLayoutMempool::new_global(Alignment::of::<u64>())));
545 let field = GaloisField::create(FreeAlgebraImpl::new_with_convolution(base_field, 5, [base_field.int_hom().map(3), base_field.int_hom().map(-4)], "x", allocator, STANDARD_CONVOLUTION).as_field().ok().unwrap());
546 let matrix = OwnedMatrix::from_fn(10, 10, |i, j| field.pow(field.int_hom().mul_map(field.canonical_gen(), i as i32 + 1), j));
547 bencher.iter(|| {
548 let mut inv = OwnedMatrix::zero(10, 10, &field);
549 let mut copy = matrix.clone_matrix(&field);
550 solve_right_using_pre_smith(&field, copy.data_mut(), OwnedMatrix::identity(10, 10, &field).data_mut(), inv.data_mut(), Global).assert_solved();
551 assert_el_eq!(&field, field.one(), <_ as ComputeInnerProduct>::inner_product_ref(field.get_ring(), inv.data().col_at(4).as_iter().zip(matrix.data().row_at(4).as_iter())));
552 });
553}