5164
|
1 /* |
|
2 |
|
3 Copyright (C) 2004 David Bateman |
|
4 Copyright (C) 1998-2004 Andy Adler |
|
5 |
|
6 Octave is free software; you can redistribute it and/or modify it |
|
7 under the terms of the GNU General Public License as published by the |
|
8 Free Software Foundation; either version 2, or (at your option) any |
|
9 later version. |
|
10 |
|
11 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 for more details. |
|
15 |
|
16 You should have received a copy of the GNU General Public License |
5307
|
17 along with this program; see the file COPYING. If not, write to the |
|
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
19 Boston, MA 02110-1301, USA. |
5164
|
20 |
|
21 */ |
|
22 |
|
23 #ifdef HAVE_CONFIG_H |
|
24 #include <config.h> |
|
25 #endif |
|
26 |
|
27 #include <cfloat> |
|
28 |
|
29 #include <iostream> |
|
30 #include <vector> |
|
31 |
|
32 #include "quit.h" |
|
33 #include "lo-ieee.h" |
|
34 #include "lo-mappers.h" |
|
35 #include "f77-fcn.h" |
|
36 #include "dRowVector.h" |
|
37 |
|
38 #include "CSparse.h" |
|
39 #include "boolSparse.h" |
|
40 #include "dSparse.h" |
|
41 #include "oct-spparms.h" |
|
42 #include "SparseCmplxLU.h" |
5451
|
43 #include "oct-sparse.h" |
5506
|
44 #include "sparse-util.h" |
|
45 #include "SparseCmplxCHOL.h" |
5610
|
46 #include "SparseCmplxQR.h" |
5164
|
47 |
5587
|
48 #include "oct-sort.h" |
|
49 |
5681
|
50 // Define whether to use a basic QR solver or one that uses a Dulmange |
|
51 // Mendelsohn factorization to seperate the problem into under-determined, |
|
52 // well-determined and over-determined parts and solves them seperately |
|
53 #ifndef USE_QRSOLVE |
|
54 #include "sparse-dmsolve.cc" |
|
55 #endif |
|
56 |
5164
|
57 // Fortran functions we call. |
|
58 extern "C" |
|
59 { |
|
60 F77_RET_T |
5275
|
61 F77_FUNC (zgbtrf, ZGBTRF) (const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, |
|
62 const octave_idx_type&, Complex*, const octave_idx_type&, octave_idx_type*, octave_idx_type&); |
5164
|
63 |
|
64 F77_RET_T |
5275
|
65 F77_FUNC (zgbtrs, ZGBTRS) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, |
|
66 const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, |
|
67 const Complex*, const octave_idx_type&, |
|
68 const octave_idx_type*, Complex*, const octave_idx_type&, octave_idx_type& |
5164
|
69 F77_CHAR_ARG_LEN_DECL); |
|
70 |
|
71 F77_RET_T |
5275
|
72 F77_FUNC (zgbcon, ZGBCON) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, |
|
73 const octave_idx_type&, const octave_idx_type&, Complex*, |
|
74 const octave_idx_type&, const octave_idx_type*, const double&, |
|
75 double&, Complex*, double*, octave_idx_type& |
5164
|
76 F77_CHAR_ARG_LEN_DECL); |
|
77 |
|
78 F77_RET_T |
5275
|
79 F77_FUNC (zpbtrf, ZPBTRF) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, |
|
80 const octave_idx_type&, Complex*, const octave_idx_type&, octave_idx_type& |
5164
|
81 F77_CHAR_ARG_LEN_DECL); |
|
82 |
|
83 F77_RET_T |
5275
|
84 F77_FUNC (zpbtrs, ZPBTRS) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, |
|
85 const octave_idx_type&, const octave_idx_type&, Complex*, const octave_idx_type&, |
|
86 Complex*, const octave_idx_type&, octave_idx_type& |
5164
|
87 F77_CHAR_ARG_LEN_DECL); |
|
88 |
|
89 F77_RET_T |
5275
|
90 F77_FUNC (zpbcon, ZPBCON) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, |
|
91 const octave_idx_type&, Complex*, const octave_idx_type&, |
5681
|
92 const double&, double&, Complex*, double*, octave_idx_type& |
5164
|
93 F77_CHAR_ARG_LEN_DECL); |
|
94 |
|
95 F77_RET_T |
5275
|
96 F77_FUNC (zgttrf, ZGTTRF) (const octave_idx_type&, Complex*, Complex*, Complex*, |
|
97 Complex*, octave_idx_type*, octave_idx_type&); |
5164
|
98 |
|
99 F77_RET_T |
5275
|
100 F77_FUNC (zgttrs, ZGTTRS) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, |
|
101 const octave_idx_type&, const Complex*, const Complex*, |
|
102 const Complex*, const Complex*, const octave_idx_type*, |
|
103 Complex *, const octave_idx_type&, octave_idx_type& |
5164
|
104 F77_CHAR_ARG_LEN_DECL); |
|
105 |
|
106 F77_RET_T |
5322
|
107 F77_FUNC (zptsv, ZPTSV) (const octave_idx_type&, const octave_idx_type&, double*, Complex*, |
5275
|
108 Complex*, const octave_idx_type&, octave_idx_type&); |
5164
|
109 |
|
110 F77_RET_T |
5275
|
111 F77_FUNC (zgtsv, ZGTSV) (const octave_idx_type&, const octave_idx_type&, Complex*, Complex*, |
|
112 Complex*, Complex*, const octave_idx_type&, octave_idx_type&); |
5164
|
113 } |
|
114 |
|
115 SparseComplexMatrix::SparseComplexMatrix (const SparseMatrix& a) |
5681
|
116 : MSparse<Complex> (a.rows (), a.cols (), a.nnz ()) |
5164
|
117 { |
5275
|
118 octave_idx_type nc = cols (); |
5681
|
119 octave_idx_type nz = a.nnz (); |
5275
|
120 |
|
121 for (octave_idx_type i = 0; i < nc + 1; i++) |
5164
|
122 cidx (i) = a.cidx (i); |
|
123 |
5275
|
124 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
125 { |
5681
|
126 data (i) = Complex (a.data (i)); |
5164
|
127 ridx (i) = a.ridx (i); |
|
128 } |
|
129 } |
|
130 |
|
131 SparseComplexMatrix::SparseComplexMatrix (const SparseBoolMatrix& a) |
5681
|
132 : MSparse<Complex> (a.rows (), a.cols (), a.nnz ()) |
5164
|
133 { |
5275
|
134 octave_idx_type nc = cols (); |
5681
|
135 octave_idx_type nz = a.nnz (); |
5275
|
136 |
|
137 for (octave_idx_type i = 0; i < nc + 1; i++) |
5164
|
138 cidx (i) = a.cidx (i); |
|
139 |
5275
|
140 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
141 { |
5681
|
142 data (i) = Complex (a.data (i)); |
5164
|
143 ridx (i) = a.ridx (i); |
|
144 } |
|
145 } |
|
146 |
|
147 bool |
|
148 SparseComplexMatrix::operator == (const SparseComplexMatrix& a) const |
|
149 { |
5275
|
150 octave_idx_type nr = rows (); |
|
151 octave_idx_type nc = cols (); |
5681
|
152 octave_idx_type nz = nnz (); |
5275
|
153 octave_idx_type nr_a = a.rows (); |
|
154 octave_idx_type nc_a = a.cols (); |
5681
|
155 octave_idx_type nz_a = a.nnz (); |
5164
|
156 |
|
157 if (nr != nr_a || nc != nc_a || nz != nz_a) |
|
158 return false; |
|
159 |
5275
|
160 for (octave_idx_type i = 0; i < nc + 1; i++) |
5164
|
161 if (cidx(i) != a.cidx(i)) |
|
162 return false; |
|
163 |
5275
|
164 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
165 if (data(i) != a.data(i) || ridx(i) != a.ridx(i)) |
|
166 return false; |
|
167 |
|
168 return true; |
|
169 } |
|
170 |
|
171 bool |
|
172 SparseComplexMatrix::operator != (const SparseComplexMatrix& a) const |
|
173 { |
|
174 return !(*this == a); |
|
175 } |
|
176 |
|
177 bool |
|
178 SparseComplexMatrix::is_hermitian (void) const |
|
179 { |
5275
|
180 octave_idx_type nr = rows (); |
|
181 octave_idx_type nc = cols (); |
5164
|
182 |
6207
|
183 if (nr == nc && nr > 0) |
5164
|
184 { |
6207
|
185 for (octave_idx_type j = 0; j < nc; j++) |
|
186 { |
|
187 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
188 { |
|
189 octave_idx_type ri = ridx(i); |
|
190 |
|
191 if (ri != j) |
|
192 { |
|
193 bool found = false; |
|
194 |
|
195 for (octave_idx_type k = cidx(ri); k < cidx(ri+1); k++) |
|
196 { |
|
197 if (ridx(k) == j) |
|
198 { |
|
199 if (data(i) == conj(data(k))) |
|
200 found = true; |
|
201 break; |
|
202 } |
|
203 } |
|
204 |
|
205 if (! found) |
|
206 return false; |
|
207 } |
|
208 } |
|
209 } |
5164
|
210 |
|
211 return true; |
|
212 } |
|
213 |
|
214 return false; |
|
215 } |
|
216 |
|
217 static const Complex Complex_NaN_result (octave_NaN, octave_NaN); |
|
218 |
|
219 SparseComplexMatrix |
|
220 SparseComplexMatrix::max (int dim) const |
|
221 { |
5275
|
222 Array2<octave_idx_type> dummy_idx; |
5164
|
223 return max (dummy_idx, dim); |
|
224 } |
|
225 |
|
226 SparseComplexMatrix |
5275
|
227 SparseComplexMatrix::max (Array2<octave_idx_type>& idx_arg, int dim) const |
5164
|
228 { |
|
229 SparseComplexMatrix result; |
|
230 dim_vector dv = dims (); |
|
231 |
|
232 if (dv.numel () == 0 || dim > dv.length () || dim < 0) |
|
233 return result; |
|
234 |
5275
|
235 octave_idx_type nr = dv(0); |
|
236 octave_idx_type nc = dv(1); |
5164
|
237 |
|
238 if (dim == 0) |
|
239 { |
|
240 idx_arg.resize (1, nc); |
5275
|
241 octave_idx_type nel = 0; |
|
242 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
243 { |
|
244 Complex tmp_max; |
|
245 double abs_max = octave_NaN; |
5275
|
246 octave_idx_type idx_j = 0; |
|
247 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
248 { |
|
249 if (ridx(i) != idx_j) |
|
250 break; |
|
251 else |
|
252 idx_j++; |
|
253 } |
|
254 |
|
255 if (idx_j != nr) |
|
256 { |
|
257 tmp_max = 0.; |
|
258 abs_max = 0.; |
|
259 } |
|
260 |
5275
|
261 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
262 { |
|
263 Complex tmp = data (i); |
|
264 |
5389
|
265 if (xisnan (tmp)) |
5164
|
266 continue; |
|
267 |
5261
|
268 double abs_tmp = std::abs (tmp); |
5164
|
269 |
5389
|
270 if (xisnan (abs_max) || abs_tmp > abs_max) |
5164
|
271 { |
|
272 idx_j = ridx (i); |
|
273 tmp_max = tmp; |
|
274 abs_max = abs_tmp; |
|
275 } |
|
276 } |
|
277 |
5389
|
278 idx_arg.elem (j) = xisnan (tmp_max) ? 0 : idx_j; |
5164
|
279 if (abs_max != 0.) |
|
280 nel++; |
|
281 } |
|
282 |
|
283 result = SparseComplexMatrix (1, nc, nel); |
|
284 |
5275
|
285 octave_idx_type ii = 0; |
5164
|
286 result.xcidx (0) = 0; |
5275
|
287 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
288 { |
|
289 Complex tmp = elem (idx_arg(j), j); |
|
290 if (tmp != 0.) |
|
291 { |
|
292 result.xdata (ii) = tmp; |
|
293 result.xridx (ii++) = 0; |
|
294 } |
|
295 result.xcidx (j+1) = ii; |
|
296 } |
|
297 } |
|
298 else |
|
299 { |
|
300 idx_arg.resize (nr, 1, 0); |
|
301 |
5275
|
302 for (octave_idx_type i = cidx(0); i < cidx(1); i++) |
5164
|
303 idx_arg.elem(ridx(i)) = -1; |
|
304 |
5275
|
305 for (octave_idx_type j = 0; j < nc; j++) |
|
306 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
307 { |
|
308 if (idx_arg.elem(i) != -1) |
|
309 continue; |
|
310 bool found = false; |
5275
|
311 for (octave_idx_type k = cidx(j); k < cidx(j+1); k++) |
5164
|
312 if (ridx(k) == i) |
|
313 { |
|
314 found = true; |
|
315 break; |
|
316 } |
|
317 |
|
318 if (!found) |
|
319 idx_arg.elem(i) = j; |
|
320 |
|
321 } |
|
322 |
5275
|
323 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
324 { |
5275
|
325 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
326 { |
5275
|
327 octave_idx_type ir = ridx (i); |
|
328 octave_idx_type ix = idx_arg.elem (ir); |
5164
|
329 Complex tmp = data (i); |
|
330 |
5389
|
331 if (xisnan (tmp)) |
5164
|
332 continue; |
5261
|
333 else if (ix == -1 || std::abs(tmp) > std::abs(elem (ir, ix))) |
5164
|
334 idx_arg.elem (ir) = j; |
|
335 } |
|
336 } |
|
337 |
5275
|
338 octave_idx_type nel = 0; |
|
339 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
340 if (idx_arg.elem(j) == -1 || elem (j, idx_arg.elem (j)) != 0.) |
|
341 nel++; |
|
342 |
|
343 result = SparseComplexMatrix (nr, 1, nel); |
|
344 |
5275
|
345 octave_idx_type ii = 0; |
5164
|
346 result.xcidx (0) = 0; |
|
347 result.xcidx (1) = nel; |
5275
|
348 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
349 { |
|
350 if (idx_arg(j) == -1) |
|
351 { |
|
352 idx_arg(j) = 0; |
|
353 result.xdata (ii) = Complex_NaN_result; |
|
354 result.xridx (ii++) = j; |
|
355 } |
|
356 else |
|
357 { |
|
358 Complex tmp = elem (j, idx_arg(j)); |
|
359 if (tmp != 0.) |
|
360 { |
|
361 result.xdata (ii) = tmp; |
|
362 result.xridx (ii++) = j; |
|
363 } |
|
364 } |
|
365 } |
|
366 } |
|
367 |
|
368 return result; |
|
369 } |
|
370 |
|
371 SparseComplexMatrix |
|
372 SparseComplexMatrix::min (int dim) const |
|
373 { |
5275
|
374 Array2<octave_idx_type> dummy_idx; |
5164
|
375 return min (dummy_idx, dim); |
|
376 } |
|
377 |
|
378 SparseComplexMatrix |
5275
|
379 SparseComplexMatrix::min (Array2<octave_idx_type>& idx_arg, int dim) const |
5164
|
380 { |
|
381 SparseComplexMatrix result; |
|
382 dim_vector dv = dims (); |
|
383 |
|
384 if (dv.numel () == 0 || dim > dv.length () || dim < 0) |
|
385 return result; |
|
386 |
5275
|
387 octave_idx_type nr = dv(0); |
|
388 octave_idx_type nc = dv(1); |
5164
|
389 |
|
390 if (dim == 0) |
|
391 { |
|
392 idx_arg.resize (1, nc); |
5275
|
393 octave_idx_type nel = 0; |
|
394 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
395 { |
|
396 Complex tmp_min; |
|
397 double abs_min = octave_NaN; |
5275
|
398 octave_idx_type idx_j = 0; |
|
399 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
400 { |
|
401 if (ridx(i) != idx_j) |
|
402 break; |
|
403 else |
|
404 idx_j++; |
|
405 } |
|
406 |
|
407 if (idx_j != nr) |
|
408 { |
|
409 tmp_min = 0.; |
|
410 abs_min = 0.; |
|
411 } |
|
412 |
5275
|
413 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
414 { |
|
415 Complex tmp = data (i); |
|
416 |
5389
|
417 if (xisnan (tmp)) |
5164
|
418 continue; |
|
419 |
5261
|
420 double abs_tmp = std::abs (tmp); |
5164
|
421 |
5389
|
422 if (xisnan (abs_min) || abs_tmp < abs_min) |
5164
|
423 { |
|
424 idx_j = ridx (i); |
|
425 tmp_min = tmp; |
|
426 abs_min = abs_tmp; |
|
427 } |
|
428 } |
|
429 |
5389
|
430 idx_arg.elem (j) = xisnan (tmp_min) ? 0 : idx_j; |
5164
|
431 if (abs_min != 0.) |
|
432 nel++; |
|
433 } |
|
434 |
|
435 result = SparseComplexMatrix (1, nc, nel); |
|
436 |
5275
|
437 octave_idx_type ii = 0; |
5164
|
438 result.xcidx (0) = 0; |
5275
|
439 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
440 { |
|
441 Complex tmp = elem (idx_arg(j), j); |
|
442 if (tmp != 0.) |
|
443 { |
|
444 result.xdata (ii) = tmp; |
|
445 result.xridx (ii++) = 0; |
|
446 } |
|
447 result.xcidx (j+1) = ii; |
|
448 } |
|
449 } |
|
450 else |
|
451 { |
|
452 idx_arg.resize (nr, 1, 0); |
|
453 |
5275
|
454 for (octave_idx_type i = cidx(0); i < cidx(1); i++) |
5164
|
455 idx_arg.elem(ridx(i)) = -1; |
|
456 |
5275
|
457 for (octave_idx_type j = 0; j < nc; j++) |
|
458 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
459 { |
|
460 if (idx_arg.elem(i) != -1) |
|
461 continue; |
|
462 bool found = false; |
5275
|
463 for (octave_idx_type k = cidx(j); k < cidx(j+1); k++) |
5164
|
464 if (ridx(k) == i) |
|
465 { |
|
466 found = true; |
|
467 break; |
|
468 } |
|
469 |
|
470 if (!found) |
|
471 idx_arg.elem(i) = j; |
|
472 |
|
473 } |
|
474 |
5275
|
475 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
476 { |
5275
|
477 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
478 { |
5275
|
479 octave_idx_type ir = ridx (i); |
|
480 octave_idx_type ix = idx_arg.elem (ir); |
5164
|
481 Complex tmp = data (i); |
|
482 |
5389
|
483 if (xisnan (tmp)) |
5164
|
484 continue; |
5261
|
485 else if (ix == -1 || std::abs(tmp) < std::abs(elem (ir, ix))) |
5164
|
486 idx_arg.elem (ir) = j; |
|
487 } |
|
488 } |
|
489 |
5275
|
490 octave_idx_type nel = 0; |
|
491 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
492 if (idx_arg.elem(j) == -1 || elem (j, idx_arg.elem (j)) != 0.) |
|
493 nel++; |
|
494 |
|
495 result = SparseComplexMatrix (nr, 1, nel); |
|
496 |
5275
|
497 octave_idx_type ii = 0; |
5164
|
498 result.xcidx (0) = 0; |
|
499 result.xcidx (1) = nel; |
5275
|
500 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
501 { |
|
502 if (idx_arg(j) == -1) |
|
503 { |
|
504 idx_arg(j) = 0; |
|
505 result.xdata (ii) = Complex_NaN_result; |
|
506 result.xridx (ii++) = j; |
|
507 } |
|
508 else |
|
509 { |
|
510 Complex tmp = elem (j, idx_arg(j)); |
|
511 if (tmp != 0.) |
|
512 { |
|
513 result.xdata (ii) = tmp; |
|
514 result.xridx (ii++) = j; |
|
515 } |
|
516 } |
|
517 } |
|
518 } |
|
519 |
|
520 return result; |
|
521 } |
|
522 |
|
523 // destructive insert/delete/reorder operations |
|
524 |
|
525 SparseComplexMatrix& |
5275
|
526 SparseComplexMatrix::insert (const SparseMatrix& a, octave_idx_type r, octave_idx_type c) |
5164
|
527 { |
|
528 SparseComplexMatrix tmp (a); |
6060
|
529 return insert (tmp /*a*/, r, c); |
5164
|
530 } |
|
531 |
|
532 SparseComplexMatrix& |
5275
|
533 SparseComplexMatrix::insert (const SparseComplexMatrix& a, octave_idx_type r, octave_idx_type c) |
5164
|
534 { |
|
535 MSparse<Complex>::insert (a, r, c); |
|
536 return *this; |
|
537 } |
|
538 |
6823
|
539 SparseComplexMatrix& |
|
540 SparseComplexMatrix::insert (const SparseMatrix& a, const Array<octave_idx_type>& indx) |
|
541 { |
|
542 SparseComplexMatrix tmp (a); |
|
543 return insert (tmp /*a*/, indx); |
|
544 } |
|
545 |
|
546 SparseComplexMatrix& |
|
547 SparseComplexMatrix::insert (const SparseComplexMatrix& a, const Array<octave_idx_type>& indx) |
|
548 { |
|
549 MSparse<Complex>::insert (a, indx); |
|
550 return *this; |
|
551 } |
|
552 |
5164
|
553 SparseComplexMatrix |
|
554 SparseComplexMatrix::concat (const SparseComplexMatrix& rb, |
5275
|
555 const Array<octave_idx_type>& ra_idx) |
5164
|
556 { |
|
557 // Don't use numel to avoid all possiblity of an overflow |
|
558 if (rb.rows () > 0 && rb.cols () > 0) |
|
559 insert (rb, ra_idx(0), ra_idx(1)); |
|
560 return *this; |
|
561 } |
|
562 |
|
563 SparseComplexMatrix |
5275
|
564 SparseComplexMatrix::concat (const SparseMatrix& rb, const Array<octave_idx_type>& ra_idx) |
5164
|
565 { |
|
566 SparseComplexMatrix tmp (rb); |
|
567 if (rb.rows () > 0 && rb.cols () > 0) |
|
568 insert (tmp, ra_idx(0), ra_idx(1)); |
|
569 return *this; |
|
570 } |
|
571 |
|
572 ComplexMatrix |
|
573 SparseComplexMatrix::matrix_value (void) const |
|
574 { |
5275
|
575 octave_idx_type nr = rows (); |
|
576 octave_idx_type nc = cols (); |
5164
|
577 ComplexMatrix retval (nr, nc, Complex (0.0, 0.0)); |
|
578 |
5275
|
579 for (octave_idx_type j = 0; j < nc; j++) |
|
580 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
581 retval.elem (ridx(i), j) = data (i); |
|
582 |
|
583 return retval; |
|
584 } |
|
585 |
|
586 SparseComplexMatrix |
|
587 SparseComplexMatrix::hermitian (void) const |
|
588 { |
5275
|
589 octave_idx_type nr = rows (); |
|
590 octave_idx_type nc = cols (); |
5681
|
591 octave_idx_type nz = nnz (); |
5164
|
592 SparseComplexMatrix retval (nc, nr, nz); |
|
593 |
5648
|
594 OCTAVE_LOCAL_BUFFER (octave_idx_type, w, nr + 1); |
|
595 for (octave_idx_type i = 0; i < nr; i++) |
|
596 w[i] = 0; |
|
597 for (octave_idx_type i = 0; i < nz; i++) |
|
598 w[ridx(i)]++; |
|
599 nz = 0; |
|
600 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
601 { |
5648
|
602 retval.xcidx(i) = nz; |
|
603 nz += w[i]; |
|
604 w[i] = retval.xcidx(i); |
5164
|
605 } |
5648
|
606 retval.xcidx(nr) = nz; |
|
607 w[nr] = nz; |
|
608 |
|
609 for (octave_idx_type j = 0; j < nc; j++) |
|
610 for (octave_idx_type k = cidx(j); k < cidx(j+1); k++) |
|
611 { |
|
612 octave_idx_type q = w [ridx(k)]++; |
|
613 retval.xridx (q) = j; |
|
614 retval.xdata (q) = conj (data (k)); |
|
615 } |
5164
|
616 |
|
617 return retval; |
|
618 } |
|
619 |
|
620 SparseComplexMatrix |
|
621 conj (const SparseComplexMatrix& a) |
|
622 { |
5275
|
623 octave_idx_type nr = a.rows (); |
|
624 octave_idx_type nc = a.cols (); |
5681
|
625 octave_idx_type nz = a.nnz (); |
5164
|
626 SparseComplexMatrix retval (nc, nr, nz); |
|
627 |
5275
|
628 for (octave_idx_type i = 0; i < nc + 1; i++) |
5164
|
629 retval.cidx (i) = a.cidx (i); |
|
630 |
5275
|
631 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
632 { |
|
633 retval.data (i) = conj (a.data (i)); |
|
634 retval.ridx (i) = a.ridx (i); |
|
635 } |
|
636 |
|
637 return retval; |
|
638 } |
|
639 |
|
640 SparseComplexMatrix |
|
641 SparseComplexMatrix::inverse (void) const |
|
642 { |
5275
|
643 octave_idx_type info; |
5164
|
644 double rcond; |
5785
|
645 MatrixType mattype (*this); |
5506
|
646 return inverse (mattype, info, rcond, 0, 0); |
|
647 } |
|
648 |
|
649 SparseComplexMatrix |
5785
|
650 SparseComplexMatrix::inverse (MatrixType& mattype) const |
5506
|
651 { |
|
652 octave_idx_type info; |
|
653 double rcond; |
|
654 return inverse (mattype, info, rcond, 0, 0); |
5164
|
655 } |
|
656 |
|
657 SparseComplexMatrix |
5785
|
658 SparseComplexMatrix::inverse (MatrixType& mattype, octave_idx_type& info) const |
5164
|
659 { |
|
660 double rcond; |
5506
|
661 return inverse (mattype, info, rcond, 0, 0); |
|
662 } |
|
663 |
|
664 SparseComplexMatrix |
5785
|
665 SparseComplexMatrix::dinverse (MatrixType &mattyp, octave_idx_type& info, |
5610
|
666 double& rcond, const bool, |
5506
|
667 const bool calccond) const |
|
668 { |
|
669 SparseComplexMatrix retval; |
|
670 |
|
671 octave_idx_type nr = rows (); |
|
672 octave_idx_type nc = cols (); |
|
673 info = 0; |
|
674 |
|
675 if (nr == 0 || nc == 0 || nr != nc) |
|
676 (*current_liboctave_error_handler) ("inverse requires square matrix"); |
|
677 else |
|
678 { |
|
679 // Print spparms("spumoni") info if requested |
|
680 int typ = mattyp.type (); |
|
681 mattyp.info (); |
|
682 |
5785
|
683 if (typ == MatrixType::Diagonal || |
|
684 typ == MatrixType::Permuted_Diagonal) |
5506
|
685 { |
5785
|
686 if (typ == MatrixType::Permuted_Diagonal) |
5506
|
687 retval = transpose(); |
|
688 else |
|
689 retval = *this; |
|
690 |
|
691 // Force make_unique to be called |
|
692 Complex *v = retval.data(); |
|
693 |
|
694 if (calccond) |
|
695 { |
|
696 double dmax = 0., dmin = octave_Inf; |
|
697 for (octave_idx_type i = 0; i < nr; i++) |
|
698 { |
|
699 double tmp = std::abs(v[i]); |
|
700 if (tmp > dmax) |
|
701 dmax = tmp; |
|
702 if (tmp < dmin) |
|
703 dmin = tmp; |
|
704 } |
|
705 rcond = dmin / dmax; |
|
706 } |
|
707 |
|
708 for (octave_idx_type i = 0; i < nr; i++) |
|
709 v[i] = 1.0 / v[i]; |
|
710 } |
|
711 else |
|
712 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
713 } |
|
714 |
|
715 return retval; |
|
716 } |
|
717 |
|
718 SparseComplexMatrix |
5785
|
719 SparseComplexMatrix::tinverse (MatrixType &mattyp, octave_idx_type& info, |
5610
|
720 double& rcond, const bool, |
5506
|
721 const bool calccond) const |
|
722 { |
|
723 SparseComplexMatrix retval; |
|
724 |
|
725 octave_idx_type nr = rows (); |
|
726 octave_idx_type nc = cols (); |
|
727 info = 0; |
|
728 |
|
729 if (nr == 0 || nc == 0 || nr != nc) |
|
730 (*current_liboctave_error_handler) ("inverse requires square matrix"); |
|
731 else |
|
732 { |
|
733 // Print spparms("spumoni") info if requested |
|
734 int typ = mattyp.type (); |
|
735 mattyp.info (); |
|
736 |
5785
|
737 if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper || |
|
738 typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) |
5506
|
739 { |
|
740 double anorm = 0.; |
|
741 double ainvnorm = 0.; |
|
742 |
|
743 if (calccond) |
|
744 { |
|
745 // Calculate the 1-norm of matrix for rcond calculation |
|
746 for (octave_idx_type j = 0; j < nr; j++) |
|
747 { |
|
748 double atmp = 0.; |
|
749 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
750 atmp += std::abs(data(i)); |
|
751 if (atmp > anorm) |
|
752 anorm = atmp; |
|
753 } |
|
754 } |
|
755 |
5785
|
756 if (typ == MatrixType::Upper || typ == MatrixType::Lower) |
5506
|
757 { |
5681
|
758 octave_idx_type nz = nnz (); |
5506
|
759 octave_idx_type cx = 0; |
|
760 octave_idx_type nz2 = nz; |
|
761 retval = SparseComplexMatrix (nr, nc, nz2); |
|
762 |
|
763 for (octave_idx_type i = 0; i < nr; i++) |
|
764 { |
|
765 OCTAVE_QUIT; |
|
766 // place the 1 in the identity position |
|
767 octave_idx_type cx_colstart = cx; |
|
768 |
|
769 if (cx == nz2) |
|
770 { |
|
771 nz2 *= 2; |
|
772 retval.change_capacity (nz2); |
|
773 } |
|
774 |
|
775 retval.xcidx(i) = cx; |
|
776 retval.xridx(cx) = i; |
|
777 retval.xdata(cx) = 1.0; |
|
778 cx++; |
|
779 |
|
780 // iterate accross columns of input matrix |
|
781 for (octave_idx_type j = i+1; j < nr; j++) |
|
782 { |
|
783 Complex v = 0.; |
|
784 // iterate to calculate sum |
|
785 octave_idx_type colXp = retval.xcidx(i); |
|
786 octave_idx_type colUp = cidx(j); |
|
787 octave_idx_type rpX, rpU; |
5876
|
788 |
|
789 if (cidx(j) == cidx(j+1)) |
|
790 { |
|
791 (*current_liboctave_error_handler) |
|
792 ("division by zero"); |
|
793 goto inverse_singular; |
|
794 } |
|
795 |
5506
|
796 do |
|
797 { |
|
798 OCTAVE_QUIT; |
|
799 rpX = retval.xridx(colXp); |
|
800 rpU = ridx(colUp); |
|
801 |
|
802 if (rpX < rpU) |
|
803 colXp++; |
|
804 else if (rpX > rpU) |
|
805 colUp++; |
|
806 else |
|
807 { |
|
808 v -= retval.xdata(colXp) * data(colUp); |
|
809 colXp++; |
|
810 colUp++; |
|
811 } |
|
812 } while ((rpX<j) && (rpU<j) && |
|
813 (colXp<cx) && (colUp<nz)); |
|
814 |
5876
|
815 |
5506
|
816 // get A(m,m) |
5876
|
817 if (typ == MatrixType::Upper) |
|
818 colUp = cidx(j+1) - 1; |
|
819 else |
5877
|
820 colUp = cidx(j); |
5506
|
821 Complex pivot = data(colUp); |
5877
|
822 if (pivot == 0. || ridx(colUp) != j) |
5876
|
823 { |
|
824 (*current_liboctave_error_handler) |
|
825 ("division by zero"); |
|
826 goto inverse_singular; |
|
827 } |
5506
|
828 |
|
829 if (v != 0.) |
|
830 { |
|
831 if (cx == nz2) |
|
832 { |
|
833 nz2 *= 2; |
|
834 retval.change_capacity (nz2); |
|
835 } |
|
836 |
|
837 retval.xridx(cx) = j; |
|
838 retval.xdata(cx) = v / pivot; |
|
839 cx++; |
|
840 } |
|
841 } |
|
842 |
|
843 // get A(m,m) |
5876
|
844 octave_idx_type colUp; |
|
845 if (typ == MatrixType::Upper) |
|
846 colUp = cidx(i+1) - 1; |
|
847 else |
5877
|
848 colUp = cidx(i); |
5506
|
849 Complex pivot = data(colUp); |
5877
|
850 if (pivot == 0. || ridx(colUp) != i) |
5876
|
851 { |
|
852 (*current_liboctave_error_handler) ("division by zero"); |
|
853 goto inverse_singular; |
|
854 } |
5506
|
855 |
|
856 if (pivot != 1.0) |
|
857 for (octave_idx_type j = cx_colstart; j < cx; j++) |
|
858 retval.xdata(j) /= pivot; |
|
859 } |
|
860 retval.xcidx(nr) = cx; |
|
861 retval.maybe_compress (); |
|
862 } |
|
863 else |
|
864 { |
5681
|
865 octave_idx_type nz = nnz (); |
5506
|
866 octave_idx_type cx = 0; |
|
867 octave_idx_type nz2 = nz; |
|
868 retval = SparseComplexMatrix (nr, nc, nz2); |
|
869 |
|
870 OCTAVE_LOCAL_BUFFER (Complex, work, nr); |
|
871 OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nr); |
|
872 |
|
873 octave_idx_type *perm = mattyp.triangular_perm(); |
5785
|
874 if (typ == MatrixType::Permuted_Upper) |
5506
|
875 { |
|
876 for (octave_idx_type i = 0; i < nr; i++) |
|
877 rperm[perm[i]] = i; |
|
878 } |
|
879 else |
|
880 { |
|
881 for (octave_idx_type i = 0; i < nr; i++) |
|
882 rperm[i] = perm[i]; |
|
883 for (octave_idx_type i = 0; i < nr; i++) |
|
884 perm[rperm[i]] = i; |
|
885 } |
|
886 |
|
887 for (octave_idx_type i = 0; i < nr; i++) |
|
888 { |
|
889 OCTAVE_QUIT; |
|
890 octave_idx_type iidx = rperm[i]; |
|
891 |
|
892 for (octave_idx_type j = 0; j < nr; j++) |
|
893 work[j] = 0.; |
|
894 |
|
895 // place the 1 in the identity position |
|
896 work[iidx] = 1.0; |
|
897 |
|
898 // iterate accross columns of input matrix |
|
899 for (octave_idx_type j = iidx+1; j < nr; j++) |
|
900 { |
|
901 Complex v = 0.; |
|
902 octave_idx_type jidx = perm[j]; |
|
903 // iterate to calculate sum |
|
904 for (octave_idx_type k = cidx(jidx); |
|
905 k < cidx(jidx+1); k++) |
|
906 { |
|
907 OCTAVE_QUIT; |
|
908 v -= work[ridx(k)] * data(k); |
|
909 } |
|
910 |
|
911 // get A(m,m) |
5876
|
912 Complex pivot; |
|
913 if (typ == MatrixType::Permuted_Upper) |
|
914 pivot = data(cidx(jidx+1) - 1); |
|
915 else |
5877
|
916 pivot = data(cidx(jidx)); |
5506
|
917 if (pivot == 0.) |
5876
|
918 { |
|
919 (*current_liboctave_error_handler) |
|
920 ("division by zero"); |
|
921 goto inverse_singular; |
|
922 } |
5506
|
923 |
|
924 work[j] = v / pivot; |
|
925 } |
|
926 |
|
927 // get A(m,m) |
5876
|
928 octave_idx_type colUp; |
|
929 if (typ == MatrixType::Permuted_Upper) |
|
930 colUp = cidx(perm[iidx]+1) - 1; |
|
931 else |
5877
|
932 colUp = cidx(perm[iidx]); |
5876
|
933 |
|
934 Complex pivot = data(colUp); |
|
935 if (pivot == 0.) |
|
936 { |
|
937 (*current_liboctave_error_handler) |
|
938 ("division by zero"); |
|
939 goto inverse_singular; |
|
940 } |
5506
|
941 |
|
942 octave_idx_type new_cx = cx; |
|
943 for (octave_idx_type j = iidx; j < nr; j++) |
|
944 if (work[j] != 0.0) |
|
945 { |
|
946 new_cx++; |
|
947 if (pivot != 1.0) |
|
948 work[j] /= pivot; |
|
949 } |
|
950 |
|
951 if (cx < new_cx) |
|
952 { |
|
953 nz2 = (2*nz2 < new_cx ? new_cx : 2*nz2); |
|
954 retval.change_capacity (nz2); |
|
955 } |
|
956 |
|
957 retval.xcidx(i) = cx; |
|
958 for (octave_idx_type j = iidx; j < nr; j++) |
|
959 if (work[j] != 0.) |
|
960 { |
|
961 retval.xridx(cx) = j; |
|
962 retval.xdata(cx++) = work[j]; |
|
963 } |
|
964 } |
|
965 |
|
966 retval.xcidx(nr) = cx; |
|
967 retval.maybe_compress (); |
|
968 } |
|
969 |
|
970 if (calccond) |
|
971 { |
|
972 // Calculate the 1-norm of inverse matrix for rcond calculation |
|
973 for (octave_idx_type j = 0; j < nr; j++) |
|
974 { |
|
975 double atmp = 0.; |
|
976 for (octave_idx_type i = retval.cidx(j); |
|
977 i < retval.cidx(j+1); i++) |
|
978 atmp += std::abs(retval.data(i)); |
|
979 if (atmp > ainvnorm) |
|
980 ainvnorm = atmp; |
|
981 } |
|
982 |
|
983 rcond = 1. / ainvnorm / anorm; |
|
984 } |
|
985 } |
|
986 else |
|
987 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
988 } |
|
989 |
|
990 return retval; |
5876
|
991 |
|
992 inverse_singular: |
|
993 return SparseComplexMatrix(); |
5164
|
994 } |
|
995 |
|
996 SparseComplexMatrix |
5785
|
997 SparseComplexMatrix::inverse (MatrixType& mattype, octave_idx_type& info, |
5610
|
998 double& rcond, int, int calc_cond) const |
5506
|
999 { |
|
1000 int typ = mattype.type (false); |
|
1001 SparseComplexMatrix ret; |
|
1002 |
5785
|
1003 if (typ == MatrixType::Unknown) |
5506
|
1004 typ = mattype.type (*this); |
|
1005 |
5785
|
1006 if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) |
5506
|
1007 ret = dinverse (mattype, info, rcond, true, calc_cond); |
5785
|
1008 else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) |
5506
|
1009 ret = tinverse (mattype, info, rcond, true, calc_cond).transpose(); |
5785
|
1010 else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) |
6185
|
1011 { |
|
1012 MatrixType newtype = mattype.transpose(); |
|
1013 ret = transpose().tinverse (newtype, info, rcond, true, calc_cond); |
|
1014 } |
6840
|
1015 else |
5506
|
1016 { |
|
1017 if (mattype.is_hermitian()) |
|
1018 { |
5785
|
1019 MatrixType tmp_typ (MatrixType::Upper); |
5506
|
1020 SparseComplexCHOL fact (*this, info, false); |
|
1021 rcond = fact.rcond(); |
|
1022 if (info == 0) |
|
1023 { |
|
1024 double rcond2; |
|
1025 SparseMatrix Q = fact.Q(); |
|
1026 SparseComplexMatrix InvL = fact.L().transpose(). |
|
1027 tinverse(tmp_typ, info, rcond2, true, false); |
|
1028 ret = Q * InvL.hermitian() * InvL * Q.transpose(); |
|
1029 } |
|
1030 else |
|
1031 { |
|
1032 // Matrix is either singular or not positive definite |
|
1033 mattype.mark_as_unsymmetric (); |
5785
|
1034 typ = MatrixType::Full; |
5506
|
1035 } |
|
1036 } |
|
1037 |
|
1038 if (!mattype.is_hermitian()) |
|
1039 { |
|
1040 octave_idx_type n = rows(); |
|
1041 ColumnVector Qinit(n); |
|
1042 for (octave_idx_type i = 0; i < n; i++) |
|
1043 Qinit(i) = i; |
|
1044 |
5785
|
1045 MatrixType tmp_typ (MatrixType::Upper); |
5506
|
1046 SparseComplexLU fact (*this, Qinit, -1.0, false); |
|
1047 rcond = fact.rcond(); |
|
1048 double rcond2; |
|
1049 SparseComplexMatrix InvL = fact.L().transpose(). |
|
1050 tinverse(tmp_typ, info, rcond2, true, false); |
|
1051 SparseComplexMatrix InvU = fact.U(). |
|
1052 tinverse(tmp_typ, info, rcond2, true, false).transpose(); |
|
1053 ret = fact.Pc().transpose() * InvU * InvL * fact.Pr(); |
|
1054 } |
|
1055 } |
|
1056 |
|
1057 return ret; |
5164
|
1058 } |
|
1059 |
|
1060 ComplexDET |
|
1061 SparseComplexMatrix::determinant (void) const |
|
1062 { |
5275
|
1063 octave_idx_type info; |
5164
|
1064 double rcond; |
|
1065 return determinant (info, rcond, 0); |
|
1066 } |
|
1067 |
|
1068 ComplexDET |
5275
|
1069 SparseComplexMatrix::determinant (octave_idx_type& info) const |
5164
|
1070 { |
|
1071 double rcond; |
|
1072 return determinant (info, rcond, 0); |
|
1073 } |
|
1074 |
|
1075 ComplexDET |
5610
|
1076 SparseComplexMatrix::determinant (octave_idx_type& err, double& rcond, int) const |
5164
|
1077 { |
|
1078 ComplexDET retval; |
5203
|
1079 #ifdef HAVE_UMFPACK |
5164
|
1080 |
5275
|
1081 octave_idx_type nr = rows (); |
|
1082 octave_idx_type nc = cols (); |
5164
|
1083 |
|
1084 if (nr == 0 || nc == 0 || nr != nc) |
|
1085 { |
|
1086 Complex d[2]; |
|
1087 d[0] = 1.0; |
|
1088 d[1] = 0.0; |
|
1089 retval = ComplexDET (d); |
|
1090 } |
|
1091 else |
|
1092 { |
|
1093 err = 0; |
|
1094 |
|
1095 // Setup the control parameters |
|
1096 Matrix Control (UMFPACK_CONTROL, 1); |
|
1097 double *control = Control.fortran_vec (); |
5322
|
1098 UMFPACK_ZNAME (defaults) (control); |
5164
|
1099 |
5893
|
1100 double tmp = octave_sparse_params::get_key ("spumoni"); |
5164
|
1101 if (!xisnan (tmp)) |
|
1102 Control (UMFPACK_PRL) = tmp; |
|
1103 |
5893
|
1104 tmp = octave_sparse_params::get_key ("piv_tol"); |
5164
|
1105 if (!xisnan (tmp)) |
|
1106 { |
|
1107 Control (UMFPACK_SYM_PIVOT_TOLERANCE) = tmp; |
|
1108 Control (UMFPACK_PIVOT_TOLERANCE) = tmp; |
|
1109 } |
|
1110 |
|
1111 // Set whether we are allowed to modify Q or not |
5893
|
1112 tmp = octave_sparse_params::get_key ("autoamd"); |
5164
|
1113 if (!xisnan (tmp)) |
|
1114 Control (UMFPACK_FIXQ) = tmp; |
|
1115 |
|
1116 // Turn-off UMFPACK scaling for LU |
|
1117 Control (UMFPACK_SCALE) = UMFPACK_SCALE_NONE; |
|
1118 |
5322
|
1119 UMFPACK_ZNAME (report_control) (control); |
5164
|
1120 |
5275
|
1121 const octave_idx_type *Ap = cidx (); |
|
1122 const octave_idx_type *Ai = ridx (); |
5164
|
1123 const Complex *Ax = data (); |
|
1124 |
5322
|
1125 UMFPACK_ZNAME (report_matrix) (nr, nc, Ap, Ai, |
5760
|
1126 reinterpret_cast<const double *> (Ax), |
|
1127 NULL, 1, control); |
5164
|
1128 |
|
1129 void *Symbolic; |
|
1130 Matrix Info (1, UMFPACK_INFO); |
|
1131 double *info = Info.fortran_vec (); |
5322
|
1132 int status = UMFPACK_ZNAME (qsymbolic) |
5760
|
1133 (nr, nc, Ap, Ai, reinterpret_cast<const double *> (Ax), NULL, |
5164
|
1134 NULL, &Symbolic, control, info); |
|
1135 |
|
1136 if (status < 0) |
|
1137 { |
|
1138 (*current_liboctave_error_handler) |
|
1139 ("SparseComplexMatrix::determinant symbolic factorization failed"); |
|
1140 |
5322
|
1141 UMFPACK_ZNAME (report_status) (control, status); |
|
1142 UMFPACK_ZNAME (report_info) (control, info); |
|
1143 |
|
1144 UMFPACK_ZNAME (free_symbolic) (&Symbolic) ; |
5164
|
1145 } |
|
1146 else |
|
1147 { |
5322
|
1148 UMFPACK_ZNAME (report_symbolic) (Symbolic, control); |
5164
|
1149 |
|
1150 void *Numeric; |
5760
|
1151 status |
|
1152 = UMFPACK_ZNAME (numeric) (Ap, Ai, |
|
1153 reinterpret_cast<const double *> (Ax), |
|
1154 NULL, Symbolic, &Numeric, control, info) ; |
5322
|
1155 UMFPACK_ZNAME (free_symbolic) (&Symbolic) ; |
5164
|
1156 |
|
1157 rcond = Info (UMFPACK_RCOND); |
|
1158 |
|
1159 if (status < 0) |
|
1160 { |
|
1161 (*current_liboctave_error_handler) |
|
1162 ("SparseComplexMatrix::determinant numeric factorization failed"); |
|
1163 |
5322
|
1164 UMFPACK_ZNAME (report_status) (control, status); |
|
1165 UMFPACK_ZNAME (report_info) (control, info); |
|
1166 |
|
1167 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5164
|
1168 } |
|
1169 else |
|
1170 { |
5322
|
1171 UMFPACK_ZNAME (report_numeric) (Numeric, control); |
5164
|
1172 |
|
1173 Complex d[2]; |
|
1174 double d_exponent; |
|
1175 |
5322
|
1176 status = UMFPACK_ZNAME (get_determinant) |
5760
|
1177 (reinterpret_cast<double *> (&d[0]), NULL, &d_exponent, |
5164
|
1178 Numeric, info); |
|
1179 d[1] = d_exponent; |
|
1180 |
|
1181 if (status < 0) |
|
1182 { |
|
1183 (*current_liboctave_error_handler) |
|
1184 ("SparseComplexMatrix::determinant error calculating determinant"); |
|
1185 |
5322
|
1186 UMFPACK_ZNAME (report_status) (control, status); |
|
1187 UMFPACK_ZNAME (report_info) (control, info); |
5164
|
1188 } |
|
1189 else |
|
1190 retval = ComplexDET (d); |
5346
|
1191 |
|
1192 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5164
|
1193 } |
|
1194 } |
|
1195 } |
5203
|
1196 #else |
|
1197 (*current_liboctave_error_handler) ("UMFPACK not installed"); |
|
1198 #endif |
5164
|
1199 |
|
1200 return retval; |
|
1201 } |
|
1202 |
|
1203 ComplexMatrix |
5785
|
1204 SparseComplexMatrix::dsolve (MatrixType &mattype, const Matrix& b, |
5681
|
1205 octave_idx_type& err, double& rcond, |
|
1206 solve_singularity_handler, bool calc_cond) const |
5164
|
1207 { |
|
1208 ComplexMatrix retval; |
|
1209 |
5275
|
1210 octave_idx_type nr = rows (); |
|
1211 octave_idx_type nc = cols (); |
5630
|
1212 octave_idx_type nm = (nc < nr ? nc : nr); |
5164
|
1213 err = 0; |
|
1214 |
5630
|
1215 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
1216 (*current_liboctave_error_handler) |
|
1217 ("matrix dimension mismatch solution of linear equations"); |
|
1218 else |
|
1219 { |
|
1220 // Print spparms("spumoni") info if requested |
|
1221 int typ = mattype.type (); |
|
1222 mattype.info (); |
|
1223 |
5785
|
1224 if (typ == MatrixType::Diagonal || |
|
1225 typ == MatrixType::Permuted_Diagonal) |
5164
|
1226 { |
5630
|
1227 retval.resize (nc, b.cols(), Complex(0.,0.)); |
5785
|
1228 if (typ == MatrixType::Diagonal) |
5275
|
1229 for (octave_idx_type j = 0; j < b.cols(); j++) |
5630
|
1230 for (octave_idx_type i = 0; i < nm; i++) |
|
1231 retval(i,j) = b(i,j) / data (i); |
5164
|
1232 else |
5275
|
1233 for (octave_idx_type j = 0; j < b.cols(); j++) |
5630
|
1234 for (octave_idx_type k = 0; k < nc; k++) |
|
1235 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
|
1236 retval(k,j) = b(ridx(i),j) / data (i); |
5164
|
1237 |
5681
|
1238 if (calc_cond) |
|
1239 { |
|
1240 double dmax = 0., dmin = octave_Inf; |
|
1241 for (octave_idx_type i = 0; i < nm; i++) |
|
1242 { |
|
1243 double tmp = std::abs(data(i)); |
|
1244 if (tmp > dmax) |
|
1245 dmax = tmp; |
|
1246 if (tmp < dmin) |
|
1247 dmin = tmp; |
|
1248 } |
|
1249 rcond = dmin / dmax; |
|
1250 } |
|
1251 else |
|
1252 rcond = 1.0; |
5164
|
1253 } |
|
1254 else |
|
1255 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
1256 } |
|
1257 |
|
1258 return retval; |
|
1259 } |
|
1260 |
|
1261 SparseComplexMatrix |
5785
|
1262 SparseComplexMatrix::dsolve (MatrixType &mattype, const SparseMatrix& b, |
5630
|
1263 octave_idx_type& err, double& rcond, |
5681
|
1264 solve_singularity_handler, |
|
1265 bool calc_cond) const |
5164
|
1266 { |
|
1267 SparseComplexMatrix retval; |
|
1268 |
5275
|
1269 octave_idx_type nr = rows (); |
|
1270 octave_idx_type nc = cols (); |
5630
|
1271 octave_idx_type nm = (nc < nr ? nc : nr); |
5164
|
1272 err = 0; |
|
1273 |
5630
|
1274 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
1275 (*current_liboctave_error_handler) |
|
1276 ("matrix dimension mismatch solution of linear equations"); |
|
1277 else |
|
1278 { |
|
1279 // Print spparms("spumoni") info if requested |
|
1280 int typ = mattype.type (); |
|
1281 mattype.info (); |
|
1282 |
5785
|
1283 if (typ == MatrixType::Diagonal || |
|
1284 typ == MatrixType::Permuted_Diagonal) |
5164
|
1285 { |
5275
|
1286 octave_idx_type b_nc = b.cols (); |
5681
|
1287 octave_idx_type b_nz = b.nnz (); |
5630
|
1288 retval = SparseComplexMatrix (nc, b_nc, b_nz); |
5164
|
1289 |
|
1290 retval.xcidx(0) = 0; |
5275
|
1291 octave_idx_type ii = 0; |
5785
|
1292 if (typ == MatrixType::Diagonal) |
5275
|
1293 for (octave_idx_type j = 0; j < b.cols(); j++) |
5164
|
1294 { |
5275
|
1295 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
1296 { |
5681
|
1297 if (b.ridx(i) >= nm) |
|
1298 break; |
5164
|
1299 retval.xridx (ii) = b.ridx(i); |
|
1300 retval.xdata (ii++) = b.data(i) / data (b.ridx (i)); |
|
1301 } |
|
1302 retval.xcidx(j+1) = ii; |
|
1303 } |
|
1304 else |
5275
|
1305 for (octave_idx_type j = 0; j < b.cols(); j++) |
5164
|
1306 { |
5630
|
1307 for (octave_idx_type l = 0; l < nc; l++) |
|
1308 for (octave_idx_type i = cidx(l); i < cidx(l+1); i++) |
|
1309 { |
|
1310 bool found = false; |
|
1311 octave_idx_type k; |
|
1312 for (k = b.cidx(j); k < b.cidx(j+1); k++) |
|
1313 if (ridx(i) == b.ridx(k)) |
|
1314 { |
|
1315 found = true; |
|
1316 break; |
|
1317 } |
|
1318 if (found) |
5164
|
1319 { |
5630
|
1320 retval.xridx (ii) = l; |
|
1321 retval.xdata (ii++) = b.data(k) / data (i); |
5164
|
1322 } |
5630
|
1323 } |
5164
|
1324 retval.xcidx(j+1) = ii; |
|
1325 } |
|
1326 |
5681
|
1327 if (calc_cond) |
|
1328 { |
|
1329 double dmax = 0., dmin = octave_Inf; |
|
1330 for (octave_idx_type i = 0; i < nm; i++) |
|
1331 { |
|
1332 double tmp = std::abs(data(i)); |
|
1333 if (tmp > dmax) |
|
1334 dmax = tmp; |
|
1335 if (tmp < dmin) |
|
1336 dmin = tmp; |
|
1337 } |
|
1338 rcond = dmin / dmax; |
|
1339 } |
|
1340 else |
|
1341 rcond = 1.0; |
5164
|
1342 } |
|
1343 else |
|
1344 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
1345 } |
|
1346 |
|
1347 return retval; |
|
1348 } |
|
1349 |
|
1350 ComplexMatrix |
5785
|
1351 SparseComplexMatrix::dsolve (MatrixType &mattype, const ComplexMatrix& b, |
5630
|
1352 octave_idx_type& err, double& rcond, |
5681
|
1353 solve_singularity_handler, |
|
1354 bool calc_cond) const |
5164
|
1355 { |
|
1356 ComplexMatrix retval; |
|
1357 |
5275
|
1358 octave_idx_type nr = rows (); |
|
1359 octave_idx_type nc = cols (); |
5630
|
1360 octave_idx_type nm = (nc < nr ? nc : nr); |
5164
|
1361 err = 0; |
|
1362 |
5630
|
1363 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
1364 (*current_liboctave_error_handler) |
|
1365 ("matrix dimension mismatch solution of linear equations"); |
|
1366 else |
|
1367 { |
|
1368 // Print spparms("spumoni") info if requested |
|
1369 int typ = mattype.type (); |
|
1370 mattype.info (); |
|
1371 |
5785
|
1372 if (typ == MatrixType::Diagonal || |
|
1373 typ == MatrixType::Permuted_Diagonal) |
5164
|
1374 { |
5630
|
1375 retval.resize (nc, b.cols(), Complex(0.,0.)); |
5785
|
1376 if (typ == MatrixType::Diagonal) |
5275
|
1377 for (octave_idx_type j = 0; j < b.cols(); j++) |
5630
|
1378 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
1379 retval(i,j) = b(i,j) / data (i); |
|
1380 else |
5275
|
1381 for (octave_idx_type j = 0; j < b.cols(); j++) |
5630
|
1382 for (octave_idx_type k = 0; k < nc; k++) |
|
1383 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
|
1384 retval(k,j) = b(ridx(i),j) / data (i); |
5164
|
1385 |
5681
|
1386 if (calc_cond) |
|
1387 { |
|
1388 double dmax = 0., dmin = octave_Inf; |
|
1389 for (octave_idx_type i = 0; i < nr; i++) |
|
1390 { |
|
1391 double tmp = std::abs(data(i)); |
|
1392 if (tmp > dmax) |
|
1393 dmax = tmp; |
|
1394 if (tmp < dmin) |
|
1395 dmin = tmp; |
|
1396 } |
|
1397 rcond = dmin / dmax; |
|
1398 } |
|
1399 else |
|
1400 rcond = 1.0; |
5164
|
1401 } |
|
1402 else |
|
1403 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
1404 } |
|
1405 |
|
1406 return retval; |
|
1407 } |
|
1408 |
|
1409 SparseComplexMatrix |
5785
|
1410 SparseComplexMatrix::dsolve (MatrixType &mattype, const SparseComplexMatrix& b, |
5630
|
1411 octave_idx_type& err, double& rcond, |
5681
|
1412 solve_singularity_handler, |
|
1413 bool calc_cond) const |
5164
|
1414 { |
|
1415 SparseComplexMatrix retval; |
|
1416 |
5275
|
1417 octave_idx_type nr = rows (); |
|
1418 octave_idx_type nc = cols (); |
5630
|
1419 octave_idx_type nm = (nc < nr ? nc : nr); |
5164
|
1420 err = 0; |
|
1421 |
5630
|
1422 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
1423 (*current_liboctave_error_handler) |
|
1424 ("matrix dimension mismatch solution of linear equations"); |
|
1425 else |
|
1426 { |
|
1427 // Print spparms("spumoni") info if requested |
|
1428 int typ = mattype.type (); |
|
1429 mattype.info (); |
|
1430 |
5785
|
1431 if (typ == MatrixType::Diagonal || |
|
1432 typ == MatrixType::Permuted_Diagonal) |
5164
|
1433 { |
5275
|
1434 octave_idx_type b_nc = b.cols (); |
5681
|
1435 octave_idx_type b_nz = b.nnz (); |
5630
|
1436 retval = SparseComplexMatrix (nc, b_nc, b_nz); |
5164
|
1437 |
|
1438 retval.xcidx(0) = 0; |
5275
|
1439 octave_idx_type ii = 0; |
5785
|
1440 if (typ == MatrixType::Diagonal) |
5275
|
1441 for (octave_idx_type j = 0; j < b.cols(); j++) |
5164
|
1442 { |
5275
|
1443 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
1444 { |
5681
|
1445 if (b.ridx(i) >= nm) |
|
1446 break; |
5164
|
1447 retval.xridx (ii) = b.ridx(i); |
|
1448 retval.xdata (ii++) = b.data(i) / data (b.ridx (i)); |
|
1449 } |
|
1450 retval.xcidx(j+1) = ii; |
|
1451 } |
|
1452 else |
5275
|
1453 for (octave_idx_type j = 0; j < b.cols(); j++) |
5164
|
1454 { |
5630
|
1455 for (octave_idx_type l = 0; l < nc; l++) |
|
1456 for (octave_idx_type i = cidx(l); i < cidx(l+1); i++) |
|
1457 { |
|
1458 bool found = false; |
|
1459 octave_idx_type k; |
|
1460 for (k = b.cidx(j); k < b.cidx(j+1); k++) |
|
1461 if (ridx(i) == b.ridx(k)) |
|
1462 { |
|
1463 found = true; |
|
1464 break; |
|
1465 } |
|
1466 if (found) |
5164
|
1467 { |
5630
|
1468 retval.xridx (ii) = l; |
|
1469 retval.xdata (ii++) = b.data(k) / data (i); |
5164
|
1470 } |
5630
|
1471 } |
5164
|
1472 retval.xcidx(j+1) = ii; |
|
1473 } |
|
1474 |
5681
|
1475 if (calc_cond) |
|
1476 { |
|
1477 double dmax = 0., dmin = octave_Inf; |
|
1478 for (octave_idx_type i = 0; i < nm; i++) |
|
1479 { |
|
1480 double tmp = std::abs(data(i)); |
|
1481 if (tmp > dmax) |
|
1482 dmax = tmp; |
|
1483 if (tmp < dmin) |
|
1484 dmin = tmp; |
|
1485 } |
|
1486 rcond = dmin / dmax; |
|
1487 } |
|
1488 else |
|
1489 rcond = 1.0; |
5164
|
1490 } |
|
1491 else |
|
1492 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
1493 } |
|
1494 |
|
1495 return retval; |
|
1496 } |
|
1497 |
|
1498 ComplexMatrix |
5785
|
1499 SparseComplexMatrix::utsolve (MatrixType &mattype, const Matrix& b, |
5630
|
1500 octave_idx_type& err, double& rcond, |
5681
|
1501 solve_singularity_handler sing_handler, |
|
1502 bool calc_cond) const |
5164
|
1503 { |
|
1504 ComplexMatrix retval; |
|
1505 |
5275
|
1506 octave_idx_type nr = rows (); |
|
1507 octave_idx_type nc = cols (); |
5630
|
1508 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
1509 err = 0; |
|
1510 |
5630
|
1511 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
1512 (*current_liboctave_error_handler) |
|
1513 ("matrix dimension mismatch solution of linear equations"); |
|
1514 else |
|
1515 { |
|
1516 // Print spparms("spumoni") info if requested |
|
1517 int typ = mattype.type (); |
|
1518 mattype.info (); |
|
1519 |
5785
|
1520 if (typ == MatrixType::Permuted_Upper || |
|
1521 typ == MatrixType::Upper) |
5164
|
1522 { |
|
1523 double anorm = 0.; |
|
1524 double ainvnorm = 0.; |
5630
|
1525 octave_idx_type b_nc = b.cols (); |
5681
|
1526 rcond = 1.; |
|
1527 |
|
1528 if (calc_cond) |
|
1529 { |
|
1530 // Calculate the 1-norm of matrix for rcond calculation |
|
1531 for (octave_idx_type j = 0; j < nc; j++) |
|
1532 { |
|
1533 double atmp = 0.; |
|
1534 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
1535 atmp += std::abs(data(i)); |
|
1536 if (atmp > anorm) |
|
1537 anorm = atmp; |
|
1538 } |
5164
|
1539 } |
|
1540 |
5785
|
1541 if (typ == MatrixType::Permuted_Upper) |
5164
|
1542 { |
5630
|
1543 retval.resize (nc, b_nc); |
5322
|
1544 octave_idx_type *perm = mattype.triangular_perm (); |
5681
|
1545 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5164
|
1546 |
5630
|
1547 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
1548 { |
5275
|
1549 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
1550 work[i] = b(i,j); |
5630
|
1551 for (octave_idx_type i = nr; i < nc; i++) |
|
1552 work[i] = 0.; |
|
1553 |
|
1554 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
1555 { |
5322
|
1556 octave_idx_type kidx = perm[k]; |
|
1557 |
|
1558 if (work[k] != 0.) |
5164
|
1559 { |
5681
|
1560 if (ridx(cidx(kidx+1)-1) != k || |
|
1561 data(cidx(kidx+1)-1) == 0.) |
5164
|
1562 { |
|
1563 err = -2; |
|
1564 goto triangular_error; |
|
1565 } |
|
1566 |
5322
|
1567 Complex tmp = work[k] / data(cidx(kidx+1)-1); |
|
1568 work[k] = tmp; |
|
1569 for (octave_idx_type i = cidx(kidx); |
|
1570 i < cidx(kidx+1)-1; i++) |
5164
|
1571 { |
5322
|
1572 octave_idx_type iidx = ridx(i); |
|
1573 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
1574 } |
|
1575 } |
|
1576 } |
|
1577 |
5630
|
1578 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
1579 retval (perm[i], j) = work[i]; |
5164
|
1580 } |
|
1581 |
5681
|
1582 if (calc_cond) |
|
1583 { |
|
1584 // Calculation of 1-norm of inv(*this) |
|
1585 for (octave_idx_type i = 0; i < nm; i++) |
|
1586 work[i] = 0.; |
|
1587 |
|
1588 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
1589 { |
5681
|
1590 work[j] = 1.; |
|
1591 |
|
1592 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
1593 { |
5681
|
1594 octave_idx_type iidx = perm[k]; |
|
1595 |
|
1596 if (work[k] != 0.) |
5164
|
1597 { |
5681
|
1598 Complex tmp = work[k] / data(cidx(iidx+1)-1); |
|
1599 work[k] = tmp; |
|
1600 for (octave_idx_type i = cidx(iidx); |
|
1601 i < cidx(iidx+1)-1; i++) |
|
1602 { |
|
1603 octave_idx_type idx2 = ridx(i); |
|
1604 work[idx2] = work[idx2] - tmp * data(i); |
|
1605 } |
5164
|
1606 } |
|
1607 } |
5681
|
1608 double atmp = 0; |
|
1609 for (octave_idx_type i = 0; i < j+1; i++) |
|
1610 { |
|
1611 atmp += std::abs(work[i]); |
|
1612 work[i] = 0.; |
|
1613 } |
|
1614 if (atmp > ainvnorm) |
|
1615 ainvnorm = atmp; |
5164
|
1616 } |
5681
|
1617 rcond = 1. / ainvnorm / anorm; |
5164
|
1618 } |
|
1619 } |
|
1620 else |
|
1621 { |
5630
|
1622 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
|
1623 retval.resize (nc, b_nc); |
|
1624 |
|
1625 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
1626 { |
5630
|
1627 for (octave_idx_type i = 0; i < nr; i++) |
|
1628 work[i] = b(i,j); |
|
1629 for (octave_idx_type i = nr; i < nc; i++) |
|
1630 work[i] = 0.; |
|
1631 |
|
1632 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
1633 { |
5630
|
1634 if (work[k] != 0.) |
5164
|
1635 { |
5681
|
1636 if (ridx(cidx(k+1)-1) != k || |
|
1637 data(cidx(k+1)-1) == 0.) |
5164
|
1638 { |
|
1639 err = -2; |
|
1640 goto triangular_error; |
|
1641 } |
|
1642 |
5630
|
1643 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
1644 work[k] = tmp; |
5275
|
1645 for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++) |
5164
|
1646 { |
5275
|
1647 octave_idx_type iidx = ridx(i); |
5630
|
1648 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
1649 } |
|
1650 } |
|
1651 } |
5630
|
1652 |
|
1653 for (octave_idx_type i = 0; i < nc; i++) |
|
1654 retval.xelem (i, j) = work[i]; |
5164
|
1655 } |
|
1656 |
5681
|
1657 if (calc_cond) |
|
1658 { |
|
1659 // Calculation of 1-norm of inv(*this) |
|
1660 for (octave_idx_type i = 0; i < nm; i++) |
|
1661 work[i] = 0.; |
|
1662 |
|
1663 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
1664 { |
5681
|
1665 work[j] = 1.; |
|
1666 |
|
1667 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
1668 { |
5681
|
1669 if (work[k] != 0.) |
5164
|
1670 { |
5681
|
1671 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
1672 work[k] = tmp; |
|
1673 for (octave_idx_type i = cidx(k); |
|
1674 i < cidx(k+1)-1; i++) |
|
1675 { |
|
1676 octave_idx_type iidx = ridx(i); |
|
1677 work[iidx] = work[iidx] - tmp * data(i); |
|
1678 } |
5164
|
1679 } |
|
1680 } |
5681
|
1681 double atmp = 0; |
|
1682 for (octave_idx_type i = 0; i < j+1; i++) |
|
1683 { |
|
1684 atmp += std::abs(work[i]); |
|
1685 work[i] = 0.; |
|
1686 } |
|
1687 if (atmp > ainvnorm) |
|
1688 ainvnorm = atmp; |
5164
|
1689 } |
5681
|
1690 rcond = 1. / ainvnorm / anorm; |
|
1691 } |
|
1692 } |
5164
|
1693 |
|
1694 triangular_error: |
|
1695 if (err != 0) |
|
1696 { |
|
1697 if (sing_handler) |
5681
|
1698 { |
|
1699 sing_handler (rcond); |
|
1700 mattype.mark_as_rectangular (); |
|
1701 } |
5164
|
1702 else |
|
1703 (*current_liboctave_error_handler) |
|
1704 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
1705 rcond); |
|
1706 } |
|
1707 |
|
1708 volatile double rcond_plus_one = rcond + 1.0; |
|
1709 |
|
1710 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
1711 { |
|
1712 err = -2; |
|
1713 |
|
1714 if (sing_handler) |
5681
|
1715 { |
|
1716 sing_handler (rcond); |
|
1717 mattype.mark_as_rectangular (); |
|
1718 } |
5164
|
1719 else |
|
1720 (*current_liboctave_error_handler) |
|
1721 ("matrix singular to machine precision, rcond = %g", |
|
1722 rcond); |
|
1723 } |
|
1724 } |
|
1725 else |
|
1726 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
1727 } |
|
1728 |
|
1729 return retval; |
|
1730 } |
|
1731 |
|
1732 SparseComplexMatrix |
5785
|
1733 SparseComplexMatrix::utsolve (MatrixType &mattype, const SparseMatrix& b, |
5630
|
1734 octave_idx_type& err, double& rcond, |
5681
|
1735 solve_singularity_handler sing_handler, |
|
1736 bool calc_cond) const |
5164
|
1737 { |
|
1738 SparseComplexMatrix retval; |
|
1739 |
5275
|
1740 octave_idx_type nr = rows (); |
|
1741 octave_idx_type nc = cols (); |
5630
|
1742 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
1743 err = 0; |
|
1744 |
5630
|
1745 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
1746 (*current_liboctave_error_handler) |
|
1747 ("matrix dimension mismatch solution of linear equations"); |
|
1748 else |
|
1749 { |
|
1750 // Print spparms("spumoni") info if requested |
|
1751 int typ = mattype.type (); |
|
1752 mattype.info (); |
|
1753 |
5785
|
1754 if (typ == MatrixType::Permuted_Upper || |
|
1755 typ == MatrixType::Upper) |
5164
|
1756 { |
|
1757 double anorm = 0.; |
|
1758 double ainvnorm = 0.; |
5681
|
1759 rcond = 1.; |
|
1760 |
|
1761 if (calc_cond) |
|
1762 { |
|
1763 // Calculate the 1-norm of matrix for rcond calculation |
|
1764 for (octave_idx_type j = 0; j < nc; j++) |
|
1765 { |
|
1766 double atmp = 0.; |
|
1767 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
1768 atmp += std::abs(data(i)); |
|
1769 if (atmp > anorm) |
|
1770 anorm = atmp; |
|
1771 } |
5164
|
1772 } |
|
1773 |
5275
|
1774 octave_idx_type b_nc = b.cols (); |
5681
|
1775 octave_idx_type b_nz = b.nnz (); |
5630
|
1776 retval = SparseComplexMatrix (nc, b_nc, b_nz); |
5164
|
1777 retval.xcidx(0) = 0; |
5275
|
1778 octave_idx_type ii = 0; |
|
1779 octave_idx_type x_nz = b_nz; |
5164
|
1780 |
5785
|
1781 if (typ == MatrixType::Permuted_Upper) |
5164
|
1782 { |
5322
|
1783 octave_idx_type *perm = mattype.triangular_perm (); |
5630
|
1784 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
|
1785 |
|
1786 OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nc); |
|
1787 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
1788 rperm[perm[i]] = i; |
5164
|
1789 |
5275
|
1790 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
1791 { |
5630
|
1792 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
1793 work[i] = 0.; |
5275
|
1794 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
1795 work[b.ridx(i)] = b.data(i); |
|
1796 |
5630
|
1797 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
1798 { |
5322
|
1799 octave_idx_type kidx = perm[k]; |
|
1800 |
|
1801 if (work[k] != 0.) |
5164
|
1802 { |
5681
|
1803 if (ridx(cidx(kidx+1)-1) != k || |
|
1804 data(cidx(kidx+1)-1) == 0.) |
5164
|
1805 { |
|
1806 err = -2; |
|
1807 goto triangular_error; |
|
1808 } |
|
1809 |
5322
|
1810 Complex tmp = work[k] / data(cidx(kidx+1)-1); |
|
1811 work[k] = tmp; |
|
1812 for (octave_idx_type i = cidx(kidx); |
|
1813 i < cidx(kidx+1)-1; i++) |
5164
|
1814 { |
5322
|
1815 octave_idx_type iidx = ridx(i); |
|
1816 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
1817 } |
|
1818 } |
|
1819 } |
|
1820 |
|
1821 // Count non-zeros in work vector and adjust space in |
|
1822 // retval if needed |
5275
|
1823 octave_idx_type new_nnz = 0; |
5630
|
1824 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
1825 if (work[i] != 0.) |
|
1826 new_nnz++; |
|
1827 |
|
1828 if (ii + new_nnz > x_nz) |
|
1829 { |
|
1830 // Resize the sparse matrix |
5275
|
1831 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
1832 retval.change_capacity (sz); |
|
1833 x_nz = sz; |
|
1834 } |
|
1835 |
5630
|
1836 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
1837 if (work[rperm[i]] != 0.) |
5164
|
1838 { |
|
1839 retval.xridx(ii) = i; |
5322
|
1840 retval.xdata(ii++) = work[rperm[i]]; |
5164
|
1841 } |
|
1842 retval.xcidx(j+1) = ii; |
|
1843 } |
|
1844 |
|
1845 retval.maybe_compress (); |
|
1846 |
5681
|
1847 if (calc_cond) |
|
1848 { |
|
1849 // Calculation of 1-norm of inv(*this) |
|
1850 for (octave_idx_type i = 0; i < nm; i++) |
|
1851 work[i] = 0.; |
|
1852 |
|
1853 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
1854 { |
5681
|
1855 work[j] = 1.; |
|
1856 |
|
1857 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
1858 { |
5681
|
1859 octave_idx_type iidx = perm[k]; |
|
1860 |
|
1861 if (work[k] != 0.) |
5164
|
1862 { |
5681
|
1863 Complex tmp = work[k] / data(cidx(iidx+1)-1); |
|
1864 work[k] = tmp; |
|
1865 for (octave_idx_type i = cidx(iidx); |
|
1866 i < cidx(iidx+1)-1; i++) |
|
1867 { |
|
1868 octave_idx_type idx2 = ridx(i); |
|
1869 work[idx2] = work[idx2] - tmp * data(i); |
|
1870 } |
5164
|
1871 } |
|
1872 } |
5681
|
1873 double atmp = 0; |
|
1874 for (octave_idx_type i = 0; i < j+1; i++) |
|
1875 { |
|
1876 atmp += std::abs(work[i]); |
|
1877 work[i] = 0.; |
|
1878 } |
|
1879 if (atmp > ainvnorm) |
|
1880 ainvnorm = atmp; |
5164
|
1881 } |
5681
|
1882 rcond = 1. / ainvnorm / anorm; |
5164
|
1883 } |
|
1884 } |
|
1885 else |
|
1886 { |
5630
|
1887 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5164
|
1888 |
5275
|
1889 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
1890 { |
5630
|
1891 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
1892 work[i] = 0.; |
5275
|
1893 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
1894 work[b.ridx(i)] = b.data(i); |
|
1895 |
5630
|
1896 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
1897 { |
|
1898 if (work[k] != 0.) |
|
1899 { |
5681
|
1900 if (ridx(cidx(k+1)-1) != k || |
|
1901 data(cidx(k+1)-1) == 0.) |
5164
|
1902 { |
|
1903 err = -2; |
|
1904 goto triangular_error; |
|
1905 } |
|
1906 |
|
1907 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
1908 work[k] = tmp; |
5275
|
1909 for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++) |
5164
|
1910 { |
5275
|
1911 octave_idx_type iidx = ridx(i); |
5164
|
1912 work[iidx] = work[iidx] - tmp * data(i); |
|
1913 } |
|
1914 } |
|
1915 } |
|
1916 |
|
1917 // Count non-zeros in work vector and adjust space in |
|
1918 // retval if needed |
5275
|
1919 octave_idx_type new_nnz = 0; |
5630
|
1920 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
1921 if (work[i] != 0.) |
|
1922 new_nnz++; |
|
1923 |
|
1924 if (ii + new_nnz > x_nz) |
|
1925 { |
|
1926 // Resize the sparse matrix |
5275
|
1927 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
1928 retval.change_capacity (sz); |
|
1929 x_nz = sz; |
|
1930 } |
|
1931 |
5630
|
1932 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
1933 if (work[i] != 0.) |
|
1934 { |
|
1935 retval.xridx(ii) = i; |
|
1936 retval.xdata(ii++) = work[i]; |
|
1937 } |
|
1938 retval.xcidx(j+1) = ii; |
|
1939 } |
|
1940 |
|
1941 retval.maybe_compress (); |
|
1942 |
5681
|
1943 if (calc_cond) |
|
1944 { |
|
1945 // Calculation of 1-norm of inv(*this) |
|
1946 for (octave_idx_type i = 0; i < nm; i++) |
|
1947 work[i] = 0.; |
|
1948 |
|
1949 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
1950 { |
5681
|
1951 work[j] = 1.; |
|
1952 |
|
1953 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
1954 { |
5681
|
1955 if (work[k] != 0.) |
5164
|
1956 { |
5681
|
1957 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
1958 work[k] = tmp; |
|
1959 for (octave_idx_type i = cidx(k); |
|
1960 i < cidx(k+1)-1; i++) |
|
1961 { |
|
1962 octave_idx_type iidx = ridx(i); |
|
1963 work[iidx] = work[iidx] - tmp * data(i); |
|
1964 } |
5164
|
1965 } |
|
1966 } |
5681
|
1967 double atmp = 0; |
|
1968 for (octave_idx_type i = 0; i < j+1; i++) |
|
1969 { |
|
1970 atmp += std::abs(work[i]); |
|
1971 work[i] = 0.; |
|
1972 } |
|
1973 if (atmp > ainvnorm) |
|
1974 ainvnorm = atmp; |
5164
|
1975 } |
5681
|
1976 rcond = 1. / ainvnorm / anorm; |
|
1977 } |
|
1978 } |
5164
|
1979 |
|
1980 triangular_error: |
|
1981 if (err != 0) |
|
1982 { |
|
1983 if (sing_handler) |
5681
|
1984 { |
|
1985 sing_handler (rcond); |
|
1986 mattype.mark_as_rectangular (); |
|
1987 } |
5164
|
1988 else |
|
1989 (*current_liboctave_error_handler) |
|
1990 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
1991 rcond); |
|
1992 } |
|
1993 |
|
1994 volatile double rcond_plus_one = rcond + 1.0; |
|
1995 |
|
1996 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
1997 { |
|
1998 err = -2; |
|
1999 |
|
2000 if (sing_handler) |
5681
|
2001 { |
|
2002 sing_handler (rcond); |
|
2003 mattype.mark_as_rectangular (); |
|
2004 } |
5164
|
2005 else |
|
2006 (*current_liboctave_error_handler) |
|
2007 ("matrix singular to machine precision, rcond = %g", |
|
2008 rcond); |
|
2009 } |
|
2010 } |
|
2011 else |
|
2012 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
2013 } |
|
2014 return retval; |
|
2015 } |
|
2016 |
|
2017 ComplexMatrix |
5785
|
2018 SparseComplexMatrix::utsolve (MatrixType &mattype, const ComplexMatrix& b, |
5630
|
2019 octave_idx_type& err, double& rcond, |
5681
|
2020 solve_singularity_handler sing_handler, |
|
2021 bool calc_cond) const |
5164
|
2022 { |
|
2023 ComplexMatrix retval; |
|
2024 |
5275
|
2025 octave_idx_type nr = rows (); |
|
2026 octave_idx_type nc = cols (); |
5630
|
2027 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
2028 err = 0; |
|
2029 |
5630
|
2030 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
2031 (*current_liboctave_error_handler) |
|
2032 ("matrix dimension mismatch solution of linear equations"); |
|
2033 else |
|
2034 { |
|
2035 // Print spparms("spumoni") info if requested |
|
2036 int typ = mattype.type (); |
|
2037 mattype.info (); |
|
2038 |
5785
|
2039 if (typ == MatrixType::Permuted_Upper || |
|
2040 typ == MatrixType::Upper) |
5164
|
2041 { |
|
2042 double anorm = 0.; |
|
2043 double ainvnorm = 0.; |
5275
|
2044 octave_idx_type b_nc = b.cols (); |
5681
|
2045 rcond = 1.; |
|
2046 |
|
2047 if (calc_cond) |
|
2048 { |
|
2049 // Calculate the 1-norm of matrix for rcond calculation |
|
2050 for (octave_idx_type j = 0; j < nc; j++) |
|
2051 { |
|
2052 double atmp = 0.; |
|
2053 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
2054 atmp += std::abs(data(i)); |
|
2055 if (atmp > anorm) |
|
2056 anorm = atmp; |
|
2057 } |
5164
|
2058 } |
|
2059 |
5785
|
2060 if (typ == MatrixType::Permuted_Upper) |
5164
|
2061 { |
5630
|
2062 retval.resize (nc, b_nc); |
5322
|
2063 octave_idx_type *perm = mattype.triangular_perm (); |
5630
|
2064 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5164
|
2065 |
5275
|
2066 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2067 { |
5275
|
2068 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
2069 work[i] = b(i,j); |
5630
|
2070 for (octave_idx_type i = nr; i < nc; i++) |
|
2071 work[i] = 0.; |
|
2072 |
|
2073 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
2074 { |
5322
|
2075 octave_idx_type kidx = perm[k]; |
|
2076 |
|
2077 if (work[k] != 0.) |
5164
|
2078 { |
5681
|
2079 if (ridx(cidx(kidx+1)-1) != k || |
|
2080 data(cidx(kidx+1)-1) == 0.) |
5164
|
2081 { |
|
2082 err = -2; |
|
2083 goto triangular_error; |
|
2084 } |
|
2085 |
5322
|
2086 Complex tmp = work[k] / data(cidx(kidx+1)-1); |
|
2087 work[k] = tmp; |
|
2088 for (octave_idx_type i = cidx(kidx); |
|
2089 i < cidx(kidx+1)-1; i++) |
5164
|
2090 { |
5322
|
2091 octave_idx_type iidx = ridx(i); |
|
2092 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
2093 } |
|
2094 } |
|
2095 } |
|
2096 |
5630
|
2097 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
2098 retval (perm[i], j) = work[i]; |
5164
|
2099 } |
|
2100 |
5681
|
2101 if (calc_cond) |
|
2102 { |
|
2103 // Calculation of 1-norm of inv(*this) |
|
2104 for (octave_idx_type i = 0; i < nm; i++) |
|
2105 work[i] = 0.; |
|
2106 |
|
2107 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2108 { |
5681
|
2109 work[j] = 1.; |
|
2110 |
|
2111 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
2112 { |
5681
|
2113 octave_idx_type iidx = perm[k]; |
|
2114 |
|
2115 if (work[k] != 0.) |
5164
|
2116 { |
5681
|
2117 Complex tmp = work[k] / data(cidx(iidx+1)-1); |
|
2118 work[k] = tmp; |
|
2119 for (octave_idx_type i = cidx(iidx); |
|
2120 i < cidx(iidx+1)-1; i++) |
|
2121 { |
|
2122 octave_idx_type idx2 = ridx(i); |
|
2123 work[idx2] = work[idx2] - tmp * data(i); |
|
2124 } |
5164
|
2125 } |
|
2126 } |
5681
|
2127 double atmp = 0; |
|
2128 for (octave_idx_type i = 0; i < j+1; i++) |
|
2129 { |
|
2130 atmp += std::abs(work[i]); |
|
2131 work[i] = 0.; |
|
2132 } |
|
2133 if (atmp > ainvnorm) |
|
2134 ainvnorm = atmp; |
5164
|
2135 } |
5681
|
2136 rcond = 1. / ainvnorm / anorm; |
5164
|
2137 } |
|
2138 } |
|
2139 else |
|
2140 { |
5630
|
2141 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
|
2142 retval.resize (nc, b_nc); |
5164
|
2143 |
5275
|
2144 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2145 { |
5630
|
2146 for (octave_idx_type i = 0; i < nr; i++) |
|
2147 work[i] = b(i,j); |
|
2148 for (octave_idx_type i = nr; i < nc; i++) |
|
2149 work[i] = 0.; |
|
2150 |
|
2151 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
2152 { |
5630
|
2153 if (work[k] != 0.) |
5164
|
2154 { |
5681
|
2155 if (ridx(cidx(k+1)-1) != k || |
|
2156 data(cidx(k+1)-1) == 0.) |
5164
|
2157 { |
|
2158 err = -2; |
|
2159 goto triangular_error; |
|
2160 } |
|
2161 |
5630
|
2162 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
2163 work[k] = tmp; |
5275
|
2164 for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++) |
5164
|
2165 { |
5275
|
2166 octave_idx_type iidx = ridx(i); |
5630
|
2167 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
2168 } |
|
2169 } |
|
2170 } |
5630
|
2171 |
|
2172 for (octave_idx_type i = 0; i < nc; i++) |
|
2173 retval.xelem (i, j) = work[i]; |
5164
|
2174 } |
|
2175 |
5681
|
2176 if (calc_cond) |
|
2177 { |
|
2178 // Calculation of 1-norm of inv(*this) |
|
2179 for (octave_idx_type i = 0; i < nm; i++) |
|
2180 work[i] = 0.; |
|
2181 |
|
2182 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2183 { |
5681
|
2184 work[j] = 1.; |
|
2185 |
|
2186 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
2187 { |
5681
|
2188 if (work[k] != 0.) |
5164
|
2189 { |
5681
|
2190 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
2191 work[k] = tmp; |
|
2192 for (octave_idx_type i = cidx(k); |
|
2193 i < cidx(k+1)-1; i++) |
|
2194 { |
|
2195 octave_idx_type iidx = ridx(i); |
|
2196 work[iidx] = work[iidx] - tmp * data(i); |
|
2197 } |
5164
|
2198 } |
|
2199 } |
5681
|
2200 double atmp = 0; |
|
2201 for (octave_idx_type i = 0; i < j+1; i++) |
|
2202 { |
|
2203 atmp += std::abs(work[i]); |
|
2204 work[i] = 0.; |
|
2205 } |
|
2206 if (atmp > ainvnorm) |
|
2207 ainvnorm = atmp; |
5164
|
2208 } |
5681
|
2209 rcond = 1. / ainvnorm / anorm; |
|
2210 } |
|
2211 } |
5164
|
2212 |
|
2213 triangular_error: |
|
2214 if (err != 0) |
|
2215 { |
|
2216 if (sing_handler) |
5681
|
2217 { |
|
2218 sing_handler (rcond); |
|
2219 mattype.mark_as_rectangular (); |
|
2220 } |
5164
|
2221 else |
|
2222 (*current_liboctave_error_handler) |
|
2223 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
2224 rcond); |
|
2225 } |
|
2226 |
|
2227 volatile double rcond_plus_one = rcond + 1.0; |
|
2228 |
|
2229 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
2230 { |
|
2231 err = -2; |
|
2232 |
|
2233 if (sing_handler) |
5681
|
2234 { |
|
2235 sing_handler (rcond); |
|
2236 mattype.mark_as_rectangular (); |
|
2237 } |
5164
|
2238 else |
|
2239 (*current_liboctave_error_handler) |
|
2240 ("matrix singular to machine precision, rcond = %g", |
|
2241 rcond); |
|
2242 } |
|
2243 } |
|
2244 else |
|
2245 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
2246 } |
|
2247 |
|
2248 return retval; |
|
2249 } |
|
2250 |
|
2251 SparseComplexMatrix |
5785
|
2252 SparseComplexMatrix::utsolve (MatrixType &mattype, const SparseComplexMatrix& b, |
5630
|
2253 octave_idx_type& err, double& rcond, |
5681
|
2254 solve_singularity_handler sing_handler, |
|
2255 bool calc_cond) const |
5164
|
2256 { |
|
2257 SparseComplexMatrix retval; |
|
2258 |
5275
|
2259 octave_idx_type nr = rows (); |
|
2260 octave_idx_type nc = cols (); |
5630
|
2261 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
2262 err = 0; |
|
2263 |
5630
|
2264 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
2265 (*current_liboctave_error_handler) |
|
2266 ("matrix dimension mismatch solution of linear equations"); |
|
2267 else |
|
2268 { |
|
2269 // Print spparms("spumoni") info if requested |
|
2270 int typ = mattype.type (); |
|
2271 mattype.info (); |
|
2272 |
5785
|
2273 if (typ == MatrixType::Permuted_Upper || |
|
2274 typ == MatrixType::Upper) |
5164
|
2275 { |
|
2276 double anorm = 0.; |
|
2277 double ainvnorm = 0.; |
5681
|
2278 rcond = 1.; |
|
2279 |
|
2280 if (calc_cond) |
|
2281 { |
|
2282 // Calculate the 1-norm of matrix for rcond calculation |
|
2283 for (octave_idx_type j = 0; j < nc; j++) |
|
2284 { |
|
2285 double atmp = 0.; |
|
2286 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
2287 atmp += std::abs(data(i)); |
|
2288 if (atmp > anorm) |
|
2289 anorm = atmp; |
|
2290 } |
5164
|
2291 } |
|
2292 |
5275
|
2293 octave_idx_type b_nc = b.cols (); |
5681
|
2294 octave_idx_type b_nz = b.nnz (); |
5630
|
2295 retval = SparseComplexMatrix (nc, b_nc, b_nz); |
5164
|
2296 retval.xcidx(0) = 0; |
5275
|
2297 octave_idx_type ii = 0; |
|
2298 octave_idx_type x_nz = b_nz; |
5164
|
2299 |
5785
|
2300 if (typ == MatrixType::Permuted_Upper) |
5164
|
2301 { |
5322
|
2302 octave_idx_type *perm = mattype.triangular_perm (); |
5630
|
2303 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
|
2304 |
|
2305 OCTAVE_LOCAL_BUFFER (octave_idx_type, rperm, nc); |
|
2306 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
2307 rperm[perm[i]] = i; |
5164
|
2308 |
5275
|
2309 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2310 { |
5630
|
2311 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
2312 work[i] = 0.; |
5275
|
2313 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
2314 work[b.ridx(i)] = b.data(i); |
|
2315 |
5630
|
2316 for (octave_idx_type k = nc-1; k >= 0; k--) |
5164
|
2317 { |
5322
|
2318 octave_idx_type kidx = perm[k]; |
|
2319 |
|
2320 if (work[k] != 0.) |
5164
|
2321 { |
5681
|
2322 if (ridx(cidx(kidx+1)-1) != k || |
|
2323 data(cidx(kidx+1)-1) == 0.) |
5164
|
2324 { |
|
2325 err = -2; |
|
2326 goto triangular_error; |
|
2327 } |
|
2328 |
5322
|
2329 Complex tmp = work[k] / data(cidx(kidx+1)-1); |
|
2330 work[k] = tmp; |
|
2331 for (octave_idx_type i = cidx(kidx); |
|
2332 i < cidx(kidx+1)-1; i++) |
5164
|
2333 { |
5322
|
2334 octave_idx_type iidx = ridx(i); |
|
2335 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
2336 } |
|
2337 } |
|
2338 } |
|
2339 |
|
2340 // Count non-zeros in work vector and adjust space in |
|
2341 // retval if needed |
5275
|
2342 octave_idx_type new_nnz = 0; |
5630
|
2343 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
2344 if (work[i] != 0.) |
|
2345 new_nnz++; |
|
2346 |
|
2347 if (ii + new_nnz > x_nz) |
|
2348 { |
|
2349 // Resize the sparse matrix |
5275
|
2350 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
2351 retval.change_capacity (sz); |
|
2352 x_nz = sz; |
|
2353 } |
|
2354 |
5630
|
2355 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
2356 if (work[rperm[i]] != 0.) |
5164
|
2357 { |
|
2358 retval.xridx(ii) = i; |
5322
|
2359 retval.xdata(ii++) = work[rperm[i]]; |
5164
|
2360 } |
|
2361 retval.xcidx(j+1) = ii; |
|
2362 } |
|
2363 |
|
2364 retval.maybe_compress (); |
|
2365 |
5681
|
2366 if (calc_cond) |
|
2367 { |
|
2368 // Calculation of 1-norm of inv(*this) |
|
2369 for (octave_idx_type i = 0; i < nm; i++) |
|
2370 work[i] = 0.; |
|
2371 |
|
2372 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2373 { |
5681
|
2374 work[j] = 1.; |
|
2375 |
|
2376 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
2377 { |
5681
|
2378 octave_idx_type iidx = perm[k]; |
|
2379 |
|
2380 if (work[k] != 0.) |
5164
|
2381 { |
5681
|
2382 Complex tmp = work[k] / data(cidx(iidx+1)-1); |
|
2383 work[k] = tmp; |
|
2384 for (octave_idx_type i = cidx(iidx); |
|
2385 i < cidx(iidx+1)-1; i++) |
|
2386 { |
|
2387 octave_idx_type idx2 = ridx(i); |
|
2388 work[idx2] = work[idx2] - tmp * data(i); |
|
2389 } |
5164
|
2390 } |
|
2391 } |
5681
|
2392 double atmp = 0; |
|
2393 for (octave_idx_type i = 0; i < j+1; i++) |
|
2394 { |
|
2395 atmp += std::abs(work[i]); |
|
2396 work[i] = 0.; |
|
2397 } |
|
2398 if (atmp > ainvnorm) |
|
2399 ainvnorm = atmp; |
5164
|
2400 } |
5681
|
2401 rcond = 1. / ainvnorm / anorm; |
5164
|
2402 } |
|
2403 } |
|
2404 else |
|
2405 { |
5630
|
2406 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5164
|
2407 |
5275
|
2408 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2409 { |
5630
|
2410 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
2411 work[i] = 0.; |
5275
|
2412 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
2413 work[b.ridx(i)] = b.data(i); |
|
2414 |
5275
|
2415 for (octave_idx_type k = nr-1; k >= 0; k--) |
5164
|
2416 { |
|
2417 if (work[k] != 0.) |
|
2418 { |
5681
|
2419 if (ridx(cidx(k+1)-1) != k || |
|
2420 data(cidx(k+1)-1) == 0.) |
5164
|
2421 { |
|
2422 err = -2; |
|
2423 goto triangular_error; |
|
2424 } |
|
2425 |
|
2426 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
2427 work[k] = tmp; |
5275
|
2428 for (octave_idx_type i = cidx(k); i < cidx(k+1)-1; i++) |
5164
|
2429 { |
5275
|
2430 octave_idx_type iidx = ridx(i); |
5164
|
2431 work[iidx] = work[iidx] - tmp * data(i); |
|
2432 } |
|
2433 } |
|
2434 } |
|
2435 |
|
2436 // Count non-zeros in work vector and adjust space in |
|
2437 // retval if needed |
5275
|
2438 octave_idx_type new_nnz = 0; |
5630
|
2439 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
2440 if (work[i] != 0.) |
|
2441 new_nnz++; |
|
2442 |
|
2443 if (ii + new_nnz > x_nz) |
|
2444 { |
|
2445 // Resize the sparse matrix |
5275
|
2446 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
2447 retval.change_capacity (sz); |
|
2448 x_nz = sz; |
|
2449 } |
|
2450 |
5630
|
2451 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
2452 if (work[i] != 0.) |
|
2453 { |
|
2454 retval.xridx(ii) = i; |
|
2455 retval.xdata(ii++) = work[i]; |
|
2456 } |
|
2457 retval.xcidx(j+1) = ii; |
|
2458 } |
|
2459 |
|
2460 retval.maybe_compress (); |
|
2461 |
5681
|
2462 if (calc_cond) |
|
2463 { |
|
2464 // Calculation of 1-norm of inv(*this) |
|
2465 for (octave_idx_type i = 0; i < nm; i++) |
|
2466 work[i] = 0.; |
|
2467 |
|
2468 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2469 { |
5681
|
2470 work[j] = 1.; |
|
2471 |
|
2472 for (octave_idx_type k = j; k >= 0; k--) |
5164
|
2473 { |
5681
|
2474 if (work[k] != 0.) |
5164
|
2475 { |
5681
|
2476 Complex tmp = work[k] / data(cidx(k+1)-1); |
|
2477 work[k] = tmp; |
|
2478 for (octave_idx_type i = cidx(k); |
|
2479 i < cidx(k+1)-1; i++) |
|
2480 { |
|
2481 octave_idx_type iidx = ridx(i); |
|
2482 work[iidx] = work[iidx] - tmp * data(i); |
|
2483 } |
5164
|
2484 } |
|
2485 } |
5681
|
2486 double atmp = 0; |
|
2487 for (octave_idx_type i = 0; i < j+1; i++) |
|
2488 { |
|
2489 atmp += std::abs(work[i]); |
|
2490 work[i] = 0.; |
|
2491 } |
|
2492 if (atmp > ainvnorm) |
|
2493 ainvnorm = atmp; |
5164
|
2494 } |
5681
|
2495 rcond = 1. / ainvnorm / anorm; |
|
2496 } |
|
2497 } |
5164
|
2498 |
|
2499 triangular_error: |
|
2500 if (err != 0) |
|
2501 { |
|
2502 if (sing_handler) |
5681
|
2503 { |
|
2504 sing_handler (rcond); |
|
2505 mattype.mark_as_rectangular (); |
|
2506 } |
5164
|
2507 else |
|
2508 (*current_liboctave_error_handler) |
|
2509 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
2510 rcond); |
|
2511 } |
|
2512 |
|
2513 volatile double rcond_plus_one = rcond + 1.0; |
|
2514 |
|
2515 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
2516 { |
|
2517 err = -2; |
|
2518 |
|
2519 if (sing_handler) |
5681
|
2520 { |
|
2521 sing_handler (rcond); |
|
2522 mattype.mark_as_rectangular (); |
|
2523 } |
5164
|
2524 else |
|
2525 (*current_liboctave_error_handler) |
|
2526 ("matrix singular to machine precision, rcond = %g", |
|
2527 rcond); |
|
2528 } |
|
2529 } |
|
2530 else |
|
2531 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
2532 } |
|
2533 |
|
2534 return retval; |
|
2535 } |
|
2536 |
|
2537 ComplexMatrix |
5785
|
2538 SparseComplexMatrix::ltsolve (MatrixType &mattype, const Matrix& b, |
5630
|
2539 octave_idx_type& err, double& rcond, |
5681
|
2540 solve_singularity_handler sing_handler, |
|
2541 bool calc_cond) const |
5164
|
2542 { |
|
2543 ComplexMatrix retval; |
|
2544 |
5275
|
2545 octave_idx_type nr = rows (); |
|
2546 octave_idx_type nc = cols (); |
5630
|
2547 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
2548 err = 0; |
|
2549 |
5630
|
2550 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
2551 (*current_liboctave_error_handler) |
|
2552 ("matrix dimension mismatch solution of linear equations"); |
|
2553 else |
|
2554 { |
|
2555 // Print spparms("spumoni") info if requested |
|
2556 int typ = mattype.type (); |
|
2557 mattype.info (); |
|
2558 |
5785
|
2559 if (typ == MatrixType::Permuted_Lower || |
|
2560 typ == MatrixType::Lower) |
5164
|
2561 { |
|
2562 double anorm = 0.; |
|
2563 double ainvnorm = 0.; |
5630
|
2564 octave_idx_type b_nc = b.cols (); |
5681
|
2565 rcond = 1.; |
|
2566 |
|
2567 if (calc_cond) |
|
2568 { |
|
2569 // Calculate the 1-norm of matrix for rcond calculation |
|
2570 for (octave_idx_type j = 0; j < nc; j++) |
|
2571 { |
|
2572 double atmp = 0.; |
|
2573 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
2574 atmp += std::abs(data(i)); |
|
2575 if (atmp > anorm) |
|
2576 anorm = atmp; |
|
2577 } |
5164
|
2578 } |
|
2579 |
5785
|
2580 if (typ == MatrixType::Permuted_Lower) |
5164
|
2581 { |
5630
|
2582 retval.resize (nc, b_nc); |
|
2583 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5322
|
2584 octave_idx_type *perm = mattype.triangular_perm (); |
5164
|
2585 |
5630
|
2586 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2587 { |
5630
|
2588 for (octave_idx_type i = 0; i < nm; i++) |
|
2589 work[i] = 0.; |
5275
|
2590 for (octave_idx_type i = 0; i < nr; i++) |
5322
|
2591 work[perm[i]] = b(i,j); |
5164
|
2592 |
5630
|
2593 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
2594 { |
5322
|
2595 if (work[k] != 0.) |
5164
|
2596 { |
5322
|
2597 octave_idx_type minr = nr; |
|
2598 octave_idx_type mini = 0; |
|
2599 |
|
2600 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
|
2601 if (perm[ridx(i)] < minr) |
|
2602 { |
|
2603 minr = perm[ridx(i)]; |
|
2604 mini = i; |
|
2605 } |
|
2606 |
5681
|
2607 if (minr != k || data (mini) == 0.) |
5164
|
2608 { |
|
2609 err = -2; |
|
2610 goto triangular_error; |
|
2611 } |
|
2612 |
5322
|
2613 Complex tmp = work[k] / data(mini); |
|
2614 work[k] = tmp; |
|
2615 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
5164
|
2616 { |
5322
|
2617 if (i == mini) |
|
2618 continue; |
|
2619 |
|
2620 octave_idx_type iidx = perm[ridx(i)]; |
|
2621 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
2622 } |
|
2623 } |
|
2624 } |
|
2625 |
5630
|
2626 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
2627 retval (i, j) = work[i]; |
5164
|
2628 } |
|
2629 |
5681
|
2630 if (calc_cond) |
|
2631 { |
|
2632 // Calculation of 1-norm of inv(*this) |
|
2633 for (octave_idx_type i = 0; i < nm; i++) |
|
2634 work[i] = 0.; |
|
2635 |
|
2636 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2637 { |
5681
|
2638 work[j] = 1.; |
|
2639 |
|
2640 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
2641 { |
5681
|
2642 if (work[k] != 0.) |
5164
|
2643 { |
5681
|
2644 octave_idx_type minr = nr; |
|
2645 octave_idx_type mini = 0; |
|
2646 |
|
2647 for (octave_idx_type i = cidx(k); |
|
2648 i < cidx(k+1); i++) |
|
2649 if (perm[ridx(i)] < minr) |
|
2650 { |
|
2651 minr = perm[ridx(i)]; |
|
2652 mini = i; |
|
2653 } |
|
2654 |
|
2655 Complex tmp = work[k] / data(mini); |
|
2656 work[k] = tmp; |
|
2657 for (octave_idx_type i = cidx(k); |
|
2658 i < cidx(k+1); i++) |
|
2659 { |
|
2660 if (i == mini) |
|
2661 continue; |
|
2662 |
|
2663 octave_idx_type iidx = perm[ridx(i)]; |
|
2664 work[iidx] = work[iidx] - tmp * data(i); |
|
2665 } |
5164
|
2666 } |
|
2667 } |
5681
|
2668 |
|
2669 double atmp = 0; |
|
2670 for (octave_idx_type i = j; i < nc; i++) |
|
2671 { |
|
2672 atmp += std::abs(work[i]); |
|
2673 work[i] = 0.; |
|
2674 } |
|
2675 if (atmp > ainvnorm) |
|
2676 ainvnorm = atmp; |
5164
|
2677 } |
5681
|
2678 rcond = 1. / ainvnorm / anorm; |
5164
|
2679 } |
|
2680 } |
|
2681 else |
|
2682 { |
5630
|
2683 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
|
2684 retval.resize (nc, b_nc, 0.); |
|
2685 |
|
2686 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2687 { |
5630
|
2688 for (octave_idx_type i = 0; i < nr; i++) |
|
2689 work[i] = b(i,j); |
|
2690 for (octave_idx_type i = nr; i < nc; i++) |
|
2691 work[i] = 0.; |
|
2692 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
2693 { |
5630
|
2694 if (work[k] != 0.) |
5164
|
2695 { |
5681
|
2696 if (ridx(cidx(k)) != k || |
|
2697 data(cidx(k)) == 0.) |
5164
|
2698 { |
|
2699 err = -2; |
|
2700 goto triangular_error; |
|
2701 } |
|
2702 |
5630
|
2703 Complex tmp = work[k] / data(cidx(k)); |
|
2704 work[k] = tmp; |
5275
|
2705 for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++) |
5164
|
2706 { |
5275
|
2707 octave_idx_type iidx = ridx(i); |
5630
|
2708 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
2709 } |
|
2710 } |
|
2711 } |
5630
|
2712 for (octave_idx_type i = 0; i < nc; i++) |
|
2713 retval.xelem (i, j) = work[i]; |
5164
|
2714 } |
|
2715 |
5681
|
2716 if (calc_cond) |
|
2717 { |
|
2718 // Calculation of 1-norm of inv(*this) |
|
2719 for (octave_idx_type i = 0; i < nm; i++) |
|
2720 work[i] = 0.; |
|
2721 |
|
2722 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2723 { |
5681
|
2724 work[j] = 1.; |
|
2725 |
|
2726 for (octave_idx_type k = j; k < nc; k++) |
5164
|
2727 { |
5681
|
2728 |
|
2729 if (work[k] != 0.) |
5164
|
2730 { |
5681
|
2731 Complex tmp = work[k] / data(cidx(k)); |
|
2732 work[k] = tmp; |
|
2733 for (octave_idx_type i = cidx(k)+1; |
|
2734 i < cidx(k+1); i++) |
|
2735 { |
|
2736 octave_idx_type iidx = ridx(i); |
|
2737 work[iidx] = work[iidx] - tmp * data(i); |
|
2738 } |
5164
|
2739 } |
|
2740 } |
5681
|
2741 double atmp = 0; |
|
2742 for (octave_idx_type i = j; i < nc; i++) |
|
2743 { |
|
2744 atmp += std::abs(work[i]); |
|
2745 work[i] = 0.; |
|
2746 } |
|
2747 if (atmp > ainvnorm) |
|
2748 ainvnorm = atmp; |
5164
|
2749 } |
5681
|
2750 rcond = 1. / ainvnorm / anorm; |
|
2751 } |
|
2752 } |
5164
|
2753 triangular_error: |
|
2754 if (err != 0) |
|
2755 { |
|
2756 if (sing_handler) |
5681
|
2757 { |
|
2758 sing_handler (rcond); |
|
2759 mattype.mark_as_rectangular (); |
|
2760 } |
5164
|
2761 else |
|
2762 (*current_liboctave_error_handler) |
|
2763 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
2764 rcond); |
|
2765 } |
|
2766 |
|
2767 volatile double rcond_plus_one = rcond + 1.0; |
|
2768 |
|
2769 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
2770 { |
|
2771 err = -2; |
|
2772 |
|
2773 if (sing_handler) |
5681
|
2774 { |
|
2775 sing_handler (rcond); |
|
2776 mattype.mark_as_rectangular (); |
|
2777 } |
5164
|
2778 else |
|
2779 (*current_liboctave_error_handler) |
|
2780 ("matrix singular to machine precision, rcond = %g", |
|
2781 rcond); |
|
2782 } |
|
2783 } |
|
2784 else |
|
2785 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
2786 } |
|
2787 |
|
2788 return retval; |
|
2789 } |
|
2790 |
|
2791 SparseComplexMatrix |
5785
|
2792 SparseComplexMatrix::ltsolve (MatrixType &mattype, const SparseMatrix& b, |
5630
|
2793 octave_idx_type& err, double& rcond, |
5681
|
2794 solve_singularity_handler sing_handler, |
|
2795 bool calc_cond) const |
5164
|
2796 { |
|
2797 SparseComplexMatrix retval; |
|
2798 |
5275
|
2799 octave_idx_type nr = rows (); |
|
2800 octave_idx_type nc = cols (); |
5630
|
2801 octave_idx_type nm = (nc > nr ? nc : nr); |
|
2802 |
5164
|
2803 err = 0; |
|
2804 |
5630
|
2805 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
2806 (*current_liboctave_error_handler) |
|
2807 ("matrix dimension mismatch solution of linear equations"); |
|
2808 else |
|
2809 { |
|
2810 // Print spparms("spumoni") info if requested |
|
2811 int typ = mattype.type (); |
|
2812 mattype.info (); |
|
2813 |
5785
|
2814 if (typ == MatrixType::Permuted_Lower || |
|
2815 typ == MatrixType::Lower) |
5164
|
2816 { |
|
2817 double anorm = 0.; |
|
2818 double ainvnorm = 0.; |
5681
|
2819 rcond = 1.; |
|
2820 |
|
2821 if (calc_cond) |
|
2822 { |
|
2823 // Calculate the 1-norm of matrix for rcond calculation |
|
2824 for (octave_idx_type j = 0; j < nc; j++) |
|
2825 { |
|
2826 double atmp = 0.; |
|
2827 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
2828 atmp += std::abs(data(i)); |
|
2829 if (atmp > anorm) |
|
2830 anorm = atmp; |
|
2831 } |
5164
|
2832 } |
|
2833 |
5275
|
2834 octave_idx_type b_nc = b.cols (); |
5681
|
2835 octave_idx_type b_nz = b.nnz (); |
5630
|
2836 retval = SparseComplexMatrix (nc, b_nc, b_nz); |
5164
|
2837 retval.xcidx(0) = 0; |
5275
|
2838 octave_idx_type ii = 0; |
|
2839 octave_idx_type x_nz = b_nz; |
5164
|
2840 |
5785
|
2841 if (typ == MatrixType::Permuted_Lower) |
5164
|
2842 { |
5630
|
2843 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5322
|
2844 octave_idx_type *perm = mattype.triangular_perm (); |
5164
|
2845 |
5275
|
2846 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2847 { |
5630
|
2848 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
2849 work[i] = 0.; |
5275
|
2850 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5322
|
2851 work[perm[b.ridx(i)]] = b.data(i); |
5164
|
2852 |
5630
|
2853 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
2854 { |
5322
|
2855 if (work[k] != 0.) |
5164
|
2856 { |
5322
|
2857 octave_idx_type minr = nr; |
|
2858 octave_idx_type mini = 0; |
|
2859 |
|
2860 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
|
2861 if (perm[ridx(i)] < minr) |
|
2862 { |
|
2863 minr = perm[ridx(i)]; |
|
2864 mini = i; |
|
2865 } |
|
2866 |
5681
|
2867 if (minr != k || data (mini) == 0.) |
5164
|
2868 { |
|
2869 err = -2; |
|
2870 goto triangular_error; |
|
2871 } |
|
2872 |
5322
|
2873 Complex tmp = work[k] / data(mini); |
|
2874 work[k] = tmp; |
|
2875 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
5164
|
2876 { |
5322
|
2877 if (i == mini) |
|
2878 continue; |
|
2879 |
|
2880 octave_idx_type iidx = perm[ridx(i)]; |
|
2881 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
2882 } |
|
2883 } |
|
2884 } |
|
2885 |
|
2886 // Count non-zeros in work vector and adjust space in |
|
2887 // retval if needed |
5275
|
2888 octave_idx_type new_nnz = 0; |
5630
|
2889 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
2890 if (work[i] != 0.) |
|
2891 new_nnz++; |
|
2892 |
|
2893 if (ii + new_nnz > x_nz) |
|
2894 { |
|
2895 // Resize the sparse matrix |
5275
|
2896 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
2897 retval.change_capacity (sz); |
|
2898 x_nz = sz; |
|
2899 } |
|
2900 |
5630
|
2901 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
2902 if (work[i] != 0.) |
5164
|
2903 { |
|
2904 retval.xridx(ii) = i; |
5322
|
2905 retval.xdata(ii++) = work[i]; |
5164
|
2906 } |
|
2907 retval.xcidx(j+1) = ii; |
|
2908 } |
|
2909 |
|
2910 retval.maybe_compress (); |
|
2911 |
5681
|
2912 if (calc_cond) |
|
2913 { |
|
2914 // Calculation of 1-norm of inv(*this) |
|
2915 for (octave_idx_type i = 0; i < nm; i++) |
|
2916 work[i] = 0.; |
|
2917 |
|
2918 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
2919 { |
5681
|
2920 work[j] = 1.; |
|
2921 |
|
2922 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
2923 { |
5681
|
2924 if (work[k] != 0.) |
5164
|
2925 { |
5681
|
2926 octave_idx_type minr = nr; |
|
2927 octave_idx_type mini = 0; |
|
2928 |
|
2929 for (octave_idx_type i = cidx(k); |
|
2930 i < cidx(k+1); i++) |
|
2931 if (perm[ridx(i)] < minr) |
|
2932 { |
|
2933 minr = perm[ridx(i)]; |
|
2934 mini = i; |
|
2935 } |
|
2936 |
|
2937 Complex tmp = work[k] / data(mini); |
|
2938 work[k] = tmp; |
|
2939 for (octave_idx_type i = cidx(k); |
|
2940 i < cidx(k+1); i++) |
|
2941 { |
|
2942 if (i == mini) |
|
2943 continue; |
|
2944 |
|
2945 octave_idx_type iidx = perm[ridx(i)]; |
|
2946 work[iidx] = work[iidx] - tmp * data(i); |
|
2947 } |
5164
|
2948 } |
|
2949 } |
5681
|
2950 |
|
2951 double atmp = 0; |
|
2952 for (octave_idx_type i = j; i < nc; i++) |
|
2953 { |
|
2954 atmp += std::abs(work[i]); |
|
2955 work[i] = 0.; |
|
2956 } |
|
2957 if (atmp > ainvnorm) |
|
2958 ainvnorm = atmp; |
5164
|
2959 } |
5681
|
2960 rcond = 1. / ainvnorm / anorm; |
5164
|
2961 } |
|
2962 } |
|
2963 else |
|
2964 { |
5630
|
2965 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5164
|
2966 |
5275
|
2967 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
2968 { |
5630
|
2969 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
2970 work[i] = 0.; |
5275
|
2971 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
2972 work[b.ridx(i)] = b.data(i); |
|
2973 |
5630
|
2974 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
2975 { |
|
2976 if (work[k] != 0.) |
|
2977 { |
5681
|
2978 if (ridx(cidx(k)) != k || |
|
2979 data(cidx(k)) == 0.) |
5164
|
2980 { |
|
2981 err = -2; |
|
2982 goto triangular_error; |
|
2983 } |
|
2984 |
|
2985 Complex tmp = work[k] / data(cidx(k)); |
|
2986 work[k] = tmp; |
5275
|
2987 for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++) |
5164
|
2988 { |
5275
|
2989 octave_idx_type iidx = ridx(i); |
5164
|
2990 work[iidx] = work[iidx] - tmp * data(i); |
|
2991 } |
|
2992 } |
|
2993 } |
|
2994 |
|
2995 // Count non-zeros in work vector and adjust space in |
|
2996 // retval if needed |
5275
|
2997 octave_idx_type new_nnz = 0; |
5630
|
2998 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
2999 if (work[i] != 0.) |
|
3000 new_nnz++; |
|
3001 |
|
3002 if (ii + new_nnz > x_nz) |
|
3003 { |
|
3004 // Resize the sparse matrix |
5275
|
3005 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
3006 retval.change_capacity (sz); |
|
3007 x_nz = sz; |
|
3008 } |
|
3009 |
5630
|
3010 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
3011 if (work[i] != 0.) |
|
3012 { |
|
3013 retval.xridx(ii) = i; |
|
3014 retval.xdata(ii++) = work[i]; |
|
3015 } |
|
3016 retval.xcidx(j+1) = ii; |
|
3017 } |
|
3018 |
|
3019 retval.maybe_compress (); |
|
3020 |
5681
|
3021 if (calc_cond) |
|
3022 { |
|
3023 // Calculation of 1-norm of inv(*this) |
|
3024 for (octave_idx_type i = 0; i < nm; i++) |
|
3025 work[i] = 0.; |
|
3026 |
|
3027 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
3028 { |
5681
|
3029 work[j] = 1.; |
|
3030 |
|
3031 for (octave_idx_type k = j; k < nc; k++) |
5164
|
3032 { |
5681
|
3033 |
|
3034 if (work[k] != 0.) |
5164
|
3035 { |
5681
|
3036 Complex tmp = work[k] / data(cidx(k)); |
|
3037 work[k] = tmp; |
|
3038 for (octave_idx_type i = cidx(k)+1; |
|
3039 i < cidx(k+1); i++) |
|
3040 { |
|
3041 octave_idx_type iidx = ridx(i); |
|
3042 work[iidx] = work[iidx] - tmp * data(i); |
|
3043 } |
5164
|
3044 } |
|
3045 } |
5681
|
3046 double atmp = 0; |
|
3047 for (octave_idx_type i = j; i < nc; i++) |
|
3048 { |
|
3049 atmp += std::abs(work[i]); |
|
3050 work[i] = 0.; |
|
3051 } |
|
3052 if (atmp > ainvnorm) |
|
3053 ainvnorm = atmp; |
5164
|
3054 } |
5681
|
3055 rcond = 1. / ainvnorm / anorm; |
|
3056 } |
|
3057 } |
5164
|
3058 |
|
3059 triangular_error: |
|
3060 if (err != 0) |
|
3061 { |
|
3062 if (sing_handler) |
5681
|
3063 { |
|
3064 sing_handler (rcond); |
|
3065 mattype.mark_as_rectangular (); |
|
3066 } |
5164
|
3067 else |
|
3068 (*current_liboctave_error_handler) |
|
3069 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
3070 rcond); |
|
3071 } |
|
3072 |
|
3073 volatile double rcond_plus_one = rcond + 1.0; |
|
3074 |
|
3075 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
3076 { |
|
3077 err = -2; |
|
3078 |
|
3079 if (sing_handler) |
5681
|
3080 { |
|
3081 sing_handler (rcond); |
|
3082 mattype.mark_as_rectangular (); |
|
3083 } |
5164
|
3084 else |
|
3085 (*current_liboctave_error_handler) |
|
3086 ("matrix singular to machine precision, rcond = %g", |
|
3087 rcond); |
|
3088 } |
|
3089 } |
|
3090 else |
|
3091 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
3092 } |
|
3093 |
|
3094 return retval; |
|
3095 } |
|
3096 |
|
3097 ComplexMatrix |
5785
|
3098 SparseComplexMatrix::ltsolve (MatrixType &mattype, const ComplexMatrix& b, |
5630
|
3099 octave_idx_type& err, double& rcond, |
5681
|
3100 solve_singularity_handler sing_handler, |
|
3101 bool calc_cond) const |
5164
|
3102 { |
|
3103 ComplexMatrix retval; |
|
3104 |
5275
|
3105 octave_idx_type nr = rows (); |
|
3106 octave_idx_type nc = cols (); |
5630
|
3107 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
3108 err = 0; |
|
3109 |
5630
|
3110 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
3111 (*current_liboctave_error_handler) |
|
3112 ("matrix dimension mismatch solution of linear equations"); |
|
3113 else |
|
3114 { |
|
3115 // Print spparms("spumoni") info if requested |
|
3116 int typ = mattype.type (); |
|
3117 mattype.info (); |
|
3118 |
5785
|
3119 if (typ == MatrixType::Permuted_Lower || |
|
3120 typ == MatrixType::Lower) |
5164
|
3121 { |
|
3122 double anorm = 0.; |
|
3123 double ainvnorm = 0.; |
5275
|
3124 octave_idx_type b_nc = b.cols (); |
5681
|
3125 rcond = 1.; |
|
3126 |
|
3127 if (calc_cond) |
|
3128 { |
|
3129 // Calculate the 1-norm of matrix for rcond calculation |
|
3130 for (octave_idx_type j = 0; j < nc; j++) |
|
3131 { |
|
3132 double atmp = 0.; |
|
3133 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
3134 atmp += std::abs(data(i)); |
|
3135 if (atmp > anorm) |
|
3136 anorm = atmp; |
|
3137 } |
5164
|
3138 } |
|
3139 |
5785
|
3140 if (typ == MatrixType::Permuted_Lower) |
5164
|
3141 { |
5630
|
3142 retval.resize (nc, b_nc); |
|
3143 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5322
|
3144 octave_idx_type *perm = mattype.triangular_perm (); |
5164
|
3145 |
5275
|
3146 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
3147 { |
5630
|
3148 for (octave_idx_type i = 0; i < nm; i++) |
|
3149 work[i] = 0.; |
5275
|
3150 for (octave_idx_type i = 0; i < nr; i++) |
5322
|
3151 work[perm[i]] = b(i,j); |
5164
|
3152 |
5630
|
3153 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
3154 { |
5322
|
3155 if (work[k] != 0.) |
5164
|
3156 { |
5322
|
3157 octave_idx_type minr = nr; |
|
3158 octave_idx_type mini = 0; |
|
3159 |
|
3160 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
|
3161 if (perm[ridx(i)] < minr) |
|
3162 { |
|
3163 minr = perm[ridx(i)]; |
|
3164 mini = i; |
|
3165 } |
|
3166 |
5681
|
3167 if (minr != k || data (mini) == 0.) |
5164
|
3168 { |
|
3169 err = -2; |
|
3170 goto triangular_error; |
|
3171 } |
|
3172 |
5322
|
3173 Complex tmp = work[k] / data(mini); |
|
3174 work[k] = tmp; |
|
3175 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
5164
|
3176 { |
5322
|
3177 if (i == mini) |
|
3178 continue; |
|
3179 |
|
3180 octave_idx_type iidx = perm[ridx(i)]; |
|
3181 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
3182 } |
|
3183 } |
|
3184 } |
|
3185 |
5630
|
3186 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
3187 retval (i, j) = work[i]; |
5164
|
3188 } |
|
3189 |
5681
|
3190 if (calc_cond) |
|
3191 { |
|
3192 // Calculation of 1-norm of inv(*this) |
|
3193 for (octave_idx_type i = 0; i < nm; i++) |
|
3194 work[i] = 0.; |
|
3195 |
|
3196 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
3197 { |
5681
|
3198 work[j] = 1.; |
|
3199 |
|
3200 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
3201 { |
5681
|
3202 if (work[k] != 0.) |
5164
|
3203 { |
5681
|
3204 octave_idx_type minr = nr; |
|
3205 octave_idx_type mini = 0; |
|
3206 |
|
3207 for (octave_idx_type i = cidx(k); |
|
3208 i < cidx(k+1); i++) |
|
3209 if (perm[ridx(i)] < minr) |
|
3210 { |
|
3211 minr = perm[ridx(i)]; |
|
3212 mini = i; |
|
3213 } |
|
3214 |
|
3215 Complex tmp = work[k] / data(mini); |
|
3216 work[k] = tmp; |
|
3217 for (octave_idx_type i = cidx(k); |
|
3218 i < cidx(k+1); i++) |
|
3219 { |
|
3220 if (i == mini) |
|
3221 continue; |
|
3222 |
|
3223 octave_idx_type iidx = perm[ridx(i)]; |
|
3224 work[iidx] = work[iidx] - tmp * data(i); |
|
3225 } |
5164
|
3226 } |
|
3227 } |
5681
|
3228 |
|
3229 double atmp = 0; |
|
3230 for (octave_idx_type i = j; i < nc; i++) |
|
3231 { |
|
3232 atmp += std::abs(work[i]); |
|
3233 work[i] = 0.; |
|
3234 } |
|
3235 if (atmp > ainvnorm) |
|
3236 ainvnorm = atmp; |
5164
|
3237 } |
5681
|
3238 rcond = 1. / ainvnorm / anorm; |
5164
|
3239 } |
|
3240 } |
|
3241 else |
|
3242 { |
5630
|
3243 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
|
3244 retval.resize (nc, b_nc, 0.); |
|
3245 |
5164
|
3246 |
5275
|
3247 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
3248 { |
5630
|
3249 for (octave_idx_type i = 0; i < nr; i++) |
|
3250 work[i] = b(i,j); |
|
3251 for (octave_idx_type i = nr; i < nc; i++) |
|
3252 work[i] = 0.; |
|
3253 |
|
3254 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
3255 { |
5630
|
3256 if (work[k] != 0.) |
5164
|
3257 { |
5681
|
3258 if (ridx(cidx(k)) != k || |
|
3259 data(cidx(k)) == 0.) |
5164
|
3260 { |
|
3261 err = -2; |
|
3262 goto triangular_error; |
|
3263 } |
|
3264 |
5630
|
3265 Complex tmp = work[k] / data(cidx(k)); |
|
3266 work[k] = tmp; |
5275
|
3267 for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++) |
5164
|
3268 { |
5275
|
3269 octave_idx_type iidx = ridx(i); |
5630
|
3270 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
3271 } |
|
3272 } |
|
3273 } |
5630
|
3274 |
|
3275 for (octave_idx_type i = 0; i < nc; i++) |
|
3276 retval.xelem (i, j) = work[i]; |
5164
|
3277 } |
|
3278 |
5681
|
3279 if (calc_cond) |
|
3280 { |
|
3281 // Calculation of 1-norm of inv(*this) |
|
3282 for (octave_idx_type i = 0; i < nm; i++) |
|
3283 work[i] = 0.; |
|
3284 |
|
3285 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
3286 { |
5681
|
3287 work[j] = 1.; |
|
3288 |
|
3289 for (octave_idx_type k = j; k < nc; k++) |
5164
|
3290 { |
5681
|
3291 |
|
3292 if (work[k] != 0.) |
5164
|
3293 { |
5681
|
3294 Complex tmp = work[k] / data(cidx(k)); |
|
3295 work[k] = tmp; |
|
3296 for (octave_idx_type i = cidx(k)+1; |
|
3297 i < cidx(k+1); i++) |
|
3298 { |
|
3299 octave_idx_type iidx = ridx(i); |
|
3300 work[iidx] = work[iidx] - tmp * data(i); |
|
3301 } |
5164
|
3302 } |
|
3303 } |
5681
|
3304 double atmp = 0; |
|
3305 for (octave_idx_type i = j; i < nc; i++) |
|
3306 { |
|
3307 atmp += std::abs(work[i]); |
|
3308 work[i] = 0.; |
|
3309 } |
|
3310 if (atmp > ainvnorm) |
|
3311 ainvnorm = atmp; |
5164
|
3312 } |
5681
|
3313 rcond = 1. / ainvnorm / anorm; |
|
3314 } |
|
3315 } |
5164
|
3316 |
|
3317 triangular_error: |
|
3318 if (err != 0) |
|
3319 { |
|
3320 if (sing_handler) |
5681
|
3321 { |
|
3322 sing_handler (rcond); |
|
3323 mattype.mark_as_rectangular (); |
|
3324 } |
5164
|
3325 else |
|
3326 (*current_liboctave_error_handler) |
|
3327 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
3328 rcond); |
|
3329 } |
|
3330 |
|
3331 volatile double rcond_plus_one = rcond + 1.0; |
|
3332 |
|
3333 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
3334 { |
|
3335 err = -2; |
|
3336 |
|
3337 if (sing_handler) |
5681
|
3338 { |
|
3339 sing_handler (rcond); |
|
3340 mattype.mark_as_rectangular (); |
|
3341 } |
5164
|
3342 else |
|
3343 (*current_liboctave_error_handler) |
|
3344 ("matrix singular to machine precision, rcond = %g", |
|
3345 rcond); |
|
3346 } |
|
3347 } |
|
3348 else |
|
3349 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
3350 } |
|
3351 |
|
3352 return retval; |
|
3353 } |
|
3354 |
|
3355 SparseComplexMatrix |
5785
|
3356 SparseComplexMatrix::ltsolve (MatrixType &mattype, const SparseComplexMatrix& b, |
5630
|
3357 octave_idx_type& err, double& rcond, |
5681
|
3358 solve_singularity_handler sing_handler, |
|
3359 bool calc_cond) const |
5164
|
3360 { |
|
3361 SparseComplexMatrix retval; |
|
3362 |
5275
|
3363 octave_idx_type nr = rows (); |
|
3364 octave_idx_type nc = cols (); |
5630
|
3365 octave_idx_type nm = (nc > nr ? nc : nr); |
5164
|
3366 err = 0; |
|
3367 |
5630
|
3368 if (nr == 0 || nc == 0 || nr != b.rows ()) |
5164
|
3369 (*current_liboctave_error_handler) |
|
3370 ("matrix dimension mismatch solution of linear equations"); |
|
3371 else |
|
3372 { |
|
3373 // Print spparms("spumoni") info if requested |
|
3374 int typ = mattype.type (); |
|
3375 mattype.info (); |
|
3376 |
5785
|
3377 if (typ == MatrixType::Permuted_Lower || |
|
3378 typ == MatrixType::Lower) |
5164
|
3379 { |
|
3380 double anorm = 0.; |
|
3381 double ainvnorm = 0.; |
5681
|
3382 rcond = 1.; |
|
3383 |
|
3384 if (calc_cond) |
|
3385 { |
|
3386 // Calculate the 1-norm of matrix for rcond calculation |
|
3387 for (octave_idx_type j = 0; j < nc; j++) |
|
3388 { |
|
3389 double atmp = 0.; |
|
3390 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
3391 atmp += std::abs(data(i)); |
|
3392 if (atmp > anorm) |
|
3393 anorm = atmp; |
|
3394 } |
5164
|
3395 } |
|
3396 |
5275
|
3397 octave_idx_type b_nc = b.cols (); |
5681
|
3398 octave_idx_type b_nz = b.nnz (); |
5630
|
3399 retval = SparseComplexMatrix (nc, b_nc, b_nz); |
5164
|
3400 retval.xcidx(0) = 0; |
5275
|
3401 octave_idx_type ii = 0; |
|
3402 octave_idx_type x_nz = b_nz; |
5164
|
3403 |
5785
|
3404 if (typ == MatrixType::Permuted_Lower) |
5164
|
3405 { |
5630
|
3406 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5322
|
3407 octave_idx_type *perm = mattype.triangular_perm (); |
5164
|
3408 |
5275
|
3409 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
3410 { |
5630
|
3411 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
3412 work[i] = 0.; |
5275
|
3413 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5322
|
3414 work[perm[b.ridx(i)]] = b.data(i); |
5164
|
3415 |
5630
|
3416 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
3417 { |
5322
|
3418 if (work[k] != 0.) |
5164
|
3419 { |
5322
|
3420 octave_idx_type minr = nr; |
|
3421 octave_idx_type mini = 0; |
|
3422 |
|
3423 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
|
3424 if (perm[ridx(i)] < minr) |
|
3425 { |
|
3426 minr = perm[ridx(i)]; |
|
3427 mini = i; |
|
3428 } |
|
3429 |
5681
|
3430 if (minr != k || data (mini) == 0.) |
5164
|
3431 { |
|
3432 err = -2; |
|
3433 goto triangular_error; |
|
3434 } |
|
3435 |
5322
|
3436 Complex tmp = work[k] / data(mini); |
|
3437 work[k] = tmp; |
|
3438 for (octave_idx_type i = cidx(k); i < cidx(k+1); i++) |
5164
|
3439 { |
5322
|
3440 if (i == mini) |
|
3441 continue; |
|
3442 |
|
3443 octave_idx_type iidx = perm[ridx(i)]; |
|
3444 work[iidx] = work[iidx] - tmp * data(i); |
5164
|
3445 } |
|
3446 } |
|
3447 } |
|
3448 |
|
3449 // Count non-zeros in work vector and adjust space in |
|
3450 // retval if needed |
5275
|
3451 octave_idx_type new_nnz = 0; |
5630
|
3452 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
3453 if (work[i] != 0.) |
|
3454 new_nnz++; |
|
3455 |
|
3456 if (ii + new_nnz > x_nz) |
|
3457 { |
|
3458 // Resize the sparse matrix |
5275
|
3459 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
3460 retval.change_capacity (sz); |
|
3461 x_nz = sz; |
|
3462 } |
|
3463 |
5630
|
3464 for (octave_idx_type i = 0; i < nc; i++) |
5322
|
3465 if (work[i] != 0.) |
5164
|
3466 { |
|
3467 retval.xridx(ii) = i; |
5322
|
3468 retval.xdata(ii++) = work[i]; |
5164
|
3469 } |
|
3470 retval.xcidx(j+1) = ii; |
|
3471 } |
|
3472 |
|
3473 retval.maybe_compress (); |
|
3474 |
5681
|
3475 if (calc_cond) |
|
3476 { |
|
3477 // Calculation of 1-norm of inv(*this) |
|
3478 for (octave_idx_type i = 0; i < nm; i++) |
|
3479 work[i] = 0.; |
|
3480 |
|
3481 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
3482 { |
5681
|
3483 work[j] = 1.; |
|
3484 |
|
3485 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
3486 { |
5681
|
3487 if (work[k] != 0.) |
5164
|
3488 { |
5681
|
3489 octave_idx_type minr = nr; |
|
3490 octave_idx_type mini = 0; |
|
3491 |
|
3492 for (octave_idx_type i = cidx(k); |
|
3493 i < cidx(k+1); i++) |
|
3494 if (perm[ridx(i)] < minr) |
|
3495 { |
|
3496 minr = perm[ridx(i)]; |
|
3497 mini = i; |
|
3498 } |
|
3499 |
|
3500 Complex tmp = work[k] / data(mini); |
|
3501 work[k] = tmp; |
|
3502 for (octave_idx_type i = cidx(k); |
|
3503 i < cidx(k+1); i++) |
|
3504 { |
|
3505 if (i == mini) |
|
3506 continue; |
|
3507 |
|
3508 octave_idx_type iidx = perm[ridx(i)]; |
|
3509 work[iidx] = work[iidx] - tmp * data(i); |
|
3510 } |
5164
|
3511 } |
|
3512 } |
5681
|
3513 |
|
3514 double atmp = 0; |
|
3515 for (octave_idx_type i = j; i < nc; i++) |
|
3516 { |
|
3517 atmp += std::abs(work[i]); |
|
3518 work[i] = 0.; |
|
3519 } |
|
3520 if (atmp > ainvnorm) |
|
3521 ainvnorm = atmp; |
5164
|
3522 } |
5681
|
3523 rcond = 1. / ainvnorm / anorm; |
5164
|
3524 } |
|
3525 } |
|
3526 else |
|
3527 { |
5630
|
3528 OCTAVE_LOCAL_BUFFER (Complex, work, nm); |
5164
|
3529 |
5275
|
3530 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
3531 { |
5630
|
3532 for (octave_idx_type i = 0; i < nm; i++) |
5164
|
3533 work[i] = 0.; |
5275
|
3534 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
3535 work[b.ridx(i)] = b.data(i); |
|
3536 |
5630
|
3537 for (octave_idx_type k = 0; k < nc; k++) |
5164
|
3538 { |
|
3539 if (work[k] != 0.) |
|
3540 { |
5681
|
3541 if (ridx(cidx(k)) != k || |
|
3542 data(cidx(k)) == 0.) |
5164
|
3543 { |
|
3544 err = -2; |
|
3545 goto triangular_error; |
|
3546 } |
|
3547 |
|
3548 Complex tmp = work[k] / data(cidx(k)); |
|
3549 work[k] = tmp; |
5275
|
3550 for (octave_idx_type i = cidx(k)+1; i < cidx(k+1); i++) |
5164
|
3551 { |
5275
|
3552 octave_idx_type iidx = ridx(i); |
5164
|
3553 work[iidx] = work[iidx] - tmp * data(i); |
|
3554 } |
|
3555 } |
|
3556 } |
|
3557 |
|
3558 // Count non-zeros in work vector and adjust space in |
|
3559 // retval if needed |
5275
|
3560 octave_idx_type new_nnz = 0; |
5630
|
3561 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
3562 if (work[i] != 0.) |
|
3563 new_nnz++; |
|
3564 |
|
3565 if (ii + new_nnz > x_nz) |
|
3566 { |
|
3567 // Resize the sparse matrix |
5275
|
3568 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
3569 retval.change_capacity (sz); |
|
3570 x_nz = sz; |
|
3571 } |
|
3572 |
5630
|
3573 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
3574 if (work[i] != 0.) |
|
3575 { |
|
3576 retval.xridx(ii) = i; |
|
3577 retval.xdata(ii++) = work[i]; |
|
3578 } |
|
3579 retval.xcidx(j+1) = ii; |
|
3580 } |
|
3581 |
|
3582 retval.maybe_compress (); |
|
3583 |
5681
|
3584 if (calc_cond) |
|
3585 { |
|
3586 // Calculation of 1-norm of inv(*this) |
|
3587 for (octave_idx_type i = 0; i < nm; i++) |
|
3588 work[i] = 0.; |
|
3589 |
|
3590 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
3591 { |
5681
|
3592 work[j] = 1.; |
|
3593 |
|
3594 for (octave_idx_type k = j; k < nc; k++) |
5164
|
3595 { |
5681
|
3596 |
|
3597 if (work[k] != 0.) |
5164
|
3598 { |
5681
|
3599 Complex tmp = work[k] / data(cidx(k)); |
|
3600 work[k] = tmp; |
|
3601 for (octave_idx_type i = cidx(k)+1; |
|
3602 i < cidx(k+1); i++) |
|
3603 { |
|
3604 octave_idx_type iidx = ridx(i); |
|
3605 work[iidx] = work[iidx] - tmp * data(i); |
|
3606 } |
5164
|
3607 } |
|
3608 } |
5681
|
3609 double atmp = 0; |
|
3610 for (octave_idx_type i = j; i < nc; i++) |
|
3611 { |
|
3612 atmp += std::abs(work[i]); |
|
3613 work[i] = 0.; |
|
3614 } |
|
3615 if (atmp > ainvnorm) |
|
3616 ainvnorm = atmp; |
5164
|
3617 } |
5681
|
3618 rcond = 1. / ainvnorm / anorm; |
|
3619 } |
|
3620 } |
5164
|
3621 |
|
3622 triangular_error: |
|
3623 if (err != 0) |
|
3624 { |
|
3625 if (sing_handler) |
5681
|
3626 { |
|
3627 sing_handler (rcond); |
|
3628 mattype.mark_as_rectangular (); |
|
3629 } |
5164
|
3630 else |
|
3631 (*current_liboctave_error_handler) |
|
3632 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
3633 rcond); |
|
3634 } |
|
3635 |
|
3636 volatile double rcond_plus_one = rcond + 1.0; |
|
3637 |
|
3638 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
3639 { |
|
3640 err = -2; |
|
3641 |
|
3642 if (sing_handler) |
5681
|
3643 { |
|
3644 sing_handler (rcond); |
|
3645 mattype.mark_as_rectangular (); |
|
3646 } |
5164
|
3647 else |
|
3648 (*current_liboctave_error_handler) |
|
3649 ("matrix singular to machine precision, rcond = %g", |
|
3650 rcond); |
|
3651 } |
|
3652 } |
|
3653 else |
|
3654 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
3655 } |
|
3656 |
|
3657 return retval; |
|
3658 } |
|
3659 |
|
3660 ComplexMatrix |
5785
|
3661 SparseComplexMatrix::trisolve (MatrixType &mattype, const Matrix& b, |
5681
|
3662 octave_idx_type& err, double& rcond, |
|
3663 solve_singularity_handler sing_handler, |
|
3664 bool calc_cond) const |
5164
|
3665 { |
|
3666 ComplexMatrix retval; |
|
3667 |
5275
|
3668 octave_idx_type nr = rows (); |
|
3669 octave_idx_type nc = cols (); |
5164
|
3670 err = 0; |
|
3671 |
|
3672 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
3673 (*current_liboctave_error_handler) |
|
3674 ("matrix dimension mismatch solution of linear equations"); |
5681
|
3675 else if (calc_cond) |
|
3676 (*current_liboctave_error_handler) |
|
3677 ("calculation of condition number not implemented"); |
5164
|
3678 else |
|
3679 { |
|
3680 // Print spparms("spumoni") info if requested |
|
3681 volatile int typ = mattype.type (); |
|
3682 mattype.info (); |
|
3683 |
5785
|
3684 if (typ == MatrixType::Tridiagonal_Hermitian) |
5164
|
3685 { |
5322
|
3686 OCTAVE_LOCAL_BUFFER (double, D, nr); |
5164
|
3687 OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1); |
|
3688 |
|
3689 if (mattype.is_dense ()) |
|
3690 { |
5275
|
3691 octave_idx_type ii = 0; |
|
3692 |
|
3693 for (octave_idx_type j = 0; j < nc-1; j++) |
5164
|
3694 { |
5322
|
3695 D[j] = std::real(data(ii++)); |
5164
|
3696 DL[j] = data(ii); |
|
3697 ii += 2; |
|
3698 } |
5322
|
3699 D[nc-1] = std::real(data(ii)); |
5164
|
3700 } |
|
3701 else |
|
3702 { |
|
3703 D[0] = 0.; |
5275
|
3704 for (octave_idx_type i = 0; i < nr - 1; i++) |
5164
|
3705 { |
|
3706 D[i+1] = 0.; |
|
3707 DL[i] = 0.; |
|
3708 } |
|
3709 |
5275
|
3710 for (octave_idx_type j = 0; j < nc; j++) |
|
3711 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
3712 { |
|
3713 if (ridx(i) == j) |
5322
|
3714 D[j] = std::real(data(i)); |
5164
|
3715 else if (ridx(i) == j + 1) |
|
3716 DL[j] = data(i); |
|
3717 } |
|
3718 } |
|
3719 |
5275
|
3720 octave_idx_type b_nc = b.cols(); |
5164
|
3721 retval = ComplexMatrix (b); |
|
3722 Complex *result = retval.fortran_vec (); |
|
3723 |
|
3724 F77_XFCN (zptsv, ZPTSV, (nr, b_nc, D, DL, result, |
|
3725 b.rows(), err)); |
|
3726 |
|
3727 if (f77_exception_encountered) |
|
3728 (*current_liboctave_error_handler) |
|
3729 ("unrecoverable error in zptsv"); |
|
3730 else if (err != 0) |
|
3731 { |
|
3732 err = 0; |
|
3733 mattype.mark_as_unsymmetric (); |
5785
|
3734 typ = MatrixType::Tridiagonal; |
5164
|
3735 } |
|
3736 else |
|
3737 rcond = 1.; |
|
3738 } |
|
3739 |
5785
|
3740 if (typ == MatrixType::Tridiagonal) |
5164
|
3741 { |
|
3742 OCTAVE_LOCAL_BUFFER (Complex, DU, nr - 1); |
|
3743 OCTAVE_LOCAL_BUFFER (Complex, D, nr); |
|
3744 OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1); |
|
3745 |
|
3746 if (mattype.is_dense ()) |
|
3747 { |
5275
|
3748 octave_idx_type ii = 0; |
|
3749 |
|
3750 for (octave_idx_type j = 0; j < nc-1; j++) |
5164
|
3751 { |
|
3752 D[j] = data(ii++); |
|
3753 DL[j] = data(ii++); |
|
3754 DU[j] = data(ii++); |
|
3755 } |
|
3756 D[nc-1] = data(ii); |
|
3757 } |
|
3758 else |
|
3759 { |
|
3760 D[0] = 0.; |
5275
|
3761 for (octave_idx_type i = 0; i < nr - 1; i++) |
5164
|
3762 { |
|
3763 D[i+1] = 0.; |
|
3764 DL[i] = 0.; |
|
3765 DU[i] = 0.; |
|
3766 } |
|
3767 |
5275
|
3768 for (octave_idx_type j = 0; j < nc; j++) |
|
3769 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
3770 { |
|
3771 if (ridx(i) == j) |
|
3772 D[j] = data(i); |
|
3773 else if (ridx(i) == j + 1) |
|
3774 DL[j] = data(i); |
|
3775 else if (ridx(i) == j - 1) |
5322
|
3776 DU[j-1] = data(i); |
5164
|
3777 } |
|
3778 } |
|
3779 |
5275
|
3780 octave_idx_type b_nc = b.cols(); |
5164
|
3781 retval = ComplexMatrix (b); |
|
3782 Complex *result = retval.fortran_vec (); |
|
3783 |
|
3784 F77_XFCN (zgtsv, ZGTSV, (nr, b_nc, DL, D, DU, result, |
|
3785 b.rows(), err)); |
|
3786 |
|
3787 if (f77_exception_encountered) |
|
3788 (*current_liboctave_error_handler) |
|
3789 ("unrecoverable error in zgtsv"); |
|
3790 else if (err != 0) |
|
3791 { |
|
3792 rcond = 0.; |
|
3793 err = -2; |
|
3794 |
|
3795 if (sing_handler) |
5681
|
3796 { |
|
3797 sing_handler (rcond); |
|
3798 mattype.mark_as_rectangular (); |
|
3799 } |
5164
|
3800 else |
|
3801 (*current_liboctave_error_handler) |
|
3802 ("matrix singular to machine precision"); |
|
3803 |
|
3804 } |
|
3805 else |
|
3806 rcond = 1.; |
|
3807 } |
5785
|
3808 else if (typ != MatrixType::Tridiagonal_Hermitian) |
5164
|
3809 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
3810 } |
|
3811 |
|
3812 return retval; |
|
3813 } |
|
3814 |
|
3815 SparseComplexMatrix |
5785
|
3816 SparseComplexMatrix::trisolve (MatrixType &mattype, const SparseMatrix& b, |
5681
|
3817 octave_idx_type& err, double& rcond, |
|
3818 solve_singularity_handler sing_handler, |
|
3819 bool calc_cond) const |
5164
|
3820 { |
|
3821 SparseComplexMatrix retval; |
|
3822 |
5275
|
3823 octave_idx_type nr = rows (); |
|
3824 octave_idx_type nc = cols (); |
5164
|
3825 err = 0; |
|
3826 |
|
3827 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
3828 (*current_liboctave_error_handler) |
|
3829 ("matrix dimension mismatch solution of linear equations"); |
5681
|
3830 else if (calc_cond) |
|
3831 (*current_liboctave_error_handler) |
|
3832 ("calculation of condition number not implemented"); |
5164
|
3833 else |
|
3834 { |
|
3835 // Print spparms("spumoni") info if requested |
|
3836 int typ = mattype.type (); |
|
3837 mattype.info (); |
|
3838 |
|
3839 // Note can't treat symmetric case as there is no dpttrf function |
5785
|
3840 if (typ == MatrixType::Tridiagonal || |
|
3841 typ == MatrixType::Tridiagonal_Hermitian) |
5164
|
3842 { |
|
3843 OCTAVE_LOCAL_BUFFER (Complex, DU2, nr - 2); |
|
3844 OCTAVE_LOCAL_BUFFER (Complex, DU, nr - 1); |
|
3845 OCTAVE_LOCAL_BUFFER (Complex, D, nr); |
|
3846 OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1); |
5275
|
3847 Array<octave_idx_type> ipvt (nr); |
|
3848 octave_idx_type *pipvt = ipvt.fortran_vec (); |
5164
|
3849 |
|
3850 if (mattype.is_dense ()) |
|
3851 { |
5275
|
3852 octave_idx_type ii = 0; |
|
3853 |
|
3854 for (octave_idx_type j = 0; j < nc-1; j++) |
5164
|
3855 { |
|
3856 D[j] = data(ii++); |
|
3857 DL[j] = data(ii++); |
|
3858 DU[j] = data(ii++); |
|
3859 } |
|
3860 D[nc-1] = data(ii); |
|
3861 } |
|
3862 else |
|
3863 { |
|
3864 D[0] = 0.; |
5275
|
3865 for (octave_idx_type i = 0; i < nr - 1; i++) |
5164
|
3866 { |
|
3867 D[i+1] = 0.; |
|
3868 DL[i] = 0.; |
|
3869 DU[i] = 0.; |
|
3870 } |
|
3871 |
5275
|
3872 for (octave_idx_type j = 0; j < nc; j++) |
|
3873 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
3874 { |
|
3875 if (ridx(i) == j) |
|
3876 D[j] = data(i); |
|
3877 else if (ridx(i) == j + 1) |
|
3878 DL[j] = data(i); |
|
3879 else if (ridx(i) == j - 1) |
5322
|
3880 DU[j-1] = data(i); |
5164
|
3881 } |
|
3882 } |
|
3883 |
|
3884 F77_XFCN (zgttrf, ZGTTRF, (nr, DL, D, DU, DU2, pipvt, err)); |
|
3885 |
|
3886 if (f77_exception_encountered) |
|
3887 (*current_liboctave_error_handler) |
|
3888 ("unrecoverable error in zgttrf"); |
|
3889 else |
|
3890 { |
|
3891 if (err != 0) |
|
3892 { |
|
3893 err = -2; |
5681
|
3894 rcond = 0.0; |
5164
|
3895 |
|
3896 if (sing_handler) |
5681
|
3897 { |
|
3898 sing_handler (rcond); |
|
3899 mattype.mark_as_rectangular (); |
|
3900 } |
5164
|
3901 else |
|
3902 (*current_liboctave_error_handler) |
|
3903 ("matrix singular to machine precision"); |
|
3904 |
|
3905 } |
|
3906 else |
|
3907 { |
|
3908 char job = 'N'; |
5681
|
3909 volatile octave_idx_type x_nz = b.nnz (); |
5275
|
3910 octave_idx_type b_nc = b.cols (); |
5164
|
3911 retval = SparseComplexMatrix (nr, b_nc, x_nz); |
|
3912 retval.xcidx(0) = 0; |
5275
|
3913 volatile octave_idx_type ii = 0; |
5681
|
3914 rcond = 1.0; |
5164
|
3915 |
|
3916 OCTAVE_LOCAL_BUFFER (Complex, work, nr); |
|
3917 |
5275
|
3918 for (volatile octave_idx_type j = 0; j < b_nc; j++) |
5164
|
3919 { |
5275
|
3920 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
3921 work[i] = 0.; |
5275
|
3922 for (octave_idx_type i = b.cidx(j); i < b.cidx(j+1); i++) |
5164
|
3923 work[b.ridx(i)] = b.data(i); |
|
3924 |
|
3925 F77_XFCN (zgttrs, ZGTTRS, |
|
3926 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
3927 nr, 1, DL, D, DU, DU2, pipvt, |
|
3928 work, b.rows (), err |
|
3929 F77_CHAR_ARG_LEN (1))); |
|
3930 |
|
3931 if (f77_exception_encountered) |
|
3932 { |
|
3933 (*current_liboctave_error_handler) |
|
3934 ("unrecoverable error in zgttrs"); |
|
3935 break; |
|
3936 } |
|
3937 |
|
3938 // Count non-zeros in work vector and adjust |
|
3939 // space in retval if needed |
5275
|
3940 octave_idx_type new_nnz = 0; |
|
3941 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
3942 if (work[i] != 0.) |
|
3943 new_nnz++; |
|
3944 |
|
3945 if (ii + new_nnz > x_nz) |
|
3946 { |
|
3947 // Resize the sparse matrix |
5275
|
3948 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
3949 retval.change_capacity (sz); |
|
3950 x_nz = sz; |
|
3951 } |
|
3952 |
5275
|
3953 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
3954 if (work[i] != 0.) |
|
3955 { |
|
3956 retval.xridx(ii) = i; |
|
3957 retval.xdata(ii++) = work[i]; |
|
3958 } |
|
3959 retval.xcidx(j+1) = ii; |
|
3960 } |
|
3961 |
|
3962 retval.maybe_compress (); |
|
3963 } |
|
3964 } |
|
3965 } |
5785
|
3966 else if (typ != MatrixType::Tridiagonal_Hermitian) |
5164
|
3967 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
3968 } |
|
3969 |
|
3970 return retval; |
|
3971 } |
|
3972 |
|
3973 ComplexMatrix |
5785
|
3974 SparseComplexMatrix::trisolve (MatrixType &mattype, const ComplexMatrix& b, |
5275
|
3975 octave_idx_type& err, double& rcond, |
5681
|
3976 solve_singularity_handler sing_handler, |
|
3977 bool calc_cond) const |
5164
|
3978 { |
|
3979 ComplexMatrix retval; |
|
3980 |
5275
|
3981 octave_idx_type nr = rows (); |
|
3982 octave_idx_type nc = cols (); |
5164
|
3983 err = 0; |
|
3984 |
|
3985 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
3986 (*current_liboctave_error_handler) |
|
3987 ("matrix dimension mismatch solution of linear equations"); |
5681
|
3988 else if (calc_cond) |
|
3989 (*current_liboctave_error_handler) |
|
3990 ("calculation of condition number not implemented"); |
5164
|
3991 else |
|
3992 { |
|
3993 // Print spparms("spumoni") info if requested |
|
3994 volatile int typ = mattype.type (); |
|
3995 mattype.info (); |
|
3996 |
5785
|
3997 if (typ == MatrixType::Tridiagonal_Hermitian) |
5164
|
3998 { |
5322
|
3999 OCTAVE_LOCAL_BUFFER (double, D, nr); |
5164
|
4000 OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1); |
|
4001 |
|
4002 if (mattype.is_dense ()) |
|
4003 { |
5275
|
4004 octave_idx_type ii = 0; |
|
4005 |
|
4006 for (octave_idx_type j = 0; j < nc-1; j++) |
5164
|
4007 { |
5322
|
4008 D[j] = std::real(data(ii++)); |
5164
|
4009 DL[j] = data(ii); |
|
4010 ii += 2; |
|
4011 } |
5322
|
4012 D[nc-1] = std::real(data(ii)); |
5164
|
4013 } |
|
4014 else |
|
4015 { |
|
4016 D[0] = 0.; |
5275
|
4017 for (octave_idx_type i = 0; i < nr - 1; i++) |
5164
|
4018 { |
|
4019 D[i+1] = 0.; |
|
4020 DL[i] = 0.; |
|
4021 } |
|
4022 |
5275
|
4023 for (octave_idx_type j = 0; j < nc; j++) |
|
4024 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4025 { |
|
4026 if (ridx(i) == j) |
5322
|
4027 D[j] = std::real (data(i)); |
5164
|
4028 else if (ridx(i) == j + 1) |
|
4029 DL[j] = data(i); |
|
4030 } |
|
4031 } |
|
4032 |
5275
|
4033 octave_idx_type b_nr = b.rows (); |
|
4034 octave_idx_type b_nc = b.cols(); |
5164
|
4035 rcond = 1.; |
|
4036 |
|
4037 retval = ComplexMatrix (b); |
|
4038 Complex *result = retval.fortran_vec (); |
|
4039 |
|
4040 F77_XFCN (zptsv, ZPTSV, (nr, b_nc, D, DL, result, |
|
4041 b_nr, err)); |
|
4042 |
|
4043 if (f77_exception_encountered) |
|
4044 { |
|
4045 (*current_liboctave_error_handler) |
|
4046 ("unrecoverable error in zptsv"); |
|
4047 err = -1; |
|
4048 } |
|
4049 else if (err != 0) |
|
4050 { |
|
4051 err = 0; |
|
4052 mattype.mark_as_unsymmetric (); |
5785
|
4053 typ = MatrixType::Tridiagonal; |
5164
|
4054 } |
|
4055 } |
|
4056 |
5785
|
4057 if (typ == MatrixType::Tridiagonal) |
5164
|
4058 { |
|
4059 OCTAVE_LOCAL_BUFFER (Complex, DU, nr - 1); |
|
4060 OCTAVE_LOCAL_BUFFER (Complex, D, nr); |
|
4061 OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1); |
|
4062 |
|
4063 if (mattype.is_dense ()) |
|
4064 { |
5275
|
4065 octave_idx_type ii = 0; |
|
4066 |
|
4067 for (octave_idx_type j = 0; j < nc-1; j++) |
5164
|
4068 { |
|
4069 D[j] = data(ii++); |
|
4070 DL[j] = data(ii++); |
|
4071 DU[j] = data(ii++); |
|
4072 } |
|
4073 D[nc-1] = data(ii); |
|
4074 } |
|
4075 else |
|
4076 { |
|
4077 D[0] = 0.; |
5275
|
4078 for (octave_idx_type i = 0; i < nr - 1; i++) |
5164
|
4079 { |
|
4080 D[i+1] = 0.; |
|
4081 DL[i] = 0.; |
|
4082 DU[i] = 0.; |
|
4083 } |
|
4084 |
5275
|
4085 for (octave_idx_type j = 0; j < nc; j++) |
|
4086 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4087 { |
|
4088 if (ridx(i) == j) |
|
4089 D[j] = data(i); |
|
4090 else if (ridx(i) == j + 1) |
|
4091 DL[j] = data(i); |
|
4092 else if (ridx(i) == j - 1) |
5322
|
4093 DU[j-1] = data(i); |
5164
|
4094 } |
|
4095 } |
|
4096 |
5275
|
4097 octave_idx_type b_nr = b.rows(); |
|
4098 octave_idx_type b_nc = b.cols(); |
5164
|
4099 rcond = 1.; |
|
4100 |
|
4101 retval = ComplexMatrix (b); |
|
4102 Complex *result = retval.fortran_vec (); |
|
4103 |
|
4104 F77_XFCN (zgtsv, ZGTSV, (nr, b_nc, DL, D, DU, result, |
|
4105 b_nr, err)); |
|
4106 |
|
4107 if (f77_exception_encountered) |
|
4108 { |
|
4109 (*current_liboctave_error_handler) |
|
4110 ("unrecoverable error in zgtsv"); |
|
4111 err = -1; |
|
4112 } |
|
4113 else if (err != 0) |
|
4114 { |
|
4115 rcond = 0.; |
|
4116 err = -2; |
|
4117 |
|
4118 if (sing_handler) |
5681
|
4119 { |
|
4120 sing_handler (rcond); |
|
4121 mattype.mark_as_rectangular (); |
|
4122 } |
5164
|
4123 else |
|
4124 (*current_liboctave_error_handler) |
|
4125 ("matrix singular to machine precision"); |
|
4126 } |
|
4127 } |
5785
|
4128 else if (typ != MatrixType::Tridiagonal_Hermitian) |
5164
|
4129 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
4130 } |
|
4131 |
|
4132 return retval; |
|
4133 } |
|
4134 |
|
4135 SparseComplexMatrix |
5785
|
4136 SparseComplexMatrix::trisolve (MatrixType &mattype, |
5681
|
4137 const SparseComplexMatrix& b, |
|
4138 octave_idx_type& err, double& rcond, |
|
4139 solve_singularity_handler sing_handler, |
|
4140 bool calc_cond) const |
5164
|
4141 { |
|
4142 SparseComplexMatrix retval; |
|
4143 |
5275
|
4144 octave_idx_type nr = rows (); |
|
4145 octave_idx_type nc = cols (); |
5164
|
4146 err = 0; |
|
4147 |
|
4148 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
4149 (*current_liboctave_error_handler) |
|
4150 ("matrix dimension mismatch solution of linear equations"); |
5681
|
4151 else if (calc_cond) |
|
4152 (*current_liboctave_error_handler) |
|
4153 ("calculation of condition number not implemented"); |
5164
|
4154 else |
|
4155 { |
|
4156 // Print spparms("spumoni") info if requested |
|
4157 int typ = mattype.type (); |
|
4158 mattype.info (); |
|
4159 |
|
4160 // Note can't treat symmetric case as there is no dpttrf function |
5785
|
4161 if (typ == MatrixType::Tridiagonal || |
|
4162 typ == MatrixType::Tridiagonal_Hermitian) |
5164
|
4163 { |
|
4164 OCTAVE_LOCAL_BUFFER (Complex, DU2, nr - 2); |
|
4165 OCTAVE_LOCAL_BUFFER (Complex, DU, nr - 1); |
|
4166 OCTAVE_LOCAL_BUFFER (Complex, D, nr); |
|
4167 OCTAVE_LOCAL_BUFFER (Complex, DL, nr - 1); |
5275
|
4168 Array<octave_idx_type> ipvt (nr); |
|
4169 octave_idx_type *pipvt = ipvt.fortran_vec (); |
5164
|
4170 |
|
4171 if (mattype.is_dense ()) |
|
4172 { |
5275
|
4173 octave_idx_type ii = 0; |
|
4174 |
|
4175 for (octave_idx_type j = 0; j < nc-1; j++) |
5164
|
4176 { |
|
4177 D[j] = data(ii++); |
|
4178 DL[j] = data(ii++); |
|
4179 DU[j] = data(ii++); |
|
4180 } |
|
4181 D[nc-1] = data(ii); |
|
4182 } |
|
4183 else |
|
4184 { |
|
4185 D[0] = 0.; |
5275
|
4186 for (octave_idx_type i = 0; i < nr - 1; i++) |
5164
|
4187 { |
|
4188 D[i+1] = 0.; |
|
4189 DL[i] = 0.; |
|
4190 DU[i] = 0.; |
|
4191 } |
|
4192 |
5275
|
4193 for (octave_idx_type j = 0; j < nc; j++) |
|
4194 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4195 { |
|
4196 if (ridx(i) == j) |
|
4197 D[j] = data(i); |
|
4198 else if (ridx(i) == j + 1) |
|
4199 DL[j] = data(i); |
|
4200 else if (ridx(i) == j - 1) |
5322
|
4201 DU[j-1] = data(i); |
5164
|
4202 } |
|
4203 } |
|
4204 |
|
4205 F77_XFCN (zgttrf, ZGTTRF, (nr, DL, D, DU, DU2, pipvt, err)); |
|
4206 |
|
4207 if (f77_exception_encountered) |
|
4208 (*current_liboctave_error_handler) |
|
4209 ("unrecoverable error in zgttrf"); |
|
4210 else |
|
4211 { |
|
4212 if (err != 0) |
|
4213 { |
5681
|
4214 rcond = 0.0; |
5164
|
4215 err = -2; |
|
4216 |
|
4217 if (sing_handler) |
5681
|
4218 { |
|
4219 sing_handler (rcond); |
|
4220 mattype.mark_as_rectangular (); |
|
4221 } |
5164
|
4222 else |
|
4223 (*current_liboctave_error_handler) |
|
4224 ("matrix singular to machine precision"); |
|
4225 } |
|
4226 else |
|
4227 { |
|
4228 rcond = 1.; |
|
4229 char job = 'N'; |
5275
|
4230 octave_idx_type b_nr = b.rows (); |
|
4231 octave_idx_type b_nc = b.cols (); |
5164
|
4232 OCTAVE_LOCAL_BUFFER (Complex, Bx, b_nr); |
|
4233 |
|
4234 // Take a first guess that the number of non-zero terms |
|
4235 // will be as many as in b |
5681
|
4236 volatile octave_idx_type x_nz = b.nnz (); |
5275
|
4237 volatile octave_idx_type ii = 0; |
5164
|
4238 retval = SparseComplexMatrix (b_nr, b_nc, x_nz); |
|
4239 |
|
4240 retval.xcidx(0) = 0; |
5275
|
4241 for (volatile octave_idx_type j = 0; j < b_nc; j++) |
5164
|
4242 { |
|
4243 |
5275
|
4244 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
4245 Bx[i] = b (i,j); |
|
4246 |
|
4247 F77_XFCN (zgttrs, ZGTTRS, |
|
4248 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4249 nr, 1, DL, D, DU, DU2, pipvt, |
|
4250 Bx, b_nr, err |
|
4251 F77_CHAR_ARG_LEN (1))); |
|
4252 |
|
4253 if (f77_exception_encountered) |
|
4254 { |
|
4255 (*current_liboctave_error_handler) |
|
4256 ("unrecoverable error in zgttrs"); |
|
4257 break; |
|
4258 } |
|
4259 |
|
4260 if (err != 0) |
|
4261 { |
|
4262 (*current_liboctave_error_handler) |
|
4263 ("SparseComplexMatrix::solve solve failed"); |
|
4264 |
|
4265 err = -1; |
|
4266 break; |
|
4267 } |
|
4268 |
|
4269 // Count non-zeros in work vector and adjust |
|
4270 // space in retval if needed |
5275
|
4271 octave_idx_type new_nnz = 0; |
|
4272 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
4273 if (Bx[i] != 0.) |
|
4274 new_nnz++; |
|
4275 |
|
4276 if (ii + new_nnz > x_nz) |
|
4277 { |
|
4278 // Resize the sparse matrix |
5275
|
4279 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
5164
|
4280 retval.change_capacity (sz); |
|
4281 x_nz = sz; |
|
4282 } |
|
4283 |
5275
|
4284 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
4285 if (Bx[i] != 0.) |
|
4286 { |
|
4287 retval.xridx(ii) = i; |
|
4288 retval.xdata(ii++) = Bx[i]; |
|
4289 } |
|
4290 |
|
4291 retval.xcidx(j+1) = ii; |
|
4292 } |
|
4293 |
|
4294 retval.maybe_compress (); |
|
4295 } |
|
4296 } |
|
4297 } |
5785
|
4298 else if (typ != MatrixType::Tridiagonal_Hermitian) |
5164
|
4299 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
4300 } |
|
4301 |
|
4302 return retval; |
|
4303 } |
|
4304 |
|
4305 ComplexMatrix |
5785
|
4306 SparseComplexMatrix::bsolve (MatrixType &mattype, const Matrix& b, |
5681
|
4307 octave_idx_type& err, double& rcond, |
|
4308 solve_singularity_handler sing_handler, |
|
4309 bool calc_cond) const |
5164
|
4310 { |
|
4311 ComplexMatrix retval; |
|
4312 |
5275
|
4313 octave_idx_type nr = rows (); |
|
4314 octave_idx_type nc = cols (); |
5164
|
4315 err = 0; |
|
4316 |
|
4317 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
4318 (*current_liboctave_error_handler) |
|
4319 ("matrix dimension mismatch solution of linear equations"); |
|
4320 else |
|
4321 { |
|
4322 // Print spparms("spumoni") info if requested |
|
4323 volatile int typ = mattype.type (); |
|
4324 mattype.info (); |
|
4325 |
5785
|
4326 if (typ == MatrixType::Banded_Hermitian) |
5164
|
4327 { |
5275
|
4328 octave_idx_type n_lower = mattype.nlower (); |
|
4329 octave_idx_type ldm = n_lower + 1; |
5164
|
4330 ComplexMatrix m_band (ldm, nc); |
|
4331 Complex *tmp_data = m_band.fortran_vec (); |
|
4332 |
|
4333 if (! mattype.is_dense ()) |
|
4334 { |
5275
|
4335 octave_idx_type ii = 0; |
|
4336 |
|
4337 for (octave_idx_type j = 0; j < ldm; j++) |
|
4338 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
4339 tmp_data[ii++] = 0.; |
|
4340 } |
|
4341 |
5275
|
4342 for (octave_idx_type j = 0; j < nc; j++) |
|
4343 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4344 { |
5275
|
4345 octave_idx_type ri = ridx (i); |
5164
|
4346 if (ri >= j) |
|
4347 m_band(ri - j, j) = data(i); |
|
4348 } |
|
4349 |
|
4350 // Calculate the norm of the matrix, for later use. |
5681
|
4351 double anorm; |
|
4352 if (calc_cond) |
|
4353 anorm = m_band.abs().sum().row(0).max(); |
5164
|
4354 |
|
4355 char job = 'L'; |
|
4356 F77_XFCN (zpbtrf, ZPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4357 nr, n_lower, tmp_data, ldm, err |
|
4358 F77_CHAR_ARG_LEN (1))); |
|
4359 |
|
4360 if (f77_exception_encountered) |
|
4361 (*current_liboctave_error_handler) |
|
4362 ("unrecoverable error in zpbtrf"); |
|
4363 else |
|
4364 { |
|
4365 if (err != 0) |
|
4366 { |
5681
|
4367 rcond = 0.0; |
5164
|
4368 // Matrix is not positive definite!! Fall through to |
|
4369 // unsymmetric banded solver. |
|
4370 mattype.mark_as_unsymmetric (); |
5785
|
4371 typ = MatrixType::Banded; |
5164
|
4372 err = 0; |
|
4373 } |
|
4374 else |
|
4375 { |
5681
|
4376 if (calc_cond) |
|
4377 { |
|
4378 Array<Complex> z (2 * nr); |
|
4379 Complex *pz = z.fortran_vec (); |
|
4380 Array<double> iz (nr); |
|
4381 double *piz = iz.fortran_vec (); |
|
4382 |
|
4383 F77_XFCN (zpbcon, ZPBCON, |
|
4384 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4385 nr, n_lower, tmp_data, ldm, |
|
4386 anorm, rcond, pz, piz, err |
|
4387 F77_CHAR_ARG_LEN (1))); |
|
4388 |
|
4389 if (f77_exception_encountered) |
|
4390 (*current_liboctave_error_handler) |
|
4391 ("unrecoverable error in zpbcon"); |
|
4392 |
|
4393 if (err != 0) |
|
4394 err = -2; |
|
4395 |
|
4396 volatile double rcond_plus_one = rcond + 1.0; |
|
4397 |
|
4398 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
4399 { |
|
4400 err = -2; |
|
4401 |
|
4402 if (sing_handler) |
|
4403 { |
|
4404 sing_handler (rcond); |
|
4405 mattype.mark_as_rectangular (); |
|
4406 } |
|
4407 else |
|
4408 (*current_liboctave_error_handler) |
|
4409 ("matrix singular to machine precision, rcond = %g", |
|
4410 rcond); |
|
4411 } |
|
4412 } |
|
4413 else |
|
4414 rcond = 1.0; |
|
4415 |
|
4416 if (err == 0) |
|
4417 { |
|
4418 retval = ComplexMatrix (b); |
|
4419 Complex *result = retval.fortran_vec (); |
|
4420 |
|
4421 octave_idx_type b_nc = b.cols (); |
|
4422 |
|
4423 F77_XFCN (zpbtrs, ZPBTRS, |
|
4424 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4425 nr, n_lower, b_nc, tmp_data, |
|
4426 ldm, result, b.rows(), err |
|
4427 F77_CHAR_ARG_LEN (1))); |
5164
|
4428 |
5681
|
4429 if (f77_exception_encountered) |
|
4430 (*current_liboctave_error_handler) |
|
4431 ("unrecoverable error in zpbtrs"); |
|
4432 |
|
4433 if (err != 0) |
|
4434 { |
|
4435 (*current_liboctave_error_handler) |
|
4436 ("SparseMatrix::solve solve failed"); |
|
4437 err = -1; |
|
4438 } |
5164
|
4439 } |
|
4440 } |
|
4441 } |
|
4442 } |
|
4443 |
5785
|
4444 if (typ == MatrixType::Banded) |
5164
|
4445 { |
|
4446 // Create the storage for the banded form of the sparse matrix |
5275
|
4447 octave_idx_type n_upper = mattype.nupper (); |
|
4448 octave_idx_type n_lower = mattype.nlower (); |
|
4449 octave_idx_type ldm = n_upper + 2 * n_lower + 1; |
5164
|
4450 |
|
4451 ComplexMatrix m_band (ldm, nc); |
|
4452 Complex *tmp_data = m_band.fortran_vec (); |
|
4453 |
|
4454 if (! mattype.is_dense ()) |
|
4455 { |
5275
|
4456 octave_idx_type ii = 0; |
|
4457 |
|
4458 for (octave_idx_type j = 0; j < ldm; j++) |
|
4459 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
4460 tmp_data[ii++] = 0.; |
|
4461 } |
|
4462 |
5275
|
4463 for (octave_idx_type j = 0; j < nc; j++) |
|
4464 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4465 m_band(ridx(i) - j + n_lower + n_upper, j) = data(i); |
|
4466 |
5681
|
4467 // Calculate the norm of the matrix, for later use. |
|
4468 double anorm; |
|
4469 if (calc_cond) |
|
4470 { |
|
4471 for (octave_idx_type j = 0; j < nr; j++) |
|
4472 { |
|
4473 double atmp = 0.; |
|
4474 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
4475 atmp += std::abs(data(i)); |
|
4476 if (atmp > anorm) |
|
4477 anorm = atmp; |
|
4478 } |
|
4479 } |
|
4480 |
5275
|
4481 Array<octave_idx_type> ipvt (nr); |
|
4482 octave_idx_type *pipvt = ipvt.fortran_vec (); |
5164
|
4483 |
5630
|
4484 F77_XFCN (zgbtrf, ZGBTRF, (nr, nc, n_lower, n_upper, tmp_data, |
5164
|
4485 ldm, pipvt, err)); |
|
4486 |
|
4487 if (f77_exception_encountered) |
|
4488 (*current_liboctave_error_handler) |
|
4489 ("unrecoverable error in zgbtrf"); |
|
4490 else |
|
4491 { |
|
4492 // Throw-away extra info LAPACK gives so as to not |
|
4493 // change output. |
|
4494 if (err != 0) |
|
4495 { |
5681
|
4496 rcond = 0.0; |
5164
|
4497 err = -2; |
|
4498 |
|
4499 if (sing_handler) |
5681
|
4500 { |
|
4501 sing_handler (rcond); |
|
4502 mattype.mark_as_rectangular (); |
|
4503 } |
5164
|
4504 else |
|
4505 (*current_liboctave_error_handler) |
|
4506 ("matrix singular to machine precision"); |
|
4507 } |
|
4508 else |
|
4509 { |
5681
|
4510 if (calc_cond) |
|
4511 { |
|
4512 char job = '1'; |
|
4513 Array<Complex> z (2 * nr); |
|
4514 Complex *pz = z.fortran_vec (); |
|
4515 Array<double> iz (nr); |
|
4516 double *piz = iz.fortran_vec (); |
|
4517 |
|
4518 F77_XFCN (zgbcon, ZGBCON, |
|
4519 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4520 nc, n_lower, n_upper, tmp_data, ldm, pipvt, |
|
4521 anorm, rcond, pz, piz, err |
|
4522 F77_CHAR_ARG_LEN (1))); |
|
4523 |
|
4524 if (f77_exception_encountered) |
|
4525 (*current_liboctave_error_handler) |
|
4526 ("unrecoverable error in zgbcon"); |
|
4527 |
|
4528 if (err != 0) |
|
4529 err = -2; |
|
4530 |
|
4531 volatile double rcond_plus_one = rcond + 1.0; |
|
4532 |
|
4533 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
4534 { |
|
4535 err = -2; |
|
4536 |
|
4537 if (sing_handler) |
|
4538 { |
|
4539 sing_handler (rcond); |
|
4540 mattype.mark_as_rectangular (); |
|
4541 } |
|
4542 else |
|
4543 (*current_liboctave_error_handler) |
|
4544 ("matrix singular to machine precision, rcond = %g", |
|
4545 rcond); |
|
4546 } |
|
4547 } |
|
4548 else |
|
4549 rcond = 1.; |
|
4550 |
|
4551 if (err == 0) |
|
4552 { |
|
4553 retval = ComplexMatrix (b); |
|
4554 Complex *result = retval.fortran_vec (); |
|
4555 |
|
4556 octave_idx_type b_nc = b.cols (); |
|
4557 |
|
4558 char job = 'N'; |
|
4559 F77_XFCN (zgbtrs, ZGBTRS, |
|
4560 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4561 nr, n_lower, n_upper, b_nc, tmp_data, |
|
4562 ldm, pipvt, result, b.rows(), err |
|
4563 F77_CHAR_ARG_LEN (1))); |
5164
|
4564 |
5681
|
4565 if (f77_exception_encountered) |
|
4566 (*current_liboctave_error_handler) |
|
4567 ("unrecoverable error in zgbtrs"); |
|
4568 } |
5164
|
4569 } |
|
4570 } |
|
4571 } |
5785
|
4572 else if (typ != MatrixType::Banded_Hermitian) |
5164
|
4573 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
4574 } |
|
4575 |
|
4576 return retval; |
|
4577 } |
|
4578 |
|
4579 SparseComplexMatrix |
5785
|
4580 SparseComplexMatrix::bsolve (MatrixType &mattype, const SparseMatrix& b, |
5275
|
4581 octave_idx_type& err, double& rcond, |
5681
|
4582 solve_singularity_handler sing_handler, |
|
4583 bool calc_cond) const |
5164
|
4584 { |
|
4585 SparseComplexMatrix retval; |
|
4586 |
5275
|
4587 octave_idx_type nr = rows (); |
|
4588 octave_idx_type nc = cols (); |
5164
|
4589 err = 0; |
|
4590 |
|
4591 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
4592 (*current_liboctave_error_handler) |
|
4593 ("matrix dimension mismatch solution of linear equations"); |
|
4594 else |
|
4595 { |
|
4596 // Print spparms("spumoni") info if requested |
|
4597 volatile int typ = mattype.type (); |
|
4598 mattype.info (); |
|
4599 |
5785
|
4600 if (typ == MatrixType::Banded_Hermitian) |
5164
|
4601 { |
5275
|
4602 octave_idx_type n_lower = mattype.nlower (); |
|
4603 octave_idx_type ldm = n_lower + 1; |
5164
|
4604 |
|
4605 ComplexMatrix m_band (ldm, nc); |
|
4606 Complex *tmp_data = m_band.fortran_vec (); |
|
4607 |
|
4608 if (! mattype.is_dense ()) |
|
4609 { |
5275
|
4610 octave_idx_type ii = 0; |
|
4611 |
|
4612 for (octave_idx_type j = 0; j < ldm; j++) |
|
4613 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
4614 tmp_data[ii++] = 0.; |
|
4615 } |
|
4616 |
5275
|
4617 for (octave_idx_type j = 0; j < nc; j++) |
|
4618 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4619 { |
5275
|
4620 octave_idx_type ri = ridx (i); |
5164
|
4621 if (ri >= j) |
|
4622 m_band(ri - j, j) = data(i); |
|
4623 } |
|
4624 |
5681
|
4625 // Calculate the norm of the matrix, for later use. |
|
4626 double anorm; |
|
4627 if (calc_cond) |
|
4628 anorm = m_band.abs().sum().row(0).max(); |
|
4629 |
5164
|
4630 char job = 'L'; |
|
4631 F77_XFCN (zpbtrf, ZPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4632 nr, n_lower, tmp_data, ldm, err |
|
4633 F77_CHAR_ARG_LEN (1))); |
|
4634 |
|
4635 if (f77_exception_encountered) |
|
4636 (*current_liboctave_error_handler) |
|
4637 ("unrecoverable error in zpbtrf"); |
|
4638 else |
|
4639 { |
|
4640 if (err != 0) |
|
4641 { |
5681
|
4642 rcond = 0.0; |
5164
|
4643 mattype.mark_as_unsymmetric (); |
5785
|
4644 typ = MatrixType::Banded; |
5164
|
4645 err = 0; |
|
4646 } |
|
4647 else |
|
4648 { |
5681
|
4649 if (calc_cond) |
|
4650 { |
|
4651 Array<Complex> z (2 * nr); |
|
4652 Complex *pz = z.fortran_vec (); |
|
4653 Array<double> iz (nr); |
|
4654 double *piz = iz.fortran_vec (); |
|
4655 |
|
4656 F77_XFCN (zpbcon, ZPBCON, |
|
4657 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4658 nr, n_lower, tmp_data, ldm, |
|
4659 anorm, rcond, pz, piz, err |
|
4660 F77_CHAR_ARG_LEN (1))); |
|
4661 |
|
4662 if (f77_exception_encountered) |
|
4663 (*current_liboctave_error_handler) |
|
4664 ("unrecoverable error in zpbcon"); |
|
4665 |
|
4666 if (err != 0) |
|
4667 err = -2; |
|
4668 |
|
4669 volatile double rcond_plus_one = rcond + 1.0; |
|
4670 |
|
4671 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
4672 { |
|
4673 err = -2; |
|
4674 |
|
4675 if (sing_handler) |
|
4676 { |
|
4677 sing_handler (rcond); |
|
4678 mattype.mark_as_rectangular (); |
|
4679 } |
|
4680 else |
|
4681 (*current_liboctave_error_handler) |
|
4682 ("matrix singular to machine precision, rcond = %g", |
|
4683 rcond); |
|
4684 } |
|
4685 } |
|
4686 else |
|
4687 rcond = 1.0; |
|
4688 |
|
4689 if (err == 0) |
5164
|
4690 { |
5681
|
4691 octave_idx_type b_nr = b.rows (); |
|
4692 octave_idx_type b_nc = b.cols (); |
|
4693 OCTAVE_LOCAL_BUFFER (Complex, Bx, b_nr); |
|
4694 |
|
4695 // Take a first guess that the number of non-zero terms |
|
4696 // will be as many as in b |
|
4697 volatile octave_idx_type x_nz = b.nnz (); |
|
4698 volatile octave_idx_type ii = 0; |
|
4699 retval = SparseComplexMatrix (b_nr, b_nc, x_nz); |
|
4700 |
|
4701 retval.xcidx(0) = 0; |
|
4702 for (volatile octave_idx_type j = 0; j < b_nc; j++) |
|
4703 { |
|
4704 for (octave_idx_type i = 0; i < b_nr; i++) |
|
4705 Bx[i] = b.elem (i, j); |
|
4706 |
|
4707 F77_XFCN (zpbtrs, ZPBTRS, |
|
4708 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4709 nr, n_lower, 1, tmp_data, |
|
4710 ldm, Bx, b_nr, err |
|
4711 F77_CHAR_ARG_LEN (1))); |
5164
|
4712 |
5681
|
4713 if (f77_exception_encountered) |
|
4714 { |
|
4715 (*current_liboctave_error_handler) |
|
4716 ("unrecoverable error in dpbtrs"); |
|
4717 err = -1; |
|
4718 break; |
|
4719 } |
|
4720 |
|
4721 if (err != 0) |
|
4722 { |
|
4723 (*current_liboctave_error_handler) |
|
4724 ("SparseComplexMatrix::solve solve failed"); |
|
4725 err = -1; |
|
4726 break; |
|
4727 } |
|
4728 |
|
4729 for (octave_idx_type i = 0; i < b_nr; i++) |
|
4730 { |
|
4731 Complex tmp = Bx[i]; |
|
4732 if (tmp != 0.0) |
|
4733 { |
|
4734 if (ii == x_nz) |
|
4735 { |
|
4736 // Resize the sparse matrix |
|
4737 octave_idx_type sz = x_nz * |
|
4738 (b_nc - j) / b_nc; |
|
4739 sz = (sz > 10 ? sz : 10) + x_nz; |
|
4740 retval.change_capacity (sz); |
|
4741 x_nz = sz; |
|
4742 } |
|
4743 retval.xdata(ii) = tmp; |
|
4744 retval.xridx(ii++) = i; |
|
4745 } |
|
4746 } |
|
4747 retval.xcidx(j+1) = ii; |
5164
|
4748 } |
|
4749 |
5681
|
4750 retval.maybe_compress (); |
5164
|
4751 } |
|
4752 } |
|
4753 } |
|
4754 } |
|
4755 |
5785
|
4756 if (typ == MatrixType::Banded) |
5164
|
4757 { |
|
4758 // Create the storage for the banded form of the sparse matrix |
5275
|
4759 octave_idx_type n_upper = mattype.nupper (); |
|
4760 octave_idx_type n_lower = mattype.nlower (); |
|
4761 octave_idx_type ldm = n_upper + 2 * n_lower + 1; |
5164
|
4762 |
|
4763 ComplexMatrix m_band (ldm, nc); |
|
4764 Complex *tmp_data = m_band.fortran_vec (); |
|
4765 |
|
4766 if (! mattype.is_dense ()) |
|
4767 { |
5275
|
4768 octave_idx_type ii = 0; |
|
4769 |
|
4770 for (octave_idx_type j = 0; j < ldm; j++) |
|
4771 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
4772 tmp_data[ii++] = 0.; |
|
4773 } |
|
4774 |
5275
|
4775 for (octave_idx_type j = 0; j < nc; j++) |
|
4776 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4777 m_band(ridx(i) - j + n_lower + n_upper, j) = data(i); |
|
4778 |
5681
|
4779 // Calculate the norm of the matrix, for later use. |
|
4780 double anorm; |
|
4781 if (calc_cond) |
|
4782 { |
|
4783 for (octave_idx_type j = 0; j < nr; j++) |
|
4784 { |
|
4785 double atmp = 0.; |
|
4786 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
4787 atmp += std::abs(data(i)); |
|
4788 if (atmp > anorm) |
|
4789 anorm = atmp; |
|
4790 } |
|
4791 } |
|
4792 |
5275
|
4793 Array<octave_idx_type> ipvt (nr); |
|
4794 octave_idx_type *pipvt = ipvt.fortran_vec (); |
5164
|
4795 |
|
4796 F77_XFCN (zgbtrf, ZGBTRF, (nr, nr, n_lower, n_upper, tmp_data, |
|
4797 ldm, pipvt, err)); |
|
4798 |
|
4799 if (f77_exception_encountered) |
|
4800 (*current_liboctave_error_handler) |
|
4801 ("unrecoverable error in zgbtrf"); |
|
4802 else |
|
4803 { |
|
4804 if (err != 0) |
|
4805 { |
5681
|
4806 rcond = 0.0; |
5164
|
4807 err = -2; |
|
4808 |
|
4809 if (sing_handler) |
5681
|
4810 { |
5164
|
4811 sing_handler (rcond); |
5681
|
4812 mattype.mark_as_rectangular (); |
|
4813 } |
5164
|
4814 else |
|
4815 (*current_liboctave_error_handler) |
|
4816 ("matrix singular to machine precision"); |
|
4817 |
|
4818 } |
|
4819 else |
|
4820 { |
5681
|
4821 if (calc_cond) |
5164
|
4822 { |
5681
|
4823 char job = '1'; |
|
4824 Array<Complex> z (2 * nr); |
|
4825 Complex *pz = z.fortran_vec (); |
|
4826 Array<double> iz (nr); |
|
4827 double *piz = iz.fortran_vec (); |
|
4828 |
|
4829 F77_XFCN (zgbcon, ZGBCON, |
|
4830 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4831 nc, n_lower, n_upper, tmp_data, ldm, pipvt, |
|
4832 anorm, rcond, pz, piz, err |
|
4833 F77_CHAR_ARG_LEN (1))); |
|
4834 |
5164
|
4835 if (f77_exception_encountered) |
5681
|
4836 (*current_liboctave_error_handler) |
|
4837 ("unrecoverable error in zgbcon"); |
|
4838 |
|
4839 if (err != 0) |
|
4840 err = -2; |
|
4841 |
|
4842 volatile double rcond_plus_one = rcond + 1.0; |
|
4843 |
|
4844 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
4845 { |
|
4846 err = -2; |
|
4847 |
|
4848 if (sing_handler) |
|
4849 { |
|
4850 sing_handler (rcond); |
|
4851 mattype.mark_as_rectangular (); |
|
4852 } |
|
4853 else |
|
4854 (*current_liboctave_error_handler) |
|
4855 ("matrix singular to machine precision, rcond = %g", |
|
4856 rcond); |
|
4857 } |
|
4858 } |
|
4859 else |
|
4860 rcond = 1.; |
|
4861 |
|
4862 if (err == 0) |
|
4863 { |
|
4864 char job = 'N'; |
|
4865 volatile octave_idx_type x_nz = b.nnz (); |
|
4866 octave_idx_type b_nc = b.cols (); |
|
4867 retval = SparseComplexMatrix (nr, b_nc, x_nz); |
|
4868 retval.xcidx(0) = 0; |
|
4869 volatile octave_idx_type ii = 0; |
|
4870 |
|
4871 OCTAVE_LOCAL_BUFFER (Complex, work, nr); |
|
4872 |
|
4873 for (volatile octave_idx_type j = 0; j < b_nc; j++) |
5164
|
4874 { |
5681
|
4875 for (octave_idx_type i = 0; i < nr; i++) |
|
4876 work[i] = 0.; |
|
4877 for (octave_idx_type i = b.cidx(j); |
|
4878 i < b.cidx(j+1); i++) |
|
4879 work[b.ridx(i)] = b.data(i); |
|
4880 |
|
4881 F77_XFCN (zgbtrs, ZGBTRS, |
|
4882 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4883 nr, n_lower, n_upper, 1, tmp_data, |
|
4884 ldm, pipvt, work, b.rows (), err |
|
4885 F77_CHAR_ARG_LEN (1))); |
|
4886 |
|
4887 if (f77_exception_encountered) |
|
4888 { |
|
4889 (*current_liboctave_error_handler) |
|
4890 ("unrecoverable error in zgbtrs"); |
|
4891 break; |
|
4892 } |
|
4893 |
|
4894 // Count non-zeros in work vector and adjust |
|
4895 // space in retval if needed |
|
4896 octave_idx_type new_nnz = 0; |
|
4897 for (octave_idx_type i = 0; i < nr; i++) |
|
4898 if (work[i] != 0.) |
|
4899 new_nnz++; |
|
4900 |
|
4901 if (ii + new_nnz > x_nz) |
|
4902 { |
|
4903 // Resize the sparse matrix |
|
4904 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
|
4905 retval.change_capacity (sz); |
|
4906 x_nz = sz; |
|
4907 } |
|
4908 |
|
4909 for (octave_idx_type i = 0; i < nr; i++) |
|
4910 if (work[i] != 0.) |
|
4911 { |
|
4912 retval.xridx(ii) = i; |
|
4913 retval.xdata(ii++) = work[i]; |
|
4914 } |
|
4915 retval.xcidx(j+1) = ii; |
5164
|
4916 } |
|
4917 |
5681
|
4918 retval.maybe_compress (); |
5164
|
4919 } |
|
4920 } |
|
4921 } |
|
4922 } |
5785
|
4923 else if (typ != MatrixType::Banded_Hermitian) |
5164
|
4924 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
4925 } |
|
4926 |
|
4927 return retval; |
|
4928 } |
|
4929 |
|
4930 ComplexMatrix |
5785
|
4931 SparseComplexMatrix::bsolve (MatrixType &mattype, const ComplexMatrix& b, |
5275
|
4932 octave_idx_type& err, double& rcond, |
5681
|
4933 solve_singularity_handler sing_handler, |
|
4934 bool calc_cond) const |
5164
|
4935 { |
|
4936 ComplexMatrix retval; |
|
4937 |
5275
|
4938 octave_idx_type nr = rows (); |
|
4939 octave_idx_type nc = cols (); |
5164
|
4940 err = 0; |
|
4941 |
|
4942 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
4943 (*current_liboctave_error_handler) |
|
4944 ("matrix dimension mismatch solution of linear equations"); |
|
4945 else |
|
4946 { |
|
4947 // Print spparms("spumoni") info if requested |
|
4948 volatile int typ = mattype.type (); |
|
4949 mattype.info (); |
|
4950 |
5785
|
4951 if (typ == MatrixType::Banded_Hermitian) |
5164
|
4952 { |
5275
|
4953 octave_idx_type n_lower = mattype.nlower (); |
|
4954 octave_idx_type ldm = n_lower + 1; |
5164
|
4955 |
|
4956 ComplexMatrix m_band (ldm, nc); |
|
4957 Complex *tmp_data = m_band.fortran_vec (); |
|
4958 |
|
4959 if (! mattype.is_dense ()) |
|
4960 { |
5275
|
4961 octave_idx_type ii = 0; |
|
4962 |
|
4963 for (octave_idx_type j = 0; j < ldm; j++) |
|
4964 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
4965 tmp_data[ii++] = 0.; |
|
4966 } |
|
4967 |
5275
|
4968 for (octave_idx_type j = 0; j < nc; j++) |
|
4969 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
4970 { |
5275
|
4971 octave_idx_type ri = ridx (i); |
5164
|
4972 if (ri >= j) |
|
4973 m_band(ri - j, j) = data(i); |
|
4974 } |
|
4975 |
5681
|
4976 // Calculate the norm of the matrix, for later use. |
|
4977 double anorm; |
|
4978 if (calc_cond) |
|
4979 anorm = m_band.abs().sum().row(0).max(); |
|
4980 |
5164
|
4981 char job = 'L'; |
|
4982 F77_XFCN (zpbtrf, ZPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1), |
|
4983 nr, n_lower, tmp_data, ldm, err |
|
4984 F77_CHAR_ARG_LEN (1))); |
|
4985 |
|
4986 if (f77_exception_encountered) |
|
4987 (*current_liboctave_error_handler) |
|
4988 ("unrecoverable error in zpbtrf"); |
|
4989 else |
|
4990 { |
|
4991 if (err != 0) |
|
4992 { |
|
4993 // Matrix is not positive definite!! Fall through to |
|
4994 // unsymmetric banded solver. |
5681
|
4995 rcond = 0.0; |
5164
|
4996 mattype.mark_as_unsymmetric (); |
5785
|
4997 typ = MatrixType::Banded; |
5164
|
4998 err = 0; |
|
4999 } |
|
5000 else |
|
5001 { |
5681
|
5002 if (calc_cond) |
|
5003 { |
|
5004 Array<Complex> z (2 * nr); |
|
5005 Complex *pz = z.fortran_vec (); |
|
5006 Array<double> iz (nr); |
|
5007 double *piz = iz.fortran_vec (); |
|
5008 |
|
5009 F77_XFCN (zpbcon, ZPBCON, |
|
5010 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5011 nr, n_lower, tmp_data, ldm, |
|
5012 anorm, rcond, pz, piz, err |
|
5013 F77_CHAR_ARG_LEN (1))); |
|
5014 |
|
5015 if (f77_exception_encountered) |
|
5016 (*current_liboctave_error_handler) |
|
5017 ("unrecoverable error in zpbcon"); |
|
5018 |
|
5019 if (err != 0) |
|
5020 err = -2; |
|
5021 |
|
5022 volatile double rcond_plus_one = rcond + 1.0; |
|
5023 |
|
5024 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
5025 { |
|
5026 err = -2; |
|
5027 |
|
5028 if (sing_handler) |
|
5029 { |
|
5030 sing_handler (rcond); |
|
5031 mattype.mark_as_rectangular (); |
|
5032 } |
|
5033 else |
|
5034 (*current_liboctave_error_handler) |
|
5035 ("matrix singular to machine precision, rcond = %g", |
|
5036 rcond); |
|
5037 } |
|
5038 } |
|
5039 else |
|
5040 rcond = 1.0; |
|
5041 |
|
5042 if (err == 0) |
|
5043 { |
|
5044 octave_idx_type b_nr = b.rows (); |
|
5045 octave_idx_type b_nc = b.cols (); |
|
5046 retval = ComplexMatrix (b); |
|
5047 Complex *result = retval.fortran_vec (); |
|
5048 |
|
5049 F77_XFCN (zpbtrs, ZPBTRS, |
|
5050 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5051 nr, n_lower, b_nc, tmp_data, |
|
5052 ldm, result, b_nr, err |
|
5053 F77_CHAR_ARG_LEN (1))); |
5164
|
5054 |
5681
|
5055 if (f77_exception_encountered) |
|
5056 { |
|
5057 (*current_liboctave_error_handler) |
|
5058 ("unrecoverable error in zpbtrs"); |
|
5059 err = -1; |
|
5060 } |
|
5061 |
|
5062 if (err != 0) |
|
5063 { |
|
5064 (*current_liboctave_error_handler) |
|
5065 ("SparseComplexMatrix::solve solve failed"); |
|
5066 err = -1; |
|
5067 } |
5164
|
5068 } |
|
5069 } |
|
5070 } |
|
5071 } |
|
5072 |
5785
|
5073 if (typ == MatrixType::Banded) |
5164
|
5074 { |
|
5075 // Create the storage for the banded form of the sparse matrix |
5275
|
5076 octave_idx_type n_upper = mattype.nupper (); |
|
5077 octave_idx_type n_lower = mattype.nlower (); |
|
5078 octave_idx_type ldm = n_upper + 2 * n_lower + 1; |
5164
|
5079 |
|
5080 ComplexMatrix m_band (ldm, nc); |
|
5081 Complex *tmp_data = m_band.fortran_vec (); |
|
5082 |
|
5083 if (! mattype.is_dense ()) |
|
5084 { |
5275
|
5085 octave_idx_type ii = 0; |
|
5086 |
|
5087 for (octave_idx_type j = 0; j < ldm; j++) |
|
5088 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
5089 tmp_data[ii++] = 0.; |
|
5090 } |
|
5091 |
5275
|
5092 for (octave_idx_type j = 0; j < nc; j++) |
|
5093 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
5094 m_band(ridx(i) - j + n_lower + n_upper, j) = data(i); |
|
5095 |
5681
|
5096 // Calculate the norm of the matrix, for later use. |
|
5097 double anorm; |
|
5098 if (calc_cond) |
|
5099 { |
|
5100 for (octave_idx_type j = 0; j < nr; j++) |
|
5101 { |
|
5102 double atmp = 0.; |
|
5103 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
5104 atmp += std::abs(data(i)); |
|
5105 if (atmp > anorm) |
|
5106 anorm = atmp; |
|
5107 } |
|
5108 } |
|
5109 |
5275
|
5110 Array<octave_idx_type> ipvt (nr); |
|
5111 octave_idx_type *pipvt = ipvt.fortran_vec (); |
5164
|
5112 |
|
5113 F77_XFCN (zgbtrf, ZGBTRF, (nr, nr, n_lower, n_upper, tmp_data, |
|
5114 ldm, pipvt, err)); |
|
5115 |
|
5116 if (f77_exception_encountered) |
|
5117 (*current_liboctave_error_handler) |
|
5118 ("unrecoverable error in zgbtrf"); |
|
5119 else |
|
5120 { |
|
5121 if (err != 0) |
|
5122 { |
|
5123 err = -2; |
5681
|
5124 rcond = 0.0; |
5164
|
5125 |
|
5126 if (sing_handler) |
5681
|
5127 { |
|
5128 sing_handler (rcond); |
|
5129 mattype.mark_as_rectangular (); |
|
5130 } |
5164
|
5131 else |
|
5132 (*current_liboctave_error_handler) |
|
5133 ("matrix singular to machine precision"); |
|
5134 } |
|
5135 else |
|
5136 { |
5681
|
5137 if (calc_cond) |
|
5138 { |
|
5139 char job = '1'; |
|
5140 Array<Complex> z (2 * nr); |
|
5141 Complex *pz = z.fortran_vec (); |
|
5142 Array<double> iz (nr); |
|
5143 double *piz = iz.fortran_vec (); |
|
5144 |
|
5145 F77_XFCN (zgbcon, ZGBCON, |
|
5146 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5147 nc, n_lower, n_upper, tmp_data, ldm, pipvt, |
|
5148 anorm, rcond, pz, piz, err |
|
5149 F77_CHAR_ARG_LEN (1))); |
|
5150 |
|
5151 if (f77_exception_encountered) |
|
5152 (*current_liboctave_error_handler) |
|
5153 ("unrecoverable error in zgbcon"); |
|
5154 |
|
5155 if (err != 0) |
|
5156 err = -2; |
|
5157 |
|
5158 volatile double rcond_plus_one = rcond + 1.0; |
|
5159 |
|
5160 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
5161 { |
|
5162 err = -2; |
|
5163 |
|
5164 if (sing_handler) |
|
5165 { |
|
5166 sing_handler (rcond); |
|
5167 mattype.mark_as_rectangular (); |
|
5168 } |
|
5169 else |
|
5170 (*current_liboctave_error_handler) |
|
5171 ("matrix singular to machine precision, rcond = %g", |
|
5172 rcond); |
|
5173 } |
|
5174 } |
|
5175 else |
|
5176 rcond = 1.; |
|
5177 |
|
5178 if (err == 0) |
|
5179 { |
|
5180 char job = 'N'; |
|
5181 octave_idx_type b_nc = b.cols (); |
|
5182 retval = ComplexMatrix (b); |
|
5183 Complex *result = retval.fortran_vec (); |
|
5184 |
|
5185 F77_XFCN (zgbtrs, ZGBTRS, |
|
5186 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5187 nr, n_lower, n_upper, b_nc, tmp_data, |
|
5188 ldm, pipvt, result, b.rows (), err |
|
5189 F77_CHAR_ARG_LEN (1))); |
5164
|
5190 |
5681
|
5191 if (f77_exception_encountered) |
|
5192 { |
|
5193 (*current_liboctave_error_handler) |
|
5194 ("unrecoverable error in dgbtrs"); |
|
5195 } |
5164
|
5196 } |
|
5197 } |
|
5198 } |
|
5199 } |
5785
|
5200 else if (typ != MatrixType::Banded_Hermitian) |
5164
|
5201 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
5202 } |
|
5203 |
|
5204 return retval; |
|
5205 } |
|
5206 |
|
5207 SparseComplexMatrix |
5785
|
5208 SparseComplexMatrix::bsolve (MatrixType &mattype, const SparseComplexMatrix& b, |
5681
|
5209 octave_idx_type& err, double& rcond, |
|
5210 solve_singularity_handler sing_handler, |
|
5211 bool calc_cond) const |
5164
|
5212 { |
|
5213 SparseComplexMatrix retval; |
|
5214 |
5275
|
5215 octave_idx_type nr = rows (); |
|
5216 octave_idx_type nc = cols (); |
5164
|
5217 err = 0; |
|
5218 |
|
5219 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
5220 (*current_liboctave_error_handler) |
|
5221 ("matrix dimension mismatch solution of linear equations"); |
|
5222 else |
|
5223 { |
|
5224 // Print spparms("spumoni") info if requested |
|
5225 volatile int typ = mattype.type (); |
|
5226 mattype.info (); |
|
5227 |
5785
|
5228 if (typ == MatrixType::Banded_Hermitian) |
5164
|
5229 { |
5275
|
5230 octave_idx_type n_lower = mattype.nlower (); |
|
5231 octave_idx_type ldm = n_lower + 1; |
5164
|
5232 |
|
5233 ComplexMatrix m_band (ldm, nc); |
|
5234 Complex *tmp_data = m_band.fortran_vec (); |
|
5235 |
|
5236 if (! mattype.is_dense ()) |
|
5237 { |
5275
|
5238 octave_idx_type ii = 0; |
|
5239 |
|
5240 for (octave_idx_type j = 0; j < ldm; j++) |
|
5241 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
5242 tmp_data[ii++] = 0.; |
|
5243 } |
|
5244 |
5275
|
5245 for (octave_idx_type j = 0; j < nc; j++) |
|
5246 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
5247 { |
5275
|
5248 octave_idx_type ri = ridx (i); |
5164
|
5249 if (ri >= j) |
|
5250 m_band(ri - j, j) = data(i); |
|
5251 } |
|
5252 |
5681
|
5253 // Calculate the norm of the matrix, for later use. |
|
5254 double anorm; |
|
5255 if (calc_cond) |
|
5256 anorm = m_band.abs().sum().row(0).max(); |
|
5257 |
5164
|
5258 char job = 'L'; |
|
5259 F77_XFCN (zpbtrf, ZPBTRF, (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5260 nr, n_lower, tmp_data, ldm, err |
|
5261 F77_CHAR_ARG_LEN (1))); |
|
5262 |
|
5263 if (f77_exception_encountered) |
|
5264 (*current_liboctave_error_handler) |
|
5265 ("unrecoverable error in zpbtrf"); |
|
5266 else |
|
5267 { |
|
5268 if (err != 0) |
|
5269 { |
|
5270 // Matrix is not positive definite!! Fall through to |
|
5271 // unsymmetric banded solver. |
|
5272 mattype.mark_as_unsymmetric (); |
5785
|
5273 typ = MatrixType::Banded; |
5164
|
5274 |
5681
|
5275 rcond = 0.0; |
5164
|
5276 err = 0; |
|
5277 } |
|
5278 else |
|
5279 { |
5681
|
5280 if (calc_cond) |
5164
|
5281 { |
5681
|
5282 Array<Complex> z (2 * nr); |
|
5283 Complex *pz = z.fortran_vec (); |
|
5284 Array<double> iz (nr); |
|
5285 double *piz = iz.fortran_vec (); |
|
5286 |
|
5287 F77_XFCN (zpbcon, ZPBCON, |
|
5288 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5289 nr, n_lower, tmp_data, ldm, |
|
5290 anorm, rcond, pz, piz, err |
|
5291 F77_CHAR_ARG_LEN (1))); |
|
5292 |
5164
|
5293 if (f77_exception_encountered) |
5681
|
5294 (*current_liboctave_error_handler) |
|
5295 ("unrecoverable error in zpbcon"); |
|
5296 |
|
5297 if (err != 0) |
|
5298 err = -2; |
|
5299 |
|
5300 volatile double rcond_plus_one = rcond + 1.0; |
|
5301 |
|
5302 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
5303 { |
|
5304 err = -2; |
|
5305 |
|
5306 if (sing_handler) |
|
5307 { |
|
5308 sing_handler (rcond); |
|
5309 mattype.mark_as_rectangular (); |
|
5310 } |
|
5311 else |
|
5312 (*current_liboctave_error_handler) |
|
5313 ("matrix singular to machine precision, rcond = %g", |
|
5314 rcond); |
|
5315 } |
|
5316 } |
|
5317 else |
|
5318 rcond = 1.0; |
|
5319 |
|
5320 if (err == 0) |
|
5321 { |
|
5322 octave_idx_type b_nr = b.rows (); |
|
5323 octave_idx_type b_nc = b.cols (); |
|
5324 OCTAVE_LOCAL_BUFFER (Complex, Bx, b_nr); |
|
5325 |
|
5326 // Take a first guess that the number of non-zero terms |
|
5327 // will be as many as in b |
|
5328 volatile octave_idx_type x_nz = b.nnz (); |
|
5329 volatile octave_idx_type ii = 0; |
|
5330 retval = SparseComplexMatrix (b_nr, b_nc, x_nz); |
|
5331 |
|
5332 retval.xcidx(0) = 0; |
|
5333 for (volatile octave_idx_type j = 0; j < b_nc; j++) |
5164
|
5334 { |
5681
|
5335 |
|
5336 for (octave_idx_type i = 0; i < b_nr; i++) |
|
5337 Bx[i] = b (i,j); |
|
5338 |
|
5339 F77_XFCN (zpbtrs, ZPBTRS, |
|
5340 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5341 nr, n_lower, 1, tmp_data, |
|
5342 ldm, Bx, b_nr, err |
|
5343 F77_CHAR_ARG_LEN (1))); |
|
5344 |
|
5345 if (f77_exception_encountered) |
|
5346 { |
|
5347 (*current_liboctave_error_handler) |
|
5348 ("unrecoverable error in zpbtrs"); |
|
5349 err = -1; |
|
5350 break; |
|
5351 } |
|
5352 |
|
5353 if (err != 0) |
|
5354 { |
|
5355 (*current_liboctave_error_handler) |
|
5356 ("SparseMatrix::solve solve failed"); |
|
5357 err = -1; |
|
5358 break; |
|
5359 } |
|
5360 |
|
5361 // Count non-zeros in work vector and adjust |
|
5362 // space in retval if needed |
|
5363 octave_idx_type new_nnz = 0; |
|
5364 for (octave_idx_type i = 0; i < nr; i++) |
|
5365 if (Bx[i] != 0.) |
|
5366 new_nnz++; |
5164
|
5367 |
5681
|
5368 if (ii + new_nnz > x_nz) |
|
5369 { |
|
5370 // Resize the sparse matrix |
|
5371 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
|
5372 retval.change_capacity (sz); |
|
5373 x_nz = sz; |
|
5374 } |
5164
|
5375 |
5681
|
5376 for (octave_idx_type i = 0; i < nr; i++) |
|
5377 if (Bx[i] != 0.) |
|
5378 { |
|
5379 retval.xridx(ii) = i; |
|
5380 retval.xdata(ii++) = Bx[i]; |
|
5381 } |
|
5382 |
|
5383 retval.xcidx(j+1) = ii; |
|
5384 } |
|
5385 |
|
5386 retval.maybe_compress (); |
5164
|
5387 } |
|
5388 } |
|
5389 } |
|
5390 } |
|
5391 |
5785
|
5392 if (typ == MatrixType::Banded) |
5164
|
5393 { |
|
5394 // Create the storage for the banded form of the sparse matrix |
5275
|
5395 octave_idx_type n_upper = mattype.nupper (); |
|
5396 octave_idx_type n_lower = mattype.nlower (); |
|
5397 octave_idx_type ldm = n_upper + 2 * n_lower + 1; |
5164
|
5398 |
|
5399 ComplexMatrix m_band (ldm, nc); |
|
5400 Complex *tmp_data = m_band.fortran_vec (); |
|
5401 |
|
5402 if (! mattype.is_dense ()) |
|
5403 { |
5275
|
5404 octave_idx_type ii = 0; |
|
5405 |
|
5406 for (octave_idx_type j = 0; j < ldm; j++) |
|
5407 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
5408 tmp_data[ii++] = 0.; |
|
5409 } |
|
5410 |
5275
|
5411 for (octave_idx_type j = 0; j < nc; j++) |
|
5412 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
5413 m_band(ridx(i) - j + n_lower + n_upper, j) = data(i); |
|
5414 |
5681
|
5415 // Calculate the norm of the matrix, for later use. |
|
5416 double anorm; |
|
5417 if (calc_cond) |
|
5418 { |
|
5419 for (octave_idx_type j = 0; j < nr; j++) |
|
5420 { |
|
5421 double atmp = 0.; |
|
5422 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
|
5423 atmp += std::abs(data(i)); |
|
5424 if (atmp > anorm) |
|
5425 anorm = atmp; |
|
5426 } |
|
5427 } |
|
5428 |
5275
|
5429 Array<octave_idx_type> ipvt (nr); |
|
5430 octave_idx_type *pipvt = ipvt.fortran_vec (); |
5164
|
5431 |
|
5432 F77_XFCN (zgbtrf, ZGBTRF, (nr, nr, n_lower, n_upper, tmp_data, |
|
5433 ldm, pipvt, err)); |
|
5434 |
|
5435 if (f77_exception_encountered) |
|
5436 (*current_liboctave_error_handler) |
|
5437 ("unrecoverable error in xgbtrf"); |
|
5438 else |
|
5439 { |
|
5440 if (err != 0) |
|
5441 { |
|
5442 err = -2; |
5681
|
5443 rcond = 0.0; |
5164
|
5444 |
|
5445 if (sing_handler) |
5681
|
5446 { |
|
5447 sing_handler (rcond); |
|
5448 mattype.mark_as_rectangular (); |
|
5449 } |
5164
|
5450 else |
|
5451 (*current_liboctave_error_handler) |
|
5452 ("matrix singular to machine precision"); |
|
5453 |
|
5454 } |
|
5455 else |
|
5456 { |
5681
|
5457 if (calc_cond) |
5164
|
5458 { |
5681
|
5459 char job = '1'; |
|
5460 Array<Complex> z (2 * nr); |
|
5461 Complex *pz = z.fortran_vec (); |
|
5462 Array<double> iz (nr); |
|
5463 double *piz = iz.fortran_vec (); |
|
5464 |
|
5465 F77_XFCN (zgbcon, ZGBCON, |
|
5466 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5467 nc, n_lower, n_upper, tmp_data, ldm, pipvt, |
|
5468 anorm, rcond, pz, piz, err |
|
5469 F77_CHAR_ARG_LEN (1))); |
|
5470 |
5164
|
5471 if (f77_exception_encountered) |
5681
|
5472 (*current_liboctave_error_handler) |
|
5473 ("unrecoverable error in zgbcon"); |
|
5474 |
|
5475 if (err != 0) |
|
5476 err = -2; |
|
5477 |
|
5478 volatile double rcond_plus_one = rcond + 1.0; |
|
5479 |
|
5480 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
5481 { |
|
5482 err = -2; |
|
5483 |
|
5484 if (sing_handler) |
|
5485 { |
|
5486 sing_handler (rcond); |
|
5487 mattype.mark_as_rectangular (); |
|
5488 } |
|
5489 else |
|
5490 (*current_liboctave_error_handler) |
|
5491 ("matrix singular to machine precision, rcond = %g", |
|
5492 rcond); |
|
5493 } |
|
5494 } |
|
5495 else |
|
5496 rcond = 1.; |
|
5497 |
|
5498 if (err == 0) |
|
5499 { |
|
5500 char job = 'N'; |
|
5501 volatile octave_idx_type x_nz = b.nnz (); |
|
5502 octave_idx_type b_nc = b.cols (); |
|
5503 retval = SparseComplexMatrix (nr, b_nc, x_nz); |
|
5504 retval.xcidx(0) = 0; |
|
5505 volatile octave_idx_type ii = 0; |
|
5506 |
|
5507 OCTAVE_LOCAL_BUFFER (Complex, Bx, nr); |
|
5508 |
|
5509 for (volatile octave_idx_type j = 0; j < b_nc; j++) |
5164
|
5510 { |
5681
|
5511 for (octave_idx_type i = 0; i < nr; i++) |
|
5512 Bx[i] = 0.; |
|
5513 |
|
5514 for (octave_idx_type i = b.cidx(j); |
|
5515 i < b.cidx(j+1); i++) |
|
5516 Bx[b.ridx(i)] = b.data(i); |
|
5517 |
|
5518 F77_XFCN (zgbtrs, ZGBTRS, |
|
5519 (F77_CONST_CHAR_ARG2 (&job, 1), |
|
5520 nr, n_lower, n_upper, 1, tmp_data, |
|
5521 ldm, pipvt, Bx, b.rows (), err |
|
5522 F77_CHAR_ARG_LEN (1))); |
|
5523 |
|
5524 if (f77_exception_encountered) |
|
5525 { |
|
5526 (*current_liboctave_error_handler) |
|
5527 ("unrecoverable error in dgbtrs"); |
|
5528 break; |
|
5529 } |
|
5530 |
|
5531 // Count non-zeros in work vector and adjust |
|
5532 // space in retval if needed |
|
5533 octave_idx_type new_nnz = 0; |
|
5534 for (octave_idx_type i = 0; i < nr; i++) |
|
5535 if (Bx[i] != 0.) |
|
5536 new_nnz++; |
|
5537 |
|
5538 if (ii + new_nnz > x_nz) |
|
5539 { |
|
5540 // Resize the sparse matrix |
|
5541 octave_idx_type sz = new_nnz * (b_nc - j) + x_nz; |
|
5542 retval.change_capacity (sz); |
|
5543 x_nz = sz; |
|
5544 } |
|
5545 |
|
5546 for (octave_idx_type i = 0; i < nr; i++) |
|
5547 if (Bx[i] != 0.) |
|
5548 { |
|
5549 retval.xridx(ii) = i; |
|
5550 retval.xdata(ii++) = Bx[i]; |
|
5551 } |
|
5552 retval.xcidx(j+1) = ii; |
5164
|
5553 } |
|
5554 |
5681
|
5555 retval.maybe_compress (); |
5164
|
5556 } |
|
5557 } |
|
5558 } |
|
5559 } |
5785
|
5560 else if (typ != MatrixType::Banded_Hermitian) |
5164
|
5561 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
5562 } |
|
5563 |
|
5564 return retval; |
|
5565 } |
|
5566 |
|
5567 void * |
5681
|
5568 SparseComplexMatrix::factorize (octave_idx_type& err, double &rcond, |
|
5569 Matrix &Control, Matrix &Info, |
|
5570 solve_singularity_handler sing_handler, |
|
5571 bool calc_cond) const |
5164
|
5572 { |
|
5573 // The return values |
5404
|
5574 void *Numeric = 0; |
5164
|
5575 err = 0; |
|
5576 |
5203
|
5577 #ifdef HAVE_UMFPACK |
5164
|
5578 // Setup the control parameters |
|
5579 Control = Matrix (UMFPACK_CONTROL, 1); |
|
5580 double *control = Control.fortran_vec (); |
5322
|
5581 UMFPACK_ZNAME (defaults) (control); |
5164
|
5582 |
5893
|
5583 double tmp = octave_sparse_params::get_key ("spumoni"); |
5164
|
5584 if (!xisnan (tmp)) |
|
5585 Control (UMFPACK_PRL) = tmp; |
5893
|
5586 tmp = octave_sparse_params::get_key ("piv_tol"); |
5164
|
5587 if (!xisnan (tmp)) |
|
5588 { |
|
5589 Control (UMFPACK_SYM_PIVOT_TOLERANCE) = tmp; |
|
5590 Control (UMFPACK_PIVOT_TOLERANCE) = tmp; |
|
5591 } |
|
5592 |
|
5593 // Set whether we are allowed to modify Q or not |
5893
|
5594 tmp = octave_sparse_params::get_key ("autoamd"); |
5164
|
5595 if (!xisnan (tmp)) |
|
5596 Control (UMFPACK_FIXQ) = tmp; |
|
5597 |
5322
|
5598 UMFPACK_ZNAME (report_control) (control); |
5164
|
5599 |
5275
|
5600 const octave_idx_type *Ap = cidx (); |
|
5601 const octave_idx_type *Ai = ridx (); |
5164
|
5602 const Complex *Ax = data (); |
5275
|
5603 octave_idx_type nr = rows (); |
|
5604 octave_idx_type nc = cols (); |
5164
|
5605 |
5322
|
5606 UMFPACK_ZNAME (report_matrix) (nr, nc, Ap, Ai, |
5760
|
5607 reinterpret_cast<const double *> (Ax), |
|
5608 NULL, 1, control); |
5164
|
5609 |
|
5610 void *Symbolic; |
|
5611 Info = Matrix (1, UMFPACK_INFO); |
|
5612 double *info = Info.fortran_vec (); |
5322
|
5613 int status = UMFPACK_ZNAME (qsymbolic) (nr, nc, Ap, Ai, |
5760
|
5614 reinterpret_cast<const double *> (Ax), |
5164
|
5615 NULL, NULL, &Symbolic, control, info); |
|
5616 |
|
5617 if (status < 0) |
|
5618 { |
|
5619 (*current_liboctave_error_handler) |
|
5620 ("SparseComplexMatrix::solve symbolic factorization failed"); |
|
5621 err = -1; |
|
5622 |
5322
|
5623 UMFPACK_ZNAME (report_status) (control, status); |
|
5624 UMFPACK_ZNAME (report_info) (control, info); |
|
5625 |
|
5626 UMFPACK_ZNAME (free_symbolic) (&Symbolic) ; |
5164
|
5627 } |
|
5628 else |
|
5629 { |
5322
|
5630 UMFPACK_ZNAME (report_symbolic) (Symbolic, control); |
|
5631 |
|
5632 status = UMFPACK_ZNAME (numeric) (Ap, Ai, |
5760
|
5633 reinterpret_cast<const double *> (Ax), NULL, |
5164
|
5634 Symbolic, &Numeric, control, info) ; |
5322
|
5635 UMFPACK_ZNAME (free_symbolic) (&Symbolic) ; |
5164
|
5636 |
5681
|
5637 if (calc_cond) |
|
5638 rcond = Info (UMFPACK_RCOND); |
|
5639 else |
|
5640 rcond = 1.; |
5164
|
5641 volatile double rcond_plus_one = rcond + 1.0; |
|
5642 |
|
5643 if (status == UMFPACK_WARNING_singular_matrix || |
|
5644 rcond_plus_one == 1.0 || xisnan (rcond)) |
|
5645 { |
5322
|
5646 UMFPACK_ZNAME (report_numeric) (Numeric, control); |
5164
|
5647 |
|
5648 err = -2; |
|
5649 |
|
5650 if (sing_handler) |
|
5651 sing_handler (rcond); |
|
5652 else |
|
5653 (*current_liboctave_error_handler) |
|
5654 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
5655 rcond); |
|
5656 |
|
5657 } |
5610
|
5658 else if (status < 0) |
5164
|
5659 { |
|
5660 (*current_liboctave_error_handler) |
|
5661 ("SparseComplexMatrix::solve numeric factorization failed"); |
|
5662 |
5322
|
5663 UMFPACK_ZNAME (report_status) (control, status); |
|
5664 UMFPACK_ZNAME (report_info) (control, info); |
5164
|
5665 |
|
5666 err = -1; |
|
5667 } |
|
5668 else |
|
5669 { |
5322
|
5670 UMFPACK_ZNAME (report_numeric) (Numeric, control); |
5164
|
5671 } |
|
5672 } |
|
5673 |
|
5674 if (err != 0) |
5322
|
5675 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5203
|
5676 #else |
|
5677 (*current_liboctave_error_handler) ("UMFPACK not installed"); |
|
5678 #endif |
5164
|
5679 |
|
5680 return Numeric; |
|
5681 } |
|
5682 |
|
5683 ComplexMatrix |
5785
|
5684 SparseComplexMatrix::fsolve (MatrixType &mattype, const Matrix& b, |
5681
|
5685 octave_idx_type& err, double& rcond, |
|
5686 solve_singularity_handler sing_handler, |
|
5687 bool calc_cond) const |
5164
|
5688 { |
|
5689 ComplexMatrix retval; |
|
5690 |
5275
|
5691 octave_idx_type nr = rows (); |
|
5692 octave_idx_type nc = cols (); |
5164
|
5693 err = 0; |
|
5694 |
|
5695 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
5696 (*current_liboctave_error_handler) |
|
5697 ("matrix dimension mismatch solution of linear equations"); |
|
5698 else |
|
5699 { |
|
5700 // Print spparms("spumoni") info if requested |
|
5701 volatile int typ = mattype.type (); |
|
5702 mattype.info (); |
|
5703 |
5785
|
5704 if (typ == MatrixType::Hermitian) |
5164
|
5705 { |
5506
|
5706 #ifdef HAVE_CHOLMOD |
|
5707 cholmod_common Common; |
|
5708 cholmod_common *cm = &Common; |
|
5709 |
|
5710 // Setup initial parameters |
|
5711 CHOLMOD_NAME(start) (cm); |
5526
|
5712 cm->prefer_zomplex = false; |
5506
|
5713 |
5893
|
5714 double spu = octave_sparse_params::get_key ("spumoni"); |
5506
|
5715 if (spu == 0.) |
|
5716 { |
|
5717 cm->print = -1; |
|
5718 cm->print_function = NULL; |
|
5719 } |
|
5720 else |
|
5721 { |
5760
|
5722 cm->print = static_cast<int> (spu) + 2; |
5506
|
5723 cm->print_function =&SparseCholPrint; |
|
5724 } |
|
5725 |
|
5726 cm->error_handler = &SparseCholError; |
|
5727 cm->complex_divide = CHOLMOD_NAME(divcomplex); |
|
5728 cm->hypotenuse = CHOLMOD_NAME(hypot); |
|
5729 |
|
5730 #ifdef HAVE_METIS |
5710
|
5731 // METIS 4.0.1 uses malloc and free, and will terminate if |
|
5732 // it runs out of memory. Use CHOLMOD's memory guard for |
|
5733 // METIS, which allocates a huge block of memory (and then |
|
5734 // immediately frees it) before calling METIS |
5506
|
5735 cm->metis_memory = 2.0; |
|
5736 |
|
5737 #if defined(METIS_VERSION) |
|
5738 #if (METIS_VERSION >= METIS_VER(4,0,2)) |
5710
|
5739 // METIS 4.0.2 uses function pointers for malloc and free. |
5506
|
5740 METIS_malloc = cm->malloc_memory; |
|
5741 METIS_free = cm->free_memory; |
5710
|
5742 // Turn off METIS memory guard. |
5506
|
5743 cm->metis_memory = 0.0; |
|
5744 #endif |
|
5745 #endif |
|
5746 #endif |
5526
|
5747 cm->final_ll = true; |
5506
|
5748 |
|
5749 cholmod_sparse Astore; |
|
5750 cholmod_sparse *A = &Astore; |
|
5751 double dummy; |
|
5752 A->nrow = nr; |
|
5753 A->ncol = nc; |
|
5754 |
|
5755 A->p = cidx(); |
|
5756 A->i = ridx(); |
5604
|
5757 A->nzmax = nnz(); |
5526
|
5758 A->packed = true; |
|
5759 A->sorted = true; |
5506
|
5760 A->nz = NULL; |
|
5761 #ifdef IDX_TYPE_LONG |
|
5762 A->itype = CHOLMOD_LONG; |
|
5763 #else |
|
5764 A->itype = CHOLMOD_INT; |
|
5765 #endif |
|
5766 A->dtype = CHOLMOD_DOUBLE; |
|
5767 A->stype = 1; |
|
5768 A->xtype = CHOLMOD_COMPLEX; |
|
5769 |
|
5770 if (nr < 1) |
|
5771 A->x = &dummy; |
|
5772 else |
|
5773 A->x = data(); |
|
5774 |
|
5775 cholmod_dense Bstore; |
|
5776 cholmod_dense *B = &Bstore; |
|
5777 B->nrow = b.rows(); |
|
5778 B->ncol = b.cols(); |
|
5779 B->d = B->nrow; |
|
5780 B->nzmax = B->nrow * B->ncol; |
|
5781 B->dtype = CHOLMOD_DOUBLE; |
|
5782 B->xtype = CHOLMOD_REAL; |
|
5783 if (nc < 1 || b.cols() < 1) |
|
5784 B->x = &dummy; |
|
5785 else |
|
5786 // We won't alter it, honest :-) |
|
5787 B->x = const_cast<double *>(b.fortran_vec()); |
|
5788 |
|
5789 cholmod_factor *L; |
|
5790 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
5791 L = CHOLMOD_NAME(analyze) (A, cm); |
|
5792 CHOLMOD_NAME(factorize) (A, L, cm); |
5681
|
5793 if (calc_cond) |
|
5794 rcond = CHOLMOD_NAME(rcond)(L, cm); |
|
5795 else |
|
5796 rcond = 1.; |
5506
|
5797 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
5798 |
|
5799 if (rcond == 0.0) |
|
5800 { |
|
5801 // Either its indefinite or singular. Try UMFPACK |
|
5802 mattype.mark_as_unsymmetric (); |
5785
|
5803 typ = MatrixType::Full; |
5506
|
5804 } |
|
5805 else |
|
5806 { |
|
5807 volatile double rcond_plus_one = rcond + 1.0; |
|
5808 |
|
5809 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
5810 { |
|
5811 err = -2; |
|
5812 |
|
5813 if (sing_handler) |
5681
|
5814 { |
|
5815 sing_handler (rcond); |
|
5816 mattype.mark_as_rectangular (); |
|
5817 } |
5506
|
5818 else |
|
5819 (*current_liboctave_error_handler) |
|
5820 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", |
|
5821 rcond); |
|
5822 |
|
5823 return retval; |
|
5824 } |
|
5825 |
|
5826 cholmod_dense *X; |
|
5827 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
5828 X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm); |
|
5829 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
5830 |
|
5831 retval.resize (b.rows (), b.cols()); |
|
5832 for (octave_idx_type j = 0; j < b.cols(); j++) |
|
5833 { |
|
5834 octave_idx_type jr = j * b.rows(); |
|
5835 for (octave_idx_type i = 0; i < b.rows(); i++) |
|
5836 retval.xelem(i,j) = static_cast<Complex *>(X->x)[jr + i]; |
|
5837 } |
|
5838 |
|
5839 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
5840 CHOLMOD_NAME(free_dense) (&X, cm); |
|
5841 CHOLMOD_NAME(free_factor) (&L, cm); |
|
5842 CHOLMOD_NAME(finish) (cm); |
6482
|
5843 static char tmp[] = " "; |
|
5844 CHOLMOD_NAME(print_common) (tmp, cm); |
5506
|
5845 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
5846 } |
|
5847 #else |
5164
|
5848 (*current_liboctave_warning_handler) |
5506
|
5849 ("CHOLMOD not installed"); |
5164
|
5850 |
|
5851 mattype.mark_as_unsymmetric (); |
5785
|
5852 typ = MatrixType::Full; |
5506
|
5853 #endif |
5164
|
5854 } |
|
5855 |
5785
|
5856 if (typ == MatrixType::Full) |
5164
|
5857 { |
5203
|
5858 #ifdef HAVE_UMFPACK |
5164
|
5859 Matrix Control, Info; |
|
5860 void *Numeric = factorize (err, rcond, Control, Info, |
5681
|
5861 sing_handler, calc_cond); |
5164
|
5862 |
|
5863 if (err == 0) |
|
5864 { |
5275
|
5865 octave_idx_type b_nr = b.rows (); |
|
5866 octave_idx_type b_nc = b.cols (); |
5164
|
5867 int status = 0; |
|
5868 double *control = Control.fortran_vec (); |
|
5869 double *info = Info.fortran_vec (); |
5275
|
5870 const octave_idx_type *Ap = cidx (); |
|
5871 const octave_idx_type *Ai = ridx (); |
5164
|
5872 const Complex *Ax = data (); |
5203
|
5873 #ifdef UMFPACK_SEPARATE_SPLIT |
5164
|
5874 const double *Bx = b.fortran_vec (); |
|
5875 OCTAVE_LOCAL_BUFFER (double, Bz, b_nr); |
5275
|
5876 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
5877 Bz[i] = 0.; |
5203
|
5878 #else |
|
5879 OCTAVE_LOCAL_BUFFER (Complex, Bz, b_nr); |
|
5880 #endif |
5164
|
5881 retval.resize (b_nr, b_nc); |
|
5882 Complex *Xx = retval.fortran_vec (); |
|
5883 |
5275
|
5884 for (octave_idx_type j = 0, iidx = 0; j < b_nc; j++, iidx += b_nr) |
5164
|
5885 { |
5203
|
5886 #ifdef UMFPACK_SEPARATE_SPLIT |
5322
|
5887 status = UMFPACK_ZNAME (solve) (UMFPACK_A, Ap, |
5760
|
5888 Ai, |
|
5889 reinterpret_cast<const double *> (Ax), |
5164
|
5890 NULL, |
5760
|
5891 reinterpret_cast<double *> (&Xx[iidx]), |
5164
|
5892 NULL, |
|
5893 &Bx[iidx], Bz, Numeric, |
|
5894 control, info); |
5203
|
5895 #else |
5275
|
5896 for (octave_idx_type i = 0; i < b_nr; i++) |
5203
|
5897 Bz[i] = b.elem (i, j); |
|
5898 |
5322
|
5899 status = UMFPACK_ZNAME (solve) (UMFPACK_A, Ap, |
5760
|
5900 Ai, |
|
5901 reinterpret_cast<const double *> (Ax), |
5203
|
5902 NULL, |
5780
|
5903 reinterpret_cast<double *> (&Xx[iidx]), |
5203
|
5904 NULL, |
5760
|
5905 reinterpret_cast<const double *> (Bz), |
5203
|
5906 NULL, Numeric, |
|
5907 control, info); |
|
5908 #endif |
|
5909 |
5164
|
5910 if (status < 0) |
|
5911 { |
|
5912 (*current_liboctave_error_handler) |
|
5913 ("SparseComplexMatrix::solve solve failed"); |
|
5914 |
5322
|
5915 UMFPACK_ZNAME (report_status) (control, status); |
5164
|
5916 |
|
5917 err = -1; |
|
5918 |
|
5919 break; |
|
5920 } |
|
5921 } |
|
5922 |
5322
|
5923 UMFPACK_ZNAME (report_info) (control, info); |
|
5924 |
|
5925 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5164
|
5926 } |
5681
|
5927 else |
|
5928 mattype.mark_as_rectangular (); |
|
5929 |
5203
|
5930 #else |
|
5931 (*current_liboctave_error_handler) ("UMFPACK not installed"); |
|
5932 #endif |
5164
|
5933 } |
5785
|
5934 else if (typ != MatrixType::Hermitian) |
5164
|
5935 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
5936 } |
|
5937 |
|
5938 return retval; |
|
5939 } |
|
5940 |
|
5941 SparseComplexMatrix |
5785
|
5942 SparseComplexMatrix::fsolve (MatrixType &mattype, const SparseMatrix& b, |
5275
|
5943 octave_idx_type& err, double& rcond, |
5681
|
5944 solve_singularity_handler sing_handler, |
|
5945 bool calc_cond) const |
5164
|
5946 { |
|
5947 SparseComplexMatrix retval; |
|
5948 |
5275
|
5949 octave_idx_type nr = rows (); |
|
5950 octave_idx_type nc = cols (); |
5164
|
5951 err = 0; |
|
5952 |
|
5953 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
5954 (*current_liboctave_error_handler) |
|
5955 ("matrix dimension mismatch solution of linear equations"); |
|
5956 else |
|
5957 { |
|
5958 // Print spparms("spumoni") info if requested |
5506
|
5959 volatile int typ = mattype.type (); |
5164
|
5960 mattype.info (); |
|
5961 |
5785
|
5962 if (typ == MatrixType::Hermitian) |
5164
|
5963 { |
5506
|
5964 #ifdef HAVE_CHOLMOD |
|
5965 cholmod_common Common; |
|
5966 cholmod_common *cm = &Common; |
|
5967 |
|
5968 // Setup initial parameters |
|
5969 CHOLMOD_NAME(start) (cm); |
5526
|
5970 cm->prefer_zomplex = false; |
5506
|
5971 |
5893
|
5972 double spu = octave_sparse_params::get_key ("spumoni"); |
5506
|
5973 if (spu == 0.) |
|
5974 { |
|
5975 cm->print = -1; |
|
5976 cm->print_function = NULL; |
|
5977 } |
|
5978 else |
|
5979 { |
5760
|
5980 cm->print = static_cast<int> (spu) + 2; |
5506
|
5981 cm->print_function =&SparseCholPrint; |
|
5982 } |
|
5983 |
|
5984 cm->error_handler = &SparseCholError; |
|
5985 cm->complex_divide = CHOLMOD_NAME(divcomplex); |
|
5986 cm->hypotenuse = CHOLMOD_NAME(hypot); |
|
5987 |
|
5988 #ifdef HAVE_METIS |
|
5989 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if |
|
5990 // it runs out of memory. Use CHOLMOD's memory guard for METIS, |
|
5991 // which mxMalloc's a huge block of memory (and then immediately |
|
5992 // mxFree's it) before calling METIS |
|
5993 cm->metis_memory = 2.0; |
|
5994 |
|
5995 #if defined(METIS_VERSION) |
|
5996 #if (METIS_VERSION >= METIS_VER(4,0,2)) |
|
5997 // METIS 4.0.2 uses function pointers for malloc and free |
|
5998 METIS_malloc = cm->malloc_memory; |
|
5999 METIS_free = cm->free_memory; |
|
6000 // Turn off METIS memory guard. It is not needed, because mxMalloc |
|
6001 // will safely terminate the mexFunction and free any workspace |
|
6002 // without killing all of octave. |
|
6003 cm->metis_memory = 0.0; |
|
6004 #endif |
|
6005 #endif |
|
6006 #endif |
|
6007 |
5526
|
6008 cm->final_ll = true; |
5506
|
6009 |
|
6010 cholmod_sparse Astore; |
|
6011 cholmod_sparse *A = &Astore; |
|
6012 double dummy; |
|
6013 A->nrow = nr; |
|
6014 A->ncol = nc; |
|
6015 |
|
6016 A->p = cidx(); |
|
6017 A->i = ridx(); |
5604
|
6018 A->nzmax = nnz(); |
5526
|
6019 A->packed = true; |
|
6020 A->sorted = true; |
5506
|
6021 A->nz = NULL; |
|
6022 #ifdef IDX_TYPE_LONG |
|
6023 A->itype = CHOLMOD_LONG; |
|
6024 #else |
|
6025 A->itype = CHOLMOD_INT; |
|
6026 #endif |
|
6027 A->dtype = CHOLMOD_DOUBLE; |
|
6028 A->stype = 1; |
|
6029 A->xtype = CHOLMOD_COMPLEX; |
|
6030 |
|
6031 if (nr < 1) |
|
6032 A->x = &dummy; |
|
6033 else |
|
6034 A->x = data(); |
|
6035 |
|
6036 cholmod_sparse Bstore; |
|
6037 cholmod_sparse *B = &Bstore; |
|
6038 B->nrow = b.rows(); |
|
6039 B->ncol = b.cols(); |
|
6040 B->p = b.cidx(); |
|
6041 B->i = b.ridx(); |
5604
|
6042 B->nzmax = b.nnz(); |
5526
|
6043 B->packed = true; |
|
6044 B->sorted = true; |
5506
|
6045 B->nz = NULL; |
|
6046 #ifdef IDX_TYPE_LONG |
|
6047 B->itype = CHOLMOD_LONG; |
|
6048 #else |
|
6049 B->itype = CHOLMOD_INT; |
|
6050 #endif |
|
6051 B->dtype = CHOLMOD_DOUBLE; |
|
6052 B->stype = 0; |
|
6053 B->xtype = CHOLMOD_REAL; |
|
6054 |
|
6055 if (b.rows() < 1 || b.cols() < 1) |
|
6056 B->x = &dummy; |
|
6057 else |
|
6058 B->x = b.data(); |
|
6059 |
|
6060 cholmod_factor *L; |
|
6061 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6062 L = CHOLMOD_NAME(analyze) (A, cm); |
|
6063 CHOLMOD_NAME(factorize) (A, L, cm); |
5681
|
6064 if (calc_cond) |
|
6065 rcond = CHOLMOD_NAME(rcond)(L, cm); |
|
6066 else |
|
6067 rcond = 1.; |
5506
|
6068 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6069 |
|
6070 if (rcond == 0.0) |
|
6071 { |
|
6072 // Either its indefinite or singular. Try UMFPACK |
|
6073 mattype.mark_as_unsymmetric (); |
5785
|
6074 typ = MatrixType::Full; |
5506
|
6075 } |
|
6076 else |
|
6077 { |
|
6078 volatile double rcond_plus_one = rcond + 1.0; |
|
6079 |
|
6080 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
6081 { |
|
6082 err = -2; |
|
6083 |
|
6084 if (sing_handler) |
5681
|
6085 { |
|
6086 sing_handler (rcond); |
|
6087 mattype.mark_as_rectangular (); |
|
6088 } |
5506
|
6089 else |
|
6090 (*current_liboctave_error_handler) |
|
6091 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", |
|
6092 rcond); |
|
6093 |
|
6094 return retval; |
|
6095 } |
|
6096 |
|
6097 cholmod_sparse *X; |
|
6098 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6099 X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm); |
|
6100 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6101 |
|
6102 retval = SparseComplexMatrix |
|
6103 (static_cast<octave_idx_type>(X->nrow), |
|
6104 static_cast<octave_idx_type>(X->ncol), |
|
6105 static_cast<octave_idx_type>(X->nzmax)); |
|
6106 for (octave_idx_type j = 0; |
|
6107 j <= static_cast<octave_idx_type>(X->ncol); j++) |
|
6108 retval.xcidx(j) = static_cast<octave_idx_type *>(X->p)[j]; |
|
6109 for (octave_idx_type j = 0; |
|
6110 j < static_cast<octave_idx_type>(X->nzmax); j++) |
|
6111 { |
|
6112 retval.xridx(j) = static_cast<octave_idx_type *>(X->i)[j]; |
|
6113 retval.xdata(j) = static_cast<Complex *>(X->x)[j]; |
|
6114 } |
|
6115 |
|
6116 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6117 CHOLMOD_NAME(free_sparse) (&X, cm); |
|
6118 CHOLMOD_NAME(free_factor) (&L, cm); |
|
6119 CHOLMOD_NAME(finish) (cm); |
6482
|
6120 static char tmp[] = " "; |
|
6121 CHOLMOD_NAME(print_common) (tmp, cm); |
5506
|
6122 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6123 } |
|
6124 #else |
5164
|
6125 (*current_liboctave_warning_handler) |
5506
|
6126 ("CHOLMOD not installed"); |
5164
|
6127 |
|
6128 mattype.mark_as_unsymmetric (); |
5785
|
6129 typ = MatrixType::Full; |
5506
|
6130 #endif |
5164
|
6131 } |
|
6132 |
5785
|
6133 if (typ == MatrixType::Full) |
5164
|
6134 { |
5203
|
6135 #ifdef HAVE_UMFPACK |
5164
|
6136 Matrix Control, Info; |
5681
|
6137 void *Numeric = factorize (err, rcond, Control, Info, |
|
6138 sing_handler, calc_cond); |
5164
|
6139 |
|
6140 if (err == 0) |
|
6141 { |
5275
|
6142 octave_idx_type b_nr = b.rows (); |
|
6143 octave_idx_type b_nc = b.cols (); |
5164
|
6144 int status = 0; |
|
6145 double *control = Control.fortran_vec (); |
|
6146 double *info = Info.fortran_vec (); |
5275
|
6147 const octave_idx_type *Ap = cidx (); |
|
6148 const octave_idx_type *Ai = ridx (); |
5164
|
6149 const Complex *Ax = data (); |
|
6150 |
5203
|
6151 #ifdef UMFPACK_SEPARATE_SPLIT |
5164
|
6152 OCTAVE_LOCAL_BUFFER (double, Bx, b_nr); |
|
6153 OCTAVE_LOCAL_BUFFER (double, Bz, b_nr); |
5275
|
6154 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
6155 Bz[i] = 0.; |
5203
|
6156 #else |
|
6157 OCTAVE_LOCAL_BUFFER (Complex, Bz, b_nr); |
|
6158 #endif |
5164
|
6159 |
|
6160 // Take a first guess that the number of non-zero terms |
|
6161 // will be as many as in b |
5681
|
6162 octave_idx_type x_nz = b.nnz (); |
5275
|
6163 octave_idx_type ii = 0; |
5164
|
6164 retval = SparseComplexMatrix (b_nr, b_nc, x_nz); |
|
6165 |
|
6166 OCTAVE_LOCAL_BUFFER (Complex, Xx, b_nr); |
|
6167 |
|
6168 retval.xcidx(0) = 0; |
5275
|
6169 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
6170 { |
|
6171 |
5203
|
6172 #ifdef UMFPACK_SEPARATE_SPLIT |
5275
|
6173 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
6174 Bx[i] = b.elem (i, j); |
|
6175 |
5322
|
6176 status = UMFPACK_ZNAME (solve) (UMFPACK_A, Ap, |
5760
|
6177 Ai, |
|
6178 reinterpret_cast<const double *> (Ax), |
5164
|
6179 NULL, |
5760
|
6180 reinterpret_cast<double *> (Xx), |
|
6181 NULL, |
5164
|
6182 Bx, Bz, Numeric, control, |
|
6183 info); |
5203
|
6184 #else |
5275
|
6185 for (octave_idx_type i = 0; i < b_nr; i++) |
5203
|
6186 Bz[i] = b.elem (i, j); |
|
6187 |
5322
|
6188 status = UMFPACK_ZNAME (solve) (UMFPACK_A, Ap, Ai, |
5760
|
6189 reinterpret_cast<const double *> (Ax), |
5203
|
6190 NULL, |
5760
|
6191 reinterpret_cast<double *> (Xx), |
|
6192 NULL, |
|
6193 reinterpret_cast<double *> (Bz), |
|
6194 NULL, |
5203
|
6195 Numeric, control, |
|
6196 info); |
|
6197 #endif |
5164
|
6198 if (status < 0) |
|
6199 { |
|
6200 (*current_liboctave_error_handler) |
|
6201 ("SparseComplexMatrix::solve solve failed"); |
|
6202 |
5322
|
6203 UMFPACK_ZNAME (report_status) (control, status); |
5164
|
6204 |
|
6205 err = -1; |
|
6206 |
|
6207 break; |
|
6208 } |
|
6209 |
5275
|
6210 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
6211 { |
|
6212 Complex tmp = Xx[i]; |
|
6213 if (tmp != 0.0) |
|
6214 { |
|
6215 if (ii == x_nz) |
|
6216 { |
|
6217 // Resize the sparse matrix |
5275
|
6218 octave_idx_type sz = x_nz * (b_nc - j) / b_nc; |
5164
|
6219 sz = (sz > 10 ? sz : 10) + x_nz; |
|
6220 retval.change_capacity (sz); |
|
6221 x_nz = sz; |
|
6222 } |
|
6223 retval.xdata(ii) = tmp; |
|
6224 retval.xridx(ii++) = i; |
|
6225 } |
|
6226 } |
|
6227 retval.xcidx(j+1) = ii; |
|
6228 } |
|
6229 |
|
6230 retval.maybe_compress (); |
|
6231 |
5322
|
6232 UMFPACK_ZNAME (report_info) (control, info); |
|
6233 |
|
6234 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5164
|
6235 } |
5681
|
6236 else |
|
6237 mattype.mark_as_rectangular (); |
|
6238 |
5203
|
6239 #else |
|
6240 (*current_liboctave_error_handler) ("UMFPACK not installed"); |
|
6241 #endif |
5164
|
6242 } |
5785
|
6243 else if (typ != MatrixType::Hermitian) |
5164
|
6244 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
6245 } |
|
6246 |
|
6247 return retval; |
|
6248 } |
|
6249 |
|
6250 ComplexMatrix |
5785
|
6251 SparseComplexMatrix::fsolve (MatrixType &mattype, const ComplexMatrix& b, |
5275
|
6252 octave_idx_type& err, double& rcond, |
5681
|
6253 solve_singularity_handler sing_handler, |
|
6254 bool calc_cond) const |
5164
|
6255 { |
|
6256 ComplexMatrix retval; |
|
6257 |
5275
|
6258 octave_idx_type nr = rows (); |
|
6259 octave_idx_type nc = cols (); |
5164
|
6260 err = 0; |
|
6261 |
|
6262 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
6263 (*current_liboctave_error_handler) |
|
6264 ("matrix dimension mismatch solution of linear equations"); |
|
6265 else |
|
6266 { |
|
6267 // Print spparms("spumoni") info if requested |
5506
|
6268 volatile int typ = mattype.type (); |
5164
|
6269 mattype.info (); |
|
6270 |
5785
|
6271 if (typ == MatrixType::Hermitian) |
5164
|
6272 { |
5506
|
6273 #ifdef HAVE_CHOLMOD |
|
6274 cholmod_common Common; |
|
6275 cholmod_common *cm = &Common; |
|
6276 |
|
6277 // Setup initial parameters |
|
6278 CHOLMOD_NAME(start) (cm); |
5526
|
6279 cm->prefer_zomplex = false; |
5506
|
6280 |
5893
|
6281 double spu = octave_sparse_params::get_key ("spumoni"); |
5506
|
6282 if (spu == 0.) |
|
6283 { |
|
6284 cm->print = -1; |
|
6285 cm->print_function = NULL; |
|
6286 } |
|
6287 else |
|
6288 { |
5760
|
6289 cm->print = static_cast<int> (spu) + 2; |
5506
|
6290 cm->print_function =&SparseCholPrint; |
|
6291 } |
|
6292 |
|
6293 cm->error_handler = &SparseCholError; |
|
6294 cm->complex_divide = CHOLMOD_NAME(divcomplex); |
|
6295 cm->hypotenuse = CHOLMOD_NAME(hypot); |
|
6296 |
|
6297 #ifdef HAVE_METIS |
|
6298 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if |
|
6299 // it runs out of memory. Use CHOLMOD's memory guard for METIS, |
|
6300 // which mxMalloc's a huge block of memory (and then immediately |
|
6301 // mxFree's it) before calling METIS |
|
6302 cm->metis_memory = 2.0; |
|
6303 |
|
6304 #if defined(METIS_VERSION) |
|
6305 #if (METIS_VERSION >= METIS_VER(4,0,2)) |
|
6306 // METIS 4.0.2 uses function pointers for malloc and free |
|
6307 METIS_malloc = cm->malloc_memory; |
|
6308 METIS_free = cm->free_memory; |
|
6309 // Turn off METIS memory guard. It is not needed, because mxMalloc |
|
6310 // will safely terminate the mexFunction and free any workspace |
|
6311 // without killing all of octave. |
|
6312 cm->metis_memory = 0.0; |
|
6313 #endif |
|
6314 #endif |
|
6315 #endif |
|
6316 |
5526
|
6317 cm->final_ll = true; |
5506
|
6318 |
|
6319 cholmod_sparse Astore; |
|
6320 cholmod_sparse *A = &Astore; |
|
6321 double dummy; |
|
6322 A->nrow = nr; |
|
6323 A->ncol = nc; |
|
6324 |
|
6325 A->p = cidx(); |
|
6326 A->i = ridx(); |
5604
|
6327 A->nzmax = nnz(); |
5526
|
6328 A->packed = true; |
|
6329 A->sorted = true; |
5506
|
6330 A->nz = NULL; |
|
6331 #ifdef IDX_TYPE_LONG |
|
6332 A->itype = CHOLMOD_LONG; |
|
6333 #else |
|
6334 A->itype = CHOLMOD_INT; |
|
6335 #endif |
|
6336 A->dtype = CHOLMOD_DOUBLE; |
|
6337 A->stype = 1; |
|
6338 A->xtype = CHOLMOD_COMPLEX; |
|
6339 |
|
6340 if (nr < 1) |
|
6341 A->x = &dummy; |
|
6342 else |
|
6343 A->x = data(); |
|
6344 |
|
6345 cholmod_dense Bstore; |
|
6346 cholmod_dense *B = &Bstore; |
|
6347 B->nrow = b.rows(); |
|
6348 B->ncol = b.cols(); |
|
6349 B->d = B->nrow; |
|
6350 B->nzmax = B->nrow * B->ncol; |
|
6351 B->dtype = CHOLMOD_DOUBLE; |
|
6352 B->xtype = CHOLMOD_COMPLEX; |
|
6353 if (nc < 1 || b.cols() < 1) |
|
6354 B->x = &dummy; |
|
6355 else |
|
6356 // We won't alter it, honest :-) |
|
6357 B->x = const_cast<Complex *>(b.fortran_vec()); |
|
6358 |
|
6359 cholmod_factor *L; |
|
6360 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6361 L = CHOLMOD_NAME(analyze) (A, cm); |
|
6362 CHOLMOD_NAME(factorize) (A, L, cm); |
5681
|
6363 if (calc_cond) |
|
6364 rcond = CHOLMOD_NAME(rcond)(L, cm); |
|
6365 else |
|
6366 rcond = 1.; |
5506
|
6367 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6368 |
|
6369 if (rcond == 0.0) |
|
6370 { |
|
6371 // Either its indefinite or singular. Try UMFPACK |
|
6372 mattype.mark_as_unsymmetric (); |
5785
|
6373 typ = MatrixType::Full; |
5506
|
6374 } |
|
6375 else |
|
6376 { |
|
6377 volatile double rcond_plus_one = rcond + 1.0; |
|
6378 |
|
6379 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
6380 { |
|
6381 err = -2; |
|
6382 |
|
6383 if (sing_handler) |
5681
|
6384 { |
|
6385 sing_handler (rcond); |
|
6386 mattype.mark_as_rectangular (); |
|
6387 } |
5506
|
6388 else |
|
6389 (*current_liboctave_error_handler) |
|
6390 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", |
|
6391 rcond); |
|
6392 |
|
6393 return retval; |
|
6394 } |
|
6395 |
|
6396 cholmod_dense *X; |
|
6397 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6398 X = CHOLMOD_NAME(solve) (CHOLMOD_A, L, B, cm); |
|
6399 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6400 |
|
6401 retval.resize (b.rows (), b.cols()); |
|
6402 for (octave_idx_type j = 0; j < b.cols(); j++) |
|
6403 { |
|
6404 octave_idx_type jr = j * b.rows(); |
|
6405 for (octave_idx_type i = 0; i < b.rows(); i++) |
|
6406 retval.xelem(i,j) = static_cast<Complex *>(X->x)[jr + i]; |
|
6407 } |
|
6408 |
|
6409 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6410 CHOLMOD_NAME(free_dense) (&X, cm); |
|
6411 CHOLMOD_NAME(free_factor) (&L, cm); |
|
6412 CHOLMOD_NAME(finish) (cm); |
6482
|
6413 static char tmp[] = " "; |
|
6414 CHOLMOD_NAME(print_common) (tmp, cm); |
5506
|
6415 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6416 } |
|
6417 #else |
5164
|
6418 (*current_liboctave_warning_handler) |
5506
|
6419 ("CHOLMOD not installed"); |
5164
|
6420 |
|
6421 mattype.mark_as_unsymmetric (); |
5785
|
6422 typ = MatrixType::Full; |
5506
|
6423 #endif |
5164
|
6424 } |
|
6425 |
5785
|
6426 if (typ == MatrixType::Full) |
5164
|
6427 { |
5203
|
6428 #ifdef HAVE_UMFPACK |
5164
|
6429 Matrix Control, Info; |
5681
|
6430 void *Numeric = factorize (err, rcond, Control, Info, |
|
6431 sing_handler, calc_cond); |
5164
|
6432 |
|
6433 if (err == 0) |
|
6434 { |
5275
|
6435 octave_idx_type b_nr = b.rows (); |
|
6436 octave_idx_type b_nc = b.cols (); |
5164
|
6437 int status = 0; |
|
6438 double *control = Control.fortran_vec (); |
|
6439 double *info = Info.fortran_vec (); |
5275
|
6440 const octave_idx_type *Ap = cidx (); |
|
6441 const octave_idx_type *Ai = ridx (); |
5164
|
6442 const Complex *Ax = data (); |
|
6443 const Complex *Bx = b.fortran_vec (); |
|
6444 |
|
6445 retval.resize (b_nr, b_nc); |
|
6446 Complex *Xx = retval.fortran_vec (); |
|
6447 |
5275
|
6448 for (octave_idx_type j = 0, iidx = 0; j < b_nc; j++, iidx += b_nr) |
5164
|
6449 { |
|
6450 status = |
5322
|
6451 UMFPACK_ZNAME (solve) (UMFPACK_A, Ap, Ai, |
5760
|
6452 reinterpret_cast<const double *> (Ax), |
|
6453 NULL, |
|
6454 reinterpret_cast<double *> (&Xx[iidx]), |
|
6455 NULL, |
|
6456 reinterpret_cast<const double *> (&Bx[iidx]), |
5164
|
6457 NULL, Numeric, control, info); |
|
6458 |
|
6459 if (status < 0) |
|
6460 { |
|
6461 (*current_liboctave_error_handler) |
|
6462 ("SparseComplexMatrix::solve solve failed"); |
|
6463 |
5322
|
6464 UMFPACK_ZNAME (report_status) (control, status); |
5164
|
6465 |
|
6466 err = -1; |
|
6467 |
|
6468 break; |
|
6469 } |
|
6470 } |
|
6471 |
5322
|
6472 UMFPACK_ZNAME (report_info) (control, info); |
|
6473 |
|
6474 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5164
|
6475 } |
5681
|
6476 else |
|
6477 mattype.mark_as_rectangular (); |
|
6478 |
5203
|
6479 #else |
|
6480 (*current_liboctave_error_handler) ("UMFPACK not installed"); |
|
6481 #endif |
5164
|
6482 } |
5785
|
6483 else if (typ != MatrixType::Hermitian) |
5164
|
6484 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
6485 } |
|
6486 |
|
6487 return retval; |
|
6488 } |
|
6489 |
|
6490 SparseComplexMatrix |
5785
|
6491 SparseComplexMatrix::fsolve (MatrixType &mattype, const SparseComplexMatrix& b, |
5275
|
6492 octave_idx_type& err, double& rcond, |
5681
|
6493 solve_singularity_handler sing_handler, |
|
6494 bool calc_cond) const |
5164
|
6495 { |
|
6496 SparseComplexMatrix retval; |
|
6497 |
5275
|
6498 octave_idx_type nr = rows (); |
|
6499 octave_idx_type nc = cols (); |
5164
|
6500 err = 0; |
|
6501 |
|
6502 if (nr == 0 || nc == 0 || nr != nc || nr != b.rows ()) |
|
6503 (*current_liboctave_error_handler) |
|
6504 ("matrix dimension mismatch solution of linear equations"); |
|
6505 else |
|
6506 { |
|
6507 // Print spparms("spumoni") info if requested |
5506
|
6508 volatile int typ = mattype.type (); |
5164
|
6509 mattype.info (); |
|
6510 |
5785
|
6511 if (typ == MatrixType::Hermitian) |
5164
|
6512 { |
5506
|
6513 #ifdef HAVE_CHOLMOD |
|
6514 cholmod_common Common; |
|
6515 cholmod_common *cm = &Common; |
|
6516 |
|
6517 // Setup initial parameters |
|
6518 CHOLMOD_NAME(start) (cm); |
5526
|
6519 cm->prefer_zomplex = false; |
5506
|
6520 |
5893
|
6521 double spu = octave_sparse_params::get_key ("spumoni"); |
5506
|
6522 if (spu == 0.) |
|
6523 { |
|
6524 cm->print = -1; |
|
6525 cm->print_function = NULL; |
|
6526 } |
|
6527 else |
|
6528 { |
5760
|
6529 cm->print = static_cast<int> (spu) + 2; |
5506
|
6530 cm->print_function =&SparseCholPrint; |
|
6531 } |
|
6532 |
|
6533 cm->error_handler = &SparseCholError; |
|
6534 cm->complex_divide = CHOLMOD_NAME(divcomplex); |
|
6535 cm->hypotenuse = CHOLMOD_NAME(hypot); |
|
6536 |
|
6537 #ifdef HAVE_METIS |
|
6538 // METIS 4.0.1 uses malloc and free, and will terminate MATLAB if |
|
6539 // it runs out of memory. Use CHOLMOD's memory guard for METIS, |
|
6540 // which mxMalloc's a huge block of memory (and then immediately |
|
6541 // mxFree's it) before calling METIS |
|
6542 cm->metis_memory = 2.0; |
|
6543 |
|
6544 #if defined(METIS_VERSION) |
|
6545 #if (METIS_VERSION >= METIS_VER(4,0,2)) |
|
6546 // METIS 4.0.2 uses function pointers for malloc and free |
|
6547 METIS_malloc = cm->malloc_memory; |
|
6548 METIS_free = cm->free_memory; |
|
6549 // Turn off METIS memory guard. It is not needed, because mxMalloc |
|
6550 // will safely terminate the mexFunction and free any workspace |
|
6551 // without killing all of octave. |
|
6552 cm->metis_memory = 0.0; |
|
6553 #endif |
|
6554 #endif |
|
6555 #endif |
|
6556 |
5526
|
6557 cm->final_ll = true; |
5506
|
6558 |
|
6559 cholmod_sparse Astore; |
|
6560 cholmod_sparse *A = &Astore; |
|
6561 double dummy; |
|
6562 A->nrow = nr; |
|
6563 A->ncol = nc; |
|
6564 |
|
6565 A->p = cidx(); |
|
6566 A->i = ridx(); |
5604
|
6567 A->nzmax = nnz(); |
5526
|
6568 A->packed = true; |
|
6569 A->sorted = true; |
5506
|
6570 A->nz = NULL; |
|
6571 #ifdef IDX_TYPE_LONG |
|
6572 A->itype = CHOLMOD_LONG; |
|
6573 #else |
|
6574 A->itype = CHOLMOD_INT; |
|
6575 #endif |
|
6576 A->dtype = CHOLMOD_DOUBLE; |
|
6577 A->stype = 1; |
|
6578 A->xtype = CHOLMOD_COMPLEX; |
|
6579 |
|
6580 if (nr < 1) |
|
6581 A->x = &dummy; |
|
6582 else |
|
6583 A->x = data(); |
|
6584 |
|
6585 cholmod_sparse Bstore; |
|
6586 cholmod_sparse *B = &Bstore; |
|
6587 B->nrow = b.rows(); |
|
6588 B->ncol = b.cols(); |
|
6589 B->p = b.cidx(); |
|
6590 B->i = b.ridx(); |
5604
|
6591 B->nzmax = b.nnz(); |
5526
|
6592 B->packed = true; |
|
6593 B->sorted = true; |
5506
|
6594 B->nz = NULL; |
|
6595 #ifdef IDX_TYPE_LONG |
|
6596 B->itype = CHOLMOD_LONG; |
|
6597 #else |
|
6598 B->itype = CHOLMOD_INT; |
|
6599 #endif |
|
6600 B->dtype = CHOLMOD_DOUBLE; |
|
6601 B->stype = 0; |
|
6602 B->xtype = CHOLMOD_COMPLEX; |
|
6603 |
|
6604 if (b.rows() < 1 || b.cols() < 1) |
|
6605 B->x = &dummy; |
|
6606 else |
|
6607 B->x = b.data(); |
|
6608 |
|
6609 cholmod_factor *L; |
|
6610 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6611 L = CHOLMOD_NAME(analyze) (A, cm); |
|
6612 CHOLMOD_NAME(factorize) (A, L, cm); |
5681
|
6613 if (calc_cond) |
|
6614 rcond = CHOLMOD_NAME(rcond)(L, cm); |
|
6615 else |
|
6616 rcond = 1.; |
5506
|
6617 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6618 |
|
6619 if (rcond == 0.0) |
|
6620 { |
|
6621 // Either its indefinite or singular. Try UMFPACK |
|
6622 mattype.mark_as_unsymmetric (); |
5785
|
6623 typ = MatrixType::Full; |
5506
|
6624 } |
|
6625 else |
|
6626 { |
|
6627 volatile double rcond_plus_one = rcond + 1.0; |
|
6628 |
|
6629 if (rcond_plus_one == 1.0 || xisnan (rcond)) |
|
6630 { |
|
6631 err = -2; |
|
6632 |
|
6633 if (sing_handler) |
5681
|
6634 { |
|
6635 sing_handler (rcond); |
|
6636 mattype.mark_as_rectangular (); |
|
6637 } |
5506
|
6638 else |
|
6639 (*current_liboctave_error_handler) |
|
6640 ("SparseMatrix::solve matrix singular to machine precision, rcond = %g", |
|
6641 rcond); |
|
6642 |
|
6643 return retval; |
|
6644 } |
|
6645 |
|
6646 cholmod_sparse *X; |
|
6647 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6648 X = CHOLMOD_NAME(spsolve) (CHOLMOD_A, L, B, cm); |
|
6649 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6650 |
|
6651 retval = SparseComplexMatrix |
|
6652 (static_cast<octave_idx_type>(X->nrow), |
|
6653 static_cast<octave_idx_type>(X->ncol), |
|
6654 static_cast<octave_idx_type>(X->nzmax)); |
|
6655 for (octave_idx_type j = 0; |
|
6656 j <= static_cast<octave_idx_type>(X->ncol); j++) |
|
6657 retval.xcidx(j) = static_cast<octave_idx_type *>(X->p)[j]; |
|
6658 for (octave_idx_type j = 0; |
|
6659 j < static_cast<octave_idx_type>(X->nzmax); j++) |
|
6660 { |
|
6661 retval.xridx(j) = static_cast<octave_idx_type *>(X->i)[j]; |
|
6662 retval.xdata(j) = static_cast<Complex *>(X->x)[j]; |
|
6663 } |
|
6664 |
|
6665 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6666 CHOLMOD_NAME(free_sparse) (&X, cm); |
|
6667 CHOLMOD_NAME(free_factor) (&L, cm); |
|
6668 CHOLMOD_NAME(finish) (cm); |
6482
|
6669 static char tmp[] = " "; |
|
6670 CHOLMOD_NAME(print_common) (tmp, cm); |
5506
|
6671 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; |
|
6672 } |
|
6673 #else |
5164
|
6674 (*current_liboctave_warning_handler) |
5506
|
6675 ("CHOLMOD not installed"); |
5164
|
6676 |
|
6677 mattype.mark_as_unsymmetric (); |
5785
|
6678 typ = MatrixType::Full; |
5506
|
6679 #endif |
5164
|
6680 } |
|
6681 |
5785
|
6682 if (typ == MatrixType::Full) |
5164
|
6683 { |
5203
|
6684 #ifdef HAVE_UMFPACK |
5164
|
6685 Matrix Control, Info; |
5681
|
6686 void *Numeric = factorize (err, rcond, Control, Info, |
|
6687 sing_handler, calc_cond); |
5164
|
6688 |
|
6689 if (err == 0) |
|
6690 { |
5275
|
6691 octave_idx_type b_nr = b.rows (); |
|
6692 octave_idx_type b_nc = b.cols (); |
5164
|
6693 int status = 0; |
|
6694 double *control = Control.fortran_vec (); |
|
6695 double *info = Info.fortran_vec (); |
5275
|
6696 const octave_idx_type *Ap = cidx (); |
|
6697 const octave_idx_type *Ai = ridx (); |
5164
|
6698 const Complex *Ax = data (); |
|
6699 |
|
6700 OCTAVE_LOCAL_BUFFER (Complex, Bx, b_nr); |
|
6701 |
|
6702 // Take a first guess that the number of non-zero terms |
|
6703 // will be as many as in b |
5681
|
6704 octave_idx_type x_nz = b.nnz (); |
5275
|
6705 octave_idx_type ii = 0; |
5164
|
6706 retval = SparseComplexMatrix (b_nr, b_nc, x_nz); |
|
6707 |
|
6708 OCTAVE_LOCAL_BUFFER (Complex, Xx, b_nr); |
|
6709 |
|
6710 retval.xcidx(0) = 0; |
5275
|
6711 for (octave_idx_type j = 0; j < b_nc; j++) |
5164
|
6712 { |
5275
|
6713 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
6714 Bx[i] = b (i,j); |
|
6715 |
5322
|
6716 status = UMFPACK_ZNAME (solve) (UMFPACK_A, Ap, |
5760
|
6717 Ai, |
|
6718 reinterpret_cast<const double *> (Ax), |
|
6719 NULL, |
|
6720 reinterpret_cast<double *> (Xx), |
|
6721 NULL, |
|
6722 reinterpret_cast<double *> (Bx), |
5164
|
6723 NULL, Numeric, control, info); |
|
6724 |
|
6725 if (status < 0) |
|
6726 { |
|
6727 (*current_liboctave_error_handler) |
|
6728 ("SparseComplexMatrix::solve solve failed"); |
|
6729 |
5322
|
6730 UMFPACK_ZNAME (report_status) (control, status); |
5164
|
6731 |
|
6732 err = -1; |
|
6733 |
|
6734 break; |
|
6735 } |
|
6736 |
5275
|
6737 for (octave_idx_type i = 0; i < b_nr; i++) |
5164
|
6738 { |
|
6739 Complex tmp = Xx[i]; |
|
6740 if (tmp != 0.0) |
|
6741 { |
|
6742 if (ii == x_nz) |
|
6743 { |
|
6744 // Resize the sparse matrix |
5275
|
6745 octave_idx_type sz = x_nz * (b_nc - j) / b_nc; |
5164
|
6746 sz = (sz > 10 ? sz : 10) + x_nz; |
|
6747 retval.change_capacity (sz); |
|
6748 x_nz = sz; |
|
6749 } |
|
6750 retval.xdata(ii) = tmp; |
|
6751 retval.xridx(ii++) = i; |
|
6752 } |
|
6753 } |
|
6754 retval.xcidx(j+1) = ii; |
|
6755 } |
|
6756 |
|
6757 retval.maybe_compress (); |
|
6758 |
|
6759 rcond = Info (UMFPACK_RCOND); |
|
6760 volatile double rcond_plus_one = rcond + 1.0; |
|
6761 |
|
6762 if (status == UMFPACK_WARNING_singular_matrix || |
|
6763 rcond_plus_one == 1.0 || xisnan (rcond)) |
|
6764 { |
|
6765 err = -2; |
|
6766 |
|
6767 if (sing_handler) |
|
6768 sing_handler (rcond); |
|
6769 else |
|
6770 (*current_liboctave_error_handler) |
|
6771 ("SparseComplexMatrix::solve matrix singular to machine precision, rcond = %g", |
|
6772 rcond); |
|
6773 |
|
6774 } |
|
6775 |
5322
|
6776 UMFPACK_ZNAME (report_info) (control, info); |
|
6777 |
|
6778 UMFPACK_ZNAME (free_numeric) (&Numeric); |
5164
|
6779 } |
5681
|
6780 else |
|
6781 mattype.mark_as_rectangular (); |
|
6782 |
5203
|
6783 #else |
|
6784 (*current_liboctave_error_handler) ("UMFPACK not installed"); |
|
6785 #endif |
5164
|
6786 } |
5785
|
6787 else if (typ != MatrixType::Hermitian) |
5164
|
6788 (*current_liboctave_error_handler) ("incorrect matrix type"); |
|
6789 } |
|
6790 |
|
6791 return retval; |
|
6792 } |
|
6793 |
|
6794 ComplexMatrix |
5785
|
6795 SparseComplexMatrix::solve (MatrixType &mattype, const Matrix& b) const |
5164
|
6796 { |
5275
|
6797 octave_idx_type info; |
5164
|
6798 double rcond; |
|
6799 return solve (mattype, b, info, rcond, 0); |
|
6800 } |
|
6801 |
|
6802 ComplexMatrix |
5785
|
6803 SparseComplexMatrix::solve (MatrixType &mattype, const Matrix& b, |
5275
|
6804 octave_idx_type& info) const |
5164
|
6805 { |
|
6806 double rcond; |
|
6807 return solve (mattype, b, info, rcond, 0); |
|
6808 } |
|
6809 |
|
6810 ComplexMatrix |
5785
|
6811 SparseComplexMatrix::solve (MatrixType &mattype, const Matrix& b, |
5697
|
6812 octave_idx_type& info, double& rcond) const |
5164
|
6813 { |
|
6814 return solve (mattype, b, info, rcond, 0); |
|
6815 } |
|
6816 |
|
6817 ComplexMatrix |
5785
|
6818 SparseComplexMatrix::solve (MatrixType &mattype, const Matrix& b, |
5697
|
6819 octave_idx_type& err, double& rcond, |
|
6820 solve_singularity_handler sing_handler, |
|
6821 bool singular_fallback) const |
5164
|
6822 { |
5681
|
6823 ComplexMatrix retval; |
5322
|
6824 int typ = mattype.type (false); |
5164
|
6825 |
5785
|
6826 if (typ == MatrixType::Unknown) |
5164
|
6827 typ = mattype.type (*this); |
|
6828 |
5785
|
6829 if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) |
5681
|
6830 retval = dsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6831 else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) |
5681
|
6832 retval = utsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6833 else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) |
5681
|
6834 retval = ltsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6835 else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian) |
5681
|
6836 retval = bsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6837 else if (typ == MatrixType::Tridiagonal || |
|
6838 typ == MatrixType::Tridiagonal_Hermitian) |
5681
|
6839 retval = trisolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6840 else if (typ == MatrixType::Full || typ == MatrixType::Hermitian) |
5681
|
6841 retval = fsolve (mattype, b, err, rcond, sing_handler, true); |
5785
|
6842 else if (typ != MatrixType::Rectangular) |
5164
|
6843 { |
5681
|
6844 (*current_liboctave_error_handler) ("unknown matrix type"); |
5164
|
6845 return ComplexMatrix (); |
|
6846 } |
5681
|
6847 |
5785
|
6848 if (singular_fallback && mattype.type(false) == MatrixType::Rectangular) |
5681
|
6849 { |
|
6850 rcond = 1.; |
|
6851 #ifdef USE_QRSOLVE |
|
6852 retval = qrsolve (*this, b, err); |
|
6853 #else |
|
6854 retval = dmsolve<ComplexMatrix, SparseComplexMatrix, |
|
6855 Matrix> (*this, b, err); |
|
6856 #endif |
|
6857 } |
|
6858 |
|
6859 return retval; |
5164
|
6860 } |
|
6861 |
|
6862 SparseComplexMatrix |
5785
|
6863 SparseComplexMatrix::solve (MatrixType &mattype, const SparseMatrix& b) const |
5164
|
6864 { |
5275
|
6865 octave_idx_type info; |
5164
|
6866 double rcond; |
|
6867 return solve (mattype, b, info, rcond, 0); |
|
6868 } |
|
6869 |
|
6870 SparseComplexMatrix |
5785
|
6871 SparseComplexMatrix::solve (MatrixType &mattype, const SparseMatrix& b, |
5275
|
6872 octave_idx_type& info) const |
5164
|
6873 { |
|
6874 double rcond; |
|
6875 return solve (mattype, b, info, rcond, 0); |
|
6876 } |
|
6877 |
|
6878 SparseComplexMatrix |
5785
|
6879 SparseComplexMatrix::solve (MatrixType &mattype, const SparseMatrix& b, |
5275
|
6880 octave_idx_type& info, double& rcond) const |
5164
|
6881 { |
|
6882 return solve (mattype, b, info, rcond, 0); |
|
6883 } |
|
6884 |
|
6885 SparseComplexMatrix |
5785
|
6886 SparseComplexMatrix::solve (MatrixType &mattype, const SparseMatrix& b, |
5275
|
6887 octave_idx_type& err, double& rcond, |
5697
|
6888 solve_singularity_handler sing_handler, |
|
6889 bool singular_fallback) const |
5164
|
6890 { |
5681
|
6891 SparseComplexMatrix retval; |
5322
|
6892 int typ = mattype.type (false); |
5164
|
6893 |
5785
|
6894 if (typ == MatrixType::Unknown) |
5164
|
6895 typ = mattype.type (*this); |
|
6896 |
5785
|
6897 if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) |
5681
|
6898 retval = dsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6899 else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) |
5681
|
6900 retval = utsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6901 else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) |
5681
|
6902 retval = ltsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6903 else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian) |
5681
|
6904 retval = bsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6905 else if (typ == MatrixType::Tridiagonal || |
|
6906 typ == MatrixType::Tridiagonal_Hermitian) |
5681
|
6907 retval = trisolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6908 else if (typ == MatrixType::Full || typ == MatrixType::Hermitian) |
5681
|
6909 retval = fsolve (mattype, b, err, rcond, sing_handler, true); |
5785
|
6910 else if (typ != MatrixType::Rectangular) |
5164
|
6911 { |
5681
|
6912 (*current_liboctave_error_handler) ("unknown matrix type"); |
5164
|
6913 return SparseComplexMatrix (); |
|
6914 } |
5681
|
6915 |
5785
|
6916 if (singular_fallback && mattype.type(false) == MatrixType::Rectangular) |
5681
|
6917 { |
|
6918 rcond = 1.; |
|
6919 #ifdef USE_QRSOLVE |
|
6920 retval = qrsolve (*this, b, err); |
|
6921 #else |
|
6922 retval = dmsolve<SparseComplexMatrix, SparseComplexMatrix, |
|
6923 SparseMatrix> (*this, b, err); |
|
6924 #endif |
|
6925 } |
|
6926 |
|
6927 return retval; |
5164
|
6928 } |
|
6929 |
|
6930 ComplexMatrix |
5785
|
6931 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexMatrix& b) const |
5164
|
6932 { |
5275
|
6933 octave_idx_type info; |
5164
|
6934 double rcond; |
|
6935 return solve (mattype, b, info, rcond, 0); |
|
6936 } |
|
6937 |
|
6938 ComplexMatrix |
5785
|
6939 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexMatrix& b, |
5275
|
6940 octave_idx_type& info) const |
5164
|
6941 { |
|
6942 double rcond; |
|
6943 return solve (mattype, b, info, rcond, 0); |
|
6944 } |
|
6945 |
|
6946 ComplexMatrix |
5785
|
6947 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexMatrix& b, |
5697
|
6948 octave_idx_type& info, double& rcond) const |
5164
|
6949 { |
|
6950 return solve (mattype, b, info, rcond, 0); |
|
6951 } |
|
6952 |
|
6953 ComplexMatrix |
5785
|
6954 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexMatrix& b, |
5697
|
6955 octave_idx_type& err, double& rcond, |
|
6956 solve_singularity_handler sing_handler, |
|
6957 bool singular_fallback) const |
5164
|
6958 { |
5681
|
6959 ComplexMatrix retval; |
5322
|
6960 int typ = mattype.type (false); |
5164
|
6961 |
5785
|
6962 if (typ == MatrixType::Unknown) |
5164
|
6963 typ = mattype.type (*this); |
|
6964 |
5785
|
6965 if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) |
5681
|
6966 retval = dsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6967 else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) |
5681
|
6968 retval = utsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6969 else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) |
5681
|
6970 retval = ltsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6971 else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian) |
5681
|
6972 retval = bsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6973 else if (typ == MatrixType::Tridiagonal || |
|
6974 typ == MatrixType::Tridiagonal_Hermitian) |
5681
|
6975 retval = trisolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
6976 else if (typ == MatrixType::Full || typ == MatrixType::Hermitian) |
5681
|
6977 retval = fsolve (mattype, b, err, rcond, sing_handler, true); |
5785
|
6978 else if (typ != MatrixType::Rectangular) |
5164
|
6979 { |
5681
|
6980 (*current_liboctave_error_handler) ("unknown matrix type"); |
5164
|
6981 return ComplexMatrix (); |
|
6982 } |
5681
|
6983 |
5785
|
6984 if (singular_fallback && mattype.type(false) == MatrixType::Rectangular) |
5681
|
6985 { |
|
6986 rcond = 1.; |
|
6987 #ifdef USE_QRSOLVE |
|
6988 retval = qrsolve (*this, b, err); |
|
6989 #else |
|
6990 retval = dmsolve<ComplexMatrix, SparseComplexMatrix, |
|
6991 ComplexMatrix> (*this, b, err); |
|
6992 #endif |
|
6993 } |
|
6994 |
|
6995 return retval; |
5164
|
6996 } |
|
6997 |
|
6998 SparseComplexMatrix |
5785
|
6999 SparseComplexMatrix::solve (MatrixType &mattype, |
5164
|
7000 const SparseComplexMatrix& b) const |
|
7001 { |
5275
|
7002 octave_idx_type info; |
5164
|
7003 double rcond; |
|
7004 return solve (mattype, b, info, rcond, 0); |
|
7005 } |
|
7006 |
|
7007 SparseComplexMatrix |
5785
|
7008 SparseComplexMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b, |
5697
|
7009 octave_idx_type& info) const |
5164
|
7010 { |
|
7011 double rcond; |
|
7012 return solve (mattype, b, info, rcond, 0); |
|
7013 } |
|
7014 |
|
7015 SparseComplexMatrix |
5785
|
7016 SparseComplexMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b, |
5697
|
7017 octave_idx_type& info, double& rcond) const |
5164
|
7018 { |
|
7019 return solve (mattype, b, info, rcond, 0); |
|
7020 } |
|
7021 |
|
7022 SparseComplexMatrix |
5785
|
7023 SparseComplexMatrix::solve (MatrixType &mattype, const SparseComplexMatrix& b, |
5275
|
7024 octave_idx_type& err, double& rcond, |
5697
|
7025 solve_singularity_handler sing_handler, |
|
7026 bool singular_fallback) const |
5164
|
7027 { |
5681
|
7028 SparseComplexMatrix retval; |
5322
|
7029 int typ = mattype.type (false); |
5164
|
7030 |
5785
|
7031 if (typ == MatrixType::Unknown) |
5164
|
7032 typ = mattype.type (*this); |
|
7033 |
5785
|
7034 if (typ == MatrixType::Diagonal || typ == MatrixType::Permuted_Diagonal) |
5681
|
7035 retval = dsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
7036 else if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) |
5681
|
7037 retval = utsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
7038 else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) |
5681
|
7039 retval = ltsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
7040 else if (typ == MatrixType::Banded || typ == MatrixType::Banded_Hermitian) |
5681
|
7041 retval = bsolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
7042 else if (typ == MatrixType::Tridiagonal || |
|
7043 typ == MatrixType::Tridiagonal_Hermitian) |
5681
|
7044 retval = trisolve (mattype, b, err, rcond, sing_handler, false); |
5785
|
7045 else if (typ == MatrixType::Full || typ == MatrixType::Hermitian) |
5681
|
7046 retval = fsolve (mattype, b, err, rcond, sing_handler, true); |
5785
|
7047 else if (typ != MatrixType::Rectangular) |
5164
|
7048 { |
5681
|
7049 (*current_liboctave_error_handler) ("unknown matrix type"); |
5164
|
7050 return SparseComplexMatrix (); |
|
7051 } |
5681
|
7052 |
5785
|
7053 if (singular_fallback && mattype.type(false) == MatrixType::Rectangular) |
5681
|
7054 { |
|
7055 rcond = 1.; |
|
7056 #ifdef USE_QRSOLVE |
|
7057 retval = qrsolve (*this, b, err); |
|
7058 #else |
|
7059 retval = dmsolve<SparseComplexMatrix, SparseComplexMatrix, |
|
7060 SparseComplexMatrix> (*this, b, err); |
|
7061 #endif |
|
7062 } |
|
7063 |
|
7064 return retval; |
5164
|
7065 } |
|
7066 |
|
7067 ComplexColumnVector |
5785
|
7068 SparseComplexMatrix::solve (MatrixType &mattype, const ColumnVector& b) const |
5164
|
7069 { |
5275
|
7070 octave_idx_type info; double rcond; |
5164
|
7071 return solve (mattype, b, info, rcond); |
|
7072 } |
|
7073 |
|
7074 ComplexColumnVector |
5785
|
7075 SparseComplexMatrix::solve (MatrixType &mattype, const ColumnVector& b, |
5275
|
7076 octave_idx_type& info) const |
5164
|
7077 { |
|
7078 double rcond; |
|
7079 return solve (mattype, b, info, rcond); |
|
7080 } |
|
7081 |
|
7082 ComplexColumnVector |
5785
|
7083 SparseComplexMatrix::solve (MatrixType &mattype, const ColumnVector& b, |
5275
|
7084 octave_idx_type& info, double& rcond) const |
5164
|
7085 { |
|
7086 return solve (mattype, b, info, rcond, 0); |
|
7087 } |
|
7088 |
|
7089 ComplexColumnVector |
5785
|
7090 SparseComplexMatrix::solve (MatrixType &mattype, const ColumnVector& b, |
5275
|
7091 octave_idx_type& info, double& rcond, |
5164
|
7092 solve_singularity_handler sing_handler) const |
|
7093 { |
|
7094 Matrix tmp (b); |
5275
|
7095 return solve (mattype, tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0)); |
5164
|
7096 } |
|
7097 |
|
7098 ComplexColumnVector |
5785
|
7099 SparseComplexMatrix::solve (MatrixType &mattype, |
5164
|
7100 const ComplexColumnVector& b) const |
|
7101 { |
5275
|
7102 octave_idx_type info; |
5164
|
7103 double rcond; |
|
7104 return solve (mattype, b, info, rcond, 0); |
|
7105 } |
|
7106 |
|
7107 ComplexColumnVector |
5785
|
7108 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b, |
5275
|
7109 octave_idx_type& info) const |
5164
|
7110 { |
|
7111 double rcond; |
|
7112 return solve (mattype, b, info, rcond, 0); |
|
7113 } |
|
7114 |
|
7115 ComplexColumnVector |
5785
|
7116 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b, |
5275
|
7117 octave_idx_type& info, double& rcond) const |
5164
|
7118 { |
|
7119 return solve (mattype, b, info, rcond, 0); |
|
7120 } |
|
7121 |
|
7122 ComplexColumnVector |
5785
|
7123 SparseComplexMatrix::solve (MatrixType &mattype, const ComplexColumnVector& b, |
5275
|
7124 octave_idx_type& info, double& rcond, |
5164
|
7125 solve_singularity_handler sing_handler) const |
|
7126 { |
|
7127 ComplexMatrix tmp (b); |
5275
|
7128 return solve (mattype, tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0)); |
5164
|
7129 } |
|
7130 |
|
7131 ComplexMatrix |
|
7132 SparseComplexMatrix::solve (const Matrix& b) const |
|
7133 { |
5275
|
7134 octave_idx_type info; |
5164
|
7135 double rcond; |
|
7136 return solve (b, info, rcond, 0); |
|
7137 } |
|
7138 |
|
7139 ComplexMatrix |
5275
|
7140 SparseComplexMatrix::solve (const Matrix& b, octave_idx_type& info) const |
5164
|
7141 { |
|
7142 double rcond; |
|
7143 return solve (b, info, rcond, 0); |
|
7144 } |
|
7145 |
|
7146 ComplexMatrix |
5275
|
7147 SparseComplexMatrix::solve (const Matrix& b, octave_idx_type& info, |
5164
|
7148 double& rcond) const |
|
7149 { |
|
7150 return solve (b, info, rcond, 0); |
|
7151 } |
|
7152 |
|
7153 ComplexMatrix |
5275
|
7154 SparseComplexMatrix::solve (const Matrix& b, octave_idx_type& err, |
5164
|
7155 double& rcond, |
|
7156 solve_singularity_handler sing_handler) const |
|
7157 { |
5785
|
7158 MatrixType mattype (*this); |
5164
|
7159 return solve (mattype, b, err, rcond, sing_handler); |
|
7160 } |
|
7161 |
|
7162 SparseComplexMatrix |
|
7163 SparseComplexMatrix::solve (const SparseMatrix& b) const |
|
7164 { |
5275
|
7165 octave_idx_type info; |
5164
|
7166 double rcond; |
|
7167 return solve (b, info, rcond, 0); |
|
7168 } |
|
7169 |
|
7170 SparseComplexMatrix |
|
7171 SparseComplexMatrix::solve (const SparseMatrix& b, |
5275
|
7172 octave_idx_type& info) const |
5164
|
7173 { |
|
7174 double rcond; |
|
7175 return solve (b, info, rcond, 0); |
|
7176 } |
|
7177 |
|
7178 SparseComplexMatrix |
|
7179 SparseComplexMatrix::solve (const SparseMatrix& b, |
5275
|
7180 octave_idx_type& info, double& rcond) const |
5164
|
7181 { |
|
7182 return solve (b, info, rcond, 0); |
|
7183 } |
|
7184 |
|
7185 SparseComplexMatrix |
|
7186 SparseComplexMatrix::solve (const SparseMatrix& b, |
5275
|
7187 octave_idx_type& err, double& rcond, |
5164
|
7188 solve_singularity_handler sing_handler) const |
|
7189 { |
5785
|
7190 MatrixType mattype (*this); |
5164
|
7191 return solve (mattype, b, err, rcond, sing_handler); |
|
7192 } |
|
7193 |
|
7194 ComplexMatrix |
|
7195 SparseComplexMatrix::solve (const ComplexMatrix& b, |
5275
|
7196 octave_idx_type& info) const |
5164
|
7197 { |
|
7198 double rcond; |
|
7199 return solve (b, info, rcond, 0); |
|
7200 } |
|
7201 |
|
7202 ComplexMatrix |
|
7203 SparseComplexMatrix::solve (const ComplexMatrix& b, |
5275
|
7204 octave_idx_type& info, double& rcond) const |
5164
|
7205 { |
|
7206 return solve (b, info, rcond, 0); |
|
7207 } |
|
7208 |
|
7209 ComplexMatrix |
|
7210 SparseComplexMatrix::solve (const ComplexMatrix& b, |
5275
|
7211 octave_idx_type& err, double& rcond, |
5164
|
7212 solve_singularity_handler sing_handler) const |
|
7213 { |
5785
|
7214 MatrixType mattype (*this); |
5164
|
7215 return solve (mattype, b, err, rcond, sing_handler); |
|
7216 } |
|
7217 |
|
7218 SparseComplexMatrix |
|
7219 SparseComplexMatrix::solve (const SparseComplexMatrix& b) const |
|
7220 { |
5275
|
7221 octave_idx_type info; |
5164
|
7222 double rcond; |
|
7223 return solve (b, info, rcond, 0); |
|
7224 } |
|
7225 |
|
7226 SparseComplexMatrix |
|
7227 SparseComplexMatrix::solve (const SparseComplexMatrix& b, |
5275
|
7228 octave_idx_type& info) const |
5164
|
7229 { |
|
7230 double rcond; |
|
7231 return solve (b, info, rcond, 0); |
|
7232 } |
|
7233 |
|
7234 SparseComplexMatrix |
|
7235 SparseComplexMatrix::solve (const SparseComplexMatrix& b, |
5275
|
7236 octave_idx_type& info, double& rcond) const |
5164
|
7237 { |
|
7238 return solve (b, info, rcond, 0); |
|
7239 } |
|
7240 |
|
7241 SparseComplexMatrix |
|
7242 SparseComplexMatrix::solve (const SparseComplexMatrix& b, |
5275
|
7243 octave_idx_type& err, double& rcond, |
5164
|
7244 solve_singularity_handler sing_handler) const |
|
7245 { |
5785
|
7246 MatrixType mattype (*this); |
5164
|
7247 return solve (mattype, b, err, rcond, sing_handler); |
|
7248 } |
|
7249 |
|
7250 ComplexColumnVector |
|
7251 SparseComplexMatrix::solve (const ColumnVector& b) const |
|
7252 { |
5275
|
7253 octave_idx_type info; double rcond; |
5164
|
7254 return solve (b, info, rcond); |
|
7255 } |
|
7256 |
|
7257 ComplexColumnVector |
5275
|
7258 SparseComplexMatrix::solve (const ColumnVector& b, octave_idx_type& info) const |
5164
|
7259 { |
|
7260 double rcond; |
|
7261 return solve (b, info, rcond); |
|
7262 } |
|
7263 |
|
7264 ComplexColumnVector |
5275
|
7265 SparseComplexMatrix::solve (const ColumnVector& b, octave_idx_type& info, |
5164
|
7266 double& rcond) const |
|
7267 { |
|
7268 return solve (b, info, rcond, 0); |
|
7269 } |
|
7270 |
|
7271 ComplexColumnVector |
5275
|
7272 SparseComplexMatrix::solve (const ColumnVector& b, octave_idx_type& info, double& rcond, |
5164
|
7273 solve_singularity_handler sing_handler) const |
|
7274 { |
|
7275 Matrix tmp (b); |
5275
|
7276 return solve (tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0)); |
5164
|
7277 } |
|
7278 |
|
7279 ComplexColumnVector |
|
7280 SparseComplexMatrix::solve (const ComplexColumnVector& b) const |
|
7281 { |
5275
|
7282 octave_idx_type info; |
5164
|
7283 double rcond; |
|
7284 return solve (b, info, rcond, 0); |
|
7285 } |
|
7286 |
|
7287 ComplexColumnVector |
5275
|
7288 SparseComplexMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info) const |
5164
|
7289 { |
|
7290 double rcond; |
|
7291 return solve (b, info, rcond, 0); |
|
7292 } |
|
7293 |
|
7294 ComplexColumnVector |
5275
|
7295 SparseComplexMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info, |
5164
|
7296 double& rcond) const |
|
7297 { |
|
7298 return solve (b, info, rcond, 0); |
|
7299 } |
|
7300 |
|
7301 ComplexColumnVector |
5275
|
7302 SparseComplexMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info, |
5164
|
7303 double& rcond, |
|
7304 solve_singularity_handler sing_handler) const |
|
7305 { |
|
7306 ComplexMatrix tmp (b); |
5275
|
7307 return solve (tmp, info, rcond, sing_handler).column (static_cast<octave_idx_type> (0)); |
5164
|
7308 } |
|
7309 |
|
7310 // unary operations |
|
7311 SparseBoolMatrix |
|
7312 SparseComplexMatrix::operator ! (void) const |
|
7313 { |
5275
|
7314 octave_idx_type nr = rows (); |
|
7315 octave_idx_type nc = cols (); |
5681
|
7316 octave_idx_type nz1 = nnz (); |
5275
|
7317 octave_idx_type nz2 = nr*nc - nz1; |
5164
|
7318 |
|
7319 SparseBoolMatrix r (nr, nc, nz2); |
|
7320 |
5275
|
7321 octave_idx_type ii = 0; |
|
7322 octave_idx_type jj = 0; |
5164
|
7323 r.cidx (0) = 0; |
5275
|
7324 for (octave_idx_type i = 0; i < nc; i++) |
5164
|
7325 { |
5275
|
7326 for (octave_idx_type j = 0; j < nr; j++) |
5164
|
7327 { |
|
7328 if (jj < cidx(i+1) && ridx(jj) == j) |
|
7329 jj++; |
|
7330 else |
|
7331 { |
|
7332 r.data(ii) = true; |
|
7333 r.ridx(ii++) = j; |
|
7334 } |
|
7335 } |
|
7336 r.cidx (i+1) = ii; |
|
7337 } |
|
7338 |
|
7339 return r; |
|
7340 } |
|
7341 |
|
7342 SparseComplexMatrix |
|
7343 SparseComplexMatrix::squeeze (void) const |
|
7344 { |
|
7345 return MSparse<Complex>::squeeze (); |
|
7346 } |
|
7347 |
|
7348 SparseComplexMatrix |
|
7349 SparseComplexMatrix::index (idx_vector& i, int resize_ok) const |
|
7350 { |
|
7351 return MSparse<Complex>::index (i, resize_ok); |
|
7352 } |
|
7353 |
|
7354 SparseComplexMatrix |
|
7355 SparseComplexMatrix::index (idx_vector& i, idx_vector& j, int resize_ok) const |
|
7356 { |
|
7357 return MSparse<Complex>::index (i, j, resize_ok); |
|
7358 } |
|
7359 |
|
7360 SparseComplexMatrix |
|
7361 SparseComplexMatrix::index (Array<idx_vector>& ra_idx, int resize_ok) const |
|
7362 { |
|
7363 return MSparse<Complex>::index (ra_idx, resize_ok); |
|
7364 } |
|
7365 SparseComplexMatrix |
|
7366 SparseComplexMatrix::reshape (const dim_vector& new_dims) const |
|
7367 { |
|
7368 return MSparse<Complex>::reshape (new_dims); |
|
7369 } |
|
7370 |
|
7371 SparseComplexMatrix |
5275
|
7372 SparseComplexMatrix::permute (const Array<octave_idx_type>& vec, bool inv) const |
5164
|
7373 { |
|
7374 return MSparse<Complex>::permute (vec, inv); |
|
7375 } |
|
7376 |
|
7377 SparseComplexMatrix |
5275
|
7378 SparseComplexMatrix::ipermute (const Array<octave_idx_type>& vec) const |
5164
|
7379 { |
|
7380 return MSparse<Complex>::ipermute (vec); |
|
7381 } |
|
7382 |
|
7383 // other operations |
|
7384 |
|
7385 SparseComplexMatrix |
|
7386 SparseComplexMatrix::map (c_c_Mapper f) const |
|
7387 { |
5275
|
7388 octave_idx_type nr = rows (); |
|
7389 octave_idx_type nc = cols (); |
5681
|
7390 octave_idx_type nz = nnz (); |
5164
|
7391 bool f_zero = (f(0.0) == 0.0); |
|
7392 |
|
7393 // Count number of non-zero elements |
5275
|
7394 octave_idx_type nel = (f_zero ? 0 : nr*nc - nz); |
|
7395 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
7396 if (f (data(i)) != 0.0) |
|
7397 nel++; |
|
7398 |
|
7399 SparseComplexMatrix retval (nr, nc, nel); |
|
7400 |
|
7401 if (f_zero) |
|
7402 { |
5275
|
7403 octave_idx_type ii = 0; |
|
7404 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
7405 { |
5275
|
7406 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
7407 { |
|
7408 Complex tmp = f (elem (i, j)); |
|
7409 if (tmp != 0.0) |
|
7410 { |
|
7411 retval.data(ii) = tmp; |
|
7412 retval.ridx(ii++) = i; |
|
7413 } |
|
7414 } |
|
7415 retval.cidx(j+1) = ii; |
|
7416 } |
|
7417 } |
|
7418 else |
|
7419 { |
5275
|
7420 octave_idx_type ii = 0; |
|
7421 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
7422 { |
5275
|
7423 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
7424 { |
|
7425 retval.data(ii) = f (elem(i)); |
|
7426 retval.ridx(ii++) = ridx(i); |
|
7427 } |
|
7428 retval.cidx(j+1) = ii; |
|
7429 } |
|
7430 } |
|
7431 |
|
7432 return retval; |
|
7433 } |
|
7434 |
|
7435 SparseMatrix |
|
7436 SparseComplexMatrix::map (d_c_Mapper f) const |
|
7437 { |
5275
|
7438 octave_idx_type nr = rows (); |
|
7439 octave_idx_type nc = cols (); |
5681
|
7440 octave_idx_type nz = nnz (); |
5164
|
7441 bool f_zero = (f(0.0) == 0.0); |
|
7442 |
|
7443 // Count number of non-zero elements |
5275
|
7444 octave_idx_type nel = (f_zero ? 0 : nr*nc - nz); |
|
7445 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
7446 if (f (data(i)) != 0.0) |
|
7447 nel++; |
|
7448 |
|
7449 SparseMatrix retval (nr, nc, nel); |
|
7450 |
|
7451 if (f_zero) |
|
7452 { |
5275
|
7453 octave_idx_type ii = 0; |
|
7454 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
7455 { |
5275
|
7456 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
7457 { |
|
7458 double tmp = f (elem (i, j)); |
|
7459 if (tmp != 0.0) |
|
7460 { |
|
7461 retval.data(ii) = tmp; |
|
7462 retval.ridx(ii++) = i; |
|
7463 } |
|
7464 } |
|
7465 retval.cidx(j+1) = ii; |
|
7466 } |
|
7467 } |
|
7468 else |
|
7469 { |
5275
|
7470 octave_idx_type ii = 0; |
|
7471 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
7472 { |
5275
|
7473 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
7474 { |
|
7475 retval.data(ii) = f (elem(i)); |
|
7476 retval.ridx(ii++) = ridx(i); |
|
7477 } |
|
7478 retval.cidx(j+1) = ii; |
|
7479 } |
|
7480 } |
|
7481 |
|
7482 return retval; |
|
7483 } |
|
7484 |
|
7485 SparseBoolMatrix |
|
7486 SparseComplexMatrix::map (b_c_Mapper f) const |
|
7487 { |
5275
|
7488 octave_idx_type nr = rows (); |
|
7489 octave_idx_type nc = cols (); |
5681
|
7490 octave_idx_type nz = nnz (); |
5164
|
7491 bool f_zero = f(0.0); |
|
7492 |
|
7493 // Count number of non-zero elements |
5275
|
7494 octave_idx_type nel = (f_zero ? 0 : nr*nc - nz); |
|
7495 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
7496 if (f (data(i)) != 0.0) |
|
7497 nel++; |
|
7498 |
|
7499 SparseBoolMatrix retval (nr, nc, nel); |
|
7500 |
|
7501 if (f_zero) |
|
7502 { |
5275
|
7503 octave_idx_type ii = 0; |
|
7504 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
7505 { |
5275
|
7506 for (octave_idx_type i = 0; i < nr; i++) |
5164
|
7507 { |
|
7508 bool tmp = f (elem (i, j)); |
|
7509 if (tmp) |
|
7510 { |
|
7511 retval.data(ii) = tmp; |
|
7512 retval.ridx(ii++) = i; |
|
7513 } |
|
7514 } |
|
7515 retval.cidx(j+1) = ii; |
|
7516 } |
|
7517 } |
|
7518 else |
|
7519 { |
5275
|
7520 octave_idx_type ii = 0; |
|
7521 for (octave_idx_type j = 0; j < nc; j++) |
5164
|
7522 { |
5275
|
7523 for (octave_idx_type i = cidx(j); i < cidx(j+1); i++) |
5164
|
7524 { |
|
7525 retval.data(ii) = f (elem(i)); |
|
7526 retval.ridx(ii++) = ridx(i); |
|
7527 } |
|
7528 retval.cidx(j+1) = ii; |
|
7529 } |
|
7530 } |
|
7531 |
|
7532 return retval; |
|
7533 } |
|
7534 |
|
7535 SparseComplexMatrix& |
|
7536 SparseComplexMatrix::apply (c_c_Mapper f) |
|
7537 { |
|
7538 *this = map (f); |
|
7539 return *this; |
|
7540 } |
|
7541 |
|
7542 bool |
|
7543 SparseComplexMatrix::any_element_is_inf_or_nan (void) const |
|
7544 { |
5681
|
7545 octave_idx_type nel = nnz (); |
5275
|
7546 |
|
7547 for (octave_idx_type i = 0; i < nel; i++) |
5164
|
7548 { |
|
7549 Complex val = data (i); |
|
7550 if (xisinf (val) || xisnan (val)) |
|
7551 return true; |
|
7552 } |
|
7553 |
|
7554 return false; |
|
7555 } |
|
7556 |
|
7557 // Return true if no elements have imaginary components. |
|
7558 |
|
7559 bool |
|
7560 SparseComplexMatrix::all_elements_are_real (void) const |
|
7561 { |
5681
|
7562 octave_idx_type nel = nnz (); |
5275
|
7563 |
|
7564 for (octave_idx_type i = 0; i < nel; i++) |
5164
|
7565 { |
5261
|
7566 double ip = std::imag (data (i)); |
5164
|
7567 |
|
7568 if (ip != 0.0 || lo_ieee_signbit (ip)) |
|
7569 return false; |
|
7570 } |
|
7571 |
|
7572 return true; |
|
7573 } |
|
7574 |
|
7575 // Return nonzero if any element of CM has a non-integer real or |
|
7576 // imaginary part. Also extract the largest and smallest (real or |
|
7577 // imaginary) values and return them in MAX_VAL and MIN_VAL. |
|
7578 |
|
7579 bool |
|
7580 SparseComplexMatrix::all_integers (double& max_val, double& min_val) const |
|
7581 { |
5681
|
7582 octave_idx_type nel = nnz (); |
5164
|
7583 |
|
7584 if (nel == 0) |
|
7585 return false; |
|
7586 |
5261
|
7587 max_val = std::real(data (0)); |
|
7588 min_val = std::real(data (0)); |
5164
|
7589 |
5275
|
7590 for (octave_idx_type i = 0; i < nel; i++) |
5164
|
7591 { |
|
7592 Complex val = data (i); |
|
7593 |
5261
|
7594 double r_val = std::real (val); |
|
7595 double i_val = std::imag (val); |
5164
|
7596 |
|
7597 if (r_val > max_val) |
|
7598 max_val = r_val; |
|
7599 |
|
7600 if (i_val > max_val) |
|
7601 max_val = i_val; |
|
7602 |
|
7603 if (r_val < min_val) |
|
7604 min_val = r_val; |
|
7605 |
|
7606 if (i_val < min_val) |
|
7607 min_val = i_val; |
|
7608 |
|
7609 if (D_NINT (r_val) != r_val || D_NINT (i_val) != i_val) |
|
7610 return false; |
|
7611 } |
|
7612 |
|
7613 return true; |
|
7614 } |
|
7615 |
|
7616 bool |
|
7617 SparseComplexMatrix::too_large_for_float (void) const |
|
7618 { |
5681
|
7619 octave_idx_type nel = nnz (); |
5275
|
7620 |
|
7621 for (octave_idx_type i = 0; i < nel; i++) |
5164
|
7622 { |
|
7623 Complex val = data (i); |
|
7624 |
5261
|
7625 double r_val = std::real (val); |
|
7626 double i_val = std::imag (val); |
5164
|
7627 |
|
7628 if (r_val > FLT_MAX |
|
7629 || i_val > FLT_MAX |
|
7630 || r_val < FLT_MIN |
|
7631 || i_val < FLT_MIN) |
|
7632 return true; |
|
7633 } |
|
7634 |
|
7635 return false; |
|
7636 } |
|
7637 |
5775
|
7638 // FIXME Do these really belong here? Maybe they should be |
5164
|
7639 // in a base class? |
|
7640 |
|
7641 SparseBoolMatrix |
|
7642 SparseComplexMatrix::all (int dim) const |
|
7643 { |
|
7644 SPARSE_ALL_OP (dim); |
|
7645 } |
|
7646 |
|
7647 SparseBoolMatrix |
|
7648 SparseComplexMatrix::any (int dim) const |
|
7649 { |
|
7650 SPARSE_ANY_OP (dim); |
|
7651 } |
|
7652 |
|
7653 SparseComplexMatrix |
|
7654 SparseComplexMatrix::cumprod (int dim) const |
|
7655 { |
|
7656 SPARSE_CUMPROD (SparseComplexMatrix, Complex, cumprod); |
|
7657 } |
|
7658 |
|
7659 SparseComplexMatrix |
|
7660 SparseComplexMatrix::cumsum (int dim) const |
|
7661 { |
|
7662 SPARSE_CUMSUM (SparseComplexMatrix, Complex, cumsum); |
|
7663 } |
|
7664 |
|
7665 SparseComplexMatrix |
|
7666 SparseComplexMatrix::prod (int dim) const |
|
7667 { |
|
7668 SPARSE_REDUCTION_OP (SparseComplexMatrix, Complex, *=, 1.0, 1.0); |
|
7669 } |
|
7670 |
|
7671 SparseComplexMatrix |
|
7672 SparseComplexMatrix::sum (int dim) const |
|
7673 { |
|
7674 SPARSE_REDUCTION_OP (SparseComplexMatrix, Complex, +=, 0.0, 0.0); |
|
7675 } |
|
7676 |
|
7677 SparseComplexMatrix |
|
7678 SparseComplexMatrix::sumsq (int dim) const |
|
7679 { |
|
7680 #define ROW_EXPR \ |
|
7681 Complex d = elem (i, j); \ |
|
7682 tmp [i] += d * conj (d) |
|
7683 |
|
7684 #define COL_EXPR \ |
|
7685 Complex d = elem (i, j); \ |
|
7686 tmp [j] += d * conj (d) |
|
7687 |
|
7688 SPARSE_BASE_REDUCTION_OP (SparseComplexMatrix, Complex, ROW_EXPR, |
|
7689 COL_EXPR, 0.0, 0.0); |
|
7690 |
|
7691 #undef ROW_EXPR |
|
7692 #undef COL_EXPR |
|
7693 } |
|
7694 |
|
7695 SparseMatrix SparseComplexMatrix::abs (void) const |
|
7696 { |
5681
|
7697 octave_idx_type nz = nnz (); |
5275
|
7698 octave_idx_type nc = cols (); |
5164
|
7699 |
|
7700 SparseMatrix retval (rows(), nc, nz); |
|
7701 |
5275
|
7702 for (octave_idx_type i = 0; i < nc + 1; i++) |
5164
|
7703 retval.cidx (i) = cidx (i); |
|
7704 |
5275
|
7705 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
7706 { |
5261
|
7707 retval.data (i) = std::abs (data (i)); |
5164
|
7708 retval.ridx (i) = ridx (i); |
|
7709 } |
|
7710 |
|
7711 return retval; |
|
7712 } |
|
7713 |
|
7714 SparseComplexMatrix |
5275
|
7715 SparseComplexMatrix::diag (octave_idx_type k) const |
5164
|
7716 { |
5275
|
7717 octave_idx_type nnr = rows (); |
|
7718 octave_idx_type nnc = cols (); |
5164
|
7719 |
|
7720 if (k > 0) |
|
7721 nnc -= k; |
|
7722 else if (k < 0) |
|
7723 nnr += k; |
|
7724 |
|
7725 SparseComplexMatrix d; |
|
7726 |
|
7727 if (nnr > 0 && nnc > 0) |
|
7728 { |
5275
|
7729 octave_idx_type ndiag = (nnr < nnc) ? nnr : nnc; |
5164
|
7730 |
|
7731 // Count the number of non-zero elements |
5275
|
7732 octave_idx_type nel = 0; |
5164
|
7733 if (k > 0) |
|
7734 { |
5275
|
7735 for (octave_idx_type i = 0; i < ndiag; i++) |
5164
|
7736 if (elem (i, i+k) != 0.) |
|
7737 nel++; |
|
7738 } |
|
7739 else if ( k < 0) |
|
7740 { |
5275
|
7741 for (octave_idx_type i = 0; i < ndiag; i++) |
5164
|
7742 if (elem (i-k, i) != 0.) |
|
7743 nel++; |
|
7744 } |
|
7745 else |
|
7746 { |
5275
|
7747 for (octave_idx_type i = 0; i < ndiag; i++) |
5164
|
7748 if (elem (i, i) != 0.) |
|
7749 nel++; |
|
7750 } |
|
7751 |
|
7752 d = SparseComplexMatrix (ndiag, 1, nel); |
|
7753 d.xcidx (0) = 0; |
|
7754 d.xcidx (1) = nel; |
|
7755 |
5275
|
7756 octave_idx_type ii = 0; |
5164
|
7757 if (k > 0) |
|
7758 { |
5275
|
7759 for (octave_idx_type i = 0; i < ndiag; i++) |
5164
|
7760 { |
|
7761 Complex tmp = elem (i, i+k); |
|
7762 if (tmp != 0.) |
|
7763 { |
|
7764 d.xdata (ii) = tmp; |
|
7765 d.xridx (ii++) = i; |
|
7766 } |
|
7767 } |
|
7768 } |
|
7769 else if ( k < 0) |
|
7770 { |
5275
|
7771 for (octave_idx_type i = 0; i < ndiag; i++) |
5164
|
7772 { |
|
7773 Complex tmp = elem (i-k, i); |
|
7774 if (tmp != 0.) |
|
7775 { |
|
7776 d.xdata (ii) = tmp; |
|
7777 d.xridx (ii++) = i; |
|
7778 } |
|
7779 } |
|
7780 } |
|
7781 else |
|
7782 { |
5275
|
7783 for (octave_idx_type i = 0; i < ndiag; i++) |
5164
|
7784 { |
|
7785 Complex tmp = elem (i, i); |
|
7786 if (tmp != 0.) |
|
7787 { |
|
7788 d.xdata (ii) = tmp; |
|
7789 d.xridx (ii++) = i; |
|
7790 } |
|
7791 } |
|
7792 } |
|
7793 } |
|
7794 else |
|
7795 (*current_liboctave_error_handler) |
|
7796 ("diag: requested diagonal out of range"); |
|
7797 |
|
7798 return d; |
|
7799 } |
|
7800 |
|
7801 std::ostream& |
|
7802 operator << (std::ostream& os, const SparseComplexMatrix& a) |
|
7803 { |
5275
|
7804 octave_idx_type nc = a.cols (); |
5164
|
7805 |
|
7806 // add one to the printed indices to go from |
|
7807 // zero-based to one-based arrays |
5275
|
7808 for (octave_idx_type j = 0; j < nc; j++) { |
5164
|
7809 OCTAVE_QUIT; |
5275
|
7810 for (octave_idx_type i = a.cidx(j); i < a.cidx(j+1); i++) { |
5164
|
7811 os << a.ridx(i) + 1 << " " << j + 1 << " "; |
|
7812 octave_write_complex (os, a.data(i)); |
|
7813 os << "\n"; |
|
7814 } |
|
7815 } |
|
7816 |
|
7817 return os; |
|
7818 } |
|
7819 |
|
7820 std::istream& |
|
7821 operator >> (std::istream& is, SparseComplexMatrix& a) |
|
7822 { |
5275
|
7823 octave_idx_type nr = a.rows (); |
|
7824 octave_idx_type nc = a.cols (); |
5604
|
7825 octave_idx_type nz = a.nzmax (); |
5164
|
7826 |
|
7827 if (nr < 1 || nc < 1) |
|
7828 is.clear (std::ios::badbit); |
|
7829 else |
|
7830 { |
5275
|
7831 octave_idx_type itmp, jtmp, jold = 0; |
5164
|
7832 Complex tmp; |
5275
|
7833 octave_idx_type ii = 0; |
5164
|
7834 |
|
7835 a.cidx (0) = 0; |
5275
|
7836 for (octave_idx_type i = 0; i < nz; i++) |
5164
|
7837 { |
|
7838 is >> itmp; |
|
7839 itmp--; |
|
7840 is >> jtmp; |
|
7841 jtmp--; |
|
7842 tmp = octave_read_complex (is); |
|
7843 |
|
7844 if (is) |
|
7845 { |
|
7846 if (jold != jtmp) |
|
7847 { |
5275
|
7848 for (octave_idx_type j = jold; j < jtmp; j++) |
5164
|
7849 a.cidx(j+1) = ii; |
|
7850 |
|
7851 jold = jtmp; |
|
7852 } |
|
7853 a.data (ii) = tmp; |
|
7854 a.ridx (ii++) = itmp; |
|
7855 } |
|
7856 else |
|
7857 goto done; |
|
7858 } |
|
7859 |
5275
|
7860 for (octave_idx_type j = jold; j < nc; j++) |
5164
|
7861 a.cidx(j+1) = ii; |
|
7862 } |
|
7863 |
|
7864 done: |
|
7865 |
|
7866 return is; |
|
7867 } |
|
7868 |
|
7869 SparseComplexMatrix |
|
7870 operator * (const SparseComplexMatrix& m, const SparseMatrix& a) |
|
7871 { |
5681
|
7872 SPARSE_SPARSE_MUL (SparseComplexMatrix, Complex, double); |
5164
|
7873 } |
|
7874 |
|
7875 SparseComplexMatrix |
|
7876 operator * (const SparseMatrix& m, const SparseComplexMatrix& a) |
|
7877 { |
5681
|
7878 SPARSE_SPARSE_MUL (SparseComplexMatrix, Complex, Complex); |
5164
|
7879 } |
|
7880 |
|
7881 SparseComplexMatrix |
|
7882 operator * (const SparseComplexMatrix& m, const SparseComplexMatrix& a) |
|
7883 { |
5681
|
7884 SPARSE_SPARSE_MUL (SparseComplexMatrix, Complex, Complex); |
5164
|
7885 } |
|
7886 |
5429
|
7887 ComplexMatrix |
|
7888 operator * (const ComplexMatrix& m, const SparseMatrix& a) |
|
7889 { |
5681
|
7890 FULL_SPARSE_MUL (ComplexMatrix, double, Complex (0.,0.)); |
5429
|
7891 } |
|
7892 |
|
7893 ComplexMatrix |
|
7894 operator * (const Matrix& m, const SparseComplexMatrix& a) |
|
7895 { |
5681
|
7896 FULL_SPARSE_MUL (ComplexMatrix, Complex, Complex (0.,0.)); |
5429
|
7897 } |
|
7898 |
|
7899 ComplexMatrix |
|
7900 operator * (const ComplexMatrix& m, const SparseComplexMatrix& a) |
|
7901 { |
5681
|
7902 FULL_SPARSE_MUL (ComplexMatrix, Complex, Complex (0.,0.)); |
5429
|
7903 } |
|
7904 |
|
7905 ComplexMatrix |
|
7906 operator * (const SparseComplexMatrix& m, const Matrix& a) |
|
7907 { |
5681
|
7908 SPARSE_FULL_MUL (ComplexMatrix, double, Complex (0.,0.)); |
5429
|
7909 } |
|
7910 |
|
7911 ComplexMatrix |
|
7912 operator * (const SparseMatrix& m, const ComplexMatrix& a) |
|
7913 { |
5681
|
7914 SPARSE_FULL_MUL (ComplexMatrix, Complex, Complex (0.,0.)); |
5429
|
7915 } |
|
7916 |
|
7917 ComplexMatrix |
|
7918 operator * (const SparseComplexMatrix& m, const ComplexMatrix& a) |
|
7919 { |
5681
|
7920 SPARSE_FULL_MUL (ComplexMatrix, Complex, Complex (0.,0.)); |
5429
|
7921 } |
|
7922 |
5775
|
7923 // FIXME -- it would be nice to share code among the min/max |
5164
|
7924 // functions below. |
|
7925 |
|
7926 #define EMPTY_RETURN_CHECK(T) \ |
|
7927 if (nr == 0 || nc == 0) \ |
|
7928 return T (nr, nc); |
|
7929 |
|
7930 SparseComplexMatrix |
|
7931 min (const Complex& c, const SparseComplexMatrix& m) |
|
7932 { |
|
7933 SparseComplexMatrix result; |
|
7934 |
5275
|
7935 octave_idx_type nr = m.rows (); |
|
7936 octave_idx_type nc = m.columns (); |
5164
|
7937 |
|
7938 EMPTY_RETURN_CHECK (SparseComplexMatrix); |
|
7939 |
|
7940 if (abs(c) == 0.) |
|
7941 return SparseComplexMatrix (nr, nc); |
|
7942 else |
|
7943 { |
|
7944 result = SparseComplexMatrix (m); |
|
7945 |
5275
|
7946 for (octave_idx_type j = 0; j < nc; j++) |
|
7947 for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++) |
5164
|
7948 result.data(i) = xmin(c, m.data(i)); |
|
7949 } |
|
7950 |
|
7951 return result; |
|
7952 } |
|
7953 |
|
7954 SparseComplexMatrix |
|
7955 min (const SparseComplexMatrix& m, const Complex& c) |
|
7956 { |
|
7957 return min (c, m); |
|
7958 } |
|
7959 |
|
7960 SparseComplexMatrix |
|
7961 min (const SparseComplexMatrix& a, const SparseComplexMatrix& b) |
|
7962 { |
|
7963 SparseComplexMatrix r; |
|
7964 |
|
7965 if ((a.rows() == b.rows()) && (a.cols() == b.cols())) |
|
7966 { |
5275
|
7967 octave_idx_type a_nr = a.rows (); |
|
7968 octave_idx_type a_nc = a.cols (); |
|
7969 |
|
7970 octave_idx_type b_nr = b.rows (); |
|
7971 octave_idx_type b_nc = b.cols (); |
5164
|
7972 |
5681
|
7973 if (a_nr == 0 || b_nc == 0 || a.nnz () == 0 || b.nnz () == 0) |
5164
|
7974 return SparseComplexMatrix (a_nr, a_nc); |
|
7975 |
|
7976 if (a_nr != b_nr || a_nc != b_nc) |
|
7977 gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); |
|
7978 else |
|
7979 { |
5681
|
7980 r = SparseComplexMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); |
5164
|
7981 |
5275
|
7982 octave_idx_type jx = 0; |
5164
|
7983 r.cidx (0) = 0; |
5275
|
7984 for (octave_idx_type i = 0 ; i < a_nc ; i++) |
5164
|
7985 { |
5275
|
7986 octave_idx_type ja = a.cidx(i); |
|
7987 octave_idx_type ja_max = a.cidx(i+1); |
5164
|
7988 bool ja_lt_max= ja < ja_max; |
|
7989 |
5275
|
7990 octave_idx_type jb = b.cidx(i); |
|
7991 octave_idx_type jb_max = b.cidx(i+1); |
5164
|
7992 bool jb_lt_max = jb < jb_max; |
|
7993 |
|
7994 while (ja_lt_max || jb_lt_max ) |
|
7995 { |
|
7996 OCTAVE_QUIT; |
|
7997 if ((! jb_lt_max) || |
|
7998 (ja_lt_max && (a.ridx(ja) < b.ridx(jb)))) |
|
7999 { |
|
8000 Complex tmp = xmin (a.data(ja), 0.); |
|
8001 if (tmp != 0.) |
|
8002 { |
|
8003 r.ridx(jx) = a.ridx(ja); |
|
8004 r.data(jx) = tmp; |
|
8005 jx++; |
|
8006 } |
|
8007 ja++; |
|
8008 ja_lt_max= ja < ja_max; |
|
8009 } |
|
8010 else if (( !ja_lt_max ) || |
|
8011 (jb_lt_max && (b.ridx(jb) < a.ridx(ja)) ) ) |
|
8012 { |
|
8013 Complex tmp = xmin (0., b.data(jb)); |
|
8014 if (tmp != 0.) |
|
8015 { |
|
8016 r.ridx(jx) = b.ridx(jb); |
|
8017 r.data(jx) = tmp; |
|
8018 jx++; |
|
8019 } |
|
8020 jb++; |
|
8021 jb_lt_max= jb < jb_max; |
|
8022 } |
|
8023 else |
|
8024 { |
|
8025 Complex tmp = xmin (a.data(ja), b.data(jb)); |
|
8026 if (tmp != 0.) |
|
8027 { |
|
8028 r.data(jx) = tmp; |
|
8029 r.ridx(jx) = a.ridx(ja); |
|
8030 jx++; |
|
8031 } |
|
8032 ja++; |
|
8033 ja_lt_max= ja < ja_max; |
|
8034 jb++; |
|
8035 jb_lt_max= jb < jb_max; |
|
8036 } |
|
8037 } |
|
8038 r.cidx(i+1) = jx; |
|
8039 } |
|
8040 |
|
8041 r.maybe_compress (); |
|
8042 } |
|
8043 } |
|
8044 else |
|
8045 (*current_liboctave_error_handler) ("matrix size mismatch"); |
|
8046 |
|
8047 return r; |
|
8048 } |
|
8049 |
|
8050 SparseComplexMatrix |
|
8051 max (const Complex& c, const SparseComplexMatrix& m) |
|
8052 { |
|
8053 SparseComplexMatrix result; |
|
8054 |
5275
|
8055 octave_idx_type nr = m.rows (); |
|
8056 octave_idx_type nc = m.columns (); |
5164
|
8057 |
|
8058 EMPTY_RETURN_CHECK (SparseComplexMatrix); |
|
8059 |
|
8060 // Count the number of non-zero elements |
|
8061 if (xmax(c, 0.) != 0.) |
|
8062 { |
|
8063 result = SparseComplexMatrix (nr, nc, c); |
5275
|
8064 for (octave_idx_type j = 0; j < nc; j++) |
|
8065 for (octave_idx_type i = m.cidx(j); i < m.cidx(j+1); i++) |
5164
|
8066 result.xdata(m.ridx(i) + j * nr) = xmax (c, m.data(i)); |
|
8067 } |
|
8068 else |
|
8069 result = SparseComplexMatrix (m); |
|
8070 |
|
8071 return result; |
|
8072 } |
|
8073 |
|
8074 SparseComplexMatrix |
|
8075 max (const SparseComplexMatrix& m, const Complex& c) |
|
8076 { |
|
8077 return max (c, m); |
|
8078 } |
|
8079 |
|
8080 SparseComplexMatrix |
|
8081 max (const SparseComplexMatrix& a, const SparseComplexMatrix& b) |
|
8082 { |
|
8083 SparseComplexMatrix r; |
|
8084 |
|
8085 if ((a.rows() == b.rows()) && (a.cols() == b.cols())) |
|
8086 { |
5275
|
8087 octave_idx_type a_nr = a.rows (); |
|
8088 octave_idx_type a_nc = a.cols (); |
|
8089 |
|
8090 octave_idx_type b_nr = b.rows (); |
|
8091 octave_idx_type b_nc = b.cols (); |
5164
|
8092 |
|
8093 if (a_nr == 0 || b_nc == 0) |
|
8094 return SparseComplexMatrix (a_nr, a_nc); |
5681
|
8095 if (a.nnz () == 0) |
5164
|
8096 return SparseComplexMatrix (b); |
5681
|
8097 if (b.nnz () == 0) |
5164
|
8098 return SparseComplexMatrix (a); |
|
8099 |
|
8100 if (a_nr != b_nr || a_nc != b_nc) |
|
8101 gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); |
|
8102 else |
|
8103 { |
5681
|
8104 r = SparseComplexMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); |
5164
|
8105 |
5275
|
8106 octave_idx_type jx = 0; |
5164
|
8107 r.cidx (0) = 0; |
5275
|
8108 for (octave_idx_type i = 0 ; i < a_nc ; i++) |
5164
|
8109 { |
5275
|
8110 octave_idx_type ja = a.cidx(i); |
|
8111 octave_idx_type ja_max = a.cidx(i+1); |
5164
|
8112 bool ja_lt_max= ja < ja_max; |
|
8113 |
5275
|
8114 octave_idx_type jb = b.cidx(i); |
|
8115 octave_idx_type jb_max = b.cidx(i+1); |
5164
|
8116 bool jb_lt_max = jb < jb_max; |
|
8117 |
|
8118 while (ja_lt_max || jb_lt_max ) |
|
8119 { |
|
8120 OCTAVE_QUIT; |
|
8121 if ((! jb_lt_max) || |
|
8122 (ja_lt_max && (a.ridx(ja) < b.ridx(jb)))) |
|
8123 { |
|
8124 Complex tmp = xmax (a.data(ja), 0.); |
|
8125 if (tmp != 0.) |
|
8126 { |
|
8127 r.ridx(jx) = a.ridx(ja); |
|
8128 r.data(jx) = tmp; |
|
8129 jx++; |
|
8130 } |
|
8131 ja++; |
|
8132 ja_lt_max= ja < ja_max; |
|
8133 } |
|
8134 else if (( !ja_lt_max ) || |
|
8135 (jb_lt_max && (b.ridx(jb) < a.ridx(ja)) ) ) |
|
8136 { |
|
8137 Complex tmp = xmax (0., b.data(jb)); |
|
8138 if (tmp != 0.) |
|
8139 { |
|
8140 r.ridx(jx) = b.ridx(jb); |
|
8141 r.data(jx) = tmp; |
|
8142 jx++; |
|
8143 } |
|
8144 jb++; |
|
8145 jb_lt_max= jb < jb_max; |
|
8146 } |
|
8147 else |
|
8148 { |
|
8149 Complex tmp = xmax (a.data(ja), b.data(jb)); |
|
8150 if (tmp != 0.) |
|
8151 { |
|
8152 r.data(jx) = tmp; |
|
8153 r.ridx(jx) = a.ridx(ja); |
|
8154 jx++; |
|
8155 } |
|
8156 ja++; |
|
8157 ja_lt_max= ja < ja_max; |
|
8158 jb++; |
|
8159 jb_lt_max= jb < jb_max; |
|
8160 } |
|
8161 } |
|
8162 r.cidx(i+1) = jx; |
|
8163 } |
|
8164 |
|
8165 r.maybe_compress (); |
|
8166 } |
|
8167 } |
|
8168 else |
|
8169 (*current_liboctave_error_handler) ("matrix size mismatch"); |
|
8170 |
|
8171 return r; |
|
8172 } |
|
8173 |
|
8174 SPARSE_SMS_CMP_OPS (SparseComplexMatrix, 0.0, real, Complex, |
|
8175 0.0, real) |
|
8176 SPARSE_SMS_BOOL_OPS (SparseComplexMatrix, Complex, 0.0) |
|
8177 |
|
8178 SPARSE_SSM_CMP_OPS (Complex, 0.0, real, SparseComplexMatrix, |
|
8179 0.0, real) |
|
8180 SPARSE_SSM_BOOL_OPS (Complex, SparseComplexMatrix, 0.0) |
|
8181 |
|
8182 SPARSE_SMSM_CMP_OPS (SparseComplexMatrix, 0.0, real, SparseComplexMatrix, |
|
8183 0.0, real) |
|
8184 SPARSE_SMSM_BOOL_OPS (SparseComplexMatrix, SparseComplexMatrix, 0.0) |
|
8185 |
|
8186 /* |
|
8187 ;;; Local Variables: *** |
|
8188 ;;; mode: C++ *** |
|
8189 ;;; End: *** |
|
8190 */ |