| 1 | #include "cs.h" |
|---|
| 2 | /* compute nonzero pattern of L(k,:) */ |
|---|
| 3 | static |
|---|
| 4 | int cs_ereach (cs *A, int j, int k, int *parent, int *s, int *w, double *x, |
|---|
| 5 | int top) |
|---|
| 6 | { |
|---|
| 7 | int i, p, len, *Ap = A->p, *Ai = A->i ; |
|---|
| 8 | double *Ax = A->x ; |
|---|
| 9 | for (p = Ap [j] ; p < Ap [j+1] ; p++) /* get pattern of L(k,:) */ |
|---|
| 10 | { |
|---|
| 11 | i = Ai [p] ; /* A(i,k) is nonzero */ |
|---|
| 12 | if (i > k) continue ; /* only use upper triangular part of A */ |
|---|
| 13 | x [i] = Ax [p] ; /* x(i) = A(i,k) */ |
|---|
| 14 | for (len = 0 ; w [i] != k ; i = parent [i]) /* traverse up etree */ |
|---|
| 15 | { |
|---|
| 16 | s [len++] = i ; /* L(k,i) is nonzero */ |
|---|
| 17 | w [i] = k ; /* mark i as visited */ |
|---|
| 18 | } |
|---|
| 19 | while (len > 0) s [--top] = s [--len] ; /* push path onto stack */ |
|---|
| 20 | } |
|---|
| 21 | return (top) ; /* s [top..n-1] contains pattern of L(k,:)*/ |
|---|
| 22 | } |
|---|
| 23 | |
|---|
| 24 | /* L = chol (A, [Pinv parent cp]), Pinv is optional */ |
|---|
| 25 | csn *cs_chol (cs *A, css *S) |
|---|
| 26 | { |
|---|
| 27 | double d, lki, *Lx, *x ; |
|---|
| 28 | int top, i, p, k, n, *Li, *Lp, *cp, *Pinv, *w, *s, *c, *parent ; |
|---|
| 29 | cs *L, *C, *E ; |
|---|
| 30 | csn *N ; |
|---|
| 31 | if (!A || !S || !S->cp || !S->parent) return (NULL) ; /* check inputs */ |
|---|
| 32 | n = A->n ; |
|---|
| 33 | N = cs_calloc (1, sizeof (csn)) ; |
|---|
| 34 | w = cs_malloc (3*n, sizeof (int)) ; s = w + n, c = w + 2*n ; |
|---|
| 35 | x = cs_malloc (n, sizeof (double)) ; |
|---|
| 36 | cp = S->cp ; Pinv = S->Pinv ; parent = S->parent ; |
|---|
| 37 | C = Pinv ? cs_symperm (A, Pinv, 1) : A ; |
|---|
| 38 | E = Pinv ? C : NULL ; |
|---|
| 39 | if (!N || !w || !x || !C) return (cs_ndone (N, E, w, x, 0)) ; |
|---|
| 40 | N->L = L = cs_spalloc (n, n, cp [n], 1, 0) ; |
|---|
| 41 | if (!L) return (cs_ndone (N, E, w, x, 0)) ; |
|---|
| 42 | Lp = L->p ; Li = L->i ; Lx = L->x ; |
|---|
| 43 | for (k = 0 ; k < n ; k++) |
|---|
| 44 | { |
|---|
| 45 | Lp [k] = c [k] = cp [k] ; /* column k of L starts here */ |
|---|
| 46 | x [k] = 0 ; /* x (0:k) is now zero */ |
|---|
| 47 | w [k] = k ; /* mark node k as visited */ |
|---|
| 48 | top = cs_ereach (C, k, k, parent, s, w, x, n) ; /* find row k of L*/ |
|---|
| 49 | d = x [k] ; /* d = C(k,k) */ |
|---|
| 50 | x [k] = 0 ; /* clear workspace for k+1st iteration */ |
|---|
| 51 | for ( ; top < n ; top++) /* solve L(0:k-1,0:k-1) * x = C(:,k) */ |
|---|
| 52 | { |
|---|
| 53 | i = s [top] ; /* s [top..n-1] is pattern of L(k,:) */ |
|---|
| 54 | lki = x [i] / Lx [Lp [i]] ; /* L(k,i) = x (i) / L(i,i) */ |
|---|
| 55 | x [i] = 0 ; /* clear workspace for k+1st iteration */ |
|---|
| 56 | for (p = Lp [i] + 1 ; p < c [i] ; p++) |
|---|
| 57 | { |
|---|
| 58 | x [Li [p]] -= Lx [p] * lki ; |
|---|
| 59 | } |
|---|
| 60 | d -= lki*lki ; /* d = d - L(k,i)*L(k,i) */ |
|---|
| 61 | p = c [i]++ ; |
|---|
| 62 | Li [p] = k ; /* store L(k,i) in column i */ |
|---|
| 63 | Lx [p] = lki ; |
|---|
| 64 | } |
|---|
| 65 | if (d <= 0) return (cs_ndone (N, E, w, x, 0)) ; /* not pos def */ |
|---|
| 66 | p = c [k]++ ; |
|---|
| 67 | Li [p] = k ; /* store L(k,k) = sqrt (d) in column k */ |
|---|
| 68 | Lx [p] = sqrt (d) ; |
|---|
| 69 | } |
|---|
| 70 | Lp [n] = cp [n] ; /* finalize L */ |
|---|
| 71 | return (cs_ndone (N, E, w, x, 1)) ; /* success: free E,w,x; return N */ |
|---|
| 72 | } |
|---|