Skip to content

Add & Sub between MatQ & MatZ #489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions src/integer/mat_z/arithmetic/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use crate::macros::arithmetics::{
};
use crate::rational::MatQ;
use crate::traits::MatrixDimensions;
use flint_sys::fmpq_mat::fmpq_mat_sub;
use flint_sys::fmpz_mat::fmpz_mat_sub;
use flint_sys::fmpz_mod_mat::_fmpz_mod_mat_reduce;
use std::ops::Sub;
Expand Down Expand Up @@ -135,23 +134,9 @@ impl Sub<&MatQ> for &MatZ {
/// # Panics ...
/// - if the dimensions of both matrices mismatch.
fn sub(self, other: &MatQ) -> Self::Output {
if self.get_num_rows() != other.get_num_rows()
|| self.get_num_columns() != other.get_num_columns()
{
panic!(
"Tried to subtract a '{}x{}' matrix from a '{}x{}' matrix.",
other.get_num_rows(),
other.get_num_columns(),
self.get_num_rows(),
self.get_num_columns()
);
}
let new_self = MatQ::from(self);

let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
unsafe {
fmpq_mat_sub(&mut out.matrix, &MatQ::from(self).matrix, &other.matrix);
}
out
new_self.sub_safe(other).unwrap()
}
}

Expand Down
146 changes: 128 additions & 18 deletions src/rational/mat_q/arithmetic/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,13 @@

use super::super::MatQ;
use crate::error::MathError;
use crate::integer::{MatZ, Z};
use crate::integer::MatZ;
use crate::macros::arithmetics::{
arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
arithmetic_trait_mixed_borrowed_owned,
arithmetic_trait_mixed_borrowed_owned, arithmetic_trait_reverse,
};
use crate::traits::MatrixDimensions;
use flint_sys::fmpq_mat::{
fmpq_mat_add, fmpq_mat_get_fmpz_mat_matwise, fmpq_mat_set_fmpz_mat_div_fmpz,
};
use flint_sys::fmpz_mat::fmpz_mat_add;
use flint_sys::fmpq_mat::fmpq_mat_add;
use std::ops::{Add, AddAssign};

impl AddAssign<&MatQ> for MatQ {
Expand Down Expand Up @@ -75,12 +72,9 @@ impl AddAssign<&MatZ> for MatQ {
);
}

let mut num = MatZ::new(self.get_num_rows(), self.get_num_columns());
let mut den = Z::default();
let other = MatQ::from(other);
unsafe {
fmpq_mat_get_fmpz_mat_matwise(&mut num.matrix, &mut den.value, &self.matrix);
fmpz_mat_add(&mut num.matrix, &num.matrix, &other.matrix);
fmpq_mat_set_fmpz_mat_div_fmpz(&mut self.matrix, &num.matrix, &den.value);
fmpq_mat_add(&mut self.matrix, &self.matrix, &other.matrix);
}
}
}
Expand All @@ -103,13 +97,13 @@ impl Add for &MatQ {
/// use qfall_math::rational::MatQ;
/// use std::str::FromStr;
///
/// let a: MatQ = MatQ::from_str("[[1/2, 2/3, 3/4],[3/4, 4/5, 5/7]]").unwrap();
/// let b: MatQ = MatQ::from_str("[[1/4, 9/7, 3/7],[1, 0, 5]]").unwrap();
/// let a = MatQ::from_str("[[1/2, 2/3, 3/4],[3/4, 4/5, 5/7]]").unwrap();
/// let b = MatQ::from_str("[[1/4, 9/7, 3/7],[1, 0, 5]]").unwrap();
///
/// let c: MatQ = &a + &b;
/// let d: MatQ = a + b;
/// let e: MatQ = &c + d;
/// let f: MatQ = c + &e;
/// let d: MatQ = &a + &b;
/// let e: MatQ = &a + b;
/// let f: MatQ = d + &e;
/// let g: MatQ = e + f;
/// ```
///
/// # Panics ...
Expand All @@ -119,6 +113,46 @@ impl Add for &MatQ {
}
}

