Reputation: 1257
I am implementing a general matrix solver. In doing so I make use of the "Not" operator to get around another issue which I'll explain below. However, when invoking the function in my tests, I get the following error:
error[E0271]: type mismatch resolving `<i32 as std::ops::Not>::Output == bool`
--> src/matrix.rs:223:15
|
90 | pub fn reduce<T>(mat: &mut Matrix<T>) -> Result<Matrix<T>, &'static str>
| ------
...
97 | + Not<Output = bool>
| ------------- required by this bound in `matrix::reduce`
...
223 | let res = reduce(&mut mat).unwrap();
| ^^^^^^ expected i32, found bool
error: aborting due to previous error
This is particularly confusing because I am not sure how else I would implement the Not
trait and have it function properly. When bool is the output type, it compiles just fine but seems to bark during execution.
Here's my code:
/// Performs a reduction operation on a given matrix, giving the reduced row echelon form
pub fn reduce<T>(mat: &mut Matrix<T>) -> Result<Matrix<T>, &'static str>
where
T: num_traits::Zero
+ num_traits::One
+ Mul<T, Output = T>
+ Add<T, Output = T>
+ Sub<T, Output = T>
+ Not<Output = bool>
+ Neg<Output = T>
+ Div<T, Output = T>
+ Copy,
{
let exchange = |matrix: &mut Matrix<T>, i: usize, j: usize| {
matrix.data.swap(i, j);
};
let scale = |matrix: &mut Matrix<T>, row: usize, factor: T| {
for i in 0..matrix.data[row].len() {
matrix.data[row][i] = matrix.data[row][i] * factor;
}
};
let row_replace = |matrix: &mut Matrix<T>, i: usize, j: usize, factor: T| {
for k in 0..matrix.data[j].len() {
matrix.data[j][k] = matrix.data[j][k] + (matrix.data[i][k] * factor);
}
};
// Reduction steps
let n = mat.data.len();
for i in 0..n {
// Find a pivot point
for j in i..n {
if !mat.data[j][i] { // <------- Error Here *********
if i != j {
exchange(mat, i, j);
break;
}
}
if j == n - 1 {
return Err("No pivot found")
}
}
// Put zeros below diagonal
for j in i + 1..n {
row_replace(mat, i, j, -mat.data[j][i] / mat.data[i][i]);
}
}
// Back substitution (bottom up)
for i in (0..n - 1).rev() {
for j in 0..i {
row_replace(mat, i, j, -mat.data[j][i] / mat.data[i][i]);
}
}
// Add 1's to the diagonal
for i in 0..n {
scale(mat, i, T::one() / mat.data[i][i]);
}
Ok(mat.clone())
}
#[test]
fn it_row_reduces() {
let mat = Matrix {
data: vec![vec![2, 1, 4], vec![1, 2, 5]],
nrows: 2,
ncols: 3,
};
let comp = Matrix {
data: vec![vec![1, 0, 1], vec![0, 1, 2]],
nrows: 2,
ncols: 3,
};
let res = reduce(&mut mat).unwrap();
assert_eq!(res.data, comp.data);
}
Originally, the code looked like the following:
if mat.data[j][i] != T::zero() {
if i != j {
exchange(mat, i, j);
break;
}
}
But it seems that even with the Not trait added to the function signature, this operation would never work, giving the following error:
binary operation `!=` cannot be applied to type `T`: T
I'm looking to figure out where I'm going wrong with this code and if my use of generics for this comparison is the most idiomatic way to do it in rust. Any additional feedback is appreciated. I can provide the struct as well, I just wanted to keep the question as brief as possible.
Upvotes: 0
Views: 80
Reputation: 65937
In Rust, !
serves as both logical NOT and bitwise NOT, depending on the argument type. It performs a logical NOT when the argument is a bool
and a bitwise NOT when the argument is an integer type. The only built-in type that implements Not<Output = bool>
is bool
.
You should stick to if mat.data[j][i] != T::zero() {
. !=
is provided by the PartialEq
trait. Instead of the T: Not<Output = bool>
bound, you'll want T: PartialEq<T>
or simply T: Eq
.
Upvotes: 2