1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use super::Matrix;
use crate::StrError;

/// Finds the maximum absolute difference between the components of two matrices
///
/// Returns (i,j,max_abs_diff)
///
/// ```text
/// max_abs_diff := max_ij ( |aᵢⱼ - bᵢⱼ| )
/// ```
///
/// # Warning
///
/// This function may be slow for large matrices.
///
/// # Example
///
/// ```
/// use russell_lab::{mat_max_abs_diff, Matrix, StrError};
/// use russell_chk::assert_approx_eq;
///
/// fn main() -> Result<(), StrError> {
///     let a = Matrix::from(&[
///         [ 10.0,  20.0],
///         [-10.0, -20.0],
///     ]);
///     let b = Matrix::from(&[
///         [ 10.0,  20.0],
///         [-10.0, -20.01],
///     ]);
///     let (i, j, max_abs_diff) = mat_max_abs_diff(&a, &b)?;
///     assert_eq!(i, 1);
///     assert_eq!(j, 1);
///     assert_approx_eq!(max_abs_diff, 0.01, 1e-14);
///     Ok(())
/// }
/// ```
pub fn mat_max_abs_diff(a: &Matrix, b: &Matrix) -> Result<(usize, usize, f64), StrError> {
    let (m, n) = a.dims();
    if b.nrow() != m || b.ncol() != n {
        return Err("matrices are incompatible");
    }
    let (mut i_found, mut j_found, mut max_abs_diff) = (0, 0, 0.0);
    for i in 0..m {
        for j in 0..n {
            let abs_diff = f64::abs(a[i][j] - b[i][j]);
            if abs_diff > max_abs_diff {
                i_found = i;
                j_found = j;
                max_abs_diff = abs_diff;
            }
        }
    }
    Ok((i_found, j_found, max_abs_diff))
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{mat_max_abs_diff, Matrix};
    use crate::StrError;

    #[test]
    fn mat_max_abs_diff_fail_on_wrong_dims() {
        let a_2x2 = Matrix::new(2, 2);
        let b_2x3 = Matrix::new(2, 3);
        let b_3x2 = Matrix::new(3, 2);
        assert_eq!(mat_max_abs_diff(&a_2x2, &b_2x3), Err("matrices are incompatible"));
        assert_eq!(mat_max_abs_diff(&a_2x2, &b_3x2), Err("matrices are incompatible"));
    }

    #[test]
    fn mat_max_abs_diff_works() -> Result<(), StrError> {
        #[rustfmt::skip]
        let a = Matrix::from(&[
            [1.0, 2.0, 3.0, 4.0],
            [1.0, 2.0, 3.0, 4.0],
        ]);
        #[rustfmt::skip]
        let b = Matrix::from(&[
            [0.5, 1.0, 1.5, 2.0],
            [0.5, 1.0, 1.5, -2.0],
        ]);
        let (i, j, max_abs_diff) = mat_max_abs_diff(&a, &b)?;
        assert_eq!(i, 1);
        assert_eq!(j, 3);
        assert_eq!(max_abs_diff, 6.0);
        Ok(())
    }
}