qfall_math/integer/mat_z/
forms.rs1use super::MatZ;
13use crate::traits::MatrixDimensions;
14use flint_sys::fmpz_mat::{
15 fmpz_mat_hnf_transform, fmpz_mat_is_in_hnf, fmpz_mat_is_in_snf, fmpz_mat_snf,
16};
17
18impl MatZ {
19 pub fn hermite_nf(&self) -> (MatZ, MatZ) {
36 let nr_rows = self.get_num_rows();
37 let nr_cols = self.get_num_columns();
38
39 let mut hnf = MatZ::new(nr_rows, nr_cols);
40 let mut transform = MatZ::new(nr_rows, nr_rows);
41
42 unsafe { fmpz_mat_hnf_transform(&mut hnf.matrix, &mut transform.matrix, &self.matrix) };
47
48 (hnf, transform)
49 }
50
51 pub fn is_in_hermite_nf(&self) -> bool {
64 1 == unsafe { fmpz_mat_is_in_hnf(&self.matrix) }
65 }
66
67 pub fn smith_nf(&self) -> Self {
81 let mut snf: MatZ = MatZ::new(self.get_num_rows(), self.get_num_columns());
82
83 unsafe { fmpz_mat_snf(&mut snf.matrix, &self.matrix) };
84
85 snf
86 }
87
88 pub fn is_in_smith_nf(&self) -> bool {
101 1 == unsafe { fmpz_mat_is_in_snf(&self.matrix) }
102 }
103}
104
105#[cfg(test)]
106mod test_hermite_nf {
107 use super::MatZ;
108 use std::str::FromStr;
109
110 #[test]
112 fn small_entries() {
113 let matrix = MatZ::from_str("[[2,3,6,2],[5,6,1,6],[8,3,1,1]]").unwrap();
114 let h_cmp = MatZ::from_str("[[1, 0, 50, -11],[0, 3, 28, -2],[0, 0, 61, -13]]").unwrap();
115 let u_cmp = MatZ::from_str("[[9, -5, 1],[5, -2, 0],[11, -6, 1]]").unwrap();
116
117 let (h, u) = matrix.hermite_nf();
118
119 assert_eq!(h_cmp, h);
120 assert_eq!(u_cmp, u);
121 assert_eq!(h, &u * &matrix);
122
123 assert!(!matrix.is_in_hermite_nf());
124 assert!(h.is_in_hermite_nf());
125 assert!(!u.is_in_hermite_nf());
126 }
127
128 #[test]
130 fn large_entries() {
131 let matrix = MatZ::from_str(&format!(
132 "[[{}, 0],[{}, {}]]",
133 i64::MAX,
134 2 * (i64::MAX as u64),
135 u64::MAX
136 ))
137 .unwrap();
138 let h_cmp = MatZ::from_str(&format!("[[{}, 0],[0, {}]]", i64::MAX, u64::MAX)).unwrap();
139 let u_cmp = MatZ::from_str("[[1, 0],[-2, 1]]").unwrap();
140
141 let (h, u) = matrix.hermite_nf();
142
143 assert_eq!(h_cmp, h);
144 assert_eq!(u_cmp, u);
145 assert_eq!(h, &u * &matrix);
146
147 assert!(!matrix.is_in_hermite_nf());
148 assert!(h.is_in_hermite_nf());
149 assert!(!u.is_in_hermite_nf());
150 }
151
152 #[test]
155 fn dimensions() {
156 let mat_0 = MatZ::sample_uniform(4, 1, 0, 16).unwrap();
157 let mat_1 = MatZ::sample_uniform(5, 5, 0, 16).unwrap();
158 let mat_2 = MatZ::sample_uniform(2, 4, 0, 16).unwrap();
159
160 let (hnf_0, u_0) = mat_0.hermite_nf();
161 let (hnf_1, u_1) = mat_1.hermite_nf();
162 let (hnf_2, u_2) = mat_2.hermite_nf();
163
164 assert!(hnf_0.is_in_hermite_nf());
165 assert!(hnf_1.is_in_hermite_nf());
166 assert!(hnf_2.is_in_hermite_nf());
167
168 assert_eq!(hnf_0, u_0 * mat_0);
169 assert_eq!(hnf_1, u_1 * mat_1);
170 assert_eq!(hnf_2, u_2 * mat_2);
171 }
172}
173
174#[cfg(test)]
175mod test_smith_nf {
176 use super::MatZ;
177 use std::str::FromStr;
178
179 #[test]
181 fn small_entries() {
182 let matrix = MatZ::from_str("[[2,3,6,2],[5,6,1,6],[8,3,1,1]]").unwrap();
183 let s_cmp = MatZ::from_str("[[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0]]").unwrap();
184
185 let s = matrix.smith_nf();
186
187 assert_eq!(s_cmp, s);
188
189 assert!(!matrix.is_in_smith_nf());
190 assert!(s.is_in_smith_nf());
191 }
192
193 #[test]
195 fn large_entries() {
196 let matrix = MatZ::from_str(&format!(
197 "[[{}, 0],[{}, {}]]",
198 i64::MAX,
199 2 * (i64::MAX as u64),
200 u64::MAX
201 ))
202 .unwrap();
203 let s_cmp =
204 MatZ::from_str("[[1, 0],[0, 170141183460469231704017187605319778305]]").unwrap();
205
206 let s = matrix.smith_nf();
207
208 assert_eq!(s_cmp, s);
209
210 assert!(!matrix.is_in_smith_nf());
211 assert!(s.is_in_smith_nf());
212 }
213
214 #[test]
217 fn dimensions() {
218 let mat_0 = MatZ::sample_uniform(4, 1, 0, 16).unwrap();
219 let mat_1 = MatZ::sample_uniform(5, 5, 0, 16).unwrap();
220 let mat_2 = MatZ::sample_uniform(2, 4, 0, 16).unwrap();
221
222 let snf_0 = mat_0.smith_nf();
223 let snf_1 = mat_1.smith_nf();
224 let snf_2 = mat_2.smith_nf();
225
226 assert!(snf_0.is_in_smith_nf());
227 assert!(snf_1.is_in_smith_nf());
228 assert!(snf_2.is_in_smith_nf());
229 }
230}