1use super::super::MatQ;
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::MatrixDimensions;
19use flint_sys::fmpq_mat::fmpq_mat_sub;
20use std::ops::{Sub, SubAssign};
21
22impl SubAssign<&MatQ> for MatQ {
23 fn sub_assign(&mut self, other: &Self) {
47 if self.get_num_rows() != other.get_num_rows()
48 || self.get_num_columns() != other.get_num_columns()
49 {
50 panic!(
51 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
52 self.get_num_rows(),
53 self.get_num_columns(),
54 other.get_num_rows(),
55 other.get_num_columns()
56 );
57 }
58
59 unsafe { fmpq_mat_sub(&mut self.matrix, &self.matrix, &other.matrix) };
60 }
61}
62impl SubAssign<&MatZ> for MatQ {
63 fn sub_assign(&mut self, other: &MatZ) {
65 if self.get_num_rows() != other.get_num_rows()
66 || self.get_num_columns() != other.get_num_columns()
67 {
68 panic!(
69 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
70 self.get_num_rows(),
71 self.get_num_columns(),
72 other.get_num_rows(),
73 other.get_num_columns()
74 );
75 }
76
77 let other = MatQ::from(other);
78 unsafe {
79 fmpq_mat_sub(&mut self.matrix, &self.matrix, &other.matrix);
80 }
81 }
82}
83
84arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatQ, MatQ);
85arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, MatQ, MatZ);
86
87impl Sub for &MatQ {
88 type Output = MatQ;
89 fn sub(self, other: Self) -> Self::Output {
114 self.sub_safe(other).unwrap()
115 }
116}
117
118impl Sub<&MatZ> for &MatQ {
119 type Output = MatQ;
120
121 fn sub(self, other: &MatZ) -> Self::Output {
146 let other = MatQ::from(other);
147
148 self.sub_safe(&other).unwrap()
149 }
150}
151
152arithmetic_trait_borrowed_to_owned!(Sub, sub, MatQ, MatZ, MatQ);
153arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatQ, MatZ, MatQ);
154
155impl MatQ {
156 pub fn sub_safe(&self, other: &Self) -> Result<MatQ, MathError> {
180 if self.get_num_rows() != other.get_num_rows()
181 || self.get_num_columns() != other.get_num_columns()
182 {
183 return Err(MathError::MismatchingMatrixDimension(format!(
184 "Tried to subtract a '{}x{}' matrix and a '{}x{}' matrix.",
185 other.get_num_rows(),
186 other.get_num_columns(),
187 self.get_num_rows(),
188 self.get_num_columns()
189 )));
190 }
191 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
192 unsafe {
193 fmpq_mat_sub(&mut out.matrix, &self.matrix, &other.matrix);
194 }
195 Ok(out)
196 }
197}
198
199arithmetic_trait_borrowed_to_owned!(Sub, sub, MatQ, MatQ, MatQ);
200arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatQ, MatQ, MatQ);
201
202#[cfg(test)]
203mod test_sub_assign {
204 use crate::{integer::MatZ, rational::MatQ};
205 use std::str::FromStr;
206
207 #[test]
209 fn correct_small() {
210 let mut a = MatQ::identity(2, 2);
211 let b = MatQ::from_str("[[-4/5, -5],[6, 1]]").unwrap();
212 let mut c = a.clone();
213 let d = MatZ::from_str("[[-4, -5],[6, 1]]").unwrap();
214 let cmp_0 = MatQ::from_str("[[9/5, 5],[-6, 0]]").unwrap();
215 let cmp_1 = MatQ::from_str("[[5, 5],[-6, 0]]").unwrap();
216
217 a -= b;
218 c -= d;
219
220 assert_eq!(cmp_0, a);
221 assert_eq!(cmp_1, c);
222 }
223
224 #[test]
226 fn correct_large() {
227 let mut a = MatQ::from_str(&format!("[[{}/1, 5/2],[{}, -1]]", i64::MAX, i64::MIN)).unwrap();
228 let b = MatQ::from_str(&format!("[[-{}, 6/2],[-6, 1]]", i64::MAX)).unwrap();
229 let cmp = MatQ::from_str(&format!(
230 "[[{}, -1/2],[{}, -2]]",
231 2 * (i64::MAX as u64),
232 i64::MIN + 6
233 ))
234 .unwrap();
235
236 a -= b;
237
238 assert_eq!(cmp, a);
239 }
240
241 #[test]
243 fn matrix_dimensions() {
244 let dimensions = [(3, 3), (5, 1), (1, 4)];
245
246 for (nr_rows, nr_cols) in dimensions {
247 let mut a = MatQ::identity(nr_rows, nr_cols);
248 let b = MatQ::new(nr_rows, nr_cols);
249
250 a -= b;
251
252 assert_eq!(MatQ::identity(nr_rows, nr_cols), a);
253 }
254 }
255
256 #[test]
258 fn availability() {
259 let mut a = MatQ::new(2, 2);
260 let b = MatQ::new(2, 2);
261 let c = MatZ::new(2, 2);
262
263 a -= &b;
264 a -= b;
265 a -= &c;
266 a -= c;
267 }
268}
269
270#[cfg(test)]
271mod test_sub {
272 use super::MatQ;
273 use crate::{integer::MatZ, rational::Q};
274 use std::str::FromStr;
275
276 #[test]
278 fn sub() {
279 let a: MatQ = MatQ::from_str("[[1/2, 1, 2],[3/7, 4/7, -5]]").unwrap();
280 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/4],[3/7, -4/9, 5]]").unwrap();
281 let c: MatQ = a - b;
282 assert_eq!(c, MatQ::from_str("[[0, -1, 5/4],[0, 64/63, -10]]").unwrap());
283 }
284
285 #[test]
287 fn sub_borrow() {
288 let a: MatQ = MatQ::from_str("[[1/2, 1, 2],[3/7, 4/7, -5]]").unwrap();
289 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/4],[3/7, -4/9, 5]]").unwrap();
290 let c: MatQ = &a - &b;
291 assert_eq!(c, MatQ::from_str("[[0, -1, 5/4],[0, 64/63, -10]]").unwrap());
292 }
293
294 #[test]
296 fn sub_first_borrowed() {
297 let a: MatQ = MatQ::from_str("[[1/2, 1, 2],[3/7, 4/7, -5]]").unwrap();
298 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/4],[3/7, -4/9, 5]]").unwrap();
299 let c: MatQ = &a - b;
300 assert_eq!(c, MatQ::from_str("[[0, -1, 5/4],[0, 64/63, -10]]").unwrap());
301 }
302
303 #[test]
305 fn sub_second_borrowed() {
306 let a: MatQ = MatQ::from_str("[[1/2, 1, 2],[3/7, 4/7, -5]]").unwrap();
307 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/4],[3/7, -4/9, 5]]").unwrap();
308 let c: MatQ = a - &b;
309 assert_eq!(c, MatQ::from_str("[[0, -1, 5/4],[0, 64/63, -10]]").unwrap());
310 }
311
312 #[test]
314 fn sub_large_numbers() {
315 let a: MatQ =
316 MatQ::from_str(&format!("[[1, 2, {}],[3, -4, {}]]", i64::MIN, u64::MAX)).unwrap();
317 let b: MatQ =
318 MatQ::from_str(&format!("[[1, 1, {}],[3, 9, 1/{}]]", i64::MAX, i64::MAX)).unwrap();
319 let c: MatQ = a - &b;
320 assert_eq!(
321 c,
322 MatQ::from_str(&format!(
323 "[[0, 1, -{}],[0, -13, {}]]",
324 u64::MAX,
325 Q::from(u64::MAX) - Q::from((1, i64::MAX))
326 ))
327 .unwrap()
328 );
329 }
330
331 #[test]
333 fn sub_safe() {
334 let a: MatQ = MatQ::from_str("[[1/2, 1, 2],[3/7, 4/7, -5]]").unwrap();
335 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/4],[3/7, -4/9, 5]]").unwrap();
336 let c: MatQ = a.sub_safe(&b).unwrap();
337 assert_eq!(c, MatQ::from_str("[[0, -1, 5/4],[0, 64/63, -10]]").unwrap());
338 }
339
340 #[test]
342 fn sub_safe_is_err() {
343 let a: MatQ = MatQ::from_str("[[1, 2],[3, 4]]").unwrap();
344 let b: MatQ = MatQ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
345 let c: MatQ = MatQ::from_str("[[1, 2, 3]]").unwrap();
346 assert!(a.sub_safe(&b).is_err());
347 assert!(c.sub_safe(&b).is_err());
348 }
349
350 #[test]
352 fn availability() {
353 let a = MatQ::new(2, 2);
354 let b = MatZ::new(2, 2);
355 let c = MatQ::new(2, 2);
356
357 let _ = &a - &b;
358 let _ = &a - b.clone();
359 let _ = a.clone() - &b;
360 let _ = a.clone() - b.clone();
361 let _ = &b - &a;
362 let _ = &b - a.clone();
363 let _ = b.clone() - &a;
364 let _ = b.clone() - a.clone();
365
366 let _ = &a - &c;
367 let _ = &a - c.clone();
368 let _ = a.clone() - &c;
369 let _ = a.clone() - c.clone();
370 let _ = &c - &a;
371 let _ = &c - a.clone();
372 let _ = c.clone() - &a;
373 let _ = c.clone() - a.clone();
374 }
375}
376
377#[cfg(test)]
378mod test_sub_matz {
379 use super::MatZ;
380 use crate::rational::{MatQ, Q};
381 use std::str::FromStr;
382
383 #[test]
385 fn small_numbers() {
386 let a = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
387 let b = MatQ::from_str("[[5, 1/2],[2, 10]]").unwrap();
388 let cmp = MatQ::from_str("[[4, -3/2],[-1, 6]]").unwrap();
389
390 let res = &b - &a;
391
392 assert_eq!(res, cmp);
393 }
394
395 #[test]
397 fn large_numbers() {
398 let a: MatZ = MatZ::from_str(&format!("[[1, 1, {}],[3, 9, 4]]", i64::MIN)).unwrap();
399 let b = MatQ::from_str(&format!("[[1, 2, 1/{}],[3, -4, 5]]", i64::MAX)).unwrap();
400
401 let c = &b - a;
402
403 assert_eq!(
404 c,
405 MatQ::from_str(&format!(
406 "[[0, 1, {}],[0, -13, 1]]",
407 Q::from((1, i64::MAX)) - Q::from((i64::MIN, 1))
408 ))
409 .unwrap()
410 );
411 }
412
413 #[test]
415 fn available() {
416 let a = MatZ::new(2, 2);
417 let b = MatQ::new(2, 2);
418
419 let _ = &b - &a;
420 let _ = &b - a.clone();
421 let _ = b.clone() - &a;
422 let _ = b.clone() - a.clone();
423 }
424
425 #[test]
427 #[should_panic]
428 fn mismatching_rows() {
429 let a = MatZ::new(3, 2);
430 let b = MatQ::new(2, 2);
431
432 let _ = &b - &a;
433 }
434
435 #[test]
437 #[should_panic]
438 fn mismatching_column() {
439 let a = MatZ::new(2, 3);
440 let b = MatQ::new(2, 2);
441
442 let _ = &b - &a;
443 }
444}