Skip to main content

qfall_math/integer/mat_poly_over_z/
get.rs

1// Copyright 2023 Marvin Beckmann
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementations to get information about a [`MatPolyOverZ`] matrix.
10
11use super::MatPolyOverZ;
12use crate::{
13    integer::PolyOverZ,
14    traits::{MatrixDimensions, MatrixGetEntry, MatrixGetSubmatrix},
15};
16use flint3_sys::{
17    fmpz_poly_set, fmpz_poly_struct,
18    {
19        fmpz_poly_mat_entry, fmpz_poly_mat_init_set, fmpz_poly_mat_window_clear,
20        fmpz_poly_mat_window_init,
21    },
22};
23use std::mem::MaybeUninit;
24
25impl MatrixDimensions for MatPolyOverZ {
26    /// Returns the number of rows of the matrix as a [`i64`].
27    ///
28    /// # Examples
29    /// ```
30    /// use qfall_math::integer::MatPolyOverZ;
31    /// use qfall_math::traits::*;
32    ///
33    /// let matrix = MatPolyOverZ::new(5, 6);
34    /// let rows = matrix.get_num_rows();
35    /// ```
36    fn get_num_rows(&self) -> i64 {
37        self.matrix.r
38    }
39
40    /// Returns the number of columns of the matrix as a [`i64`].
41    ///
42    /// # Examples
43    /// ```
44    /// use qfall_math::integer::MatPolyOverZ;
45    /// use qfall_math::traits::*;
46    ///
47    /// let matrix = MatPolyOverZ::new(5, 6);
48    /// let columns = matrix.get_num_columns();
49    /// ```
50    fn get_num_columns(&self) -> i64 {
51        self.matrix.c
52    }
53}
54
55impl MatrixGetEntry<PolyOverZ> for MatPolyOverZ {
56    /// Outputs the [`PolyOverZ`] value of a specific matrix entry
57    /// without checking whether it's part of the matrix.
58    ///
59    /// Parameters:
60    /// - `row`: specifies the row in which the entry is located
61    /// - `column`: specifies the column in which the entry is located
62    ///
63    /// Returns the [`PolyOverZ`] value of the matrix at the position of the given
64    /// row and column.
65    ///
66    /// # Safety
67    /// To use this function safely, make sure that the selected entry is part
68    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
69    /// occur.
70    ///
71    /// # Examples
72    /// ```
73    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
74    /// use qfall_math::traits::*;
75    /// use std::str::FromStr;
76    ///
77    /// let matrix = MatPolyOverZ::from_str("[[1  1, 1  2],[1  3, 1  4],[0, 1  6]]").unwrap();
78    ///
79    /// assert_eq!(PolyOverZ::from(2), unsafe { matrix.get_entry_unchecked(0, 1) });
80    /// assert_eq!(PolyOverZ::from(4), unsafe { matrix.get_entry_unchecked(1, 1) });
81    /// ```
82    unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> PolyOverZ {
83        let mut copy = PolyOverZ::default();
84        let entry = unsafe { fmpz_poly_mat_entry(&self.matrix, row, column) };
85        unsafe { fmpz_poly_set(&mut copy.poly, entry) };
86
87        copy
88    }
89}
90
91impl MatrixGetSubmatrix for MatPolyOverZ {
92    /// Returns a deep copy of the submatrix defined by the given parameters
93    /// and does not check the provided dimensions.
94    /// There is also a safe version of this function that checks the input.
95    ///
96    /// Parameters:
97    /// `row_1`: the starting row of the submatrix
98    /// `row_2`: the ending row of the submatrix
99    /// `col_1`: the starting column of the submatrix
100    /// `col_2`: the ending column of the submatrix
101    ///
102    /// Returns the submatrix from `(row_1, col_1)` to `(row_2, col_2)`(exclusively).
103    ///
104    /// # Examples
105    /// ```
106    /// use qfall_math::{integer::MatPolyOverZ, traits::MatrixGetSubmatrix};
107    /// use std::str::FromStr;
108    ///
109    /// let mat = MatPolyOverZ::identity(3, 3);
110    ///
111    /// let sub_mat_1 = mat.get_submatrix(0, 2, 1, 1).unwrap();
112    /// let sub_mat_2 = mat.get_submatrix(0, -1, 1, -2).unwrap();
113    /// let sub_mat_3 = unsafe{mat.get_submatrix_unchecked(0, 3, 1, 2)};
114    ///
115    /// let e_2 = MatPolyOverZ::from_str("[[0],[1  1],[0]]").unwrap();
116    /// assert_eq!(e_2, sub_mat_1);
117    /// assert_eq!(e_2, sub_mat_2);
118    /// assert_eq!(e_2, sub_mat_3);
119    /// ```
120    ///
121    /// # Safety
122    /// To use this function safely, make sure that the selected submatrix is part
123    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
124    /// occur.
125    unsafe fn get_submatrix_unchecked(
126        &self,
127        row_1: i64,
128        row_2: i64,
129        col_1: i64,
130        col_2: i64,
131    ) -> Self {
132        let mut window = MaybeUninit::uninit();
133        // The memory for the elements of window is shared with self.
134        unsafe {
135            fmpz_poly_mat_window_init(
136                window.as_mut_ptr(),
137                &self.matrix,
138                row_1,
139                col_1,
140                row_2,
141                col_2,
142            )
143        };
144        let mut window_copy = MaybeUninit::uninit();
145        unsafe {
146            // Deep clone of the content of the window
147            fmpz_poly_mat_init_set(window_copy.as_mut_ptr(), window.as_ptr());
148            // Clears the matrix window and releases any memory that it uses. Note that
149            // the memory to the underlying matrix that window points to is not freed
150            fmpz_poly_mat_window_clear(window.as_mut_ptr());
151        }
152        MatPolyOverZ {
153            matrix: unsafe { window_copy.assume_init() },
154        }
155    }
156}
157
158impl MatPolyOverZ {
159    /// Efficiently collects all [`fmpz_poly_struct`]s in a [`MatPolyOverZ`] without cloning them.
160    ///
161    /// Hence, the values on the returned [`Vec`] are intended for short-term use
162    /// as the access to [`fmpz_poly_struct`] values could lead to memory leaks or
163    /// modified values once the [`MatPolyOverZ`] instance was modified or dropped.
164    ///
165    /// # Examples
166    /// ```compile_fail
167    /// use qfall_math::integer::MatPolyOverZ;
168    /// use std::str::FromStr;
169    ///
170    /// let mat = MatPolyOverZ::from_str("[[1  1, 0],[1  3, 1  4],[0, 1  6]]").unwrap();
171    ///
172    /// let fmpz_entries = mat.collect_entries();
173    /// ```
174    pub(crate) fn collect_entries<'a>(&self) -> Vec<&'a fmpz_poly_struct> {
175        let mut entries: Vec<&'a fmpz_poly_struct> =
176            Vec::with_capacity((self.get_num_rows() * self.get_num_columns()) as usize);
177
178        for row in 0..self.get_num_rows() {
179            for col in 0..self.get_num_columns() {
180                // efficiently get entry without cloning the entry itself
181                unsafe {
182                    let entry_ptr = fmpz_poly_mat_entry(&self.matrix, row, col);
183                    let entry_ref: &'a fmpz_poly_struct = &*entry_ptr;
184                    entries.push(entry_ref);
185                }
186            }
187        }
188
189        entries
190    }
191}
192
193#[cfg(test)]
194mod test_get_entry {
195    use crate::{
196        integer::{MatPolyOverZ, PolyOverZ},
197        traits::{MatrixGetEntry, MatrixSetEntry},
198    };
199    use std::str::FromStr;
200
201    /// Ensure that getting entries works with large polynomials.
202    #[test]
203    fn max_int_positive() {
204        let mut matrix = MatPolyOverZ::new(5, 10);
205        let value = PolyOverZ::from_str(&format!("2  {} 1", i64::MAX)).unwrap();
206        matrix.set_entry(1, 1, value).unwrap();
207
208        let entry = matrix.get_entry(1, 1).unwrap();
209
210        assert_eq!(format!("2  {} 1", i64::MAX), entry.to_string());
211    }
212
213    /// Ensure that getting entries works with large polynomials (larger than [`i64`]).
214    #[test]
215    fn large_positive() {
216        let mut matrix = MatPolyOverZ::new(5, 10);
217        let value = PolyOverZ::from_str(&format!("2  {} 1", u64::MAX)).unwrap();
218        matrix.set_entry(1, 1, value).unwrap();
219
220        let entry = matrix.get_entry(1, 1).unwrap();
221
222        assert_eq!(format!("2  {} 1", u64::MAX), entry.to_string());
223    }
224
225    /// Ensure that getting entries works with large negative polynomials.
226    #[test]
227    fn max_int_negative() {
228        let mut matrix = MatPolyOverZ::new(5, 10);
229        let value = PolyOverZ::from_str(&format!("2  {} 1", i64::MIN)).unwrap();
230        matrix.set_entry(1, 1, value).unwrap();
231
232        let entry = matrix.get_entry(1, 1).unwrap();
233
234        assert_eq!(format!("2  {} 1", i64::MIN), entry.to_string());
235    }
236
237    /// Ensure that getting entries works with large negative polynomials (larger than [`i64`]).
238    #[test]
239    fn large_negative() {
240        let mut matrix = MatPolyOverZ::new(5, 10);
241        let value = PolyOverZ::from_str(&format!("2  -{} 1", u64::MAX)).unwrap();
242        matrix.set_entry(1, 1, value).unwrap();
243
244        let entry = matrix.get_entry(1, 1).unwrap();
245
246        assert_eq!(format!("2  -{} 1", u64::MAX), entry.to_string());
247    }
248
249    /// Ensure that polynomials with many entries are correctly retrieved
250    #[test]
251    fn large_poly() {
252        let mut matrix = MatPolyOverZ::new(5, 10);
253        let value =
254            PolyOverZ::from_str(&format!("10000  -{} 1{}", u64::MAX, " 17".repeat(9998))).unwrap();
255        matrix.set_entry(1, 1, value).unwrap();
256
257        let entry = matrix.get_entry(1, 1).unwrap();
258
259        assert_eq!(
260            format!("10000  -{} 1{}", u64::MAX, " 17".repeat(9998)),
261            entry.to_string()
262        );
263    }
264
265    /// Ensure that getting entries at (0, 0) works.
266    #[test]
267    fn getting_at_zero() {
268        let mut matrix = MatPolyOverZ::new(5, 10);
269        let value = PolyOverZ::from_str(&format!("2  {} 1", i64::MAX)).unwrap();
270        matrix.set_entry(0, 0, value).unwrap();
271
272        let entry = matrix.get_entry(0, 0).unwrap();
273
274        assert_eq!(format!("2  {} 1", i64::MAX), entry.to_string());
275    }
276
277    /// Ensure that a wrong number of rows yields an Error.
278    #[test]
279    fn error_wrong_row() {
280        let matrix = MatPolyOverZ::new(5, 10);
281
282        assert!(matrix.get_entry(5, 1).is_err());
283        assert!(matrix.get_entry(-6, 1).is_err());
284    }
285
286    /// Ensure that a wrong number of columns yields an Error.
287    #[test]
288    fn error_wrong_column() {
289        let matrix = MatPolyOverZ::new(5, 10);
290
291        assert!(matrix.get_entry(1, 100).is_err());
292        assert!(matrix.get_entry(1, -11).is_err());
293    }
294
295    /// Ensure that negative indices return the correct values.
296    #[test]
297    fn negative_indexing() {
298        let matrix = MatPolyOverZ::from_str("[[1  1, 1  2],[1  3, 1  4],[1  5 , 1  6]]").unwrap();
299
300        assert_eq!(PolyOverZ::from(2), matrix.get_entry(0, -1).unwrap());
301        assert_eq!(PolyOverZ::from(4), matrix.get_entry(-2, 1).unwrap());
302        assert_eq!(PolyOverZ::from(4), matrix.get_entry(-2, -1).unwrap());
303        assert_eq!(PolyOverZ::from(6), matrix.get_entry(-1, -1).unwrap());
304    }
305
306    /// Ensure that the entry is a deep copy and not just a clone of the reference.
307    #[test]
308    fn memory_test() {
309        let mut matrix = MatPolyOverZ::new(5, 10);
310        let value = PolyOverZ::from_str(&format!("2  {} 1", u64::MAX)).unwrap();
311        matrix.set_entry(1, 1, value).unwrap();
312        let entry = matrix.get_entry(1, 1).unwrap();
313        matrix.set_entry(1, 1, PolyOverZ::default()).unwrap();
314
315        assert_eq!(format!("2  {} 1", u64::MAX), entry.to_string());
316    }
317}
318
319#[cfg(test)]
320mod test_get_num {
321    use crate::{integer::MatPolyOverZ, traits::MatrixDimensions};
322
323    /// Ensure that the getter for number of rows works correctly.
324    #[test]
325    fn num_rows() {
326        let matrix = MatPolyOverZ::new(5, 10);
327
328        assert_eq!(matrix.get_num_rows(), 5);
329    }
330
331    /// Ensure that the getter for number of columns works correctly.
332    #[test]
333    fn num_columns() {
334        let matrix = MatPolyOverZ::new(5, 10);
335
336        assert_eq!(matrix.get_num_columns(), 10);
337    }
338}
339
340#[cfg(test)]
341mod test_get_vec {
342    use crate::{integer::MatPolyOverZ, traits::MatrixGetSubmatrix};
343    use std::str::FromStr;
344
345    /// Ensure that getting a row works
346    #[test]
347    fn get_row_works() {
348        let matrix = MatPolyOverZ::from_str(&format!(
349            "[[0, 0, 0],[1  42, 1  {}, 1  {}]]",
350            i64::MAX,
351            i64::MIN
352        ))
353        .unwrap();
354        let row_1 = matrix.get_row(0).unwrap();
355        let row_2 = matrix.get_row(1).unwrap();
356
357        let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
358        let cmp_2 = MatPolyOverZ::from_str(&format!("[[1  42, 1  {}, 1  {}]]", i64::MAX, i64::MIN))
359            .unwrap();
360
361        assert_eq!(cmp_1, row_1);
362        assert_eq!(cmp_2, row_2);
363    }
364
365    /// Ensure that getting a row with a negative index works
366    #[test]
367    fn get_row_negative_indexing_works() {
368        let matrix = MatPolyOverZ::from_str(&format!(
369            "[[0, 0, 0],[1  42, 1  {}, 1  {}]]",
370            i64::MAX,
371            i64::MIN
372        ))
373        .unwrap();
374        let row_1 = matrix.get_row(-2).unwrap();
375        let row_2 = matrix.get_row(-1).unwrap();
376
377        let cmp_1 = MatPolyOverZ::from_str("[[0, 0, 0]]").unwrap();
378        let cmp_2 = MatPolyOverZ::from_str(&format!("[[1  42, 1  {}, 1  {}]]", i64::MAX, i64::MIN))
379            .unwrap();
380
381        assert_eq!(cmp_1, row_1);
382        assert_eq!(cmp_2, row_2);
383    }
384
385    /// Ensure that getting a column works
386    #[test]
387    fn get_column_works() {
388        let matrix = MatPolyOverZ::from_str(&format!(
389            "[[1  42, 0, 2  17 42],[1  {}, 0, 2  17 42],[1  {}, 0, 2  17 42]]",
390            i64::MAX,
391            i64::MIN
392        ))
393        .unwrap();
394        let column_1 = matrix.get_column(0).unwrap();
395        let column_2 = matrix.get_column(1).unwrap();
396        let column_3 = matrix.get_column(2).unwrap();
397
398        let cmp_1 =
399            MatPolyOverZ::from_str(&format!("[[1  42],[1  {}],[1  {}]]", i64::MAX, i64::MIN))
400                .unwrap();
401        let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
402        let cmp_3 = MatPolyOverZ::from_str("[[2  17 42],[2  17 42],[2  17 42]]").unwrap();
403
404        assert_eq!(cmp_1, column_1);
405        assert_eq!(cmp_2, column_2);
406        assert_eq!(cmp_3, column_3);
407    }
408
409    /// Ensure that getting a column with a negative index works
410    #[test]
411    fn get_column_negative_indexing_works() {
412        let matrix = MatPolyOverZ::from_str(&format!(
413            "[[1  42, 0, 2  17 42],[1  {}, 0, 2  17 42],[1  {}, 0, 2  17 42]]",
414            i64::MAX,
415            i64::MIN
416        ))
417        .unwrap();
418        let column_1 = matrix.get_column(-3).unwrap();
419        let column_2 = matrix.get_column(-2).unwrap();
420        let column_3 = matrix.get_column(-1).unwrap();
421
422        let cmp_1 =
423            MatPolyOverZ::from_str(&format!("[[1  42],[1  {}],[1  {}]]", i64::MAX, i64::MIN))
424                .unwrap();
425        let cmp_2 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
426        let cmp_3 = MatPolyOverZ::from_str("[[2  17 42],[2  17 42],[2  17 42]]").unwrap();
427
428        assert_eq!(cmp_1, column_1);
429        assert_eq!(cmp_2, column_2);
430        assert_eq!(cmp_3, column_3);
431    }
432
433    /// Ensure that wrong row and column dimensions yields an error
434    #[test]
435    fn wrong_dim_error() {
436        let matrix = MatPolyOverZ::from_str(&format!(
437            "[[1  17, 2  17 42, 3  1 1 1],[1  {}, 1  1, 2  2 3],[1  {}, 1  142, 1  1]]",
438            i64::MAX,
439            i64::MIN
440        ))
441        .unwrap();
442        let row_1 = matrix.get_row(-4);
443        let row_2 = matrix.get_row(4);
444        let column_1 = matrix.get_column(-4);
445        let column_2 = matrix.get_column(4);
446
447        assert!(row_1.is_err());
448        assert!(row_2.is_err());
449        assert!(column_1.is_err());
450        assert!(column_2.is_err());
451    }
452}
453
454#[cfg(test)]
455mod test_get_submatrix {
456    use crate::{
457        integer::{MatPolyOverZ, Z},
458        traits::{MatrixDimensions, MatrixGetSubmatrix},
459    };
460    use std::str::FromStr;
461
462    /// Ensures that getting the entire matrix as a submatrix works.
463    #[test]
464    fn entire_matrix() {
465        let mat = MatPolyOverZ::identity(5, 5);
466
467        let sub_mat = mat.get_submatrix(0, 4, 0, 4).unwrap();
468
469        assert_eq!(mat, sub_mat);
470    }
471
472    /// Ensures that a single matrix entry can be retrieved.
473    #[test]
474    fn matrix_single_entry() {
475        let mat = MatPolyOverZ::identity(5, 5);
476
477        let sub_mat = mat.get_submatrix(0, 0, 0, 0).unwrap();
478
479        let cmp_mat = MatPolyOverZ::identity(1, 1);
480        assert_eq!(cmp_mat, sub_mat);
481    }
482
483    /// Ensures that the dimensions of the submatrix are correct.
484    #[test]
485    fn correct_dimensions() {
486        let mat = MatPolyOverZ::identity(100, 100);
487
488        let sub_mat = mat.get_submatrix(1, 37, 0, 29).unwrap();
489
490        assert_eq!(37, sub_mat.get_num_rows());
491        assert_eq!(30, sub_mat.get_num_columns());
492    }
493
494    /// Ensures that a submatrix can be correctly retrieved for a matrix with large
495    /// entries.
496    #[test]
497    fn large_entries() {
498        let mat = MatPolyOverZ::from_str(&format!(
499            "[[2  {} {}, 1  2, 1  3],[1  1, 1  {}, 1  3]]",
500            u64::MAX,
501            i64::MAX,
502            i64::MIN
503        ))
504        .unwrap();
505
506        let sub_mat = mat.get_submatrix(0, 1, 0, 1).unwrap();
507
508        let cmp_mat = MatPolyOverZ::from_str(&format!(
509            "[[2  {} {}, 1  2],[1  1, 1  {}]]",
510            u64::MAX,
511            i64::MAX,
512            i64::MIN
513        ))
514        .unwrap();
515        assert_eq!(cmp_mat, sub_mat);
516    }
517
518    /// Ensures that an error is returned if coordinates are addressed that are not
519    /// within the matrix.
520    #[test]
521    fn invalid_coordinates() {
522        let mat = MatPolyOverZ::identity(10, 10);
523
524        assert!(mat.get_submatrix(0, 0, 0, 10).is_err());
525        assert!(mat.get_submatrix(0, 10, 0, 0).is_err());
526        assert!(mat.get_submatrix(0, 0, -11, 0).is_err());
527        assert!(mat.get_submatrix(-11, 0, 0, 0).is_err());
528    }
529
530    /// Ensure that negative indices return the correct submatrix.
531    #[test]
532    fn negative_indexing() {
533        let matrix = MatPolyOverZ::identity(3, 3);
534
535        assert_eq!(matrix, matrix.get_submatrix(0, -1, 0, -1).unwrap());
536        assert_eq!(matrix, matrix.get_submatrix(-3, -1, -3, -1).unwrap());
537        assert_eq!(
538            matrix.get_row(0).unwrap(),
539            matrix.get_submatrix(0, -3, -3, -1).unwrap()
540        );
541    }
542
543    /// Ensures that the function panics if no columns of the matrix are addressed.
544    #[test]
545    #[should_panic]
546    fn no_columns() {
547        let mat = MatPolyOverZ::identity(10, 10);
548
549        let _ = mat.get_submatrix(0, 0, 6, 5);
550    }
551
552    /// Ensures that the function panics if no rows of the matrix are addressed.
553    #[test]
554    #[should_panic]
555    fn no_rows() {
556        let mat = MatPolyOverZ::identity(10, 10);
557
558        let _ = mat.get_submatrix(5, 4, 0, 0);
559    }
560
561    /// Ensure that the submatrix function can be called with several types.
562    #[test]
563    fn availability() {
564        let mat = MatPolyOverZ::identity(10, 10);
565
566        let _ = mat.get_submatrix(0_i8, 0_i8, 0_i8, 0_i8);
567        let _ = mat.get_submatrix(0_i16, 0_i16, 0_i16, 0_i16);
568        let _ = mat.get_submatrix(0_i32, 0_i32, 0_i32, 0_i32);
569        let _ = mat.get_submatrix(0_i64, 0_i64, 0_i64, 0_i64);
570        let _ = mat.get_submatrix(0_u8, 0_u8, 0_u8, 0_u8);
571        let _ = mat.get_submatrix(0_u16, 0_i16, 0_u16, 0_u16);
572        let _ = mat.get_submatrix(0_u32, 0_i32, 0_u32, 0_u32);
573        let _ = mat.get_submatrix(0_u64, 0_i64, 0_u64, 0_u64);
574        let _ = mat.get_submatrix(&Z::ZERO, &Z::ZERO, &Z::ZERO, &Z::ZERO);
575    }
576}
577
578#[cfg(test)]
579mod test_collect_entries {
580    use super::MatPolyOverZ;
581    use std::str::FromStr;
582
583    /// Ensures that all entries from the matrices are actually collected in the vector.
584    #[test]
585    fn all_entries_collected() {
586        let mat_1 = MatPolyOverZ::from_str(&format!(
587            "[[1  1, 0],[1  {}, 1  {}],[1  -3, 0]]",
588            i64::MAX,
589            i64::MIN
590        ))
591        .unwrap();
592        let mat_2 = MatPolyOverZ::from_str("[[1  -1, 2  1 2]]").unwrap();
593
594        let entries_1 = mat_1.collect_entries();
595        let entries_2 = mat_2.collect_entries();
596
597        assert_eq!(entries_1.len(), 6);
598        assert_eq!(unsafe { *entries_1[0].coeffs }, 1);
599        assert!(unsafe { *entries_1[2].coeffs } >= 2_i64.pow(62));
600        assert!(unsafe { *entries_1[3].coeffs } >= 2_i64.pow(62));
601        assert_eq!(unsafe { *entries_1[4].coeffs }, -3);
602
603        assert_eq!(entries_2.len(), 2);
604        assert_eq!(unsafe { *entries_2[0].coeffs.offset(0) }, -1);
605        assert_eq!(entries_2[0].length, 1);
606        assert_eq!(unsafe { *entries_2[1].coeffs.offset(0) }, 1);
607        assert_eq!(unsafe { *entries_2[1].coeffs.offset(1) }, 2);
608        assert_eq!(entries_2[1].length, 2);
609    }
610}