resopt 0.3.0

Declarative constrained residual optimization in Rust
Documentation
use crate::core::Error;

/// Dense row-major matrix.
#[derive(Debug, Clone, PartialEq)]
pub struct Matrix {
    nrows: usize,
    ncols: usize,
    data: Vec<f64>,
}

impl Matrix {
    /// Creates a matrix from row-major data.
    pub fn from_row_major(nrows: usize, ncols: usize, data: Vec<f64>) -> Result<Self, Error> {
        let expected = nrows * ncols;
        let got = data.len();

        if expected != got {
            return Err(Error::InvalidMatrixShape { expected, got });
        }

        Ok(Self { nrows, ncols, data })
    }

    /// Returns the number of rows.
    pub fn nrows(&self) -> usize {
        self.nrows
    }

    /// Returns the number of columns.
    pub fn ncols(&self) -> usize {
        self.ncols
    }

    /// Returns the underlying row-major coefficients.
    pub fn data(&self) -> &[f64] {
        &self.data
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::Error;

    #[test]
    fn from_row_major_valid() {
        let m = Matrix::from_row_major(2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
        assert_eq!(m.nrows(), 2);
        assert_eq!(m.ncols(), 3);
        assert_eq!(m.data(), &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
    }

    #[test]
    fn from_row_major_wrong_length() {
        let result = Matrix::from_row_major(2, 3, vec![1.0, 2.0]);
        assert_eq!(
            result.unwrap_err(),
            Error::InvalidMatrixShape {
                expected: 6,
                got: 2
            }
        );
    }

    #[test]
    fn zero_dimensions() {
        let m = Matrix::from_row_major(0, 0, vec![]).unwrap();
        assert_eq!(m.nrows(), 0);
        assert_eq!(m.ncols(), 0);
        assert!(m.data().is_empty());
    }

    #[test]
    fn single_element() {
        let m = Matrix::from_row_major(1, 1, vec![42.0]).unwrap();
        assert_eq!(m.data(), &[42.0]);
    }

    #[test]
    fn clone_and_eq() {
        let m = Matrix::from_row_major(2, 2, vec![1.0, 0.0, 0.0, 1.0]).unwrap();
        assert_eq!(m, m.clone());
    }
}