Skip to content

Commit 0e03e31

Browse files
authored
Merge pull request #223 from vbarrielle/bind_suitesparse_camd
Bind suitesparse camd
2 parents e6b759f + c17ea19 commit 0e03e31

File tree

19 files changed

+457
-36
lines changed

19 files changed

+457
-36
lines changed

.github/workflows/ci.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,23 @@ jobs:
105105
override: true
106106

107107
- name: Build (exclude suitesparse)
108-
run: cargo build --verbose --workspace --exclude suitesparse_ldl_sys --exclude sprs_suitesparse_ldl
108+
run: cargo build --verbose --workspace --exclude suitesparse_ldl_sys --exclude sprs_suitesparse_ldl --exclude sprs_suitesparse_camd --exclude suitesparse_camd_sys
109109
if: matrix.os != 'ubuntu-18.04'
110110

111111
- name: Build (all)
112112
run: cargo build --verbose --workspace
113113
if: matrix.os == 'ubuntu-18.04'
114114

115115
- name: Test (exclude suitesparse)
116-
run: cargo test --verbose --workspace --exclude suitesparse_ldl_sys --exclude sprs_suitesparse_ldl
116+
run: cargo test --verbose --workspace --exclude suitesparse_ldl_sys --exclude sprs_suitesparse_ldl --exclude sprs_suitesparse_camd --exclude suitesparse_camd_sys
117117
if: matrix.os != 'ubuntu-18.04'
118118

119119
- name: Test (all)
120120
run: cargo test --verbose --workspace
121121
if: matrix.os == 'ubuntu-18.04'
122122

123123
- name: Test (suitesparse integration)
124-
run: cargo test -p sprs-ldl --features sprs_suitesparse_ldl -Zpackage-features
124+
run: cargo test -p sprs-ldl --features "sprs_suitesparse_ldl sprs_suitesparse_camd" -Zpackage-features
125125
if: matrix.os == 'ubuntu-18.04' && matrix.build == 'nightly'
126126

127127
benches:

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ script:
1919
- cargo test --release --all --verbose
2020
- cargo run --example heat
2121
- ./.travis_rustfmt
22-
- ./.travis_nightly
2322

2423
notifications:
2524
email:

.travis_nightly

-13
This file was deleted.

Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
name = "sprs"
44
description = "A sparse matrix library"
5-
version = "0.8.1"
5+
version = "0.9.0"
66
authors = ["Vincent Barrielle <[email protected]>"]
77
edition = "2018"
88

@@ -51,6 +51,8 @@ members = [
5151
"sprs-ldl",
5252
"suitesparse_bindings/suitesparse_ldl_sys",
5353
"suitesparse_bindings/sprs_suitesparse_ldl",
54+
"suitesparse_bindings/suitesparse_camd_sys",
55+
"suitesparse_bindings/sprs_suitesparse_camd",
5456
"sprs-rand",
5557
"sprs-benches",
5658
]

changelog.rst

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
Changelog
33
=========
44

5+
- 0.9.0
6+
- Make FillInReduction enum non exhaustive to prevent excessive breakage
7+
when new algorithms are implemented. **breaking change**
8+
- Make rayon optional **breaking change**
59
- 0.8.1
610
- Expose the ``num_kinds`` module to allow generic usage of matrix market
711
serialization functions in client crates

sprs-benches/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ authors = ["Vincent Barrielle <[email protected]>"]
55
edition = "2018"
66

77
[dependencies.sprs]
8-
version = "0.8.0"
8+
version = "0.9.0"
99
path = ".."
1010

1111
[dependencies.sprs-rand]
12-
version = "0.1.0"
12+
version = "0.2.0"
1313
path = "../sprs-rand"
1414

1515
[dependencies.plotters]

sprs-ldl/Cargo.toml

+11-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
name = "sprs-ldl"
44
description = "Sparse cholesky factorization"
5-
version = "0.6.1"
5+
version = "0.7.0"
66
authors = ["Vincent Barrielle"]
77
edition = "2018"
88

@@ -18,10 +18,18 @@ num-traits = "0.1.32"
1818

1919

2020
[dependencies.sprs]
21-
version = "0.8.0"
21+
version = "0.9.0"
2222
path = ".."
2323

2424
[dependencies.sprs_suitesparse_ldl]
25-
version = "0.4.0"
25+
version = "0.5.0"
2626
path = "../suitesparse_bindings/sprs_suitesparse_ldl"
2727
optional = true
28+
29+
[dependencies.sprs_suitesparse_camd]
30+
version = "0.1.0"
31+
path = "../suitesparse_bindings/sprs_suitesparse_camd"
32+
optional = true
33+
34+
[dev-dependencies]
35+
ndarray = ">=0.11.0,<0.14"

