unitforge 0.4.1

A library for unit and quantity consistent computations in Rust
Documentation
#[cfg(test)]
mod matrix3_tests {
    pub fn approx_eq(a: f64, b: f64, epsilon: f64) -> bool {
        (a - b).abs() < epsilon
    }
    use unitforge::quantities::*;
    use unitforge::small_linalg::{Matrix3, Vector3};
    use unitforge::PhysicsQuantity;
    #[test]
    fn test_new() {
        let matrix = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        assert_eq!(matrix[(0, 0)], 1.0);
        assert_eq!(matrix[(2, 2)], 9.0);
    }

    #[test]
    fn test_zero() {
        let matrix: Matrix3<f64> = Matrix3::zero();
        assert_eq!(matrix[(0, 0)], 0_f64);
        assert_eq!(matrix[(0, 1)], 0_f64);
        assert_eq!(matrix[(0, 2)], 0_f64);
        assert_eq!(matrix[(0, 0)], 0_f64);
        assert_eq!(matrix[(1, 1)], 0_f64);
        assert_eq!(matrix[(2, 2)], 0_f64);
        assert_eq!(matrix[(0, 0)], 0_f64);
        assert_eq!(matrix[(1, 1)], 0_f64);
        assert_eq!(matrix[(2, 2)], 0_f64);
    }

    #[test]
    fn test_index() {
        let matrix = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        assert_eq!(matrix[(0, 0)], 1.0);
        assert_eq!(matrix[(1, 1)], 5.0);
        assert_eq!(matrix[(2, 2)], 9.0);
    }

    #[test]
    fn test_index_mut() {
        let mut matrix = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        matrix[(0, 0)] = 10.0;
        matrix[(2, 2)] = 100.0;
        assert_eq!(matrix[(0, 0)], 10.0);
        assert_eq!(matrix[(2, 2)], 100.0);
    }

    #[test]
    fn test_det() {
        let matrix1 = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        assert_eq!(matrix1.det(), 0.0); // This matrix is singular, so determinant should be 0

        let matrix2 = Matrix3::new([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]);
        assert_eq!(matrix2.det(), 1.0); // Identity matrix, determinant should be 1

        let matrix3: Matrix3<Distance> =
            Matrix3::from_f64([[6.0, 1.0, 1.0], [4.0, -2.0, 5.0], [2.0, 8.0, 7.0]]);
        let deviation = (matrix3.det() - Volume::new(-306.0, VolumeUnit::mcb)).abs();
        assert!(deviation.get_power() < -10);
    }

    #[test]
    fn test_inverse() {
        let matrix1 = Matrix3::new([[1.0, 2.0, 3.0], [0.0, 1.0, 4.0], [5.0, 6.0, 0.0]]);
        let expected_inv1 =
            Matrix3::new([[-24.0, 18.0, 5.0], [20.0, -15.0, -4.0], [-5.0, 4.0, 1.0]]);
        assert_eq!(matrix1.inverse(), Some(expected_inv1));

        let matrix2 = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        assert_eq!(matrix2.inverse(), None); // This matrix is singular, so no inverse exists
    }

    #[test]
    fn test_inverse_distance() {
        let d = Distance::new(2., DistanceUnit::mm);
        let a = d * d;
        let v = d * d * d;
        let inverse_distance = a / v;
        assert!(approx_eq(
            inverse_distance.to(InverseDistanceUnit::_m),
            500.,
            10E-10
        ));

        let matrix1: Matrix3<Distance> =
            Matrix3::from_f64([[1.0, 2.0, 3.0], [0.0, 1.0, 4.0], [5.0, 6.0, 0.0]]);
        let expected_inv1: Matrix3<InverseDistance> =
            Matrix3::from_f64([[-24.0, 18.0, 5.0], [20.0, -15.0, -4.0], [-5.0, 4.0, 1.0]]);
        let inv = matrix1.inverse().unwrap();
        let diff = (expected_inv1 - inv).frobenius_norm();
        assert!(diff.get_power() < -12);
    }

