1use super::super::MatZ;
12use crate::error::MathError;
13use crate::macros::arithmetics::{
14 arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
15 arithmetic_trait_mixed_borrowed_owned,
16};
17use crate::traits::MatrixDimensions;
18use flint_sys::fmpz_mat::fmpz_mat_add;
19use std::ops::{Add, AddAssign};
20
21impl AddAssign<&MatZ> for MatZ {
22 fn add_assign(&mut self, other: &Self) {
41 if self.get_num_rows() != other.get_num_rows()
42 || self.get_num_columns() != other.get_num_columns()
43 {
44 panic!(
45 "Tried to add a '{}x{}' matrix and a '{}x{}' matrix.",
46 self.get_num_rows(),
47 self.get_num_columns(),
48 other.get_num_rows(),
49 other.get_num_columns()
50 );
51 }
52
53 unsafe { fmpz_mat_add(&mut self.matrix, &self.matrix, &other.matrix) };
54 }
55}
56
57arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, MatZ, MatZ);
58
59impl Add for &MatZ {
60 type Output = MatZ;
61 fn add(self, other: Self) -> Self::Output {
86 self.add_safe(other).unwrap()
87 }
88}
89
90impl MatZ {
91 pub fn add_safe(&self, other: &Self) -> Result<MatZ, MathError> {
115 if self.get_num_rows() != other.get_num_rows()
116 || self.get_num_columns() != other.get_num_columns()
117 {
118 return Err(MathError::MismatchingMatrixDimension(format!(
119 "Tried to add a '{}x{}' matrix and a '{}x{}' matrix.",
120 self.get_num_rows(),
121 self.get_num_columns(),
122 other.get_num_rows(),
123 other.get_num_columns()
124 )));
125 }
126 let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
127 unsafe {
128 fmpz_mat_add(&mut out.matrix, &self.matrix, &other.matrix);
129 }
130 Ok(out)
131 }
132}
133
134arithmetic_trait_borrowed_to_owned!(Add, add, MatZ, MatZ, MatZ);
135arithmetic_trait_mixed_borrowed_owned!(Add, add, MatZ, MatZ, MatZ);
136
137#[cfg(test)]
138mod test_add_assign {
139 use crate::integer::MatZ;
140 use std::str::FromStr;
141
142 #[test]
144 fn correct_small() {
145 let mut a = MatZ::identity(2, 2);
146 let b = MatZ::from_str("[[4, 5],[-6, -1]]").unwrap();
147 let cmp = MatZ::from_str("[[5, 5],[-6, 0]]").unwrap();
148
149 a += b;
150
151 assert_eq!(cmp, a);
152 }
153
154 #[test]
156 fn correct_large() {
157 let mut a = MatZ::from_str(&format!("[[{}, 5],[{}, -1]]", i64::MAX, i64::MIN)).unwrap();
158 let b = MatZ::from_str(&format!("[[{}, -6],[6, -1]]", i64::MAX)).unwrap();
159 let cmp = MatZ::from_str(&format!(
160 "[[{}, -1],[{}, -2]]",
161 2 * (i64::MAX as u64),
162 i64::MIN + 6
163 ))
164 .unwrap();
165
166 a += b;
167
168 assert_eq!(cmp, a);
169 }
170
171 #[test]
173 fn matrix_dimensions() {
174 let dimensions = [(3, 3), (5, 1), (1, 4)];
175
176 for (nr_rows, nr_cols) in dimensions {
177 let mut a = MatZ::new(nr_rows, nr_cols);
178 let b = MatZ::identity(nr_rows, nr_cols);
179
180 a += b;
181
182 assert_eq!(MatZ::identity(nr_rows, nr_cols), a);
183 }
184 }
185
186 #[test]
188 fn availability() {
189 let mut a = MatZ::new(2, 2);
190 let b = MatZ::new(2, 2);
191
192 a += &b;
193 a += b;
194 }
195}
196
197#[cfg(test)]
198mod test_add {
199 use super::MatZ;
200 use std::str::FromStr;
201
202 #[test]
204 fn add() {
205 let a: MatZ = MatZ::from_str("[[1, 2, 3],[3, 4, 5]]").unwrap();
206 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
207 let c: MatZ = a + b;
208 assert_eq!(c, MatZ::from_str("[[2, 4, 6],[6, 0, 10]]").unwrap());
209 }
210
211 #[test]
213 fn add_borrow() {
214 let a: MatZ = MatZ::from_str("[[1, 2, 3],[3, 4, 5]]").unwrap();
215 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
216 let c: MatZ = &a + &b;
217 assert_eq!(c, MatZ::from_str("[[2, 4, 6],[6, 0, 10]]").unwrap());
218 }
219
220 #[test]
222 fn add_first_borrowed() {
223 let a: MatZ = MatZ::from_str("[[1, 2, 3],[3, 4, 5]]").unwrap();
224 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
225 let c: MatZ = &a + b;
226 assert_eq!(c, MatZ::from_str("[[2, 4, 6],[6, 0, 10]]").unwrap());
227 }
228
229 #[test]
231 fn add_second_borrowed() {
232 let a: MatZ = MatZ::from_str("[[1, 2, 3],[3, 4, 5]]").unwrap();
233 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
234 let c: MatZ = a + &b;
235 assert_eq!(c, MatZ::from_str("[[2, 4, 6],[6, 0, 10]]").unwrap());
236 }
237
238 #[test]
240 fn add_large_numbers() {
241 let a: MatZ =
242 MatZ::from_str(&format!("[[1, 2, {}],[3, -4, {}]]", i64::MIN, i128::MAX)).unwrap();
243 let b: MatZ =
244 MatZ::from_str(&format!("[[1, 2, {}],[3, 9, {}]]", i64::MIN + 1, i128::MAX)).unwrap();
245 let c: MatZ = a + &b;
246 assert_eq!(
247 c,
248 MatZ::from_str(&format!(
249 "[[2, 4, -{}],[6, 5, {}]]",
250 u64::MAX,
251 u128::MAX - 1
252 ))
253 .unwrap()
254 );
255 }
256
257 #[test]
259 fn add_safe() {
260 let a: MatZ = MatZ::from_str("[[1, 2, 3],[3, 4, 5]]").unwrap();
261 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
262 let c = a.add_safe(&b);
263 assert_eq!(
264 c.unwrap(),
265 MatZ::from_str("[[2, 4, 6],[6, 0, 10]]").unwrap()
266 );
267 }
268
269 #[test]
271 fn add_safe_is_err() {
272 let a: MatZ = MatZ::from_str("[[1, 2],[3, 4]]").unwrap();
273 let b: MatZ = MatZ::from_str("[[1, 2, 3],[3, -4, 5]]").unwrap();
274 let c: MatZ = MatZ::from_str("[[1, 2, 3]]").unwrap();
275 assert!(a.add_safe(&b).is_err());
276 assert!(c.add_safe(&b).is_err());
277 }
278}