diff --git a/src/integer/mat_poly_over_z/arithmetic.rs b/src/integer/mat_poly_over_z/arithmetic.rs
index 0767e3a7..22c4bed3 100644
--- a/src/integer/mat_poly_over_z/arithmetic.rs
+++ b/src/integer/mat_poly_over_z/arithmetic.rs
@@ -13,4 +13,5 @@ mod add;
mod modulo;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer/mat_poly_over_z/arithmetic/neg.rs b/src/integer/mat_poly_over_z/arithmetic/neg.rs
new file mode 100644
index 00000000..eeaac073
--- /dev/null
+++ b/src/integer/mat_poly_over_z/arithmetic/neg.rs
@@ -0,0 +1,90 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`MatPolyOverZ`] values.
+
+use super::super::MatPolyOverZ;
+use crate::traits::MatrixDimensions;
+use flint3_sys::fmpz_poly_mat_neg;
+use std::ops::Neg;
+
+impl Neg for MatPolyOverZ {
+ type Output = MatPolyOverZ;
+
+ /// Implements the [`Neg`] trait for [`MatPolyOverZ`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`MatPolyOverZ`].
+ ///
+ /// When called on owned [`MatPolyOverZ`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`MatPolyOverZ`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer::MatPolyOverZ;
+ /// use std::str::FromStr;
+ ///
+ /// let a: MatPolyOverZ = MatPolyOverZ::from_str("[[2 1 -2, 0],[1 42, 3 1 2 3]]").unwrap();
+ ///
+ /// let b: MatPolyOverZ = -&a;
+ /// let c: MatPolyOverZ = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpz_poly_mat_neg(&mut self.matrix, &self.matrix) };
+ self
+ }
+}
+
+impl Neg for &MatPolyOverZ {
+ type Output = MatPolyOverZ;
+
+ /// Documentation at [`MatPolyOverZ::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
+ unsafe { fmpz_poly_mat_neg(&mut out.matrix, &self.matrix) };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::MatPolyOverZ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small coefficients.
+ #[test]
+ fn correct_small() {
+ let a = MatPolyOverZ::from_str("[[2 1 -2, 0, 1 5],[1 -3, 3 1 0 4, 0]]").unwrap();
+ let b = MatPolyOverZ::from_str("[[2 -1 2, 0, 1 -5],[1 3, 3 -1 0 -4, 0]]").unwrap();
+ let c = MatPolyOverZ::new(2, 3);
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large coefficients.
+ #[test]
+ fn correct_large() {
+ let a =
+ MatPolyOverZ::from_str(&format!("[[2 {} {}],[1 1]]", u64::MAX, i64::MIN)).unwrap();
+ let b = MatPolyOverZ::from_str(&format!(
+ "[[2 -{} {}],[1 -1]]",
+ u64::MAX,
+ i64::MAX as u64 + 1
+ ))
+ .unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+}
diff --git a/src/integer/mat_z/arithmetic.rs b/src/integer/mat_z/arithmetic.rs
index aaeff03d..a23bd67b 100644
--- a/src/integer/mat_z/arithmetic.rs
+++ b/src/integer/mat_z/arithmetic.rs
@@ -14,4 +14,5 @@ mod div;
mod modulo;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer/mat_z/arithmetic/neg.rs b/src/integer/mat_z/arithmetic/neg.rs
new file mode 100644
index 00000000..5d0926a1
--- /dev/null
+++ b/src/integer/mat_z/arithmetic/neg.rs
@@ -0,0 +1,89 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`MatZ`] values.
+
+use super::super::MatZ;
+use crate::traits::MatrixDimensions;
+use flint3_sys::fmpz_mat_neg;
+use std::ops::Neg;
+
+impl Neg for MatZ {
+ type Output = MatZ;
+
+ /// Implements the [`Neg`] trait for [`MatZ`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`MatZ`].
+ ///
+ /// When called on owned [`MatZ`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`MatZ`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer::MatZ;
+ /// use std::str::FromStr;
+ ///
+ /// let a: MatZ = MatZ::from_str("[[1, -2],[3, 42]]").unwrap();
+ ///
+ /// let b: MatZ = -&a;
+ /// let c: MatZ = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpz_mat_neg(&mut self.matrix, &self.matrix) };
+ self
+ }
+}
+
+impl Neg for &MatZ {
+ type Output = MatZ;
+
+ /// Documentation at [`MatZ::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
+ unsafe { fmpz_mat_neg(&mut out.matrix, &self.matrix) };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::MatZ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small entries.
+ #[test]
+ fn correct_small() {
+ let a = MatZ::from_str("[[1, -2, 0],[3, 4, -5]]").unwrap();
+ let b = MatZ::from_str("[[-1, 2, 0],[-3, -4, 5]]").unwrap();
+ let c = MatZ::new(2, 3);
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large entries.
+ #[test]
+ fn correct_large() {
+ let a = MatZ::from_str(&format!("[[{}, {}],[1, 2]]", u64::MAX, i64::MIN)).unwrap();
+ let b = MatZ::from_str(&format!(
+ "[[-{}, {}],[-1, -2]]",
+ u64::MAX,
+ i64::MAX as u64 + 1
+ ))
+ .unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+}
diff --git a/src/integer/poly_over_z/arithmetic.rs b/src/integer/poly_over_z/arithmetic.rs
index 0767e3a7..22c4bed3 100644
--- a/src/integer/poly_over_z/arithmetic.rs
+++ b/src/integer/poly_over_z/arithmetic.rs
@@ -13,4 +13,5 @@ mod add;
mod modulo;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer/poly_over_z/arithmetic/neg.rs b/src/integer/poly_over_z/arithmetic/neg.rs
new file mode 100644
index 00000000..f118aa54
--- /dev/null
+++ b/src/integer/poly_over_z/arithmetic/neg.rs
@@ -0,0 +1,84 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`PolyOverZ`] values.
+
+use super::super::PolyOverZ;
+use flint3_sys::fmpz_poly_neg;
+use std::ops::Neg;
+
+impl Neg for PolyOverZ {
+ type Output = PolyOverZ;
+
+ /// Implements the [`Neg`] trait for [`PolyOverZ`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`PolyOverZ`].
+ ///
+ /// When called on owned [`PolyOverZ`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`PolyOverZ`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer::PolyOverZ;
+ /// use std::str::FromStr;
+ ///
+ /// let a: PolyOverZ = PolyOverZ::from_str("3 1 -2 42").unwrap();
+ ///
+ /// let b: PolyOverZ = -&a;
+ /// let c: PolyOverZ = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpz_poly_neg(&mut self.poly, &self.poly) };
+ self
+ }
+}
+
+impl Neg for &PolyOverZ {
+ type Output = PolyOverZ;
+
+ /// Documentation at [`PolyOverZ::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = PolyOverZ::default();
+ unsafe { fmpz_poly_neg(&mut out.poly, &self.poly) };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::PolyOverZ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small coefficients.
+ #[test]
+ fn correct_small() {
+ let a = PolyOverZ::from_str("4 1 -2 0 3").unwrap();
+ let b = PolyOverZ::from_str("4 -1 2 0 -3").unwrap();
+ let c = PolyOverZ::default();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large coefficients.
+ #[test]
+ fn correct_large() {
+ let a = PolyOverZ::from_str(&format!("3 {} 0 {}", u64::MAX, i64::MIN)).unwrap();
+ let b =
+ PolyOverZ::from_str(&format!("3 -{} 0 {}", u64::MAX, i64::MAX as u64 + 1)).unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+}
diff --git a/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic.rs b/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic.rs
index f829920a..128e3620 100644
--- a/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic.rs
+++ b/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic.rs
@@ -12,4 +12,5 @@
mod add;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/neg.rs b/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/neg.rs
new file mode 100644
index 00000000..4d5a31bf
--- /dev/null
+++ b/src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/neg.rs
@@ -0,0 +1,115 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`MatPolynomialRingZq`] values.
+
+use super::super::MatPolynomialRingZq;
+use flint3_sys::fmpz_poly_mat_neg;
+use std::ops::Neg;
+
+impl Neg for MatPolynomialRingZq {
+ type Output = MatPolynomialRingZq;
+
+ /// Implements the [`Neg`] trait for [`MatPolynomialRingZq`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`MatPolynomialRingZq`].
+ ///
+ /// When called on owned [`MatPolynomialRingZq`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`MatPolynomialRingZq`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
+ /// use qfall_math::integer::MatPolyOverZ;
+ /// use std::str::FromStr;
+ ///
+ /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
+ /// let poly_mat = MatPolyOverZ::from_str("[[2 1 2, 0],[1 42, 3 1 2 3]]").unwrap();
+ /// let a: MatPolynomialRingZq = MatPolynomialRingZq::from((&poly_mat, &modulus));
+ ///
+ /// let b: MatPolynomialRingZq = -&a;
+ /// let c: MatPolynomialRingZq = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpz_poly_mat_neg(&mut self.matrix.matrix, &self.matrix.matrix) };
+ self.reduce();
+ self
+ }
+}
+
+impl Neg for &MatPolynomialRingZq {
+ type Output = MatPolynomialRingZq;
+
+ /// Documentation at [`MatPolynomialRingZq::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = MatPolynomialRingZq {
+ matrix: -&self.matrix,
+ modulus: self.modulus.clone(),
+ };
+ out.reduce();
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::MatPolynomialRingZq;
+ use crate::integer::MatPolyOverZ;
+ use crate::integer_mod_q::ModulusPolynomialRingZq;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small coefficients.
+ #[test]
+ fn correct_small() {
+ let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
+ let mat_a = MatPolyOverZ::from_str("[[2 1 -2, 0],[1 -3, 3 1 0 4]]").unwrap();
+ let mat_b = MatPolyOverZ::from_str("[[2 -1 2, 0],[1 3, 3 -1 0 -4]]").unwrap();
+ let a = MatPolynomialRingZq::from((&mat_a, &modulus));
+ let b = MatPolynomialRingZq::from((&mat_b, &modulus));
+ let c = MatPolynomialRingZq::new(2, 2, &modulus);
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large coefficients and moduli.
+ #[test]
+ fn correct_large() {
+ let modulus =
+ ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
+ let mat_a = MatPolyOverZ::from_str(&format!("[[2 {} 1],[0]]", i64::MAX)).unwrap();
+ let mat_b = MatPolyOverZ::from_str(&format!("[[2 -{} -1],[0]]", i64::MAX)).unwrap();
+ let a = MatPolynomialRingZq::from((&mat_a, &modulus));
+ let b = MatPolynomialRingZq::from((&mat_b, &modulus));
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+
+ /// Ensure that the result is reduced to the least non-negative residues
+ /// and that the modulus is kept.
+ #[test]
+ fn reduced() {
+ let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
+ let mat_a = MatPolyOverZ::from_str("[[2 1 16, 0],[1 8, 3 1 0 4]]").unwrap();
+ let a = MatPolynomialRingZq::from((&mat_a, &modulus));
+ let cmp = MatPolyOverZ::from_str("[[2 16 1, 0],[1 9, 3 16 0 13]]").unwrap();
+
+ let neg_a = -&a;
+
+ assert_eq!(cmp, neg_a.get_representative_least_nonnegative_residue());
+ assert_eq!(cmp, (-a).get_representative_least_nonnegative_residue());
+ assert_eq!(modulus, neg_a.get_mod());
+ }
+}
diff --git a/src/integer_mod_q/mat_zq/arithmetic.rs b/src/integer_mod_q/mat_zq/arithmetic.rs
index 95249458..5ad590df 100644
--- a/src/integer_mod_q/mat_zq/arithmetic.rs
+++ b/src/integer_mod_q/mat_zq/arithmetic.rs
@@ -12,4 +12,5 @@
mod add;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer_mod_q/mat_zq/arithmetic/neg.rs b/src/integer_mod_q/mat_zq/arithmetic/neg.rs
new file mode 100644
index 00000000..c3943961
--- /dev/null
+++ b/src/integer_mod_q/mat_zq/arithmetic/neg.rs
@@ -0,0 +1,112 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`MatZq`] values.
+
+use super::super::MatZq;
+use crate::traits::MatrixDimensions;
+use flint3_sys::fmpz_mod_mat_neg;
+use std::ops::Neg;
+
+impl Neg for MatZq {
+ type Output = MatZq;
+
+ /// Implements the [`Neg`] trait for [`MatZq`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`MatZq`].
+ ///
+ /// When called on owned [`MatZq`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`MatZq`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer_mod_q::MatZq;
+ /// use std::str::FromStr;
+ ///
+ /// let a: MatZq = MatZq::from_str("[[1, 2],[3, 42]] mod 17").unwrap();
+ ///
+ /// let b: MatZq = -&a;
+ /// let c: MatZq = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe {
+ fmpz_mod_mat_neg(
+ &mut self.matrix,
+ &self.matrix,
+ self.modulus.get_fmpz_mod_ctx_struct(),
+ )
+ };
+ self
+ }
+}
+
+impl Neg for &MatZq {
+ type Output = MatZq;
+
+ /// Documentation at [`MatZq::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
+ unsafe {
+ fmpz_mod_mat_neg(
+ &mut out.matrix,
+ &self.matrix,
+ self.modulus.get_fmpz_mod_ctx_struct(),
+ )
+ };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::MatZq;
+ use crate::integer::MatZ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small entries.
+ #[test]
+ fn correct_small() {
+ let a = MatZq::from_str("[[1, -2, 0],[3, 4, -5]] mod 17").unwrap();
+ let b = MatZq::from_str("[[-1, 2, 0],[-3, -4, 5]] mod 17").unwrap();
+ let c = MatZq::new(2, 3, 17);
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large entries and moduli.
+ #[test]
+ fn correct_large() {
+ let a = MatZq::from_str(&format!("[[{}, 1],[0, 2]] mod {}", i64::MAX, u64::MAX)).unwrap();
+ let b =
+ MatZq::from_str(&format!("[[-{}, -1],[0, -2]] mod {}", i64::MAX, u64::MAX)).unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+
+ /// Ensure that the result is reduced to the least non-negative residues
+ /// and that the modulus is kept.
+ #[test]
+ fn reduced() {
+ let a = MatZq::from_str("[[1, 16, 0],[3, 8, 9]] mod 17").unwrap();
+ let cmp = MatZ::from_str("[[16, 1, 0],[14, 9, 8]]").unwrap();
+
+ let neg_a = -&a;
+
+ assert_eq!(cmp, neg_a.get_representative_least_nonnegative_residue());
+ assert_eq!(cmp, (-a).get_representative_least_nonnegative_residue());
+ assert_eq!(17, neg_a.get_mod());
+ }
+}
diff --git a/src/integer_mod_q/poly_over_zq/arithmetic.rs b/src/integer_mod_q/poly_over_zq/arithmetic.rs
index 95249458..5ad590df 100644
--- a/src/integer_mod_q/poly_over_zq/arithmetic.rs
+++ b/src/integer_mod_q/poly_over_zq/arithmetic.rs
@@ -12,4 +12,5 @@
mod add;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer_mod_q/poly_over_zq/arithmetic/neg.rs b/src/integer_mod_q/poly_over_zq/arithmetic/neg.rs
new file mode 100644
index 00000000..568a8a7a
--- /dev/null
+++ b/src/integer_mod_q/poly_over_zq/arithmetic/neg.rs
@@ -0,0 +1,110 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`PolyOverZq`] values.
+
+use super::super::PolyOverZq;
+use flint3_sys::fmpz_mod_poly_neg;
+use std::ops::Neg;
+
+impl Neg for PolyOverZq {
+ type Output = PolyOverZq;
+
+ /// Implements the [`Neg`] trait for [`PolyOverZq`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`PolyOverZq`].
+ ///
+ /// When called on owned [`PolyOverZq`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`PolyOverZq`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer_mod_q::PolyOverZq;
+ /// use std::str::FromStr;
+ ///
+ /// let a: PolyOverZq = PolyOverZq::from_str("3 1 2 42 mod 17").unwrap();
+ ///
+ /// let b: PolyOverZq = -&a;
+ /// let c: PolyOverZq = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe {
+ fmpz_mod_poly_neg(
+ &mut self.poly,
+ &self.poly,
+ self.modulus.get_fmpz_mod_ctx_struct(),
+ )
+ };
+ self
+ }
+}
+
+impl Neg for &PolyOverZq {
+ type Output = PolyOverZq;
+
+ /// Documentation at [`PolyOverZq::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = PolyOverZq::from(&self.modulus);
+ unsafe {
+ fmpz_mod_poly_neg(
+ &mut out.poly,
+ &self.poly,
+ self.modulus.get_fmpz_mod_ctx_struct(),
+ )
+ };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::PolyOverZq;
+ use crate::integer::PolyOverZ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small coefficients.
+ #[test]
+ fn correct_small() {
+ let a = PolyOverZq::from_str("4 1 -2 0 3 mod 17").unwrap();
+ let b = PolyOverZq::from_str("4 -1 2 0 -3 mod 17").unwrap();
+ let c = PolyOverZq::from_str("0 mod 17").unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large coefficients and moduli.
+ #[test]
+ fn correct_large() {
+ let a = PolyOverZq::from_str(&format!("3 {} 0 1 mod {}", i64::MAX, u64::MAX)).unwrap();
+ let b = PolyOverZq::from_str(&format!("3 -{} 0 -1 mod {}", i64::MAX, u64::MAX)).unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+
+ /// Ensure that the result is reduced to the least non-negative residues
+ /// and that the modulus is kept.
+ #[test]
+ fn reduced() {
+ let a = PolyOverZq::from_str("4 1 16 0 8 mod 17").unwrap();
+ let cmp = PolyOverZ::from_str("4 16 1 0 9").unwrap();
+
+ let neg_a = -&a;
+
+ assert_eq!(cmp, neg_a.get_representative_least_nonnegative_residue());
+ assert_eq!(cmp, (-a).get_representative_least_nonnegative_residue());
+ assert_eq!(17, neg_a.get_mod());
+ }
+}
diff --git a/src/integer_mod_q/polynomial_ring_zq/arithmetic.rs b/src/integer_mod_q/polynomial_ring_zq/arithmetic.rs
index 95249458..5ad590df 100644
--- a/src/integer_mod_q/polynomial_ring_zq/arithmetic.rs
+++ b/src/integer_mod_q/polynomial_ring_zq/arithmetic.rs
@@ -12,4 +12,5 @@
mod add;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/integer_mod_q/polynomial_ring_zq/arithmetic/neg.rs b/src/integer_mod_q/polynomial_ring_zq/arithmetic/neg.rs
new file mode 100644
index 00000000..2a76df64
--- /dev/null
+++ b/src/integer_mod_q/polynomial_ring_zq/arithmetic/neg.rs
@@ -0,0 +1,116 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`PolynomialRingZq`] values.
+
+use super::super::PolynomialRingZq;
+use flint3_sys::fmpz_poly_neg;
+use std::ops::Neg;
+
+impl Neg for PolynomialRingZq {
+ type Output = PolynomialRingZq;
+
+ /// Implements the [`Neg`] trait for [`PolynomialRingZq`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`PolynomialRingZq`].
+ ///
+ /// When called on owned [`PolynomialRingZq`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`PolynomialRingZq`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq};
+ /// use qfall_math::integer::PolyOverZ;
+ /// use std::str::FromStr;
+ ///
+ /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
+ /// let poly = PolyOverZ::from_str("3 1 2 42").unwrap();
+ /// let a: PolynomialRingZq = PolynomialRingZq::from((&poly, &modulus));
+ ///
+ /// let b: PolynomialRingZq = -&a;
+ /// let c: PolynomialRingZq = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpz_poly_neg(&mut self.poly.poly, &self.poly.poly) };
+ self.reduce();
+ self
+ }
+}
+
+impl Neg for &PolynomialRingZq {
+ type Output = PolynomialRingZq;
+
+ /// Documentation at [`PolynomialRingZq::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = PolynomialRingZq {
+ poly: -&self.poly,
+ modulus: self.modulus.clone(),
+ };
+ out.reduce();
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::PolynomialRingZq;
+ use crate::integer::PolyOverZ;
+ use crate::integer_mod_q::ModulusPolynomialRingZq;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small coefficients.
+ #[test]
+ fn correct_small() {
+ let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
+ let a = PolynomialRingZq::from((&PolyOverZ::from_str("3 1 -2 3").unwrap(), &modulus));
+ let b = PolynomialRingZq::from((&PolyOverZ::from_str("3 -1 2 -3").unwrap(), &modulus));
+ let c = PolynomialRingZq::from((&PolyOverZ::default(), &modulus));
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large coefficients and moduli.
+ #[test]
+ fn correct_large() {
+ let modulus =
+ ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
+ let a = PolynomialRingZq::from((
+ &PolyOverZ::from_str(&format!("3 {} 0 1", i64::MAX)).unwrap(),
+ &modulus,
+ ));
+ let b = PolynomialRingZq::from((
+ &PolyOverZ::from_str(&format!("3 -{} 0 -1", i64::MAX)).unwrap(),
+ &modulus,
+ ));
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+
+ /// Ensure that the result is reduced to the least non-negative residues
+ /// and that the modulus is kept.
+ #[test]
+ fn reduced() {
+ let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
+ let a = PolynomialRingZq::from((&PolyOverZ::from_str("3 1 16 8").unwrap(), &modulus));
+ let cmp = PolyOverZ::from_str("3 16 1 9").unwrap();
+
+ let neg_a = -&a;
+
+ assert_eq!(cmp, neg_a.get_representative_least_nonnegative_residue());
+ assert_eq!(cmp, (-a).get_representative_least_nonnegative_residue());
+ assert_eq!(modulus, neg_a.get_mod());
+ }
+}
diff --git a/src/integer_mod_q/z_q/arithmetic.rs b/src/integer_mod_q/z_q/arithmetic.rs
index e8bbe62e..90357f6a 100644
--- a/src/integer_mod_q/z_q/arithmetic.rs
+++ b/src/integer_mod_q/z_q/arithmetic.rs
@@ -11,5 +11,6 @@
mod add;
mod mul;
+mod neg;
mod pow;
mod sub;
diff --git a/src/integer_mod_q/z_q/arithmetic/neg.rs b/src/integer_mod_q/z_q/arithmetic/neg.rs
new file mode 100644
index 00000000..29b06a29
--- /dev/null
+++ b/src/integer_mod_q/z_q/arithmetic/neg.rs
@@ -0,0 +1,123 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`Zq`] values.
+
+use super::super::Zq;
+use crate::integer::Z;
+use flint3_sys::fmpz_mod_neg;
+use std::ops::Neg;
+
+impl Neg for Zq {
+ type Output = Zq;
+
+ /// Implements the [`Neg`] trait for [`Zq`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`Zq`].
+ ///
+ /// When called on owned [`Zq`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`Zq`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::integer_mod_q::Zq;
+ ///
+ /// let a: Zq = Zq::from((42, 17));
+ ///
+ /// let b: Zq = -&a;
+ /// let c: Zq = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe {
+ fmpz_mod_neg(
+ &mut self.value.value,
+ &self.value.value,
+ self.modulus.get_fmpz_mod_ctx_struct(),
+ )
+ };
+ self
+ }
+}
+
+impl Neg for &Zq {
+ type Output = Zq;
+
+ /// Documentation at [`Zq::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = Z::ZERO;
+ unsafe {
+ fmpz_mod_neg(
+ &mut out.value,
+ &self.value.value,
+ self.modulus.get_fmpz_mod_ctx_struct(),
+ )
+ };
+ Zq {
+ value: out,
+ modulus: self.modulus.clone(),
+ }
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::Zq;
+ use crate::integer::Z;
+
+ /// Ensure that `neg` works for small values.
+ #[test]
+ fn correct_small() {
+ let a = Zq::from((1, 17));
+ let b = Zq::from((-1, 17));
+ let c = Zq::from((0, 17));
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large values and moduli.
+ #[test]
+ fn correct_large() {
+ let a = Zq::from((i64::MAX, u64::MAX));
+ let b = Zq::from((u64::MAX - i64::MAX as u64, u64::MAX));
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+
+ /// Ensure that the result is reduced to the least non-negative residue
+ /// and that the modulus is kept.
+ #[test]
+ fn reduced() {
+ let a = Zq::from((3, 17));
+ let c = Zq::from((0, 17));
+
+ let neg_a = -&a;
+ let neg_c = -c;
+
+ assert_eq!(
+ Z::from(14),
+ neg_a.get_representative_least_nonnegative_residue()
+ );
+ assert_eq!(
+ Z::from(14),
+ (-a).get_representative_least_nonnegative_residue()
+ );
+ assert_eq!(
+ Z::ZERO,
+ neg_c.get_representative_least_nonnegative_residue()
+ );
+ assert_eq!(Z::from(17), neg_a.get_mod());
+ }
+}
diff --git a/src/rational/mat_q/arithmetic.rs b/src/rational/mat_q/arithmetic.rs
index 6b8278f9..2636f54c 100644
--- a/src/rational/mat_q/arithmetic.rs
+++ b/src/rational/mat_q/arithmetic.rs
@@ -13,4 +13,5 @@ mod add;
mod div_scalar;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/rational/mat_q/arithmetic/neg.rs b/src/rational/mat_q/arithmetic/neg.rs
new file mode 100644
index 00000000..6450306e
--- /dev/null
+++ b/src/rational/mat_q/arithmetic/neg.rs
@@ -0,0 +1,84 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`MatQ`] values.
+
+use super::super::MatQ;
+use crate::traits::MatrixDimensions;
+use flint3_sys::fmpq_mat_neg;
+use std::ops::Neg;
+
+impl Neg for MatQ {
+ type Output = MatQ;
+
+ /// Implements the [`Neg`] trait for [`MatQ`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`MatQ`].
+ ///
+ /// When called on owned [`MatQ`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`MatQ`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::rational::MatQ;
+ /// use std::str::FromStr;
+ ///
+ /// let a: MatQ = MatQ::from_str("[[1/2, -2],[3, 1/42]]").unwrap();
+ ///
+ /// let b: MatQ = -&a;
+ /// let c: MatQ = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpq_mat_neg(&mut self.matrix, &self.matrix) };
+ self
+ }
+}
+
+impl Neg for &MatQ {
+ type Output = MatQ;
+
+ /// Documentation at [`MatQ::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
+ unsafe { fmpq_mat_neg(&mut out.matrix, &self.matrix) };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::MatQ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small entries.
+ #[test]
+ fn correct_small() {
+ let a = MatQ::from_str("[[1/2, -2, 0],[3, 4/7, -5]]").unwrap();
+ let b = MatQ::from_str("[[-1/2, 2, 0],[-3, -4/7, 5]]").unwrap();
+ let c = MatQ::new(2, 3);
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large entries.
+ #[test]
+ fn correct_large() {
+ let a = MatQ::from_str(&format!("[[{}, 1/{}],[1, 2]]", u64::MAX, i64::MAX)).unwrap();
+ let b = MatQ::from_str(&format!("[[-{}, -1/{}],[-1, -2]]", u64::MAX, i64::MAX)).unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+}
diff --git a/src/rational/poly_over_q/arithmetic.rs b/src/rational/poly_over_q/arithmetic.rs
index 0cf420f6..fa5957b2 100644
--- a/src/rational/poly_over_q/arithmetic.rs
+++ b/src/rational/poly_over_q/arithmetic.rs
@@ -14,4 +14,5 @@ mod div_scalar;
mod exp;
mod mul;
mod mul_scalar;
+mod neg;
mod sub;
diff --git a/src/rational/poly_over_q/arithmetic/neg.rs b/src/rational/poly_over_q/arithmetic/neg.rs
new file mode 100644
index 00000000..8ec4f7aa
--- /dev/null
+++ b/src/rational/poly_over_q/arithmetic/neg.rs
@@ -0,0 +1,83 @@
+// Copyright 2026 Jan Niklas Siemer
+//
+// This file is part of qFALL-math
+//
+// qFALL-math is free software: you can redistribute it and/or modify it under
+// the terms of the Mozilla Public License Version 2.0 as published by the
+// Mozilla Foundation. See .
+
+//! Implementation of the [`Neg`] trait for [`PolyOverQ`] values.
+
+use super::super::PolyOverQ;
+use flint3_sys::fmpq_poly_neg;
+use std::ops::Neg;
+
+impl Neg for PolyOverQ {
+ type Output = PolyOverQ;
+
+ /// Implements the [`Neg`] trait for [`PolyOverQ`] values.
+ /// [`Neg`] is implemented for both borrowed and owned [`PolyOverQ`].
+ ///
+ /// When called on owned [`PolyOverQ`] it will reuse the memory of `self`.
+ ///
+ /// Returns the additive inverse of `self` as a [`PolyOverQ`].
+ ///
+ /// # Examples
+ /// ```
+ /// use qfall_math::rational::PolyOverQ;
+ /// use std::str::FromStr;
+ ///
+ /// let a: PolyOverQ = PolyOverQ::from_str("3 1/2 -2 42").unwrap();
+ ///
+ /// let b: PolyOverQ = -&a;
+ /// let c: PolyOverQ = -a;
+ /// ```
+ fn neg(mut self) -> Self::Output {
+ unsafe { fmpq_poly_neg(&mut self.poly, &self.poly) };
+ self
+ }
+}
+
+impl Neg for &PolyOverQ {
+ type Output = PolyOverQ;
+
+ /// Documentation at [`PolyOverQ::neg`].
+ fn neg(self) -> Self::Output {
+ let mut out = PolyOverQ::default();
+ unsafe { fmpq_poly_neg(&mut out.poly, &self.poly) };
+ out
+ }
+}
+
+#[cfg(test)]
+mod test_neg {
+ use super::PolyOverQ;
+ use std::str::FromStr;
+
+ /// Ensure that `neg` works for small coefficients.
+ #[test]
+ fn correct_small() {
+ let a = PolyOverQ::from_str("4 1/2 -2 0 3/7").unwrap();
+ let b = PolyOverQ::from_str("4 -1/2 2 0 -3/7").unwrap();
+ let c = PolyOverQ::default();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(a, -&b);
+ assert_eq!(b, -&a);
+ assert_eq!(a, -b.clone());
+ assert_eq!(b, -a);
+ assert_eq!(c, -&c);
+ assert_eq!(c.clone(), -c);
+ }
+
+ /// Ensure that `neg` works for large coefficients.
+ #[test]
+ fn correct_large() {
+ let a = PolyOverQ::from_str(&format!("3 {} 0 1/{}", u64::MAX, i64::MAX)).unwrap();
+ let b = PolyOverQ::from_str(&format!("3 -{} 0 -1/{}", u64::MAX, i64::MAX)).unwrap();
+
+ assert_eq!(a, -(-&a));
+ assert_eq!(b, -&a);
+ assert_eq!(b, -a);
+ }
+}