Mercurial > hg > octave-nkf
annotate liboctave/CMatrix.cc @ 11875:f53f57d2ee51 release-3-0-x
improve inverse preconditioning according to Marco Caliari
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Sun, 12 Oct 2008 10:31:14 +0200 |
parents | 0b9c56b6bf0e |
children |
rev | line source |
---|---|
1993 | 1 // Matrix manipulations. |
458 | 2 /* |
3 | |
7017 | 4 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
11740 | 5 2003, 2004, 2005, 2006, 2007, 2008 John W. Eaton |
458 | 6 |
7 This file is part of Octave. | |
8 | |
9 Octave is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
7016 | 11 Free Software Foundation; either version 3 of the License, or (at your |
12 option) any later version. | |
458 | 13 |
14 Octave is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
7016 | 20 along with Octave; see the file COPYING. If not, see |
21 <http://www.gnu.org/licenses/>. | |
458 | 22 |
23 */ | |
24 | |
25 #ifdef HAVE_CONFIG_H | |
1192 | 26 #include <config.h> |
458 | 27 #endif |
28 | |
1367 | 29 #include <cfloat> |
30 | |
3503 | 31 #include <iostream> |
6209 | 32 #include <vector> |
1367 | 33 |
5775 | 34 // FIXME |
2443 | 35 #ifdef HAVE_SYS_TYPES_H |
36 #include <sys/types.h> | |
37 #endif | |
458 | 38 |
4669 | 39 #include "Array-util.h" |
2828 | 40 #include "CMatrix.h" |
1819 | 41 #include "CmplxAEPBAL.h" |
458 | 42 #include "CmplxDET.h" |
1819 | 43 #include "CmplxSCHUR.h" |
740 | 44 #include "CmplxSVD.h" |
6207 | 45 #include "CmplxCHOL.h" |
1847 | 46 #include "f77-fcn.h" |
458 | 47 #include "lo-error.h" |
2354 | 48 #include "lo-ieee.h" |
49 #include "lo-mappers.h" | |
1968 | 50 #include "lo-utils.h" |
1367 | 51 #include "mx-base.h" |
2828 | 52 #include "mx-cm-dm.h" |
3176 | 53 #include "mx-dm-cm.h" |
2828 | 54 #include "mx-cm-s.h" |
1367 | 55 #include "mx-inlines.cc" |
1650 | 56 #include "oct-cmplx.h" |
458 | 57 |
4773 | 58 #if defined (HAVE_FFTW3) |
3827 | 59 #include "oct-fftw.h" |
60 #endif | |
61 | |
458 | 62 // Fortran functions we call. |
63 | |
64 extern "C" | |
65 { | |
11646 | 66 F77_RET_T |
67 F77_FUNC (xilaenv, XILAENV) (const octave_idx_type&, F77_CONST_CHAR_ARG_DECL, | |
68 F77_CONST_CHAR_ARG_DECL, | |
69 const octave_idx_type&, const octave_idx_type&, | |
70 const octave_idx_type&, const octave_idx_type&, | |
71 octave_idx_type& | |
72 F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL); | |
11640 | 73 |
4552 | 74 F77_RET_T |
75 F77_FUNC (zgebal, ZGEBAL) (F77_CONST_CHAR_ARG_DECL, | |
5275 | 76 const octave_idx_type&, Complex*, const octave_idx_type&, octave_idx_type&, |
77 octave_idx_type&, double*, octave_idx_type& | |
4552 | 78 F77_CHAR_ARG_LEN_DECL); |
79 | |
80 F77_RET_T | |
81 F77_FUNC (dgebak, DGEBAK) (F77_CONST_CHAR_ARG_DECL, | |
82 F77_CONST_CHAR_ARG_DECL, | |
5275 | 83 const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, double*, |
84 const octave_idx_type&, double*, const octave_idx_type&, octave_idx_type& | |
4552 | 85 F77_CHAR_ARG_LEN_DECL |
86 F77_CHAR_ARG_LEN_DECL); | |
87 | |
88 F77_RET_T | |
89 F77_FUNC (zgemm, ZGEMM) (F77_CONST_CHAR_ARG_DECL, | |
90 F77_CONST_CHAR_ARG_DECL, | |
5275 | 91 const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, |
92 const Complex&, const Complex*, const octave_idx_type&, | |
93 const Complex*, const octave_idx_type&, const Complex&, | |
94 Complex*, const octave_idx_type& | |
4552 | 95 F77_CHAR_ARG_LEN_DECL |
96 F77_CHAR_ARG_LEN_DECL); | |
97 | |
98 F77_RET_T | |
5983 | 99 F77_FUNC (zgemv, ZGEMV) (F77_CONST_CHAR_ARG_DECL, |
100 const octave_idx_type&, const octave_idx_type&, const Complex&, | |
101 const Complex*, const octave_idx_type&, const Complex*, | |
102 const octave_idx_type&, const Complex&, Complex*, const octave_idx_type& | |
103 F77_CHAR_ARG_LEN_DECL); | |
104 | |
105 F77_RET_T | |
106 F77_FUNC (xzdotu, XZDOTU) (const octave_idx_type&, const Complex*, const octave_idx_type&, | |
107 const Complex*, const octave_idx_type&, Complex&); | |
108 | |
109 F77_RET_T | |
5275 | 110 F77_FUNC (zgetrf, ZGETRF) (const octave_idx_type&, const octave_idx_type&, Complex*, const octave_idx_type&, |
111 octave_idx_type*, octave_idx_type&); | |
4552 | 112 |
113 F77_RET_T | |
114 F77_FUNC (zgetrs, ZGETRS) (F77_CONST_CHAR_ARG_DECL, | |
5275 | 115 const octave_idx_type&, const octave_idx_type&, Complex*, const octave_idx_type&, |
116 const octave_idx_type*, Complex*, const octave_idx_type&, octave_idx_type& | |
4552 | 117 F77_CHAR_ARG_LEN_DECL); |
118 | |
119 F77_RET_T | |
5275 | 120 F77_FUNC (zgetri, ZGETRI) (const octave_idx_type&, Complex*, const octave_idx_type&, const octave_idx_type*, |
121 Complex*, const octave_idx_type&, octave_idx_type&); | |
4552 | 122 |
123 F77_RET_T | |
124 F77_FUNC (zgecon, ZGECON) (F77_CONST_CHAR_ARG_DECL, | |
5275 | 125 const octave_idx_type&, Complex*, |
126 const octave_idx_type&, const double&, double&, | |
127 Complex*, double*, octave_idx_type& | |
4552 | 128 F77_CHAR_ARG_LEN_DECL); |
129 | |
130 F77_RET_T | |
7072 | 131 F77_FUNC (zgelsy, ZGELSY) (const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, |
132 Complex*, const octave_idx_type&, Complex*, | |
133 const octave_idx_type&, octave_idx_type*, double&, octave_idx_type&, | |
134 Complex*, const octave_idx_type&, double*, octave_idx_type&); | |
135 | |
136 F77_RET_T | |
137 F77_FUNC (zgelsd, ZGELSD) (const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, | |
5275 | 138 Complex*, const octave_idx_type&, Complex*, |
7071 | 139 const octave_idx_type&, double*, double&, octave_idx_type&, |
7072 | 140 Complex*, const octave_idx_type&, double*, |
141 octave_idx_type*, octave_idx_type&); | |
458 | 142 |
5785 | 143 F77_RET_T |
144 F77_FUNC (zpotrf, ZPOTRF) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, | |
145 Complex*, const octave_idx_type&, | |
146 octave_idx_type& F77_CHAR_ARG_LEN_DECL); | |
147 | |
148 F77_RET_T | |
149 F77_FUNC (zpocon, ZPOCON) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, | |
150 Complex*, const octave_idx_type&, const double&, | |
151 double&, Complex*, double*, | |
152 octave_idx_type& F77_CHAR_ARG_LEN_DECL); | |
153 | |
154 F77_RET_T | |
155 F77_FUNC (zpotrs, ZPOTRS) (F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, | |
156 const octave_idx_type&, const Complex*, | |
157 const octave_idx_type&, Complex*, | |
158 const octave_idx_type&, octave_idx_type& | |
159 F77_CHAR_ARG_LEN_DECL); | |
160 | |
161 F77_RET_T | |
6207 | 162 F77_FUNC (ztrtri, ZTRTRI) (F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, |
163 const octave_idx_type&, const Complex*, | |
164 const octave_idx_type&, octave_idx_type& | |
165 F77_CHAR_ARG_LEN_DECL | |
166 F77_CHAR_ARG_LEN_DECL); | |
167 | |
168 F77_RET_T | |
5785 | 169 F77_FUNC (ztrcon, ZTRCON) (F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, |
170 F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, | |
171 const Complex*, const octave_idx_type&, double&, | |
172 Complex*, double*, octave_idx_type& | |
173 F77_CHAR_ARG_LEN_DECL | |
174 F77_CHAR_ARG_LEN_DECL | |
175 F77_CHAR_ARG_LEN_DECL); | |
176 | |
177 F77_RET_T | |
178 F77_FUNC (ztrtrs, ZTRTRS) (F77_CONST_CHAR_ARG_DECL, F77_CONST_CHAR_ARG_DECL, | |
179 F77_CONST_CHAR_ARG_DECL, const octave_idx_type&, | |
180 const octave_idx_type&, const Complex*, | |
181 const octave_idx_type&, Complex*, | |
182 const octave_idx_type&, octave_idx_type& | |
183 F77_CHAR_ARG_LEN_DECL | |
184 F77_CHAR_ARG_LEN_DECL | |
185 F77_CHAR_ARG_LEN_DECL); | |
186 | |
1360 | 187 // Note that the original complex fft routines were not written for |
188 // double complex arguments. They have been modified by adding an | |
189 // implicit double precision (a-h,o-z) statement at the beginning of | |
190 // each subroutine. | |
458 | 191 |
4552 | 192 F77_RET_T |
5275 | 193 F77_FUNC (cffti, CFFTI) (const octave_idx_type&, Complex*); |
4552 | 194 |
195 F77_RET_T | |
5275 | 196 F77_FUNC (cfftf, CFFTF) (const octave_idx_type&, Complex*, Complex*); |
4552 | 197 |
198 F77_RET_T | |
5275 | 199 F77_FUNC (cfftb, CFFTB) (const octave_idx_type&, Complex*, Complex*); |
4552 | 200 |
201 F77_RET_T | |
202 F77_FUNC (zlartg, ZLARTG) (const Complex&, const Complex&, | |
203 double&, Complex&, Complex&); | |
204 | |
205 F77_RET_T | |
206 F77_FUNC (ztrsyl, ZTRSYL) (F77_CONST_CHAR_ARG_DECL, | |
207 F77_CONST_CHAR_ARG_DECL, | |
5275 | 208 const octave_idx_type&, const octave_idx_type&, const octave_idx_type&, |
209 const Complex*, const octave_idx_type&, | |
210 const Complex*, const octave_idx_type&, | |
211 const Complex*, const octave_idx_type&, double&, octave_idx_type& | |
4552 | 212 F77_CHAR_ARG_LEN_DECL |
213 F77_CHAR_ARG_LEN_DECL); | |
214 | |
215 F77_RET_T | |
216 F77_FUNC (xzlange, XZLANGE) (F77_CONST_CHAR_ARG_DECL, | |
5275 | 217 const octave_idx_type&, const octave_idx_type&, const Complex*, |
218 const octave_idx_type&, double*, double& | |
4552 | 219 F77_CHAR_ARG_LEN_DECL); |
458 | 220 } |
221 | |
2354 | 222 static const Complex Complex_NaN_result (octave_NaN, octave_NaN); |
223 | |
1360 | 224 // Complex Matrix class |
458 | 225 |
226 ComplexMatrix::ComplexMatrix (const Matrix& a) | |
1214 | 227 : MArray2<Complex> (a.rows (), a.cols ()) |
458 | 228 { |
5275 | 229 for (octave_idx_type j = 0; j < cols (); j++) |
230 for (octave_idx_type i = 0; i < rows (); i++) | |
458 | 231 elem (i, j) = a.elem (i, j); |
232 } | |
233 | |
2349 | 234 ComplexMatrix::ComplexMatrix (const RowVector& rv) |
235 : MArray2<Complex> (1, rv.length (), 0.0) | |
236 { | |
5275 | 237 for (octave_idx_type i = 0; i < rv.length (); i++) |
2349 | 238 elem (0, i) = rv.elem (i); |
239 } | |
240 | |
241 ComplexMatrix::ComplexMatrix (const ColumnVector& cv) | |
242 : MArray2<Complex> (cv.length (), 1, 0.0) | |
243 { | |
5275 | 244 for (octave_idx_type i = 0; i < cv.length (); i++) |
2349 | 245 elem (i, 0) = cv.elem (i); |
246 } | |
247 | |
458 | 248 ComplexMatrix::ComplexMatrix (const DiagMatrix& a) |
1214 | 249 : MArray2<Complex> (a.rows (), a.cols (), 0.0) |
458 | 250 { |
5275 | 251 for (octave_idx_type i = 0; i < a.length (); i++) |
458 | 252 elem (i, i) = a.elem (i, i); |
253 } | |
254 | |
2349 | 255 ComplexMatrix::ComplexMatrix (const ComplexRowVector& rv) |
256 : MArray2<Complex> (1, rv.length (), 0.0) | |
257 { | |
5275 | 258 for (octave_idx_type i = 0; i < rv.length (); i++) |
2349 | 259 elem (0, i) = rv.elem (i); |
260 } | |
261 | |
262 ComplexMatrix::ComplexMatrix (const ComplexColumnVector& cv) | |
263 : MArray2<Complex> (cv.length (), 1, 0.0) | |
264 { | |
5275 | 265 for (octave_idx_type i = 0; i < cv.length (); i++) |
2349 | 266 elem (i, 0) = cv.elem (i); |
267 } | |
268 | |
458 | 269 ComplexMatrix::ComplexMatrix (const ComplexDiagMatrix& a) |
1214 | 270 : MArray2<Complex> (a.rows (), a.cols (), 0.0) |
458 | 271 { |
5275 | 272 for (octave_idx_type i = 0; i < a.length (); i++) |
458 | 273 elem (i, i) = a.elem (i, i); |
274 } | |
275 | |
5775 | 276 // FIXME -- could we use a templated mixed-type copy function |
1574 | 277 // here? |
278 | |
2828 | 279 ComplexMatrix::ComplexMatrix (const boolMatrix& a) |
3180 | 280 : MArray2<Complex> (a.rows (), a.cols (), 0.0) |
2828 | 281 { |
5275 | 282 for (octave_idx_type i = 0; i < a.rows (); i++) |
283 for (octave_idx_type j = 0; j < a.cols (); j++) | |
2828 | 284 elem (i, j) = a.elem (i, j); |
285 } | |
286 | |
1574 | 287 ComplexMatrix::ComplexMatrix (const charMatrix& a) |
3180 | 288 : MArray2<Complex> (a.rows (), a.cols (), 0.0) |
1574 | 289 { |
5275 | 290 for (octave_idx_type i = 0; i < a.rows (); i++) |
291 for (octave_idx_type j = 0; j < a.cols (); j++) | |
1574 | 292 elem (i, j) = a.elem (i, j); |
293 } | |
294 | |
2384 | 295 bool |
458 | 296 ComplexMatrix::operator == (const ComplexMatrix& a) const |
297 { | |
298 if (rows () != a.rows () || cols () != a.cols ()) | |
2384 | 299 return false; |
458 | 300 |
3769 | 301 return mx_inline_equal (data (), a.data (), length ()); |
458 | 302 } |
303 | |
2384 | 304 bool |
458 | 305 ComplexMatrix::operator != (const ComplexMatrix& a) const |
306 { | |
307 return !(*this == a); | |
308 } | |
309 | |
2815 | 310 bool |
311 ComplexMatrix::is_hermitian (void) const | |
312 { | |
5275 | 313 octave_idx_type nr = rows (); |
314 octave_idx_type nc = cols (); | |
2815 | 315 |
316 if (is_square () && nr > 0) | |
317 { | |
5275 | 318 for (octave_idx_type i = 0; i < nr; i++) |
319 for (octave_idx_type j = i; j < nc; j++) | |
2815 | 320 if (elem (i, j) != conj (elem (j, i))) |
321 return false; | |
322 | |
323 return true; | |
324 } | |
325 | |
326 return false; | |
327 } | |
328 | |
458 | 329 // destructive insert/delete/reorder operations |
330 | |
331 ComplexMatrix& | |
5275 | 332 ComplexMatrix::insert (const Matrix& a, octave_idx_type r, octave_idx_type c) |
458 | 333 { |
5275 | 334 octave_idx_type a_nr = a.rows (); |
335 octave_idx_type a_nc = a.cols (); | |
1699 | 336 |
337 if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ()) | |
458 | 338 { |
339 (*current_liboctave_error_handler) ("range error for insert"); | |
340 return *this; | |
341 } | |
342 | |
4316 | 343 if (a_nr >0 && a_nc > 0) |
344 { | |
345 make_unique (); | |
346 | |
5275 | 347 for (octave_idx_type j = 0; j < a_nc; j++) |
348 for (octave_idx_type i = 0; i < a_nr; i++) | |
4316 | 349 xelem (r+i, c+j) = a.elem (i, j); |
350 } | |
458 | 351 |
352 return *this; | |
353 } | |
354 | |
355 ComplexMatrix& | |
5275 | 356 ComplexMatrix::insert (const RowVector& a, octave_idx_type r, octave_idx_type c) |
458 | 357 { |
5275 | 358 octave_idx_type a_len = a.length (); |
4316 | 359 |
1699 | 360 if (r < 0 || r >= rows () || c < 0 || c + a_len > cols ()) |
458 | 361 { |
362 (*current_liboctave_error_handler) ("range error for insert"); | |
363 return *this; | |
364 } | |
365 | |
4316 | 366 if (a_len > 0) |
367 { | |
368 make_unique (); | |
369 | |
5275 | 370 for (octave_idx_type i = 0; i < a_len; i++) |
4316 | 371 xelem (r, c+i) = a.elem (i); |
372 } | |
458 | 373 |
374 return *this; | |
375 } | |
376 | |
377 ComplexMatrix& | |
5275 | 378 ComplexMatrix::insert (const ColumnVector& a, octave_idx_type r, octave_idx_type c) |
458 | 379 { |
5275 | 380 octave_idx_type a_len = a.length (); |
4316 | 381 |
1699 | 382 if (r < 0 || r + a_len > rows () || c < 0 || c >= cols ()) |
458 | 383 { |
384 (*current_liboctave_error_handler) ("range error for insert"); | |
385 return *this; | |
386 } | |
387 | |
4316 | 388 if (a_len > 0) |
389 { | |
390 make_unique (); | |
391 | |
5275 | 392 for (octave_idx_type i = 0; i < a_len; i++) |
4316 | 393 xelem (r+i, c) = a.elem (i); |
394 } | |
458 | 395 |
396 return *this; | |
397 } | |
398 | |
399 ComplexMatrix& | |
5275 | 400 ComplexMatrix::insert (const DiagMatrix& a, octave_idx_type r, octave_idx_type c) |
458 | 401 { |
5275 | 402 octave_idx_type a_nr = a.rows (); |
403 octave_idx_type a_nc = a.cols (); | |
1699 | 404 |
405 if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ()) | |
458 | 406 { |
407 (*current_liboctave_error_handler) ("range error for insert"); | |
408 return *this; | |
409 } | |
410 | |
1699 | 411 fill (0.0, r, c, r + a_nr - 1, c + a_nc - 1); |
412 | |
5275 | 413 octave_idx_type a_len = a.length (); |
4316 | 414 |
415 if (a_len > 0) | |
416 { | |
417 make_unique (); | |
418 | |
5275 | 419 for (octave_idx_type i = 0; i < a_len; i++) |
4316 | 420 xelem (r+i, c+i) = a.elem (i, i); |
421 } | |
458 | 422 |
423 return *this; | |
424 } | |
425 | |
426 ComplexMatrix& | |
5275 | 427 ComplexMatrix::insert (const ComplexMatrix& a, octave_idx_type r, octave_idx_type c) |
458 | 428 { |
1561 | 429 Array2<Complex>::insert (a, r, c); |
458 | 430 return *this; |
431 } | |
432 | |
433 ComplexMatrix& | |
5275 | 434 ComplexMatrix::insert (const ComplexRowVector& a, octave_idx_type r, octave_idx_type c) |
458 | 435 { |
5275 | 436 octave_idx_type a_len = a.length (); |
1699 | 437 if (r < 0 || r >= rows () || c < 0 || c + a_len > cols ()) |
458 | 438 { |
439 (*current_liboctave_error_handler) ("range error for insert"); | |
440 return *this; | |
441 } | |
442 | |
5275 | 443 for (octave_idx_type i = 0; i < a_len; i++) |
458 | 444 elem (r, c+i) = a.elem (i); |
445 | |
446 return *this; | |
447 } | |
448 | |
449 ComplexMatrix& | |
5275 | 450 ComplexMatrix::insert (const ComplexColumnVector& a, octave_idx_type r, octave_idx_type c) |
458 | 451 { |
5275 | 452 octave_idx_type a_len = a.length (); |
4316 | 453 |
1699 | 454 if (r < 0 || r + a_len > rows () || c < 0 || c >= cols ()) |
458 | 455 { |
456 (*current_liboctave_error_handler) ("range error for insert"); | |
457 return *this; | |
458 } | |
459 | |
4316 | 460 if (a_len > 0) |
461 { | |
462 make_unique (); | |
463 | |
5275 | 464 for (octave_idx_type i = 0; i < a_len; i++) |
4316 | 465 xelem (r+i, c) = a.elem (i); |
466 } | |
458 | 467 |
468 return *this; | |
469 } | |
470 | |
471 ComplexMatrix& | |
5275 | 472 ComplexMatrix::insert (const ComplexDiagMatrix& a, octave_idx_type r, octave_idx_type c) |
458 | 473 { |
5275 | 474 octave_idx_type a_nr = a.rows (); |
475 octave_idx_type a_nc = a.cols (); | |
1699 | 476 |
477 if (r < 0 || r + a_nr > rows () || c < 0 || c + a_nc > cols ()) | |
458 | 478 { |
479 (*current_liboctave_error_handler) ("range error for insert"); | |
480 return *this; | |
481 } | |
482 | |
1699 | 483 fill (0.0, r, c, r + a_nr - 1, c + a_nc - 1); |
484 | |
5275 | 485 octave_idx_type a_len = a.length (); |
4316 | 486 |
487 if (a_len > 0) | |
488 { | |
489 make_unique (); | |
490 | |
5275 | 491 for (octave_idx_type i = 0; i < a_len; i++) |
4316 | 492 xelem (r+i, c+i) = a.elem (i, i); |
493 } | |
458 | 494 |
495 return *this; | |
496 } | |
497 | |
498 ComplexMatrix& | |
499 ComplexMatrix::fill (double val) | |
500 { | |
5275 | 501 octave_idx_type nr = rows (); |
502 octave_idx_type nc = cols (); | |
4316 | 503 |
458 | 504 if (nr > 0 && nc > 0) |
4316 | 505 { |
506 make_unique (); | |
507 | |
5275 | 508 for (octave_idx_type j = 0; j < nc; j++) |
509 for (octave_idx_type i = 0; i < nr; i++) | |
4316 | 510 xelem (i, j) = val; |
511 } | |
458 | 512 |
513 return *this; | |
514 } | |
515 | |
516 ComplexMatrix& | |
517 ComplexMatrix::fill (const Complex& val) | |
518 { | |
5275 | 519 octave_idx_type nr = rows (); |
520 octave_idx_type nc = cols (); | |
4316 | 521 |
458 | 522 if (nr > 0 && nc > 0) |
4316 | 523 { |
524 make_unique (); | |
525 | |
5275 | 526 for (octave_idx_type j = 0; j < nc; j++) |
527 for (octave_idx_type i = 0; i < nr; i++) | |
4316 | 528 xelem (i, j) = val; |
529 } | |
458 | 530 |
531 return *this; | |
532 } | |
533 | |
534 ComplexMatrix& | |
5275 | 535 ComplexMatrix::fill (double val, octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) |
458 | 536 { |
5275 | 537 octave_idx_type nr = rows (); |
538 octave_idx_type nc = cols (); | |
4316 | 539 |
458 | 540 if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0 |
541 || r1 >= nr || r2 >= nr || c1 >= nc || c2 >= nc) | |
542 { | |
543 (*current_liboctave_error_handler) ("range error for fill"); | |
544 return *this; | |
545 } | |
546 | |
5275 | 547 if (r1 > r2) { octave_idx_type tmp = r1; r1 = r2; r2 = tmp; } |
548 if (c1 > c2) { octave_idx_type tmp = c1; c1 = c2; c2 = tmp; } | |
458 | 549 |
4316 | 550 if (r2 >= r1 && c2 >= c1) |
551 { | |
552 make_unique (); | |
553 | |
5275 | 554 for (octave_idx_type j = c1; j <= c2; j++) |
555 for (octave_idx_type i = r1; i <= r2; i++) | |
4316 | 556 xelem (i, j) = val; |
557 } | |
458 | 558 |
559 return *this; | |
560 } | |
561 | |
562 ComplexMatrix& | |
5275 | 563 ComplexMatrix::fill (const Complex& val, octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) |
458 | 564 { |
5275 | 565 octave_idx_type nr = rows (); |
566 octave_idx_type nc = cols (); | |
4316 | 567 |
458 | 568 if (r1 < 0 || r2 < 0 || c1 < 0 || c2 < 0 |
569 || r1 >= nr || r2 >= nr || c1 >= nc || c2 >= nc) | |
570 { | |
571 (*current_liboctave_error_handler) ("range error for fill"); | |
572 return *this; | |
573 } | |
574 | |
5275 | 575 if (r1 > r2) { octave_idx_type tmp = r1; r1 = r2; r2 = tmp; } |
576 if (c1 > c2) { octave_idx_type tmp = c1; c1 = c2; c2 = tmp; } | |
458 | 577 |
4316 | 578 if (r2 >= r1 && c2 >=c1) |
579 { | |
580 make_unique (); | |
581 | |
5275 | 582 for (octave_idx_type j = c1; j <= c2; j++) |
583 for (octave_idx_type i = r1; i <= r2; i++) | |
4316 | 584 xelem (i, j) = val; |
585 } | |
458 | 586 |
587 return *this; | |
588 } | |
589 | |
590 ComplexMatrix | |
591 ComplexMatrix::append (const Matrix& a) const | |
592 { | |
5275 | 593 octave_idx_type nr = rows (); |
594 octave_idx_type nc = cols (); | |
458 | 595 if (nr != a.rows ()) |
596 { | |
597 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
598 return *this; | |
599 } | |
600 | |
5275 | 601 octave_idx_type nc_insert = nc; |
458 | 602 ComplexMatrix retval (nr, nc + a.cols ()); |
603 retval.insert (*this, 0, 0); | |
604 retval.insert (a, 0, nc_insert); | |
605 return retval; | |
606 } | |
607 | |
608 ComplexMatrix | |
609 ComplexMatrix::append (const RowVector& a) const | |
610 { | |
5275 | 611 octave_idx_type nr = rows (); |
612 octave_idx_type nc = cols (); | |
458 | 613 if (nr != 1) |
614 { | |
615 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
616 return *this; | |
617 } | |
618 | |
5275 | 619 octave_idx_type nc_insert = nc; |
458 | 620 ComplexMatrix retval (nr, nc + a.length ()); |
621 retval.insert (*this, 0, 0); | |
622 retval.insert (a, 0, nc_insert); | |
623 return retval; | |
624 } | |
625 | |
626 ComplexMatrix | |
627 ComplexMatrix::append (const ColumnVector& a) const | |
628 { | |
5275 | 629 octave_idx_type nr = rows (); |
630 octave_idx_type nc = cols (); | |
458 | 631 if (nr != a.length ()) |
632 { | |
633 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
634 return *this; | |
635 } | |
636 | |
5275 | 637 octave_idx_type nc_insert = nc; |
458 | 638 ComplexMatrix retval (nr, nc + 1); |
639 retval.insert (*this, 0, 0); | |
640 retval.insert (a, 0, nc_insert); | |
641 return retval; | |
642 } | |
643 | |
644 ComplexMatrix | |
645 ComplexMatrix::append (const DiagMatrix& a) const | |
646 { | |
5275 | 647 octave_idx_type nr = rows (); |
648 octave_idx_type nc = cols (); | |
458 | 649 if (nr != a.rows ()) |
650 { | |
651 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
652 return *this; | |
653 } | |
654 | |
5275 | 655 octave_idx_type nc_insert = nc; |
458 | 656 ComplexMatrix retval (nr, nc + a.cols ()); |
657 retval.insert (*this, 0, 0); | |
658 retval.insert (a, 0, nc_insert); | |
659 return retval; | |
660 } | |
661 | |
662 ComplexMatrix | |
663 ComplexMatrix::append (const ComplexMatrix& a) const | |
664 { | |
5275 | 665 octave_idx_type nr = rows (); |
666 octave_idx_type nc = cols (); | |
458 | 667 if (nr != a.rows ()) |
668 { | |
669 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
670 return *this; | |
671 } | |
672 | |
5275 | 673 octave_idx_type nc_insert = nc; |
458 | 674 ComplexMatrix retval (nr, nc + a.cols ()); |
675 retval.insert (*this, 0, 0); | |
676 retval.insert (a, 0, nc_insert); | |
677 return retval; | |
678 } | |
679 | |
680 ComplexMatrix | |
681 ComplexMatrix::append (const ComplexRowVector& a) const | |
682 { | |
5275 | 683 octave_idx_type nr = rows (); |
684 octave_idx_type nc = cols (); | |
458 | 685 if (nr != 1) |
686 { | |
687 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
688 return *this; | |
689 } | |
690 | |
5275 | 691 octave_idx_type nc_insert = nc; |
458 | 692 ComplexMatrix retval (nr, nc + a.length ()); |
693 retval.insert (*this, 0, 0); | |
694 retval.insert (a, 0, nc_insert); | |
695 return retval; | |
696 } | |
697 | |
698 ComplexMatrix | |
699 ComplexMatrix::append (const ComplexColumnVector& a) const | |
700 { | |
5275 | 701 octave_idx_type nr = rows (); |
702 octave_idx_type nc = cols (); | |
458 | 703 if (nr != a.length ()) |
704 { | |
705 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
706 return *this; | |
707 } | |
708 | |
5275 | 709 octave_idx_type nc_insert = nc; |
458 | 710 ComplexMatrix retval (nr, nc + 1); |
711 retval.insert (*this, 0, 0); | |
712 retval.insert (a, 0, nc_insert); | |
713 return retval; | |
714 } | |
715 | |
716 ComplexMatrix | |
717 ComplexMatrix::append (const ComplexDiagMatrix& a) const | |
718 { | |
5275 | 719 octave_idx_type nr = rows (); |
720 octave_idx_type nc = cols (); | |
458 | 721 if (nr != a.rows ()) |
722 { | |
723 (*current_liboctave_error_handler) ("row dimension mismatch for append"); | |
724 return *this; | |
725 } | |
726 | |
5275 | 727 octave_idx_type nc_insert = nc; |
458 | 728 ComplexMatrix retval (nr, nc + a.cols ()); |
729 retval.insert (*this, 0, 0); | |
730 retval.insert (a, 0, nc_insert); | |
731 return retval; | |
732 } | |
733 | |
734 ComplexMatrix | |
735 ComplexMatrix::stack (const Matrix& a) const | |
736 { | |
5275 | 737 octave_idx_type nr = rows (); |
738 octave_idx_type nc = cols (); | |
458 | 739 if (nc != a.cols ()) |
740 { | |
741 (*current_liboctave_error_handler) | |
742 ("column dimension mismatch for stack"); | |
743 return *this; | |
744 } | |
745 | |
5275 | 746 octave_idx_type nr_insert = nr; |
458 | 747 ComplexMatrix retval (nr + a.rows (), nc); |
748 retval.insert (*this, 0, 0); | |
749 retval.insert (a, nr_insert, 0); | |
750 return retval; | |
751 } | |
752 | |
753 ComplexMatrix | |
754 ComplexMatrix::stack (const RowVector& a) const | |
755 { | |
5275 | 756 octave_idx_type nr = rows (); |
757 octave_idx_type nc = cols (); | |
458 | 758 if (nc != a.length ()) |
759 { | |
760 (*current_liboctave_error_handler) | |
761 ("column dimension mismatch for stack"); | |
762 return *this; | |
763 } | |
764 | |
5275 | 765 octave_idx_type nr_insert = nr; |
458 | 766 ComplexMatrix retval (nr + 1, nc); |
767 retval.insert (*this, 0, 0); | |
768 retval.insert (a, nr_insert, 0); | |
769 return retval; | |
770 } | |
771 | |
772 ComplexMatrix | |
773 ComplexMatrix::stack (const ColumnVector& a) const | |
774 { | |
5275 | 775 octave_idx_type nr = rows (); |
776 octave_idx_type nc = cols (); | |
458 | 777 if (nc != 1) |
778 { | |
779 (*current_liboctave_error_handler) | |
780 ("column dimension mismatch for stack"); | |
781 return *this; | |
782 } | |
783 | |
5275 | 784 octave_idx_type nr_insert = nr; |
458 | 785 ComplexMatrix retval (nr + a.length (), nc); |
786 retval.insert (*this, 0, 0); | |
787 retval.insert (a, nr_insert, 0); | |
788 return retval; | |
789 } | |
790 | |
791 ComplexMatrix | |
792 ComplexMatrix::stack (const DiagMatrix& a) const | |
793 { | |
5275 | 794 octave_idx_type nr = rows (); |
795 octave_idx_type nc = cols (); | |
458 | 796 if (nc != a.cols ()) |
797 { | |
798 (*current_liboctave_error_handler) | |
799 ("column dimension mismatch for stack"); | |
800 return *this; | |
801 } | |
802 | |
5275 | 803 octave_idx_type nr_insert = nr; |
458 | 804 ComplexMatrix retval (nr + a.rows (), nc); |
805 retval.insert (*this, 0, 0); | |
806 retval.insert (a, nr_insert, 0); | |
807 return retval; | |
808 } | |
809 | |
810 ComplexMatrix | |
811 ComplexMatrix::stack (const ComplexMatrix& a) const | |
812 { | |
5275 | 813 octave_idx_type nr = rows (); |
814 octave_idx_type nc = cols (); | |
458 | 815 if (nc != a.cols ()) |
816 { | |
817 (*current_liboctave_error_handler) | |
818 ("column dimension mismatch for stack"); | |
819 return *this; | |
820 } | |
821 | |
5275 | 822 octave_idx_type nr_insert = nr; |
458 | 823 ComplexMatrix retval (nr + a.rows (), nc); |
824 retval.insert (*this, 0, 0); | |
825 retval.insert (a, nr_insert, 0); | |
826 return retval; | |
827 } | |
828 | |
829 ComplexMatrix | |
830 ComplexMatrix::stack (const ComplexRowVector& a) const | |
831 { | |
5275 | 832 octave_idx_type nr = rows (); |
833 octave_idx_type nc = cols (); | |
458 | 834 if (nc != a.length ()) |
835 { | |
836 (*current_liboctave_error_handler) | |
837 ("column dimension mismatch for stack"); | |
838 return *this; | |
839 } | |
840 | |
5275 | 841 octave_idx_type nr_insert = nr; |
458 | 842 ComplexMatrix retval (nr + 1, nc); |
843 retval.insert (*this, 0, 0); | |
844 retval.insert (a, nr_insert, 0); | |
845 return retval; | |
846 } | |
847 | |
848 ComplexMatrix | |
849 ComplexMatrix::stack (const ComplexColumnVector& a) const | |
850 { | |
5275 | 851 octave_idx_type nr = rows (); |
852 octave_idx_type nc = cols (); | |
458 | 853 if (nc != 1) |
854 { | |
855 (*current_liboctave_error_handler) | |
856 ("column dimension mismatch for stack"); | |
857 return *this; | |
858 } | |
859 | |
5275 | 860 octave_idx_type nr_insert = nr; |
458 | 861 ComplexMatrix retval (nr + a.length (), nc); |
862 retval.insert (*this, 0, 0); | |
863 retval.insert (a, nr_insert, 0); | |
864 return retval; | |
865 } | |
866 | |
867 ComplexMatrix | |
868 ComplexMatrix::stack (const ComplexDiagMatrix& a) const | |
869 { | |
5275 | 870 octave_idx_type nr = rows (); |
871 octave_idx_type nc = cols (); | |
458 | 872 if (nc != a.cols ()) |
873 { | |
874 (*current_liboctave_error_handler) | |
875 ("column dimension mismatch for stack"); | |
876 return *this; | |
877 } | |
878 | |
5275 | 879 octave_idx_type nr_insert = nr; |
458 | 880 ComplexMatrix retval (nr + a.rows (), nc); |
881 retval.insert (*this, 0, 0); | |
882 retval.insert (a, nr_insert, 0); | |
883 return retval; | |
884 } | |
885 | |
886 ComplexMatrix | |
887 ComplexMatrix::hermitian (void) const | |
888 { | |
5275 | 889 octave_idx_type nr = rows (); |
890 octave_idx_type nc = cols (); | |
458 | 891 ComplexMatrix result; |
892 if (length () > 0) | |
893 { | |
894 result.resize (nc, nr); | |
5275 | 895 for (octave_idx_type j = 0; j < nc; j++) |
896 for (octave_idx_type i = 0; i < nr; i++) | |
458 | 897 result.elem (j, i) = conj (elem (i, j)); |
898 } | |
899 return result; | |
900 } | |
901 | |
902 ComplexMatrix | |
903 conj (const ComplexMatrix& a) | |
904 { | |
5275 | 905 octave_idx_type a_len = a.length (); |
458 | 906 ComplexMatrix retval; |
907 if (a_len > 0) | |
3769 | 908 retval = ComplexMatrix (mx_inline_conj_dup (a.data (), a_len), |
909 a.rows (), a.cols ()); | |
458 | 910 return retval; |
911 } | |
912 | |
913 // resize is the destructive equivalent for this one | |
914 | |
915 ComplexMatrix | |
5275 | 916 ComplexMatrix::extract (octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const |
458 | 917 { |
5275 | 918 if (r1 > r2) { octave_idx_type tmp = r1; r1 = r2; r2 = tmp; } |
919 if (c1 > c2) { octave_idx_type tmp = c1; c1 = c2; c2 = tmp; } | |
920 | |
921 octave_idx_type new_r = r2 - r1 + 1; | |
922 octave_idx_type new_c = c2 - c1 + 1; | |
458 | 923 |
924 ComplexMatrix result (new_r, new_c); | |
925 | |
5275 | 926 for (octave_idx_type j = 0; j < new_c; j++) |
927 for (octave_idx_type i = 0; i < new_r; i++) | |
4316 | 928 result.xelem (i, j) = elem (r1+i, c1+j); |
929 | |
930 return result; | |
931 } | |
932 | |
933 ComplexMatrix | |
5275 | 934 ComplexMatrix::extract_n (octave_idx_type r1, octave_idx_type c1, octave_idx_type nr, octave_idx_type nc) const |
4316 | 935 { |
936 ComplexMatrix result (nr, nc); | |
937 | |
5275 | 938 for (octave_idx_type j = 0; j < nc; j++) |
939 for (octave_idx_type i = 0; i < nr; i++) | |
4316 | 940 result.xelem (i, j) = elem (r1+i, c1+j); |
458 | 941 |
942 return result; | |
943 } | |
944 | |
945 // extract row or column i. | |
946 | |
947 ComplexRowVector | |
5275 | 948 ComplexMatrix::row (octave_idx_type i) const |
458 | 949 { |
5275 | 950 octave_idx_type nc = cols (); |
458 | 951 if (i < 0 || i >= rows ()) |
952 { | |
953 (*current_liboctave_error_handler) ("invalid row selection"); | |
954 return ComplexRowVector (); | |
955 } | |
956 | |
957 ComplexRowVector retval (nc); | |
5275 | 958 for (octave_idx_type j = 0; j < cols (); j++) |
4316 | 959 retval.xelem (j) = elem (i, j); |
458 | 960 |
961 return retval; | |
962 } | |
963 | |
964 ComplexColumnVector | |
5275 | 965 ComplexMatrix::column (octave_idx_type i) const |
458 | 966 { |
5275 | 967 octave_idx_type nr = rows (); |
458 | 968 if (i < 0 || i >= cols ()) |
969 { | |
970 (*current_liboctave_error_handler) ("invalid column selection"); | |
971 return ComplexColumnVector (); | |
972 } | |
973 | |
974 ComplexColumnVector retval (nr); | |
5275 | 975 for (octave_idx_type j = 0; j < nr; j++) |
4316 | 976 retval.xelem (j) = elem (j, i); |
458 | 977 |
978 return retval; | |
979 } | |
980 | |
981 ComplexMatrix | |
982 ComplexMatrix::inverse (void) const | |
983 { | |
5275 | 984 octave_idx_type info; |
479 | 985 double rcond; |
6207 | 986 MatrixType mattype (*this); |
987 return inverse (mattype, info, rcond, 0, 0); | |
988 } | |
989 | |
990 ComplexMatrix | |
6479 | 991 ComplexMatrix::inverse (octave_idx_type& info) const |
992 { | |
993 double rcond; | |
994 MatrixType mattype (*this); | |
995 return inverse (mattype, info, rcond, 0, 0); | |
996 } | |
997 | |
998 ComplexMatrix | |
999 ComplexMatrix::inverse (octave_idx_type& info, double& rcond, int force, | |
1000 int calc_cond) const | |
1001 { | |
1002 MatrixType mattype (*this); | |
6482 | 1003 return inverse (mattype, info, rcond, force, calc_cond); |
6479 | 1004 } |
1005 | |
1006 ComplexMatrix | |
6207 | 1007 ComplexMatrix::inverse (MatrixType &mattype) const |
1008 { | |
1009 octave_idx_type info; | |
1010 double rcond; | |
1011 return inverse (mattype, info, rcond, 0, 0); | |
1012 } | |
1013 | |
1014 ComplexMatrix | |
1015 ComplexMatrix::inverse (MatrixType &mattype, octave_idx_type& info) const | |
1016 { | |
1017 double rcond; | |
1018 return inverse (mattype, info, rcond, 0, 0); | |
458 | 1019 } |
1020 | |
1021 ComplexMatrix | |
6207 | 1022 ComplexMatrix::tinverse (MatrixType &mattype, octave_idx_type& info, |
1023 double& rcond, int force, int calc_cond) const | |
458 | 1024 { |
6207 | 1025 ComplexMatrix retval; |
1026 | |
1027 octave_idx_type nr = rows (); | |
1028 octave_idx_type nc = cols (); | |
1029 | |
1030 if (nr != nc || nr == 0 || nc == 0) | |
1031 (*current_liboctave_error_handler) ("inverse requires square matrix"); | |
1032 else | |
1033 { | |
1034 int typ = mattype.type (); | |
1035 char uplo = (typ == MatrixType::Lower ? 'L' : 'U'); | |
1036 char udiag = 'N'; | |
1037 retval = *this; | |
1038 Complex *tmp_data = retval.fortran_vec (); | |
1039 | |
1040 F77_XFCN (ztrtri, ZTRTRI, (F77_CONST_CHAR_ARG2 (&uplo, 1), | |
1041 F77_CONST_CHAR_ARG2 (&udiag, 1), | |
1042 nr, tmp_data, nr, info | |
1043 F77_CHAR_ARG_LEN (1) | |
1044 F77_CHAR_ARG_LEN (1))); | |
1045 | |
1046 if (f77_exception_encountered) | |
1047 (*current_liboctave_error_handler) ("unrecoverable error in ztrtri"); | |
1048 else | |
1049 { | |
1050 // Throw-away extra info LAPACK gives so as to not change output. | |
1051 rcond = 0.0; | |
1052 if (info != 0) | |
1053 info = -1; | |
1054 else if (calc_cond) | |
1055 { | |
1056 octave_idx_type ztrcon_info = 0; | |
1057 char job = '1'; | |
1058 | |
6482 | 1059 OCTAVE_LOCAL_BUFFER (Complex, cwork, 2*nr); |
6207 | 1060 OCTAVE_LOCAL_BUFFER (double, rwork, nr); |
1061 | |
1062 F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&job, 1), | |
1063 F77_CONST_CHAR_ARG2 (&uplo, 1), | |
1064 F77_CONST_CHAR_ARG2 (&udiag, 1), | |
1065 nr, tmp_data, nr, rcond, | |
1066 cwork, rwork, ztrcon_info | |
1067 F77_CHAR_ARG_LEN (1) | |
1068 F77_CHAR_ARG_LEN (1) | |
1069 F77_CHAR_ARG_LEN (1))); | |
1070 | |
1071 if (f77_exception_encountered) | |
1072 (*current_liboctave_error_handler) | |
1073 ("unrecoverable error in ztrcon"); | |
1074 | |
1075 if (ztrcon_info != 0) | |
1076 info = -1; | |
1077 } | |
1078 } | |
1079 | |
1080 if (info == -1 && ! force) | |
1081 retval = *this; // Restore matrix contents. | |
1082 } | |
1083 | |
1084 return retval; | |
458 | 1085 } |
1086 | |
1087 ComplexMatrix | |
6207 | 1088 ComplexMatrix::finverse (MatrixType &mattype, octave_idx_type& info, |
1089 double& rcond, int force, int calc_cond) const | |
458 | 1090 { |
1948 | 1091 ComplexMatrix retval; |
1092 | |
5275 | 1093 octave_idx_type nr = rows (); |
1094 octave_idx_type nc = cols (); | |
1948 | 1095 |
458 | 1096 if (nr != nc) |
1948 | 1097 (*current_liboctave_error_handler) ("inverse requires square matrix"); |
458 | 1098 else |
1099 { | |
5275 | 1100 Array<octave_idx_type> ipvt (nr); |
1101 octave_idx_type *pipvt = ipvt.fortran_vec (); | |
1948 | 1102 |
1103 retval = *this; | |
1104 Complex *tmp_data = retval.fortran_vec (); | |
1105 | |
4329 | 1106 Array<Complex> z(1); |
5275 | 1107 octave_idx_type lwork = -1; |
4330 | 1108 |
1109 // Query the optimum work array size. | |
4329 | 1110 |
1111 F77_XFCN (zgetri, ZGETRI, (nc, tmp_data, nr, pipvt, | |
1112 z.fortran_vec (), lwork, info)); | |
1113 | |
1114 if (f77_exception_encountered) | |
1115 { | |
1116 (*current_liboctave_error_handler) | |
1117 ("unrecoverable error in zgetri"); | |
1118 return retval; | |
1119 } | |
1120 | |
5315 | 1121 lwork = static_cast<octave_idx_type> (std::real(z(0))); |
4329 | 1122 lwork = (lwork < 2 *nc ? 2*nc : lwork); |
1123 z.resize (lwork); | |
1124 Complex *pz = z.fortran_vec (); | |
1125 | |
1126 info = 0; | |
1127 | |
4330 | 1128 // Calculate the norm of the matrix, for later use. |
4329 | 1129 double anorm; |
1130 if (calc_cond) | |
5275 | 1131 anorm = retval.abs().sum().row(static_cast<octave_idx_type>(0)).max(); |
4329 | 1132 |
1133 F77_XFCN (zgetrf, ZGETRF, (nc, nc, tmp_data, nr, pipvt, info)); | |
1948 | 1134 |
1135 if (f77_exception_encountered) | |
4329 | 1136 (*current_liboctave_error_handler) ("unrecoverable error in zgetrf"); |
1948 | 1137 else |
1138 { | |
4330 | 1139 // Throw-away extra info LAPACK gives so as to not change output. |
4509 | 1140 rcond = 0.0; |
1141 if (info != 0) | |
1948 | 1142 info = -1; |
4329 | 1143 else if (calc_cond) |
1144 { | |
4330 | 1145 // Now calculate the condition number for non-singular matrix. |
5275 | 1146 octave_idx_type zgecon_info = 0; |
4329 | 1147 char job = '1'; |
1148 Array<double> rz (2 * nc); | |
1149 double *prz = rz.fortran_vec (); | |
4552 | 1150 F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1), |
1151 nc, tmp_data, nr, anorm, | |
5061 | 1152 rcond, pz, prz, zgecon_info |
4552 | 1153 F77_CHAR_ARG_LEN (1))); |
4329 | 1154 |
1155 if (f77_exception_encountered) | |
1156 (*current_liboctave_error_handler) | |
1157 ("unrecoverable error in zgecon"); | |
1158 | |
5061 | 1159 if (zgecon_info != 0) |
4329 | 1160 info = -1; |
1161 } | |
1948 | 1162 |
1163 if (info == -1 && ! force) | |
1164 retval = *this; // Restore contents. | |
1165 else | |
1166 { | |
5275 | 1167 octave_idx_type zgetri_info = 0; |
5061 | 1168 |
4329 | 1169 F77_XFCN (zgetri, ZGETRI, (nc, tmp_data, nr, pipvt, |
5061 | 1170 pz, lwork, zgetri_info)); |
1948 | 1171 |
1172 if (f77_exception_encountered) | |
1173 (*current_liboctave_error_handler) | |
4329 | 1174 ("unrecoverable error in zgetri"); |
1175 | |
5061 | 1176 if (zgetri_info != 0) |
4329 | 1177 info = -1; |
1948 | 1178 } |
1179 } | |
6207 | 1180 |
1181 if (info != 0) | |
1182 mattype.mark_as_rectangular(); | |
458 | 1183 } |
4329 | 1184 |
1948 | 1185 return retval; |
458 | 1186 } |
1187 | |
1188 ComplexMatrix | |
6207 | 1189 ComplexMatrix::inverse (MatrixType &mattype, octave_idx_type& info, |
1190 double& rcond, int force, int calc_cond) const | |
1191 { | |
1192 int typ = mattype.type (false); | |
1193 ComplexMatrix ret; | |
1194 | |
1195 if (typ == MatrixType::Unknown) | |
1196 typ = mattype.type (*this); | |
1197 | |
1198 if (typ == MatrixType::Upper || typ == MatrixType::Lower) | |
1199 ret = tinverse (mattype, info, rcond, force, calc_cond); | |
6840 | 1200 else |
6207 | 1201 { |
1202 if (mattype.is_hermitian ()) | |
1203 { | |
6486 | 1204 ComplexCHOL chol (*this, info, calc_cond); |
6207 | 1205 if (info == 0) |
6486 | 1206 { |
1207 if (calc_cond) | |
1208 rcond = chol.rcond(); | |
1209 else | |
1210 rcond = 1.0; | |
1211 ret = chol.inverse (); | |
1212 } | |
6207 | 1213 else |
1214 mattype.mark_as_unsymmetric (); | |
1215 } | |
1216 | |
1217 if (!mattype.is_hermitian ()) | |
1218 ret = finverse(mattype, info, rcond, force, calc_cond); | |
6840 | 1219 |
7033 | 1220 if ((mattype.is_hermitian () || calc_cond) && rcond == 0.) |
6840 | 1221 ret = ComplexMatrix (rows (), columns (), Complex (octave_Inf, 0.)); |
6207 | 1222 } |
1223 | |
1224 return ret; | |
1225 } | |
1226 | |
1227 ComplexMatrix | |
4384 | 1228 ComplexMatrix::pseudo_inverse (double tol) const |
740 | 1229 { |
1549 | 1230 ComplexMatrix retval; |
1231 | |
3480 | 1232 ComplexSVD result (*this, SVD::economy); |
740 | 1233 |
1234 DiagMatrix S = result.singular_values (); | |
1235 ComplexMatrix U = result.left_singular_matrix (); | |
1236 ComplexMatrix V = result.right_singular_matrix (); | |
1237 | |
1238 ColumnVector sigma = S.diag (); | |
1239 | |
5275 | 1240 octave_idx_type r = sigma.length () - 1; |
1241 octave_idx_type nr = rows (); | |
1242 octave_idx_type nc = cols (); | |
740 | 1243 |
1244 if (tol <= 0.0) | |
1245 { | |
1246 if (nr > nc) | |
1247 tol = nr * sigma.elem (0) * DBL_EPSILON; | |
1248 else | |
1249 tol = nc * sigma.elem (0) * DBL_EPSILON; | |
1250 } | |
1251 | |
1252 while (r >= 0 && sigma.elem (r) < tol) | |
1253 r--; | |
1254 | |
1255 if (r < 0) | |
1549 | 1256 retval = ComplexMatrix (nc, nr, 0.0); |
740 | 1257 else |
1258 { | |
1259 ComplexMatrix Ur = U.extract (0, 0, nr-1, r); | |
1260 DiagMatrix D = DiagMatrix (sigma.extract (0, r)) . inverse (); | |
1261 ComplexMatrix Vr = V.extract (0, 0, nc-1, r); | |
1549 | 1262 retval = Vr * D * Ur.hermitian (); |
740 | 1263 } |
1549 | 1264 |
1265 return retval; | |
740 | 1266 } |
1267 | |
4773 | 1268 #if defined (HAVE_FFTW3) |
3827 | 1269 |
1270 ComplexMatrix | |
1271 ComplexMatrix::fourier (void) const | |
1272 { | |
1273 size_t nr = rows (); | |
1274 size_t nc = cols (); | |
1275 | |
1276 ComplexMatrix retval (nr, nc); | |
1277 | |
1278 size_t npts, nsamples; | |
1279 | |
1280 if (nr == 1 || nc == 1) | |
1281 { | |
1282 npts = nr > nc ? nr : nc; | |
1283 nsamples = 1; | |
1284 } | |
1285 else | |
1286 { | |
1287 npts = nr; | |
1288 nsamples = nc; | |
1289 } | |
1290 | |
1291 const Complex *in (data ()); | |
1292 Complex *out (retval.fortran_vec ()); | |
1293 | |
4773 | 1294 octave_fftw::fft (in, out, npts, nsamples); |
3827 | 1295 |
1296 return retval; | |
1297 } | |
1298 | |
1299 ComplexMatrix | |
1300 ComplexMatrix::ifourier (void) const | |
1301 { | |
1302 size_t nr = rows (); | |
1303 size_t nc = cols (); | |
1304 | |
1305 ComplexMatrix retval (nr, nc); | |
1306 | |
1307 size_t npts, nsamples; | |
1308 | |
1309 if (nr == 1 || nc == 1) | |
1310 { | |
1311 npts = nr > nc ? nr : nc; | |
1312 nsamples = 1; | |
1313 } | |
1314 else | |
1315 { | |
1316 npts = nr; | |
1317 nsamples = nc; | |
1318 } | |
1319 | |
1320 const Complex *in (data ()); | |
1321 Complex *out (retval.fortran_vec ()); | |
1322 | |
4773 | 1323 octave_fftw::ifft (in, out, npts, nsamples); |
3827 | 1324 |
1325 return retval; | |
1326 } | |
1327 | |
1328 ComplexMatrix | |
1329 ComplexMatrix::fourier2d (void) const | |
1330 { | |
4773 | 1331 dim_vector dv(rows (), cols ()); |
1332 | |
1333 ComplexMatrix retval (rows (), cols ()); | |
1334 const Complex *in (data ()); | |
1335 Complex *out (retval.fortran_vec ()); | |
1336 | |
1337 octave_fftw::fftNd (in, out, 2, dv); | |
3827 | 1338 |
1339 return retval; | |
1340 } | |
1341 | |
1342 ComplexMatrix | |
1343 ComplexMatrix::ifourier2d (void) const | |
1344 { | |
4773 | 1345 dim_vector dv(rows (), cols ()); |
1346 | |
1347 ComplexMatrix retval (rows (), cols ()); | |
1348 const Complex *in (data ()); | |
1349 Complex *out (retval.fortran_vec ()); | |
1350 | |
1351 octave_fftw::ifftNd (in, out, 2, dv); | |
3827 | 1352 |
1353 return retval; | |
1354 } | |
1355 | |
1356 #else | |
1357 | |
740 | 1358 ComplexMatrix |
458 | 1359 ComplexMatrix::fourier (void) const |
1360 { | |
1948 | 1361 ComplexMatrix retval; |
1362 | |
5275 | 1363 octave_idx_type nr = rows (); |
1364 octave_idx_type nc = cols (); | |
1365 | |
1366 octave_idx_type npts, nsamples; | |
1948 | 1367 |
458 | 1368 if (nr == 1 || nc == 1) |
1369 { | |
1370 npts = nr > nc ? nr : nc; | |
1371 nsamples = 1; | |
1372 } | |
1373 else | |
1374 { | |
1375 npts = nr; | |
1376 nsamples = nc; | |
1377 } | |
1378 | |
5275 | 1379 octave_idx_type nn = 4*npts+15; |
1948 | 1380 |
1381 Array<Complex> wsave (nn); | |
1382 Complex *pwsave = wsave.fortran_vec (); | |
1383 | |
1384 retval = *this; | |
1385 Complex *tmp_data = retval.fortran_vec (); | |
1386 | |
3887 | 1387 F77_FUNC (cffti, CFFTI) (npts, pwsave); |
458 | 1388 |
5275 | 1389 for (octave_idx_type j = 0; j < nsamples; j++) |
4153 | 1390 { |
1391 OCTAVE_QUIT; | |
1392 | |
1393 F77_FUNC (cfftf, CFFTF) (npts, &tmp_data[npts*j], pwsave); | |
1394 } | |
1948 | 1395 |
1396 return retval; | |
458 | 1397 } |
1398 | |
1399 ComplexMatrix | |
1400 ComplexMatrix::ifourier (void) const | |
1401 { | |
1948 | 1402 ComplexMatrix retval; |
1403 | |
5275 | 1404 octave_idx_type nr = rows (); |
1405 octave_idx_type nc = cols (); | |
1406 | |
1407 octave_idx_type npts, nsamples; | |
1948 | 1408 |
458 | 1409 if (nr == 1 || nc == 1) |
1410 { | |
1411 npts = nr > nc ? nr : nc; | |
1412 nsamples = 1; | |
1413 } | |
1414 else | |
1415 { | |
1416 npts = nr; | |
1417 nsamples = nc; | |
1418 } | |
1419 | |
5275 | 1420 octave_idx_type nn = 4*npts+15; |
1948 | 1421 |
1422 Array<Complex> wsave (nn); | |
1423 Complex *pwsave = wsave.fortran_vec (); | |
1424 | |
1425 retval = *this; | |
1426 Complex *tmp_data = retval.fortran_vec (); | |
1427 | |
3887 | 1428 F77_FUNC (cffti, CFFTI) (npts, pwsave); |
458 | 1429 |
5275 | 1430 for (octave_idx_type j = 0; j < nsamples; j++) |
4153 | 1431 { |
1432 OCTAVE_QUIT; | |
1433 | |
1434 F77_FUNC (cfftb, CFFTB) (npts, &tmp_data[npts*j], pwsave); | |
1435 } | |
458 | 1436 |
5275 | 1437 for (octave_idx_type j = 0; j < npts*nsamples; j++) |
3572 | 1438 tmp_data[j] = tmp_data[j] / static_cast<double> (npts); |
458 | 1439 |
1948 | 1440 return retval; |
458 | 1441 } |
1442 | |
677 | 1443 ComplexMatrix |
1444 ComplexMatrix::fourier2d (void) const | |
1445 { | |
1948 | 1446 ComplexMatrix retval; |
1447 | |
5275 | 1448 octave_idx_type nr = rows (); |
1449 octave_idx_type nc = cols (); | |
1450 | |
1451 octave_idx_type npts, nsamples; | |
1948 | 1452 |
677 | 1453 if (nr == 1 || nc == 1) |
1454 { | |
1455 npts = nr > nc ? nr : nc; | |
1456 nsamples = 1; | |
1457 } | |
1458 else | |
1459 { | |
1460 npts = nr; | |
1461 nsamples = nc; | |
1462 } | |
1463 | |
5275 | 1464 octave_idx_type nn = 4*npts+15; |
1948 | 1465 |
1466 Array<Complex> wsave (nn); | |
1467 Complex *pwsave = wsave.fortran_vec (); | |
1468 | |
1469 retval = *this; | |
1470 Complex *tmp_data = retval.fortran_vec (); | |
1471 | |
3887 | 1472 F77_FUNC (cffti, CFFTI) (npts, pwsave); |
677 | 1473 |
5275 | 1474 for (octave_idx_type j = 0; j < nsamples; j++) |
4153 | 1475 { |
1476 OCTAVE_QUIT; | |
1477 | |
1478 F77_FUNC (cfftf, CFFTF) (npts, &tmp_data[npts*j], pwsave); | |
1479 } | |
677 | 1480 |
1481 npts = nc; | |
1482 nsamples = nr; | |
1483 nn = 4*npts+15; | |
1948 | 1484 |
1485 wsave.resize (nn); | |
1486 pwsave = wsave.fortran_vec (); | |
1487 | |
4773 | 1488 Array<Complex> tmp (npts); |
1489 Complex *prow = tmp.fortran_vec (); | |
1948 | 1490 |
3887 | 1491 F77_FUNC (cffti, CFFTI) (npts, pwsave); |
677 | 1492 |
5275 | 1493 for (octave_idx_type j = 0; j < nsamples; j++) |
677 | 1494 { |
4153 | 1495 OCTAVE_QUIT; |
1496 | |
5275 | 1497 for (octave_idx_type i = 0; i < npts; i++) |
1948 | 1498 prow[i] = tmp_data[i*nr + j]; |
1499 | |
3887 | 1500 F77_FUNC (cfftf, CFFTF) (npts, prow, pwsave); |
677 | 1501 |
5275 | 1502 for (octave_idx_type i = 0; i < npts; i++) |
1948 | 1503 tmp_data[i*nr + j] = prow[i]; |
677 | 1504 } |
1505 | |
1948 | 1506 return retval; |
677 | 1507 } |
1508 | |
1509 ComplexMatrix | |
1510 ComplexMatrix::ifourier2d (void) const | |
1511 { | |
1948 | 1512 ComplexMatrix retval; |
1513 | |
5275 | 1514 octave_idx_type nr = rows (); |
1515 octave_idx_type nc = cols (); | |
1516 | |
1517 octave_idx_type npts, nsamples; | |
1948 | 1518 |
677 | 1519 if (nr == 1 || nc == 1) |
1520 { | |
1521 npts = nr > nc ? nr : nc; | |
1522 nsamples = 1; | |
1523 } | |
1524 else | |
1525 { | |
1526 npts = nr; | |
1527 nsamples = nc; | |
1528 } | |
1529 | |
5275 | 1530 octave_idx_type nn = 4*npts+15; |
1948 | 1531 |
1532 Array<Complex> wsave (nn); | |
1533 Complex *pwsave = wsave.fortran_vec (); | |
1534 | |
1535 retval = *this; | |
1536 Complex *tmp_data = retval.fortran_vec (); | |
1537 | |
3887 | 1538 F77_FUNC (cffti, CFFTI) (npts, pwsave); |
677 | 1539 |
5275 | 1540 for (octave_idx_type j = 0; j < nsamples; j++) |
4153 | 1541 { |
1542 OCTAVE_QUIT; | |
1543 | |
1544 F77_FUNC (cfftb, CFFTB) (npts, &tmp_data[npts*j], pwsave); | |
1545 } | |
677 | 1546 |
5275 | 1547 for (octave_idx_type j = 0; j < npts*nsamples; j++) |
3572 | 1548 tmp_data[j] = tmp_data[j] / static_cast<double> (npts); |
677 | 1549 |
1550 npts = nc; | |
1551 nsamples = nr; | |
1552 nn = 4*npts+15; | |
1948 | 1553 |
1554 wsave.resize (nn); | |
1555 pwsave = wsave.fortran_vec (); | |
1556 | |
4773 | 1557 Array<Complex> tmp (npts); |
1558 Complex *prow = tmp.fortran_vec (); | |
1948 | 1559 |
3887 | 1560 F77_FUNC (cffti, CFFTI) (npts, pwsave); |
677 | 1561 |
5275 | 1562 for (octave_idx_type j = 0; j < nsamples; j++) |
677 | 1563 { |
4153 | 1564 OCTAVE_QUIT; |
1565 | |
5275 | 1566 for (octave_idx_type i = 0; i < npts; i++) |
1948 | 1567 prow[i] = tmp_data[i*nr + j]; |
1568 | |
3887 | 1569 F77_FUNC (cfftb, CFFTB) (npts, prow, pwsave); |
677 | 1570 |
5275 | 1571 for (octave_idx_type i = 0; i < npts; i++) |
3572 | 1572 tmp_data[i*nr + j] = prow[i] / static_cast<double> (npts); |
677 | 1573 } |
1574 | |
1948 | 1575 return retval; |
677 | 1576 } |
1577 | |
3827 | 1578 #endif |
1579 | |
458 | 1580 ComplexDET |
1581 ComplexMatrix::determinant (void) const | |
1582 { | |
5275 | 1583 octave_idx_type info; |
458 | 1584 double rcond; |
4329 | 1585 return determinant (info, rcond, 0); |
458 | 1586 } |
1587 | |
1588 ComplexDET | |
5275 | 1589 ComplexMatrix::determinant (octave_idx_type& info) const |
458 | 1590 { |
1591 double rcond; | |
4329 | 1592 return determinant (info, rcond, 0); |
458 | 1593 } |
1594 | |
1595 ComplexDET | |
5275 | 1596 ComplexMatrix::determinant (octave_idx_type& info, double& rcond, int calc_cond) const |
458 | 1597 { |
1598 ComplexDET retval; | |
1599 | |
5275 | 1600 octave_idx_type nr = rows (); |
1601 octave_idx_type nc = cols (); | |
458 | 1602 |
1603 if (nr == 0 || nc == 0) | |
1604 { | |
5634 | 1605 retval = ComplexDET (1.0, 0); |
458 | 1606 } |
1607 else | |
1608 { | |
5275 | 1609 Array<octave_idx_type> ipvt (nr); |
1610 octave_idx_type *pipvt = ipvt.fortran_vec (); | |
1948 | 1611 |
1612 ComplexMatrix atmp = *this; | |
1613 Complex *tmp_data = atmp.fortran_vec (); | |
1614 | |
4329 | 1615 info = 0; |
1616 | |
4330 | 1617 // Calculate the norm of the matrix, for later use. |
4329 | 1618 double anorm = 0; |
1619 if (calc_cond) | |
5275 | 1620 anorm = atmp.abs().sum().row(static_cast<octave_idx_type>(0)).max(); |
4329 | 1621 |
1622 F77_XFCN (zgetrf, ZGETRF, (nr, nc, tmp_data, nr, pipvt, info)); | |
1948 | 1623 |
1624 if (f77_exception_encountered) | |
4329 | 1625 (*current_liboctave_error_handler) ("unrecoverable error in zgetrf"); |
458 | 1626 else |
1627 { | |
4330 | 1628 // Throw-away extra info LAPACK gives so as to not change output. |
4509 | 1629 rcond = 0.0; |
1630 if (info != 0) | |
1948 | 1631 { |
1632 info = -1; | |
1633 retval = ComplexDET (); | |
4329 | 1634 } |
1635 else | |
1948 | 1636 { |
4329 | 1637 if (calc_cond) |
1638 { | |
4330 | 1639 // Now calc the condition number for non-singular matrix. |
4329 | 1640 char job = '1'; |
1641 Array<Complex> z (2*nr); | |
1642 Complex *pz = z.fortran_vec (); | |
1643 Array<double> rz (2*nr); | |
1644 double *prz = rz.fortran_vec (); | |
1645 | |
4552 | 1646 F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1), |
1647 nc, tmp_data, nr, anorm, | |
1648 rcond, pz, prz, info | |
1649 F77_CHAR_ARG_LEN (1))); | |
4329 | 1650 |
1651 if (f77_exception_encountered) | |
1652 (*current_liboctave_error_handler) | |
1653 ("unrecoverable error in zgecon"); | |
1654 } | |
1655 | |
4509 | 1656 if (info != 0) |
4329 | 1657 { |
1658 info = -1; | |
1659 retval = ComplexDET (); | |
1660 } | |
1661 else | |
1662 { | |
5634 | 1663 Complex c = 1.0; |
1664 int e = 0; | |
1665 | |
1666 for (octave_idx_type i = 0; i < nc; i++) | |
4329 | 1667 { |
5634 | 1668 if (ipvt(i) != (i+1)) |
1669 c = -c; | |
1670 | |
1671 c *= atmp(i,i); | |
1672 | |
1673 if (c == 0.0) | |
1674 break; | |
1675 | |
1676 while (std::abs(c) < 0.5) | |
4329 | 1677 { |
5634 | 1678 c *= 2.0; |
1679 e--; | |
4329 | 1680 } |
5634 | 1681 |
1682 while (std::abs(c) >= 2.0) | |
4329 | 1683 { |
5634 | 1684 c /= 2.0; |
1685 e++; | |
4329 | 1686 } |
1687 } | |
5634 | 1688 |
1689 retval = ComplexDET (c, e); | |
4329 | 1690 } |
1948 | 1691 } |
458 | 1692 } |
1693 } | |
4329 | 1694 |
458 | 1695 return retval; |
1696 } | |
1697 | |
1698 ComplexMatrix | |
5785 | 1699 ComplexMatrix::utsolve (MatrixType &mattype, const ComplexMatrix& b, |
1700 octave_idx_type& info, double& rcond, | |
1701 solve_singularity_handler sing_handler, | |
1702 bool calc_cond) const | |
1703 { | |
1704 ComplexMatrix retval; | |
1705 | |
1706 octave_idx_type nr = rows (); | |
1707 octave_idx_type nc = cols (); | |
1708 | |
6924 | 1709 if (nr != b.rows ()) |
5785 | 1710 (*current_liboctave_error_handler) |
1711 ("matrix dimension mismatch solution of linear equations"); | |
6924 | 1712 else if (nr == 0 || nc == 0 || b.cols () == 0) |
1713 retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0)); | |
5785 | 1714 else |
1715 { | |
1716 volatile int typ = mattype.type (); | |
1717 | |
1718 if (typ == MatrixType::Permuted_Upper || | |
1719 typ == MatrixType::Upper) | |
1720 { | |
1721 octave_idx_type b_nc = b.cols (); | |
1722 rcond = 1.; | |
1723 info = 0; | |
1724 | |
1725 if (typ == MatrixType::Permuted_Upper) | |
1726 { | |
1727 (*current_liboctave_error_handler) | |
6390 | 1728 ("permuted triangular matrix not implemented"); |
5785 | 1729 } |
1730 else | |
1731 { | |
1732 const Complex *tmp_data = fortran_vec (); | |
1733 | |
1734 if (calc_cond) | |
1735 { | |
1736 char norm = '1'; | |
1737 char uplo = 'U'; | |
1738 char dia = 'N'; | |
1739 | |
1740 Array<Complex> z (2 * nc); | |
1741 Complex *pz = z.fortran_vec (); | |
1742 Array<double> rz (nc); | |
1743 double *prz = rz.fortran_vec (); | |
1744 | |
1745 F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1), | |
1746 F77_CONST_CHAR_ARG2 (&uplo, 1), | |
1747 F77_CONST_CHAR_ARG2 (&dia, 1), | |
1748 nr, tmp_data, nr, rcond, | |
1749 pz, prz, info | |
1750 F77_CHAR_ARG_LEN (1) | |
1751 F77_CHAR_ARG_LEN (1) | |
1752 F77_CHAR_ARG_LEN (1))); | |
1753 | |
1754 if (f77_exception_encountered) | |
1755 (*current_liboctave_error_handler) | |
1756 ("unrecoverable error in ztrcon"); | |
1757 | |
1758 if (info != 0) | |
1759 info = -2; | |
1760 | |
1761 volatile double rcond_plus_one = rcond + 1.0; | |
1762 | |
1763 if (rcond_plus_one == 1.0 || xisnan (rcond)) | |
1764 { | |
1765 info = -2; | |
1766 | |
1767 if (sing_handler) | |
1768 sing_handler (rcond); | |
1769 else | |
1770 (*current_liboctave_error_handler) | |
1771 ("matrix singular to machine precision, rcond = %g", | |
1772 rcond); | |
1773 } | |
1774 } | |
1775 | |
1776 if (info == 0) | |
1777 { | |
1778 retval = b; | |
1779 Complex *result = retval.fortran_vec (); | |
1780 | |
1781 char uplo = 'U'; | |
1782 char trans = 'N'; | |
1783 char dia = 'N'; | |
1784 | |
1785 F77_XFCN (ztrtrs, ZTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1), | |
1786 F77_CONST_CHAR_ARG2 (&trans, 1), | |
1787 F77_CONST_CHAR_ARG2 (&dia, 1), | |
1788 nr, b_nc, tmp_data, nr, | |
1789 result, nr, info | |
1790 F77_CHAR_ARG_LEN (1) | |
1791 F77_CHAR_ARG_LEN (1) | |
1792 F77_CHAR_ARG_LEN (1))); | |
1793 | |
1794 if (f77_exception_encountered) | |
1795 (*current_liboctave_error_handler) | |
1796 ("unrecoverable error in dtrtrs"); | |
1797 } | |
1798 } | |
1799 } | |
1800 else | |
1801 (*current_liboctave_error_handler) ("incorrect matrix type"); | |
1802 } | |
1803 | |
1804 return retval; | |
1805 } | |
1806 | |
1807 ComplexMatrix | |
1808 ComplexMatrix::ltsolve (MatrixType &mattype, const ComplexMatrix& b, | |
1809 octave_idx_type& info, double& rcond, | |
1810 solve_singularity_handler sing_handler, | |
1811 bool calc_cond) const | |
1812 { | |
1813 ComplexMatrix retval; | |
1814 | |
1815 octave_idx_type nr = rows (); | |
1816 octave_idx_type nc = cols (); | |
1817 | |
6924 | 1818 if (nr != b.rows ()) |
5785 | 1819 (*current_liboctave_error_handler) |
1820 ("matrix dimension mismatch solution of linear equations"); | |
6924 | 1821 else if (nr == 0 || nc == 0 || b.cols () == 0) |
1822 retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0)); | |
5785 | 1823 else |
1824 { | |
1825 volatile int typ = mattype.type (); | |
1826 | |
1827 if (typ == MatrixType::Permuted_Lower || | |
1828 typ == MatrixType::Lower) | |
1829 { | |
1830 octave_idx_type b_nc = b.cols (); | |
1831 rcond = 1.; | |
1832 info = 0; | |
1833 | |
1834 if (typ == MatrixType::Permuted_Lower) | |
1835 { | |
1836 (*current_liboctave_error_handler) | |
6390 | 1837 ("permuted triangular matrix not implemented"); |
5785 | 1838 } |
1839 else | |
1840 { | |
1841 const Complex *tmp_data = fortran_vec (); | |
1842 | |
1843 if (calc_cond) | |
1844 { | |
1845 char norm = '1'; | |
1846 char uplo = 'L'; | |
1847 char dia = 'N'; | |
1848 | |
1849 Array<Complex> z (2 * nc); | |
1850 Complex *pz = z.fortran_vec (); | |
1851 Array<double> rz (nc); | |
1852 double *prz = rz.fortran_vec (); | |
1853 | |
1854 F77_XFCN (ztrcon, ZTRCON, (F77_CONST_CHAR_ARG2 (&norm, 1), | |
1855 F77_CONST_CHAR_ARG2 (&uplo, 1), | |
1856 F77_CONST_CHAR_ARG2 (&dia, 1), | |
1857 nr, tmp_data, nr, rcond, | |
1858 pz, prz, info | |
1859 F77_CHAR_ARG_LEN (1) | |
1860 F77_CHAR_ARG_LEN (1) | |
1861 F77_CHAR_ARG_LEN (1))); | |
1862 | |
1863 if (f77_exception_encountered) | |
1864 (*current_liboctave_error_handler) | |
1865 ("unrecoverable error in ztrcon"); | |
1866 | |
1867 if (info != 0) | |
1868 info = -2; | |
1869 | |
1870 volatile double rcond_plus_one = rcond + 1.0; | |
1871 | |
1872 if (rcond_plus_one == 1.0 || xisnan (rcond)) | |
1873 { | |
1874 info = -2; | |
1875 | |
1876 if (sing_handler) | |
1877 sing_handler (rcond); | |
1878 else | |
1879 (*current_liboctave_error_handler) | |
1880 ("matrix singular to machine precision, rcond = %g", | |
1881 rcond); | |
1882 } | |
1883 } | |
1884 | |
1885 if (info == 0) | |
1886 { | |
1887 retval = b; | |
1888 Complex *result = retval.fortran_vec (); | |
1889 | |
1890 char uplo = 'L'; | |
1891 char trans = 'N'; | |
1892 char dia = 'N'; | |
1893 | |
1894 F77_XFCN (ztrtrs, ZTRTRS, (F77_CONST_CHAR_ARG2 (&uplo, 1), | |
1895 F77_CONST_CHAR_ARG2 (&trans, 1), | |
1896 F77_CONST_CHAR_ARG2 (&dia, 1), | |
1897 nr, b_nc, tmp_data, nr, | |
1898 result, nr, info | |
1899 F77_CHAR_ARG_LEN (1) | |
1900 F77_CHAR_ARG_LEN (1) | |
1901 F77_CHAR_ARG_LEN (1))); | |
1902 | |
1903 if (f77_exception_encountered) | |
1904 (*current_liboctave_error_handler) | |
1905 ("unrecoverable error in dtrtrs"); | |
1906 } | |
1907 } | |
1908 } | |
1909 else | |
1910 (*current_liboctave_error_handler) ("incorrect matrix type"); | |
1911 } | |
1912 | |
1913 return retval; | |
1914 } | |
1915 | |
1916 ComplexMatrix | |
1917 ComplexMatrix::fsolve (MatrixType &mattype, const ComplexMatrix& b, | |
1918 octave_idx_type& info, double& rcond, | |
1919 solve_singularity_handler sing_handler, | |
1920 bool calc_cond) const | |
1921 { | |
1922 ComplexMatrix retval; | |
1923 | |
1924 octave_idx_type nr = rows (); | |
1925 octave_idx_type nc = cols (); | |
1926 | |
6924 | 1927 |
1928 if (nr != nc || nr != b.rows ()) | |
5785 | 1929 (*current_liboctave_error_handler) |
6924 | 1930 ("matrix dimension mismatch solution of linear equations"); |
1931 else if (nr == 0 || b.cols () == 0) | |
1932 retval = ComplexMatrix (nc, b.cols (), Complex (0.0, 0.0)); | |
5785 | 1933 else |
1934 { | |
1935 volatile int typ = mattype.type (); | |
1936 | |
1937 // Calculate the norm of the matrix, for later use. | |
1938 double anorm = -1.; | |
1939 | |
1940 if (typ == MatrixType::Hermitian) | |
1941 { | |
1942 info = 0; | |
1943 char job = 'L'; | |
1944 ComplexMatrix atmp = *this; | |
1945 Complex *tmp_data = atmp.fortran_vec (); | |
1946 anorm = atmp.abs().sum().row(static_cast<octave_idx_type>(0)).max(); | |
1947 | |
1948 F77_XFCN (zpotrf, ZPOTRF, (F77_CONST_CHAR_ARG2 (&job, 1), nr, | |
1949 tmp_data, nr, info | |
1950 F77_CHAR_ARG_LEN (1))); | |
1951 | |
1952 if (f77_exception_encountered) | |
1953 (*current_liboctave_error_handler) | |
1954 ("unrecoverable error in zpotrf"); | |
1955 else | |
1956 { | |
1957 // Throw-away extra info LAPACK gives so as to not change output. | |
1958 rcond = 0.0; | |
1959 if (info != 0) | |
1960 { | |
1961 info = -2; | |
1962 | |
1963 mattype.mark_as_unsymmetric (); | |
1964 typ = MatrixType::Full; | |
1965 } | |
1966 else | |
1967 { | |
1968 if (calc_cond) | |
1969 { | |
1970 Array<Complex> z (2 * nc); | |
1971 Complex *pz = z.fortran_vec (); | |
1972 Array<double> rz (nc); | |
1973 double *prz = rz.fortran_vec (); | |
1974 | |
1975 F77_XFCN (zpocon, ZPOCON, (F77_CONST_CHAR_ARG2 (&job, 1), | |
1976 nr, tmp_data, nr, anorm, | |
1977 rcond, pz, prz, info | |
1978 F77_CHAR_ARG_LEN (1))); | |
1979 | |
1980 if (f77_exception_encountered) | |
1981 (*current_liboctave_error_handler) | |
1982 ("unrecoverable error in zpocon"); | |
1983 | |
1984 if (info != 0) | |
1985 info = -2; | |
1986 | |
1987 volatile double rcond_plus_one = rcond + 1.0; | |
1988 | |
1989 if (rcond_plus_one == 1.0 || xisnan (rcond)) | |
1990 { | |
1991 info = -2; | |
1992 | |
1993 if (sing_handler) | |
1994 sing_handler (rcond); | |
1995 else | |
1996 (*current_liboctave_error_handler) | |
1997 ("matrix singular to machine precision, rcond = %g", | |
1998 rcond); | |
1999 } | |
2000 } | |
2001 | |
2002 if (info == 0) | |
2003 { | |
2004 retval = b; | |
2005 Complex *result = retval.fortran_vec (); | |
2006 | |
2007 octave_idx_type b_nc = b.cols (); | |
2008 | |
2009 F77_XFCN (zpotrs, ZPOTRS, (F77_CONST_CHAR_ARG2 (&job, 1), | |
2010 nr, b_nc, tmp_data, nr, | |
2011 result, b.rows(), info | |
2012 F77_CHAR_ARG_LEN (1))); | |
2013 | |
2014 if (f77_exception_encountered) | |
2015 (*current_liboctave_error_handler) | |
2016 ("unrecoverable error in zpotrs"); | |
2017 } | |
2018 else | |
2019 { | |
2020 mattype.mark_as_unsymmetric (); | |
2021 typ = MatrixType::Full; | |
2022 } | |
2023 } | |
2024 } | |
2025 } | |
2026 | |
2027 if (typ == MatrixType::Full) | |
2028 { | |
2029 info = 0; | |
2030 | |
2031 Array<octave_idx_type> ipvt (nr); | |
2032 octave_idx_type *pipvt = ipvt.fortran_vec (); | |
2033 | |
2034 ComplexMatrix atmp = *this; | |
2035 Complex *tmp_data = atmp.fortran_vec (); | |
2036 | |
2037 Array<Complex> z (2 * nc); | |
2038 Complex *pz = z.fortran_vec (); | |
2039 Array<double> rz (2 * nc); | |
2040 double *prz = rz.fortran_vec (); | |
2041 | |
2042 // Calculate the norm of the matrix, for later use. | |
2043 if (anorm < 0.) | |
2044 anorm = atmp.abs().sum().row(static_cast<octave_idx_type>(0)).max(); | |
2045 | |
2046 F77_XFCN (zgetrf, ZGETRF, (nr, nr, tmp_data, nr, pipvt, info)); | |
2047 | |
2048 if (f77_exception_encountered) | |
2049 (*current_liboctave_error_handler) | |
2050 ("unrecoverable error in zgetrf"); | |
2051 else | |
2052 { | |
2053 // Throw-away extra info LAPACK gives so as to not change output. | |
2054 rcond = 0.0; | |
2055 if (info != 0) | |
2056 { | |
2057 info = -2; | |
2058 | |
2059 if (sing_handler) | |
2060 sing_handler (rcond); | |
2061 else | |
2062 (*current_liboctave_error_handler) | |
2063 ("matrix singular to machine precision"); | |
2064 | |
2065 mattype.mark_as_rectangular (); | |
2066 } | |
2067 else | |
2068 { | |
2069 if (calc_cond) | |
2070 { | |
2071 // Now calculate the condition number for | |
2072 // non-singular matrix. | |
2073 char job = '1'; | |
2074 F77_XFCN (zgecon, ZGECON, (F77_CONST_CHAR_ARG2 (&job, 1), | |
2075 nc, tmp_data, nr, anorm, | |
2076 rcond, pz, prz, info | |
2077 F77_CHAR_ARG_LEN (1))); | |
2078 | |
2079 if (f77_exception_encountered) | |
2080 (*current_liboctave_error_handler) | |
2081 ("unrecoverable error in zgecon"); | |
2082 | |
2083 if (info != 0) | |
2084 info = -2; | |
2085 | |
2086 volatile double rcond_plus_one = rcond + 1.0; | |
2087 | |
2088 if (rcond_plus_one == 1.0 || xisnan (rcond)) | |
2089 { | |
2090 info = -2; | |
2091 | |
2092 if (sing_handler) | |
2093 sing_handler (rcond); | |
2094 else | |
2095 (*current_liboctave_error_handler) | |
2096 ("matrix singular to machine precision, rcond = %g", | |
2097 rcond); | |
2098 } | |
2099 } | |
2100 | |
2101 if (info == 0) | |
2102 { | |
2103 retval = b; | |
2104 Complex *result = retval.fortran_vec (); | |
2105 | |
2106 octave_idx_type b_nc = b.cols (); | |
2107 | |
2108 char job = 'N'; | |
2109 F77_XFCN (zgetrs, ZGETRS, (F77_CONST_CHAR_ARG2 (&job, 1), | |
2110 nr, b_nc, tmp_data, nr, | |
2111 pipvt, result, b.rows(), info | |
2112 F77_CHAR_ARG_LEN (1))); | |
2113 | |
2114 if (f77_exception_encountered) | |
2115 (*current_liboctave_error_handler) | |
2116 ("unrecoverable error in zgetrs"); | |
2117 } | |
2118 else | |
2119 mattype.mark_as_rectangular (); | |
2120 } | |
2121 } | |
2122 } | |
2123 } | |
2124 | |
2125 return retval; | |
2126 } | |
2127 | |
2128 ComplexMatrix | |
2129 ComplexMatrix::solve (MatrixType &typ, const Matrix& b) const | |
2130 { | |
2131 octave_idx_type info; | |
2132 double rcond; | |
2133 return solve (typ, b, info, rcond, 0); | |
2134 } | |
2135 | |
2136 ComplexMatrix | |
2137 ComplexMatrix::solve (MatrixType &typ, const Matrix& b, | |
2138 octave_idx_type& info) const | |
2139 { | |
2140 double rcond; | |
2141 return solve (typ, b, info, rcond, 0); | |
2142 } | |
2143 | |
2144 ComplexMatrix | |
2145 ComplexMatrix::solve (MatrixType &typ, const Matrix& b, octave_idx_type& info, | |
2146 double& rcond) const | |
2147 { | |
2148 return solve (typ, b, info, rcond, 0); | |
2149 } | |
2150 | |
2151 ComplexMatrix | |
2152 ComplexMatrix::solve (MatrixType &typ, const Matrix& b, octave_idx_type& info, | |
2153 double& rcond, solve_singularity_handler sing_handler, | |
2154 bool singular_fallback) const | |
2155 { | |
2156 ComplexMatrix tmp (b); | |
2157 return solve (typ, tmp, info, rcond, sing_handler, singular_fallback); | |
2158 } | |
2159 | |
2160 ComplexMatrix | |
2161 ComplexMatrix::solve (MatrixType &typ, const ComplexMatrix& b) const | |
2162 { | |
2163 octave_idx_type info; | |
2164 double rcond; | |
2165 return solve (typ, b, info, rcond, 0); | |
2166 } | |
2167 | |
2168 ComplexMatrix | |
2169 ComplexMatrix::solve (MatrixType &typ, const ComplexMatrix& b, | |
2170 octave_idx_type& info) const | |
2171 { | |
2172 double rcond; | |
2173 return solve (typ, b, info, rcond, 0); | |
2174 } | |
2175 | |
2176 ComplexMatrix | |
2177 ComplexMatrix::solve (MatrixType &typ, const ComplexMatrix& b, | |
2178 octave_idx_type& info, double& rcond) const | |
2179 { | |
2180 return solve (typ, b, info, rcond, 0); | |
2181 } | |
2182 | |
2183 ComplexMatrix | |
2184 ComplexMatrix::solve (MatrixType &mattype, const ComplexMatrix& b, | |
2185 octave_idx_type& info, double& rcond, | |
2186 solve_singularity_handler sing_handler, | |
2187 bool singular_fallback) const | |
2188 { | |
2189 ComplexMatrix retval; | |
2190 int typ = mattype.type (); | |
2191 | |
2192 if (typ == MatrixType::Unknown) | |
2193 typ = mattype.type (*this); | |
2194 | |
2195 // Only calculate the condition number for LU/Cholesky | |
2196 if (typ == MatrixType::Upper || typ == MatrixType::Permuted_Upper) | |
2197 retval = utsolve (mattype, b, info, rcond, sing_handler, false); | |
2198 else if (typ == MatrixType::Lower || typ == MatrixType::Permuted_Lower) | |
2199 retval = ltsolve (mattype, b, info, rcond, sing_handler, false); | |
2200 else if (typ == MatrixType::Full || typ == MatrixType::Hermitian) | |
2201 retval = fsolve (mattype, b, info, rcond, sing_handler, true); | |
2202 else if (typ != MatrixType::Rectangular) | |
2203 { | |
2204 (*current_liboctave_error_handler) ("unknown matrix type"); | |
2205 return ComplexMatrix (); | |
2206 } | |
2207 | |
2208 // Rectangular or one of the above solvers flags a singular matrix | |
2209 if (singular_fallback && mattype.type () == MatrixType::Rectangular) | |
2210 { | |
2211 octave_idx_type rank; | |
7076 | 2212 retval = lssolve (b, info, rank, rcond); |
5785 | 2213 } |
2214 | |
2215 return retval; | |
2216 } | |
2217 | |
2218 ComplexColumnVector | |
2219 ComplexMatrix::solve (MatrixType &typ, const ColumnVector& b) const | |
2220 { | |
2221 octave_idx_type info; | |
2222 double rcond; | |
2223 return solve (typ, ComplexColumnVector (b), info, rcond, 0); | |
2224 } | |
2225 | |
2226 ComplexColumnVector | |
2227 ComplexMatrix::solve (MatrixType &typ, const ColumnVector& b, | |
2228 octave_idx_type& info) const | |
2229 { | |
2230 double rcond; | |
2231 return solve (typ, ComplexColumnVector (b), info, rcond, 0); | |
2232 } | |
2233 | |
2234 ComplexColumnVector | |
2235 ComplexMatrix::solve (MatrixType &typ, const ColumnVector& b, | |
2236 octave_idx_type& info, double& rcond) const | |
2237 { | |
2238 return solve (typ, ComplexColumnVector (b), info, rcond, 0); | |
2239 } | |
2240 | |
2241 ComplexColumnVector | |
2242 ComplexMatrix::solve (MatrixType &typ, const ColumnVector& b, | |
2243 octave_idx_type& info, double& rcond, | |
2244 solve_singularity_handler sing_handler) const | |
2245 { | |
2246 return solve (typ, ComplexColumnVector (b), info, rcond, sing_handler); | |
2247 } | |
2248 | |
2249 ComplexColumnVector | |
2250 ComplexMatrix::solve (MatrixType &typ, const ComplexColumnVector& b) const | |
2251 { | |
2252 octave_idx_type info; | |
2253 double rcond; | |
2254 return solve (typ, b, info, rcond, 0); | |
2255 } | |
2256 | |
2257 ComplexColumnVector | |
2258 ComplexMatrix::solve (MatrixType &typ, const ComplexColumnVector& b, | |
2259 octave_idx_type& info) const | |
2260 { | |
2261 double rcond; | |
2262 return solve (typ, b, info, rcond, 0); | |
2263 } | |
2264 | |
2265 ComplexColumnVector | |
2266 ComplexMatrix::solve (MatrixType &typ, const ComplexColumnVector& b, | |
2267 octave_idx_type& info, double& rcond) const | |
2268 { | |
2269 return solve (typ, b, info, rcond, 0); | |
2270 } | |
2271 | |
2272 ComplexColumnVector | |
2273 ComplexMatrix::solve (MatrixType &typ, const ComplexColumnVector& b, | |
2274 octave_idx_type& info, double& rcond, | |
2275 solve_singularity_handler sing_handler) const | |
2276 { | |
2277 | |
2278 ComplexMatrix tmp (b); | |
2279 return solve (typ, tmp, info, rcond, sing_handler).column(static_cast<octave_idx_type> (0)); | |
2280 } | |
2281 | |
2282 ComplexMatrix | |
458 | 2283 ComplexMatrix::solve (const Matrix& b) const |
2284 { | |
5275 | 2285 octave_idx_type info; |
458 | 2286 double rcond; |
3480 | 2287 return solve (b, info, rcond, 0); |
458 | 2288 } |
2289 | |
2290 ComplexMatrix | |
5275 | 2291 ComplexMatrix::solve (const Matrix& b, octave_idx_type& info) const |
458 | 2292 { |
2293 double rcond; | |
3480 | 2294 return solve (b, info, rcond, 0); |
458 | 2295 } |
2296 | |
2297 ComplexMatrix | |
5275 | 2298 ComplexMatrix::solve (const Matrix& b, octave_idx_type& info, double& rcond) const |
458 | 2299 { |
3480 | 2300 return solve (b, info, rcond, 0); |
2301 } | |
2302 | |
2303 ComplexMatrix | |
5275 | 2304 ComplexMatrix::solve (const Matrix& b, octave_idx_type& info, double& rcond, |
3480 | 2305 solve_singularity_handler sing_handler) const |
2306 { | |
458 | 2307 ComplexMatrix tmp (b); |
3480 | 2308 return solve (tmp, info, rcond, sing_handler); |
458 | 2309 } |
2310 | |
2311 ComplexMatrix | |
2312 ComplexMatrix::solve (const ComplexMatrix& b) const | |
2313 { | |
5275 | 2314 octave_idx_type info; |
458 | 2315 double rcond; |
3480 | 2316 return solve (b, info, rcond, 0); |
458 | 2317 } |
2318 | |
2319 ComplexMatrix | |
5275 | 2320 ComplexMatrix::solve (const ComplexMatrix& b, octave_idx_type& info) const |
458 | 2321 { |
2322 double rcond; | |
3480 | 2323 return solve (b, info, rcond, 0); |
458 | 2324 } |
3480 | 2325 |
458 | 2326 ComplexMatrix |
5275 | 2327 ComplexMatrix::solve (const ComplexMatrix& b, octave_idx_type& info, double& rcond) const |
458 | 2328 { |
3480 | 2329 return solve (b, info, rcond, 0); |
2330 } | |
2331 | |
2332 ComplexMatrix | |
5275 | 2333 ComplexMatrix::solve (const ComplexMatrix& b, octave_idx_type& info, double& rcond, |
3480 | 2334 solve_singularity_handler sing_handler) const |
2335 { | |
5785 | 2336 MatrixType mattype (*this); |
6060 | 2337 return solve (mattype, b, info, rcond, sing_handler); |
458 | 2338 } |
2339 | |
2340 ComplexColumnVector | |
3585 | 2341 ComplexMatrix::solve (const ColumnVector& b) const |
2342 { | |
5275 | 2343 octave_idx_type info; |
3585 | 2344 double rcond; |
2345 return solve (ComplexColumnVector (b), info, rcond, 0); | |
2346 } | |
2347 | |
2348 ComplexColumnVector | |
5275 | 2349 ComplexMatrix::solve (const ColumnVector& b, octave_idx_type& info) const |
3585 | 2350 { |
2351 double rcond; | |
2352 return solve (ComplexColumnVector (b), info, rcond, 0); | |
2353 } | |
2354 | |
2355 ComplexColumnVector | |
5785 | 2356 ComplexMatrix::solve (const ColumnVector& b, octave_idx_type& info, |
2357 double& rcond) const | |
3585 | 2358 { |
2359 return solve (ComplexColumnVector (b), info, rcond, 0); | |
2360 } | |
2361 | |
2362 ComplexColumnVector | |
5785 | 2363 ComplexMatrix::solve (const ColumnVector& b, octave_idx_type& info, |
2364 double& rcond, | |
3585 | 2365 solve_singularity_handler sing_handler) const |
2366 { | |
2367 return solve (ComplexColumnVector (b), info, rcond, sing_handler); | |
2368 } | |
2369 | |
2370 ComplexColumnVector | |
458 | 2371 ComplexMatrix::solve (const ComplexColumnVector& b) const |
2372 { | |
5275 | 2373 octave_idx_type info; |
458 | 2374 double rcond; |
3480 | 2375 return solve (b, info, rcond, 0); |
458 | 2376 } |
2377 | |
2378 ComplexColumnVector | |
5275 | 2379 ComplexMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info) const |
458 | 2380 { |
2381 double rcond; | |
3480 | 2382 return solve (b, info, rcond, 0); |
458 | 2383 } |
2384 | |
2385 ComplexColumnVector | |
5275 | 2386 ComplexMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info, |
532 | 2387 double& rcond) const |
458 | 2388 { |
3480 | 2389 return solve (b, info, rcond, 0); |
2390 } | |
2391 | |
2392 ComplexColumnVector | |
5275 | 2393 ComplexMatrix::solve (const ComplexColumnVector& b, octave_idx_type& info, |
3480 | 2394 double& rcond, |
2395 solve_singularity_handler sing_handler) const | |
2396 { | |
5785 | 2397 MatrixType mattype (*this); |
2398 return solve (mattype, b, info, rcond, sing_handler); | |
458 | 2399 } |
2400 | |
2401 ComplexMatrix | |
3585 | 2402 ComplexMatrix::lssolve (const Matrix& b) const |
2403 { | |
5275 | 2404 octave_idx_type info; |
2405 octave_idx_type rank; | |
7076 | 2406 double rcond; |
2407 return lssolve (ComplexMatrix (b), info, rank, rcond); | |
3585 | 2408 } |
2409 | |
2410 ComplexMatrix | |
5275 | 2411 ComplexMatrix::lssolve (const Matrix& b, octave_idx_type& info) const |
3585 | 2412 { |
5275 | 2413 octave_idx_type rank; |
7076 | 2414 double rcond; |
2415 return lssolve (ComplexMatrix (b), info, rank, rcond); | |
3585 | 2416 } |
2417 | |
2418 ComplexMatrix | |
7076 | 2419 ComplexMatrix::lssolve (const Matrix& b, octave_idx_type& info, |
2420 octave_idx_type& rank) const | |
3585 | 2421 { |
7076 | 2422 double rcond; |
2423 return lssolve (ComplexMatrix (b), info, rank, rcond); | |
2424 } | |
2425 | |
2426 ComplexMatrix | |
2427 ComplexMatrix::lssolve (const Matrix& b, octave_idx_type& info, | |
2428 octave_idx_type& rank, double& rcond) const | |
2429 { | |
2430 return lssolve (ComplexMatrix (b), info, rank, rcond); | |
3585 | 2431 } |
2432 | |
2433 ComplexMatrix | |
458 | 2434 ComplexMatrix::lssolve (const ComplexMatrix& b) const |
2435 { | |
5275 | 2436 octave_idx_type info; |
2437 octave_idx_type rank; | |
7076 | 2438 double rcond; |
2439 return lssolve (b, info, rank, rcond); | |
458 | 2440 } |
2441 | |
2442 ComplexMatrix | |
5275 | 2443 ComplexMatrix::lssolve (const ComplexMatrix& b, octave_idx_type& info) const |
458 | 2444 { |
5275 | 2445 octave_idx_type rank; |
7076 | 2446 double rcond; |
2447 return lssolve (b, info, rank, rcond); | |
458 | 2448 } |
2449 | |
2450 ComplexMatrix | |
7076 | 2451 ComplexMatrix::lssolve (const ComplexMatrix& b, octave_idx_type& info, |
2452 octave_idx_type& rank) const | |
2453 { | |
2454 double rcond; | |
2455 return lssolve (b, info, rank, rcond); | |
2456 } | |
2457 | |
2458 ComplexMatrix | |
2459 ComplexMatrix::lssolve (const ComplexMatrix& b, octave_idx_type& info, | |
2460 octave_idx_type& rank, double& rcond) const | |
458 | 2461 { |
1948 | 2462 ComplexMatrix retval; |
2463 | |
5275 | 2464 octave_idx_type nrhs = b.cols (); |
2465 | |
2466 octave_idx_type m = rows (); | |
2467 octave_idx_type n = cols (); | |
458 | 2468 |
6924 | 2469 if (m != b.rows ()) |
1948 | 2470 (*current_liboctave_error_handler) |
2471 ("matrix dimension mismatch solution of linear equations"); | |
6924 | 2472 else if (m== 0 || n == 0 || b.cols () == 0) |
2473 retval = ComplexMatrix (n, b.cols (), Complex (0.0, 0.0)); | |
1948 | 2474 else |
458 | 2475 { |
7072 | 2476 volatile octave_idx_type minmn = (m < n ? m : n); |
2477 octave_idx_type maxmn = m > n ? m : n; | |
7076 | 2478 rcond = -1.0; |
7072 | 2479 |
2480 if (m != n) | |
2481 { | |
2482 retval = ComplexMatrix (maxmn, nrhs); | |
2483 | |
2484 for (octave_idx_type j = 0; j < nrhs; j++) | |
2485 for (octave_idx_type i = 0; i < m; i++) | |
2486 retval.elem (i, j) = b.elem (i, j); | |
2487 } | |
2488 else | |
2489 retval = b; | |
2490 | |
1948 | 2491 ComplexMatrix atmp = *this; |
2492 Complex *tmp_data = atmp.fortran_vec (); | |
2493 | |
7072 | 2494 Complex *pretval = retval.fortran_vec (); |
2495 Array<double> s (minmn); | |
7071 | 2496 double *ps = s.fortran_vec (); |
2563 | 2497 |
7072 | 2498 // Ask ZGELSD what the dimension of WORK should be. |
5275 | 2499 octave_idx_type lwork = -1; |
3752 | 2500 |
2501 Array<Complex> work (1); | |
7079 | 2502 |
11646 | 2503 octave_idx_type smlsiz; |
2504 F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("ZGELSD", 6), | |
2505 F77_CONST_CHAR_ARG2 (" ", 1), | |
2506 0, 0, 0, 0, smlsiz | |
2507 F77_CHAR_ARG_LEN (6) | |
2508 F77_CHAR_ARG_LEN (1)); | |
7079 | 2509 |
11651
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2510 octave_idx_type mnthr; |
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2511 F77_FUNC (xilaenv, XILAENV) (6, F77_CONST_CHAR_ARG2 ("ZGELSD", 6), |
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2512 F77_CONST_CHAR_ARG2 (" ", 1), |
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2513 m, n, nrhs, -1, mnthr |
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2514 F77_CHAR_ARG_LEN (6) |
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2515 F77_CHAR_ARG_LEN (1)); |
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2516 |
7079 | 2517 // We compute the size of rwork and iwork because ZGELSD in |
2518 // older versions of LAPACK does not return them on a query | |
2519 // call. | |
7124 | 2520 double dminmn = static_cast<double> (minmn); |
2521 double dsmlsizp1 = static_cast<double> (smlsiz+1); | |
7079 | 2522 #if defined (HAVE_LOG2) |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2523 double tmp = log2 (dminmn / dsmlsizp1); |
7079 | 2524 #else |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2525 double tmp = log (dminmn / dsmlsizp1) / log (2.0); |
7079 | 2526 #endif |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2527 octave_idx_type nlvl = static_cast<octave_idx_type> (tmp) + 1; |
7079 | 2528 if (nlvl < 0) |
2529 nlvl = 0; | |
2530 | |
2531 octave_idx_type lrwork = minmn*(10 + 2*smlsiz + 8*nlvl) | |
2532 + 3*smlsiz*nrhs + (smlsiz+1)*(smlsiz+1); | |
2533 if (lrwork < 1) | |
2534 lrwork = 1; | |
2535 Array<double> rwork (lrwork); | |
2536 double *prwork = rwork.fortran_vec (); | |
2537 | |
2538 octave_idx_type liwork = 3 * minmn * nlvl + 11 * minmn; | |
2539 if (liwork < 1) | |
2540 liwork = 1; | |
2541 Array<octave_idx_type> iwork (liwork); | |
2542 octave_idx_type* piwork = iwork.fortran_vec (); | |
7072 | 2543 |
2544 F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn, | |
2545 ps, rcond, rank, work.fortran_vec (), | |
7079 | 2546 lwork, prwork, piwork, info)); |
1948 | 2547 |
11640 | 2548 // The workspace query is broken in at least LAPACK 3.0.0 |
11652
ef95e842ba81
another small xGELSD workspace fix
John W. Eaton <jwe@octave.org>
parents:
11651
diff
changeset
|
2549 // through 3.1.1 when n >= mnthr. The obtuse formula below |
11651
74de76325d12
more xGELSD workspace fixes
John W. Eaton <jwe@octave.org>
parents:
11646
diff
changeset
|
2550 // should provide sufficient workspace for ZGELSD to operate |
11640 | 2551 // efficiently. |
11652
ef95e842ba81
another small xGELSD workspace fix
John W. Eaton <jwe@octave.org>
parents:
11651
diff
changeset
|
2552 if (n >= mnthr) |
11640 | 2553 { |
2554 octave_idx_type addend = m; | |
2555 | |
2556 if (2*m-4 > addend) | |
2557 addend = 2*m-4; | |
2558 | |
2559 if (nrhs > addend) | |
2560 addend = nrhs; | |
2561 | |
2562 if (n-3*m > addend) | |
2563 addend = n-3*m; | |
2564 | |
2565 const octave_idx_type lworkaround = 4*m + m*m + addend; | |
2566 | |
2567 if (std::real (work(0)) < lworkaround) | |
2568 work(0) = lworkaround; | |
2569 } | |
11661
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2570 else if (m >= n) |
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2571 { |
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2572 octave_idx_type lworkaround = 2*m + m*nrhs; |
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2573 |
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2574 if (std::real (work(0)) < lworkaround) |
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2575 work(0) = lworkaround; |
ef2b2df1ed9a
avoid another xGELSD workspace query bug
John W. Eaton <jwe@octave.org>
parents:
11652
diff
changeset
|
2576 } |
11640 | 2577 |
1948 | 2578 if (f77_exception_encountered) |
7072 | 2579 (*current_liboctave_error_handler) |
2580 ("unrecoverable error in zgelsd"); | |
1948 | 2581 else |
2582 { | |
5315 | 2583 lwork = static_cast<octave_idx_type> (std::real (work(0))); |
3752 | 2584 work.resize (lwork); |
7072 | 2585 |
2586 F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, tmp_data, m, pretval, | |
2587 maxmn, ps, rcond, rank, | |
2588 work.fortran_vec (), lwork, | |
7079 | 2589 prwork, piwork, info)); |
3752 | 2590 |
2591 if (f77_exception_encountered) | |
7072 | 2592 (*current_liboctave_error_handler) |
2593 ("unrecoverable error in zgelsd"); | |
7076 | 2594 else |
2595 { | |
2596 if (rank < minmn) | |
2597 (*current_liboctave_warning_handler) | |
2598 ("zgelsd: rank deficient %dx%d matrix, rank = %d, tol = %e", | |
2599 m, n, rank, rcond); | |
2600 | |
2601 if (s.elem (0) == 0.0) | |
2602 rcond = 0.0; | |
2603 else | |
2604 rcond = s.elem (minmn - 1) / s.elem (0); | |
7079 | 2605 |
2606 retval.resize (n, nrhs); | |
7076 | 2607 } |
1948 | 2608 } |
458 | 2609 } |
2610 | |
2611 return retval; | |
2612 } | |
2613 | |
2614 ComplexColumnVector | |
3585 | 2615 ComplexMatrix::lssolve (const ColumnVector& b) const |
2616 { | |
5275 | 2617 octave_idx_type info; |
2618 octave_idx_type rank; | |
7076 | 2619 double rcond; |
2620 return lssolve (ComplexColumnVector (b), info, rank, rcond); | |
3585 | 2621 } |
2622 | |
2623 ComplexColumnVector | |
5275 | 2624 ComplexMatrix::lssolve (const ColumnVector& b, octave_idx_type& info) const |
3585 | 2625 { |
5275 | 2626 octave_idx_type rank; |
7076 | 2627 double rcond; |
2628 return lssolve (ComplexColumnVector (b), info, rank, rcond); | |
3585 | 2629 } |
2630 | |
2631 ComplexColumnVector | |
7076 | 2632 ComplexMatrix::lssolve (const ColumnVector& b, octave_idx_type& info, |
2633 octave_idx_type& rank) const | |
3585 | 2634 { |
7076 | 2635 double rcond; |
2636 return lssolve (ComplexColumnVector (b), info, rank, rcond); | |
2637 } | |
2638 | |
2639 ComplexColumnVector | |
2640 ComplexMatrix::lssolve (const ColumnVector& b, octave_idx_type& info, | |
2641 octave_idx_type& rank, double& rcond) const | |
2642 { | |
2643 return lssolve (ComplexColumnVector (b), info, rank, rcond); | |
3585 | 2644 } |
2645 | |
2646 ComplexColumnVector | |
458 | 2647 ComplexMatrix::lssolve (const ComplexColumnVector& b) const |
2648 { | |
5275 | 2649 octave_idx_type info; |
2650 octave_idx_type rank; | |
7076 | 2651 double rcond; |
2652 return lssolve (b, info, rank, rcond); | |
458 | 2653 } |
2654 | |
2655 ComplexColumnVector | |
5275 | 2656 ComplexMatrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info) const |
458 | 2657 { |
5275 | 2658 octave_idx_type rank; |
7076 | 2659 double rcond; |
2660 return lssolve (b, info, rank, rcond); | |
458 | 2661 } |
2662 | |
2663 ComplexColumnVector | |
5275 | 2664 ComplexMatrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info, |
2665 octave_idx_type& rank) const | |
458 | 2666 { |
7076 | 2667 double rcond; |
2668 return lssolve (b, info, rank, rcond); | |
2669 | |
2670 } | |
2671 | |
2672 ComplexColumnVector | |
2673 ComplexMatrix::lssolve (const ComplexColumnVector& b, octave_idx_type& info, | |
2674 octave_idx_type& rank, double& rcond) const | |
2675 { | |
1948 | 2676 ComplexColumnVector retval; |
2677 | |
5275 | 2678 octave_idx_type nrhs = 1; |
2679 | |
2680 octave_idx_type m = rows (); | |
2681 octave_idx_type n = cols (); | |
458 | 2682 |
6924 | 2683 if (m != b.length ()) |
1948 | 2684 (*current_liboctave_error_handler) |
6924 | 2685 ("matrix dimension mismatch solution of linear equations"); |
2686 else if (m == 0 || n == 0 || b.cols () == 0) | |
2687 retval = ComplexColumnVector (n, Complex (0.0, 0.0)); | |
1948 | 2688 else |
458 | 2689 { |
7072 | 2690 volatile octave_idx_type minmn = (m < n ? m : n); |
2691 octave_idx_type maxmn = m > n ? m : n; | |
7076 | 2692 rcond = -1.0; |
7072 | 2693 |
2694 if (m != n) | |
2695 { | |
2696 retval = ComplexColumnVector (maxmn); | |
2697 | |
2698 for (octave_idx_type i = 0; i < m; i++) | |
2699 retval.elem (i) = b.elem (i); | |
2700 } | |
2701 else | |
2702 retval = b; | |
2703 | |
1948 | 2704 ComplexMatrix atmp = *this; |
2705 Complex *tmp_data = atmp.fortran_vec (); | |
2706 | |
7072 | 2707 Complex *pretval = retval.fortran_vec (); |
2708 Array<double> s (minmn); | |
7071 | 2709 double *ps = s.fortran_vec (); |
1948 | 2710 |
7072 | 2711 // Ask ZGELSD what the dimension of WORK should be. |
5275 | 2712 octave_idx_type lwork = -1; |
3752 | 2713 |
2714 Array<Complex> work (1); | |
7079 | 2715 |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2716 octave_idx_type smlsiz; |
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2717 F77_FUNC (xilaenv, XILAENV) (9, F77_CONST_CHAR_ARG2 ("ZGELSD", 6), |
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2718 F77_CONST_CHAR_ARG2 (" ", 1), |
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2719 0, 0, 0, 0, smlsiz |
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2720 F77_CHAR_ARG_LEN (6) |
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2721 F77_CHAR_ARG_LEN (1)); |
7079 | 2722 |
2723 // We compute the size of rwork and iwork because ZGELSD in | |
2724 // older versions of LAPACK does not return them on a query | |
2725 // call. | |
7124 | 2726 double dminmn = static_cast<double> (minmn); |
2727 double dsmlsizp1 = static_cast<double> (smlsiz+1); | |
7079 | 2728 #if defined (HAVE_LOG2) |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2729 double tmp = log2 (dminmn / dsmlsizp1); |
7079 | 2730 #else |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2731 double tmp = log (dminmn / dsmlsizp1) / log (2.0); |
7079 | 2732 #endif |
11668
8ac2994e4596
more xGELSD workspace fixes
Jaroslav Hajek <highegg@gmail.com>
parents:
11661
diff
changeset
|
2733 octave_idx_type nlvl = static_cast<octave_idx_type> (tmp) + 1; |
7079 | 2734 if (nlvl < 0) |
2735 nlvl = 0; | |
2736 | |
2737 octave_idx_type lrwork = minmn*(10 + 2*smlsiz + 8*nlvl) | |
2738 + 3*smlsiz*nrhs + (smlsiz+1)*(smlsiz+1); | |
2739 if (lrwork < 1) | |
2740 lrwork = 1; | |
2741 Array<double> rwork (lrwork); | |
2742 double *prwork = rwork.fortran_vec (); | |
2743 | |
2744 octave_idx_type liwork = 3 * minmn * nlvl + 11 * minmn; | |
2745 if (liwork < 1) | |
2746 liwork = 1; | |
2747 Array<octave_idx_type> iwork (liwork); | |
2748 octave_idx_type* piwork = iwork.fortran_vec (); | |
7072 | 2749 |
2750 F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn, | |
2751 ps, rcond, rank, work.fortran_vec (), | |
7079 | 2752 lwork, prwork, piwork, info)); |
1948 | 2753 |
2754 if (f77_exception_encountered) | |
7072 | 2755 (*current_liboctave_error_handler) |
2756 ("unrecoverable error in zgelsd"); | |
1948 | 2757 else |
2758 { | |
7072 | 2759 lwork = static_cast<octave_idx_type> (std::real (work(0))); |
3752 | 2760 work.resize (lwork); |
7072 | 2761 rwork.resize (static_cast<octave_idx_type> (rwork(0))); |
2762 iwork.resize (iwork(0)); | |
2763 | |
2764 F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, tmp_data, m, pretval, | |
2765 maxmn, ps, rcond, rank, | |
2766 work.fortran_vec (), lwork, | |
7079 | 2767 prwork, piwork, info)); |
3752 | 2768 |
2769 if (f77_exception_encountered) | |
7072 | 2770 (*current_liboctave_error_handler) |
2771 ("unrecoverable error in zgelsd"); | |
2772 else if (rank < minmn) | |
7076 | 2773 { |
2774 if (rank < minmn) | |
2775 (*current_liboctave_warning_handler) | |
2776 ("zgelsd: rank deficient %dx%d matrix, rank = %d, tol = %e", | |
2777 m, n, rank, rcond); | |
2778 | |
2779 if (s.elem (0) == 0.0) | |
2780 rcond = 0.0; | |
2781 else | |
2782 rcond = s.elem (minmn - 1) / s.elem (0); | |
7079 | 2783 |
2784 retval.resize (n, nrhs); | |
7076 | 2785 } |
1948 | 2786 } |
458 | 2787 } |
2788 | |
2789 return retval; | |
2790 } | |
2791 | |
1819 | 2792 // Constants for matrix exponential calculation. |
2793 | |
2794 static double padec [] = | |
2795 { | |
2796 5.0000000000000000e-1, | |
2797 1.1666666666666667e-1, | |
2798 1.6666666666666667e-2, | |
2799 1.6025641025641026e-3, | |
2800 1.0683760683760684e-4, | |
2801 4.8562548562548563e-6, | |
2802 1.3875013875013875e-7, | |
2803 1.9270852604185938e-9, | |
2804 }; | |
2805 | |
2806 ComplexMatrix | |
2807 ComplexMatrix::expm (void) const | |
2808 { | |
2809 ComplexMatrix retval; | |
2810 | |
2811 ComplexMatrix m = *this; | |
2812 | |
5275 | 2813 octave_idx_type nc = columns (); |
1819 | 2814 |
3130 | 2815 // Preconditioning step 1: trace normalization to reduce dynamic |
2816 // range of poles, but avoid making stable eigenvalues unstable. | |
2817 | |
1819 | 2818 // trace shift value |
2819 Complex trshift = 0.0; | |
2820 | |
5275 | 2821 for (octave_idx_type i = 0; i < nc; i++) |
1819 | 2822 trshift += m.elem (i, i); |
2823 | |
2824 trshift /= nc; | |
2825 | |
3130 | 2826 if (trshift.real () < 0.0) |
6958 | 2827 { |
2828 trshift = trshift.imag (); | |
2829 if (trshift.real () > 709.0) | |
2830 trshift = 709.0; | |
2831 } | |
3130 | 2832 |
5275 | 2833 for (octave_idx_type i = 0; i < nc; i++) |
1819 | 2834 m.elem (i, i) -= trshift; |
2835 | |
2836 // Preconditioning step 2: eigenvalue balancing. | |
3331 | 2837 // code follows development in AEPBAL |
2838 | |
2839 Complex *mp = m.fortran_vec (); | |
3467 | 2840 |
5275 | 2841 octave_idx_type info, ilo, ihi,ilos,ihis; |
3468 | 2842 Array<double> dpermute (nc); |
2843 Array<double> dscale (nc); | |
2844 | |
5775 | 2845 // FIXME -- should pass job as a parameter in expm |
3468 | 2846 |
2847 // Permute first | |
2848 char job = 'P'; | |
4552 | 2849 F77_XFCN (zgebal, ZGEBAL, (F77_CONST_CHAR_ARG2 (&job, 1), |
2850 nc, mp, nc, ilo, ihi, | |
2851 dpermute.fortran_vec (), info | |
2852 F77_CHAR_ARG_LEN (1))); | |
3331 | 2853 |
2854 if (f77_exception_encountered) | |
2855 { | |
2856 (*current_liboctave_error_handler) ("unrecoverable error in zgebal"); | |
2857 return retval; | |
2858 } | |
2859 | |
3468 | 2860 // then scale |
2861 job = 'S'; | |
4552 | 2862 F77_XFCN (zgebal, ZGEBAL, (F77_CONST_CHAR_ARG2 (&job, 1), |
2863 nc, mp, nc, ilos, ihis, | |
2864 dscale.fortran_vec (), info | |
2865 F77_CHAR_ARG_LEN (1))); | |
3331 | 2866 |
2867 if (f77_exception_encountered) | |
2868 { | |
3467 | 2869 (*current_liboctave_error_handler) ("unrecoverable error in zgebal"); |
3331 | 2870 return retval; |
2871 } | |
1819 | 2872 |
2873 // Preconditioning step 3: scaling. | |
2874 | |
2875 ColumnVector work (nc); | |
3130 | 2876 double inf_norm; |
2877 | |
4552 | 2878 F77_XFCN (xzlange, XZLANGE, (F77_CONST_CHAR_ARG2 ("I", 1), |
2879 nc, nc, m.fortran_vec (), nc, | |
2880 work.fortran_vec (), inf_norm | |
2881 F77_CHAR_ARG_LEN (1))); | |
3331 | 2882 |
2883 if (f77_exception_encountered) | |
2884 { | |
2885 (*current_liboctave_error_handler) ("unrecoverable error in zlange"); | |
2886 return retval; | |
2887 } | |
1819 | 2888 |
2800 | 2889 int sqpow = (inf_norm > 0.0 |
2890 ? static_cast<int> (1.0 + log (inf_norm) / log (2.0)) : 0); | |
1819 | 2891 |
2892 // Check whether we need to square at all. | |
2893 | |
2894 if (sqpow < 0) | |
2895 sqpow = 0; | |
2896 | |
2897 if (sqpow > 0) | |
2898 { | |
11842
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2899 if (sqpow > 1023) |
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2900 sqpow = 1023; |
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2901 |
1819 | 2902 double scale_factor = 1.0; |
5275 | 2903 for (octave_idx_type i = 0; i < sqpow; i++) |
1819 | 2904 scale_factor *= 2.0; |
2905 | |
2906 m = m / scale_factor; | |
2907 } | |
2908 | |
2909 // npp, dpp: pade' approx polynomial matrices. | |
2910 | |
2911 ComplexMatrix npp (nc, nc, 0.0); | |
6958 | 2912 Complex *pnpp = npp.fortran_vec (); |
1819 | 2913 ComplexMatrix dpp = npp; |
6958 | 2914 Complex *pdpp = dpp.fortran_vec (); |
1819 | 2915 |
2916 // Now powers a^8 ... a^1. | |
2917 | |
2918 int minus_one_j = -1; | |
5275 | 2919 for (octave_idx_type j = 7; j >= 0; j--) |
1819 | 2920 { |
6958 | 2921 for (octave_idx_type i = 0; i < nc; i++) |
2922 { | |
2923 octave_idx_type k = i * nc + i; | |
7265 | 2924 pnpp[k] += padec[j]; |
2925 pdpp[k] += minus_one_j * padec[j]; | |
6958 | 2926 } |
7265 | 2927 |
6958 | 2928 npp = m * npp; |
7265 | 2929 pnpp = npp.fortran_vec (); |
2930 | |
6958 | 2931 dpp = m * dpp; |
7265 | 2932 pdpp = dpp.fortran_vec (); |
2933 | |
1819 | 2934 minus_one_j *= -1; |
2935 } | |
2936 | |
2937 // Zero power. | |
2938 | |
2939 dpp = -dpp; | |
5275 | 2940 for (octave_idx_type j = 0; j < nc; j++) |
1819 | 2941 { |
2942 npp.elem (j, j) += 1.0; | |
2943 dpp.elem (j, j) += 1.0; | |
2944 } | |
2945 | |
2946 // Compute pade approximation = inverse (dpp) * npp. | |
2947 | |
11842
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2948 retval = dpp.solve (npp, info); |
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2949 |
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2950 if (info < 0) |
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2951 return retval; |
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2952 |
1819 | 2953 // Reverse preconditioning step 3: repeated squaring. |
2954 | |
2955 while (sqpow) | |
2956 { | |
2957 retval = retval * retval; | |
2958 sqpow--; | |
2959 } | |
2960 | |
2961 // Reverse preconditioning step 2: inverse balancing. | |
3467 | 2962 // Done in two steps: inverse scaling, then inverse permutation |
2963 | |
2964 // inverse scaling (diagonal transformation) | |
5275 | 2965 for (octave_idx_type i = 0; i < nc; i++) |
2966 for (octave_idx_type j = 0; j < nc; j++) | |
11875
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2967 retval(i,j) *= dscale(i) / dscale(j); |
3467 | 2968 |
4153 | 2969 OCTAVE_QUIT; |
2970 | |
3467 | 2971 // construct balancing permutation vector |
6867 | 2972 Array<octave_idx_type> iperm (nc); |
5275 | 2973 for (octave_idx_type i = 0; i < nc; i++) |
11875
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2974 iperm(i) = i; // identity permutation |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2975 |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2976 // trailing permutations must be done in reverse order |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2977 for (octave_idx_type i = nc - 1; i >= ihi; i--) |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2978 { |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2979 octave_idx_type swapidx = static_cast<octave_idx_type> (dpermute(i)) - 1; |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2980 octave_idx_type tmp = iperm(i); |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2981 iperm(i) = iperm(swapidx); |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2982 iperm(swapidx) = tmp; |
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2983 } |
3467 | 2984 |
2985 // leading permutations in forward order | |
5275 | 2986 for (octave_idx_type i = 0; i < (ilo-1); i++) |
3468 | 2987 { |
6867 | 2988 octave_idx_type swapidx = static_cast<octave_idx_type> (dpermute(i)) - 1; |
5275 | 2989 octave_idx_type tmp = iperm(i); |
11875
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
2990 iperm(i) = iperm (swapidx); |
4593 | 2991 iperm(swapidx) = tmp; |
3468 | 2992 } |
3467 | 2993 |
11841 | 2994 // construct inverse balancing permutation vector |
11842
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
2995 Array<octave_idx_type> invpvec (nc); |
11841 | 2996 for (octave_idx_type i = 0; i < nc; i++) |
2997 invpvec(iperm(i)) = i; // Thanks to R. A. Lippert for this method | |
2998 | |
2999 OCTAVE_QUIT; | |
3000 | |
11842
0b9c56b6bf0e
partially sync Matrix::expm and ComplexMatrix::expm with development repo
Jaroslav Hajek <highegg@gmail.com>
parents:
11841
diff
changeset
|
3001 ComplexMatrix tmpMat = retval; |
11841 | 3002 for (octave_idx_type i = 0; i < nc; i++) |
3003 for (octave_idx_type j = 0; j < nc; j++) | |
3004 retval(i,j) = tmpMat(invpvec(i),invpvec(j)); | |
3005 | |
11875
f53f57d2ee51
improve inverse preconditioning according to Marco Caliari
Jaroslav Hajek <highegg@gmail.com>
parents:
11842
diff
changeset
|
3006 // Reverse preconditioning step 1: fix trace normalization. |
1819 | 3007 |
3130 | 3008 return exp (trshift) * retval; |
1819 | 3009 } |
3010 | |
1205 | 3011 // column vector by row vector -> matrix operations |
3012 | |
3013 ComplexMatrix | |
3014 operator * (const ColumnVector& v, const ComplexRowVector& a) | |
3015 { | |
3016 ComplexColumnVector tmp (v); | |
3017 return tmp * a; | |
3018 } | |
3019 | |
3020 ComplexMatrix | |
3021 operator * (const ComplexColumnVector& a, const RowVector& b) | |
3022 { | |
3023 ComplexRowVector tmp (b); | |
3024 return a * tmp; | |
3025 } | |
3026 | |
3027 ComplexMatrix | |
3028 operator * (const ComplexColumnVector& v, const ComplexRowVector& a) | |
3029 { | |
1948 | 3030 ComplexMatrix retval; |
3031 | |
5275 | 3032 octave_idx_type len = v.length (); |
3233 | 3033 |
3034 if (len != 0) | |
1205 | 3035 { |
5275 | 3036 octave_idx_type a_len = a.length (); |
3233 | 3037 |
3038 retval.resize (len, a_len); | |
3039 Complex *c = retval.fortran_vec (); | |
3040 | |
4552 | 3041 F77_XFCN (zgemm, ZGEMM, (F77_CONST_CHAR_ARG2 ("N", 1), |
3042 F77_CONST_CHAR_ARG2 ("N", 1), | |
3043 len, a_len, 1, 1.0, v.data (), len, | |
3044 a.data (), 1, 0.0, c, len | |
3045 F77_CHAR_ARG_LEN (1) | |
3046 F77_CHAR_ARG_LEN (1))); | |
3233 | 3047 |
3048 if (f77_exception_encountered) | |
3049 (*current_liboctave_error_handler) | |
3050 ("unrecoverable error in zgemm"); | |
1205 | 3051 } |
3052 | |
1948 | 3053 return retval; |
1205 | 3054 } |
3055 | |
458 | 3056 // matrix by diagonal matrix -> matrix operations |
3057 | |
3058 ComplexMatrix& | |
3059 ComplexMatrix::operator += (const DiagMatrix& a) | |
3060 { | |
5275 | 3061 octave_idx_type nr = rows (); |
3062 octave_idx_type nc = cols (); | |
3063 | |
3064 octave_idx_type a_nr = rows (); | |
3065 octave_idx_type a_nc = cols (); | |
2384 | 3066 |
3067 if (nr != a_nr || nc != a_nc) | |
458 | 3068 { |
2384 | 3069 gripe_nonconformant ("operator +=", nr, nc, a_nr, a_nc); |
889 | 3070 return *this; |
458 | 3071 } |
3072 | |
5275 | 3073 for (octave_idx_type i = 0; i < a.length (); i++) |
458 | 3074 elem (i, i) += a.elem (i, i); |
3075 | |
3076 return *this; | |
3077 } | |
3078 | |
3079 ComplexMatrix& | |
3080 ComplexMatrix::operator -= (const DiagMatrix& a) | |
3081 { | |
5275 | 3082 octave_idx_type nr = rows (); |
3083 octave_idx_type nc = cols (); | |
3084 | |
3085 octave_idx_type a_nr = rows (); | |
3086 octave_idx_type a_nc = cols (); | |
2384 | 3087 |
3088 if (nr != a_nr || nc != a_nc) | |
458 | 3089 { |
2384 | 3090 gripe_nonconformant ("operator -=", nr, nc, a_nr, a_nc); |
889 | 3091 return *this; |
458 | 3092 } |
3093 | |
5275 | 3094 for (octave_idx_type i = 0; i < a.length (); i++) |
458 | 3095 elem (i, i) -= a.elem (i, i); |
3096 | |
3097 return *this; | |
3098 } | |
3099 | |
3100 ComplexMatrix& | |
3101 ComplexMatrix::operator += (const ComplexDiagMatrix& a) | |
3102 { | |
5275 | 3103 octave_idx_type nr = rows (); |
3104 octave_idx_type nc = cols (); | |
3105 | |
3106 octave_idx_type a_nr = rows (); | |
3107 octave_idx_type a_nc = cols (); | |
2384 | 3108 |
3109 if (nr != a_nr || nc != a_nc) | |
458 | 3110 { |
2384 | 3111 gripe_nonconformant ("operator +=", nr, nc, a_nr, a_nc); |
889 | 3112 return *this; |
458 | 3113 } |
3114 | |
5275 | 3115 for (octave_idx_type i = 0; i < a.length (); i++) |
458 | 3116 elem (i, i) += a.elem (i, i); |
3117 | |
3118 return *this; | |
3119 } | |
3120 | |
3121 ComplexMatrix& | |
3122 ComplexMatrix::operator -= (const ComplexDiagMatrix& a) | |
3123 { | |
5275 | 3124 octave_idx_type nr = rows (); |
3125 octave_idx_type nc = cols (); | |
3126 | |
3127 octave_idx_type a_nr = rows (); | |
3128 octave_idx_type a_nc = cols (); | |
2384 | 3129 |
3130 if (nr != a_nr || nc != a_nc) | |
458 | 3131 { |
2384 | 3132 gripe_nonconformant ("operator -=", nr, nc, a_nr, a_nc); |
889 | 3133 return *this; |
458 | 3134 } |
3135 | |
5275 | 3136 for (octave_idx_type i = 0; i < a.length (); i++) |
458 | 3137 elem (i, i) -= a.elem (i, i); |
3138 | |
3139 return *this; | |
3140 } | |
3141 | |
3142 // matrix by matrix -> matrix operations | |
3143 | |
3144 ComplexMatrix& | |
3145 ComplexMatrix::operator += (const Matrix& a) | |
3146 { | |
5275 | 3147 octave_idx_type nr = rows (); |
3148 octave_idx_type nc = cols (); | |
3149 | |
3150 octave_idx_type a_nr = a.rows (); | |
3151 octave_idx_type a_nc = a.cols (); | |
2384 | 3152 |
3153 if (nr != a_nr || nc != a_nc) | |
458 | 3154 { |
2384 | 3155 gripe_nonconformant ("operator +=", nr, nc, a_nr, a_nc); |
458 | 3156 return *this; |
3157 } | |
3158 | |
3159 if (nr == 0 || nc == 0) | |
3160 return *this; | |
3161 | |
3162 Complex *d = fortran_vec (); // Ensures only one reference to my privates! | |
3163 | |
3769 | 3164 mx_inline_add2 (d, a.data (), length ()); |
458 | 3165 return *this; |
3166 } | |
3167 | |
3168 ComplexMatrix& | |
3169 ComplexMatrix::operator -= (const Matrix& a) | |
3170 { | |
5275 | 3171 octave_idx_type nr = rows (); |
3172 octave_idx_type nc = cols (); | |
3173 | |
3174 octave_idx_type a_nr = a.rows (); | |
3175 octave_idx_type a_nc = a.cols (); | |
2384 | 3176 |
3177 if (nr != a_nr || nc != a_nc) | |
458 | 3178 { |
2384 | 3179 gripe_nonconformant ("operator -=", nr, nc, a_nr, a_nc); |
458 | 3180 return *this; |
3181 } | |
3182 | |
3183 if (nr == 0 || nc == 0) | |
3184 return *this; | |
3185 | |
3186 Complex *d = fortran_vec (); // Ensures only one reference to my privates! | |
3187 | |
3769 | 3188 mx_inline_subtract2 (d, a.data (), length ()); |
458 | 3189 return *this; |
3190 } | |
3191 | |
3192 // unary operations | |
3193 | |
2964 | 3194 boolMatrix |
458 | 3195 ComplexMatrix::operator ! (void) const |
3196 { | |
5275 | 3197 octave_idx_type nr = rows (); |
3198 octave_idx_type nc = cols (); | |
2964 | 3199 |
3200 boolMatrix b (nr, nc); | |
3201 | |
5275 | 3202 for (octave_idx_type j = 0; j < nc; j++) |
3203 for (octave_idx_type i = 0; i < nr; i++) | |
5139 | 3204 b.elem (i, j) = elem (i, j) == 0.0; |
2964 | 3205 |
3206 return b; | |
458 | 3207 } |
3208 | |
3209 // other operations | |
3210 | |
3211 ComplexMatrix | |
2676 | 3212 ComplexMatrix::map (c_c_Mapper f) const |
458 | 3213 { |
2676 | 3214 ComplexMatrix b (*this); |
3215 return b.apply (f); | |
458 | 3216 } |
3217 | |
2676 | 3218 Matrix |
3219 ComplexMatrix::map (d_c_Mapper f) const | |
458 | 3220 { |
5275 | 3221 octave_idx_type nr = rows (); |
3222 octave_idx_type nc = cols (); | |
3248 | 3223 |
3224 Matrix retval (nr, nc); | |
3225 | |
5275 | 3226 for (octave_idx_type j = 0; j < nc; j++) |
3227 for (octave_idx_type i = 0; i < nr; i++) | |
3248 | 3228 retval(i,j) = f (elem(i,j)); |
3229 | |
3230 return retval; | |
3231 } | |
3232 | |
3233 boolMatrix | |
3234 ComplexMatrix::map (b_c_Mapper f) const | |
3235 { | |
5275 | 3236 octave_idx_type nr = rows (); |
3237 octave_idx_type nc = cols (); | |
3248 | 3238 |
3239 boolMatrix retval (nr, nc); | |
3240 | |
5275 | 3241 for (octave_idx_type j = 0; j < nc; j++) |
3242 for (octave_idx_type i = 0; i < nr; i++) | |
3248 | 3243 retval(i,j) = f (elem(i,j)); |
2676 | 3244 |
3245 return retval; | |
3246 } | |
3247 | |
3248 ComplexMatrix& | |
3249 ComplexMatrix::apply (c_c_Mapper f) | |
3250 { | |
3251 Complex *d = fortran_vec (); // Ensures only one reference to my privates! | |
3252 | |
5275 | 3253 for (octave_idx_type i = 0; i < length (); i++) |
2676 | 3254 d[i] = f (d[i]); |
3255 | |
3256 return *this; | |
458 | 3257 } |
3258 | |
2384 | 3259 bool |
3260 ComplexMatrix::any_element_is_inf_or_nan (void) const | |
3261 { | |
5275 | 3262 octave_idx_type nr = rows (); |
3263 octave_idx_type nc = cols (); | |
3264 | |
3265 for (octave_idx_type j = 0; j < nc; j++) | |
3266 for (octave_idx_type i = 0; i < nr; i++) | |
2384 | 3267 { |
3268 Complex val = elem (i, j); | |
3269 if (xisinf (val) || xisnan (val)) | |
3270 return true; | |
3271 } | |
3272 | |
3273 return false; | |
3274 } | |
3275 | |
2408 | 3276 // Return true if no elements have imaginary components. |
3277 | |
3278 bool | |
3279 ComplexMatrix::all_elements_are_real (void) const | |
3280 { | |
5275 | 3281 octave_idx_type nr = rows (); |
3282 octave_idx_type nc = cols (); | |
3283 | |
3284 for (octave_idx_type j = 0; j < nc; j++) | |
4349 | 3285 { |
5275 | 3286 for (octave_idx_type i = 0; i < nr; i++) |
4349 | 3287 { |
5315 | 3288 double ip = std::imag (elem (i, j)); |
4349 | 3289 |
3290 if (ip != 0.0 || lo_ieee_signbit (ip)) | |
3291 return false; | |
3292 } | |
3293 } | |
2408 | 3294 |
3295 return true; | |
3296 } | |
3297 | |
1968 | 3298 // Return nonzero if any element of CM has a non-integer real or |
3299 // imaginary part. Also extract the largest and smallest (real or | |
3300 // imaginary) values and return them in MAX_VAL and MIN_VAL. | |
3301 | |
2384 | 3302 bool |
1968 | 3303 ComplexMatrix::all_integers (double& max_val, double& min_val) const |
3304 { | |
5275 | 3305 octave_idx_type nr = rows (); |
3306 octave_idx_type nc = cols (); | |
1968 | 3307 |
3308 if (nr > 0 && nc > 0) | |
3309 { | |
3310 Complex val = elem (0, 0); | |
3311 | |
5315 | 3312 double r_val = std::real (val); |
3313 double i_val = std::imag (val); | |
1968 | 3314 |
3315 max_val = r_val; | |
3316 min_val = r_val; | |
3317 | |
3318 if (i_val > max_val) | |
3319 max_val = i_val; | |
3320 | |
3321 if (i_val < max_val) | |
3322 min_val = i_val; | |
3323 } | |
3324 else | |
2384 | 3325 return false; |
1968 | 3326 |
5275 | 3327 for (octave_idx_type j = 0; j < nc; j++) |
3328 for (octave_idx_type i = 0; i < nr; i++) | |
1968 | 3329 { |
3330 Complex val = elem (i, j); | |
3331 | |
5315 | 3332 double r_val = std::real (val); |
3333 double i_val = std::imag (val); | |
1968 | 3334 |
3335 if (r_val > max_val) | |
3336 max_val = r_val; | |
3337 | |
3338 if (i_val > max_val) | |
3339 max_val = i_val; | |
3340 | |
3341 if (r_val < min_val) | |
3342 min_val = r_val; | |
3343 | |
3344 if (i_val < min_val) | |
3345 min_val = i_val; | |
3346 | |
3347 if (D_NINT (r_val) != r_val || D_NINT (i_val) != i_val) | |
2384 | 3348 return false; |
1968 | 3349 } |
2384 | 3350 |
3351 return true; | |
1968 | 3352 } |
3353 | |
2384 | 3354 bool |
1968 | 3355 ComplexMatrix::too_large_for_float (void) const |
3356 { | |
5275 | 3357 octave_idx_type nr = rows (); |
3358 octave_idx_type nc = cols (); | |
3359 | |
3360 for (octave_idx_type j = 0; j < nc; j++) | |
3361 for (octave_idx_type i = 0; i < nr; i++) | |
1968 | 3362 { |
3363 Complex val = elem (i, j); | |
3364 | |
5315 | 3365 double r_val = std::real (val); |
3366 double i_val = std::imag (val); | |
1968 | 3367 |
5389 | 3368 if ((! (xisnan (r_val) || xisinf (r_val)) |
5387 | 3369 && fabs (r_val) > FLT_MAX) |
5389 | 3370 || (! (xisnan (i_val) || xisinf (i_val)) |
5387 | 3371 && fabs (i_val) > FLT_MAX)) |
2384 | 3372 return true; |
1968 | 3373 } |
3374 | |
2384 | 3375 return false; |
1968 | 3376 } |
3377 | |
5775 | 3378 // FIXME Do these really belong here? Maybe they should be |
4015 | 3379 // in a base class? |
3380 | |
2832 | 3381 boolMatrix |
4015 | 3382 ComplexMatrix::all (int dim) const |
458 | 3383 { |
4015 | 3384 MX_ALL_OP (dim); |
458 | 3385 } |
3386 | |
2832 | 3387 boolMatrix |
4015 | 3388 ComplexMatrix::any (int dim) const |
458 | 3389 { |
4015 | 3390 MX_ANY_OP (dim); |
458 | 3391 } |
3392 | |
3393 ComplexMatrix | |
3723 | 3394 ComplexMatrix::cumprod (int dim) const |
458 | 3395 { |
4015 | 3396 MX_CUMULATIVE_OP (ComplexMatrix, Complex, *=); |
458 | 3397 } |
3398 | |
3399 ComplexMatrix | |
3723 | 3400 ComplexMatrix::cumsum (int dim) const |
458 | 3401 { |
4015 | 3402 MX_CUMULATIVE_OP (ComplexMatrix, Complex, +=); |
458 | 3403 } |
3404 | |
3405 ComplexMatrix | |
3723 | 3406 ComplexMatrix::prod (int dim) const |
458 | 3407 { |
3864 | 3408 MX_REDUCTION_OP (ComplexMatrix, *=, 1.0, 1.0); |
458 | 3409 } |
3410 | |
3411 ComplexMatrix | |
3723 | 3412 ComplexMatrix::sum (int dim) const |
458 | 3413 { |
3864 | 3414 MX_REDUCTION_OP (ComplexMatrix, +=, 0.0, 0.0); |
458 | 3415 } |
3416 | |
3417 ComplexMatrix | |
3723 | 3418 ComplexMatrix::sumsq (int dim) const |
458 | 3419 { |
3864 | 3420 #define ROW_EXPR \ |
3421 Complex d = elem (i, j); \ | |
3422 retval.elem (i, 0) += d * conj (d) | |
3423 | |
3424 #define COL_EXPR \ | |
3425 Complex d = elem (i, j); \ | |
3426 retval.elem (0, j) += d * conj (d) | |
3427 | |
3428 MX_BASE_REDUCTION_OP (ComplexMatrix, ROW_EXPR, COL_EXPR, 0.0, 0.0); | |
3429 | |
3430 #undef ROW_EXPR | |
3431 #undef COL_EXPR | |
458 | 3432 } |
3433 | |
4329 | 3434 Matrix ComplexMatrix::abs (void) const |
3435 { | |
5275 | 3436 octave_idx_type nr = rows (); |
3437 octave_idx_type nc = cols (); | |
4329 | 3438 |
3439 Matrix retval (nr, nc); | |
3440 | |
5275 | 3441 for (octave_idx_type j = 0; j < nc; j++) |
3442 for (octave_idx_type i = 0; i < nr; i++) | |
5315 | 3443 retval (i, j) = std::abs (elem (i, j)); |
4329 | 3444 |
3445 return retval; | |
3446 } | |
3447 | |
458 | 3448 ComplexColumnVector |
3449 ComplexMatrix::diag (void) const | |
3450 { | |
3451 return diag (0); | |
3452 } | |
3453 | |
3454 ComplexColumnVector | |
5275 | 3455 ComplexMatrix::diag (octave_idx_type k) const |
458 | 3456 { |
5275 | 3457 octave_idx_type nnr = rows (); |
3458 octave_idx_type nnc = cols (); | |
458 | 3459 if (k > 0) |
3460 nnc -= k; | |
3461 else if (k < 0) | |
3462 nnr += k; | |
3463 | |
3464 ComplexColumnVector d; | |
3465 | |
3466 if (nnr > 0 && nnc > 0) | |
3467 { | |
5275 | 3468 octave_idx_type ndiag = (nnr < nnc) ? nnr : nnc; |
458 | 3469 |
3470 d.resize (ndiag); | |
3471 | |
3472 if (k > 0) | |
3473 { | |
5275 | 3474 for (octave_idx_type i = 0; i < ndiag; i++) |
458 | 3475 d.elem (i) = elem (i, i+k); |
3476 } | |
4509 | 3477 else if (k < 0) |
458 | 3478 { |
5275 | 3479 for (octave_idx_type i = 0; i < ndiag; i++) |
458 | 3480 d.elem (i) = elem (i-k, i); |
3481 } | |
3482 else | |
3483 { | |
5275 | 3484 for (octave_idx_type i = 0; i < ndiag; i++) |
458 | 3485 d.elem (i) = elem (i, i); |
3486 } | |
3487 } | |
3488 else | |
4513 | 3489 (*current_liboctave_error_handler) |
3490 ("diag: requested diagonal out of range"); | |
458 | 3491 |
3492 return d; | |
3493 } | |
3494 | |
2354 | 3495 bool |
5275 | 3496 ComplexMatrix::row_is_real_only (octave_idx_type i) const |
2354 | 3497 { |
3498 bool retval = true; | |
3499 | |
5275 | 3500 octave_idx_type nc = columns (); |
3501 | |
3502 for (octave_idx_type j = 0; j < nc; j++) | |
2354 | 3503 { |
5315 | 3504 if (std::imag (elem (i, j)) != 0.0) |
2354 | 3505 { |
3506 retval = false; | |
3507 break; | |
3508 } | |
3509 } | |
3510 | |
3511 return retval; | |
3512 } | |
3513 | |
3514 bool | |
5275 | 3515 ComplexMatrix::column_is_real_only (octave_idx_type j) const |
2354 | 3516 { |
3517 bool retval = true; | |
3518 | |
5275 | 3519 octave_idx_type nr = rows (); |
3520 | |
3521 for (octave_idx_type i = 0; i < nr; i++) | |
2354 | 3522 { |
5315 | 3523 if (std::imag (elem (i, j)) != 0.0) |
2354 | 3524 { |
3525 retval = false; | |
3526 break; | |
3527 } | |
3528 } | |
3529 | |
3530 return retval; | |
3531 } | |
891 | 3532 |
458 | 3533 ComplexColumnVector |
3534 ComplexMatrix::row_min (void) const | |
3535 { | |
5275 | 3536 Array<octave_idx_type> dummy_idx; |
4587 | 3537 return row_min (dummy_idx); |
458 | 3538 } |
3539 | |
3540 ComplexColumnVector | |
5275 | 3541 ComplexMatrix::row_min (Array<octave_idx_type>& idx_arg) const |
458 | 3542 { |
3543 ComplexColumnVector result; | |
3544 | |
5275 | 3545 octave_idx_type nr = rows (); |
3546 octave_idx_type nc = cols (); | |
458 | 3547 |
3548 if (nr > 0 && nc > 0) | |
3549 { | |
3550 result.resize (nr); | |
4587 | 3551 idx_arg.resize (nr); |
458 | 3552 |
5275 | 3553 for (octave_idx_type i = 0; i < nr; i++) |
458 | 3554 { |
2354 | 3555 bool real_only = row_is_real_only (i); |
3556 | |
5275 | 3557 octave_idx_type idx_j; |
4469 | 3558 |
3559 Complex tmp_min; | |
3560 | |
3561 double abs_min = octave_NaN; | |
3562 | |
3563 for (idx_j = 0; idx_j < nc; idx_j++) | |
3564 { | |
3565 tmp_min = elem (i, idx_j); | |
3566 | |
5389 | 3567 if (! xisnan (tmp_min)) |
4469 | 3568 { |
5315 | 3569 abs_min = real_only ? std::real (tmp_min) : std::abs (tmp_min); |
4469 | 3570 break; |
3571 } | |
3572 } | |
3573 | |
5275 | 3574 for (octave_idx_type j = idx_j+1; j < nc; j++) |
4469 | 3575 { |
3576 Complex tmp = elem (i, j); | |
3577 | |
5389 | 3578 if (xisnan (tmp)) |
4469 | 3579 continue; |
3580 | |
5315 | 3581 double abs_tmp = real_only ? std::real (tmp) : std::abs (tmp); |
4469 | 3582 |
3583 if (abs_tmp < abs_min) | |
3584 { | |
3585 idx_j = j; | |
3586 tmp_min = tmp; | |
3587 abs_min = abs_tmp; | |
3588 } | |
3589 } | |
3590 | |
5389 | 3591 if (xisnan (tmp_min)) |
4469 | 3592 { |
3593 result.elem (i) = Complex_NaN_result; | |
4587 | 3594 idx_arg.elem (i) = 0; |
4469 | 3595 } |
891 | 3596 else |
3597 { | |
4469 | 3598 result.elem (i) = tmp_min; |
4587 | 3599 idx_arg.elem (i) = idx_j; |
891 | 3600 } |
458 | 3601 } |
3602 } | |
3603 | |
3604 return result; | |
3605 } | |
3606 | |
3607 ComplexColumnVector | |
3608 ComplexMatrix::row_max (void) const | |
3609 { | |
5275 | 3610 Array<octave_idx_type> dummy_idx; |
4587 | 3611 return row_max (dummy_idx); |
458 | 3612 } |
3613 | |
3614 ComplexColumnVector | |
5275 | 3615 ComplexMatrix::row_max (Array<octave_idx_type>& idx_arg) const |
458 | 3616 { |
3617 ComplexColumnVector result; | |
3618 | |
5275 | 3619 octave_idx_type nr = rows (); |
3620 octave_idx_type nc = cols (); | |
458 | 3621 |
3622 if (nr > 0 && nc > 0) | |
3623 { | |
3624 result.resize (nr); | |
4587 | 3625 idx_arg.resize (nr); |
458 | 3626 |
5275 | 3627 for (octave_idx_type i = 0; i < nr; i++) |
458 | 3628 { |
2354 | 3629 bool real_only = row_is_real_only (i); |
3630 | |
5275 | 3631 octave_idx_type idx_j; |
4469 | 3632 |
3633 Complex tmp_max; | |
3634 | |
3635 double abs_max = octave_NaN; | |
3636 | |
3637 for (idx_j = 0; idx_j < nc; idx_j++) | |
3638 { | |
3639 tmp_max = elem (i, idx_j); | |
3640 | |
5389 | 3641 if (! xisnan (tmp_max)) |
4469 | 3642 { |
5315 | 3643 abs_max = real_only ? std::real (tmp_max) : std::abs (tmp_max); |
4469 | 3644 break; |
3645 } | |
3646 } | |
3647 | |
5275 | 3648 for (octave_idx_type j = idx_j+1; j < nc; j++) |
4469 | 3649 { |
3650 Complex tmp = elem (i, j); | |
3651 | |
5389 | 3652 if (xisnan (tmp)) |
4469 | 3653 continue; |
3654 | |
5315 | 3655 double abs_tmp = real_only ? std::real (tmp) : std::abs (tmp); |
4469 | 3656 |
3657 if (abs_tmp > abs_max) | |
3658 { | |
3659 idx_j = j; | |
3660 tmp_max = tmp; | |
3661 abs_max = abs_tmp; | |
3662 } | |
3663 } | |
3664 | |
5389 | 3665 if (xisnan (tmp_max)) |
4469 | 3666 { |
3667 result.elem (i) = Complex_NaN_result; | |
4587 | 3668 idx_arg.elem (i) = 0; |
4469 | 3669 } |
891 | 3670 else |
3671 { | |
4469 | 3672 result.elem (i) = tmp_max; |
4587 | 3673 idx_arg.elem (i) = idx_j; |
891 | 3674 } |
458 | 3675 } |
3676 } | |
3677 | |
3678 return result; | |
3679 } | |
3680 | |
3681 ComplexRowVector | |
3682 ComplexMatrix::column_min (void) const | |
3683 { | |
5275 | 3684 Array<octave_idx_type> dummy_idx; |
4587 | 3685 return column_min (dummy_idx); |
458 | 3686 } |
3687 | |
3688 ComplexRowVector | |
5275 | 3689 ComplexMatrix::column_min (Array<octave_idx_type>& idx_arg) const |
458 | 3690 { |
3691 ComplexRowVector result; | |
3692 | |
5275 | 3693 octave_idx_type nr = rows (); |
3694 octave_idx_type nc = cols (); | |
458 | 3695 |
3696 if (nr > 0 && nc > 0) | |
3697 { | |
3698 result.resize (nc); | |
4587 | 3699 idx_arg.resize (nc); |
458 | 3700 |
5275 | 3701 for (octave_idx_type j = 0; j < nc; j++) |
458 | 3702 { |
2354 | 3703 bool real_only = column_is_real_only (j); |
3704 | |
5275 | 3705 octave_idx_type idx_i; |
4469 | 3706 |
3707 Complex tmp_min; | |
3708 | |
3709 double abs_min = octave_NaN; | |
3710 | |
3711 for (idx_i = 0; idx_i < nr; idx_i++) | |
3712 { | |
3713 tmp_min = elem (idx_i, j); | |
3714 | |
5389 | 3715 if (! xisnan (tmp_min)) |
4469 | 3716 { |
5315 | 3717 abs_min = real_only ? std::real (tmp_min) : std::abs (tmp_min); |
4469 | 3718 break; |
3719 } | |
3720 } | |
3721 | |
5275 | 3722 for (octave_idx_type i = idx_i+1; i < nr; i++) |
4469 | 3723 { |
3724 Complex tmp = elem (i, j); | |
3725 | |
5389 | 3726 if (xisnan (tmp)) |
4469 | 3727 continue; |
3728 | |
5315 | 3729 double abs_tmp = real_only ? std::real (tmp) : std::abs (tmp); |
4469 | 3730 |
3731 if (abs_tmp < abs_min) | |
3732 { | |
3733 idx_i = i; | |
3734 tmp_min = tmp; | |
3735 abs_min = abs_tmp; | |
3736 } | |
3737 } | |
3738 | |
5389 | 3739 if (xisnan (tmp_min)) |
4469 | 3740 { |
3741 result.elem (j) = Complex_NaN_result; | |
4587 | 3742 idx_arg.elem (j) = 0; |
4469 | 3743 } |
891 | 3744 else |
3745 { | |
4469 | 3746 result.elem (j) = tmp_min; |
4587 | 3747 idx_arg.elem (j) = idx_i; |
891 | 3748 } |
458 | 3749 } |
3750 } | |
3751 | |
3752 return result; | |
3753 } | |
3754 | |
3755 ComplexRowVector | |
3756 ComplexMatrix::column_max (void) const | |
3757 { | |
5275 | 3758 Array<octave_idx_type> dummy_idx; |
4587 | 3759 return column_max (dummy_idx); |
458 | 3760 } |
3761 | |
3762 ComplexRowVector | |
5275 | 3763 ComplexMatrix::column_max (Array<octave_idx_type>& idx_arg) const |
458 | 3764 { |
3765 ComplexRowVector result; | |
3766 | |
5275 | 3767 octave_idx_type nr = rows (); |
3768 octave_idx_type nc = cols (); | |
458 | 3769 |
3770 if (nr > 0 && nc > 0) | |
3771 { | |
3772 result.resize (nc); | |
4587 | 3773 idx_arg.resize (nc); |
458 | 3774 |
5275 | 3775 for (octave_idx_type j = 0; j < nc; j++) |
458 | 3776 { |
2354 | 3777 bool real_only = column_is_real_only (j); |
3778 | |
5275 | 3779 octave_idx_type idx_i; |
4469 | 3780 |
3781 Complex tmp_max; | |
3782 | |
3783 double abs_max = octave_NaN; | |
3784 | |
3785 for (idx_i = 0; idx_i < nr; idx_i++) | |
3786 { | |
3787 tmp_max = elem (idx_i, j); | |
3788 | |
5389 | 3789 if (! xisnan (tmp_max)) |
4469 | 3790 { |
5315 | 3791 abs_max = real_only ? std::real (tmp_max) : std::abs (tmp_max); |
4469 | 3792 break; |
3793 } | |
3794 } | |
3795 | |
5275 | 3796 for (octave_idx_type i = idx_i+1; i < nr; i++) |
4469 | 3797 { |
3798 Complex tmp = elem (i, j); | |
3799 | |
5389 | 3800 if (xisnan (tmp)) |
4469 | 3801 continue; |
3802 | |
5315 | 3803 double abs_tmp = real_only ? std::real (tmp) : std::abs (tmp); |
4469 | 3804 |
3805 if (abs_tmp > abs_max) | |
3806 { | |
3807 idx_i = i; | |
3808 tmp_max = tmp; | |
3809 abs_max = abs_tmp; | |
3810 } | |
3811 } | |
3812 | |
5389 | 3813 if (xisnan (tmp_max)) |
4469 | 3814 { |
3815 result.elem (j) = Complex_NaN_result; | |
4587 | 3816 idx_arg.elem (j) = 0; |
4469 | 3817 } |
891 | 3818 else |
3819 { | |
4469 | 3820 result.elem (j) = tmp_max; |
4587 | 3821 idx_arg.elem (j) = idx_i; |
891 | 3822 } |
458 | 3823 } |
3824 } | |
3825 | |
3826 return result; | |
3827 } | |
3828 | |
3829 // i/o | |
3830 | |
3504 | 3831 std::ostream& |
3832 operator << (std::ostream& os, const ComplexMatrix& a) | |
458 | 3833 { |
5275 | 3834 for (octave_idx_type i = 0; i < a.rows (); i++) |
458 | 3835 { |
5275 | 3836 for (octave_idx_type j = 0; j < a.cols (); j++) |
4130 | 3837 { |
3838 os << " "; | |
3839 octave_write_complex (os, a.elem (i, j)); | |
3840 } | |
458 | 3841 os << "\n"; |
3842 } | |
3843 return os; | |
3844 } | |
3845 | |
3504 | 3846 std::istream& |
3847 operator >> (std::istream& is, ComplexMatrix& a) | |
458 | 3848 { |
5275 | 3849 octave_idx_type nr = a.rows (); |
3850 octave_idx_type nc = a.cols (); | |
458 | 3851 |
3852 if (nr < 1 || nc < 1) | |
3504 | 3853 is.clear (std::ios::badbit); |
458 | 3854 else |
3855 { | |
3856 Complex tmp; | |
5275 | 3857 for (octave_idx_type i = 0; i < nr; i++) |
3858 for (octave_idx_type j = 0; j < nc; j++) | |
458 | 3859 { |
4130 | 3860 tmp = octave_read_complex (is); |
458 | 3861 if (is) |
3862 a.elem (i, j) = tmp; | |
3863 else | |
2993 | 3864 goto done; |
458 | 3865 } |
3866 } | |
3867 | |
2993 | 3868 done: |
3869 | |
458 | 3870 return is; |
3871 } | |
3872 | |
1819 | 3873 ComplexMatrix |
3874 Givens (const Complex& x, const Complex& y) | |
3875 { | |
3876 double cc; | |
3877 Complex cs, temp_r; | |
3878 | |
3887 | 3879 F77_FUNC (zlartg, ZLARTG) (x, y, cc, cs, temp_r); |
1819 | 3880 |
3881 ComplexMatrix g (2, 2); | |
3882 | |
3883 g.elem (0, 0) = cc; | |
3884 g.elem (1, 1) = cc; | |
3885 g.elem (0, 1) = cs; | |
3886 g.elem (1, 0) = -conj (cs); | |
3887 | |
3888 return g; | |
3889 } | |
3890 | |
3891 ComplexMatrix | |
3892 Sylvester (const ComplexMatrix& a, const ComplexMatrix& b, | |
3893 const ComplexMatrix& c) | |
3894 { | |
3895 ComplexMatrix retval; | |
3896 | |
5775 | 3897 // FIXME -- need to check that a, b, and c are all the same |
1819 | 3898 // size. |
3899 | |
3900 // Compute Schur decompositions | |
3901 | |
3902 ComplexSCHUR as (a, "U"); | |
3903 ComplexSCHUR bs (b, "U"); | |
3904 | |
3905 // Transform c to new coordinates. | |
3906 | |
3907 ComplexMatrix ua = as.unitary_matrix (); | |
3908 ComplexMatrix sch_a = as.schur_matrix (); | |
3909 | |
3910 ComplexMatrix ub = bs.unitary_matrix (); | |
3911 ComplexMatrix sch_b = bs.schur_matrix (); | |
3912 | |
3913 ComplexMatrix cx = ua.hermitian () * c * ub; | |
3914 | |
3915 // Solve the sylvester equation, back-transform, and return the | |
3916 // solution. | |
3917 | |
5275 | 3918 octave_idx_type a_nr = a.rows (); |
3919 octave_idx_type b_nr = b.rows (); | |
1819 | 3920 |
3921 double scale; | |
5275 | 3922 octave_idx_type info; |
1950 | 3923 |
3924 Complex *pa = sch_a.fortran_vec (); | |
3925 Complex *pb = sch_b.fortran_vec (); | |
3926 Complex *px = cx.fortran_vec (); | |
1819 | 3927 |
4552 | 3928 F77_XFCN (ztrsyl, ZTRSYL, (F77_CONST_CHAR_ARG2 ("N", 1), |
3929 F77_CONST_CHAR_ARG2 ("N", 1), | |
3930 1, a_nr, b_nr, pa, a_nr, pb, | |
3931 b_nr, px, a_nr, scale, info | |
3932 F77_CHAR_ARG_LEN (1) | |
3933 F77_CHAR_ARG_LEN (1))); | |
1950 | 3934 |
3935 if (f77_exception_encountered) | |
3936 (*current_liboctave_error_handler) ("unrecoverable error in ztrsyl"); | |
3937 else | |
3938 { | |
5775 | 3939 // FIXME -- check info? |
1950 | 3940 |
3941 retval = -ua * cx * ub.hermitian (); | |
3942 } | |
1819 | 3943 |
3944 return retval; | |
3945 } | |
3946 | |
2828 | 3947 ComplexMatrix |
3948 operator * (const ComplexMatrix& m, const Matrix& a) | |
3949 { | |
3950 ComplexMatrix tmp (a); | |
3951 return m * tmp; | |
3952 } | |
3953 | |
3954 ComplexMatrix | |
3955 operator * (const Matrix& m, const ComplexMatrix& a) | |
3956 { | |
3957 ComplexMatrix tmp (m); | |
3958 return tmp * a; | |
3959 } | |
3960 | |
6162 | 3961 /* Simple Dot Product, Matrix-Vector and Matrix-Matrix Unit tests |
3962 %!assert([1+i 2+i 3+i] * [ 4+i ; 5+i ; 6+i], 29+21i, 1e-14) | |
3963 %!assert([1+i 2+i ; 3+i 4+i ] * [5+i ; 6+i], [15 + 14i ; 37 + 18i], 1e-14) | |
3964 %!assert([1+i 2+i ; 3+i 4+i ] * [5+i 6+i ; 7+i 8+i], [17 + 15i 20 + 17i; 41 + 19i 48 + 21i], 1e-14) | |
3965 */ | |
3966 | |
3967 /* Test some simple identities | |
3968 %!shared M, cv, rv | |
3969 %! M = randn(10,10)+i*rand(10,10); | |
3970 %! cv = randn(10,1)+i*rand(10,1); | |
3971 %! rv = randn(1,10)+i*rand(1,10); | |
3972 %!assert([M*cv,M*cv],M*[cv,cv],1e-14) | |
3973 %!assert([rv*M;rv*M],[rv;rv]*M,1e-14) | |
3974 %!assert(2*rv*cv,[rv,rv]*[cv;cv],1e-14) | |
3975 */ | |
3976 | |
2828 | 3977 ComplexMatrix |
3978 operator * (const ComplexMatrix& m, const ComplexMatrix& a) | |
3979 { | |
3980 ComplexMatrix retval; | |
3981 | |
5275 | 3982 octave_idx_type nr = m.rows (); |
3983 octave_idx_type nc = m.cols (); | |
3984 | |
3985 octave_idx_type a_nr = a.rows (); | |
3986 octave_idx_type a_nc = a.cols (); | |
2828 | 3987 |
3988 if (nc != a_nr) | |
3989 gripe_nonconformant ("operator *", nr, nc, a_nr, a_nc); | |
3990 else | |
3991 { | |
3992 if (nr == 0 || nc == 0 || a_nc == 0) | |
3760 | 3993 retval.resize (nr, a_nc, 0.0); |
2828 | 3994 else |
3995 { | |
5275 | 3996 octave_idx_type ld = nr; |
3997 octave_idx_type lda = a.rows (); | |
2828 | 3998 |
3999 retval.resize (nr, a_nc); | |
4000 Complex *c = retval.fortran_vec (); | |
4001 | |
5983 | 4002 if (a_nc == 1) |
4003 { | |
4004 if (nr == 1) | |
4005 F77_FUNC (xzdotu, XZDOTU) (nc, m.data (), 1, a.data (), 1, *c); | |
4006 else | |
6390 | 4007 { |
4008 F77_XFCN (zgemv, ZGEMV, (F77_CONST_CHAR_ARG2 ("N", 1), | |
4009 nr, nc, 1.0, m.data (), ld, | |
4010 a.data (), 1, 0.0, c, 1 | |
4011 F77_CHAR_ARG_LEN (1))); | |
4012 | |
4013 if (f77_exception_encountered) | |
4014 (*current_liboctave_error_handler) | |
4015 ("unrecoverable error in zgemv"); | |
4016 } | |
5983 | 4017 } |
4018 else | |
6390 | 4019 { |
4020 F77_XFCN (zgemm, ZGEMM, (F77_CONST_CHAR_ARG2 ("N", 1), | |
4021 F77_CONST_CHAR_ARG2 ("N", 1), | |
4022 nr, a_nc, nc, 1.0, m.data (), | |
4023 ld, a.data (), lda, 0.0, c, nr | |
4024 F77_CHAR_ARG_LEN (1) | |
4025 F77_CHAR_ARG_LEN (1))); | |
4026 | |
4027 if (f77_exception_encountered) | |
4028 (*current_liboctave_error_handler) | |
4029 ("unrecoverable error in zgemm"); | |
4030 } | |
2828 | 4031 } |
4032 } | |
4033 | |
4034 return retval; | |
4035 } | |
4036 | |
5775 | 4037 // FIXME -- it would be nice to share code among the min/max |
4309 | 4038 // functions below. |
4039 | |
4040 #define EMPTY_RETURN_CHECK(T) \ | |
4041 if (nr == 0 || nc == 0) \ | |
4042 return T (nr, nc); | |
4043 | |
4044 ComplexMatrix | |
4045 min (const Complex& c, const ComplexMatrix& m) | |
4046 { | |
5275 | 4047 octave_idx_type nr = m.rows (); |
4048 octave_idx_type nc = m.columns (); | |
4309 | 4049 |
4050 EMPTY_RETURN_CHECK (ComplexMatrix); | |
4051 | |
4052 ComplexMatrix result (nr, nc); | |
4053 | |
5275 | 4054 for (octave_idx_type j = 0; j < nc; j++) |
4055 for (octave_idx_type i = 0; i < nr; i++) | |
4309 | 4056 { |
4057 OCTAVE_QUIT; | |
4058 result (i, j) = xmin (c, m (i, j)); | |
4059 } | |
4060 | |
4061 return result; | |
4062 } | |
4063 | |
4064 ComplexMatrix | |
4065 min (const ComplexMatrix& m, const Complex& c) | |
4066 { | |
5275 | 4067 octave_idx_type nr = m.rows (); |
4068 octave_idx_type nc = m.columns (); | |
4309 | 4069 |
4070 EMPTY_RETURN_CHECK (ComplexMatrix); | |
4071 | |
4072 ComplexMatrix result (nr, nc); | |
4073 | |
5275 | 4074 for (octave_idx_type j = 0; j < nc; j++) |
4075 for (octave_idx_type i = 0; i < nr; i++) | |
4309 | 4076 { |
4077 OCTAVE_QUIT; | |
4078 result (i, j) = xmin (m (i, j), c); | |
4079 } | |
4080 | |
4081 return result; | |
4082 } | |
4083 | |
4084 ComplexMatrix | |
4085 min (const ComplexMatrix& a, const ComplexMatrix& b) | |
4086 { | |
5275 | 4087 octave_idx_type nr = a.rows (); |
4088 octave_idx_type nc = a.columns (); | |
4309 | 4089 |
4090 if (nr != b.rows () || nc != b.columns ()) | |
4091 { | |
4092 (*current_liboctave_error_handler) | |
4093 ("two-arg min expecting args of same size"); | |
4094 return ComplexMatrix (); | |
4095 } | |
4096 | |
4097 EMPTY_RETURN_CHECK (ComplexMatrix); | |
4098 | |
4099 ComplexMatrix result (nr, nc); | |
4100 | |
5275 | 4101 for (octave_idx_type j = 0; j < nc; j++) |
4309 | 4102 { |
4103 int columns_are_real_only = 1; | |
5275 | 4104 for (octave_idx_type i = 0; i < nr; i++) |
4309 | 4105 { |
4106 OCTAVE_QUIT; | |
5315 | 4107 if (std::imag (a (i, j)) != 0.0 || std::imag (b (i, j)) != 0.0) |
4309 | 4108 { |
4109 columns_are_real_only = 0; | |
4110 break; | |
4111 } | |
4112 } | |
4113 | |
4114 if (columns_are_real_only) | |
4115 { | |
5275 | 4116 for (octave_idx_type i = 0; i < nr; i++) |
5315 | 4117 result (i, j) = xmin (std::real (a (i, j)), std::real (b (i, j))); |
4309 | 4118 } |
4119 else | |
4120 { | |
5275 | 4121 for (octave_idx_type i = 0; i < nr; i++) |
4309 | 4122 { |
4123 OCTAVE_QUIT; | |
4124 result (i, j) = xmin (a (i, j), b (i, j)); | |
4125 } | |
4126 } | |
4127 } | |
4128 | |
4129 return result; | |
4130 } | |
4131 | |
4132 ComplexMatrix | |
4133 max (const Complex& c, const ComplexMatrix& m) | |
4134 { | |
5275 | 4135 octave_idx_type nr = m.rows (); |
4136 octave_idx_type nc = m.columns (); | |
4309 | 4137 |
4138 EMPTY_RETURN_CHECK (ComplexMatrix); | |
4139 | |
4140 ComplexMatrix result (nr, nc); | |
4141 | |
5275 | 4142 for (octave_idx_type j = 0; j < nc; j++) |
4143 for (octave_idx_type i = 0; i < nr; i++) | |
4309 | 4144 { |
4145 OCTAVE_QUIT; | |
4146 result (i, j) = xmax (c, m (i, j)); | |
4147 } | |
4148 | |
4149 return result; | |
4150 } | |
4151 | |
4152 ComplexMatrix | |
4153 max (const ComplexMatrix& m, const Complex& c) | |
4154 { | |
5275 | 4155 octave_idx_type nr = m.rows (); |
4156 octave_idx_type nc = m.columns (); | |
4309 | 4157 |
4158 EMPTY_RETURN_CHECK (ComplexMatrix); | |
4159 | |
4160 ComplexMatrix result (nr, nc); | |
4161 | |
5275 | 4162 for (octave_idx_type j = 0; j < nc; j++) |
4163 for (octave_idx_type i = 0; i < nr; i++) | |
4309 | 4164 { |
4165 OCTAVE_QUIT; | |
4166 result (i, j) = xmax (m (i, j), c); | |
4167 } | |
4168 | |
4169 return result; | |
4170 } | |
4171 | |
4172 ComplexMatrix | |
4173 max (const ComplexMatrix& a, const ComplexMatrix& b) | |
4174 { | |
5275 | 4175 octave_idx_type nr = a.rows (); |
4176 octave_idx_type nc = a.columns (); | |
4309 | 4177 |
4178 if (nr != b.rows () || nc != b.columns ()) | |
4179 { | |
4180 (*current_liboctave_error_handler) | |
4181 ("two-arg max expecting args of same size"); | |
4182 return ComplexMatrix (); | |
4183 } | |
4184 | |
4185 EMPTY_RETURN_CHECK (ComplexMatrix); | |
4186 | |
4187 ComplexMatrix result (nr, nc); | |
4188 | |
5275 | 4189 for (octave_idx_type j = 0; j < nc; j++) |
4309 | 4190 { |
4191 int columns_are_real_only = 1; | |
5275 | 4192 for (octave_idx_type i = 0; i < nr; i++) |
4309 | 4193 { |
4194 OCTAVE_QUIT; | |
5315 | 4195 if (std::imag (a (i, j)) != 0.0 || std::imag (b (i, j)) != 0.0) |
4309 | 4196 { |
4197 columns_are_real_only = 0; | |
4198 break; | |
4199 } | |
4200 } | |
4201 | |
4202 if (columns_are_real_only) | |
4203 { | |
5275 | 4204 for (octave_idx_type i = 0; i < nr; i++) |
4309 | 4205 { |
4206 OCTAVE_QUIT; | |
5315 | 4207 result (i, j) = xmax (std::real (a (i, j)), std::real (b (i, j))); |
4309 | 4208 } |
4209 } | |
4210 else | |
4211 { | |
5275 | 4212 for (octave_idx_type i = 0; i < nr; i++) |
4309 | 4213 { |
4214 OCTAVE_QUIT; | |
4215 result (i, j) = xmax (a (i, j), b (i, j)); | |
4216 } | |
4217 } | |
4218 } | |
4219 | |
4220 return result; | |
4221 } | |
4222 | |
5315 | 4223 MS_CMP_OPS(ComplexMatrix, std::real, Complex, std::real) |
3504 | 4224 MS_BOOL_OPS(ComplexMatrix, Complex, 0.0) |
2870 | 4225 |
5315 | 4226 SM_CMP_OPS(Complex, std::real, ComplexMatrix, std::real) |
3504 | 4227 SM_BOOL_OPS(Complex, ComplexMatrix, 0.0) |
2870 | 4228 |
5315 | 4229 MM_CMP_OPS(ComplexMatrix, std::real, ComplexMatrix, std::real) |
3504 | 4230 MM_BOOL_OPS(ComplexMatrix, ComplexMatrix, 0.0) |
2870 | 4231 |
458 | 4232 /* |
4233 ;;; Local Variables: *** | |
4234 ;;; mode: C++ *** | |
4235 ;;; End: *** | |
4236 */ |