1 // =============================================================================
2 // === spqr_happly =============================================================
3 // =============================================================================
4
5 // Applies a set n of sparse Householder vectors to a dense m-by-n matrix X.
6 //
7 // Let H(k) = I - Tau(k) * V(k) * V(k)', then either of the following is done:
8 //
9 // method 0: X = Q'*X
10 // X = H(nh-1) * ... * H(1) * H(0) * X where H is m-by-nh
11 //
12 // method 1: X = Q*X
13 // X = H(0)' * H(1)' * ... * H(nh-1)' * X where H is m-by-nh
14 //
15 // method 2: X = X*Q'
16 // X = X * H(nh-1) * ... * H(1) * H(0) where H is n-by-nh
17 //
18 // method 3: X = X*Q
19 // X = X * H(0)' * H(1) * ... * H(nh-1)' where H is n-by-nh
20 //
21 // The first nonzero entry in each column of H is assumed to be equal to 1.
22 // This function does not apply the row permutation vector (the Q.P part of
23 // the Q struct in the MATLAB interface).
24
25 #include "spqr.hpp"
26
27 // =============================================================================
28 // === spqr_private_do_panel ===================================================
29 // =============================================================================
30
31 // Loads V with a panel of Householder vectors and applies them to X
32
spqr_private_do_panel(int method,Long m,Long n,Long v,Long * Wi,Long h1,Long h2,Long * Hp,Long * Hi,Entry * Hx,Entry * Tau,Long * Wmap,Entry * X,Entry * V,Entry * C,Entry * W,cholmod_common * cc)33 template <typename Entry> void spqr_private_do_panel
34 (
35 // inputs, not modified
36 int method, // which method to use (0,1,2,3)
37 Long m,
38 Long n,
39 Long v, // number of Householder vectors in the panel
40 Long *Wi, // Wi [0:v-1] defines the pattern of the panel
41 Long h1, // load H (h1) to H (h2-1) into V
42 Long h2,
43
44 // FUTURE : make H cholmod_sparse:
45 Long *Hp, // Householder vectors: mh-by-nh sparse matrix
46 Long *Hi,
47 Entry *Hx,
48
49 Entry *Tau, // Householder coefficients (size nh)
50
51 // input/output
52 Long *Wmap, // inverse of Wi on input, set to all EMPTY on output
53 Entry *X, // m-by-n with leading dimension m
54
55 // workspace, undefined on input and output
56 Entry *V, // dense panel
57 Entry *C, // workspace
58 Entry *W, // workspace
59 cholmod_common *cc
60 )
61 {
62 Entry *V1 ;
63 Long h, k, p, i ;
64
65 // -------------------------------------------------------------------------
66 // load the panel with Householder vectors h1 ... h2-1
67 // -------------------------------------------------------------------------
68
69 // Wi [0 .. v-1] defines the pattern of the panel, and Wmap gives its
70 // inverse (Wmap [Wi [k]] == k for k = 0 to v-1). The V matrix is v-by-k.
71
72 #ifndef NDEBUG
73 for (k = 0 ; k < v ; k++) ASSERT (Wmap [Wi [k]] == k) ;
74 #endif
75
76 V1 = V ;
77 for (h = h1 ; h < h2 ; h++)
78 {
79 PR (("loading %ld\n", h)) ;
80 for (k = 0 ; k < v ; k++)
81 {
82 V1 [k] = 0 ;
83 }
84 for (p = Hp [h] ; p < Hp [h+1] ; p++)
85 {
86 i = Hi [p] ;
87 ASSERT (Wmap [i] >= 0 && Wmap [i] < v) ;
88 V1 [Wmap [i]] = Hx [p] ;
89 }
90 V1 += v ;
91 }
92
93 // -------------------------------------------------------------------------
94 // apply the panel
95 // -------------------------------------------------------------------------
96
97 spqr_panel (method, m, n, v, h2-h1, Wi, V, Tau+h1, m, X, C, W, cc) ;
98
99 // -------------------------------------------------------------------------
100 // clear the panel mapping
101 // -------------------------------------------------------------------------
102
103 for (k = 0 ; k < v ; k++)
104 {
105 i = Wi [k] ;
106 Wmap [i] = EMPTY ;
107 }
108 }
109
110
111 // =============================================================================
112 // === spqr_happly =============================================================
113 // =============================================================================
114
spqr_happly(int method,Long m,Long n,Long nh,Long * Hp,Long * Hi,Entry * Hx,Entry * Tau,Entry * X,Long vmax,Long hchunk,Long * Wi,Long * Wmap,Entry * C,Entry * V,cholmod_common * cc)115 template <typename Entry> void spqr_happly
116 (
117 // input
118 int method, // 0,1,2,3
119
120 Long m, // X is m-by-n with leading dimension m
121 Long n,
122
123 // FUTURE : make H cholmod_sparse:
124 Long nh, // number of Householder vectors
125 Long *Hp, // size nh+1, column pointers for H
126 Long *Hi, // size hnz = Hp [nh], row indices of H
127 Entry *Hx, // size hnz, Householder values. Note that the first
128 // entry in each column must be equal to 1.0
129
130 Entry *Tau, // size nh
131
132 // input/output
133 Entry *X, // size m-by-n with leading dimension m
134
135 // workspace
136 Long vmax,
137 Long hchunk,
138 Long *Wi, // size vmax
139 Long *Wmap, // size MAX(mh,1) where H is mh-by-nh; all EMPTY
140 Entry *C, // size csize
141 Entry *V, // size vsize
142 cholmod_common *cc
143 )
144 {
145 Entry *W ;
146 Long h, h1, h2, i, k, hmax, hmin, v, v1, p, done, v2, mh ;
147
148 // -------------------------------------------------------------------------
149 // get inputs
150 // -------------------------------------------------------------------------
151
152 if (m == 0 || n == 0 || nh == 0)
153 {
154 // nothing to do
155 return ;
156 }
157
158 // number of rows of H
159 mh = (method == 0 || method == 1) ? m : n ;
160
161 W = V + vmax * hchunk ;
162
163 // -------------------------------------------------------------------------
164 // apply the Householder vectors
165 // -------------------------------------------------------------------------
166
167 if (method == 0 || method == 3)
168 {
169
170 // ---------------------------------------------------------------------
171 // apply in forward direction
172 // ---------------------------------------------------------------------
173
174 PR (("\nHAPPLY Forward, method %d\n", method)) ;
175
176 for (h1 = 0 ; h1 < nh ; h1 = h2)
177 {
178
179 // -----------------------------------------------------------------
180 // start the panel with Householder vector h1
181 // -----------------------------------------------------------------
182
183 #ifndef NDEBUG
184 for (i = 0 ; i < mh ; i++) ASSERT (Wmap [i] == EMPTY) ;
185 PR (("\n ------ h1 %ld\n", h1)) ;
186 #endif
187
188 v = 0 ;
189 for (p = Hp [h1] ; p < Hp [h1+1] ; p++)
190 {
191 i = Hi [p] ;
192 Wmap [i] = v ;
193 Wi [v] = i ;
194 v++ ;
195 }
196 Long this_vmax = 2*v + 8 ; // max # rows in this panel
197 this_vmax = MIN (this_vmax, mh) ;
198 ASSERT (this_vmax <= vmax) ;
199
200 // -----------------------------------------------------------------
201 // acquire pattern of panel of Householder vectors
202 // -----------------------------------------------------------------
203
204 hmax = MIN (h1 + hchunk, nh) ; // at most h1 .. hmax-1 in panel
205 done = FALSE ;
206 for (h2 = h1+1 ; h2 < hmax ; h2++)
207 {
208 PR (("try %ld\n", h2)) ;
209 p = Hp [h2] ;
210 i = Hi [p] ;
211 // check to see that this vector fits in the lower triangle
212 if (h2-h1 >= v || Wi [h2-h1] != i)
213 {
214 // h2 will not be part of this panel
215 PR (("triangle broken\n")) ;
216 break ;
217 }
218 v1 = v ; // save this in case h2 is not part of panel
219 for ( ; p < Hp [h2+1] ; p++)
220 {
221 i = Hi [p] ;
222 if (Wmap [i] == EMPTY)
223 {
224 if (v >= this_vmax)
225 {
226 // h2 is not part of this panel
227 for (v2 = v1 ; v2 < v ; v2++)
228 {
229 // clear the partial column h2 from the panel
230 Wmap [Wi [v2]] = EMPTY ;
231 }
232 v = v1 ;
233 done = TRUE ;
234 PR (("too long\n")) ;
235 break ;
236 }
237 Wmap [i] = v ;
238 Wi [v] = i ;
239 v++ ;
240 }
241 }
242 if (done)
243 {
244 break ;
245 }
246 }
247
248 // -----------------------------------------------------------------
249 // load and apply the panel
250 // -----------------------------------------------------------------
251
252 spqr_private_do_panel (method, m, n, v, Wi, h1, h2, Hp, Hi, Hx, Tau,
253 Wmap, X, V, C, W, cc) ;
254 }
255
256 }
257 else
258 {
259
260 // ---------------------------------------------------------------------
261 // apply in backward direction
262 // ---------------------------------------------------------------------
263
264 PR (("\nHAPPLY Backward, method %d\n", method)) ;
265
266 for (h2 = nh ; h2 > 0 ; h2 = h1)
267 {
268
269 // -----------------------------------------------------------------
270 // start the panel with Householder vector h2-1 as the last one
271 // -----------------------------------------------------------------
272
273 #ifndef NDEBUG
274 for (i = 0 ; i < mh ; i++) ASSERT (Wmap [i] == EMPTY) ;
275 PR (("\n ------ h2 %ld\n", h2)) ;
276 #endif
277
278 // use Wi as a stack, growing upwards starting at Wi [vmax-1]
279 h = h2-1 ;
280 v = vmax ;
281 for (p = Hp [h+1]-1 ; p >= Hp [h] ; p--)
282 {
283 i = Hi [p] ;
284 v-- ;
285 Wmap [i] = v ; // this will be shifted later
286 Wi [v] = i ;
287 }
288 Long this_vmin = v - 32 ;
289 this_vmin = MAX (this_vmin, 0) ;
290
291 // -----------------------------------------------------------------
292 // acquire pattern of panel of Householder vectors
293 // -----------------------------------------------------------------
294
295 hmin = MAX (h2 - hchunk, 0) ; // at most hmin .. h2-1 in panel
296 done = FALSE ;
297
298 for (h1 = h2-2 ; h1 >= hmin ; h1--)
299 {
300 // try to add h1 to the panel
301 PR (("try %ld\n", h1)) ;
302
303 p = Hp [h1] ;
304
305 // check to see that this vector fits in the lower triangle
306 Long hlen = Hp [h1+1] - p ;
307 if (hlen > 1 && Hi [p+1] != Wi [v])
308 {
309 // h1 will not be part of this panel
310 h1++ ;
311 PR (("triangle broken\n")) ;
312 break ;
313 }
314
315 // ensure that the first entry of h1 is not in Wi
316 i = Hi [p] ;
317 if (Wmap [i] != EMPTY)
318 {
319 h1++ ;
320 PR (("first entry %ld present; triangle broken\n", i)) ;
321 break ;
322 }
323
324 // ensure that all of h1 is already in Wi (except first entry)
325 for (p++ ; p < Hp [h1+1] ; p++)
326 {
327 i = Hi [p] ;
328 if (Wmap [i] == EMPTY)
329 {
330 // h1 is not in the panel
331 done = TRUE ;
332 PR (("pattern broken\n")) ;
333 h1++ ;
334 break ;
335 }
336 }
337
338 if (done)
339 {
340 break;
341 }
342
343 // h1 is added to the panel
344 p = Hp [h1] ;
345 i = Hi [p] ;
346 v-- ;
347 Wi [v] = i ;
348 Wmap [i] = v ; // this will be shifted later
349
350 #ifndef NDEBUG
351 for (k = v ; k < vmax ; k++) ASSERT (Wmap [Wi [k]] == k) ;
352 #endif
353 }
354
355 h1 = MAX (h1, hmin) ;
356
357 // shift Wi upwards from Wi [v..vmax-1] to Wi [0...], and
358 // recompute Wmap
359
360 v2 = 0 ;
361 for (k = v ; k < vmax ; k++)
362 {
363 Wi [v2++] = Wi [k] ;
364 }
365 v = v2 ;
366
367 for (k = 0 ; k < v ; k++)
368 {
369 Wmap [Wi [k]] = k ;
370 }
371
372 // -----------------------------------------------------------------
373 // load and apply the panel
374 // -----------------------------------------------------------------
375
376 spqr_private_do_panel (method, m, n, v, Wi, h1, h2, Hp, Hi, Hx, Tau,
377 Wmap, X, V, C, W, cc) ;
378 }
379 }
380 }
381
382
383 // =============================================================================
384
385 template void spqr_happly <double>
386 (
387 // input
388 int method, // 0,1,2,3
389
390 Long m, // X is m-by-n
391 Long n,
392
393 Long nh, // number of Householder vectors
394 Long *Hp, // size nh+1, column pointers for H
395 Long *Hi, // size hnz = Hp [nh], row indices of H
396 double *Hx, // size hnz, Householder values. Note that the first
397 // entry in each column must be equal to 1.0
398
399 double *Tau, // size nh
400
401 // input/output
402 double *X, // size m-by-n with leading dimension m
403
404 // workspace
405 Long vmax,
406 Long hchunk,
407 Long *Wi, // size vmax
408 Long *Wmap, // size MAX(mh,1) where H is mh-by-nh
409 double *C, // size csize
410 double *V, // size vsize
411 cholmod_common *cc
412 ) ;
413
414 // =============================================================================
415
416 template void spqr_happly <Complex>
417 (
418 // input
419 int method, // 0,1,2,3
420
421 Long m, // X is m-by-n
422 Long n,
423
424 Long nh, // number of Householder vectors
425 Long *Hp, // size nh+1, column pointers for H
426 Long *Hi, // size hnz = Hp [nh], row indices of H
427 Complex *Hx, // size hnz, Householder values. Note that the first
428 // entry in each column must be equal to 1.0
429
430 Complex *Tau, // size nh
431
432 // input/output
433 Complex *X, // size m-by-n with leading dimension m
434
435 // workspace
436 Long vmax,
437 Long hchunk,
438 Long *Wi, // size vmax
439 Long *Wmap, // size MAX(mh,1) where H is mh-by-nh
440 Complex *C, // size csize
441 Complex *V, // size vsize
442 cholmod_common *cc
443 ) ;
444