impl Add<&MatZ> for &MatQ {
type Output = MatQ;

/// Implements the [`Add`] trait for two [`MatQ`] values.
/// [`Add`] is implemented for any combination of [`MatQ`] and [`MatZ`].
///
/// Parameters:
/// - `other`: specifies the value to add to `self`
///
/// Returns the sum of both numbers as a [`MatQ`].
///
/// # Examples
/// ```
/// use qfall_math::{rational::MatQ, integer::MatZ};
/// use std::str::FromStr;
///
/// let a = MatQ::from_str("[[1/2, 2/3, 3/4],[3/4, 4/5, 5/7]]").unwrap();
/// let b = MatZ::identity(2, 3);
///
/// let d: MatQ = &a + &b;
/// let e: MatQ = a + &b;
/// let f: MatQ = &b + d;
/// let g: MatQ = b + f;
/// ```
///
/// # Panics ...
/// - if the dimensions of both matrices mismatch.
fn add(self, other: &MatZ) -> Self::Output {
let other = MatQ::from(other);

self.add_safe(&other).unwrap()
}
}

arithmetic_trait_borrowed_to_owned!(Add, add, MatQ, MatZ, MatQ);
arithmetic_trait_mixed_borrowed_owned!(Add, add, MatQ, MatZ, MatQ);
arithmetic_trait_reverse!(Add, add, MatZ, MatQ, MatQ);
arithmetic_trait_borrowed_to_owned!(Add, add, MatZ, MatQ, MatQ);
arithmetic_trait_mixed_borrowed_owned!(Add, add, MatZ, MatQ, MatQ);

