first untested sparse implementation

This commit is contained in:
Magnus Ulimoen
2020-06-12 21:04:18 +02:00
parent 9261f1b239
commit 4f772b8dc5
6 changed files with 802 additions and 40 deletions

View File

@@ -9,10 +9,12 @@ ndarray = { version = "0.13.1", features = ["approx"] }
approx = "0.3.2"
packed_simd = "0.3.3"
rayon = { version = "1.3.0", optional = true }
sprs = { version = "0.7.1", optional = true }
[features]
# Use f32 as precision, default is f64
f32 = []
sparse = ["sprs"]
[dev-dependencies]
criterion = "0.3.1"

View File

@@ -11,6 +11,14 @@ pub trait SbpOperator1d: Send + Sync {
fn is_h2(&self) -> bool {
false
}
#[cfg(feature = "sparse")]
fn diff_matrix(&self, n: usize) -> sprs::CsMat<Float> {
unimplemented!()
}
#[cfg(feature = "sparse")]
fn h_matrix(&self, n: usize) -> sprs::CsMat<Float> {
unimplemented!()
}
}
pub trait SbpOperator2d: Send + Sync {
@@ -517,6 +525,95 @@ fn diff_op_row(
}
}
#[cfg(feature = "sparse")]
fn sparse_from_block(
block: &[&[Float]],
diag: &[Float],
symmetry: Symmetry,
optype: OperatorType,
n: usize,
) -> sprs::CsMat<Float> {
assert!(n >= 2 * block.len());
let nnz = {
let block_elems = block.iter().fold(0, |acc, x| {
acc + x
.iter()
.fold(0, |acc, &x| if x != 0.0 { acc + 1 } else { acc })
});
let diag_elems = diag
.iter()
.fold(0, |acc, &x| if x != 0.0 { acc + 1 } else { acc });
2 * block_elems + (n - 2 * block.len()) * diag_elems
};
let mut mat = sprs::TriMat::with_capacity((n, n), nnz);
let dx = if optype == OperatorType::H2 {
1.0 / (n - 2) as Float
} else {
1.0 / (n - 1) as Float
};
let idx = 1.0 / dx;
for (j, bl) in block.iter().enumerate() {
for (i, &b) in bl.iter().enumerate() {
if b == 0.0 {
continue;
}
mat.add_triplet(j, i, b * idx);
}
}
for j in block.len()..n - block.len() {
let half_diag_len = diag.len() / 2;
for (&d, i) in diag.iter().zip(j - half_diag_len..) {
if d == 0.0 {
continue;
}
mat.add_triplet(j, i, d * idx);
}
}
for (bl, j) in block.iter().zip((0..n).rev()).rev() {
for (&b, i) in bl.iter().zip((0..n).rev()).rev() {
if b == 0.0 {
continue;
}
if symmetry == Symmetry::AntiSymmetric {
mat.add_triplet(j, i, -b * idx);
} else {
mat.add_triplet(j, i, b * idx);
}
}
}
mat.to_csr()
}
#[cfg(feature = "sparse")]
fn h_matrix(diag: &[Float], n: usize, is_h2: bool) -> sprs::CsMat<Float> {
let h = if is_h2 {
1.0 / (n - 2) as Float
} else {
1.0 / (n - 1) as Float
};
let nmiddle = n - 2 * diag.len();
let iter = diag
.iter()
.chain(std::iter::repeat(&1.0).take(nmiddle))
.chain(diag.iter().rev())
.map(|&x| h * x);
let mut mat = sprs::TriMat::with_capacity((n, n), n);
for (i, d) in iter.enumerate() {
mat.add_triplet(i, i, d);
}
mat.to_csr()
}
mod upwind4;
pub use upwind4::Upwind4;
mod upwind9;

View File

@@ -207,6 +207,20 @@ impl SbpOperator1d for Upwind4 {
fn h(&self) -> &'static [Float] {
Self::HBLOCK
}
#[cfg(feature = "sparse")]
fn diff_matrix(&self, n: usize) -> sprs::CsMat<Float> {
super::sparse_from_block(
Self::BLOCK,
Self::DIAG,
super::Symmetry::AntiSymmetric,
super::OperatorType::Normal,
n,
)
}
#[cfg(feature = "sparse")]
fn h_matrix(&self, n: usize) -> sprs::CsMat<Float> {
super::h_matrix(Self::DIAG, n, self.is_h2())
}
}
impl<SBP: SbpOperator1d> SbpOperator2d for (&SBP, &Upwind4) {