1use super::super::MatZq;
12use crate::error::MathError;
13use crate::integer::MatZ;
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::traits::{CompareBase, MatrixDimensions};
19use flint3_sys::fmpz_mat_sub;
20use flint3_sys::{_fmpz_mod_mat_reduce, fmpz_mod_mat_sub};
21use std::ops::{Sub, SubAssign};
22
23impl SubAssign<&MatZq> for MatZq {
24 fn sub_assign(&mut self, other: &Self) {
49 if self.get_num_rows() != other.get_num_rows()
50 || self.get_num_columns() != other.get_num_columns()
51 {
52 panic!(
53 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
54 self.get_num_rows(),
55 self.get_num_columns(),
56 other.get_num_rows(),
57 other.get_num_columns()
58 );
59 }
60 if !self.compare_base(other) {
61 panic!("{}", self.call_compare_base_error(other).unwrap());
62 }
63
64 unsafe {
65 fmpz_mod_mat_sub(
66 &mut self.matrix,
67 &self.matrix,
68 &other.matrix,
69 self.modulus.get_fmpz_mod_ctx_struct(),
70 )
71 };
72 }
73}
74impl SubAssign<&MatZ> for MatZq {
75 fn sub_assign(&mut self, other: &MatZ) {
77 if self.get_num_rows() != other.get_num_rows()
78 || self.get_num_columns() != other.get_num_columns()
79 {
80 panic!(
81 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
82 self.get_num_rows(),
83 self.get_num_columns(),
84 other.get_num_rows(),
85 other.get_num_columns()
86 );
87 }
88
89 unsafe {
90 fmpz_mat_sub(&mut self.matrix, &self.matrix, &other.matrix);
91 _fmpz_mod_mat_reduce(&mut self.matrix, self.modulus.get_fmpz_mod_ctx_struct());
92 };
93 }
94}
95
96arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatZq, MatZq);
97arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatZq, MatZ);
98
99impl Sub for &MatZq {
100 type Output = MatZq;
101 fn sub(self, other: Self) -> Self::Output {
127 self.sub_safe(other).unwrap()
128 }
129}
130
131arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZq, MatZq, MatZq);
132arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZq, MatZq, MatZq);
133
134impl Sub<&MatZ> for &MatZq {
135 type Output = MatZq;
136
137 fn sub(self, other: &MatZ) -> Self::Output {
162 if self.get_num_rows() != other.get_num_rows()
163 || self.get_num_columns() != other.get_num_columns()
164 {
165 panic!(
166 "Tried to subtract a '{}x{}' matrix from a '{}x{}' matrix.",
167 other.get_num_rows(),
168 other.get_num_columns(),
169 self.get_num_rows(),
170 self.get_num_columns()
171 );
172 }
173
174 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
175 unsafe {
176 fmpz_mat_sub(&mut out.matrix, &self.matrix, &other.matrix);
177 _fmpz_mod_mat_reduce(&mut out.matrix, self.modulus.get_fmpz_mod_ctx_struct());
178 }
179 out
180 }
181}
182
183arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZq, MatZ, MatZq);
184arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZq, MatZ, MatZq);
185
186impl MatZq {
187 pub fn sub_safe(&self, other: &Self) -> Result<MatZq, MathError> {
212 if !self.compare_base(other) {
213 return Err(self.call_compare_base_error(other).unwrap());
214 }
215 if self.get_num_rows() != other.get_num_rows()
216 || self.get_num_columns() != other.get_num_columns()
217 {
218 return Err(MathError::MismatchingMatrixDimension(format!(
219 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
220 other.get_num_rows(),
221 other.get_num_columns(),
222 self.get_num_rows(),
223 self.get_num_columns()
224 )));
225 }
226 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
227 unsafe {
228 fmpz_mod_mat_sub(
229 &mut out.matrix,
230 &self.matrix,
231 &other.matrix,
232 self.modulus.get_fmpz_mod_ctx_struct(),
233 );
234 }
235 Ok(out)
236 }
237}
238
239#[cfg(test)]
240mod test_sub_assign {
241 use crate::{integer::MatZ, integer_mod_q::MatZq};
242 use std::str::FromStr;
243
244 #[test]
246 fn correct_small() {
247 let mut a = MatZq::identity(2, 2, 7);
248 let b = MatZq::from_str("[[-4, -5],[6, -6]] mod 7").unwrap();
249 let mut c = a.clone();
250 let d = b.get_representative_least_nonnegative_residue();
251 let cmp = MatZq::from_str("[[5, 5],[1, 0]] mod 7").unwrap();
252
253 a -= b;
254 c -= d;
255
256 assert_eq!(cmp, a);
257 assert_eq!(cmp, c);
258 }
259
260 #[test]
262 fn correct_large() {
263 let mut a = MatZq::from_str(&format!(
264 "[[{}, 5],[{}, -1]] mod {}",
265 i64::MAX,
266 i64::MIN,
267 u64::MAX
268 ))
269 .unwrap();
270 let b = MatZq::from_str(&format!("[[-{}, 6],[-6, 1]] mod {}", i64::MAX, u64::MAX)).unwrap();
271 let cmp = MatZq::from_str(&format!(
272 "[[{}, -1],[{}, -2]] mod {}",
273 2 * (i64::MAX as u64),
274 i64::MIN + 6,
275 u64::MAX
276 ))
277 .unwrap();
278
279 a -= b;
280
281 assert_eq!(cmp, a);
282 }
283
284 #[test]
286 fn matrix_dimensions() {
287 let dimensions = [(3, 3), (5, 1), (1, 4)];
288
289 for (nr_rows, nr_cols) in dimensions {
290 let mut a = MatZq::identity(nr_rows, nr_cols, 7);
291 let b = MatZq::new(nr_rows, nr_cols, 7);
292
293 a -= b;
294
295 assert_eq!(MatZq::identity(nr_rows, nr_cols, 7), a);
296 }
297 }
298
299 #[test]
301 #[should_panic]
302 fn mismatching_moduli() {
303 let mut a = MatZq::new(1, 1, 5);
304 let b = MatZq::new(1, 1, 6);
305
306 a -= b;
307 }
308
309 #[test]
311 fn availability() {
312 let mut a = MatZq::new(2, 2, 7);
313 let b = MatZq::new(2, 2, 7);
314 let c = MatZ::new(2, 2);
315
316 a -= &b;
317 a -= b;
318 a -= &c;
319 a -= c;
320 }
321}
322
323#[cfg(test)]
324mod test_sub {
325 use super::MatZq;
326 use std::str::FromStr;
327
328 #[test]
330 fn sub() {
331 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 3").unwrap();
332 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 3").unwrap();
333 let c: MatZq = a - b;
334 assert_eq!(c, MatZq::from_str("[[0, -1, -1],[0, 8, 2]] mod 3").unwrap());
335 }
336
337 #[test]
339 fn sub_borrow() {
340 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 7").unwrap();
341 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
342 let c: MatZq = &a - &b;
343 assert_eq!(
344 c,
345 MatZq::from_str("[[0, -1, -1],[0, 8, -10]] mod 7").unwrap()
346 );
347 }
348
349 #[test]
351 fn sub_first_borrowed() {
352 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 7").unwrap();
353 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
354 let c: MatZq = &a - b;
355 assert_eq!(
356 c,
357 MatZq::from_str("[[0, -1, -1],[0, 8, -10]] mod 7").unwrap()
358 );
359 }
360
361 #[test]
363 fn sub_second_borrowed() {
364 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 7").unwrap();
365 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
366 let c: MatZq = a - &b;
367 assert_eq!(
368 c,
369 MatZq::from_str("[[0, -1, -1],[0, 8, -10]] mod 7").unwrap()
370 );
371 }
372
373 #[test]
375 fn sub_large_numbers() {
376 let a: MatZq = MatZq::from_str(&format!(
377 "[[1, 2, {}],[3, -4, {}]] mod {}",
378 i64::MIN,
379 u64::MAX,
380 u64::MAX - 58
381 ))
382 .unwrap();
383 let b: MatZq = MatZq::from_str(&format!(
384 "[[1, 1, {}],[3, 9, {}]] mod {}",
385 i64::MAX,
386 i64::MAX,
387 u64::MAX - 58
388 ))
389 .unwrap();
390 let c: MatZq = a - &b;
391 assert_eq!(
392 c,
393 MatZq::from_str(&format!(
394 "[[0, 1, -{}],[0, -13, {}]] mod {}",
395 u64::MAX,
396 (u64::MAX - 1) / 2 + 1,
397 u64::MAX - 58
398 ))
399 .unwrap()
400 );
401 }
402
403 #[test]
405 fn sub_safe() {
406 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 7").unwrap();
407 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
408 let c: MatZq = a.sub_safe(&b).unwrap();
409 assert_eq!(c, MatZq::from_str("[[0, -1, -1],[0, 8, 4]] mod 7").unwrap());
410 }
411
412 #[test]
414 fn sub_safe_is_err() {
415 let a: MatZq = MatZq::from_str("[[1, 2],[3, 4]] mod 7").unwrap();
416 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
417 let c: MatZq = MatZq::from_str("[[1, 2, 3]] mod 7").unwrap();
418 let d: MatZq = MatZq::from_str("[[1, 2],[3, 4]] mod 3").unwrap();
419 assert!(a.sub_safe(&b).is_err());
420 assert!(c.sub_safe(&b).is_err());
421 assert!(a.add_safe(&d).is_err());
422 }
423}
424
425#[cfg(test)]
426mod test_sub_matz {
427 use super::MatZ;
428 use crate::integer_mod_q::MatZq;
429 use std::str::FromStr;
430
431 #[test]
433 fn small_numbers() {
434 let a = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
435 let b = MatZq::from_str("[[5, 6],[2, 10]] mod 11").unwrap();
436 let cmp = MatZq::from_str("[[4, 4],[-1, 6]] mod 11").unwrap();
437
438 let res_0 = &b - &a;
439 let res_1 = b - MatZq::from((a, 11));
440
441 assert_eq!(res_0, res_1);
442 assert_eq!(cmp, res_0);
443 }
444
445 #[test]
447 fn large_numbers() {
448 let a: MatZ =
449 MatZ::from_str(&format!("[[1, 1, {}],[3, 9, {}]]", i64::MAX, i64::MAX)).unwrap();
450 let b: MatZq = MatZq::from_str(&format!(
451 "[[1, 2, {}],[3, -4, {}]] mod {}",
452 i64::MIN,
453 u64::MAX,
454 u64::MAX - 58
455 ))
456 .unwrap();
457
458 let c = &b - a;
459
460 assert_eq!(
461 c,
462 MatZq::from_str(&format!(
463 "[[0, 1, -{}],[0, -13, {}]] mod {}",
464 u64::MAX,
465 (u64::MAX - 1) / 2 + 1,
466 u64::MAX - 58
467 ))
468 .unwrap()
469 );
470 }
471
472 #[test]
474 fn available() {
475 let a = MatZ::new(2, 2);
476 let b = MatZq::new(2, 2, 7);
477
478 let _ = &b - &a;
479 let _ = &b - a.clone();
480 let _ = b.clone() - &a;
481 let _ = b.clone() - a.clone();
482 }
483
484 #[test]
486 #[should_panic]
487 fn mismatching_rows() {
488 let a = MatZ::new(3, 2);
489 let b = MatZq::new(2, 2, 7);
490
491 let _ = &b - &a;
492 }
493
494 #[test]
496 #[should_panic]
497 fn mismatching_column() {
498 let a = MatZ::new(2, 3);
499 let b = MatZq::new(2, 2, 7);
500
501 let _ = &b - &a;
502 }
503}