1use super::super::MatPolyOverZ;
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_poly_mat::fmpz_poly_mat_add;
19use std::ops::{Add, AddAssign};
20
21impl AddAssign<&MatPolyOverZ> for MatPolyOverZ {
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_poly_mat_add(&mut self.matrix, &self.matrix, &other.matrix) };
54 }
55}
56
57arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, MatPolyOverZ, MatPolyOverZ);
58
59impl Add for &MatPolyOverZ {
60 type Output = MatPolyOverZ;
61 fn add(self, other: Self) -> Self::Output {
86 self.add_safe(other).unwrap()
87 }
88}
89
90impl MatPolyOverZ {
91 pub fn add_safe(&self, other: &Self) -> Result<MatPolyOverZ, MathError> {
116 if self.get_num_rows() != other.get_num_rows()
117 || self.get_num_columns() != other.get_num_columns()
118 {
119 return Err(MathError::MismatchingMatrixDimension(format!(
120 "Tried to add a '{}x{}' matrix and a '{}x{}' matrix.",
121 self.get_num_rows(),
122 self.get_num_columns(),
123 other.get_num_rows(),
124 other.get_num_columns()
125 )));
126 }
127 let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
128 unsafe {
129 fmpz_poly_mat_add(&mut out.matrix, &self.matrix, &other.matrix);
130 }
131 Ok(out)
132 }
133}
134
135arithmetic_trait_borrowed_to_owned!(Add, add, MatPolyOverZ, MatPolyOverZ, MatPolyOverZ);
136arithmetic_trait_mixed_borrowed_owned!(Add, add, MatPolyOverZ, MatPolyOverZ, MatPolyOverZ);
137
138#[cfg(test)]
139mod test_add_assign {
140 use crate::integer::MatPolyOverZ;
141 use std::str::FromStr;
142
143 #[test]
145 fn correct_small() {
146 let mut a = MatPolyOverZ::identity(2, 2);
147 let b = MatPolyOverZ::from_str("[[1 4, 2 1 5],[1 -6, 1 -1]]").unwrap();
148 let cmp = MatPolyOverZ::from_str("[[1 5, 2 1 5],[1 -6, 0]]").unwrap();
149
150 a += b;
151
152 assert_eq!(cmp, a);
153 }
154
155 #[test]
157 fn correct_large() {
158 let mut a =
159 MatPolyOverZ::from_str(&format!("[[1 {}, 2 0 2],[1 {}, 0]]", i64::MAX, i64::MIN))
160 .unwrap();
161 let b = MatPolyOverZ::from_str(&format!("[[1 {}, 1 1],[1 6, 1 3]]", i64::MAX)).unwrap();
162 let cmp = MatPolyOverZ::from_str(&format!(
163 "[[1 {}, 2 1 2],[1 {}, 1 3]]",
164 2 * (i64::MAX as u64),
165 i64::MIN + 6
166 ))
167 .unwrap();
168
169 a += b;
170
171 assert_eq!(cmp, a);
172 }
173
174 #[test]
176 fn matrix_dimensions() {
177 let dimensions = [(3, 3), (5, 1), (1, 4)];
178
179 for (nr_rows, nr_cols) in dimensions {
180 let mut a = MatPolyOverZ::new(nr_rows, nr_cols);
181 let b = MatPolyOverZ::identity(nr_rows, nr_cols);
182
183 a += b;
184
185 assert_eq!(MatPolyOverZ::identity(nr_rows, nr_cols), a);
186 }
187 }
188
189 #[test]
191 fn availability() {
192 let mut a = MatPolyOverZ::new(2, 2);
193 let b = MatPolyOverZ::new(2, 2);
194
195 a += &b;
196 a += b;
197 }
198}
199
200#[cfg(test)]
201mod test_add {
202 use super::MatPolyOverZ;
203 use std::str::FromStr;
204
205 #[test]
207 fn add() {
208 let a: MatPolyOverZ =
209 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
210 let b: MatPolyOverZ =
211 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
212
213 let c: MatPolyOverZ = a + b;
214 assert_eq!(
215 c,
216 MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
217 .unwrap()
218 );
219 }
220
221 #[test]
223 fn add_borrow() {
224 let a: MatPolyOverZ =
225 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
226 let b: MatPolyOverZ =
227 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
228
229 let c: MatPolyOverZ = &a + &b;
230 assert_eq!(
231 c,
232 MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
233 .unwrap()
234 );
235 }
236
237 #[test]
239 fn add_first_borrowed() {
240 let a: MatPolyOverZ =
241 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
242 let b: MatPolyOverZ =
243 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
244
245 let c: MatPolyOverZ = &a + b;
246 assert_eq!(
247 c,
248 MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
249 .unwrap()
250 );
251 }
252
253 #[test]
255 fn add_second_borrowed() {
256 let a: MatPolyOverZ =
257 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
258 let b: MatPolyOverZ =
259 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
260
261 let c: MatPolyOverZ = a + &b;
262 assert_eq!(
263 c,
264 MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
265 .unwrap()
266 );
267 }
268
269 #[test]
271 fn add_large_numbers() {
272 let a: MatPolyOverZ = MatPolyOverZ::from_str(&format!(
273 "[[1 {}, 2 1 {}],[2 -{} 7, 0]]",
274 i64::MAX,
275 i64::MIN,
276 u64::MAX
277 ))
278 .unwrap();
279 let b: MatPolyOverZ = MatPolyOverZ::from_str(&format!(
280 "[[1 {}, 2 1 {}],[2 {} 7, 0]]",
281 i64::MAX,
282 i64::MIN + 1,
283 i64::MAX
284 ))
285 .unwrap();
286 let c: MatPolyOverZ = a + &b;
287 assert_eq!(
288 c,
289 MatPolyOverZ::from_str(&format!(
290 "[[1 {}, 2 2 -{}],[2 -{} 14, 0]]",
291 u64::MAX - 1,
292 u64::MAX,
293 (u64::MAX - 1) / 2 + 1
294 ))
295 .unwrap()
296 );
297 }
298
299 #[test]
301 fn add_safe() {
302 let a: MatPolyOverZ =
303 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
304 let b: MatPolyOverZ =
305 MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
306
307 let c: MatPolyOverZ = a.add_safe(&b).unwrap();
308 assert_eq!(
309 c,
310 MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
311 .unwrap()
312 );
313 }
314
315 #[test]
317 fn add_safe_is_err() {
318 let a: MatPolyOverZ =
319 MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
320 let b: MatPolyOverZ = MatPolyOverZ::from_str("[[1 -42, 0],[3 1 12 4, 1 17]]").unwrap();
321 let c: MatPolyOverZ = MatPolyOverZ::from_str("[[0, 1 42, 2 42 24]]").unwrap();
322 assert!(a.add_safe(&b).is_err());
323 assert!(c.add_safe(&b).is_err());
324 }
325}