Skip to content

Commit 7297305

Browse files
authored
Merge pull request #245 from vbarrielle/indptr_trait
Refactor to allow partial views
2 parents 130745d + 6f563e9 commit 7297305

File tree

14 files changed

+784
-446
lines changed

14 files changed

+784
-446
lines changed

sprs-benches/src/main.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,11 @@ fn scipy_mat<'a>(
1010
py: &Python,
1111
mat: &sprs::CsMat<f64>,
1212
) -> Result<&'a PyAny, String> {
13+
let indptr = mat.indptr().to_proper().to_vec();
1314
scipy_sparse
1415
.call(
1516
"csr_matrix",
16-
((
17-
mat.data().to_vec(),
18-
mat.indices().to_vec(),
19-
mat.indptr().to_vec(),
20-
),),
17+
((mat.data().to_vec(), mat.indices().to_vec(), indptr),),
2118
Some([("shape", mat.shape())].into_py_dict(*py)),
2219
)
2320
.map_err(|e| {
@@ -51,14 +48,14 @@ fn eigen_prod(a: sprs::CsMatView<f64>, b: sprs::CsMatView<f64>) -> usize {
5148
assert_eq!(a_cols, b_rows);
5249
assert!(a.is_csr());
5350
assert!(a.rows() <= isize::MAX as usize);
54-
assert!(a.indptr()[a.rows()] <= isize::MAX as usize);
51+
assert!(a.indptr().nnz() <= isize::MAX as usize);
5552
assert!(b.is_csr());
5653
assert!(b.rows() <= isize::MAX as usize);
57-
assert!(b.indptr()[b.rows()] <= isize::MAX as usize);
58-
let a_indptr = a.indptr().as_ptr() as *const isize;
54+
assert!(b.indptr().nnz() <= isize::MAX as usize);
55+
let a_indptr_proper = a.proper_indptr();
5956
let a_indices = a.indices().as_ptr() as *const isize;
6057
let a_data = a.data().as_ptr();
61-
let b_indptr = b.indptr().as_ptr() as *const isize;
58+
let b_indptr_proper = b.proper_indptr();
6259
let b_indices = b.indices().as_ptr() as *const isize;
6360
let b_data = b.data().as_ptr();
6461
// Safety: sprs guarantees the validity of these pointers, and our wrapping
@@ -71,8 +68,15 @@ fn eigen_prod(a: sprs::CsMatView<f64>, b: sprs::CsMatView<f64>) -> usize {
7168
// reinterpretation of the data will not produce negative values.
7269
unsafe {
7370
prod_nnz(
74-
a_rows, a_cols, b_cols, a_indptr, a_indices, a_data, b_indptr,
75-
b_indices, b_data,
71+
a_rows,
72+
a_cols,
73+
b_cols,
74+
a_indptr_proper.as_ptr() as *const isize,
75+
a_indices,
76+
a_data,
77+
b_indptr_proper.as_ptr() as *const isize,
78+
b_indices,
79+
b_data,
7680
)
7781
}
7882
}

sprs-ldl/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ impl Ldl {
146146
}
147147
FillInReduction::CAMDSuiteSparse => {
148148
#[cfg(not(feature = "sprs_suitesparse_camd"))]
149-
panic!("Unavailable without the `sprs_suitesparse_camd` feature");
149+
panic!(
150+
"Unavailable without the `sprs_suitesparse_camd` feature"
151+
);
150152
#[cfg(feature = "sprs_suitesparse_camd")]
151153
sprs_suitesparse_camd::camd(mat.structure_view())
152154
}

src/lib.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ pub type Ix2 = ndarray::Ix2;
8888
pub use crate::indexing::SpIndex;
8989

9090
pub use crate::sparse::{
91-
csmat::CsIter, csmat::OuterIterator, csmat::OuterIteratorMut,
92-
csmat::OuterIteratorPerm, kronecker::kronecker_product, CsMat, CsMatBase,
93-
CsMatI, CsMatVecView, CsMatView, CsMatViewI, CsMatViewMut, CsMatViewMutI,
94-
CsStructure, CsStructureI, CsStructureView, CsStructureViewI, CsVec,
95-
CsVecBase, CsVecI, CsVecView, CsVecViewI, CsVecViewMut, CsVecViewMutI,
96-
SparseMat, TriMat, TriMatBase, TriMatI, TriMatIter, TriMatView,
97-
TriMatViewI, TriMatViewMut, TriMatViewMutI,
91+
csmat::CsIter,
92+
indptr::{IndPtr, IndPtrBase, IndPtrView},
93+
kronecker::kronecker_product,
94+
CsMat, CsMatBase, CsMatI, CsMatVecView, CsMatView, CsMatViewI,
95+
CsMatViewMut, CsMatViewMutI, CsStructure, CsStructureI, CsStructureView,
96+
CsStructureViewI, CsVec, CsVecBase, CsVecI, CsVecView, CsVecViewI,
97+
CsVecViewMut, CsVecViewMutI, SparseMat, TriMat, TriMatBase, TriMatI,
98+
TriMatIter, TriMatView, TriMatViewI, TriMatViewMut, TriMatViewMutI,
9899
};
99100

100101
pub use crate::sparse::symmetric::is_symmetric;

src/sparse.rs

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::array_backend::Array2;
22
use crate::errors::SprsError;
33
use crate::indexing::SpIndex;
4+
use crate::IndPtrBase;
45
use std::ops::Deref;
56

67
#[cfg(feature = "serde")]
@@ -93,7 +94,8 @@ where
9394
storage: CompressedStorage,
9495
nrows: usize,
9596
ncols: usize,
96-
indptr: IptrStorage,
97+
#[cfg_attr(feature = "serde", serde(flatten))]
98+
indptr: IndPtrBase<Iptr, IptrStorage>,
9799
indices: IndStorage,
98100
data: DataStorage,
99101
}
@@ -282,6 +284,7 @@ pub(crate) mod utils {
282284
indptr: &[Iptr],
283285
indices: &[I],
284286
) -> Result<(), SprsError> {
287+
let indptr = crate::IndPtrView::new(indptr)?;
285288
if indptr.len() != outer + 1 {
286289
return Err(SprsError::IllegalArguments(
287290
"Indptr length does not match dimension",
@@ -298,15 +301,8 @@ pub(crate) mod utils {
298301
"Iptr type not large enough for this matrix",
299302
));
300303
}
301-
// Make sure both indptr and indices can be converted to usize
304+
// Make sure indices can be converted to usize
302305
// this could happen if index is negative for sized types
303-
for i in indptr.iter() {
304-
if i.try_index().is_none() {
305-
return Err(SprsError::IllegalArguments(
306-
"Indptr value out of range of usize",
307-
));
308-
}
309-
}
310306
for i in indices.iter() {
311307
if i.try_index().is_none() {
312308
return Err(SprsError::IllegalArguments(
@@ -315,43 +311,15 @@ pub(crate) mod utils {
315311
}
316312
}
317313
let nnz = indices.len();
318-
if nnz != indptr.last().unwrap().to_usize().unwrap() {
314+
if nnz != indptr.nnz() {
319315
return Err(SprsError::IllegalArguments(
320316
"Indices length and inpdtr's nnz do not match",
321317
));
322318
}
323319

324-
// indptr should be non-monotonically increasing
325-
if !indptr
326-
.windows(2)
327-
.all(|x| x[0].index_unchecked() <= x[1].index_unchecked())
328-
{
329-
return Err(SprsError::UnsortedIndptr);
330-
}
331-
// Guaranteed to have at least one element
332-
let max_indptr = indptr.last().unwrap();
333-
if max_indptr.index_unchecked() > nnz {
334-
return Err(SprsError::IllegalArguments(
335-
"An indptr value is out of bounds",
336-
));
337-
}
338-
if max_indptr.index_unchecked() > usize::max_value() / 2 {
339-
// We do not allow indptr values to be larger than half
340-
// the maximum value of an usize, as that would clearly exhaust
341-
// all available memory
342-
// This means we could have an isize, but in practice it's
343-
// easier to work with usize for indexing.
344-
return Err(SprsError::IllegalArguments(
345-
"An indptr value is larger than allowed",
346-
));
347-
}
348-
349320
// check that the indices are sorted for each row
350-
for win in indptr.windows(2) {
351-
let [i1, i2]: &[Iptr; 2] = win.try_into().unwrap();
352-
let i1 = i1.to_usize().unwrap();
353-
let i2 = i2.to_usize().unwrap();
354-
let indices = &indices[i1..i2];
321+
for range in indptr.iter_outer_sz() {
322+
let indices = &indices[range];
355323
// Indices must be monotonically increasing
356324
if !sorted_indices(indices) {
357325
return Err(SprsError::NonSortedIndices);
@@ -410,6 +378,7 @@ pub mod binop;
410378
pub mod compressed;
411379
pub mod construct;
412380
pub mod csmat;
381+
pub mod indptr;
413382
pub mod kronecker;
414383
pub mod linalg;
415384
pub mod permutation;

src/sparse/binop.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::sparse::csmat::CompressedStorage;
55
use crate::sparse::prelude::*;
66
use crate::sparse::vec::NnzEither::{Both, Left, Right};
77
use crate::sparse::vec::SparseIterTools;
8+
use crate::IndPtr;
89
use ndarray::{
910
self, Array, ArrayBase, ArrayView, ArrayViewMut, Axis, ShapeBuilder,
1011
};
@@ -125,7 +126,7 @@ where
125126
storage,
126127
nrows,
127128
ncols,
128-
indptr: out_indptr,
129+
indptr: IndPtr::new_trusted(out_indptr),
129130
indices: out_indices,
130131
data: out_data,
131132
}

0 commit comments

Comments
 (0)