sprs-ldl/src/lib.rs

+56-2
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,22 @@ impl Ldl {
138138
pub fn perm<N, I>(&self, mat: CsMatViewI<N, I>) -> PermOwnedI<I>
139139
where
140140
I: SpIndex,
141-
N: Copy + PartialEq,
142141
{
143142
match self.fill_red_method {
144143
FillInReduction::NoReduction => PermOwnedI::identity(mat.rows()),
145144
FillInReduction::ReverseCuthillMcKee => {
146-
sprs::linalg::reverse_cuthill_mckee(mat).perm
145+
sprs::linalg::reverse_cuthill_mckee(mat.structure_view()).perm
146+
}
147+
FillInReduction::CAMDSuiteSparse => {
148+
#[cfg(not(feature = "sprs_suitesparse_camd"))]
149+
panic!("Unavailable without the `sprs_suitesparse_camd` feature");
150+
#[cfg(feature = "sprs_suitesparse_camd")]
151+
sprs_suitesparse_camd::camd(mat.structure_view())
152+
}
153+
_ => {
154+
unreachable!(
155+
"Unhandled method, report a bug at https://github.com/vbarrielle/sprs/issues/199"
156+
)
147157
}
148158
}
149159
}
@@ -861,4 +871,48 @@ mod test {
861871
let x = ldlt.solve(&b);
862872
assert_eq!(x, x0);
863873
}
874+
875+
#[cfg(feature = "sprs_suitesparse_camd")]
876+
#[test]
877+
fn camd_ldl_solve() {
878+
// 0 - A - 2 - 3
879+
// | \ | \ | / |
880+
// 7 - 5 - 6 - 4
881+
// | / | / | \ |
882+
// 8 - 9 - 1 - E
883+
#[rustfmt::skip]
884+
let triangles = ndarray::arr2(
885+
&[[0, 7, 5],
886+
[0, 5, 10],
887+
[10, 5, 6],
888+
[10, 6, 2],
889+
[2, 6, 3],
890+
[3, 6, 4],
891+
[7, 8, 5],
892+
[5, 8, 9],
893+
[5, 9, 6],
894+
[6, 9, 1],
895+
[6, 1, 11],
896+
[6, 11, 4]],
897+
);
898+
let lap_mat =
899+
sprs::special_mats::tri_mesh_graph_laplacian(12, triangles.view());
900+
let ldlt_camd = super::Ldl::new()
901+
.check_symmetry(super::SymmetryCheck::DontCheckSymmetry)
902+
.fill_in_reduction(super::FillInReduction::CAMDSuiteSparse)
903+
.numeric(lap_mat.view())
904+
.unwrap();
905+
let ldlt_cuthill = super::Ldl::new()
906+
.check_symmetry(super::SymmetryCheck::DontCheckSymmetry)
907+
.fill_in_reduction(super::FillInReduction::ReverseCuthillMcKee)
908+
.numeric(lap_mat.view())
909+
.unwrap();
910+
let ldlt_raw = super::Ldl::new()
911+
.check_symmetry(super::SymmetryCheck::DontCheckSymmetry)
912+
.fill_in_reduction(super::FillInReduction::NoReduction)
913+
.numeric(lap_mat.view())
914+
.unwrap();
915+
assert!(ldlt_camd.nnz() < ldlt_raw.nnz());
916+
assert!(ldlt_camd.nnz() < ldlt_cuthill.nnz());
917+
}
864918
}

sprs-rand/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "sprs-rand"
33
description = "Random sparse matrix generation"
4-
version = "0.1.0"
4+
version = "0.2.0"
55
authors = ["Vincent Barrielle <[email protected]>"]
66
license = "MIT OR Apache-2.0"
77
edition = "2018"
@@ -13,5 +13,5 @@ rand_distr = "0.2.2"
1313
rand_pcg = "0.2.1"
1414

1515
[dependencies.sprs]
16-
version = "0.8.0"
16+
version = "0.9.0"
1717
path = ".."

src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ pub use crate::sparse::{
9393
csmat::CsIter, csmat::OuterIterator, csmat::OuterIteratorMut,
9494
csmat::OuterIteratorPerm, kronecker::kronecker_product, CsMat, CsMatBase,
9595
CsMatI, CsMatVecView, CsMatView, CsMatViewI, CsMatViewMut, CsMatViewMutI,
96-
CsVec, CsVecBase, CsVecI, CsVecView, CsVecViewI, CsVecViewMut,
97-
CsVecViewMutI, SparseMat, TriMat, TriMatBase, TriMatI, TriMatIter,
98-
TriMatView, TriMatViewI, TriMatViewMut, TriMatViewMutI,
96+
CsStructure, CsStructureI, CsStructureView, CsStructureViewI, CsVec,
97+
CsVecBase, CsVecI, CsVecView, CsVecViewI, CsVecViewMut, CsVecViewMutI,
98+
SparseMat, TriMat, TriMatBase, TriMatI, TriMatIter, TriMatView,
99+
TriMatViewI, TriMatViewMut, TriMatViewMutI,
99100
};
100101

