Enhance matrix assertions for row and column operations to allow 0-row matrices with empty columns and improve error messages for index out of bounds.

This commit is contained in:
Palash Tyagi 2025-05-01 23:10:51 +01:00
parent 3c8b69d3ab
commit 38c5c28454

View File

@ -14,7 +14,11 @@ impl<T: Clone> Matrix<T> {
let cols = cols_data.len();
assert!(cols > 0, "need at least one column");
let rows = cols_data[0].len();
assert!(rows > 0, "need at least one row");
// Allow 0-row matrices if columns are empty, but not 0-col matrices if rows > 0
assert!(
rows > 0 || cols == 0,
"need at least one row if columns exist"
);
for (i, col) in cols_data.iter().enumerate().skip(1) {
assert!(
col.len() == rows,
@ -32,8 +36,14 @@ impl<T: Clone> Matrix<T> {
}
pub fn from_vec(data: Vec<T>, rows: usize, cols: usize) -> Self {
assert!(rows > 0, "need at least one row");
assert!(cols > 0, "need at least one column");
assert!(
rows > 0 || cols == 0,
"need at least one row if columns exist"
);
assert!(
cols > 0 || rows == 0,
"need at least one column if rows exist"
);
assert_eq!(data.len(), rows * cols, "data length mismatch");
Matrix { rows, cols, data }
}
@ -67,11 +77,23 @@ impl<T: Clone> Matrix<T> {
#[inline]
pub fn column(&self, c: usize) -> &[T] {
assert!(
c < self.cols,
"column index {} out of bounds for {} columns",
c,
self.cols
);
let start = c * self.rows;
&self.data[start..start + self.rows]
}
#[inline]
pub fn column_mut(&mut self, c: usize) -> &mut [T] {
assert!(
c < self.cols,
"column index {} out of bounds for {} columns",
c,
self.cols
);
let start = c * self.rows;
&mut self.data[start..start + self.rows]
}
@ -90,8 +112,16 @@ impl<T: Clone> Matrix<T> {
/// Swaps two columns in the matrix.
pub fn swap_columns(&mut self, c1: usize, c2: usize) {
assert!(
c1 < self.cols && c2 < self.cols,
"column index out of bounds"
c1 < self.cols,
"column index c1={} out of bounds for {} columns",
c1,
self.cols
);
assert!(
c2 < self.cols,
"column index c2={} out of bounds for {} columns",
c2,
self.cols
);
if c1 == c2 {
// Indices are equal; no operation required
@ -132,7 +162,7 @@ impl<T: Clone> Matrix<T> {
impl<T: Clone> Matrix<T> {
/// Adds a column to the matrix at the specified index.
pub fn add_column(&mut self, index: usize, column: Vec<T>) {
assert!(index <= self.cols, "column index out of bounds");
assert!(index <= self.cols, "add_column index {} out of bounds for {} columns", index, self.cols);
assert_eq!(column.len(), self.rows, "column length mismatch");
for (r, value) in column.into_iter().enumerate() {
@ -143,7 +173,7 @@ impl<T: Clone> Matrix<T> {
/// Adds a row to the matrix at the specified index.
pub fn add_row(&mut self, index: usize, row: Vec<T>) {
assert!(index <= self.rows, "row index out of bounds");
assert!(index <= self.rows, "add_row index {} out of bounds for {} rows", index, self.rows);
assert_eq!(row.len(), self.cols, "row length mismatch");
for (c, value) in row.into_iter().enumerate() {
@ -159,7 +189,14 @@ impl<T> Index<(usize, usize)> for Matrix<T> {
#[inline]
fn index(&self, (r, c): (usize, usize)) -> &T {
// Validate that the requested indices are within bounds
assert!(r < self.rows && c < self.cols, "index out of bounds");
assert!(
r < self.rows && c < self.cols,
"index out of bounds: ({}, {}) vs {}x{}",
r,
c,
self.rows,
self.cols
);
// Compute column-major offset and return reference
&self.data[c * self.rows + r]
}
@ -169,7 +206,14 @@ impl<T> IndexMut<(usize, usize)> for Matrix<T> {
#[inline]
fn index_mut(&mut self, (r, c): (usize, usize)) -> &mut T {
// Validate that the requested indices are within bounds
assert!(r < self.rows && c < self.cols, "index out of bounds");
assert!(
r < self.rows && c < self.cols,
"index out of bounds: ({}, {}) vs {}x{}",
r,
c,
self.rows,
self.cols
);
// Compute column-major offset and return mutable reference
&mut self.data[c * self.rows + r]
}