qfall_math/integer_mod_q/mat_zq/
trace.rs1use flint_sys::fmpz_mod_mat::fmpz_mod_mat_trace;
12
13use super::MatZq;
14use crate::{error::MathError, integer_mod_q::Zq, traits::MatrixDimensions};
15
16impl MatZq {
17 pub fn trace(&self) -> Result<Zq, MathError> {
33 if self.get_num_rows() != self.get_num_columns() {
35 return Err(MathError::NoSquareMatrix(self.to_string()));
36 }
37
38 let mut out = Zq::from((0, self.get_mod()));
39 unsafe {
40 fmpz_mod_mat_trace(&mut out.value.value, &self.matrix);
41 }
42 Ok(out)
43 }
44}
45
46#[cfg(test)]
47mod test_trace {
48 use crate::integer_mod_q::{MatZq, Zq};
49 use std::str::FromStr;
50
51 #[test]
53 fn trace_works() {
54 let mat_1 = MatZq::from_str("[[5, 2, 0],[2, 8, 0],[0, 0, 4]] mod 10").unwrap();
55 let mat_2 = MatZq::from_str("[[-1, 0],[0, 1]] mod 2").unwrap();
56
57 let trace_1 = mat_1.trace().unwrap();
58 let trace_2 = mat_2.trace().unwrap();
59
60 assert_eq!(Zq::from((7, 10)), trace_1);
61 assert_eq!(Zq::from((0, 2)), trace_2);
62 }
63
64 #[test]
66 fn trace_large_values() {
67 let mat_1 = MatZq::from_str(&format!(
68 "[[{}, 5],[1, {}]] mod {}",
69 i64::MAX,
70 i64::MAX,
71 u64::MAX
72 ))
73 .unwrap();
74 let mat_2 = MatZq::from_str(&format!("[[{}]] mod {}", i64::MIN, u64::MAX)).unwrap();
75 let mat_3 = MatZq::from_str(&format!(
76 "[[{}, 5],[1, {}]] mod {}",
77 i64::MIN,
78 i64::MAX,
79 u64::MAX
80 ))
81 .unwrap();
82
83 let trace_1 = mat_1.trace().unwrap();
84 let trace_2 = mat_2.trace().unwrap();
85 let trace_3 = mat_3.trace().unwrap();
86
87 assert_eq!(Zq::from((2 * i64::MAX as u64, u64::MAX)), trace_1);
88 assert_eq!(Zq::from((i64::MIN, u64::MAX)), trace_2);
89 assert_eq!(Zq::from((-1, u64::MAX)), trace_3);
90 }
91
92 #[test]
94 fn trace_error_not_squared() {
95 let mat_1 = MatZq::from_str("[[1, 0, 1],[0, 1, 1]] mod 42").unwrap();
96 let mat_2 = MatZq::from_str("[[1, 0],[0, 1],[1, 0]] mod 17").unwrap();
97
98 assert!(mat_1.trace().is_err());
99 assert!(mat_2.trace().is_err());
100 }
101}