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, arithmetic_trait_reverse,
17};
18use crate::traits::MatrixDimensions;
19use flint_sys::fmpq_mat::fmpq_mat_add;
20use std::ops::{Add, AddAssign};
21
22impl AddAssign<&MatQ> for MatQ {
23 fn add_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 add 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_add(&mut self.matrix, &self.matrix, &other.matrix) };
60 }
61}
62impl AddAssign<&MatZ> for MatQ {
63 fn add_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 add 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_add(&mut self.matrix, &self.matrix, &other.matrix);
80 }
81 }
82}
83
84arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, MatQ, MatQ);
85arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, MatQ, MatZ);
86
87impl Add for &MatQ {
88 type Output = MatQ;
89 fn add(self, other: Self) -> Self::Output {
114 self.add_safe(other).unwrap()
115 }
116}
117
118impl Add<&MatZ> for &MatQ {
119 type Output = MatQ;
120
121 fn add(self, other: &MatZ) -> Self::Output {
146 let other = MatQ::from(other);
147
148 self.add_safe(&other).unwrap()
149 }
150}
151
152arithmetic_trait_borrowed_to_owned!(Add, add, MatQ, MatZ, MatQ);
153arithmetic_trait_mixed_borrowed_owned!(Add, add, MatQ, MatZ, MatQ);
154arithmetic_trait_reverse!(Add, add, MatZ, MatQ, MatQ);
155arithmetic_trait_borrowed_to_owned!(Add, add, MatZ, MatQ, MatQ);
156arithmetic_trait_mixed_borrowed_owned!(Add, add, MatZ, MatQ, MatQ);
157
158impl MatQ {
159 pub fn add_safe(&self, other: &Self) -> Result<MatQ, MathError> {
183 if self.get_num_rows() != other.get_num_rows()
184 || self.get_num_columns() != other.get_num_columns()
185 {
186 return Err(MathError::MismatchingMatrixDimension(format!(
187 "Tried to add a '{}x{}' matrix and a '{}x{}' matrix.",
188 self.get_num_rows(),
189 self.get_num_columns(),
190 other.get_num_rows(),
191 other.get_num_columns()
192 )));
193 }
194 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
195 unsafe {
196 fmpq_mat_add(&mut out.matrix, &self.matrix, &other.matrix);
197 }
198 Ok(out)
199 }
200}
201
202arithmetic_trait_borrowed_to_owned!(Add, add, MatQ, MatQ, MatQ);
203arithmetic_trait_mixed_borrowed_owned!(Add, add, MatQ, MatQ, MatQ);
204
205#[cfg(test)]
206mod test_add_assign {
207 use crate::{integer::MatZ, rational::MatQ};
208 use std::str::FromStr;
209
210 #[test]
212 fn correct_small() {
213 let mut a = MatQ::identity(2, 2);
214 let b = MatQ::from_str("[[4/5, 5],[-6, -1]]").unwrap();
215 let mut c = a.clone();
216 let d = MatZ::from_str("[[4, 5],[-6, -1]]").unwrap();
217 let cmp_0 = MatQ::from_str("[[9/5, 5],[-6, 0]]").unwrap();
218 let cmp_1 = MatQ::from_str("[[5, 5],[-6, 0]]").unwrap();
219
220 a += b;
221 c += d;
222
223 assert_eq!(cmp_0, a);
224 assert_eq!(cmp_1, c);
225 }
226
227 #[test]
229 fn correct_large() {
230 let mut a = MatQ::from_str(&format!("[[{}/1, 5/2],[{}, -1]]", i64::MAX, i64::MIN)).unwrap();
231 let b = MatQ::from_str(&format!("[[{}, -6/2],[6, -1]]", i64::MAX)).unwrap();
232 let cmp = MatQ::from_str(&format!(
233 "[[{}, -1/2],[{}, -2]]",
234 2 * (i64::MAX as u64),
235 i64::MIN + 6
236 ))
237 .unwrap();
238
239 a += b;
240
241 assert_eq!(cmp, a);
242 }
243
244 #[test]
246 fn matrix_dimensions() {
247 let dimensions = [(3, 3), (5, 1), (1, 4)];
248
249 for (nr_rows, nr_cols) in dimensions {
250 let mut a = MatQ::new(nr_rows, nr_cols);
251 let b = MatQ::identity(nr_rows, nr_cols);
252
253 a += b;
254
255 assert_eq!(MatQ::identity(nr_rows, nr_cols), a);
256 }
257 }
258
259 #[test]
261 fn availability() {
262 let mut a = MatQ::new(2, 2);
263 let b = MatQ::new(2, 2);
264 let c = MatZ::new(2, 2);
265
266 a += &b;
267 a += b;
268 a += &c;
269 a += c;
270 }
271}
272
273#[cfg(test)]
274mod test_add {
275 use super::{MatQ, MatZ};
276 use crate::rational::Q;
277 use std::str::FromStr;
278
279 #[test]
281 fn correct_small() {
282 let a = MatZ::identity(2, 2);
283 let b = MatQ::from_str("[[4/5, 5],[-6, -1]]").unwrap();
284 let c = a.clone();
285 let d = MatQ::from_str("[[4, -5/-1],[-6, -1]]").unwrap();
286 let cmp_0 = MatQ::from_str("[[9/5, 5],[-6, 0]]").unwrap();
287 let cmp_1 = MatQ::from_str("[[5, 5],[-6, 0]]").unwrap();
288
289 let res_0 = a + b;
290 let res_1 = c + d;
291
292 assert_eq!(cmp_0, res_0);
293 assert_eq!(cmp_1, res_1);
294 }
295
296 #[test]
298 fn correct_large() {
299 let a = MatQ::from_str(&format!("[[{}/1, 5/2],[{}, -1]]", i64::MAX, i64::MIN)).unwrap();
300 let b = MatZ::from_str(&format!("[[{}, -3],[6, -1]]", i64::MAX)).unwrap();
301 let cmp = MatQ::from_str(&format!(
302 "[[{}, -1/2],[{}, -2]]",
303 2 * (i64::MAX as u64),
304 i64::MIN + 6
305 ))
306 .unwrap();
307
308 let c = a + b;
309
310 assert_eq!(cmp, c);
311 }
312
313 #[test]
315 fn matrix_dimensions() {
316 let dimensions = [(3, 3), (5, 1), (1, 4)];
317
318 for (nr_rows, nr_cols) in dimensions {
319 let a = MatQ::new(nr_rows, nr_cols);
320 let b = MatQ::identity(nr_rows, nr_cols);
321
322 let c = a + b;
323
324 assert_eq!(MatQ::identity(nr_rows, nr_cols), c);
325 }
326 }
327
328 #[test]
330 fn add() {
331 let a: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, 4/7, 5/7]]").unwrap();
332 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, -4/7, 5/7]]").unwrap();
333 let c: MatQ = a + b;
334 assert_eq!(c, MatQ::from_str("[[1, 4, 3],[6/7, 0, 10/7]]").unwrap());
335 }
336
337 #[test]
339 fn add_borrow() {
340 let a: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, 4/7, 5/7]]").unwrap();
341 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, -4/7, 5/7]]").unwrap();
342 let c: MatQ = &a + &b;
343 assert_eq!(c, MatQ::from_str("[[1, 4, 3],[6/7, 0, 10/7]]").unwrap());
344 }
345
346 #[test]
348 fn add_first_borrowed() {
349 let a: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, 4/7, 5/7]]").unwrap();
350 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, -4/7, 5/7]]").unwrap();
351 let c: MatQ = &a + b;
352 assert_eq!(c, MatQ::from_str("[[1, 4, 3],[6/7, 0, 10/7]]").unwrap());
353 }
354
355 #[test]
357 fn add_second_borrowed() {
358 let a: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, 4/7, 5/7]]").unwrap();
359 let b: MatQ = MatQ::from_str("[[1/2, 2, 3/2],[3/7, -4/7, 5/7]]").unwrap();
360 let c: MatQ = a + &b;
361 assert_eq!(c, MatQ::from_str("[[1, 4, 3],[6/7, 0, 10/7]]").unwrap());
362 }
363
364 #[test]
366 fn add_large_numbers() {
367 let a: MatQ =
368 MatQ::from_str(&format!("[[1, 2, {}],[3, -4, {}]]", i64::MIN, i64::MAX)).unwrap();
369 let b: MatQ = MatQ::from_str(&format!(
370 "[[1, 2, {}],[3, 9, 1/{}]]",
371 i64::MIN + 1,
372 i64::MAX
373 ))
374 .unwrap();
375 let c: MatQ = a + &b;
376 assert_eq!(
377 c,
378 MatQ::from_str(&format!(
379 "[[2, 4, -{}],[6, 5, {}]]",
380 u64::MAX,
381 Q::from(i64::MAX) + Q::from((1, i64::MAX))
382 ))
383 .unwrap()
384 );
385 }
386
387 #[test]
389 fn add_safe() {
390 let a: MatQ = MatQ::from_str("[[1/9, 2/8, 3/4],[3, 4, 5]]").unwrap();
391 let b: MatQ = MatQ::from_str("[[1/9, 2/8, 3/4],[3, -4, 5]]").unwrap();
392 let c = a.add_safe(&b);
393 assert_eq!(
394 c.unwrap(),
395 MatQ::from_str("[[2/9, 4/8, 6/4],[6, 0, 10]]").unwrap()
396 );
397 }
398
399 #[test]
401 fn add_safe_is_err() {
402 let a: MatQ = MatQ::from_str("[[1, 2/7],[3/1912, 4]]").unwrap();
403 let b: MatQ = MatQ::from_str("[[1, 5/2, 0],[3, -4/6, 7/5]]").unwrap();
404 let c: MatQ = MatQ::from_str("[[1, -2/9, 3/7]]").unwrap();
405 assert!(a.add_safe(&b).is_err());
406 assert!(c.add_safe(&b).is_err());
407 }
408
409 #[test]
411 fn availability() {
412 let a = MatQ::new(2, 2);
413 let b = MatZ::new(2, 2);
414 let c = MatQ::new(2, 2);
415
416 let _ = &a + &b;
417 let _ = &a + b.clone();
418 let _ = a.clone() + &b;
419 let _ = a.clone() + b.clone();
420 let _ = &b + &a;
421 let _ = &b + a.clone();
422 let _ = b.clone() + &a;
423 let _ = b.clone() + a.clone();
424
425 let _ = &a + &c;
426 let _ = &a + c.clone();
427 let _ = a.clone() + &c;
428 let _ = a.clone() + c.clone();
429 let _ = &c + &a;
430 let _ = &c + a.clone();
431 let _ = c.clone() + &a;
432 let _ = c.clone() + a.clone();
433 }
434}