-
Notifications
You must be signed in to change notification settings - Fork 2
MatZ Mul, Cmp, Transpose #115
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
Changes from all commits
6f5fa12
439aab0
ffb150b
39d5cdc
3d7fd86
8281d0a
e59492f
9f5aa9e
58631ab
ecdd67d
f81caef
4c27d3d
b04df0d
1681eff
86c04e8
be011ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| // Copyright © 2023 Niklas Siemer | ||
| // | ||
| // This file is part of qFALL-math. | ||
| // | ||
| // qFALL-math is free software: you can redistribute it and/or modify it under | ||
| // the terms of the Mozilla Public License Version 2.0 as published by the | ||
| // Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>. | ||
|
|
||
| //! This module contains implementations for comparison of [`MatZ`]. | ||
|
|
||
| use super::MatZ; | ||
| use flint_sys::fmpz_mat::fmpz_mat_equal; | ||
|
|
||
| impl PartialEq for MatZ { | ||
| /// Checks if two [`MatZ`] instances are equal. Used by the `==` and `!=` operators. | ||
| /// | ||
| /// Parameters: | ||
| /// - `other`: the other value that is compare against `self` | ||
| /// | ||
| /// Returns `true` if the elements are equal, otherwise `false`. | ||
| /// | ||
| /// # Example | ||
| /// ``` | ||
| /// use math::integer::MatZ; | ||
| /// use std::str::FromStr; | ||
| /// | ||
| /// let a = MatZ::from_str("[[1,2],[3,4]]").unwrap(); | ||
| /// let b = MatZ::from_str("[[1,2],[2,4]]").unwrap(); | ||
| /// | ||
| /// // These are all equivalent and return false. | ||
| /// let compared: bool = (a == b); | ||
| /// # assert!(!compared); | ||
| /// let compared: bool = (&a == &b); | ||
| /// # assert!(!compared); | ||
| /// let compared: bool = (a.eq(&b)); | ||
| /// # assert!(!compared); | ||
| /// let compared: bool = (MatZ::eq(&a,&b)); | ||
| /// # assert!(!compared); | ||
| /// ``` | ||
| fn eq(&self, other: &Self) -> bool { | ||
| unsafe { fmpz_mat_equal(&self.matrix, &other.matrix) != 0 } | ||
| } | ||
| } | ||
|
|
||
| // With the [`Eq`] trait, `a == a` is always true. | ||
| // This is not guaranteed by the [`PartialEq`] trait. | ||
| impl Eq for MatZ {} | ||
|
|
||
| /// Test that the [`PartialEq`] trait is correctly implemented. | ||
| #[cfg(test)] | ||
| mod test_partial_eq { | ||
|
|
||
| use super::MatZ; | ||
| use std::str::FromStr; | ||
|
|
||
| /// Ensures that different instantiations do not break the equality between matrices | ||
| #[test] | ||
| fn equality_between_instantiations() { | ||
| let a = MatZ::from_str("[[0,1],[0,0]]").unwrap(); | ||
| let mut b = MatZ::new(2, 2).unwrap(); | ||
| b.set_entry(0, 1, 1).unwrap(); | ||
|
|
||
| assert_eq!(a, b); | ||
| } | ||
|
|
||
| /// Checks that large and small entries (and different points in storage) do not break equality | ||
| #[test] | ||
| fn equality_for_large_and_small_entries() { | ||
| let a = MatZ::from_str(&format!( | ||
| "[[{},{}, 1],[-10, 10, 0],[0, 1, -10]]", | ||
| i64::MIN, | ||
| i64::MAX | ||
| )) | ||
| .unwrap(); | ||
| let b = MatZ::from_str(&format!( | ||
| "[[{},{}, 1],[-10, 10, 0],[0, 1, -10]]", | ||
| i64::MIN, | ||
| i64::MAX | ||
| )) | ||
| .unwrap(); | ||
|
|
||
| assert_eq!(&a, &b); | ||
| } | ||
|
|
||
| /// Checks that different unequal matrices are unequal | ||
| #[test] | ||
| fn not_equal() { | ||
| let a = MatZ::from_str(&format!("[[{},{}],[-10, 10]]", i64::MIN, i64::MAX)).unwrap(); | ||
| let b = MatZ::from_str(&format!("[[0,{}],[-10, 10]]", i64::MAX)).unwrap(); | ||
| let c = MatZ::from_str(&format!("[[{},{}],[-10, 10],[0,0]]", i64::MIN, i64::MAX)).unwrap(); | ||
| let d = MatZ::from_str(&format!("[[{},{}]]", i64::MIN, i64::MAX)).unwrap(); | ||
| let e = MatZ::from_str("[[0]]").unwrap(); | ||
|
|
||
| assert_ne!(&a, &b); | ||
| assert_ne!(&a, &c); | ||
| assert_ne!(&a, &d); | ||
| assert_ne!(&a, &e); | ||
| assert_ne!(&b, &c); | ||
| assert_ne!(&b, &d); | ||
| assert_ne!(&b, &e); | ||
| assert_ne!(&c, &d); | ||
| assert_ne!(&c, &e); | ||
| assert_ne!(&d, &e); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| // Copyright © 2023 Niklas Siemer | ||
| // | ||
| // This file is part of qFALL-math. | ||
| // | ||
| // qFALL-math is free software: you can redistribute it and/or modify it under | ||
| // the terms of the Mozilla Public License Version 2.0 as published by the | ||
| // Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>. | ||
|
|
||
| //! Implementation of the [`Mul`] trait for [`MatZ`] values. | ||
|
|
||
| use super::MatZ; | ||
| use crate::{ | ||
| macros::arithmetics::{ | ||
| arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned, | ||
| }, | ||
| traits::{GetNumColumns, GetNumRows}, | ||
| }; | ||
| use flint_sys::fmpz_mat::fmpz_mat_mul; | ||
| use std::ops::Mul; | ||
|
|
||
| impl Mul for &MatZ { | ||
| type Output = MatZ; | ||
|
|
||
| /// Implements the [`Mul`] trait for two [`MatZ`] values. | ||
| /// | ||
| /// [`Mul`] is implemented for any combination of owned and borrowed [`MatZ`]. | ||
| /// | ||
| /// Parameters: | ||
| /// - `other`: specifies the value to multiply with `self` | ||
| /// | ||
| /// Returns the product of `self` and `other` as a [`MatZ`]. | ||
| /// | ||
| /// # Example | ||
| /// ``` | ||
| /// use math::integer::MatZ; | ||
| /// use std::str::FromStr; | ||
| /// | ||
| /// let a = MatZ::from_str("[[2,1],[1,2]]").unwrap(); | ||
| /// let b = MatZ::from_str("[[1,0],[0,1]]").unwrap(); | ||
| /// | ||
| /// let c = &a * &b; | ||
| /// let d = a * b; | ||
| /// let e = &c * d; | ||
| /// let f = c * &e; | ||
| /// ``` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Panics is missing
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
| /// | ||
| /// # Errors and Failures | ||
| /// - Panics if the dimensions of `self` and `other` do not match for multiplication. | ||
| fn mul(self, other: Self) -> Self::Output { | ||
| // TODO: mul_safe | ||
| if self.get_num_columns() != other.get_num_rows() { | ||
| panic!("Matrix dimensions do not match for matrix multiplication!"); | ||
| } | ||
Marvin-Beckmann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| let mut new = MatZ::new(self.get_num_rows(), other.get_num_columns()).unwrap(); | ||
| unsafe { fmpz_mat_mul(&mut new.matrix, &self.matrix, &other.matrix) }; | ||
| new | ||
| } | ||
| } | ||
|
|
||
| arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ); | ||
| arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ); | ||
Marvin-Beckmann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #[cfg(test)] | ||
| mod test_mul { | ||
|
|
||
| use super::MatZ; | ||
| use crate::integer::Z; | ||
| use std::str::FromStr; | ||
|
|
||
| /// Checks if matrix multiplication works fine for sqaured matrices | ||
| #[test] | ||
| fn square_correctness() { | ||
| let mat_1 = MatZ::from_str("[[2,1],[1,2]]").unwrap(); | ||
| let mat_2 = MatZ::from_str("[[1,0],[0,1]]").unwrap(); | ||
| let mat_3 = MatZ::from_str("[[1,2],[2,1]]").unwrap(); | ||
| let cmp = MatZ::from_str("[[4,5],[5,4]]").unwrap(); | ||
|
|
||
| assert_eq!(mat_1, &mat_1 * &mat_2); | ||
| assert_eq!(cmp, &mat_1 * &mat_3); | ||
| } | ||
|
|
||
| /// Checks if matrix multiplication works fine for matrices of different dimensions | ||
| #[test] | ||
| fn different_dimensions_correctness() { | ||
| let mat = MatZ::from_str("[[2,1],[1,2]]").unwrap(); | ||
| let vec = MatZ::from_str("[[1],[0]]").unwrap(); | ||
| let cmp = MatZ::from_str("[[2],[1]]").unwrap(); | ||
|
|
||
| assert_eq!(cmp, &mat * &vec); | ||
| } | ||
|
|
||
| /// Checks if matrix multiplication works fine for large entries | ||
| #[test] | ||
| fn large_entries() { | ||
| let mat = MatZ::from_str(&format!("[[{},1],[0,2]]", i64::MAX)).unwrap(); | ||
| let vec = MatZ::from_str(&format!("[[{}],[0]]", i64::MAX)).unwrap(); | ||
| let mut cmp = MatZ::new(2, 1).unwrap(); | ||
| let max: Z = i64::MAX.into(); | ||
| cmp.set_entry_ref_z(0, 0, &(&max * &max)).unwrap(); | ||
|
|
||
| assert_eq!(cmp, mat * vec); | ||
| } | ||
|
|
||
| /// Checks if matrix multiplication with incompatible matrix dimensions | ||
| /// results in panic | ||
| #[test] | ||
| #[should_panic] | ||
| fn incompatible_dimensions() { | ||
| let mat_1 = MatZ::from_str("[[2,1],[1,2]]").unwrap(); | ||
| let mat_2 = MatZ::from_str("[[1,0],[0,1],[0,0]]").unwrap(); | ||
|
|
||
| let _ = mat_1 * mat_2; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // Copyright © 2023 Niklas Siemer | ||
| // | ||
| // This file is part of qFALL-math. | ||
| // | ||
| // qFALL-math is free software: you can redistribute it and/or modify it under | ||
| // the terms of the Mozilla Public License Version 2.0 as published by the | ||
| // Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>. | ||
|
|
||
| //! This module containts the implementation of the `transpose` function. | ||
|
|
||
| use crate::traits::{GetNumColumns, GetNumRows}; | ||
|
|
||
| use super::MatZ; | ||
| use flint_sys::fmpz_mat::fmpz_mat_transpose; | ||
|
|
||
| impl MatZ { | ||
| /// Returns the transposed form of the given matrix, i.e. rows get transformed to columns | ||
| /// and vice versa. | ||
| /// | ||
| /// # Example | ||
| /// ``` | ||
| /// use math::integer::MatZ; | ||
| /// use std::str::FromStr; | ||
| /// | ||
| /// let mat = MatZ::from_str("[[2,1],[2,1],[2,1]]").unwrap(); | ||
| /// let cmp = MatZ::from_str("[[2,2,2],[1,1,1]]").unwrap(); | ||
| /// | ||
| /// assert_eq!(mat.transpose(), cmp); | ||
| /// ``` | ||
| pub fn transpose(&self) -> Self { | ||
| let mut out = Self::new(self.get_num_columns(), self.get_num_rows()).unwrap(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better use "expect" with a simple message that the number of rows or columns was saved wrongly.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we know that this can not fail, it's ok to use unwrap |
||
| unsafe { fmpz_mat_transpose(&mut out.matrix, &self.matrix) }; | ||
| out | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod test_transpose { | ||
|
|
||
| use super::MatZ; | ||
| use std::str::FromStr; | ||
|
|
||
| /// Checks if a row is correctly converted to a column | ||
| #[test] | ||
| fn row_to_column() { | ||
| let mat = MatZ::from_str("[[1],[2],[3]]").unwrap(); | ||
| let cmp = MatZ::from_str("[[1,2,3]]").unwrap(); | ||
|
|
||
| assert_eq!(cmp, mat.transpose()); | ||
| } | ||
|
|
||
| /// Checks if a column is correctly converted to a row | ||
| #[test] | ||
| fn column_to_row() { | ||
| let mat = MatZ::from_str("[[1,2,3]]").unwrap(); | ||
| let cmp = MatZ::from_str("[[1],[2],[3]]").unwrap(); | ||
|
|
||
| assert_eq!(cmp, mat.transpose()); | ||
| } | ||
Marvin-Beckmann marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// Checks if large, negative, and zero values are transposed correctly | ||
| #[test] | ||
| fn different_entry_values() { | ||
| let mat = MatZ::from_str(&format!("[[{},{},0]]", i64::MAX, i64::MIN)).unwrap(); | ||
| let cmp = MatZ::from_str(&format!("[[{}],[{}],[0]]", i64::MAX, i64::MIN)).unwrap(); | ||
|
|
||
| assert_eq!(cmp, mat.transpose()); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the tests are all 2x2 matrices, please also add one for different sizes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now one 3x3 test was included