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}