use super::super::MatPolyOverZ;
use crate::error::MathError;
use crate::macros::arithmetics::{
arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
arithmetic_trait_mixed_borrowed_owned,
};
use crate::traits::MatrixDimensions;
use flint_sys::fmpz_poly_mat::fmpz_poly_mat_add;
use std::ops::{Add, AddAssign};
impl AddAssign<&MatPolyOverZ> for MatPolyOverZ {
fn add_assign(&mut self, other: &Self) {
if self.get_num_rows() != other.get_num_rows()
|| self.get_num_columns() != other.get_num_columns()
{
panic!(
"Tried to add a '{}x{}' matrix and a '{}x{}' matrix.",
self.get_num_rows(),
self.get_num_columns(),
other.get_num_rows(),
other.get_num_columns()
);
}
unsafe { fmpz_poly_mat_add(&mut self.matrix, &self.matrix, &other.matrix) };
}
}
arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, MatPolyOverZ, MatPolyOverZ);
impl Add for &MatPolyOverZ {
type Output = MatPolyOverZ;
fn add(self, other: Self) -> Self::Output {
self.add_safe(other).unwrap()
}
}
impl MatPolyOverZ {
pub fn add_safe(&self, other: &Self) -> Result<MatPolyOverZ, MathError> {
if self.get_num_rows() != other.get_num_rows()
|| self.get_num_columns() != other.get_num_columns()
{
return Err(MathError::MismatchingMatrixDimension(format!(
"Tried to add a '{}x{}' matrix and a '{}x{}' matrix.",
self.get_num_rows(),
self.get_num_columns(),
other.get_num_rows(),
other.get_num_columns()
)));
}
let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
unsafe {
fmpz_poly_mat_add(&mut out.matrix, &self.matrix, &other.matrix);
}
Ok(out)
}
}
arithmetic_trait_borrowed_to_owned!(Add, add, MatPolyOverZ, MatPolyOverZ, MatPolyOverZ);
arithmetic_trait_mixed_borrowed_owned!(Add, add, MatPolyOverZ, MatPolyOverZ, MatPolyOverZ);
#[cfg(test)]
mod test_add_assign {
use crate::integer::MatPolyOverZ;
use std::str::FromStr;
#[test]
fn correct_small() {
let mut a = MatPolyOverZ::identity(2, 2);
let b = MatPolyOverZ::from_str("[[1 4, 2 1 5],[1 -6, 1 -1]]").unwrap();
let cmp = MatPolyOverZ::from_str("[[1 5, 2 1 5],[1 -6, 0]]").unwrap();
a += b;
assert_eq!(cmp, a);
}
#[test]
fn correct_large() {
let mut a =
MatPolyOverZ::from_str(&format!("[[1 {}, 2 0 2],[1 {}, 0]]", i64::MAX, i64::MIN))
.unwrap();
let b = MatPolyOverZ::from_str(&format!("[[1 {}, 1 1],[1 6, 1 3]]", i64::MAX)).unwrap();
let cmp = MatPolyOverZ::from_str(&format!(
"[[1 {}, 2 1 2],[1 {}, 1 3]]",
2 * (i64::MAX as u64),
i64::MIN + 6
))
.unwrap();
a += b;
assert_eq!(cmp, a);
}
#[test]
fn matrix_dimensions() {
let dimensions = [(3, 3), (5, 1), (1, 4)];
for (nr_rows, nr_cols) in dimensions {
let mut a = MatPolyOverZ::new(nr_rows, nr_cols);
let b = MatPolyOverZ::identity(nr_rows, nr_cols);
a += b;
assert_eq!(MatPolyOverZ::identity(nr_rows, nr_cols), a);
}
}
#[test]
fn availability() {
let mut a = MatPolyOverZ::new(2, 2);
let b = MatPolyOverZ::new(2, 2);
a += &b;
a += b;
}
}
#[cfg(test)]
mod test_add {
use super::MatPolyOverZ;
use std::str::FromStr;
#[test]
fn add() {
let a: MatPolyOverZ =
MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
let b: MatPolyOverZ =
MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
let c: MatPolyOverZ = a + b;
assert_eq!(
c,
MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
.unwrap()
);
}
#[test]
fn add_borrow() {
let a: MatPolyOverZ =
MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
let b: MatPolyOverZ =
MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
let c: MatPolyOverZ = &a + &b;
assert_eq!(
c,
MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
.unwrap()
);
}
#[test]
fn add_first_borrowed() {
let a: MatPolyOverZ =
MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
let b: MatPolyOverZ =
MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
let c: MatPolyOverZ = &a + b;
assert_eq!(
c,
MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
.unwrap()
);
}
#[test]
fn add_second_borrowed() {
let a: MatPolyOverZ =
MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
let b: MatPolyOverZ =
MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
let c: MatPolyOverZ = a + &b;
assert_eq!(
c,
MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
.unwrap()
);
}
#[test]
fn add_large_numbers() {
let a: MatPolyOverZ = MatPolyOverZ::from_str(&format!(
"[[1 {}, 2 1 {}],[2 -{} 7, 0]]",
i64::MAX,
i64::MIN,
u64::MAX
))
.unwrap();
let b: MatPolyOverZ = MatPolyOverZ::from_str(&format!(
"[[1 {}, 2 1 {}],[2 {} 7, 0]]",
i64::MAX,
i64::MIN + 1,
i64::MAX
))
.unwrap();
let c: MatPolyOverZ = a + &b;
assert_eq!(
c,
MatPolyOverZ::from_str(&format!(
"[[1 {}, 2 2 -{}],[2 -{} 14, 0]]",
u64::MAX - 1,
u64::MAX,
(u64::MAX - 1) / 2 + 1
))
.unwrap()
);
}
#[test]
fn add_safe() {
let a: MatPolyOverZ =
MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
let b: MatPolyOverZ =
MatPolyOverZ::from_str("[[1 -42, 0, 2 24 42],[3 1 12 4, 1 -1, 1 17]]").unwrap();
let c: MatPolyOverZ = a.add_safe(&b).unwrap();
assert_eq!(
c,
MatPolyOverZ::from_str("[[1 -42, 1 42, 2 66 66],[3 18 36 46, 1 16, 1 59]]")
.unwrap()
);
}
#[test]
fn add_safe_is_err() {
let a: MatPolyOverZ =
MatPolyOverZ::from_str("[[0, 1 42, 2 42 24],[3 17 24 42, 1 17, 1 42]]").unwrap();
let b: MatPolyOverZ = MatPolyOverZ::from_str("[[1 -42, 0],[3 1 12 4, 1 17]]").unwrap();
let c: MatPolyOverZ = MatPolyOverZ::from_str("[[0, 1 42, 2 42 24]]").unwrap();
assert!(a.add_safe(&b).is_err());
assert!(c.add_safe(&b).is_err());
}
}