Skip to main content

qfall_math/integer_mod_q/mat_zq/arithmetic/
neg.rs

1// Copyright 2026 Jan Niklas Siemer
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 of the [`Neg`] trait for [`MatZq`] values.
10
11use super::super::MatZq;
12use crate::traits::MatrixDimensions;
13use flint3_sys::fmpz_mod_mat_neg;
14use std::ops::Neg;
15
16impl Neg for MatZq {
17    type Output = MatZq;
18
19    /// Implements the [`Neg`] trait for [`MatZq`] values.
20    /// [`Neg`] is implemented for both borrowed and owned [`MatZq`].
21    ///
22    /// When called on owned [`MatZq`] it will reuse the memory of `self`.
23    ///
24    /// Returns the additive inverse of `self` as a [`MatZq`].
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::integer_mod_q::MatZq;
29    /// use std::str::FromStr;
30    ///
31    /// let a: MatZq = MatZq::from_str("[[1, 2],[3, 42]] mod 17").unwrap();
32    ///
33    /// let b: MatZq = -&a;
34    /// let c: MatZq = -a;
35    /// ```
36    fn neg(mut self) -> Self::Output {
37        unsafe {
38            fmpz_mod_mat_neg(
39                &mut self.matrix,
40                &self.matrix,
41                self.modulus.get_fmpz_mod_ctx_struct(),
42            )
43        };
44        self
45    }
46}
47
48impl Neg for &MatZq {
49    type Output = MatZq;
50
51    /// Documentation at [`MatZq::neg`].
52    fn neg(self) -> Self::Output {
53        let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
54        unsafe {
55            fmpz_mod_mat_neg(
56                &mut out.matrix,
57                &self.matrix,
58                self.modulus.get_fmpz_mod_ctx_struct(),
59            )
60        };
61        out
62    }
63}
64
65#[cfg(test)]
66mod test_neg {
67    use super::MatZq;
68    use crate::integer::MatZ;
69    use std::str::FromStr;
70
71    /// Ensure that `neg` works for small entries.
72    #[test]
73    fn correct_small() {
74        let a = MatZq::from_str("[[1, -2, 0],[3, 4, -5]] mod 17").unwrap();
75        let b = MatZq::from_str("[[-1, 2, 0],[-3, -4, 5]] mod 17").unwrap();
76        let c = MatZq::new(2, 3, 17);
77
78        assert_eq!(a, -(-&a));
79        assert_eq!(a, -&b);
80        assert_eq!(b, -&a);
81        assert_eq!(a, -b.clone());
82        assert_eq!(b, -a);
83        assert_eq!(c, -&c);
84        assert_eq!(c.clone(), -c);
85    }
86
87    /// Ensure that `neg` works for large entries and moduli.
88    #[test]
89    fn correct_large() {
90        let a = MatZq::from_str(&format!("[[{}, 1],[0, 2]] mod {}", i64::MAX, u64::MAX)).unwrap();
91        let b =
92            MatZq::from_str(&format!("[[-{}, -1],[0, -2]] mod {}", i64::MAX, u64::MAX)).unwrap();
93
94        assert_eq!(a, -(-&a));
95        assert_eq!(b, -&a);
96        assert_eq!(b, -a);
97    }
98
99    /// Ensure that the result is reduced to the least non-negative residues
100    /// and that the modulus is kept.
101    #[test]
102    fn reduced() {
103        let a = MatZq::from_str("[[1, 16, 0],[3, 8, 9]] mod 17").unwrap();
104        let cmp = MatZ::from_str("[[16, 1, 0],[14, 9, 8]]").unwrap();
105
106        let neg_a = -&a;
107
108        assert_eq!(cmp, neg_a.get_representative_least_nonnegative_residue());
109        assert_eq!(cmp, (-a).get_representative_least_nonnegative_residue());
110        assert_eq!(17, neg_a.get_mod());
111    }
112}