qfall_math/integer_mod_q/mat_zq/
trace.rs1use flint3_sys::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(
41 &mut out.value.value,
42 &self.matrix,
43 self.modulus.get_fmpz_mod_ctx_struct(),
44 );
45 }
46 Ok(out)
47 }
48}
49
50#[cfg(test)]
51mod test_trace {
52 use crate::integer_mod_q::{MatZq, Zq};
53 use std::str::FromStr;
54
55 #[test]
57 fn trace_works() {
58 let mat_1 = MatZq::from_str("[[5, 2, 0],[2, 8, 0],[0, 0, 4]] mod 10").unwrap();
59 let mat_2 = MatZq::from_str("[[-1, 0],[0, 1]] mod 2").unwrap();
60
61 let trace_1 = mat_1.trace().unwrap();
62 let trace_2 = mat_2.trace().unwrap();
63
64 assert_eq!(Zq::from((7, 10)), trace_1);
65 assert_eq!(Zq::from((0, 2)), trace_2);
66 }
67
68 #[test]
70 fn trace_large_values() {
71 let mat_1 = MatZq::from_str(&format!(
72 "[[{}, 5],[1, {}]] mod {}",
73 i64::MAX,
74 i64::MAX,
75 u64::MAX
76 ))
77 .unwrap();
78 let mat_2 = MatZq::from_str(&format!("[[{}]] mod {}", i64::MIN, u64::MAX)).unwrap();
79 let mat_3 = MatZq::from_str(&format!(
80 "[[{}, 5],[1, {}]] mod {}",
81 i64::MIN,
82 i64::MAX,
83 u64::MAX
84 ))
85 .unwrap();
86
87 let trace_1 = mat_1.trace().unwrap();
88 let trace_2 = mat_2.trace().unwrap();
89 let trace_3 = mat_3.trace().unwrap();
90
91 assert_eq!(Zq::from((2 * i64::MAX as u64, u64::MAX)), trace_1);
92 assert_eq!(Zq::from((i64::MIN, u64::MAX)), trace_2);
93 assert_eq!(Zq::from((-1, u64::MAX)), trace_3);
94 }
95
96 #[test]
98 fn trace_error_not_squared() {
99 let mat_1 = MatZq::from_str("[[1, 0, 1],[0, 1, 1]] mod 42").unwrap();
100 let mat_2 = MatZq::from_str("[[1, 0],[0, 1],[1, 0]] mod 17").unwrap();
101
102 assert!(mat_1.trace().is_err());
103 assert!(mat_2.trace().is_err());
104 }
105}