comparison liboctave/SparseQR.cc @ 5610:9761b7d24e9e

[project @ 2006-02-09 09:12:02 by dbateman]
author dbateman
date Thu, 09 Feb 2006 09:12:03 +0000
parents
children 69a4f320d95a
comparison
equal deleted inserted replaced
5609:bf96b0f9dbd7 5610:9761b7d24e9e
1 /*
2
3 Copyright (C) 2005 David Bateman
4
5 Octave is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
9
10 Octave is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <vector>
26
27 #include "lo-error.h"
28 #include "SparseQR.h"
29
30 SparseQR::SparseQR_rep::SparseQR_rep (const SparseMatrix& a, int order)
31 {
32 #ifdef HAVE_CXSPARSE
33 CXSPARSE_DNAME (cs) A;
34 A.nzmax = a.nzmax ();
35 A.m = a.rows ();
36 A.n = a.cols ();
37 nrows = A.m;
38 // Cast away const on A, with full knowledge that CSparse won't touch it
39 // Prevents the methods below making a copy of the data.
40 A.p = const_cast<octave_idx_type *>(a.cidx ());
41 A.i = const_cast<octave_idx_type *>(a.ridx ());
42 A.x = const_cast<double *>(a.data ());
43 A.nz = -1;
44 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
45 S = CXSPARSE_DNAME (cs_sqr) (&A, order, 1);
46 N = CXSPARSE_DNAME (cs_qr) (&A, S);
47 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
48 if (!N)
49 (*current_liboctave_error_handler)
50 ("SparseQR: sparse matrix QR factorization filled");
51 count = 1;
52 #else
53 (*current_liboctave_error_handler)
54 ("SparseQR: sparse matrix QR factorization not implemented");
55 #endif
56 }
57
58 SparseQR::SparseQR_rep::~SparseQR_rep (void)
59 {
60 #ifdef HAVE_CXSPARSE
61 CXSPARSE_DNAME (cs_sfree) (S);
62 CXSPARSE_DNAME (cs_nfree) (N);
63 #endif
64 }
65
66 SparseMatrix
67 SparseQR::SparseQR_rep::V (void) const
68 {
69 #ifdef HAVE_CXSPARSE
70 // Drop zeros from V and sort
71 // XXX FIXME XXX Is the double transpose to sort necessary?
72 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
73 CXSPARSE_DNAME (cs_dropzeros) (N->L);
74 CXSPARSE_DNAME (cs) *D = CXSPARSE_DNAME (cs_transpose) (N->L, 1);
75 CXSPARSE_DNAME (cs_spfree) (N->L);
76 N->L = CXSPARSE_DNAME (cs_transpose) (D, 1);
77 CXSPARSE_DNAME (cs_spfree) (D);
78 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
79
80 octave_idx_type nc = N->L->n;
81 octave_idx_type nz = N->L->nzmax;
82 SparseMatrix ret (N->L->m, nc, nz);
83 for (octave_idx_type j = 0; j < nc+1; j++)
84 ret.xcidx (j) = N->L->p[j];
85 for (octave_idx_type j = 0; j < nz; j++)
86 {
87 ret.xridx (j) = N->L->i[j];
88 ret.xdata (j) = N->L->x[j];
89 }
90 return ret;
91 #else
92 return SparseMatrix ();
93 #endif
94 }
95
96 ColumnVector
97 SparseQR::SparseQR_rep::Pinv (void) const
98 {
99 #ifdef HAVE_CXSPARSE
100 ColumnVector ret(N->L->m);
101 for (octave_idx_type i = 0; i < N->L->m; i++)
102 ret.xelem(i) = S->Pinv[i];
103 return ret;
104 #else
105 return ColumnVector ();
106 #endif
107 }
108
109 ColumnVector
110 SparseQR::SparseQR_rep::P (void) const
111 {
112 #ifdef HAVE_CXSPARSE
113 ColumnVector ret(N->L->m);
114 for (octave_idx_type i = 0; i < N->L->m; i++)
115 ret.xelem(S->Pinv[i]) = i;
116 return ret;
117 #else
118 return ColumnVector ();
119 #endif
120 }
121
122 SparseMatrix
123 SparseQR::SparseQR_rep::R (const bool econ) const
124 {
125 #ifdef HAVE_CXSPARSE
126 // Drop zeros from R and sort
127 // XXX FIXME XXX Is the double transpose to sort necessary?
128 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
129 CXSPARSE_DNAME (cs_dropzeros) (N->U);
130 CXSPARSE_DNAME (cs) *D = CXSPARSE_DNAME (cs_transpose) (N->U, 1);
131 CXSPARSE_DNAME (cs_spfree) (N->U);
132 N->U = CXSPARSE_DNAME (cs_transpose) (D, 1);
133 CXSPARSE_DNAME (cs_spfree) (D);
134 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
135
136 octave_idx_type nc = N->U->n;
137 octave_idx_type nz = N->U->nzmax;
138
139 SparseMatrix ret ((econ ? (nc > nrows ? nrows : nc) : nrows), nc, nz);
140
141 for (octave_idx_type j = 0; j < nc+1; j++)
142 ret.xcidx (j) = N->U->p[j];
143 for (octave_idx_type j = 0; j < nz; j++)
144 {
145 ret.xridx (j) = N->U->i[j];
146 ret.xdata (j) = N->U->x[j];
147 }
148 return ret;
149 #else
150 return SparseMatrix ();
151 #endif
152 }
153
154 Matrix
155 SparseQR::SparseQR_rep::C (const Matrix &b) const
156 {
157 #ifdef HAVE_CXSPARSE
158 octave_idx_type b_nr = b.rows();
159 octave_idx_type b_nc = b.cols();
160 octave_idx_type nc = N->L->n;
161 octave_idx_type nr = nrows;
162 const double *bvec = b.fortran_vec();
163 Matrix ret(b_nr,b_nc);
164 double *vec = ret.fortran_vec();
165 if (nr < 1 || nc < 1 || nr != b_nr)
166 (*current_liboctave_error_handler) ("matrix dimension mismatch");
167 else
168 {
169 OCTAVE_LOCAL_BUFFER (double, buf, S->m2);
170 for (volatile octave_idx_type j = 0, idx = 0; j < b_nc; j++, idx+=b_nr)
171 {
172 OCTAVE_QUIT;
173 volatile octave_idx_type nm = (nr < nc ? nr : nc);
174 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
175 // cast away const on bvec, with full knowledge that CSparse
176 // won't touch it
177 CXSPARSE_DNAME (cs_ipvec) (b_nr, S->Pinv, bvec + idx, buf);
178 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
179
180 for (volatile octave_idx_type i = 0; i < nm; i++)
181 {
182 OCTAVE_QUIT;
183 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
184 CXSPARSE_DNAME (cs_happly) (N->L, i, N->B[i], buf);
185 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
186 }
187 for (octave_idx_type i = 0; i < b_nr; i++)
188 vec[i+idx] = buf[i];
189 }
190 }
191 return ret;
192 #else
193 return Matrix ();
194 #endif
195 }
196
197 Matrix
198 qrsolve(const SparseMatrix&a, const Matrix &b, octave_idx_type& info)
199 {
200 #ifdef HAVE_CXSPARSE
201 octave_idx_type nr = a.rows();
202 octave_idx_type nc = a.cols();
203 octave_idx_type b_nc = b.cols();
204 octave_idx_type b_nr = b.rows();
205 const double *bvec = b.fortran_vec();
206 Matrix x;
207 info = 0;
208
209 if (nr < 1 || nc < 1 || nr != b_nr)
210 (*current_liboctave_error_handler)
211 ("matrix dimension mismatch in solution of minimum norm problem");
212 else if (nr >= nc)
213 {
214 SparseQR q (a, 2);
215 if (! q.ok ())
216 {
217 info = -1;
218 return Matrix();
219 }
220 x.resize(nc, b_nc);
221 double *vec = x.fortran_vec();
222 OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
223 for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc;
224 i++, idx+=nc, bidx+=b_nr)
225 {
226 OCTAVE_QUIT;
227 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
228 // cast away const on bvec, with full knowledge that CSparse
229 // won't touch it
230 CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, bvec + bidx, buf);
231 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
232 for (volatile octave_idx_type j = 0; j < nc; j++)
233 {
234 OCTAVE_QUIT;
235 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
236 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
237 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
238 }
239 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
240 CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf);
241 CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, vec + idx);
242 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
243 }
244 }
245 else
246 {
247 SparseMatrix at = a.hermitian();
248 SparseQR q (at, 2);
249 if (! q.ok ())
250 {
251 info = -1;
252 return Matrix();
253 }
254 x.resize(nc, b_nc);
255 double *vec = x.fortran_vec();
256 OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2);
257 for (volatile octave_idx_type i = 0, idx = 0, bidx = 0; i < b_nc;
258 i++, idx+=nc, bidx+=b_nr)
259 {
260 OCTAVE_QUIT;
261 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
262 // cast away const on bvec, with full knowledge that CSparse
263 // won't touch it
264 CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, bvec + bidx, buf);
265 CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf);
266 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
267 for (volatile octave_idx_type j = nr-1; j >= 0; j--)
268 {
269 OCTAVE_QUIT;
270 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
271 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
272 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
273 }
274 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
275 CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, vec + idx);
276 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
277 }
278 }
279
280 return x;
281 #else
282 return Matrix ();
283 #endif
284 }
285
286 SparseMatrix
287 qrsolve(const SparseMatrix&a, const SparseMatrix &b, octave_idx_type &info)
288 {
289 #ifdef HAVE_CXSPARSE
290 octave_idx_type nr = a.rows();
291 octave_idx_type nc = a.cols();
292 octave_idx_type b_nr = b.rows();
293 octave_idx_type b_nc = b.cols();
294 SparseMatrix x;
295 volatile octave_idx_type ii, x_nz;
296 info = 0;
297
298 if (nr < 1 || nc < 1 || nr != b_nr)
299 (*current_liboctave_error_handler)
300 ("matrix dimension mismatch in solution of minimum norm problem");
301 else if (nr >= nc)
302 {
303 SparseQR q (a, 2);
304 if (! q.ok ())
305 {
306 info = -1;
307 return SparseMatrix();
308 }
309 x = SparseMatrix (nc, b_nc, b.nzmax());
310 x.xcidx(0) = 0;
311 x_nz = b.nzmax();
312 ii = 0;
313 OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
314 OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
315 for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
316 {
317 OCTAVE_QUIT;
318 for (octave_idx_type j = 0; j < b_nr; j++)
319 Xx[j] = b.xelem(j,i);
320 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
321 CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xx, buf);
322 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
323 for (volatile octave_idx_type j = 0; j < nc; j++)
324 {
325 OCTAVE_QUIT;
326 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
327 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
328 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
329 }
330 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
331 CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf);
332 CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xx);
333 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
334
335 for (octave_idx_type j = 0; j < nc; j++)
336 {
337 double tmp = Xx[j];
338 if (tmp != 0.0)
339 {
340 if (ii == x_nz)
341 {
342 // Resize the sparse matrix
343 octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
344 sz = (sz > 10 ? sz : 10) + x_nz;
345 x.change_capacity (sz);
346 x_nz = sz;
347 }
348 x.xdata(ii) = tmp;
349 x.xridx(ii++) = j;
350 }
351 }
352 x.xcidx(i+1) = ii;
353 }
354 }
355 else
356 {
357 SparseMatrix at = a.hermitian();
358 SparseQR q (at, 2);
359 if (! q.ok ())
360 {
361 info = -1;
362 return SparseMatrix();
363 }
364 x = SparseMatrix (nc, b_nc, b.nzmax());
365 x.xcidx(0) = 0;
366 x_nz = b.nzmax();
367 ii = 0;
368 OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
369 OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2);
370 for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
371 {
372 OCTAVE_QUIT;
373 for (octave_idx_type j = 0; j < b_nr; j++)
374 Xx[j] = b.xelem(j,i);
375 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
376 CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xx, buf);
377 CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf);
378 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
379 for (volatile octave_idx_type j = nr-1; j >= 0; j--)
380 {
381 OCTAVE_QUIT;
382 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
383 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
384 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
385 }
386 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
387 CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xx);
388 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
389
390 for (octave_idx_type j = 0; j < nc; j++)
391 {
392 double tmp = Xx[j];
393 if (tmp != 0.0)
394 {
395 if (ii == x_nz)
396 {
397 // Resize the sparse matrix
398 octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
399 sz = (sz > 10 ? sz : 10) + x_nz;
400 x.change_capacity (sz);
401 x_nz = sz;
402 }
403 x.xdata(ii) = tmp;
404 x.xridx(ii++) = j;
405 }
406 }
407 x.xcidx(i+1) = ii;
408 }
409 }
410
411 x.maybe_compress ();
412 return x;
413 #else
414 return SparseMatrix ();
415 #endif
416 }
417
418 ComplexMatrix
419 qrsolve(const SparseMatrix&a, const ComplexMatrix &b, octave_idx_type &info)
420 {
421 #ifdef HAVE_CXSPARSE
422 octave_idx_type nr = a.rows();
423 octave_idx_type nc = a.cols();
424 octave_idx_type b_nc = b.cols();
425 octave_idx_type b_nr = b.rows();
426 ComplexMatrix x;
427 info = 0;
428
429 if (nr < 1 || nc < 1 || nr != b_nr)
430 (*current_liboctave_error_handler)
431 ("matrix dimension mismatch in solution of minimum norm problem");
432 else if (nr >= nc)
433 {
434 SparseQR q (a, 2);
435 if (! q.ok ())
436 {
437 info = -1;
438 return ComplexMatrix();
439 }
440 x.resize(nc, b_nc);
441 Complex *vec = x.fortran_vec();
442 OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
443 OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
444 OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
445 for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
446 {
447 OCTAVE_QUIT;
448 for (octave_idx_type j = 0; j < b_nr; j++)
449 {
450 Complex c = b.xelem (j,i);
451 Xx[j] = std::real (c);
452 Xz[j] = std::imag (c);
453 }
454 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
455 CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xx, buf);
456 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
457 for (volatile octave_idx_type j = 0; j < nc; j++)
458 {
459 OCTAVE_QUIT;
460 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
461 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
462 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
463 }
464 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
465 CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf);
466 CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xx);
467
468 CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xz, buf);
469 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
470 for (volatile octave_idx_type j = 0; j < nc; j++)
471 {
472 OCTAVE_QUIT;
473 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
474 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
475 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
476 }
477 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
478 CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf);
479 CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xz);
480 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
481 for (octave_idx_type j = 0; j < nc; j++)
482 vec[j+idx] = Complex (Xx[j], Xz[j]);
483 }
484 }
485 else
486 {
487 SparseMatrix at = a.hermitian();
488 SparseQR q (at, 2);
489 if (! q.ok ())
490 {
491 info = -1;
492 return ComplexMatrix();
493 }
494 x.resize(nc, b_nc);
495 Complex *vec = x.fortran_vec();
496 OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
497 OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
498 OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2);
499 for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
500 {
501 OCTAVE_QUIT;
502 for (octave_idx_type j = 0; j < b_nr; j++)
503 {
504 Complex c = b.xelem (j,i);
505 Xx[j] = std::real (c);
506 Xz[j] = std::imag (c);
507 }
508 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
509 CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xx, buf);
510 CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf);
511 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
512 for (volatile octave_idx_type j = nr-1; j >= 0; j--)
513 {
514 OCTAVE_QUIT;
515 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
516 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
517 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
518 }
519 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
520 CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xx);
521 CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xz, buf);
522 CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf);
523 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
524 for (volatile octave_idx_type j = nr-1; j >= 0; j--)
525 {
526 OCTAVE_QUIT;
527 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
528 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
529 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
530 }
531 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
532 CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xz);
533 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
534 for (octave_idx_type j = 0; j < nc; j++)
535 vec[j+idx] = Complex (Xx[j], Xz[j]);
536 }
537 }
538
539 return x;
540 #else
541 return ComplexMatrix ();
542 #endif
543 }
544
545 SparseComplexMatrix
546 qrsolve(const SparseMatrix&a, const SparseComplexMatrix &b, octave_idx_type &info)
547 {
548 #ifdef HAVE_CXSPARSE
549 octave_idx_type nr = a.rows();
550 octave_idx_type nc = a.cols();
551 octave_idx_type b_nr = b.rows();
552 octave_idx_type b_nc = b.cols();
553 SparseComplexMatrix x;
554 volatile octave_idx_type ii, x_nz;
555 info = 0;
556
557 if (nr < 1 || nc < 1 || nr != b_nr)
558 (*current_liboctave_error_handler)
559 ("matrix dimension mismatch in solution of minimum norm problem");
560 else if (nr >= nc)
561 {
562 SparseQR q (a, 2);
563 if (! q.ok ())
564 {
565 info = -1;
566 return SparseComplexMatrix();
567 }
568 x = SparseComplexMatrix (nc, b_nc, b.nzmax());
569 x.xcidx(0) = 0;
570 x_nz = b.nzmax();
571 ii = 0;
572 OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
573 OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
574 OCTAVE_LOCAL_BUFFER (double, buf, q.S()->m2);
575 for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
576 {
577 OCTAVE_QUIT;
578 for (octave_idx_type j = 0; j < b_nr; j++)
579 {
580 Complex c = b.xelem (j,i);
581 Xx[j] = std::real (c);
582 Xz[j] = std::imag (c);
583 }
584 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
585 CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xx, buf);
586 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
587 for (volatile octave_idx_type j = 0; j < nc; j++)
588 {
589 OCTAVE_QUIT;
590 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
591 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
592 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
593 }
594 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
595 CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf);
596 CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xx);
597 CXSPARSE_DNAME (cs_ipvec) (nr, q.S()->Pinv, Xz, buf);
598 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
599 for (volatile octave_idx_type j = 0; j < nc; j++)
600 {
601 OCTAVE_QUIT;
602 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
603 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
604 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
605 }
606 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
607 CXSPARSE_DNAME (cs_usolve) (q.N()->U, buf);
608 CXSPARSE_DNAME (cs_ipvec) (nc, q.S()->Q, buf, Xz);
609 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
610
611 for (octave_idx_type j = 0; j < nc; j++)
612 {
613 Complex tmp = Complex (Xx[j], Xz[j]);
614 if (tmp != 0.0)
615 {
616 if (ii == x_nz)
617 {
618 // Resize the sparse matrix
619 octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
620 sz = (sz > 10 ? sz : 10) + x_nz;
621 x.change_capacity (sz);
622 x_nz = sz;
623 }
624 x.xdata(ii) = tmp;
625 x.xridx(ii++) = j;
626 }
627 }
628 x.xcidx(i+1) = ii;
629 }
630 }
631 else
632 {
633 SparseMatrix at = a.hermitian();
634 SparseQR q (at, 2);
635 if (! q.ok ())
636 {
637 info = -1;
638 return SparseComplexMatrix();
639 }
640 x = SparseComplexMatrix (nc, b_nc, b.nzmax());
641 x.xcidx(0) = 0;
642 x_nz = b.nzmax();
643 ii = 0;
644 OCTAVE_LOCAL_BUFFER (double, Xx, (b_nr > nc ? b_nr : nc));
645 OCTAVE_LOCAL_BUFFER (double, Xz, (b_nr > nc ? b_nr : nc));
646 OCTAVE_LOCAL_BUFFER (double, buf, nc > q.S()->m2 ? nc : q.S()->m2);
647 for (volatile octave_idx_type i = 0, idx = 0; i < b_nc; i++, idx+=nc)
648 {
649 OCTAVE_QUIT;
650 for (octave_idx_type j = 0; j < b_nr; j++)
651 {
652 Complex c = b.xelem (j,i);
653 Xx[j] = std::real (c);
654 Xz[j] = std::imag (c);
655 }
656 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
657 CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xx, buf);
658 CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf);
659 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
660 for (volatile octave_idx_type j = nr-1; j >= 0; j--)
661 {
662 OCTAVE_QUIT;
663 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
664 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
665 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
666 }
667 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
668 CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xx);
669 CXSPARSE_DNAME (cs_pvec) (nr, q.S()->Q, Xz, buf);
670 CXSPARSE_DNAME (cs_utsolve) (q.N()->U, buf);
671 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
672 for (volatile octave_idx_type j = nr-1; j >= 0; j--)
673 {
674 OCTAVE_QUIT;
675 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
676 CXSPARSE_DNAME (cs_happly) (q.N()->L, j, q.N()->B[j], buf);
677 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
678 }
679 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
680 CXSPARSE_DNAME (cs_pvec) (nc, q.S()->Pinv, buf, Xz);
681 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
682
683 for (octave_idx_type j = 0; j < nc; j++)
684 {
685 Complex tmp = Complex (Xx[j], Xz[j]);
686 if (tmp != 0.0)
687 {
688 if (ii == x_nz)
689 {
690 // Resize the sparse matrix
691 octave_idx_type sz = x_nz * (b_nc - i) / b_nc;
692 sz = (sz > 10 ? sz : 10) + x_nz;
693 x.change_capacity (sz);
694 x_nz = sz;
695 }
696 x.xdata(ii) = tmp;
697 x.xridx(ii++) = j;
698 }
699 }
700 x.xcidx(i+1) = ii;
701 }
702 }
703
704 x.maybe_compress ();
705 return x;
706 #else
707 return SparseComplexMatrix ();
708 #endif
709 }
710
711 /*
712 ;;; Local Variables: ***
713 ;;; mode: C++ ***
714 ;;; End: ***
715 */