1use crate::{
12 integer::Z,
13 macros::{
14 arithmetics::{
15 arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
16 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
17 },
18 for_others::implement_for_others,
19 },
20 rational::{MatQ, Q},
21 traits::MatrixDimensions,
22};
23use flint_sys::fmpq_mat::fmpq_mat_scalar_div_fmpz;
24use std::ops::{Div, DivAssign, MulAssign};
25
26impl Div<&Z> for &MatQ {
27 type Output = MatQ;
28
29 fn div(self, scalar: &Z) -> Self::Output {
48 assert!(!scalar.is_zero(), "Tried to divide {self} by zero.");
49
50 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
51 unsafe {
52 fmpq_mat_scalar_div_fmpz(&mut out.matrix, &self.matrix, &scalar.value);
53 }
54 out
55 }
56}
57
58arithmetic_trait_borrowed_to_owned!(Div, div, MatQ, Z, MatQ);
59arithmetic_trait_mixed_borrowed_owned!(Div, div, MatQ, Z, MatQ);
60
61implement_for_others!(Z, MatQ, MatQ, Div Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
62
63impl Div<&Q> for &MatQ {
64 type Output = MatQ;
65 #[allow(clippy::suspicious_arithmetic_impl)]
87 fn div(self, scalar: &Q) -> Self::Output {
88 assert!(!scalar.is_zero(), "Tried to divide {self} by zero.");
89
90 let scalar = scalar.inverse().unwrap();
91 self * scalar
92 }
93}
94
95arithmetic_trait_borrowed_to_owned!(Div, div, MatQ, Q, MatQ);
96arithmetic_trait_mixed_borrowed_owned!(Div, div, MatQ, Q, MatQ);
97
98implement_for_others!(Q, MatQ, MatQ, Div Scalar for f32 f64);
99
100impl DivAssign<&Q> for MatQ {
101 fn div_assign(&mut self, scalar: &Q) {
130 assert!(!scalar.is_zero(), "Tried to divide {self} by zero.");
131
132 let scalar = scalar.inverse().unwrap();
133 self.mul_assign(scalar);
134 }
135}
136
137impl DivAssign<&Z> for MatQ {
138 fn div_assign(&mut self, scalar: &Z) {
140 assert!(!scalar.is_zero(), "Tried to divide {self} by zero.");
141
142 unsafe { fmpq_mat_scalar_div_fmpz(&mut self.matrix, &self.matrix, &scalar.value) };
143 }
144}
145
146arithmetic_assign_trait_borrowed_to_owned!(DivAssign, div_assign, MatQ, Q);
147arithmetic_assign_trait_borrowed_to_owned!(DivAssign, div_assign, MatQ, Z);
148arithmetic_assign_between_types!(DivAssign, div_assign, MatQ, Z, u64 u32 u16 u8 i64 i32 i16 i8);
149arithmetic_assign_between_types!(DivAssign, div_assign, MatQ, Q, f32 f64);
150
151#[cfg(test)]
152mod test_div_z {
153 use super::MatQ;
154 use crate::integer::Z;
155 use std::str::FromStr;
156
157 #[test]
159 fn borrowed_correctness() {
160 let cmp = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
161 let mat = MatQ::from_str("[[2, 3],[3/2, 6]]").unwrap();
162 let integer = Z::from(3);
163
164 assert_eq!(cmp, &mat / &integer);
165 }
166
167 #[test]
169 fn owned_correctness() {
170 let cmp = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
171 let mat = MatQ::from_str("[[2, 3],[3/2, 6]]").unwrap();
172 let integer = Z::from(3);
173
174 assert_eq!(cmp, mat / integer);
175 }
176
177 #[test]
179 fn half_correctness() {
180 let cmp = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
181 let mat = MatQ::from_str("[[2, 3],[3/2, 6]]").unwrap();
182 let integer = Z::from(3);
183
184 assert_eq!(cmp, &mat / integer.clone());
185 assert_eq!(cmp, mat / &integer);
186 }
187
188 #[test]
190 #[allow(clippy::erasing_op)]
191 fn different_types() {
192 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
193 let mat_2 = MatQ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
194 let mat_3 = MatQ::from_str("[[1],[0],[8]]").unwrap();
195 let mat_5 = MatQ::from_str("[[-1/2],[0],[-4]]").unwrap();
196 let mat_6 = MatQ::from_str("[[6, 15, 18],[3, 9, 3]]").unwrap();
197
198 assert_eq!(&mat_3 / 2u8, mat_1);
199 assert_eq!(&mat_3 / 2i8, mat_1);
200 assert_eq!(&mat_3 / 2u16, mat_1);
201 assert_eq!(&mat_3 / 2i16, mat_1);
202 assert_eq!(&mat_3 / 2u32, mat_1);
203 assert_eq!(&mat_3 / 2i32, mat_1);
204 assert_eq!(&mat_3 / 2u64, mat_1);
205 assert_eq!(&mat_3 / 2i64, mat_1);
206 assert_eq!(mat_5, &mat_1 / -1);
207 assert_eq!(&mat_6 / 3, mat_2);
208 }
209
210 #[test]
212 fn different_dimensions_correctness() {
213 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
214 let mat_2 = MatQ::from_str("[[2, 5/8, 6],[1, 3, 1/7]]").unwrap();
215 let mat_3 = MatQ::from_str("[[3/2],[0],[12]]").unwrap();
216 let mat_4 = MatQ::from_str("[[6, 15/8, 18],[3, 9, 3/7]]").unwrap();
217 let integer = Z::from(3);
218
219 assert_eq!(mat_1, mat_3 / &integer);
220 assert_eq!(mat_2, mat_4 / integer);
221 }
222
223 #[test]
225 fn large_entries() {
226 let mat_1 = MatQ::from_str(&format!("[[1],[{}],[1/{}]]", i64::MAX, i64::MAX)).unwrap();
227 let mat_2 = MatQ::from_str("[[3]]").unwrap();
228 let mat_3 = MatQ::from_str(&format!(
229 "[[3],[{}],[3/{}]]",
230 3 * i64::MAX as i128,
231 i64::MAX
232 ))
233 .unwrap();
234 let mat_4 = MatQ::from_str(&format!("[[{}]]", 3 * i64::MAX as i128)).unwrap();
235 let integer_1 = Z::from(3);
236 let integer_2 = Z::from(i64::MAX);
237
238 assert_eq!(mat_3 / integer_1, mat_1);
239 assert_eq!(mat_4 / integer_2, mat_2);
240 }
241
242 #[test]
244 #[should_panic]
245 fn div_0() {
246 let mat = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
247 let integer = Z::from(0);
248
249 let _ = &mat / &integer;
250 }
251}
252
253#[cfg(test)]
254mod test_mul_q {
255 use super::MatQ;
256 use crate::rational::Q;
257 use std::str::FromStr;
258
259 #[test]
261 fn borrowed_correctness() {
262 let mat = MatQ::from_str("[[1, 3/2],[3/4, 3]]").unwrap();
263 let rational = Q::from((3, 2));
264 let cmp = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
265
266 assert_eq!(&mat / &rational, cmp);
267 }
268
269 #[test]
271 fn owned_correctness() {
272 let mat = MatQ::from_str("[[1, 3/2],[3/4, 3]]").unwrap();
273 let rational = Q::from((3, 2));
274 let cmp = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
275
276 assert_eq!(mat / rational, cmp);
277 }
278
279 #[test]
281 fn half_correctness() {
282 let mat = MatQ::from_str("[[1, 3/2],[3/4, 3]]").unwrap();
283 let rational = Q::from((3, 2));
284 let cmp = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
285
286 assert_eq!(&mat / rational.clone(), cmp);
287 assert_eq!(mat / &rational, cmp);
288 }
289
290 #[test]
292 #[allow(clippy::erasing_op)]
293 fn different_types() {
294 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
295 let mat_2 = MatQ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
296 let mat_3 = MatQ::from_str("[[5/4],[0],[10]]").unwrap();
297 let mat_4 = MatQ::from_str("[[-799/8],[0],[-799]]").unwrap();
298 let mat_5 = MatQ::from_str("[[285/4, 1425/8, 855/4],[285/8, 855/8, 285/8]]").unwrap();
299
300 assert_eq!(mat_3 / 2.5f32, mat_1);
301 assert_eq!(mat_4 / -199.75f64, mat_1);
302 assert_eq!(mat_5 / 35.625, mat_2);
303 }
304
305 #[test]
307 fn different_dimensions_correctness() {
308 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
309 let mat_2 = MatQ::from_str("[[2, 5/8, 6],[1, 3, 1/7]]").unwrap();
310 let mat_3 = MatQ::from_str("[[3/4],[0],[6]]").unwrap();
311 let mat_4 = MatQ::from_str("[[3, 15/16, 9],[3/2, 9/2, 3/14]]").unwrap();
312 let rational = Q::from((3, 2));
313
314 assert_eq!(mat_3, &rational * mat_1);
315 assert_eq!(mat_4, rational * mat_2);
316 }
317
318 #[test]
320 fn large_entries() {
321 let mat_1 = MatQ::from_str(&format!("[[1],[{}],[1/{}]]", i64::MAX, i64::MAX)).unwrap();
322 let mat_2 = MatQ::from_str("[[3]]").unwrap();
323 let mat_3 = MatQ::from_str(&format!(
324 "[[3/2],[{}/2],[3/{}]]",
325 3 * i64::MAX as i128,
326 2 * i64::MAX as i128
327 ))
328 .unwrap();
329 let mat_4 = MatQ::from_str(&format!("[[{}/2]]", 3 * i64::MAX as i128)).unwrap();
330 let mat_5 = MatQ::from_str(&format!("[[6/{}]]", i64::MAX)).unwrap();
331 let rational_1 = Q::from((3, 2));
332 let rational_2 = Q::from((i64::MAX, 2));
333 let rational_3 = Q::from((2, i64::MAX));
334
335 assert_eq!(mat_3 / rational_1, mat_1);
336 assert_eq!(mat_4 / rational_2, mat_2);
337 assert_eq!(mat_5 / rational_3, mat_2);
338 }
339
340 #[test]
342 #[should_panic]
343 fn div_0() {
344 let mat = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
345 let rational = Q::from(0);
346
347 let _ = &mat / &rational;
348 }
349}
350
351#[cfg(test)]
352mod test_div_assign {
353 use crate::integer::Z;
354 use crate::rational::{MatQ, Q};
355 use std::str::FromStr;
356
357 #[test]
359 fn consistency() {
360 let mut a = MatQ::from_str("[[2, 1],[-1, 0]]").unwrap();
361 let b = Q::from((1, i32::MAX));
362 let cmp = &a / &b;
363
364 a /= b;
365
366 assert_eq!(cmp, a);
367 }
368
369 #[test]
371 fn availability() {
372 let mut a = MatQ::from_str("[[2, 1],[1, 2]]").unwrap();
373 let b = Z::from(2);
374 let c = Q::from((2, 3));
375
376 a /= &b;
377 a /= b;
378 a /= &c;
379 a /= c;
380 a /= 1_u8;
381 a /= 1_u16;
382 a /= 1_u32;
383 a /= 1_u64;
384 a /= 1_i8;
385 a /= 1_i16;
386 a /= 1_i32;
387 a /= 1_i64;
388 a /= 1_f32;
389 a /= 1_f64;
390 }
391
392 #[test]
394 #[should_panic]
395 fn div_0() {
396 let mut a = MatQ::from_str("[[2, 1],[-1, 0]]").unwrap();
397 let b = Q::from((0, i32::MAX));
398
399 a /= b;
400 }
401}