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