Avoid bound-checking on cholesky decomposition.
This commit is contained in:
parent
9bf1d0280d
commit
50d0b64924
|
@ -21,7 +21,6 @@ where
|
||||||
// equal to `original_i.len()` at the end.
|
// equal to `original_i.len()` at the end.
|
||||||
original_p: Vec<usize>,
|
original_p: Vec<usize>,
|
||||||
original_i: Vec<usize>,
|
original_i: Vec<usize>,
|
||||||
original_len: usize, // Number of elements on the numerical value vector of the original matrix.
|
|
||||||
// Decomposition result.
|
// Decomposition result.
|
||||||
l: CsMatrix<N, D, D>,
|
l: CsMatrix<N, D, D>,
|
||||||
// Used only for the pattern.
|
// Used only for the pattern.
|
||||||
|
@ -63,7 +62,6 @@ where
|
||||||
CsCholesky {
|
CsCholesky {
|
||||||
original_p,
|
original_p,
|
||||||
original_i: m.data.i.clone(),
|
original_i: m.data.i.clone(),
|
||||||
original_len: m.data.i.len(),
|
|
||||||
l,
|
l,
|
||||||
u,
|
u,
|
||||||
ok: false,
|
ok: false,
|
||||||
|
@ -91,7 +89,7 @@ where
|
||||||
// Performs the numerical Cholesky decomposition given the set of numerical values.
|
// Performs the numerical Cholesky decomposition given the set of numerical values.
|
||||||
pub fn decompose(&mut self, values: &[N]) -> bool {
|
pub fn decompose(&mut self, values: &[N]) -> bool {
|
||||||
assert!(
|
assert!(
|
||||||
values.len() >= self.original_len,
|
values.len() >= self.original_i.len(),
|
||||||
"The set of values is too small."
|
"The set of values is too small."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -100,51 +98,64 @@ where
|
||||||
|
|
||||||
// Perform the decomposition.
|
// Perform the decomposition.
|
||||||
for k in 0..self.l.nrows() {
|
for k in 0..self.l.nrows() {
|
||||||
// Scatter the k-th column of the original matrix with the values provided.
|
unsafe {
|
||||||
let column_range = self.original_p[k]..self.original_p[k + 1];
|
// Scatter the k-th column of the original matrix with the values provided.
|
||||||
|
let column_range =
|
||||||
|
*self.original_p.get_unchecked(k)..*self.original_p.get_unchecked(k + 1);
|
||||||
|
|
||||||
self.work_x[k] = N::zero();
|
*self.work_x.vget_unchecked_mut(k) = N::zero();
|
||||||
for p in column_range.clone() {
|
for p in column_range.clone() {
|
||||||
let irow = self.original_i[p];
|
let irow = *self.original_i.get_unchecked(p);
|
||||||
|
|
||||||
if irow <= k {
|
if irow <= k {
|
||||||
self.work_x[irow] = values[p];
|
*self.work_x.vget_unchecked_mut(irow) = *values.get_unchecked(p);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut diag = self.work_x[k];
|
|
||||||
self.work_x[k] = N::zero();
|
|
||||||
|
|
||||||
// Triangular solve.
|
|
||||||
for irow in self.u.data.column_row_indices(k) {
|
|
||||||
if irow >= k {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let lki = self.work_x[irow] / self.l.data.vals[self.l.data.p[irow]];
|
let mut diag = *self.work_x.vget_unchecked(k);
|
||||||
self.work_x[irow] = N::zero();
|
*self.work_x.vget_unchecked_mut(k) = N::zero();
|
||||||
|
|
||||||
for p in self.l.data.p[irow] + 1..self.work_c[irow] {
|
// Triangular solve.
|
||||||
self.work_x[self.l.data.i[p]] -= self.l.data.vals[p] * lki;
|
for irow in self.u.data.column_row_indices(k) {
|
||||||
|
if irow >= k {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lki = *self.work_x.vget_unchecked(irow)
|
||||||
|
/ *self
|
||||||
|
.l
|
||||||
|
.data
|
||||||
|
.vals
|
||||||
|
.get_unchecked(*self.l.data.p.vget_unchecked(irow));
|
||||||
|
*self.work_x.vget_unchecked_mut(irow) = N::zero();
|
||||||
|
|
||||||
|
for p in
|
||||||
|
*self.l.data.p.vget_unchecked(irow) + 1..*self.work_c.vget_unchecked(irow)
|
||||||
|
{
|
||||||
|
*self
|
||||||
|
.work_x
|
||||||
|
.vget_unchecked_mut(*self.l.data.i.get_unchecked(p)) -=
|
||||||
|
*self.l.data.vals.get_unchecked(p) * lki;
|
||||||
|
}
|
||||||
|
|
||||||
|
diag -= lki * lki;
|
||||||
|
let p = *self.work_c.vget_unchecked(irow);
|
||||||
|
*self.work_c.vget_unchecked_mut(irow) += 1;
|
||||||
|
*self.l.data.i.get_unchecked_mut(p) = k;
|
||||||
|
*self.l.data.vals.get_unchecked_mut(p) = lki;
|
||||||
}
|
}
|
||||||
|
|
||||||
diag -= lki * lki;
|
if diag <= N::zero() {
|
||||||
let p = self.work_c[irow];
|
self.ok = false;
|
||||||
self.work_c[irow] += 1;
|
return false;
|
||||||
self.l.data.i[p] = k;
|
}
|
||||||
self.l.data.vals[p] = lki;
|
|
||||||
}
|
|
||||||
|
|
||||||
if diag <= N::zero() {
|
// Deal with the diagonal element.
|
||||||
self.ok = false;
|
let p = *self.work_c.vget_unchecked(k);
|
||||||
return false;
|
*self.work_c.vget_unchecked_mut(k) += 1;
|
||||||
|
*self.l.data.i.get_unchecked_mut(p) = k;
|
||||||
|
*self.l.data.vals.get_unchecked_mut(p) = diag.sqrt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deal with the diagonal element.
|
|
||||||
let p = self.work_c[k];
|
|
||||||
self.work_c[k] += 1;
|
|
||||||
self.l.data.i[p] = k;
|
|
||||||
self.l.data.vals[p] = diag.sqrt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ok = true;
|
self.ok = true;
|
||||||
|
|
Loading…
Reference in New Issue