unitforge 0.3.17

A library for unit and quantity consistent computations in Rust
Documentation
#[cfg(test)]
mod matrix2_vector2_tests {
    use unitforge::small_linalg::{Matrix2, Vector2};

    #[test]
    fn test_matrix2_dot_vector2() {
        let m: Matrix2<f64> = Matrix2::from_f64([[2.0, 0.0], [0.0, 3.0]]);
        let v: Vector2<f64> = Vector2::from_f64([1.0, 2.0]);
        let result = m.dot(&v);
        assert_eq!(result, Vector2::from_f64([2.0, 6.0]));
    }
    #[test]
    fn test_matrix2_get_row_col() {
        let m: Matrix2<f64> = Matrix2::from_f64([[10.0, 20.0], [30.0, 40.0]]);
        assert_eq!(m.get_row(0), Vector2::from_f64([10.0, 20.0]));
        assert_eq!(m.get_column(1), Vector2::from_f64([20.0, 40.0]));
    }
}

#[cfg(test)]
mod matrix2x3_dot_tests {
    use unitforge::small_linalg::{Matrix2x3, Vector2, Vector3};
    use unitforge::{Force, ForceUnit, PhysicsQuantity};

    #[test]
    fn test_dot_vector3_direct() {
        let m: Matrix2x3<f64> = Matrix2x3::from_f64([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]);
        let v: Vector3<f64> = Vector3::from_f64([1.0, 1.0, 1.0]);
        let result = m.dot_vector3(&v);
        let expected = Vector2::from_f64([6.0, 15.0]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_mul_vector3_operator() {
        let m: Matrix2x3<f64> = Matrix2x3::from_f64([[2.0, 0.0, 1.0], [1.0, 3.0, 1.0]]);
        let v: Vector3<f64> = Vector3::from_f64([1.0, 2.0, 3.0]);
        let result = m * v;
        let expected = Vector2::from_f64([5.0, 10.0]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_dot_vector3_with_units() {
        let m: Matrix2x3<f64> = Matrix2x3::from_f64([[2.0, 1.0, 0.0], [0.0, 1.0, 3.0]]);
        let v = Vector3::new([
            Force::new(1.0, ForceUnit::N),
            Force::new(2.0, ForceUnit::N),
            Force::new(3.0, ForceUnit::N),
        ]);
        let result = m.dot_vector3(&v);
        let expected = Vector2::new([
            Force::new(4.0, ForceUnit::N),
            Force::new(11.0, ForceUnit::N),
        ]);
        assert_eq!(result, expected);
    }
}

#[cfg(test)]
mod matrix3_vector3_tests {
    use unitforge::small_linalg::{Matrix3, Vector3};
    use unitforge::{Area, Distance, Force, ForceUnit, PhysicsQuantity};

    #[test]
    fn test_vector_element_times_matrix3() {
        let mat = Matrix3::new([[3_f64; 3]; 3]);
        let f = Force::new(1., ForceUnit::kN);
        let res = f * mat;
        for i in 0..3 {
            for j in 0..3 {
                assert_eq!(res[(i, j)], Force::new(3., ForceUnit::kN))
            }
        }
    }

    #[test]
    fn test_matrix3_times_vector_element() {
        let mat = Matrix3::new([[3_f64; 3]; 3]);
        let f = Force::new(1., ForceUnit::kN);
        let res = mat * f;
        for i in 0..3 {
            for j in 0..3 {
                assert_eq!(res[(i, j)], Force::new(3., ForceUnit::kN))
            }
        }
    }

    #[test]
    fn test_matrix3_dot() {
        let mat: Matrix3<Distance> = Matrix3::from_f64([[4., 7., 2.], [0., 3., 9.], [5., 1., 3.]]);
        let v: Vector3<Distance> = Vector3::from_f64([2., 6., 5.]);
        let res = mat.dot(&v);
        let expected: Vector3<Area> = Vector3::from_f64([60., 63., 31.]);
        assert!((res - expected).norm().as_f64() < f64::EPSILON);
    }

    #[test]
    fn test_solve() {
        let matrix = Matrix3::new([[2.0, -1.0, 0.0], [-1.0, 2.0, -1.0], [0.0, -1.0, 2.0]]);
        let rhs = Vector3::new([1.0, 0.0, 1.0]);
        let solution = matrix.solve(&rhs);

        assert!(solution.is_some());
        let sol = solution.unwrap();

        assert!((matrix.dot(&sol) - rhs)
            .data
            .iter()
            .all(|&x| x.abs() < 1e-6));
    }

    #[test]
    fn test_qr_decomposition() {
        let a = Matrix3::new([[12.0, -51.0, 4.0], [6.0, 167.0, -68.0], [-4.0, 24.0, -41.0]]);

        let (q, r) = a.qr_decomposition();

        let identity = q.transpose() * q;
        let expected_identity = Matrix3::identity();
        for i in 0..3 {
            for j in 0..3 {
                assert!((identity[(i, j)] - expected_identity[(i, j)]).abs() < 1e-6);
            }
        }
        let recomposed = q * r;
        for i in 0..3 {
            for j in 0..3 {
                assert!((recomposed[(i, j)] - a[(i, j)]).abs() < 1e-6);
            }
        }
    }

    #[test]
    fn test_qr_eigenvalues() {
        let a = Matrix3::new([[4.0, -2.0, 1.0], [-2.0, 4.0, -2.0], [1.0, -2.0, 3.0]]);

        let eigen_pairs = a.qr_eigen(100, 1e-9);

        let expected_eigenvalues = [1.31260044, 2.56837289, 7.11902668];
        for (i, ev) in eigen_pairs.iter().enumerate() {
            assert!((ev.0 - expected_eigenvalues[i]).abs() < 1e-6);
        }
    }

    #[test]
    fn test_qr_eigenvectors() {
        let a = Matrix3::new([[4.0, -2.0, 1.0], [-2.0, 4.0, -2.0], [1.0, -2.0, 3.0]]);

        let eigen_pairs = a.qr_eigen(100, 1e-9);
        for i in 0..3 {
            let lambda = eigen_pairs[i].0;
            let v = eigen_pairs[i].1;
            let av = a.dot(&v);
            let expected = v * lambda;
            assert!((av - expected).norm() < 1e-6);
        }
    }

    #[test]
    fn test_get_column() {
        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.get_column(0).data, [1.0, 4.0, 7.0]);
        assert_eq!(matrix.get_column(1).data, [2.0, 5.0, 8.0]);
        assert_eq!(matrix.get_column(2).data, [3.0, 6.0, 9.0]);
    }

    #[test]
    fn test_set_column() {
        let mut matrix = Matrix3::zero();
        let column = Vector3::new([1.0, 2.0, 3.0]);
        matrix.set_column(1, column);

        assert_eq!(matrix[(0, 1)], 1.0);
        assert_eq!(matrix[(1, 1)], 2.0);
        assert_eq!(matrix[(2, 1)], 3.0);
    }

    #[test]
    fn test_get_row() {
        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.get_row(0), Vector3::new([1.0, 2.0, 3.0]));
        assert_eq!(matrix.get_row(1), Vector3::new([4.0, 5.0, 6.0]));
        assert_eq!(matrix.get_row(2), Vector3::new([7.0, 8.0, 9.0]));
    }

    #[test]
    fn test_set_row() {
        let mut matrix = Matrix3::zero();
        let row = Vector3::new([1.0, 2.0, 3.0]);
        matrix.set_row(1, row);

        assert_eq!(matrix[(1, 0)], 1.0);
        assert_eq!(matrix[(1, 1)], 2.0);
        assert_eq!(matrix[(1, 2)], 3.0);
    }

    #[test]
    fn test_from_rows() {
        let rows = [
            Vector3::new([1.0, 2.0, 3.0]),
            Vector3::new([4.0, 5.0, 6.0]),
            Vector3::new([7.0, 8.0, 9.0]),
        ];
        let matrix = Matrix3::from_rows(&rows);
        for i in 0..3 {
            assert!((matrix.get_row(i) - rows[i]).norm() < 1E-10);
        }
    }

    #[test]
    fn test_from_columns() {
        let columns = [
            Vector3::new([1.0, 4.0, 7.0]),
            Vector3::new([2.0, 5.0, 8.0]),
            Vector3::new([3.0, 6.0, 9.0]),
        ];
        let matrix = Matrix3::from_columns(&columns);
        for i in 0..3 {
            assert!((matrix.get_column(i) - columns[i]).norm() < 1E-10);
        }
    }

    #[test]
    fn test_matrix_multiplication() {
        let a = Matrix3::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
        let b = Matrix3::new([[9.0, 8.0, 7.0], [6.0, 5.0, 4.0], [3.0, 2.0, 1.0]]);
        let result = a * b;
        let expected = Matrix3::new([[30.0, 24.0, 18.0], [84.0, 69.0, 54.0], [138.0, 114.0, 90.0]]);
        for i in 0..3 {
            for j in 0..3 {
                assert_eq!(result[(i, j)], expected[(i, j)]);
            }
        }
    }
}

#[cfg(test)]
mod matrix3x2_dot_tests {
    use unitforge::small_linalg::{Matrix3x2, Vector2, Vector3};
    use unitforge::{Distance, DistanceUnit, PhysicsQuantity};

    #[test]
    fn test_dot_vector2_direct() {
        let m: Matrix3x2<f64> = Matrix3x2::from_f64([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]);
        let v: Vector2<f64> = Vector2::from_f64([1.0, 1.0]);
        let result = m.dot_vector2(&v);
        let expected = Vector3::from_f64([3.0, 7.0, 11.0]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_mul_vector2_operator() {
        let m: Matrix3x2<f64> = Matrix3x2::from_f64([[1.0, 0.0], [0.0, 1.0], [2.0, 2.0]]);
        let v: Vector2<f64> = Vector2::from_f64([2.0, 3.0]);
        let result = m * v;
        let expected = Vector3::from_f64([2.0, 3.0, 10.0]);
        assert_eq!(result, expected);
    }

    #[test]
    fn test_dot_vector2_with_units() {
        let m: Matrix3x2<f64> = Matrix3x2::from_f64([[1.0, 2.0], [0.0, 1.0], [3.0, 0.0]]);
        let v = Vector2::new([
            Distance::new(2.0, DistanceUnit::m),
            Distance::new(1.0, DistanceUnit::m),
        ]);
        let result = m.dot_vector2(&v);
        let expected = Vector3::new([
            Distance::new(4.0, DistanceUnit::m),
            Distance::new(1.0, DistanceUnit::m),
            Distance::new(6.0, DistanceUnit::m),
        ]);
        assert_eq!(result, expected);
    }
}

#[cfg(test)]
mod matrix3_mul_matrix3x2_tests {
    use unitforge::small_linalg::{Matrix3, Matrix3x2};

    #[test]
    fn test_matrix3_times_matrix3x2() {
        let a: Matrix3<f64> =
            Matrix3::from_f64([[1.0, 2.0, 3.0], [0.0, 1.0, 4.0], [5.0, 6.0, 0.0]]);
        let b: Matrix3x2<f64> = Matrix3x2::from_f64([[1.0, 2.0], [0.0, 1.0], [4.0, 0.0]]);

        let result = a * b;
        let expected = Matrix3x2::from_f64([[13.0, 4.0], [16.0, 1.0], [5.0, 16.0]]);

        assert_eq!(result, expected);
    }
}

#[cfg(test)]
mod matrix2_mul_matrix2x3_tests {
    use unitforge::small_linalg::{Matrix2, Matrix2x3};

    #[test]
    fn test_matrix2_times_matrix2x3() {
        let a: Matrix2<f64> = Matrix2::from_f64([[1.0, 2.0], [3.0, 4.0]]);
        let b: Matrix2x3<f64> = Matrix2x3::from_f64([[2.0, 0.0, 1.0], [1.0, 2.0, 3.0]]);

        let result = a * b;
        let expected = Matrix2x3::from_f64([[4.0, 4.0, 7.0], [10.0, 8.0, 15.0]]);

        assert_eq!(result, expected);
    }
}

#[cfg(test)]
mod matrix3x2_mul_matrix2x3_tests {
    use unitforge::small_linalg::{Matrix2x3, Matrix3, Matrix3x2};

    #[test]
    fn test_matrix3x2_times_matrix2x3() {
        let a: Matrix3x2<f64> = Matrix3x2::from_f64([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]);
        let b: Matrix2x3<f64> = Matrix2x3::from_f64([[7.0, 8.0, 9.0], [0.0, 1.0, 2.0]]);

        let result = a * b;
        let expected =
            Matrix3::from_f64([[7.0, 10.0, 13.0], [21.0, 28.0, 35.0], [35.0, 46.0, 57.0]]);

        assert_eq!(result, expected);
    }
}

#[cfg(test)]
mod matrix2x3_mul_matrix3x2_tests {
    use unitforge::small_linalg::{Matrix2, Matrix2x3, Matrix3x2};

    #[test]
    fn test_matrix2x3_times_matrix3x2() {
        let a: Matrix2x3<f64> = Matrix2x3::from_f64([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]);
        let b: Matrix3x2<f64> = Matrix3x2::from_f64([[7.0, 8.0], [9.0, 10.0], [11.0, 12.0]]);

        let result = a * b;
        let expected = Matrix2::from_f64([[58.0, 64.0], [139.0, 154.0]]);

        assert_eq!(result, expected);
    }
}