Jarred Parr
Jarred Parr

Reputation: 1257

Type mismatch for std::op trait "Not"

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

Answers (1)

Francis Gagn&#233;
Francis Gagn&#233;

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

Related Questions