impl MatQ {
/// Implements addition for two [`MatQ`] matrices.
///
Expand Down Expand Up @@ -236,10 +270,60 @@ mod test_add_assign {

#[cfg(test)]
mod test_add {
use super::MatQ;
use super::{MatQ, MatZ};
use crate::rational::Q;
use std::str::FromStr;

/// Ensure that `add` works for small numbers between [`MatZ`] and [`MatQ`].
#[test]
fn correct_small() {
let a = MatZ::identity(2, 2);
let b = MatQ::from_str("[[4/5, 5],[-6, -1]]").unwrap();
let c = a.clone();
let d = MatQ::from_str("[[4, -5/-1],[-6, -1]]").unwrap();
let cmp_0 = MatQ::from_str("[[9/5, 5],[-6, 0]]").unwrap();
let cmp_1 = MatQ::from_str("[[5, 5],[-6, 0]]").unwrap();

let res_0 = a + b;
println!("{}", res_0);
let res_1 = c + d;

assert_eq!(cmp_0, res_0);
assert_eq!(cmp_1, res_1);
}

/// Ensure that `add` works for large numbers between [`MatZ`] and [`MatQ`].
#[test]
fn correct_large() {
let a = MatQ::from_str(&format!("[[{}/1, 5/2],[{}, -1]]", i64::MAX, i64::MIN)).unwrap();
let b = MatZ::from_str(&format!("[[{}, -3],[6, -1]]", i64::MAX)).unwrap();
let cmp = MatQ::from_str(&format!(
"[[{}, -1/2],[{}, -2]]",
2 * (i64::MAX as u64),
i64::MIN + 6
))
.unwrap();

let c = a + b;

assert_eq!(cmp, c);
}

/// Ensure that `add` works for different matrix dimensions between [`MatZ`] and [`MatQ`].
#[test]
fn matrix_dimensions() {
let dimensions = [(3, 3), (5, 1), (1, 4)];

for (nr_rows, nr_cols) in dimensions {
let a = MatQ::new(nr_rows, nr_cols);
let b = MatQ::identity(nr_rows, nr_cols);

let c = a + b;

assert_eq!(MatQ::identity(nr_rows, nr_cols), c);
}
}

/// Testing addition for two [`MatQ`]
#[test]
fn add() {
Expand Down Expand Up @@ -320,4 +404,30 @@ mod test_add {
assert!(a.add_safe(&b).is_err());
assert!(c.add_safe(&b).is_err());
}

/// Ensure that `add` is available for all types between [`MatZ`] and [`MatQ`].
#[test]
fn availability() {
let a = MatQ::new(2, 2);
let b = MatZ::new(2, 2);
let c = MatQ::new(2, 2);

let _ = &a + &b;
let _ = &a + b.clone();
let _ = a.clone() + &b;
let _ = a.clone() + b.clone();
let _ = &b + &a;
let _ = &b + a.clone();
let _ = b.clone() + &a;
let _ = b.clone() + a.clone();

let _ = &a + &c;
let _ = &a + c.clone();
let _ = a.clone() + &c;
let _ = a.clone() + c.clone();
let _ = &c + &a;
let _ = &c + a.clone();
let _ = c.clone() + &a;
let _ = c.clone() + a.clone();
}
}
58 changes: 35 additions & 23 deletions src/rational/mat_q/arithmetic/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ use std::ops::Sub;

impl Sub for &MatQ {
type Output = MatQ;
/// Implements the [`Sub`] trait for two [`MatQ`] values.
/// Implements the [`Sub`] trait for two matrices.
/// [`Sub`] is implemented for any combination of [`MatQ`] and borrowed [`MatQ`].
///
/// Parameters:
/// - `other`: specifies the value to subtract from`self`
/// - `other`: specifies the value to subtract from `self`
///
/// Returns the result of the subtraction as a [`MatQ`].
///
Expand All @@ -36,10 +36,10 @@ impl Sub for &MatQ {
/// let a: MatQ = MatQ::from_str("[[1/2, 2/3, 3/4],[3/4, 4/5, 5/7]]").unwrap();
/// let b: MatQ = MatQ::from_str("[[1/4, 9/7, 3/7],[1, 0, 5]]").unwrap();
///
/// let c: MatQ = &a - &b;
/// let d: MatQ = a - b;
/// let e: MatQ = &c - d;
/// let f: MatQ = c - &e;
/// let d: MatQ = &a - &b;
/// let e: MatQ = a - b;
/// let f: MatQ = &d - e;
/// let g: MatQ = d - &f;
/// ```
///
/// # Panics ...
Expand Down Expand Up @@ -77,23 +77,9 @@ impl Sub<&MatZ> for &MatQ {
/// # Panics ...
/// - if the dimensions of both matrices mismatch.
fn sub(self, other: &MatZ) -> Self::Output {
if self.get_num_rows() != other.get_num_rows()
|| self.get_num_columns() != other.get_num_columns()
{
panic!(
"Tried to subtract a '{}x{}' matrix from a '{}x{}' matrix.",
other.get_num_rows(),
other.get_num_columns(),
self.get_num_rows(),
self.get_num_columns()
);
}
let other = MatQ::from(other);

let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
unsafe {
fmpq_mat_sub(&mut out.matrix, &self.matrix, &MatQ::from(other).matrix);
}
out
self.sub_safe(&other).unwrap()
}
}

Expand Down Expand Up @@ -150,7 +136,7 @@ arithmetic_trait_mixed_borrowed_owned!(Sub, sub, MatQ, MatQ, MatQ);
#[cfg(test)]
mod test_sub {
use super::MatQ;
use crate::rational::Q;
use crate::{integer::MatZ, rational::Q};
use std::str::FromStr;

/// Testing subtraction for two [`MatQ`]
Expand Down Expand Up @@ -226,6 +212,32 @@ mod test_sub {
assert!(a.sub_safe(&b).is_err());
assert!(c.sub_safe(&b).is_err());
}

/// Ensure that `sub` is available for all types between [`MatZ`] and [`MatQ`].
#[test]
fn availability() {
let a = MatQ::new(2, 2);
let b = MatZ::new(2, 2);
let c = MatQ::new(2, 2);

let _ = &a - &b;
let _ = &a - b.clone();
let _ = a.clone() - &b;
let _ = a.clone() - b.clone();
let _ = &b - &a;
let _ = &b - a.clone();
let _ = b.clone() - &a;
let _ = b.clone() - a.clone();

let _ = &a - &c;
let _ = &a - c.clone();
let _ = a.clone() - &c;
let _ = a.clone() - c.clone();
let _ = &c - &a;
let _ = &c - a.clone();
let _ = c.clone() - &a;
let _ = c.clone() - a.clone();
}
}

#[cfg(test)]
Expand Down
Loading