1use super::super::MatZ;
12use crate::error::MathError;
13use crate::integer_mod_q::MatZq;
14use crate::macros::arithmetics::{
15 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
16 arithmetic_trait_mixed_borrowed_owned,
17};
18use crate::rational::MatQ;
19use crate::traits::MatrixDimensions;
20use flint_sys::fmpz_mat::fmpz_mat_sub;
21use flint_sys::fmpz_mod_mat::_fmpz_mod_mat_reduce;
22use std::ops::{Sub, SubAssign};
23
24impl SubAssign<&MatZ> for MatZ {
25 fn sub_assign(&mut self, other: &Self) {
44 if self.get_num_rows() != other.get_num_rows()
45 || self.get_num_columns() != other.get_num_columns()
46 {
47 panic!(
48 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
49 self.get_num_rows(),
50 self.get_num_columns(),
51 other.get_num_rows(),
52 other.get_num_columns()
53 );
54 }
55
56 unsafe { fmpz_mat_sub(&mut self.matrix, &self.matrix, &other.matrix) };
57 }
58}
59
60arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatZ, MatZ);
61
62impl Sub for &MatZ {
63 type Output = MatZ;
64 fn sub(self, other: Self) -> Self::Output {
89 self.sub_safe(other).unwrap()
90 }
91}
92
93arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZ, MatZ, MatZ);
94arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZ, MatZ, MatZ);
95
96impl Sub<&MatZq> for &MatZ {
97 type Output = MatZq;
98
99 fn sub(self, other: &MatZq) -> Self::Output {
124 if self.get_num_rows() != other.get_num_rows()
125 || self.get_num_columns() != other.get_num_columns()
126 {
127 panic!(
128 "Tried to subtract a '{}x{}' matrix from a '{}x{}' matrix.",
129 other.get_num_rows(),
130 other.get_num_columns(),
131 self.get_num_rows(),
132 self.get_num_columns()
133 );
134 }
135
136 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), other.get_mod());
137 unsafe {
138 fmpz_mat_sub(&mut out.matrix.mat[0], &self.matrix, &other.matrix.mat[0]);
139 _fmpz_mod_mat_reduce(&mut out.matrix);
140 }
141 out
142 }
143}
144
145arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZ, MatZq, MatZq);
146arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZ, MatZq, MatZq);
147
148impl Sub<&MatQ> for &MatZ {
149 type Output = MatQ;
150
151 fn sub(self, other: &MatQ) -> Self::Output {
176 let new_self = MatQ::from(self);
177
178 new_self.sub_safe(other).unwrap()
179 }
180}
181
182arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZ, MatQ, MatQ);
183arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZ, MatQ, MatQ);
184
185impl MatZ {
186 pub fn sub_safe(&self, other: &Self) -> Result<MatZ, MathError> {
210 if self.get_num_rows() != other.get_num_rows()
211 || self.get_num_columns() != other.get_num_columns()
212 {
213 return Err(MathError::MismatchingMatrixDimension(format!(
214 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
215 other.get_num_rows(),
216 other.get_num_columns(),
217 self.get_num_rows(),
218 self.get_num_columns()
219 )));
220 }
221 let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
222 unsafe {
223 fmpz_mat_sub(&mut out.matrix, &self.matrix, &other.matrix);
224 }
225 Ok(out)
226 }
227}
228
229#[cfg(test)]
230mod test_sub_assign {
231 use crate::integer::MatZ;
232 use std::str::FromStr;
233
234 #[test]
236 fn correct_small() {
237 let mut a = MatZ::identity(2, 2);
238 let b = MatZ::from_str("[[-4, -5],[6, 1]]").unwrap();
239 let cmp = MatZ::from_str("[[5, 5],[-6, 0]]").unwrap();
240
241 a -= b;
242
243 assert_eq!(cmp, a);
244 }
245
246 #[test]
248 fn correct_large() {
249 let mut a = MatZ::from_str(&format!("[[{}, 5],[{}, -1]]", i64::MAX, i64::MIN)).unwrap();
250 let b = MatZ::from_str(&format!("[[-{}, 6],[-6, 1]]", i64::MAX)).unwrap();
251 let cmp = MatZ::from_str(&format!(
252 "[[{}, -1],[{}, -2]]",
253 2 * (i64::MAX as u64),
254 i64::MIN + 6
255 ))
256 .unwrap();
257
258 a -= b;
259
260 assert_eq!(cmp, a);
261 }
262
263 #[test]
265 fn matrix_dimensions() {
266 let dimensions = [(3, 3), (5, 1), (1, 4)];
267
268 for (nr_rows, nr_cols) in dimensions {
269 let mut a = MatZ::identity(nr_rows, nr_cols);
270 let b = MatZ::new(nr_rows, nr_cols);
271
272 a -= b;
273
274 assert_eq!(MatZ::identity(nr_rows, nr_cols), a);
275 }
276 }
277
278 #[test]
280 fn availability() {
281 let mut a = MatZ::new(2, 2);
282 let b = MatZ::new(2, 2);
283
284 a -= &b;
285 a -= b;
286 }
287}
288
289#[cfg(test)]
290mod test_sub {
291 use super::MatZ;
292 use std::str::FromStr;
293
294 #[test]
296 fn sub() {
297 let a: MatZ = MatZ::from_str("[[1, 1, 2],[3, 4, -5]]").unwrap();
298 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
299 let c: MatZ = a - b;
300 assert_eq!(c, MatZ::from_str("[[0, -1, -1],[0, 8, -10]]").unwrap());
301 }
302
303 #[test]
305 fn sub_borrow() {
306 let a: MatZ = MatZ::from_str("[[1, 1, 2],[3, 4, -5]]").unwrap();
307 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
308 let c: MatZ = &a - &b;
309 assert_eq!(c, MatZ::from_str("[[0, -1, -1],[0, 8, -10]]").unwrap());
310 }
311
312 #[test]
314 fn sub_first_borrowed() {
315 let a: MatZ = MatZ::from_str("[[1, 1, 2],[3, 4, -5]]").unwrap();
316 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
317 let c: MatZ = &a - b;
318 assert_eq!(c, MatZ::from_str("[[0, -1, -1],[0, 8, -10]]").unwrap());
319 }
320
321 #[test]
323 fn sub_second_borrowed() {
324 let a: MatZ = MatZ::from_str("[[1, 1, 2],[3, 4, -5]]").unwrap();
325 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
326 let c: MatZ = a - &b;
327 assert_eq!(c, MatZ::from_str("[[0, -1, -1],[0, 8, -10]]").unwrap());
328 }
329
330 #[test]
332 fn sub_large_numbers() {
333 let a: MatZ =
334 MatZ::from_str(&format!("[[1, 2, {}],[3, -4, {}]]", i64::MIN, u64::MAX)).unwrap();
335 let b: MatZ =
336 MatZ::from_str(&format!("[[1, 1, {}],[3, 9, {}]]", i64::MAX, i64::MAX)).unwrap();
337 let c: MatZ = a - &b;
338 assert_eq!(
339 c,
340 MatZ::from_str(&format!(
341 "[[0, 1, -{}],[0, -13, {}]]",
342 u64::MAX,
343 (u64::MAX - 1) / 2 + 1
344 ))
345 .unwrap()
346 );
347 }
348
349 #[test]
351 fn sub_safe() {
352 let a: MatZ = MatZ::from_str("[[1, 1, 2],[3, 4, -5]]").unwrap();
353 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
354 let c: MatZ = a.sub_safe(&b).unwrap();
355 assert_eq!(c, MatZ::from_str("[[0, -1, -1],[0, 8, -10]]").unwrap());
356 }
357
358 #[test]
360 fn sub_safe_is_err() {
361 let a: MatZ = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
362 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
363 let c: MatZ = MatZ::from_str("[[1, 2, 3]]").unwrap();
364 assert!(a.sub_safe(&b).is_err());
365 assert!(c.sub_safe(&b).is_err());
366 }
367}
368
369#[cfg(test)]
370mod test_sub_matzq {
371 use super::MatZ;
372 use crate::integer_mod_q::MatZq;
373 use std::str::FromStr;
374
375 #[test]
377 fn small_numbers() {
378 let a = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
379 let b = MatZq::from_str("[[5, 6],[2, 10]] mod 11").unwrap();
380 let cmp = MatZq::from_str("[[7, 7],[1, 5]] mod 11").unwrap();
381
382 let res_0 = &a - &b;
383 let res_1 = MatZq::from((a, 11)) - b.get_representative_least_nonnegative_residue();
384
385 assert_eq!(res_0, res_1);
386 assert_eq!(cmp, res_0);
387 }
388
389 #[test]
391 fn large_numbers() {
392 let a: MatZ =
393 MatZ::from_str(&format!("[[1, 2, {}],[3, -4, {}]]", i64::MIN, u64::MAX)).unwrap();
394 let b: MatZq = MatZq::from_str(&format!(
395 "[[1, 1, {}],[3, 9, {}]] mod {}",
396 i64::MAX,
397 i64::MAX,
398 u64::MAX - 58
399 ))
400 .unwrap();
401
402 let c = a - &b;
403
404 assert_eq!(
405 c,
406 MatZq::from_str(&format!(
407 "[[0, 1, -{}],[0, -13, {}]] mod {}",
408 u64::MAX,
409 (u64::MAX - 1) / 2 + 1,
410 u64::MAX - 58
411 ))
412 .unwrap()
413 );
414 }
415
416 #[test]
418 fn available() {
419 let a = MatZ::new(2, 2);
420 let b = MatZq::new(2, 2, 7);
421
422 let _ = &a - &b;
423 let _ = &a - b.clone();
424 let _ = a.clone() - &b;
425 let _ = a.clone() - b.clone();
426 }
427
428 #[test]
430 #[should_panic]
431 fn mismatching_rows() {
432 let a = MatZ::new(3, 2);
433 let b = MatZq::new(2, 2, 7);
434
435 let _ = &a - &b;
436 }
437
438 #[test]
440 #[should_panic]
441 fn mismatching_column() {
442 let a = MatZ::new(2, 3);
443 let b = MatZq::new(2, 2, 7);
444
445 let _ = &a - &b;
446 }
447}
448
449#[cfg(test)]
450mod test_sub_matq {
451 use super::MatZ;
452 use crate::rational::{MatQ, Q};
453 use std::str::FromStr;
454
455 #[test]
457 fn small_numbers() {
458 let a = MatQ::from_str("[[5, 1/2],[2, 10]]").unwrap();
459 let b = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
460 let cmp = MatQ::from_str("[[-4, 3/2],[1, -6]]").unwrap();
461
462 let res = &b - &a;
463
464 assert_eq!(res, cmp);
465 }
466
467 #[test]
469 fn large_numbers() {
470 let a = MatQ::from_str(&format!("[[1, 2, 1/{}],[3, -4, 5]]", i64::MAX)).unwrap();
471 let b: MatZ = MatZ::from_str(&format!("[[1, 1, {}],[3, 9, 4]]", i64::MIN)).unwrap();
472
473 let c = &b - a;
474
475 assert_eq!(
476 c,
477 MatQ::from_str(&format!(
478 "[[0, -1, -{}],[0, 13, -1]]",
479 Q::from((1, i64::MAX)) - Q::from((i64::MIN, 1))
480 ))
481 .unwrap()
482 );
483 }
484
485 #[test]
487 fn available() {
488 let a = MatQ::new(2, 2);
489 let b = MatZ::new(2, 2);
490
491 let _ = &b - &a;
492 let _ = &b - a.clone();
493 let _ = b.clone() - &a;
494 let _ = b.clone() - a.clone();
495 }
496
497 #[test]
499 #[should_panic]
500 fn mismatching_rows() {
501 let a = MatQ::new(2, 2);
502 let b = MatZ::new(3, 2);
503
504 let _ = &b - &a;
505 }
506
507 #[test]
509 #[should_panic]
510 fn mismatching_column() {
511 let a = MatQ::new(2, 2);
512 let b = MatZ::new(2, 3);
513
514 let _ = &b - &a;
515 }
516}