1mod csc;
31mod csr;
32pub(crate) const NONE: usize = usize::MAX;
33pub mod linalg;
37pub mod ops;
39use crate::internal_prelude_sp::Index;
40pub use csc::{
41 SparseColMat, SparseColMatMut, SparseColMatRef, SymbolicSparseColMat,
42 SymbolicSparseColMatRef, numeric as csc_numeric, symbolic as csc_symbolic,
43};
44pub use csr::{
45 SparseRowMat, SparseRowMatMut, SparseRowMatRef, SymbolicSparseRowMat,
46 SymbolicSparseRowMatRef, numeric as csr_numeric, symbolic as csr_symbolic,
47};
48use reborrow::*;
49extern crate alloc;
50#[derive(Copy, Clone, Debug, PartialEq, Eq)]
52#[repr(C)]
53pub struct Pair<Row, Col> {
54 pub row: Row,
56 pub col: Col,
58}
59#[derive(Copy, Clone, Debug)]
61#[repr(C)]
62pub struct Triplet<Row, Col, T> {
63 pub row: Row,
65 pub col: Col,
67 pub val: T,
69}
70impl<Row, Col> Pair<Row, Col> {
71 #[inline]
73 pub const fn new(row: Row, col: Col) -> Self {
74 Pair { row, col }
75 }
76}
77impl<Row, Col, T> Triplet<Row, Col, T> {
78 #[inline]
80 pub const fn new(row: Row, col: Col, val: T) -> Self {
81 Triplet { row, col, val }
82 }
83}
84#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
86#[non_exhaustive]
87pub enum FaerError {
88 IndexOverflow,
91 OutOfMemory,
93}
94impl From<dyn_stack::mem::AllocError> for FaerError {
95 #[inline]
96 fn from(value: dyn_stack::mem::AllocError) -> Self {
97 _ = value;
98 FaerError::OutOfMemory
99 }
100}
101impl From<alloc::collections::TryReserveError> for FaerError {
102 #[inline]
103 fn from(value: alloc::collections::TryReserveError) -> Self {
104 _ = value;
105 FaerError::OutOfMemory
106 }
107}
108impl core::fmt::Display for FaerError {
109 #[inline]
110 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111 core::fmt::Debug::fmt(self, f)
112 }
113}
114impl core::error::Error for FaerError {}
115#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
117pub enum CreationError {
118 Generic(FaerError),
120 OutOfBounds {
122 row: usize,
124 col: usize,
126 },
127}
128impl From<FaerError> for CreationError {
129 #[inline]
130 fn from(value: FaerError) -> Self {
131 Self::Generic(value)
132 }
133}
134impl core::fmt::Display for CreationError {
135 #[inline]
136 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
137 core::fmt::Debug::fmt(self, f)
138 }
139}
140impl core::error::Error for CreationError {}
141#[inline(always)]
142pub(crate) fn windows2<I>(
143 slice: &[I],
144) -> impl DoubleEndedIterator<Item = &[I; 2]> {
145 slice.windows(2).map(
146 #[inline(always)]
147 |window| unsafe { &*(window.as_ptr() as *const [I; 2]) },
148 )
149}
150#[inline]
151#[track_caller]
152pub(crate) fn try_zeroed<I: bytemuck::Pod>(
153 n: usize,
154) -> Result<alloc::vec::Vec<I>, FaerError> {
155 let mut v = alloc::vec::Vec::new();
156 v.try_reserve_exact(n).map_err(|_| FaerError::OutOfMemory)?;
157 unsafe {
158 core::ptr::write_bytes::<I>(v.as_mut_ptr(), 0u8, n);
159 v.set_len(n);
160 }
161 Ok(v)
162}
163#[inline]
164#[track_caller]
165pub(crate) fn try_collect<I: IntoIterator>(
166 iter: I,
167) -> Result<alloc::vec::Vec<I::Item>, FaerError> {
168 let iter = iter.into_iter();
169 let mut v = alloc::vec::Vec::new();
170 v.try_reserve_exact(iter.size_hint().0)
171 .map_err(|_| FaerError::OutOfMemory)?;
172 v.extend(iter);
173 Ok(v)
174}
175#[derive(Debug, Clone)]
181pub struct Argsort<I> {
182 idx: alloc::vec::Vec<I>,
183 all_nnz: usize,
184 nnz: usize,
185}
186pub mod utils;
188impl<I: Index, T> core::ops::Index<(usize, usize)>
189 for SparseColMatRef<'_, I, T>
190{
191 type Output = T;
192
193 #[track_caller]
194 fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
195 self.get(row, col).unwrap()
196 }
197}
198impl<I: Index, T> core::ops::Index<(usize, usize)>
199 for SparseRowMatRef<'_, I, T>
200{
201 type Output = T;
202
203 #[track_caller]
204 fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
205 self.get(row, col).unwrap()
206 }
207}
208impl<I: Index, T> core::ops::Index<(usize, usize)>
209 for SparseColMatMut<'_, I, T>
210{
211 type Output = T;
212
213 #[track_caller]
214 fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
215 self.rb().get(row, col).unwrap()
216 }
217}
218impl<I: Index, T> core::ops::Index<(usize, usize)>
219 for SparseRowMatMut<'_, I, T>
220{
221 type Output = T;
222
223 #[track_caller]
224 fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
225 self.rb().get(row, col).unwrap()
226 }
227}
228impl<I: Index, T> core::ops::IndexMut<(usize, usize)>
229 for SparseColMatMut<'_, I, T>
230{
231 #[track_caller]
232 fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
233 self.rb_mut().get_mut(row, col).unwrap()
234 }
235}
236impl<I: Index, T> core::ops::IndexMut<(usize, usize)>
237 for SparseRowMatMut<'_, I, T>
238{
239 #[track_caller]
240 fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
241 self.rb_mut().get_mut(row, col).unwrap()
242 }
243}
244impl<I: Index, T> core::ops::Index<(usize, usize)> for SparseColMat<I, T> {
245 type Output = T;
246
247 #[track_caller]
248 fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
249 self.rb().get(row, col).unwrap()
250 }
251}
252impl<I: Index, T> core::ops::Index<(usize, usize)> for SparseRowMat<I, T> {
253 type Output = T;
254
255 #[track_caller]
256 fn index(&self, (row, col): (usize, usize)) -> &Self::Output {
257 self.rb().get(row, col).unwrap()
258 }
259}
260impl<I: Index, T> core::ops::IndexMut<(usize, usize)> for SparseColMat<I, T> {
261 #[track_caller]
262 fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
263 self.rb_mut().get_mut(row, col).unwrap()
264 }
265}
266impl<I: Index, T> core::ops::IndexMut<(usize, usize)> for SparseRowMat<I, T> {
267 #[track_caller]
268 fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut Self::Output {
269 self.rb_mut().get_mut(row, col).unwrap()
270 }
271}
272#[cfg(test)]
273mod tests {
274 use super::*;
275 use crate::assert;
276 #[test]
277 fn test_from_indices() {
278 let nrows = 5;
279 let ncols = 4;
280 let indices = &[
281 Pair::new(0, 0),
282 Pair::new(1, 2),
283 Pair::new(0, 0),
284 Pair::new(1, 1),
285 Pair::new(0, 1),
286 Pair::new(3, 3),
287 Pair::new(3, 3usize),
288 ];
289 let values = &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0f64];
290 let triplets = &[
291 Triplet::new(0, 0, 1.0),
292 Triplet::new(1, 2, 2.0),
293 Triplet::new(0, 0, 3.0),
294 Triplet::new(1, 1, 4.0),
295 Triplet::new(0, 1, 5.0),
296 Triplet::new(3, 3, 6.0),
297 Triplet::new(3, 3usize, 7.0_f64),
298 ];
299 {
300 let mat = SymbolicSparseColMat::try_new_from_indices(
301 nrows, ncols, indices,
302 );
303 assert!(mat.is_ok());
304 let (mat, order) = mat.unwrap();
305 assert!(mat.nrows() == nrows);
306 assert!(mat.ncols() == ncols);
307 assert!(mat.col_ptr() == &[0, 1, 3, 4, 5]);
308 assert!(mat.col_nnz() == None);
309 assert!(mat.row_idx() == &[0, 0, 1, 1, 3]);
310 let mat =
311 SparseColMat::<_, f64>::new_from_argsort(mat, &order, values)
312 .unwrap();
313 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
314 }
315 {
316 let mat =
317 SparseColMat::try_new_from_triplets(nrows, ncols, triplets);
318 assert!(mat.is_ok());
319 let mat = mat.unwrap();
320 assert!(mat.nrows() == nrows);
321 assert!(mat.ncols() == ncols);
322 assert!(mat.col_ptr() == &[0, 1, 3, 4, 5]);
323 assert!(mat.col_nnz() == None);
324 assert!(mat.row_idx() == &[0, 0, 1, 1, 3]);
325 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
326 }
327 {
328 let mat = SymbolicSparseRowMat::try_new_from_indices(
329 nrows, ncols, indices,
330 );
331 assert!(mat.is_ok());
332 let (mat, order) = mat.unwrap();
333 assert!(mat.nrows() == nrows);
334 assert!(mat.ncols() == ncols);
335 assert!(mat.row_ptr() == &[0, 2, 4, 4, 5, 5]);
336 assert!(mat.row_nnz() == None);
337 assert!(mat.col_idx() == &[0, 1, 1, 2, 3]);
338 let mat =
339 SparseRowMat::<_, f64>::new_from_argsort(mat, &order, values)
340 .unwrap();
341 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
342 }
343 {
344 let mat =
345 SparseRowMat::try_new_from_triplets(nrows, ncols, triplets);
346 assert!(mat.is_ok());
347 let mat = mat.unwrap();
348 assert!(mat.nrows() == nrows);
349 assert!(mat.ncols() == ncols);
350 assert!(mat.row_ptr() == &[0, 2, 4, 4, 5, 5]);
351 assert!(mat.row_nnz() == None);
352 assert!(mat.col_idx() == &[0, 1, 1, 2, 3]);
353 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
354 }
355 }
356 #[test]
357 fn test_from_nonnegative_indices() {
358 let nrows = 5;
359 let ncols = 4;
360 let indices = &[
361 Pair::new(0, 0),
362 Pair::new(1, 2),
363 Pair::new(0, 0),
364 Pair::new(1, 1),
365 Pair::new(0, 1),
366 Pair::new(-1, 2),
367 Pair::new(-2, 1),
368 Pair::new(-3, -4),
369 Pair::new(3, 3),
370 Pair::new(3, 3isize),
371 ];
372 let values = &[
373 1.0,
374 2.0,
375 3.0,
376 4.0,
377 5.0,
378 f64::NAN,
379 f64::NAN,
380 f64::NAN,
381 6.0,
382 7.0f64,
383 ];
384 let triplets = &[
385 Triplet::new(0, 0, 1.0),
386 Triplet::new(1, 2, 2.0),
387 Triplet::new(0, 0, 3.0),
388 Triplet::new(1, 1, 4.0),
389 Triplet::new(0, 1, 5.0),
390 Triplet::new(-1, 2, f64::NAN),
391 Triplet::new(-2, 1, f64::NAN),
392 Triplet::new(-3, -4, f64::NAN),
393 Triplet::new(3, 3, 6.0),
394 Triplet::new(3, 3isize, 7.0_f64),
395 ];
396 {
397 let mat =
398 SymbolicSparseColMat::<usize>::try_new_from_nonnegative_indices(
399 nrows, ncols, indices,
400 );
401 assert!(mat.is_ok());
402 let (mat, order) = mat.unwrap();
403 assert!(mat.nrows() == nrows);
404 assert!(mat.ncols() == ncols);
405 assert!(mat.col_ptr() == &[0, 1, 3, 4, 5]);
406 assert!(mat.col_nnz() == None);
407 assert!(mat.row_idx() == &[0, 0, 1, 1, 3]);
408 let mat =
409 SparseColMat::<_, f64>::new_from_argsort(mat, &order, values)
410 .unwrap();
411 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
412 }
413 {
414 let mat =
415 SparseColMat::<usize, _>::try_new_from_nonnegative_triplets(
416 nrows, ncols, triplets,
417 );
418 assert!(mat.is_ok());
419 let mat = mat.unwrap();
420 assert!(mat.nrows() == nrows);
421 assert!(mat.ncols() == ncols);
422 assert!(mat.col_ptr() == &[0, 1, 3, 4, 5]);
423 assert!(mat.col_nnz() == None);
424 assert!(mat.row_idx() == &[0, 0, 1, 1, 3]);
425 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
426 }
427 {
428 let mat =
429 SymbolicSparseRowMat::<usize>::try_new_from_nonnegative_indices(
430 nrows, ncols, indices,
431 );
432 assert!(mat.is_ok());
433 let (mat, order) = mat.unwrap();
434 assert!(mat.nrows() == nrows);
435 assert!(mat.ncols() == ncols);
436 assert!(mat.row_ptr() == &[0, 2, 4, 4, 5, 5]);
437 assert!(mat.row_nnz() == None);
438 assert!(mat.col_idx() == &[0, 1, 1, 2, 3]);
439 let mat =
440 SparseRowMat::<_, f64>::new_from_argsort(mat, &order, values)
441 .unwrap();
442 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
443 }
444 {
445 let mat =
446 SparseRowMat::<usize, _>::try_new_from_nonnegative_triplets(
447 nrows, ncols, triplets,
448 );
449 assert!(mat.is_ok());
450 let mat = mat.unwrap();
451 assert!(mat.nrows() == nrows);
452 assert!(mat.ncols() == ncols);
453 assert!(mat.row_ptr() == &[0, 2, 4, 4, 5, 5]);
454 assert!(mat.row_nnz() == None);
455 assert!(mat.col_idx() == &[0, 1, 1, 2, 3]);
456 assert!(mat.val() == &[1.0 + 3.0, 5.0, 4.0, 2.0, 6.0 + 7.0]);
457 }
458 }
459 #[test]
460 fn test_from_indices_oob_row() {
461 let nrows = 5;
462 let ncols = 4;
463 let indices = &[
464 Pair::new(0, 0),
465 Pair::new(1, 2),
466 Pair::new(0, 0),
467 Pair::new(1, 1),
468 Pair::new(0, 1),
469 Pair::new(3, 3),
470 Pair::new(3, 3),
471 Pair::new(5, 3usize),
472 ];
473 let err =
474 SymbolicSparseColMat::try_new_from_indices(nrows, ncols, indices);
475 assert!(err.is_err());
476 let err = err.unwrap_err();
477 assert!(err == CreationError::OutOfBounds { row: 5, col: 3 });
478 }
479 #[test]
480 fn test_from_indices_oob_col() {
481 let nrows = 5;
482 let ncols = 4;
483 let indices = &[
484 Pair::new(0, 0),
485 Pair::new(1, 2),
486 Pair::new(0, 0),
487 Pair::new(1, 1),
488 Pair::new(0, 1),
489 Pair::new(3, 3),
490 Pair::new(3, 3),
491 Pair::new(2, 4usize),
492 ];
493 let err =
494 SymbolicSparseColMat::try_new_from_indices(nrows, ncols, indices);
495 assert!(err.is_err());
496 let err = err.unwrap_err();
497 assert!(err == CreationError::OutOfBounds { row: 2, col: 4 });
498 }
499}