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 flint_sys::fmpz_mat::fmpz_mat_sub;
20use flint_sys::fmpz_mod_mat::{_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 { fmpz_mod_mat_sub(&mut self.matrix, &self.matrix, &other.matrix) };
65 }
66}
67impl SubAssign<&MatZ> for MatZq {
68 fn sub_assign(&mut self, other: &MatZ) {
70 if self.get_num_rows() != other.get_num_rows()
71 || self.get_num_columns() != other.get_num_columns()
72 {
73 panic!(
74 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
75 self.get_num_rows(),
76 self.get_num_columns(),
77 other.get_num_rows(),
78 other.get_num_columns()
79 );
80 }
81
82 unsafe {
83 fmpz_mat_sub(&mut self.matrix.mat[0], &self.matrix.mat[0], &other.matrix);
84 _fmpz_mod_mat_reduce(&mut self.matrix);
85 };
86 }
87}
88
89arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatZq, MatZq);
90arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatZq, MatZ);
91
92impl Sub for &MatZq {
93 type Output = MatZq;
94 fn sub(self, other: Self) -> Self::Output {
120 self.sub_safe(other).unwrap()
121 }
122}
123
124arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZq, MatZq, MatZq);
125arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZq, MatZq, MatZq);
126
127impl Sub<&MatZ> for &MatZq {
128 type Output = MatZq;
129
130 fn sub(self, other: &MatZ) -> Self::Output {
155 if self.get_num_rows() != other.get_num_rows()
156 || self.get_num_columns() != other.get_num_columns()
157 {
158 panic!(
159 "Tried to subtract a '{}x{}' matrix from a '{}x{}' matrix.",
160 other.get_num_rows(),
161 other.get_num_columns(),
162 self.get_num_rows(),
163 self.get_num_columns()
164 );
165 }
166
167 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
168 unsafe {
169 fmpz_mat_sub(&mut out.matrix.mat[0], &self.matrix.mat[0], &other.matrix);
170 _fmpz_mod_mat_reduce(&mut out.matrix);
171 }
172 out
173 }
174}
175
176arithmetic_trait_borrowed_to_owned!(Sub, sub, MatZq, MatZ, MatZq);
177arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatZq, MatZ, MatZq);
178
179impl MatZq {
180 pub fn sub_safe(&self, other: &Self) -> Result<MatZq, MathError> {
205 if !self.compare_base(other) {
206 return Err(self.call_compare_base_error(other).unwrap());
207 }
208 if self.get_num_rows() != other.get_num_rows()
209 || self.get_num_columns() != other.get_num_columns()
210 {
211 return Err(MathError::MismatchingMatrixDimension(format!(
212 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
213 other.get_num_rows(),
214 other.get_num_columns(),
215 self.get_num_rows(),
216 self.get_num_columns()
217 )));
218 }
219 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
220 unsafe {
221 fmpz_mod_mat_sub(&mut out.matrix, &self.matrix, &other.matrix);
222 }
223 Ok(out)
224 }
225}
226
227#[cfg(test)]
228mod test_sub_assign {
229 use crate::{integer::MatZ, integer_mod_q::MatZq};
230 use std::str::FromStr;
231
232 #[test]
234 fn correct_small() {
235 let mut a = MatZq::identity(2, 2, 7);
236 let b = MatZq::from_str("[[-4, -5],[6, -6]] mod 7").unwrap();
237 let mut c = a.clone();
238 let d = b.get_representative_least_nonnegative_residue();
239 let cmp = MatZq::from_str("[[5, 5],[1, 0]] mod 7").unwrap();
240
241 a -= b;
242 c -= d;
243
244 assert_eq!(cmp, a);
245 assert_eq!(cmp, c);
246 }
247
248 #[test]
250 fn correct_large() {
251 let mut a = MatZq::from_str(&format!(
252 "[[{}, 5],[{}, -1]] mod {}",
253 i64::MAX,
254 i64::MIN,
255 u64::MAX
256 ))
257 .unwrap();
258 let b = MatZq::from_str(&format!("[[-{}, 6],[-6, 1]] mod {}", i64::MAX, u64::MAX)).unwrap();
259 let cmp = MatZq::from_str(&format!(
260 "[[{}, -1],[{}, -2]] mod {}",
261 2 * (i64::MAX as u64),
262 i64::MIN + 6,
263 u64::MAX
264 ))
265 .unwrap();
266
267 a -= b;
268
269 assert_eq!(cmp, a);
270 }
271
272 #[test]
274 fn matrix_dimensions() {
275 let dimensions = [(3, 3), (5, 1), (1, 4)];
276
277 for (nr_rows, nr_cols) in dimensions {
278 let mut a = MatZq::identity(nr_rows, nr_cols, 7);
279 let b = MatZq::new(nr_rows, nr_cols, 7);
280
281 a -= b;
282
283 assert_eq!(MatZq::identity(nr_rows, nr_cols, 7), a);
284 }
285 }
286
287 #[test]
289 #[should_panic]
290 fn mismatching_moduli() {
291 let mut a = MatZq::new(1, 1, 5);
292 let b = MatZq::new(1, 1, 6);
293
294 a -= b;
295 }
296
297 #[test]
299 fn availability() {
300 let mut a = MatZq::new(2, 2, 7);
301 let b = MatZq::new(2, 2, 7);
302 let c = MatZ::new(2, 2);
303
304 a -= &b;
305 a -= b;
306 a -= &c;
307 a -= c;
308 }
309}
310
311#[cfg(test)]
312mod test_sub {
313 use super::MatZq;
314 use std::str::FromStr;
315
316 #[test]
318 fn sub() {
319 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 3").unwrap();
320 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 3").unwrap();
321 let c: MatZq = a - b;
322 assert_eq!(c, MatZq::from_str("[[0, -1, -1],[0, 8, 2]] mod 3").unwrap());
323 }
324
325 #[test]
327 fn sub_borrow() {
328 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 7").unwrap();
329 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
330 let c: MatZq = &a - &b;
331 assert_eq!(
332 c,
333 MatZq::from_str("[[0, -1, -1],[0, 8, -10]] mod 7").unwrap()
334 );
335 }
336
337 #[test]
339 fn sub_first_borrowed() {
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_second_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_large_numbers() {
364 let a: MatZq = MatZq::from_str(&format!(
365 "[[1, 2, {}],[3, -4, {}]] mod {}",
366 i64::MIN,
367 u64::MAX,
368 u64::MAX - 58
369 ))
370 .unwrap();
371 let b: MatZq = MatZq::from_str(&format!(
372 "[[1, 1, {}],[3, 9, {}]] mod {}",
373 i64::MAX,
374 i64::MAX,
375 u64::MAX - 58
376 ))
377 .unwrap();
378 let c: MatZq = a - &b;
379 assert_eq!(
380 c,
381 MatZq::from_str(&format!(
382 "[[0, 1, -{}],[0, -13, {}]] mod {}",
383 u64::MAX,
384 (u64::MAX - 1) / 2 + 1,
385 u64::MAX - 58
386 ))
387 .unwrap()
388 );
389 }
390
391 #[test]
393 fn sub_safe() {
394 let a: MatZq = MatZq::from_str("[[1, 1, 2],[3, 4, -5]] mod 7").unwrap();
395 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
396 let c: MatZq = a.sub_safe(&b).unwrap();
397 assert_eq!(c, MatZq::from_str("[[0, -1, -1],[0, 8, 4]] mod 7").unwrap());
398 }
399
400 #[test]
402 fn sub_safe_is_err() {
403 let a: MatZq = MatZq::from_str("[[1, 2],[3, 4]] mod 7").unwrap();
404 let b: MatZq = MatZq::from_str("[[1, 2, 3],[3, -4, 5]] mod 7").unwrap();
405 let c: MatZq = MatZq::from_str("[[1, 2, 3]] mod 7").unwrap();
406 let d: MatZq = MatZq::from_str("[[1, 2],[3, 4]] mod 3").unwrap();
407 assert!(a.sub_safe(&b).is_err());
408 assert!(c.sub_safe(&b).is_err());
409 assert!(a.add_safe(&d).is_err());
410 }
411}
412
413#[cfg(test)]
414mod test_sub_matz {
415 use super::MatZ;
416 use crate::integer_mod_q::MatZq;
417 use std::str::FromStr;
418
419 #[test]
421 fn small_numbers() {
422 let a = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
423 let b = MatZq::from_str("[[5, 6],[2, 10]] mod 11").unwrap();
424 let cmp = MatZq::from_str("[[4, 4],[-1, 6]] mod 11").unwrap();
425
426 let res_0 = &b - &a;
427 let res_1 = b - MatZq::from((a, 11));
428
429 assert_eq!(res_0, res_1);
430 assert_eq!(cmp, res_0);
431 }
432
433 #[test]
435 fn large_numbers() {
436 let a: MatZ =
437 MatZ::from_str(&format!("[[1, 1, {}],[3, 9, {}]]", i64::MAX, i64::MAX)).unwrap();
438 let b: MatZq = MatZq::from_str(&format!(
439 "[[1, 2, {}],[3, -4, {}]] mod {}",
440 i64::MIN,
441 u64::MAX,
442 u64::MAX - 58
443 ))
444 .unwrap();
445
446 let c = &b - a;
447
448 assert_eq!(
449 c,
450 MatZq::from_str(&format!(
451 "[[0, 1, -{}],[0, -13, {}]] mod {}",
452 u64::MAX,
453 (u64::MAX - 1) / 2 + 1,
454 u64::MAX - 58
455 ))
456 .unwrap()
457 );
458 }
459
460 #[test]
462 fn available() {
463 let a = MatZ::new(2, 2);
464 let b = MatZq::new(2, 2, 7);
465
466 let _ = &b - &a;
467 let _ = &b - a.clone();
468 let _ = b.clone() - &a;
469 let _ = b.clone() - a.clone();
470 }
471
472 #[test]
474 #[should_panic]
475 fn mismatching_rows() {
476 let a = MatZ::new(3, 2);
477 let b = MatZq::new(2, 2, 7);
478
479 let _ = &b - &a;
480 }
481
482 #[test]
484 #[should_panic]
485 fn mismatching_column() {
486 let a = MatZ::new(2, 3);
487 let b = MatZq::new(2, 2, 7);
488
489 let _ = &b - &a;
490 }
491}