algebra_sparse/
csm.rs

1// Copyright (C) 2020-2025 algebra-sparse authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use na::{DMatrix, RealField};
16use nalgebra::DMatrixView;
17
18use crate::Real;
19use crate::csv::{CsVecBuilder, CsVecMut, CsVecRef};
20use crate::traits::IntoView;
21
22/// Compressed Sparse Matrix in either CSR or CSC format.
23///
24/// This is the core sparse matrix structure that can represent either:
25/// - CSR (Compressed Sparse Row) format when rows are compressed
26/// - CSC (Compressed Sparse Column) format when columns are compressed
27///
28/// The matrix stores only non-zero elements and their indices, making it
29/// memory-efficient for matrices with few non-zero elements.
30///
31/// # Format
32///
33/// The matrix uses three internal arrays:
34/// - `secondary_indices`: Column indices for CSR or row indices for CSC
35/// - `primary_offsets`: Offsets for each row (CSR) or column (CSC)
36/// - `values`: Non-zero values stored in row-major (CSR) or column-major (CSC) order
37///
38/// # Examples
39///
40/// ```rust
41/// use algebra_sparse::{CsMatrix, CsrMatrix};
42/// use nalgebra::DMatrix;
43///
44/// // Create from dense matrix
45/// let dense = DMatrix::from_row_slice(2, 3, &[
46///     1.0, 0.0, 2.0,
47///     0.0, 3.0, 0.0,
48/// ]);
49/// let sparse = CsrMatrix::from_dense(dense.as_view());
50/// ```
51#[derive(Default, Clone, Debug)]
52pub struct CsMatrix<T> {
53    /// The secondary axis indices of the non-zero entries.
54    /// For CSR format, these are column indices.
55    /// For CSC format, these are row indices.
56    pub(crate) secondary_indices: Vec<usize>,
57    /// The offsets of each primary axis in the `values` array.
58    /// For CSR format, these are row offsets.
59    /// For CSC format, these are column offsets.
60    pub(crate) primary_offsets: Vec<usize>,
61    /// All non-zero values for the matrix.
62    pub(crate) values: Vec<T>,
63    /// The dimension size of the secondary axis.
64    /// For CSR format, this is the number of columns.
65    /// For CSC format, this is the number of rows.
66    pub(crate) num_secondary: usize,
67}
68
69impl<T> CsMatrix<T>
70where
71    T: Real,
72{
73    /// Create a `CsMatrix` from a dense matrix.
74    ///
75    /// # Arguments
76    /// * `dense_mat` - The dense matrix to convert
77    /// * `row_sparse` - If true, creates CSR format; if false, creates CSC format
78    /// * `zero_threshold` - Values below this threshold are treated as zero and not stored
79    ///
80    /// # Examples
81    ///
82    /// ```rust
83    /// use algebra_sparse::CsMatrix;
84    /// use nalgebra::DMatrix;
85    ///
86    /// let dense = DMatrix::from_row_slice(2, 3, &[
87    ///     1.0, 0.0, 2.0,
88    ///     0.0, 3.0, 0.0,
89    /// ]);
90    ///
91    /// // Create CSR format
92    /// let csr = CsMatrix::from_dense(dense.as_view(), true, 1e-10);
93    ///
94    /// // Create CSC format
95    /// let csc = CsMatrix::from_dense(dense.as_view(), false, 1e-10);
96    /// ```
97    #[inline]
98    pub fn from_dense(dense_mat: DMatrixView<T>, row_sparse: bool, zero_threshold: T) -> Self {
99        let secondary_size = if row_sparse {
100            dense_mat.ncols()
101        } else {
102            dense_mat.nrows()
103        };
104        let mut csm = CsMatrix::new(secondary_size);
105
106        if row_sparse {
107            for i in 0..dense_mat.nrows() {
108                let mut rb = csm.new_lane_builder(zero_threshold);
109                let lane = dense_mat.row(i);
110                rb.extend_with_nonzeros(lane.iter().copied().enumerate());
111            }
112        } else {
113            for i in 0..dense_mat.ncols() {
114                let mut rb = csm.new_lane_builder(zero_threshold);
115                let lane = dense_mat.column(i);
116                rb.extend_with_nonzeros(lane.iter().copied().enumerate());
117            }
118        }
119        csm
120    }
121
122    /// Creates a new empty `CsMatrix` with the given secondary axis size.
123    ///
124    /// # Arguments
125    /// * `secondary_size` - Number of columns for CSR format or rows for CSC format
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use algebra_sparse::CsMatrix;
131    ///
132    /// // Create an empty CSR matrix with 3 columns
133    /// let csr: CsMatrix<f64> = CsMatrix::new(3);
134    /// ```
135    pub fn new(secondary_size: usize) -> Self {
136        let primary_offsets = vec![0];
137        Self {
138            secondary_indices: Vec::new(),
139            values: Vec::new(),
140            primary_offsets,
141            num_secondary: secondary_size,
142        }
143    }
144
145    /// Creates a new lane (row or column) builder for this matrix.
146    ///
147    /// Returns a `CsVecBuilder` that can be used to efficiently add non-zero elements
148    /// to the next lane of the matrix. When the builder is dropped, the lane is finalized.
149    ///
150    /// # Arguments
151    /// * `zero_threshold` - Values below this threshold are filtered out
152    ///
153    /// # Examples
154    ///
155    /// ```rust
156    /// use algebra_sparse::CsMatrix;
157    ///
158    /// let mut matrix = CsMatrix::new(3);
159    /// let mut builder = matrix.new_lane_builder(1e-10);
160    /// builder.push(0, 1.0);  // Add element at column 0
161    /// builder.push(2, 2.0);  // Add element at column 2
162    /// ```
163    #[inline]
164    pub fn new_lane_builder(&mut self, zero_threshold: T) -> CsVecBuilder<T> {
165        CsVecBuilder::new(self, zero_threshold)
166    }
167
168    /// Resets the matrix to empty state with a new secondary axis size.
169    ///
170    /// This clears all data and allows reuse of the matrix with different dimensions.
171    ///
172    /// # Arguments
173    /// * `secondary_size` - New secondary axis size
174    pub fn reset(&mut self, secondary_size: usize) {
175        self.clear();
176        self.num_secondary = secondary_size;
177    }
178
179    /// Clears all data from the matrix while preserving the secondary axis size.
180    ///
181    /// This removes all lanes but keeps the matrix ready for reuse with the same dimensions.
182    #[inline]
183    pub fn clear(&mut self) {
184        self.secondary_indices.clear();
185        self.values.clear();
186        self.primary_offsets.clear();
187        self.primary_offsets.push(0);
188    }
189
190    /// Returns the number of primary axes (rows for CSR, columns for CSC).
191    #[inline]
192    pub fn num_primary(&self) -> usize {
193        self.primary_offsets.len() - 1
194    }
195
196    /// Returns the number of secondary axes (columns for CSR, rows for CSC).
197    #[inline]
198    pub fn num_secondary(&self) -> usize {
199        self.num_secondary
200    }
201
202    /// Gets a lane (row for CSR, column for CSC) as an immutable sparse vector.
203    ///
204    /// # Arguments
205    /// * `lane_index` - Index of the lane to retrieve
206    ///
207    /// # Returns
208    /// A `CsVecRef` representing the sparse vector for this lane
209    #[inline]
210    pub fn get_lane(&self, lane_index: usize) -> CsVecRef<T> {
211        let start = self.primary_offsets[lane_index];
212        let end = self.primary_offsets[lane_index + 1];
213        let col_indices = &self.secondary_indices[start..end];
214        let values = &self.values[start..end];
215        CsVecRef::from_parts_unchecked(col_indices, values, self.num_secondary)
216    }
217
218    /// Gets a lane (row for CSR, column for CSC) as a mutable sparse vector.
219    ///
220    /// # Arguments
221    /// * `lane_index` - Index of the lane to retrieve
222    ///
223    /// # Returns
224    /// A `CsVecMut` allowing modification of the lane's values
225    #[inline]
226    pub fn get_lane_mut(&mut self, lane_index: usize) -> CsVecMut<T> {
227        let start = self.primary_offsets[lane_index];
228        let end = self.primary_offsets[lane_index + 1];
229        let col_indices = &self.secondary_indices[start..end];
230        let values = &mut self.values[start..end];
231        CsVecMut {
232            col_indices,
233            values,
234        }
235    }
236
237    /// Returns an immutable view of this matrix.
238    ///
239    /// The view allows efficient read-only access without allocation.
240    #[inline]
241    pub fn as_view(&self) -> CsMatrixView<T> {
242        CsMatrixView {
243            secondary_indices: &self.secondary_indices,
244            primary_offsets: &self.primary_offsets,
245            values: &self.values,
246            num_secondary: self.num_secondary,
247        }
248    }
249
250    /// Returns the density rate of the matrix.
251    ///
252    /// This is the ratio of non-zero elements to total elements.
253    /// A value of 0.1 means 10% of elements are non-zero.
254    #[inline]
255    pub fn dense_rate(&self) -> f32 {
256        self.values.len() as f32 / (self.num_primary() * self.num_secondary()) as f32
257    }
258}
259
260impl<'a, T> IntoView for &'a CsMatrix<T> {
261    type View = CsMatrixView<'a, T>;
262
263    fn into_view(self) -> Self::View {
264        CsMatrixView {
265            secondary_indices: &self.secondary_indices,
266            primary_offsets: &self.primary_offsets,
267            values: &self.values,
268            num_secondary: self.num_secondary,
269        }
270    }
271}
272
273/// An immutable view of a compressed sparse matrix.
274///
275/// This provides efficient read-only access to sparse matrix data without
276/// allocation. Views can be created from both mutable and immutable matrices
277/// and are useful for passing matrices to functions without transferring ownership.
278///
279/// The view has the same format capabilities as `CsMatrix` - it can represent
280/// both CSR and CSC formats depending on how it's created.
281#[derive(Clone, Copy, Debug)]
282pub struct CsMatrixView<'a, T> {
283    /// The secondary axis indices of the non-zero entries.
284    /// For CSR format, these are column indices.
285    /// For CSC format, these are row indices.
286    secondary_indices: &'a [usize],
287    /// The offsets of each primary axis in the `values` array.
288    /// For CSR format, these are row offsets.
289    /// For CSC format, these are column offsets.
290    primary_offsets: &'a [usize],
291    /// All non-zero values for the matrix.
292    values: &'a [T],
293    /// The dimension size of the secondary axis.
294    /// For CSR format, this is the number of columns.
295    /// For CSC format, this is the number of rows.
296    num_secondary: usize,
297}
298
299impl<'a, T> CsMatrixView<'a, T>
300where
301    T: RealField,
302{
303    /// Returns the number of primary axes (rows for CSR, columns for CSC).
304    #[inline]
305    pub fn num_primary(&self) -> usize {
306        self.primary_offsets.len() - 1
307    }
308
309    /// Returns the number of secondary axes (columns for CSR, rows for CSC).
310    #[inline]
311    pub fn num_secondary(&self) -> usize {
312        self.num_secondary
313    }
314
315    /// Gets a lane (row for CSR, column for CSC) as an immutable sparse vector.
316    ///
317    /// # Arguments
318    /// * `lane_index` - Index of the lane to retrieve
319    ///
320    /// # Returns
321    /// A `CsVecRef` representing the sparse vector for this lane
322    #[inline]
323    pub fn get_lane(self, lane_index: usize) -> CsVecRef<'a, T> {
324        let start = self.primary_offsets[lane_index];
325        let end = self.primary_offsets[lane_index + 1];
326        let col_indices = &self.secondary_indices[start..end];
327        let values = &self.values[start..end];
328        CsVecRef::from_parts_unchecked(col_indices, values, self.num_secondary)
329    }
330
331    /// Returns the density rate of the matrix.
332    ///
333    /// This is the ratio of non-zero elements to total elements.
334    /// A value of 0.1 means 10% of elements are non-zero.
335    #[inline]
336    pub fn dense_rate(&self) -> f32 {
337        self.values.len() as f32 / (self.num_primary() * self.num_secondary()) as f32
338    }
339}
340
341impl<'a, T> IntoView for CsMatrixView<'a, T> {
342    type View = CsMatrixView<'a, T>;
343
344    #[inline]
345    fn into_view(self) -> Self::View {
346        self
347    }
348}
349
350/// Compressed Sparse Row (CSR) Matrix.
351///
352/// CSR format is optimized for row-wise operations and matrix-vector products.
353/// It stores non-zero elements row by row, making it efficient for:
354/// - Row access and iteration
355/// - Sparse matrix-vector multiplication
356/// - Row-based computations
357///
358/// # Format
359///
360/// The CSR format uses three arrays:
361/// - `values`: Non-zero values stored row by row
362/// - `col_indices`: Column indices for each non-zero value
363/// - `row_offsets`: Starting index in values/col_indices for each row
364///
365/// # Examples
366///
367/// ```rust
368/// use algebra_sparse::CsrMatrix;
369/// use nalgebra::DMatrix;
370///
371/// // Create from dense matrix
372/// let dense = DMatrix::from_row_slice(2, 3, &[
373///     1.0, 0.0, 2.0,
374///     0.0, 3.0, 0.0,
375/// ]);
376/// let csr = CsrMatrix::from_dense(dense.as_view());
377///
378/// // Get row as sparse vector
379/// let row = csr.as_view().get_row(0);
380/// for (col, val) in row.iter() {
381///     println!("({}, {})", col, val);
382/// }
383/// ```
384#[derive(Default, Clone)]
385pub struct CsrMatrix<T>(CsMatrix<T>);
386
387impl<T> CsrMatrix<T>
388where
389    T: Real,
390{
391    /// Creates a CSR matrix from a dense matrix.
392    ///
393    /// Values below the zero threshold are automatically filtered out.
394    /// The zero threshold is obtained from the `Real` trait implementation.
395    ///
396    /// # Arguments
397    /// * `dense_mat` - The dense matrix to convert
398    ///
399    /// # Examples
400    ///
401    /// ```rust
402    /// use algebra_sparse::CsrMatrix;
403    /// use nalgebra::DMatrix;
404    ///
405    /// let dense = DMatrix::from_row_slice(2, 2, &[1.0, 0.0, 0.0, 2.0]);
406    /// let csr = CsrMatrix::from_dense(dense.as_view());
407    /// ```
408    #[inline]
409    pub fn from_dense(dense_mat: DMatrixView<T>) -> Self {
410        Self(CsMatrix::from_dense(dense_mat, true, T::zero_threshold()))
411    }
412
413    /// Creates a new empty CSR matrix with the given number of columns.
414    ///
415    /// # Arguments
416    /// * `ncols` - Number of columns in the matrix
417    ///
418    /// # Examples
419    ///
420    /// ```rust
421    /// use algebra_sparse::CsrMatrix;
422    ///
423    /// let mut csr: CsrMatrix<f64> = CsrMatrix::new(3);
424    /// // Now you can add rows using new_row_builder()
425    /// ```
426    pub fn new(ncols: usize) -> Self {
427        Self(CsMatrix::new(ncols))
428    }
429
430    /// Resets the CSR matrix to empty state with the given number of columns.
431    ///
432    /// This clears all data and allows reuse of the matrix.
433    ///
434    /// # Arguments
435    /// * `ncols` - New number of columns
436    pub fn reset(&mut self, ncols: usize) {
437        self.0.reset(ncols);
438    }
439
440    /// Clears all rows in the CSR matrix while preserving the number of columns.
441    ///
442    /// This removes all rows but keeps the matrix ready for reuse.
443    #[inline]
444    pub fn clear(&mut self) {
445        self.0.clear();
446    }
447
448    /// Creates a new row builder for adding elements to the next row.
449    ///
450    /// The builder allows efficient construction of sparse rows. When the builder
451    /// is dropped, the row is finalized and added to the matrix.
452    ///
453    /// # Arguments
454    /// * `zero_threshold` - Values below this threshold are filtered out
455    ///
456    /// # Examples
457    ///
458    /// ```rust
459    /// use algebra_sparse::CsrMatrix;
460    ///
461    /// let mut csr = CsrMatrix::new(3);
462    /// let mut builder = csr.new_row_builder(1e-10);
463    /// builder.push(0, 1.0);  // Add element at column 0
464    /// builder.push(2, 2.0);  // Add element at column 2
465    /// // Row is automatically added when builder is dropped
466    /// ```
467    #[inline]
468    pub fn new_row_builder(&mut self, zero_threshold: T) -> CsVecBuilder<T> {
469        self.0.new_lane_builder(zero_threshold)
470    }
471
472    /// Gets a mutable row as a sparse vector.
473    ///
474    /// # Arguments
475    /// * `row_index` - Index of the row to retrieve
476    ///
477    /// # Returns
478    /// A `CsVecMut` allowing modification of the row's values
479    ///
480    /// # Note
481    /// This only allows modification of existing values, not structural changes.
482    #[inline]
483    pub fn get_row_mut(&mut self, row_index: usize) -> CsVecMut<T> {
484        self.0.get_lane_mut(row_index)
485    }
486
487    /// Returns an immutable view of this CSR matrix.
488    ///
489    /// The view allows efficient read-only access without allocation
490    /// and can be used for matrix operations.
491    #[inline]
492    pub fn as_view(&self) -> CsrMatrixView<T> {
493        CsrMatrixView(self.0.as_view())
494    }
495}
496
497impl<'a, T> IntoView for &'a CsrMatrix<T>
498where
499    T: Real,
500{
501    type View = CsrMatrixView<'a, T>;
502
503    fn into_view(self) -> Self::View {
504        CsrMatrixView(self.0.as_view())
505    }
506}
507
508/// An immutable view of a CSR matrix.
509///
510/// This provides efficient read-only access to CSR matrix data without allocation.
511/// Views are commonly used for matrix operations and can be easily created from
512/// both mutable and immutable CSR matrices.
513///
514/// # Examples
515///
516/// ```rust
517/// use algebra_sparse::{CsrMatrix, CsrMatrixViewMethods};
518/// use nalgebra::DMatrix;
519///
520/// let dense = DMatrix::from_row_slice(2, 2, &[1.0, 2.0, 3.0, 4.0]);
521/// let csr = CsrMatrix::from_dense(dense.as_view());
522/// let view = csr.as_view();
523///
524/// println!("Number of rows: {}", view.nrows());
525/// println!("Number of columns: {}", view.ncols());
526/// ```
527#[derive(Clone, Copy, Debug)]
528pub struct CsrMatrixView<'a, T>(CsMatrixView<'a, T>);
529
530impl<'a, T> CsrMatrixView<'a, T> {
531    /// Creates a `CsrMatrixView` from raw parts without checking validity.
532    ///
533    /// # Safety
534    /// This function does not validate that the provided parts form a valid CSR matrix.
535    /// Invalid parts may cause undefined behavior when accessing the matrix.
536    ///
537    /// # Arguments
538    /// * `row_offsets` - Row offset array (length = nrows + 1)
539    /// * `col_indices` - Column index array for non-zero elements
540    /// * `values` - Non-zero values array
541    /// * `ncol` - Number of columns
542    #[inline]
543    pub fn from_parts_unchecked(
544        row_offsets: &'a [usize],
545        col_indices: &'a [usize],
546        values: &'a [T],
547        ncol: usize,
548    ) -> Self {
549        Self(CsMatrixView {
550            secondary_indices: col_indices,
551            primary_offsets: row_offsets,
552            values,
553            num_secondary: ncol,
554        })
555    }
556}
557
558impl<'a, T> CsrMatrixView<'a, T>
559where
560    T: Real,
561{
562    /// Returns the density rate of the matrix.
563    ///
564    /// This is the ratio of non-zero elements to total elements.
565    /// A value of 0.1 means 10% of elements are non-zero.
566    #[inline]
567    pub fn dense_rate(&self) -> f32 {
568        self.0.dense_rate()
569    }
570
571    /// Transposes the CSR matrix view to a CSC matrix view.
572    ///
573    /// This is a zero-cost operation that only changes the interpretation of the data.
574    /// No data is copied or moved.
575    ///
576    /// # Returns
577    /// A CSC view of the same matrix data
578    #[inline]
579    pub fn transpose(&self) -> CscMatrixView<'a, T> {
580        CscMatrixView(self.0)
581    }
582
583    /// Returns the shape of the matrix as (nrows, ncols).
584    #[inline]
585    pub fn shape(&self) -> (usize, usize) {
586        (self.nrows(), self.ncols())
587    }
588
589    /// Returns the number of rows in the matrix.
590    #[inline]
591    pub fn nrows(&self) -> usize {
592        self.0.num_primary()
593    }
594
595    /// Returns the number of columns in the matrix.
596    #[inline]
597    pub fn ncols(&self) -> usize {
598        self.0.num_secondary()
599    }
600
601    /// Gets a row as a sparse vector.
602    ///
603    /// # Arguments
604    /// * `row_index` - Index of the row to retrieve
605    ///
606    /// # Returns
607    /// A `CsVecRef` representing the sparse vector for this row
608    #[inline]
609    pub fn get_row(self, row_index: usize) -> CsVecRef<'a, T> {
610        self.0.get_lane(row_index)
611    }
612}
613
614impl<'a, T> IntoView for CsrMatrixView<'a, T> {
615    type View = CsrMatrixView<'a, T>;
616
617    #[inline]
618    fn into_view(self) -> Self::View {
619        self
620    }
621}
622
623impl<'b, T> IntoView for &CsrMatrixView<'b, T>
624where
625    T: Copy,
626{
627    type View = CsrMatrixView<'b, T>;
628
629    #[inline]
630    fn into_view(self) -> Self::View {
631        *self
632    }
633}
634
635/// Trait providing methods for CSR matrix view operations.
636///
637/// This trait extends types that can be converted to CSR views with convenient
638/// methods for matrix operations and introspection.
639pub trait CsrMatrixViewMethods<'a, T> {
640    /// Returns the number of rows in the matrix.
641    fn nrows(self) -> usize;
642
643    /// Returns the number of columns in the matrix.
644    fn ncols(self) -> usize;
645
646    /// Gets a row as a sparse vector.
647    ///
648    /// # Arguments
649    /// * `row_index` - Index of the row to retrieve
650    ///
651    /// # Returns
652    /// A `CsVecRef` representing the sparse vector for this row
653    fn get_row(self, row_index: usize) -> CsVecRef<'a, T>;
654
655    /// Converts to a dense matrix.
656    ///
657    /// This allocates a new dense matrix and copies all non-zero elements.
658    ///
659    /// # Returns
660    /// A dense `DMatrix` containing the same data
661    fn to_dense(self) -> DMatrix<T>
662    where
663        Self: Sized + Copy,
664        T: Real,
665    {
666        let mut m = DMatrix::zeros(self.nrows(), self.ncols());
667        for i in 0..self.nrows() {
668            let row = self.get_row(i);
669            for (col, value) in row.iter() {
670                unsafe {
671                    *m.get_unchecked_mut((i, col)) = value;
672                }
673            }
674        }
675        m
676    }
677}
678
679impl<'a, T, V> CsrMatrixViewMethods<'a, V> for &'a T
680where
681    V: Real,
682    &'a T: IntoView<View = CsrMatrixView<'a, V>>,
683{
684    /// Get the number of rows.
685    #[inline]
686    fn nrows(self) -> usize {
687        CsrMatrixView::nrows(&self.into_view())
688    }
689
690    /// Get the number of columns.
691    #[inline]
692    fn ncols(self) -> usize {
693        CsrMatrixView::ncols(&self.into_view())
694    }
695
696    /// Get a row as a sparse vector.
697    #[inline]
698    fn get_row(self, row_index: usize) -> CsVecRef<'a, V> {
699        self.into_view().get_row(row_index)
700    }
701}
702
703/// Compressed Sparse Column (CSC) Matrix View.
704///
705/// CSC format is optimized for column-wise operations and is the transpose
706/// of CSR format. It stores non-zero elements column by column, making it
707/// efficient for:
708/// - Column access and iteration
709/// - Column-based computations
710/// - Matrix operations that benefit from column-wise access
711///
712/// This is a view type that provides efficient read-only access to matrix data
713/// without allocation.
714///
715/// # Examples
716///
717/// ```rust
718/// use algebra_sparse::CsrMatrix;
719/// use nalgebra::DMatrix;
720///
721/// let dense = DMatrix::from_row_slice(2, 2, &[1.0, 2.0, 3.0, 4.0]);
722/// let csr = CsrMatrix::from_dense(dense.as_view());
723/// let csc = csr.as_view().transpose();
724///
725/// // Access columns
726/// for col_idx in 0..csc.ncols() {
727///     let col = csc.get_col(col_idx);
728///     for (row, val) in col.iter() {
729///         println!("({}, {})", row, val);
730///     }
731/// }
732/// ```
733#[derive(Clone, Copy)]
734pub struct CscMatrixView<'a, T>(CsMatrixView<'a, T>);
735
736impl<'a, T> CscMatrixView<'a, T>
737where
738    T: Real,
739{
740    /// Returns the number of rows in the matrix.
741    #[inline]
742    pub fn nrows(&self) -> usize {
743        self.0.num_secondary()
744    }
745
746    /// Returns the number of columns in the matrix.
747    #[inline]
748    pub fn ncols(&self) -> usize {
749        self.0.num_primary()
750    }
751
752    /// Gets a column as a sparse vector.
753    ///
754    /// # Arguments
755    /// * `col_index` - Index of the column to retrieve
756    ///
757    /// # Returns
758    /// A `CsVecRef` representing the sparse vector for this column
759    #[inline]
760    pub fn get_col(&self, col_index: usize) -> CsVecRef<'a, T> {
761        self.0.get_lane(col_index)
762    }
763
764    /// Transposes to a `CsrMatrixView`.
765    ///
766    /// This is a zero-cost operation that only changes the interpretation of the data.
767    /// No data is copied or moved.
768    ///
769    /// # Returns
770    /// A CSR view of the same matrix data
771    #[inline]
772    pub fn transpose(&self) -> CsrMatrixView<'a, T> {
773        CsrMatrixView(self.0)
774    }
775
776    /// Converts to a dense matrix.
777    ///
778    /// This allocates a new dense matrix and copies all non-zero elements.
779    ///
780    /// # Returns
781    /// A dense `DMatrix` containing the same data
782    pub fn to_dense(&self) -> DMatrix<T> {
783        let mut dense = DMatrix::zeros(self.nrows(), self.ncols());
784        for col in 0..self.ncols() {
785            let col_vec = self.get_col(col);
786            for (row, value) in col_vec.iter() {
787                dense[(row, col)] = value;
788            }
789        }
790        dense
791    }
792}