101102
pub use crate::sparse::symmetric::is_symmetric;
@@ -152,9 +153,11 @@ pub use PermutationCheck::*;
152153

153154
/// The different kinds of fill-in-reduction algorithms supported by sprs
154155
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
156+
#[non_exhaustive]
155157
pub enum FillInReduction {
156158
NoReduction,
157159
ReverseCuthillMcKee,
160+
CAMDSuiteSparse,
158161
}
159162

160163
#[cfg(feature = "approx")]

src/sparse.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ pub type CsMatViewMut<'a, N> = CsMatViewMutI<'a, N, usize>;
111111
// FIXME: a fixed size array would be better, but no Deref impl
112112
pub type CsMatVecView<'a, N> = CsMatVecView_<'a, N, usize>;
113113

114+
pub type CsStructureViewI<'a, I, Iptr = I> = CsMatViewI<'a, (), I, Iptr>;
115+
pub type CsStructureView<'a> = CsStructureViewI<'a, usize>;
116+
pub type CsStructureI<I, Iptr = I> = CsMatI<(), I, Iptr>;
117+
pub type CsStructure = CsStructureI<usize>;
118+
114119
/// A sparse vector, storing the indices of its non-zero data.
115120
///
116121
/// A `CsVec` represents a sparse vector by storing a sorted `indices()` array
@@ -235,10 +240,11 @@ pub struct TriMatIter<RI, CI, DI> {
235240
mod prelude {
236241
pub use super::{
237242
CsMat, CsMatBase, CsMatI, CsMatVecView, CsMatVecView_, CsMatView,
238-
CsMatViewI, CsMatViewMut, CsMatViewMutI, CsVec, CsVecBase, CsVecI,
239-
CsVecView, CsVecViewI, CsVecViewMut, CsVecViewMutI, SparseMat, TriMat,
240-
TriMatBase, TriMatI, TriMatIter, TriMatView, TriMatViewI,
241-
TriMatViewMut, TriMatViewMutI,
243+
CsMatViewI, CsMatViewMut, CsMatViewMutI, CsStructure, CsStructureI,
244+
CsStructureView, CsStructureViewI, CsVec, CsVecBase, CsVecI, CsVecView,
245+
CsVecViewI, CsVecViewMut, CsVecViewMutI, SparseMat, TriMat, TriMatBase,
246+
TriMatI, TriMatIter, TriMatView, TriMatViewI, TriMatViewMut,
247+
TriMatViewMutI,
242248
};
243249
}
244250

src/sparse/csmat.rs

+22
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,28 @@ where
11271127
}
11281128
}
11291129

1130+
pub fn structure_view(&self) -> CsStructureViewI<I, Iptr> {
1131+
// Safety: std::slice::from_raw_parts requires its passed
1132+
// pointer to be valid for the whole length of the slice. We have a
1133+
// zero-sized type, so the length is zero, and since we cast
1134+
// a non-null pointer, the pointer is valid as all pointers to zero-sized
1135+
// types are valid if they are not null.
1136+
let zst_data = unsafe {
1137+
std::slice::from_raw_parts(
1138+
self.data.as_ptr() as *const (),
1139+
self.data.len(),
1140+
)
1141+
};
1142+
CsStructureViewI {
1143+
storage: self.storage,
1144+
nrows: self.nrows,
1145+
ncols: self.ncols,
1146+
indptr: &self.indptr[..],
1147+
indices: &self.indices[..],
1148+
data: zst_data,
1149+
}
1150+
}
1151+
11301152
pub fn to_dense(&self) -> Array<N, Ix2>
11311153
where
11321154
N: Clone + Zero,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "sprs_suitesparse_camd"
3+
description = "sprs bindings to the suitesparse camd fill-in reducting ordering"
4+
version = "0.1.0"
5+
authors = ["Vincent Barrielle <[email protected]>"]
6+
edition = "2018"
7+
keywords = ["sparse", "matrix", "fill-in", "permutation", "suitesparse"]
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
11+
[dependencies.sprs]
12+
version = "0.9.0"
13+
path = "../.."
14+
15+
[dependencies.suitesparse_camd_sys]
16+
path = "../suitesparse_camd_sys/"
17+
version = "0.1.0"

0 commit comments

Comments
 (0)