Skip to main content

qfall_math/integer_mod_q/mat_polynomial_ring_zq/
set.rs

1// Copyright © 2023 Marcel Luca Schmidt
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//! Implementation to set elements of a [`MatPolynomialRingZq`] matrix.
10
11use super::MatPolynomialRingZq;
12use crate::integer_mod_q::PolynomialRingZq;
13use crate::macros::for_others::implement_for_owned;
14use crate::traits::{MatrixSetSubmatrix, MatrixSwaps};
15use crate::{error::MathError, integer::PolyOverZ, traits::MatrixSetEntry};
16use flint_sys::fmpz_poly_mat::{
17    fmpz_poly_mat_set, fmpz_poly_mat_window_clear, fmpz_poly_mat_window_init,
18};
19use flint_sys::{fmpz_poly::fmpz_poly_set, fmpz_poly_mat::fmpz_poly_mat_entry};
20use std::fmt::Display;
21use std::mem::MaybeUninit;
22
23impl MatrixSetEntry<&PolyOverZ> for MatPolynomialRingZq {
24    /// Sets the value of a specific matrix entry according to a given `value` of type [`PolyOverZ`].
25    ///
26    /// Parameters:
27    /// - `row`: specifies the row in which the entry is located
28    /// - `column`: specifies the column in which the entry is located
29    /// - `value`: specifies the value to which the entry is set
30    ///
31    /// Negative indices can be used to index from the back, e.g., `-1` for
32    /// the last element.
33    ///
34    /// Returns an empty `Ok` if the action could be performed successfully.
35    /// Otherwise, a [`MathError`] is returned if the specified entry is
36    /// not part of the matrix.
37    ///
38    /// # Examples
39    /// ```
40    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
41    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
42    /// use crate::qfall_math::traits::*;
43    /// use std::str::FromStr;
44    ///
45    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
46    /// let poly_mat = MatPolyOverZ::from_str("[[0, 1  42],[0, 2  1 2]]").unwrap();
47    /// let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
48    /// let value = PolyOverZ::default();
49    ///
50    /// poly_ring_mat.set_entry(0, 1, &value).unwrap();
51    /// poly_ring_mat.set_entry(-1, -1, &value).unwrap();
52    ///
53    /// let mat_cmp = MatPolynomialRingZq::from((&MatPolyOverZ::new(2, 2), &modulus));
54    /// assert_eq!(poly_ring_mat, mat_cmp);
55    /// ```
56    ///
57    /// # Errors and Failures
58    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
59    ///   if `row` or `column` are greater than the matrix size.
60    fn set_entry(
61        &mut self,
62        row: impl TryInto<i64> + Display,
63        column: impl TryInto<i64> + Display,
64        value: &PolyOverZ,
65    ) -> Result<(), MathError> {
66        let value = PolynomialRingZq::from((value, self.get_mod()));
67
68        self.set_entry(row, column, value)
69    }
70
71    /// Sets the value of a specific matrix entry according to a given `value` of type [`PolyOverZ`]
72    /// without checking whether the coordinate is part of the matrix, if the moduli match
73    /// or if the entry is reduced.
74    ///
75    /// Parameters:
76    /// - `row`: specifies the row in which the entry is located
77    /// - `column`: specifies the column in which the entry is located
78    /// - `value`: specifies the value to which the entry is set
79    ///
80    /// # Safety
81    /// To use this function safely, make sure that the selected entry is part
82    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
83    /// occur.
84    ///
85    /// # Examples
86    /// ```
87    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
88    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
89    /// use crate::qfall_math::traits::*;
90    /// use std::str::FromStr;
91    ///
92    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
93    /// let poly_mat = MatPolyOverZ::from_str("[[0, 1  42],[0, 2  1 2]]").unwrap();
94    /// let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
95    /// let value = PolyOverZ::default();
96    ///
97    /// unsafe {
98    ///     poly_ring_mat.set_entry_unchecked(0, 1, &value);
99    ///     poly_ring_mat.set_entry_unchecked(1, 1, &value);
100    /// }
101    ///
102    /// let mat_cmp = MatPolynomialRingZq::from((&MatPolyOverZ::new(2, 2), &modulus));
103    /// assert_eq!(poly_ring_mat, mat_cmp);
104    /// ```
105    unsafe fn set_entry_unchecked(&mut self, row: i64, column: i64, value: &PolyOverZ) {
106        unsafe {
107            let entry = fmpz_poly_mat_entry(&self.matrix.matrix, row, column);
108            fmpz_poly_set(entry, &value.poly)
109        };
110    }
111}
112
113impl MatrixSetEntry<&PolynomialRingZq> for MatPolynomialRingZq {
114    /// Sets the value of a specific matrix entry according to a given `value` of type [`PolynomialRingZq`]
115    /// without checking whether the coordinate is part of the matrix or if the moduli match.
116    ///
117    /// Parameters:
118    /// - `row`: specifies the row in which the entry is located
119    /// - `column`: specifies the column in which the entry is located
120    /// - `value`: specifies the value to which the entry is set
121    ///
122    /// # Safety
123    /// To use this function safely, make sure that the selected entry is part
124    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
125    /// occur.
126    ///
127    /// # Examples
128    /// ```
129    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq, PolynomialRingZq};
130    /// use qfall_math::integer::{MatPolyOverZ, PolyOverZ};
131    /// use crate::qfall_math::traits::*;
132    /// use std::str::FromStr;
133    ///
134    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
135    /// let poly_mat = MatPolyOverZ::from_str("[[0, 1  42],[0, 2  1 2]]").unwrap();
136    /// let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
137    /// let value = PolynomialRingZq::from((&PolyOverZ::default(), &modulus));
138    ///
139    /// unsafe {
140    ///     poly_ring_mat.set_entry_unchecked(0, 1, &value);
141    ///     poly_ring_mat.set_entry_unchecked(1, 1, &value);
142    /// }
143    ///
144    /// let mat_cmp = MatPolynomialRingZq::from((&MatPolyOverZ::new(2, 2), &modulus));
145    /// assert_eq!(poly_ring_mat, mat_cmp);
146    /// ```
147    unsafe fn set_entry_unchecked(&mut self, row: i64, column: i64, value: &PolynomialRingZq) {
148        unsafe {
149            let entry = fmpz_poly_mat_entry(&self.matrix.matrix, row, column);
150            fmpz_poly_set(entry, &value.poly.poly)
151        };
152    }
153}
154
155implement_for_owned!(PolyOverZ, MatPolynomialRingZq, MatrixSetEntry);
156implement_for_owned!(PolynomialRingZq, MatPolynomialRingZq, MatrixSetEntry);
157
158impl MatrixSetSubmatrix for MatPolynomialRingZq {
159    /// Sets the matrix entries in `self` to entries defined in `other`.
160    /// The entries in `self` starting from `(row_self_start, col_self_start)` up to
161    /// `(row_self_end, col_self_end)`are set to be
162    /// the entries from the submatrix from `other` defined by `(row_other_start, col_other_start)`
163    /// to `(row_other_end, col_other_end)` (exclusively).
164    ///
165    /// Parameters:
166    /// `row_self_start`: the starting row of the matrix in which to set a submatrix
167    /// `col_self_start`: the starting column of the matrix in which to set a submatrix
168    /// `other`: the matrix from where to take the submatrix to set
169    /// `row_other_start`: the starting row of the specified submatrix
170    /// `col_other_start`: the starting column of the specified submatrix
171    /// `row_other_end`: the ending row of the specified submatrix
172    /// `col_other_end`:the ending column of the specified submatrix
173    ///
174    /// # Examples
175    /// ```
176    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
177    /// use qfall_math::integer::MatPolyOverZ;
178    /// use qfall_math::traits::MatrixSetSubmatrix;
179    /// use std::str::FromStr;
180    ///
181    /// let mat = MatPolyOverZ::identity(3, 3);
182    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
183    /// let mut mat = MatPolynomialRingZq::from((&mat, &modulus));
184    ///
185    /// mat.set_submatrix(0, 1, &mat.clone(), 0, 0, 1, 1).unwrap();
186    /// // [[1,1,0],[0,0,1],[0,0,1]]
187    /// let mat_cmp = MatPolyOverZ::from_str("[[1  1, 1  1, 0],[0, 0, 1  1],[0, 0, 1  1]]").unwrap();
188    /// assert_eq!(mat, MatPolynomialRingZq::from((&mat_cmp, &modulus)));
189    ///
190    /// unsafe{ mat.set_submatrix_unchecked(2, 0, 3, 2, &mat.clone(), 0, 0, 1, 2) };
191    /// let mat_cmp = MatPolyOverZ::from_str("[[1  1, 1  1, 0],[0, 0, 1  1],[1  1, 1  1, 1  1]]").unwrap();
192    /// assert_eq!(mat, MatPolynomialRingZq::from((&mat_cmp, &modulus)));
193    /// ```
194    ///
195    /// # Safety
196    /// To use this function safely, make sure that the selected submatrices are part
197    /// of the matrices, the submatrices are of the same dimensions and the base types are the same.
198    /// If not, memory leaks, unexpected panics, etc. might occur.
199    unsafe fn set_submatrix_unchecked(
200        &mut self,
201        row_self_start: i64,
202        col_self_start: i64,
203        row_self_end: i64,
204        col_self_end: i64,
205        other: &Self,
206        row_other_start: i64,
207        col_other_start: i64,
208        row_other_end: i64,
209        col_other_end: i64,
210    ) {
211        {
212            let mut window_self = MaybeUninit::uninit();
213            // The memory for the elements of window is shared with self.
214            unsafe {
215                fmpz_poly_mat_window_init(
216                    window_self.as_mut_ptr(),
217                    &self.matrix.matrix,
218                    row_self_start,
219                    col_self_start,
220                    row_self_end,
221                    col_self_end,
222                )
223            };
224            let mut window_other = MaybeUninit::uninit();
225            // The memory for the elements of window is shared with other.
226            unsafe {
227                fmpz_poly_mat_window_init(
228                    window_other.as_mut_ptr(),
229                    &other.matrix.matrix,
230                    row_other_start,
231                    col_other_start,
232                    row_other_end,
233                    col_other_end,
234                )
235            };
236            unsafe {
237                // TODO: this should not be mutable for the other window
238                fmpz_poly_mat_set(window_self.as_mut_ptr(), window_other.as_mut_ptr());
239
240                // Clears the matrix window and releases any memory that it uses. Note that
241                // the memory to the underlying matrix that window points to is not freed
242                fmpz_poly_mat_window_clear(window_self.as_mut_ptr());
243                fmpz_poly_mat_window_clear(window_other.as_mut_ptr());
244            }
245        }
246    }
247}
248
249impl MatrixSwaps for MatPolynomialRingZq {
250    /// Swaps two entries of the specified matrix.
251    ///
252    /// Parameters:
253    /// - `row_0`: specifies the row, in which the first entry is located
254    /// - `col_0`: specifies the column, in which the first entry is located
255    /// - `row_1`: specifies the row, in which the second entry is located
256    /// - `col_1`: specifies the column, in which the second entry is located
257    ///
258    /// Negative indices can be used to index from the back, e.g., `-1` for
259    /// the last element.
260    ///
261    /// Returns an empty `Ok` if the action could be performed successfully.
262    /// Otherwise, a [`MathError`] is returned if one of the specified entries is not part of the matrix.
263    ///
264    /// # Examples
265    /// ```
266    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
267    /// use qfall_math::traits::MatrixSwaps;
268    /// use std::str::FromStr;
269    ///
270    /// let mut matrix = MatPolynomialRingZq::new(4, 3, ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap());
271    /// matrix.swap_entries(0, 0, 2, 1);
272    /// ```
273    ///
274    /// # Errors and Failures
275    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
276    ///   if row or column are greater than the matrix size.
277    fn swap_entries(
278        &mut self,
279        row_0: impl TryInto<i64> + Display,
280        col_0: impl TryInto<i64> + Display,
281        row_1: impl TryInto<i64> + Display,
282        col_1: impl TryInto<i64> + Display,
283    ) -> Result<(), MathError> {
284        self.matrix.swap_entries(row_0, col_0, row_1, col_1)
285    }
286
287    /// Swaps two columns of the specified matrix.
288    ///
289    /// Parameters:
290    /// - `col_0`: specifies the first column which is swapped with the second one
291    /// - `col_1`: specifies the second column which is swapped with the first one
292    ///
293    /// Negative indices can be used to index from the back, e.g., `-1` for
294    /// the last element.
295    ///
296    /// Returns an empty `Ok` if the action could be performed successfully.
297    /// Otherwise, a [`MathError`] is returned if one of the specified columns is not part of the matrix.
298    ///
299    /// # Examples
300    /// ```
301    /// use qfall_math::traits::MatrixSwaps;
302    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
303    /// use std::str::FromStr;
304    ///
305    /// let mut matrix = MatPolynomialRingZq::new(4, 3, ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap());
306    /// matrix.swap_columns(0, 2);
307    /// ```
308    ///
309    /// # Errors and Failures
310    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
311    ///   if one of the given columns is not in the matrix.
312    fn swap_columns(
313        &mut self,
314        col_0: impl TryInto<i64> + Display,
315        col_1: impl TryInto<i64> + Display,
316    ) -> Result<(), MathError> {
317        self.matrix.swap_columns(col_0, col_1)
318    }
319
320    /// Swaps two rows of the specified matrix.
321    ///
322    /// Parameters:
323    /// - `row_0`: specifies the first row which is swapped with the second one
324    /// - `row_1`: specifies the second row which is swapped with the first one
325    ///
326    /// Negative indices can be used to index from the back, e.g., `-1` for
327    /// the last element.
328    ///
329    /// Returns an empty `Ok` if the action could be performed successfully.
330    /// Otherwise, a [`MathError`] is returned if one of the specified rows is not part of the matrix.
331    ///
332    /// # Examples
333    /// ```
334    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
335    /// use qfall_math::traits::MatrixSwaps;
336    /// use std::str::FromStr;
337    ///
338    /// let mut matrix = MatPolynomialRingZq::new(4, 3, ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap());
339    /// matrix.swap_rows(0, 2);
340    /// ```
341    ///
342    /// # Errors and Failures
343    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
344    ///   if one of the given rows is not in the matrix.
345    fn swap_rows(
346        &mut self,
347        row_0: impl TryInto<i64> + Display,
348        row_1: impl TryInto<i64> + Display,
349    ) -> Result<(), MathError> {
350        self.matrix.swap_rows(row_0, row_1)
351    }
352}
353
354impl MatPolynomialRingZq {
355    /// Swaps the `i`-th column with the `n-i`-th column for all `i <= n/2`
356    /// of the specified matrix with `n` columns.
357    ///
358    /// # Examples
359    /// ```
360    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
361    /// use std::str::FromStr;
362    ///
363    /// let mut matrix = MatPolynomialRingZq::new(4, 3, ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap());
364    /// matrix.reverse_columns();
365    /// ```
366    pub fn reverse_columns(&mut self) {
367        self.matrix.reverse_columns()
368    }
369
370    /// Swaps the `i`-th row with the `n-i`-th row for all `i <= n/2`
371    /// of the specified matrix with `n` rows.
372    ///
373    /// # Examples
374    /// ```
375    /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
376    /// use std::str::FromStr;
377    ///
378    /// let mut matrix = MatPolynomialRingZq::new(4, 3, ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap());
379    /// matrix.reverse_rows();
380    /// ```
381    pub fn reverse_rows(&mut self) {
382        self.matrix.reverse_rows()
383    }
384}
385
386#[cfg(test)]
387mod test_setter {
388    use crate::{
389        integer::{MatPolyOverZ, PolyOverZ},
390        integer_mod_q::{
391            MatPolynomialRingZq, ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq,
392        },
393        traits::{MatrixGetEntry, MatrixSetEntry, MatrixSetSubmatrix},
394    };
395    use std::str::FromStr;
396
397    const LARGE_PRIME: u64 = u64::MAX - 58;
398
399    /// Ensure that setting entries works with standard numbers.
400    #[test]
401    fn standard_value() {
402        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
403        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
404        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
405        let value = PolyOverZ::default();
406
407        poly_ring_mat.set_entry(1, 1, value).unwrap();
408
409        let entry_z: PolyOverZ = poly_ring_mat.get_entry(1, 1).unwrap();
410        let entry_zq: PolynomialRingZq = poly_ring_mat.get_entry(1, 1).unwrap();
411
412        assert_eq!("0", entry_z.to_string());
413        assert_eq!("0", entry_zq.poly.to_string());
414        assert_eq!("4  1 0 0 1 mod 17", entry_zq.modulus.to_string());
415    }
416
417    /// Ensure that when using a [`PolyOverZ`] the set entry is actually reduced by the
418    /// modulus.
419    #[test]
420    fn set_entry_reduced() {
421        let id_mat = MatPolyOverZ::identity(2, 2);
422        let modulus = PolyOverZq::from_str("5  1 0 0 0 1 mod 17").unwrap();
423        let poly_mod = ModulusPolynomialRingZq::from(modulus);
424
425        let mut poly_mat = MatPolynomialRingZq::from((id_mat, &poly_mod));
426
427        poly_mat
428            .set_entry(0, 0, PolyOverZ::from_str("5  -1 0 0 0 16").unwrap())
429            .unwrap();
430
431        let entry: PolyOverZ = poly_mat.get_entry(0, 0).unwrap();
432        assert!(entry.is_zero());
433    }
434
435    /// Ensure that setting entries works with large numbers.
436    #[test]
437    fn large_positive() {
438        let modulus =
439            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {LARGE_PRIME}")).unwrap();
440        let poly_mat =
441            MatPolyOverZ::from_str(&format!("[[2  1 1, 1  42],[0, 2  {} 2]]", i64::MAX)).unwrap();
442        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
443        let value = PolyOverZ::from_str(&format!("3  1 {} 1", i64::MAX)).unwrap();
444
445        poly_ring_mat.set_entry(0, 0, value).unwrap();
446
447        let entry_z: PolyOverZ = poly_ring_mat.get_entry(0, 0).unwrap();
448        let entry_zq: PolynomialRingZq = poly_ring_mat.get_entry(0, 0).unwrap();
449
450        assert_eq!(format!("3  1 {} 1", i64::MAX), entry_z.to_string());
451        assert_eq!(format!("3  1 {} 1", i64::MAX), entry_zq.poly.to_string());
452        assert_eq!(
453            format!("4  1 0 0 1 mod {LARGE_PRIME}"),
454            entry_zq.modulus.to_string()
455        );
456    }
457
458    /// Ensure that setting entries works with referenced large numbers.
459    #[test]
460    fn large_positive_ref() {
461        let modulus =
462            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {LARGE_PRIME}")).unwrap();
463        let poly_mat = MatPolyOverZ::from_str(&format!(
464            "[[2  1 1, 1  42, 0],[0, 2  {} 2, 1  1]]",
465            i64::MAX
466        ))
467        .unwrap();
468        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
469        let value = PolyOverZ::from_str(&format!("3  1 {} 1", i64::MAX)).unwrap();
470
471        poly_ring_mat.set_entry(0, 0, &value).unwrap();
472
473        let entry_z: PolyOverZ = poly_ring_mat.get_entry(0, 0).unwrap();
474        let entry_zq: PolynomialRingZq = poly_ring_mat.get_entry(0, 0).unwrap();
475
476        assert_eq!(format!("3  1 {} 1", i64::MAX), entry_z.to_string());
477        assert_eq!(format!("3  1 {} 1", i64::MAX), entry_zq.poly.to_string());
478        assert_eq!(
479            format!("4  1 0 0 1 mod {LARGE_PRIME}"),
480            entry_zq.modulus.to_string()
481        );
482    }
483
484    /// Ensure that setting entries works with large negative numbers.
485    #[test]
486    fn large_negative() {
487        let modulus =
488            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {LARGE_PRIME}")).unwrap();
489        let poly_mat = MatPolyOverZ::from_str(&format!(
490            "[[2  1 1, 1  42],[0, 2  {} 2],[1  2, 0]]",
491            i64::MAX
492        ))
493        .unwrap();
494        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
495        let value = PolyOverZ::from_str(&format!("3  1 {} 1", i64::MIN)).unwrap();
496
497        poly_ring_mat.set_entry(0, 1, value).unwrap();
498
499        let entry_z: PolyOverZ = poly_ring_mat.get_entry(0, 1).unwrap();
500        let entry_zq: PolynomialRingZq = poly_ring_mat.get_entry(0, 1).unwrap();
501
502        assert_eq!(
503            format!("3  1 {} 1", LARGE_PRIME - i64::MIN as u64),
504            entry_z.to_string()
505        );
506        assert_eq!(
507            format!("3  1 {} 1", LARGE_PRIME - i64::MIN as u64),
508            entry_zq.poly.to_string()
509        );
510        assert_eq!(
511            format!("4  1 0 0 1 mod {LARGE_PRIME}"),
512            entry_zq.modulus.to_string()
513        );
514    }
515
516    /// Ensure that a wrong number of rows yields an Error.
517    #[test]
518    fn error_wrong_row() {
519        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
520        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
521        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
522        let value = PolyOverZ::default();
523
524        assert!(poly_ring_mat.set_entry(2, 0, &value).is_err());
525        assert!(poly_ring_mat.set_entry(-3, 0, value).is_err());
526    }
527
528    /// Ensure that a wrong number of columns yields an Error.
529    #[test]
530    fn error_wrong_column() {
531        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
532        let poly_mat =
533            MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42, 0],[0, 2  1 2, 1  17]]").unwrap();
534        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus));
535        let value = PolyOverZ::default();
536
537        assert!(poly_ring_mat.set_entry(0, 3, &value).is_err());
538        assert!(poly_ring_mat.set_entry(0, -4, value).is_err());
539    }
540
541    /// Ensure that differing moduli result in an error.
542    #[test]
543    fn modulus_error() {
544        let modulus_1 = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
545        let modulus_2 = ModulusPolynomialRingZq::from_str("4  1 0 2 1 mod 17").unwrap();
546        let poly_mat = MatPolyOverZ::from_str("[[4  -1 0 1 1, 1  42],[0, 2  1 2]]").unwrap();
547        let mut poly_ring_mat = MatPolynomialRingZq::from((&poly_mat, &modulus_1));
548        let value = PolynomialRingZq::from((&PolyOverZ::default(), &modulus_2));
549
550        assert!(poly_ring_mat.set_entry(1, 1, value).is_err());
551    }
552
553    /// Ensures that setting columns works fine for small entries.
554    #[test]
555    fn column_small_entries() {
556        let mut mat_1 =
557            MatPolynomialRingZq::from_str("[[0, 1  2, 0],[0, 1  5, 1  6]] / 2  1 1 mod 6").unwrap();
558        let mat_2 = MatPolynomialRingZq::from_str("[[0],[1  -1]] / 2  1 1 mod 6").unwrap();
559        let cmp =
560            MatPolynomialRingZq::from_str("[[0, 0, 0],[0, 1  -1, 1  6]] / 2  1 1 mod 6").unwrap();
561
562        mat_1.set_column(1, &mat_2, 0).unwrap();
563
564        assert_eq!(cmp, mat_1);
565    }
566
567    /// Ensures that setting columns works fine for large entries.
568    #[test]
569    fn column_large_entries() {
570        let mut mat_1 = MatPolynomialRingZq::from_str(&format!(
571            "[[1  {}, 1  1, 1  3, 1  4],[1  {}, 1  4, 1  {}, 1  5],[1  7, 1  6, 2  8 9, 0]] / 2  1 1 mod {}",
572            i64::MIN,
573            i64::MAX,
574            u64::MAX-1,
575            u64::MAX
576        ))
577        .unwrap();
578        let mat_2 = MatPolynomialRingZq::from_str(&format!(
579            "[[1  1, 1  {}],[1  {}, 0],[1  7, 1  -1]] / 2  1 1 mod {}",
580            i64::MIN,
581            i64::MAX,
582            u64::MAX
583        ))
584        .unwrap();
585        let cmp = MatPolynomialRingZq::from_str(&format!(
586            "[[1  {}, 1  1, 1  3, 1  4],[0, 1  4, 1  {}, 1  5],[1  -1, 1  6, 2  8 9, 0]] / 2  1 1 mod {}",
587            i64::MIN,
588            u64::MAX-1,
589            u64::MAX
590        ))
591        .unwrap();
592
593        mat_1.set_column(0, &mat_2, 1).unwrap();
594
595        assert_eq!(cmp, mat_1);
596    }
597
598    /// Ensures that setting the column to itself does not change anything.
599    #[test]
600    fn column_swap_same_entry() {
601        let mut mat_1 = MatPolynomialRingZq::from_str(&format!(
602            "[[1  {}, 1  1, 1  3, 1  4],[1  {}, 1  4, 1  {}, 1  5],[1  7, 1  6, 2  8 9, 0]] / 2  1 1 mod {}",
603            i64::MIN,
604            i64::MAX,
605            u64::MAX-1,
606            u64::MAX
607        ))
608        .unwrap();
609        let cmp = mat_1.clone();
610
611        mat_1.set_column(0, &cmp, 0).unwrap();
612        mat_1.set_column(1, &cmp, 1).unwrap();
613
614        assert_eq!(cmp, mat_1);
615    }
616
617    /// Ensures that `set_column` returns an error if one of the specified columns is out of bounds.
618    #[test]
619    fn column_out_of_bounds() {
620        let mut mat_1 =
621            MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 6")
622                .unwrap();
623        let mat_2 = mat_1.clone();
624
625        assert!(mat_1.set_column(-3, &mat_2, 0).is_err());
626        assert!(mat_1.set_column(2, &mat_2, 0).is_err());
627        assert!(mat_1.set_column(1, &mat_2, -3).is_err());
628        assert!(mat_1.set_column(1, &mat_2, 2).is_err());
629    }
630
631    /// Ensures that mismatching row dimensions result in an error.
632    #[test]
633    fn column_mismatching_columns() {
634        let mut mat_1 =
635            MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 6")
636                .unwrap();
637        let mat_2 = MatPolynomialRingZq::from_str("[[0, 0],[0, 0]] / 2  1 1 mod 6").unwrap();
638
639        assert!(mat_1.set_column(0, &mat_2, 0).is_err());
640        assert!(mat_1.set_column(1, &mat_2, 1).is_err());
641    }
642
643    /// Ensures that mismatching moduli result in an error.
644    #[test]
645    fn column_mismatching_moduli() {
646        let mut mat_1 =
647            MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 6").unwrap();
648        let mat_2 = MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 7").unwrap();
649
650        assert!(mat_1.set_column(0, &mat_2, 0).is_err());
651        assert!(mat_1.set_column(1, &mat_2, 1).is_err());
652    }
653
654    /// Ensures that setting rows works fine for small entries.
655    #[test]
656    fn row_small_entries() {
657        let mut mat_1 =
658            MatPolynomialRingZq::from_str("[[0, 1  2, 0],[0, 2  5 6, 0]] / 2  1 1 mod 6").unwrap();
659        let mat_2 = MatPolynomialRingZq::from_str("[[0, 1  -1, 1  2]] / 2  1 1 mod 6").unwrap();
660        let cmp = MatPolynomialRingZq::from_str("[[0, 1  2, 0],[0, 1  -1, 1  2]] / 2  1 1 mod 6")
661            .unwrap();
662
663        let _ = mat_1.set_row(1, &mat_2, 0);
664
665        assert_eq!(cmp, mat_1);
666    }
667
668    /// Ensures that setting rows works fine for large entries.
669    #[test]
670    fn row_large_entries() {
671        let mut mat_1 = MatPolynomialRingZq::from_str(&format!(
672            "[[1  {}, 1  1, 1  3, 1  4],[1  {}, 1  4, 1  {}, 1  5],[1  7, 1  6, 2  8 9, 0]] / 2  1 1 mod {}",
673            i64::MIN,
674            i64::MAX,
675            u64::MAX-1,
676            u64::MAX
677        ))
678        .unwrap();
679        let mat_2 = MatPolynomialRingZq::from_str(&format!(
680            "[[0, 0, 0, 0],[1  {}, 0, 1  {}, 0]] / 2  1 1 mod {}",
681            i64::MIN,
682            i64::MAX,
683            u64::MAX
684        ))
685        .unwrap();
686        let cmp = MatPolynomialRingZq::from_str(&format!(
687            "[[1  {}, 0, 1  {}, 0],[1  {}, 1  4, 1  {}, 1  5],[1  7, 1  6, 2  8 9, 0]] / 2  1 1 mod {}",
688            i64::MIN,
689            i64::MAX,
690            i64::MAX,
691            u64::MAX-1,
692            u64::MAX
693        ))
694        .unwrap();
695
696        let _ = mat_1.set_row(0, &mat_2, 1);
697
698        assert_eq!(cmp, mat_1);
699    }
700
701    /// Ensures that setting the rows to itself does not change anything.
702    #[test]
703    fn row_swap_same_entry() {
704        let mut mat_1 = MatPolynomialRingZq::from_str(&format!(
705            "[[1  {}, 1  1, 1  3, 1  4],[1  {}, 1  4, 1  {}, 1  5],[1  7, 1  6, 2  8 9, 0]] / 2  1 1 mod {}",
706            i64::MIN,
707            i64::MAX,
708            u64::MAX-1,
709            u64::MAX
710        ))
711        .unwrap();
712        let cmp = mat_1.clone();
713
714        let _ = mat_1.set_row(0, &cmp, 0);
715        let _ = mat_1.set_row(1, &cmp, 1);
716
717        assert_eq!(cmp, mat_1);
718    }
719
720    /// Ensures that `set_row` returns an error if one of the specified rows is out of bounds.
721    #[test]
722    fn row_out_of_bounds() {
723        let mut mat_1 =
724            MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 6")
725                .unwrap();
726        let mat_2 = mat_1.clone();
727
728        assert!(mat_1.set_row(-6, &mat_2, 0).is_err());
729        assert!(mat_1.set_row(5, &mat_2, 0).is_err());
730        assert!(mat_1.set_row(2, &mat_2, -6).is_err());
731        assert!(mat_1.set_row(2, &mat_2, 5).is_err());
732    }
733
734    /// Ensures that mismatching column dimensions result in an error.
735    #[test]
736    fn row_mismatching_columns() {
737        let mut mat_1 =
738            MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 6").unwrap();
739        let mat_2 = MatPolynomialRingZq::from_str("[[0, 0, 0],[0, 0, 0],[0, 0, 0]] / 2  1 1 mod 6")
740            .unwrap();
741
742        assert!(mat_1.set_row(0, &mat_2, 0).is_err());
743        assert!(mat_1.set_row(1, &mat_2, 1).is_err());
744    }
745
746    /// Ensures that mismatching moduli result in an error.
747    #[test]
748    fn row_mismatching_moduli() {
749        let mut mat_1 =
750            MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 6").unwrap();
751        let mat_2 = MatPolynomialRingZq::from_str("[[0, 0],[0, 0],[0, 0]] / 2  1 1 mod 7").unwrap();
752
753        assert!(mat_1.set_row(0, &mat_2, 0).is_err());
754        assert!(mat_1.set_row(1, &mat_2, 1).is_err());
755    }
756}
757
758#[cfg(test)]
759mod test_swaps {
760    use super::MatPolynomialRingZq;
761    use crate::{
762        integer_mod_q::ModulusPolynomialRingZq,
763        traits::{MatrixGetSubmatrix, MatrixSwaps},
764    };
765    use std::str::FromStr;
766
767    // Since swapping functions only call the existing tested functions for [`MatPolyOverZ`](crate::integer::MatPolyOverZ),
768    // we omit some tests that are already covered.
769
770    /// Ensures that swapping entries works
771    #[test]
772    fn entries_swapping() {
773        let mut matrix = MatPolynomialRingZq::from_str(
774            "[[1  1, 1  2, 1  3],[1  4, 2  5 6, 0]] / 3  1 2 1 mod 17",
775        )
776        .unwrap();
777        let cmp = MatPolynomialRingZq::from_str(
778            "[[1  1, 2  5 6, 1  3],[1  4, 1  2, 0]] / 3  1 2 1 mod 17",
779        )
780        .unwrap();
781
782        let _ = matrix.swap_entries(1, 1, 0, 1);
783
784        assert_eq!(cmp, matrix);
785    }
786
787    /// Ensures that `swap_entries` returns an error if one of the specified entries is out of bounds
788    #[test]
789    fn entries_out_of_bounds() {
790        let modulus = ModulusPolynomialRingZq::from_str("3  3 0 1 mod 17").unwrap();
791        let mut matrix = MatPolynomialRingZq::new(5, 2, modulus);
792
793        assert!(matrix.swap_entries(-6, 0, 0, 0).is_err());
794        assert!(matrix.swap_entries(0, -3, 0, 0).is_err());
795        assert!(matrix.swap_entries(0, 0, 5, 0).is_err());
796        assert!(matrix.swap_entries(0, 5, 0, 0).is_err());
797    }
798
799    /// Ensure that `swap_entries` can properly handle negative indexing.
800    #[test]
801    fn entries_negative_indexing() {
802        let modulus = ModulusPolynomialRingZq::from_str("3  1 0 1 mod 17").unwrap();
803        let mut matrix = MatPolynomialRingZq::identity(2, 2, modulus);
804
805        matrix.swap_entries(-2, -2, -2, -1).unwrap();
806        assert_eq!(
807            "[[0, 1  1],[0, 1  1]] / 3  1 0 1 mod 17",
808            matrix.to_string()
809        );
810    }
811
812    /// Ensures that swapping columns works fine for small entries
813    #[test]
814    fn columns_swapping() {
815        let mut matrix = MatPolynomialRingZq::from_str(
816            "[[1  1, 1  2, 1  3],[1  4, 1  5, 1  6]] / 3  1 2 1 mod 17",
817        )
818        .unwrap();
819        let cmp_vec_0 = MatPolynomialRingZq::from_str("[[1  1],[1  4]] / 3  1 2 1 mod 17").unwrap();
820        let cmp_vec_1 = MatPolynomialRingZq::from_str("[[1  3],[1  6]] / 3  1 2 1 mod 17").unwrap();
821        let cmp_vec_2 = MatPolynomialRingZq::from_str("[[1  2],[1  5]] / 3  1 2 1 mod 17").unwrap();
822
823        let _ = matrix.swap_columns(1, 2);
824
825        assert_eq!(cmp_vec_0, matrix.get_column(0).unwrap());
826        assert_eq!(cmp_vec_1, matrix.get_column(1).unwrap());
827        assert_eq!(cmp_vec_2, matrix.get_column(2).unwrap());
828    }
829
830    /// Ensures that `swap_columns` returns an error if one of the specified columns is out of bounds
831    #[test]
832    fn column_out_of_bounds() {
833        let modulus = ModulusPolynomialRingZq::from_str("3  3 0 1 mod 17").unwrap();
834        let mut matrix = MatPolynomialRingZq::new(5, 2, modulus);
835
836        assert!(matrix.swap_columns(-6, 0).is_err());
837        assert!(matrix.swap_columns(0, -6).is_err());
838        assert!(matrix.swap_columns(5, 0).is_err());
839        assert!(matrix.swap_columns(0, 5).is_err());
840    }
841
842    /// Ensures that swapping rows works
843    #[test]
844    fn rows_swapping() {
845        let mut matrix =
846            MatPolynomialRingZq::from_str("[[1  1, 1  2],[1  3, 2  4 5]] / 3  1 2 1 mod 17")
847                .unwrap();
848        let cmp_vec_0 =
849            MatPolynomialRingZq::from_str("[[1  3, 2  4 5]] / 3  1 2 1 mod 17").unwrap();
850        let cmp_vec_1 = MatPolynomialRingZq::from_str("[[1  1, 1  2]] / 3  1 2 1 mod 17").unwrap();
851
852        let _ = matrix.swap_rows(1, 0);
853
854        assert_eq!(cmp_vec_0, matrix.get_row(0).unwrap());
855        assert_eq!(cmp_vec_1, matrix.get_row(1).unwrap());
856    }
857
858    /// Ensures that `swap_rows` returns an error if one of the specified rows is out of bounds
859    #[test]
860    fn row_out_of_bounds() {
861        let modulus = ModulusPolynomialRingZq::from_str("3  3 0 1 mod 17").unwrap();
862        let mut matrix = MatPolynomialRingZq::new(2, 4, modulus);
863
864        assert!(matrix.swap_rows(-3, 0).is_err());
865        assert!(matrix.swap_rows(0, -3).is_err());
866        assert!(matrix.swap_rows(4, 0).is_err());
867        assert!(matrix.swap_rows(0, 4).is_err());
868    }
869}
870
871#[cfg(test)]
872mod test_reverses {
873    use super::MatPolynomialRingZq;
874    use crate::traits::MatrixGetSubmatrix;
875    use std::str::FromStr;
876
877    // Since reversing functions only call the existing tested functions for [`MatPolyOverZ`](crate::integer::MatPolyOverZ),
878    // we omit some tests that are already covered.
879
880    /// Ensures that reversing columns works fine for small entries
881    #[test]
882    fn columns_reversing() {
883        let mut matrix = MatPolynomialRingZq::from_str(
884            "[[1  1, 1  2, 2  3 4],[0, 1  5, 1  6]] / 3  1 2 1 mod 17",
885        )
886        .unwrap();
887        let cmp_vec_0 = MatPolynomialRingZq::from_str("[[1  1],[0]] / 3  1 2 1 mod 17").unwrap();
888        let cmp_vec_1 = MatPolynomialRingZq::from_str("[[1  2],[1  5]] / 3  1 2 1 mod 17").unwrap();
889        let cmp_vec_2 =
890            MatPolynomialRingZq::from_str("[[2  3 4],[1  6]] / 3  1 2 1 mod 17").unwrap();
891
892        matrix.reverse_columns();
893
894        assert_eq!(cmp_vec_2, matrix.get_column(0).unwrap());
895        assert_eq!(cmp_vec_1, matrix.get_column(1).unwrap());
896        assert_eq!(cmp_vec_0, matrix.get_column(2).unwrap());
897    }
898
899    /// Ensures that reversing rows works fine for small entries
900    #[test]
901    fn rows_reversing() {
902        let mut matrix =
903            MatPolynomialRingZq::from_str("[[1  1, 1  2],[2  3 4, 0]] / 3  1 2 1 mod 17").unwrap();
904        let cmp_vec_0 = MatPolynomialRingZq::from_str("[[1  1, 1  2]] / 3  1 2 1 mod 17").unwrap();
905        let cmp_vec_1 = MatPolynomialRingZq::from_str("[[2  3 4, 0]] / 3  1 2 1 mod 17").unwrap();
906
907        matrix.reverse_rows();
908
909        assert_eq!(cmp_vec_1, matrix.get_row(0).unwrap());
910        assert_eq!(cmp_vec_0, matrix.get_row(1).unwrap());
911    }
912}
913
914#[cfg(test)]
915mod test_set_submatrix {
916    use crate::{
917        integer::MatPolyOverZ,
918        integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
919        traits::MatrixSetSubmatrix,
920    };
921    use std::str::FromStr;
922
923    /// Ensure that the entire matrix can be set.
924    #[test]
925    fn entire_matrix() {
926        let modulus =
927            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
928        let mut mat = MatPolynomialRingZq::from((
929            &MatPolyOverZ::sample_uniform(10, 10, 5, -100, 100).unwrap(),
930            &modulus,
931        ));
932        let identity = MatPolynomialRingZq::identity(10, 10, &modulus);
933
934        mat.set_submatrix(0, 0, &identity, 0, 0, 9, 9).unwrap();
935
936        assert_eq!(identity, mat);
937    }
938
939    /// Ensure that matrix access out of bounds leadss to an error.
940    #[test]
941    fn out_of_bounds() {
942        let modulus =
943            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
944        let mut mat = MatPolynomialRingZq::identity(10, 10, &modulus);
945
946        assert!(mat.set_submatrix(10, 0, &mat.clone(), 0, 0, 9, 9).is_err());
947        assert!(mat.set_submatrix(0, 10, &mat.clone(), 0, 0, 9, 9).is_err());
948        assert!(mat.set_submatrix(0, 0, &mat.clone(), 10, 0, 9, 9).is_err());
949        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 10, 9, 9).is_err());
950        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, 10, 9).is_err());
951        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, 9, 10).is_err());
952        assert!(mat.set_submatrix(-11, 0, &mat.clone(), 0, 0, 9, 9).is_err());
953        assert!(mat.set_submatrix(0, -11, &mat.clone(), 0, 0, 9, 9).is_err());
954        assert!(mat.set_submatrix(0, 0, &mat.clone(), -11, 0, 9, 9).is_err());
955        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, -11, 9, 9).is_err());
956        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, -11, 9).is_err());
957        assert!(mat.set_submatrix(0, 0, &mat.clone(), 0, 0, 9, -11).is_err());
958    }
959
960    /// Ensure that the function returns an error if the defined submatrix is too large
961    /// and there is not enough space in the original matrix.
962    #[test]
963    fn submatrix_too_large() {
964        let modulus =
965            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
966        let mut mat = MatPolynomialRingZq::identity(10, 10, &modulus);
967
968        assert!(
969            mat.set_submatrix(
970                0,
971                0,
972                &MatPolynomialRingZq::identity(11, 11, &modulus),
973                0,
974                0,
975                10,
976                10
977            )
978            .is_err()
979        );
980        assert!(mat.set_submatrix(1, 2, &mat.clone(), 0, 0, 9, 9).is_err());
981    }
982
983    /// Ensure that setting submatrices with large values works.
984    #[test]
985    fn large_values() {
986        let modulus =
987            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
988        let mut mat = MatPolynomialRingZq::from((
989            &MatPolyOverZ::from_str(&format!(
990                "[[1  1, 2  1 {}],[1  -{}, 0]]",
991                u64::MAX,
992                u64::MAX
993            ))
994            .unwrap(),
995            &modulus,
996        ));
997        let cmp_mat = MatPolynomialRingZq::from((
998            &MatPolyOverZ::from_str(&format!("[[1  -{}, 0],[1  -{}, 0]]", u64::MAX, u64::MAX))
999                .unwrap(),
1000            &modulus,
1001        ));
1002
1003        mat.set_submatrix(0, 0, &mat.clone(), 1, 0, 1, 1).unwrap();
1004        assert_eq!(cmp_mat, mat);
1005    }
1006
1007    /// Ensure that setting with an undefined submatrix.
1008    #[test]
1009    #[should_panic]
1010    fn submatrix_negative() {
1011        let modulus =
1012            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
1013        let mut mat = MatPolynomialRingZq::identity(10, 10, &modulus);
1014
1015        let _ = mat.set_submatrix(0, 0, &mat.clone(), 0, 9, 9, 5);
1016    }
1017
1018    /// Ensure that different moduli cause the set_submatrix to fail.
1019    #[test]
1020    fn different_moduli() {
1021        let modulus1 =
1022            ModulusPolynomialRingZq::from_str(&format!("4  1 0 0 1 mod {}", u64::MAX)).unwrap();
1023        let mut mat1 = MatPolynomialRingZq::identity(10, 10, &modulus1);
1024
1025        let modulus2 =
1026            ModulusPolynomialRingZq::from_str(&format!("4  2 0 0 1 mod {}", u64::MAX - 1)).unwrap();
1027        let mat2 = MatPolynomialRingZq::identity(10, 10, &modulus2);
1028
1029        assert!(mat1.set_submatrix(0, 0, &mat2.clone(), 0, 9, 0, 9).is_err());
1030    }
1031}