    #[test]
    fn test_inverse_singular_large_exponents_returns_none() {
        let huge = Distance::from_exponential(1.0, i32::MAX / 2);
        let zero = Distance::from_raw(0.0);
        let one = Distance::from_raw(1.0);
        let matrix: Matrix3<Distance> =
            Matrix3::new([[one, zero, zero], [zero, huge, huge], [zero, huge, huge]]);

        let inverse: Option<Matrix3<InverseDistance>> = matrix.inverse();
        assert_eq!(inverse, None);
    }

    #[test]
    fn test_dot() {
        let matrix = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        let vector = Vector3::new([1.0, 0.0, -1.0]);
        let result = matrix.dot(&vector);
        assert_eq!(result, Vector3::new([-2.0, -2.0, -2.0]));
    }

    #[test]
    fn test_add_matrix3() {
        let mat1 = Matrix3::new([[1_f64; 3]; 3]);
        let mat2 = Matrix3::new([[2_f64; 3]; 3]);
        let result = mat1 + mat2;
        let expected = Matrix3::new([[3_f64; 3]; 3]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_sub_matrix3() {
        let mat1 = Matrix3::new([[3_f64; 3]; 3]);
        let mat2 = Matrix3::new([[2_f64; 3]; 3]);
        let result = mat1 - mat2;
        let expected = Matrix3::new([[1_f64; 3]; 3]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_add_assign_matrix3() {
        let mut mat1 = Matrix3::new([[1_f64; 3]; 3]);
        let mat2 = Matrix3::new([[2_f64; 3]; 3]);
        mat1 += mat2;
        let expected = Matrix3::new([[3_f64; 3]; 3]);
        assert_eq!(mat1, expected);
    }

    #[test]
    fn test_sub_assign_matrix3() {
        let mut mat1 = Matrix3::new([[3_f64; 3]; 3]);
        let mat2 = Matrix3::new([[2_f64; 3]; 3]);
        mat1 -= mat2;
        let expected = Matrix3::new([[1_f64; 3]; 3]);
        assert_eq!(mat1, expected);
    }
}

#[cfg(test)]
mod test_ndarray_interface {
    use unitforge::small_linalg::Matrix3;

    #[test]
    fn test_transpose() {
        let matrix = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        let transposed = matrix.transpose();
        for i in 0..3 {
            for j in 0..3 {
                assert_eq!(matrix[(i, j)], transposed[(j, i)]);
            }
        }
    }

    #[test]
    fn test_abs() {
        let matrix = Matrix3::new([[-1.0, 2.0, -3.0], [4.0, -5.0, 6.0], [-7.0, 8.0, -9.0]]);
        let abs = matrix.abs();
        assert_eq!(
            abs,
            Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])
        );
    }

    #[cfg(test)]
    mod tests {
        use super::*;
        use ndarray::arr2;

        #[test]
        fn test_to_ndarray_matrix3() {
            let mat = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);

            let arr = mat.to_ndarray();
            assert_eq!(mat[(0, 0)], arr[[0, 0]]);
            assert_eq!(mat[(0, 1)], arr[[0, 1]]);
            assert_eq!(mat[(0, 2)], arr[[0, 2]]);
            assert_eq!(mat[(1, 0)], arr[[1, 0]]);
            assert_eq!(mat[(1, 1)], arr[[1, 1]]);
            assert_eq!(mat[(1, 2)], arr[[1, 2]]);
            assert_eq!(mat[(2, 0)], arr[[2, 0]]);
            assert_eq!(mat[(2, 1)], arr[[2, 1]]);
            assert_eq!(mat[(2, 2)], arr[[2, 2]]);
        }

        #[test]
        fn test_from_ndarray_matrix3() {
            let arr = arr2(&[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);

            let mat = Matrix3::from_ndarray(arr.view()).unwrap();
            assert_eq!(mat[(0, 0)], arr[[0, 0]]);
            assert_eq!(mat[(0, 1)], arr[[0, 1]]);
            assert_eq!(mat[(0, 2)], arr[[0, 2]]);
            assert_eq!(mat[(1, 0)], arr[[1, 0]]);
            assert_eq!(mat[(1, 1)], arr[[1, 1]]);
            assert_eq!(mat[(1, 2)], arr[[1, 2]]);
            assert_eq!(mat[(2, 0)], arr[[2, 0]]);
            assert_eq!(mat[(2, 1)], arr[[2, 1]]);
            assert_eq!(mat[(2, 2)], arr[[2, 2]]);
        }
    }
}