qfall_math/integer/mat_z/arithmetic/
div.rs1use super::super::MatZ;
12use crate::integer::Z;
13use crate::macros::arithmetics::{
14 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
15};
16use crate::rational::MatQ;
17use crate::traits::MatrixDimensions;
18use flint_sys::fmpq_mat::fmpq_mat_set_fmpz_mat_div_fmpz;
19use flint_sys::fmpz_mat::fmpz_mat_scalar_divexact_fmpz;
20use std::ops::Div;
21
22impl MatZ {
23 pub unsafe fn div_exact(mut self, divisor: impl Into<Z>) -> MatZ {
50 let divisor: Z = divisor.into();
51 assert!(!divisor.is_zero(), "Tried to divide {self} by zero.");
52
53 unsafe { fmpz_mat_scalar_divexact_fmpz(&mut self.matrix, &self.matrix, &divisor.value) };
54
55 self
56 }
57
58 pub unsafe fn div_exact_ref(&self, divisor: impl Into<Z>) -> MatZ {
85 let divisor: Z = divisor.into();
86 assert!(!divisor.is_zero(), "Tried to divide {self} by zero.");
87
88 let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
89 unsafe { fmpz_mat_scalar_divexact_fmpz(&mut out.matrix, &self.matrix, &divisor.value) };
90
91 out
92 }
93}
94
95impl Div<&Z> for &MatZ {
96 type Output = MatQ;
97 fn div(self, divisor: &Z) -> Self::Output {
121 assert!(!divisor.is_zero(), "Tried to divide {self} by zero.");
122 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
123 unsafe {
124 fmpq_mat_set_fmpz_mat_div_fmpz(&mut out.matrix, &self.matrix, &divisor.value);
125 }
126 out
127 }
128}
129
130arithmetic_trait_borrowed_to_owned!(Div, div, MatZ, Z, MatQ);
131arithmetic_trait_mixed_borrowed_owned!(Div, div, MatZ, Z, MatQ);
132
133#[cfg(test)]
134mod test_div_exact {
135 use super::*;
136 use crate::integer_mod_q::Modulus;
137 use std::str::FromStr;
138
139 #[test]
141 #[allow(clippy::needless_borrows_for_generic_args)]
142 fn availability() {
143 let mat = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
144
145 let _ = unsafe { mat.div_exact_ref(3i64) };
146 let _ = unsafe { mat.div_exact_ref(3i32) };
147 let _ = unsafe { mat.div_exact_ref(3i16) };
148 let _ = unsafe { mat.div_exact_ref(3i8) };
149 let _ = unsafe { mat.div_exact_ref(3u64) };
150 let _ = unsafe { mat.div_exact_ref(3u32) };
151 let _ = unsafe { mat.div_exact_ref(3u16) };
152 let _ = unsafe { mat.div_exact_ref(3u8) };
153 let _ = unsafe { mat.div_exact_ref(Z::from(3)) };
154 let _ = unsafe { mat.div_exact_ref(Modulus::from(3)) };
155 let _ = unsafe { mat.div_exact_ref(&Z::from(3)) };
156 let _ = unsafe { mat.div_exact_ref(&Modulus::from(3)) };
157
158 let _ = unsafe { mat.clone().div_exact(3i64) };
159 let _ = unsafe { mat.clone().div_exact(3i32) };
160 let _ = unsafe { mat.clone().div_exact(3i16) };
161 let _ = unsafe { mat.clone().div_exact(3i8) };
162 let _ = unsafe { mat.clone().div_exact(3u64) };
163 let _ = unsafe { mat.clone().div_exact(3u32) };
164 let _ = unsafe { mat.clone().div_exact(3u16) };
165 let _ = unsafe { mat.clone().div_exact(3u8) };
166 let _ = unsafe { mat.clone().div_exact(Z::from(3)) };
167 let _ = unsafe { mat.clone().div_exact(Modulus::from(3)) };
168 let _ = unsafe { mat.clone().div_exact(&Z::from(3)) };
169 let _ = unsafe { mat.div_exact(&Modulus::from(3)) };
170 }
171
172 #[test]
174 fn division_correctness() {
175 let mat = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
176
177 let mat_divided_1 = unsafe { mat.div_exact_ref(3) };
178 let mat_divided_2 = unsafe { mat.div_exact(3) };
179
180 let mat_cmp = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
181 assert_eq!(mat_cmp, mat_divided_1);
182 assert_eq!(mat_cmp, mat_divided_2);
183 }
184
185 #[test]
187 fn negative_correctness() {
188 let mat = MatZ::from_str("[[6, -3],[3, -6]]").unwrap();
189
190 let mat_divided_1 = unsafe { mat.div_exact_ref(3) };
191 let mat_divided_2 = unsafe { mat.div_exact_ref(-3) };
192
193 let mat_cmp_1 = MatZ::from_str("[[2, -1],[1, -2]]").unwrap();
194 let mat_cmp_2 = MatZ::from_str("[[-2, 1],[-1, 2]]").unwrap();
195 assert_eq!(mat_cmp_1, mat_divided_1);
196 assert_eq!(mat_cmp_2, mat_divided_2);
197 }
198
199 #[test]
201 fn different_dimensions_correctness() {
202 let mat_1 = MatZ::from_str("[[-3],[0],[12]]").unwrap();
203 let mat_2 = MatZ::from_str("[[6, 15, 18],[3, -9, 3]]").unwrap();
204
205 let mat_cmp_1 = MatZ::from_str("[[-1],[0],[4]]").unwrap();
206 let mat_cmp_2 = MatZ::from_str("[[2, 5, 6],[1, -3, 1]]").unwrap();
207 assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact_ref(3) });
208 assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact_ref(3) });
209 assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact(3) });
210 assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact(3) });
211 }
212
213 #[test]
215 fn large_entries() {
216 let mat_1 =
217 MatZ::from_str(&format!("[[6],[{}],[{}]]", i64::MAX / 3, i64::MIN / 3)).unwrap();
218 let mat_2 = MatZ::from_str(&format!("[[{}]]", i64::MAX)).unwrap();
219 let mat_3 = MatZ::from_str(&format!("[[{}]]", i64::MIN)).unwrap();
220
221 let mat_cmp_1 =
222 MatZ::from_str(&format!("[[3],[{}],[{}]]", (i64::MAX / 6), (i64::MIN / 6))).unwrap();
223 let mat_cmp_2 = MatZ::from_str("[[1]]").unwrap();
224 assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact_ref(2) });
225 assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact_ref(i64::MAX) });
226 assert_eq!(mat_cmp_2, unsafe { mat_3.div_exact_ref(i64::MIN) });
227 assert_eq!(mat_cmp_1, unsafe { mat_1.div_exact(2) });
228 assert_eq!(mat_cmp_2, unsafe { mat_2.div_exact(i64::MAX) });
229 assert_eq!(mat_cmp_2, unsafe { mat_3.div_exact(i64::MIN) });
230 }
231
232 #[test]
234 #[should_panic]
235 fn div_by_0_error() {
236 let mat = MatZ::from_str("[[6, 2],[3, 10]]").unwrap();
237
238 let _mat = unsafe { mat.div_exact(0) };
239 }
240
241 #[test]
243 #[should_panic]
244 fn div_by_0_error_ref() {
245 let mat = MatZ::from_str("[[6, 2],[3, 10]]").unwrap();
246
247 let _mat = unsafe { mat.div_exact_ref(0) };
248 }
249}
250
251#[cfg(test)]
252mod test_div {
253 use super::*;
254 use std::str::FromStr;
255
256 #[test]
258 fn availability() {
259 let mat = MatZ::from_str("[[6, 5],[2, 6]]").unwrap();
260 let divisor = Z::from(3);
261
262 let _ = &mat / &divisor;
263 let _ = mat.clone() / &divisor;
264 let _ = &mat / divisor.clone();
265 let _ = mat / divisor;
266 }
267
268 #[test]
270 fn division_correctness() {
271 let mat = MatZ::from_str("[[6, 5],[2, 6]]").unwrap();
272 let divisor = Z::from(3);
273
274 let mat_q = &mat / &divisor;
275
276 let mat_cmp = MatQ::from_str("[[2, 5/3],[2/3, 2]]").unwrap();
277 assert_eq!(mat_cmp, mat_q);
278 }
279
280 #[test]
282 fn different_dimensions_correctness() {
283 let mat_1 = MatZ::from_str("[[4],[0],[12]]").unwrap();
284 let mat_2 = MatZ::from_str("[[6, 15, 18],[3, 10, 3]]").unwrap();
285 let divisor = Z::from(3);
286
287 let mat_cmp_1 = MatQ::from_str("[[4/3],[0],[4]]").unwrap();
288 let mat_cmp_2 = MatQ::from_str("[[2, 5, 6],[1, 10/3, 1]]").unwrap();
289 assert_eq!(mat_cmp_1, mat_1 / &divisor);
290 assert_eq!(mat_cmp_2, mat_2 / divisor);
291 }
292
293 #[test]
295 fn large_entries() {
296 let mat_1 =
297 MatZ::from_str(&format!("[[6],[{}],[{}]]", i64::MAX / 3, i64::MIN / 3)).unwrap();
298 let mat_2 = MatZ::from_str(&format!("[[{}]]", i64::MAX)).unwrap();
299 let mat_3 = MatZ::from_str(&format!("[[{}]]", i64::MIN)).unwrap();
300 let divisor_1 = Z::from(2);
301 let divisor_2 = Z::from(i64::MAX);
302 let divisor_3 = Z::from(i64::MIN);
303
304 let mat_cmp_1 =
305 MatQ::from_str(&format!("[[3],[{}],[{}]]", (i64::MAX / 6), (i64::MIN / 6))).unwrap();
306 let mat_cmp_2 = MatQ::from_str("[[1]]").unwrap();
307 assert_eq!(mat_cmp_1, mat_1 / divisor_1);
308 assert_eq!(mat_cmp_2, mat_2 / divisor_2);
309 assert_eq!(mat_cmp_2, mat_3 / divisor_3);
310 }
311
312 #[test]
314 #[should_panic]
315 fn div_by_0_error() {
316 let mat = MatZ::from_str("[[6, 2],[3, 10]]").unwrap();
317 let divisor = Z::ZERO;
318
319 let _mat = mat / divisor;
320 }
321
322 #[test]
324 fn doctest_correct() {
325 let mat = MatZ::from_str("[[3, 5],[9, 22]]").unwrap();
326 let divisor = Z::from(3);
327
328 let mat_q = &mat / &divisor;
329
330 assert_eq!("[[1, 5/3],[3, 22/3]]", mat_q.to_string());
331 }
332}