UNPKG

3.92 kBJavaScriptView Raw
1import { factory } from '../../../utils/factory'
2import { csEreach } from './csEreach'
3import { createCsSymperm } from './csSymperm'
4
5const name = 'csChol'
6const dependencies = [
7 'divideScalar',
8 'sqrt',
9 'subtract',
10 'multiply',
11 'im',
12 're',
13 'conj',
14 'equal',
15 'smallerEq',
16 'SparseMatrix'
17]
18
19export const createCsChol = /* #__PURE__ */ factory(name, dependencies, (
20 {
21 divideScalar,
22 sqrt,
23 subtract,
24 multiply,
25 im,
26 re,
27 conj,
28 equal,
29 smallerEq,
30 SparseMatrix
31 }
32) => {
33 const csSymperm = createCsSymperm({ conj, SparseMatrix })
34
35 /**
36 * Computes the Cholesky factorization of matrix A. It computes L and P so
37 * L * L' = P * A * P'
38 *
39 * @param {Matrix} m The A Matrix to factorize, only upper triangular part used
40 * @param {Object} s The symbolic analysis from cs_schol()
41 *
42 * @return {Number} The numeric Cholesky factorization of A or null
43 *
44 * Reference: http://faculty.cse.tamu.edu/davis/publications.html
45 */
46 return function csChol (m, s) {
47 // validate input
48 if (!m) { return null }
49 // m arrays
50 const size = m._size
51 // columns
52 const n = size[1]
53 // symbolic analysis result
54 const parent = s.parent
55 const cp = s.cp
56 const pinv = s.pinv
57 // L arrays
58 const lvalues = []
59 const lindex = []
60 const lptr = []
61 // L
62 const L = new SparseMatrix({
63 values: lvalues,
64 index: lindex,
65 ptr: lptr,
66 size: [n, n]
67 })
68 // vars
69 const c = [] // (2 * n)
70 const x = [] // (n)
71 // compute C = P * A * P'
72 const cm = pinv ? csSymperm(m, pinv, 1) : m
73 // C matrix arrays
74 const cvalues = cm._values
75 const cindex = cm._index
76 const cptr = cm._ptr
77 // vars
78 let k, p
79 // initialize variables
80 for (k = 0; k < n; k++) { lptr[k] = c[k] = cp[k] }
81 // compute L(k,:) for L*L' = C
82 for (k = 0; k < n; k++) {
83 // nonzero pattern of L(k,:)
84 let top = csEreach(cm, k, parent, c)
85 // x (0:k) is now zero
86 x[k] = 0
87 // x = full(triu(C(:,k)))
88 for (p = cptr[k]; p < cptr[k + 1]; p++) {
89 if (cindex[p] <= k) { x[cindex[p]] = cvalues[p] }
90 }
91 // d = C(k,k)
92 let d = x[k]
93 // clear x for k+1st iteration
94 x[k] = 0
95 // solve L(0:k-1,0:k-1) * x = C(:,k)
96 for (; top < n; top++) {
97 // s[top..n-1] is pattern of L(k,:)
98 const i = s[top]
99 // L(k,i) = x (i) / L(i,i)
100 const lki = divideScalar(x[i], lvalues[lptr[i]])
101 // clear x for k+1st iteration
102 x[i] = 0
103 for (p = lptr[i] + 1; p < c[i]; p++) {
104 // row
105 const r = lindex[p]
106 // update x[r]
107 x[r] = subtract(x[r], multiply(lvalues[p], lki))
108 }
109 // d = d - L(k,i)*L(k,i)
110 d = subtract(d, multiply(lki, conj(lki)))
111 p = c[i]++
112 // store L(k,i) in column i
113 lindex[p] = k
114 lvalues[p] = conj(lki)
115 }
116 // compute L(k,k)
117 if (smallerEq(re(d), 0) || !equal(im(d), 0)) {
118 // not pos def
119 return null
120 }
121 p = c[k]++
122 // store L(k,k) = sqrt(d) in column k
123 lindex[p] = k
124 lvalues[p] = sqrt(d)
125 }
126 // finalize L
127 lptr[n] = cp[n]
128 // P matrix
129 let P
130 // check we need to calculate P
131 if (pinv) {
132 // P arrays
133 const pvalues = []
134 const pindex = []
135 const pptr = []
136 // create P matrix
137 for (p = 0; p < n; p++) {
138 // initialize ptr (one value per column)
139 pptr[p] = p
140 // index (apply permutation vector)
141 pindex.push(pinv[p])
142 // value 1
143 pvalues.push(1)
144 }
145 // update ptr
146 pptr[n] = n
147 // P
148 P = new SparseMatrix({
149 values: pvalues,
150 index: pindex,
151 ptr: pptr,
152 size: [n, n]
153 })
154 }
155 // return L & P
156 return {
157 L: L,
158 P: P
159 }
160 }
161})