1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch 2!! 3!! This program is free software; you can redistribute it and/or modify 4!! it under the terms of the GNU General Public License as published by 5!! the Free Software Foundation; either version 2, or (at your option) 6!! any later version. 7!! 8!! This program is distributed in the hope that it will be useful, 9!! but WITHOUT ANY WARRANTY; without even the implied warranty of 10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11!! GNU General Public License for more details. 12!! 13!! You should have received a copy of the GNU General Public License 14!! along with this program; if not, write to the Free Software 15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 16!! 02110-1301, USA. 17!! 18 19! --------------------------------------------------------- 20!> Compute the Cholesky decomposition of real symmetric or complex Hermitian positive definite 21!! matrix a, dim(a) = n x n. On return a = u^T u with u upper triangular matrix. 22subroutine X(cholesky)(n, a, bof, err_code) 23 integer, intent(in) :: n 24 R_TYPE, intent(inout) :: a(:,:) !< (n,n) 25 logical, optional, intent(inout) :: bof !< Bomb on failure. 26 integer, optional, intent(out) :: err_code 27 28 integer :: info 29 30 call profiling_in(cholesky_prof, "CHOLESKY") 31 PUSH_SUB(X(cholesky)) 32 33 ASSERT(n > 0) 34 35 call lapack_potrf('U', n, a(1, 1), lead_dim(a), info) 36 if(info /= 0) then 37 if(optional_default(bof, .true.)) then 38 write(message(1), '(5a,i5)') 'In ', TOSTRING(X(cholesky)), ', LAPACK ', TOSTRING(X(potrf)), ' returned error message ', info 39! http://www.netlib.org/lapack/explore-3.1.1-html/dpotrf.f.html and zpotrf.f.html 40! * INFO (output) INTEGER 41! * = 0: successful exit 42! * < 0: if INFO = -i, the i-th argument had an illegal value 43! * > 0: if INFO = i, the leading minor of order i is not 44! * positive definite, and the factorization could not be 45! * completed. 46 if(info < 0) then 47 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 48 else 49 write(message(2), '(a,i5,a)') 'The leading minor of order ', info, ' is not positive definite.' 50 end if 51 call messages_fatal(2) 52 else 53 if(present(bof)) then 54 bof = .true. 55 end if 56 end if 57 else 58 if(present(bof)) then 59 bof = .false. 60 end if 61 end if 62 if(present(err_code)) then 63 err_code = info 64 end if 65 66 call profiling_out(cholesky_prof) 67 POP_SUB(X(cholesky)) 68end subroutine X(cholesky) 69 70 71! --------------------------------------------------------- 72!> Computes all the eigenvalues and the eigenvectors of a real symmetric or complex Hermitian 73!! generalized definite eigenproblem, of the form \f$ Ax=\lambda Bx \f$. B is also positive definite. 74subroutine X(geneigensolve)(n, a, b, e, preserve_mat, bof, err_code) 75 integer, intent(in) :: n 76 R_TYPE, intent(inout) :: a(:,:) !< (n,n) 77 R_TYPE, intent(inout) :: b(:,:) !< (n,n) 78 FLOAT, intent(out) :: e(:) !< (n) 79 logical, intent(in) :: preserve_mat !< If true, the matrix a and b on exit are the same 80 !< as on input 81 logical, optional, intent(inout) :: bof !< Bomb on failure. 82 integer, optional, intent(out) :: err_code 83 84 integer :: info, lwork, ii, jj 85#ifdef R_TCOMPLEX 86 FLOAT, allocatable :: rwork(:) 87#endif 88 R_TYPE, allocatable :: work(:), diag(:) 89 90 call profiling_in(eigensolver_prof, "DENSE_EIGENSOLVER") 91 PUSH_SUB(X(geneigensolve)) 92 93 ASSERT(n > 0) 94 95 if(preserve_mat) then 96 SAFE_ALLOCATE(diag(1:n)) 97 ! store the diagonal of b 98 do ii = 1, n 99 diag(ii) = b(ii, ii) 100 end do 101 end if 102 103 lwork = 5*n ! get this from workspace query 104 SAFE_ALLOCATE(work(1:lwork)) 105#ifdef R_TCOMPLEX 106 SAFE_ALLOCATE(rwork(1:max(1, 3*n-2))) 107 call lapack_hegv(1, 'V', 'U', n, a(1, 1), lead_dim(a), b(1, 1), lead_dim(b), e(1), work(1), lwork, rwork(1), info) 108 SAFE_DEALLOCATE_A(rwork) 109#else 110 call lapack_sygv(1, 'V', 'U', n, a(1, 1), lead_dim(a), b(1, 1), lead_dim(b), e(1), work(1), lwork, info) 111#endif 112 SAFE_DEALLOCATE_A(work) 113 114 if(preserve_mat) then 115 ! b was destroyed, so we rebuild it 116 do ii = 1, n 117 do jj = 1, ii - 1 118 b(jj, ii) = R_CONJ(b(ii, jj)) 119 end do 120 b(ii, ii) = diag(ii) 121 end do 122 123 SAFE_DEALLOCATE_A(diag) 124 end if 125 126 if(info /= 0) then 127 if(optional_default(bof, .true.)) then 128 write(message(1),'(3a)') 'In ', TOSTRING(X(geneigensolve)), ', LAPACK ' 129#ifdef R_TCOMPLEX 130 write(message(1),'(3a,i5)') trim(message(1)), TOSTRING(X(hegv)), ' returned error message ', info 131#else 132 write(message(1),'(3a,i5)') trim(message(1)), TOSTRING(X(sygv)), ' returned error message ', info 133#endif 134!* INFO (output) INTEGER 135!* = 0: successful exit 136!* < 0: if INFO = -i, the i-th argument had an illegal value 137!* > 0: ZPOTRF or ZHEEV returned an error code: 138!* <= N: if INFO = i, ZHEEV failed to converge; 139!* i off-diagonal elements of an intermediate 140!* tridiagonal form did not converge to zero; 141!* > N: if INFO = N + i, for 1 <= i <= N, then the leading 142!* minor of order i of B is not positive definite. 143!* The factorization of B could not be completed and 144!* no eigenvalues or eigenvectors were computed. 145 if(info < 0) then 146 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 147 else if(info <= n) then 148 write(message(2), '(i5,a)') info, ' off-diagonal elements of an intermediate tridiagonal did not converge to zero.' 149 else 150 write(message(2), '(a,i5,a)') 'The leading minor of order ', info - n, ' of B is not positive definite.' 151 end if 152 call messages_fatal(2) 153 else 154 if(present(bof)) then 155 bof = .true. 156 end if 157 end if 158 else 159 if(present(bof)) then 160 bof = .false. 161 end if 162 end if 163 if(present(err_code)) then 164 err_code = info 165 end if 166 167 call profiling_out(eigensolver_prof) 168 POP_SUB(X(geneigensolve)) 169end subroutine X(geneigensolve) 170 171 172! --------------------------------------------------------- 173!> Computes all the eigenvalues and the right (left) eigenvectors of a real or complex 174!! (non-Hermitian) eigenproblem, of the form A*x=(lambda)*x 175subroutine X(eigensolve_nonh)(n, a, e, err_code, side, sort_eigenvectors) 176 integer, intent(in) :: n 177 R_TYPE, intent(inout) :: a(:, :) !< (n,n) 178 CMPLX, intent(out) :: e(:) !< (n) 179 integer, optional, intent(out) :: err_code 180 character(1), optional, intent(in) :: side !< which eigenvectors ('L' or 'R') 181 logical, optional, intent(in) :: sort_eigenvectors !< only applies to complex version, sorts by real part 182 183 integer :: info, lwork, ii 184 FLOAT, allocatable :: rwork(:), re(:) 185 R_TYPE, allocatable :: work(:), vl(:, :), vr(:, :), a_copy(:, :) 186 CMPLX, allocatable :: e_copy(:) 187 character(1) :: side_ 188 integer, allocatable :: ind(:) 189 190 PUSH_SUB(X(eigensolve_nonh)) 191 192 ASSERT(n > 0) 193 194 if (present(side)) then 195 side_ = side 196 else 197 side_ = 'R' 198 end if 199 200 lwork = -1 201 ! Initializing info, if not it can cause that the geev query mode fails. 202 ! Besides, if info is not initialized valgrind complains about it. 203 info = 0 204 ! A bug in the query mode of zgeev demands that the working array has to be larger than 1 205 ! problem here is that a value is written somewhere into the array whether it is 206 ! allocated or not. I noticed that it happens (hopefully) always at an index which 207 ! is below the matrix dimension. 208 SAFE_ALLOCATE(work(1:n)) 209 SAFE_ALLOCATE(vl(1:1, 1:1)) 210 SAFE_ALLOCATE(vr(1:n, 1:n)) ! even in query mode, the size of vr is checked, so we allocate it 211 SAFE_ALLOCATE(rwork(1:1)) 212 call lapack_geev('N', 'V', n, a, lead_dim(a), e, vl, lead_dim(vl), vr, lead_dim(vr), & 213 work, lwork, rwork, info) 214 if(info /= 0) then 215 write(message(1),'(5a,i5)') 'In ', TOSTRING(X(eigensolve_nonh)), & 216 ', LAPACK ', TOSTRING(X(geev)), ' workspace query returned error message ', info 217 call messages_fatal(1) 218 end if 219 220 lwork = int(work(1)) 221 SAFE_DEALLOCATE_A(work) 222 SAFE_DEALLOCATE_A(vl) 223 SAFE_DEALLOCATE_A(vr) 224 SAFE_DEALLOCATE_A(rwork) 225 226 SAFE_ALLOCATE(work(1:lwork)) 227 SAFE_ALLOCATE(rwork(1:max(1, 2*n))) 228 if(side_ == 'L'.or.side_ == 'l') then 229 SAFE_ALLOCATE(vl(1:n, 1:n)) 230 SAFE_ALLOCATE(vr(1:1, 1:1)) 231 call lapack_geev('V', 'N', n, a, lead_dim(a), e, vl, lead_dim(vl), vr, lead_dim(vr), & 232 work, lwork, rwork, info) 233 a(1:n, 1:n) = vl(1:n, 1:n) 234 else 235 SAFE_ALLOCATE(vl(1:1, 1:1)) 236 SAFE_ALLOCATE(vr(1:n, 1:n)) 237 call lapack_geev('N', 'V', n, a, lead_dim(a), e, vl, lead_dim(vl), vr, lead_dim(vr), & 238 work, lwork, rwork, info) 239 a(1:n, 1:n) = vr(1:n, 1:n) 240 end if 241 SAFE_DEALLOCATE_A(work) 242 SAFE_DEALLOCATE_A(rwork) 243 SAFE_DEALLOCATE_A(vr) 244 SAFE_DEALLOCATE_A(vl) 245 246 if(info /= 0) then 247 write(message(1),'(5a,i5)') 'In ', TOSTRING(X(eigensolve_nonh)), & 248 ', LAPACK ', TOSTRING(X(geev)), ' returned error message ', info 249!* INFO (output) INTEGER 250!* = 0: successful exit 251!* < 0: if INFO = -i, the i-th argument had an illegal value. 252!* > 0: if INFO = i, the QR algorithm failed to compute all the 253!* eigenvalues, and no eigenvectors have been computed; 254!* elements i+1:N of WR and WI contain eigenvalues which 255!* have converged. 256 if(info < 0) then 257 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 258 else 259 write(message(2), '(a,i5,a,i5,a)') 'Only eigenvalues ', info + 1, ' to ', n, ' could be computed.' 260 end if 261 call messages_fatal(2) 262 end if 263 if(present(err_code)) then 264 err_code = info 265 end if 266 267 if(optional_default(sort_eigenvectors, .false.)) then 268 SAFE_ALLOCATE(re(1:n)) 269 SAFE_ALLOCATE(ind(1:n)) 270 SAFE_ALLOCATE(e_copy(1:n)) 271 SAFE_ALLOCATE(a_copy(1:n, 1:n)) 272 re = TOFLOAT(e) 273 e_copy = e 274 a_copy = a 275 call sort(re, ind) 276 do ii = 1, n 277 e(ii) = e_copy(ind(ii)) 278 a(1:n, ii) = a_copy(1:n, ind(ii)) 279 end do 280 SAFE_DEALLOCATE_A(e_copy) 281 SAFE_DEALLOCATE_A(a_copy) 282 SAFE_DEALLOCATE_A(re) 283 SAFE_DEALLOCATE_A(ind) 284 end if 285 286 POP_SUB(X(eigensolve_nonh)) 287end subroutine X(eigensolve_nonh) 288 289 290! --------------------------------------------------------- 291!> Computes the k lowest eigenvalues and the eigenvectors of a real symmetric or complex Hermitian 292!! generalized definite eigenproblem, of the form A*x=(lambda)*B*x. B is also positive definite. 293subroutine X(lowest_geneigensolve)(k, n, a, b, e, v, preserve_mat, bof, err_code) 294 integer, intent(in) :: k, n 295 R_TYPE, intent(inout) :: a(:,:) !< (n, n) 296 R_TYPE, intent(inout) :: b(:,:) !< (n, n) 297 FLOAT, intent(out) :: e(:) !< (n) 298 R_TYPE, intent(out) :: v(:,:) !< (n, n) 299 logical, intent(in) :: preserve_mat !< If true, the matrix a and b on exit are the same 300 !< as on input 301 logical, optional, intent(inout) :: bof !< Bomb on failure. 302 integer, optional, intent(out) :: err_code 303 304 integer :: m, iwork(5*n), ifail(n), info, lwork, ii, jj ! allocate me 305 FLOAT :: abstol 306 R_TYPE, allocatable :: work(:), diaga(:), diagb(:) 307#ifndef R_TREAL 308 FLOAT :: rwork(7*n) 309#endif 310 PUSH_SUB(X(lowest_geneigensolve)) 311 312 ASSERT(n > 0) 313 314 abstol = 2*sfmin() 315 316 if(preserve_mat) then 317 SAFE_ALLOCATE(diaga(1:n)) 318 SAFE_ALLOCATE(diagb(1:n)) 319 320 ! store the diagonal of a and b 321 do ii = 1, n 322 diaga(ii) = a(ii, ii) 323 diagb(ii) = b(ii, ii) 324 end do 325 end if 326 327 328 ! Work size query. 329 SAFE_ALLOCATE(work(1:1)) 330 331#ifdef R_TREAL 332 call dsygvx(1, 'V', 'I', 'U', n, a(1, 1), lead_dim(a), b(1, 1), lead_dim(b), M_ZERO, M_ZERO, & 333 1, k, abstol, m, e(1), v(1, 1), lead_dim(v), work(1), -1, iwork(1), ifail(1), info) 334 if(info /= 0) then 335 write(message(1),'(3a,i5)') 'In dlowest_geneigensolve, LAPACK ', & 336 TOSTRING(dsygvx), ' workspace query returned error message ', info 337 call messages_fatal(1) 338 end if 339 lwork = int(work(1)) 340 SAFE_DEALLOCATE_A(work) 341 342 SAFE_ALLOCATE(work(1:lwork)) 343 344 call dsygvx(1, 'V', 'I', 'U', n, a(1, 1), lead_dim(a), b(1, 1), lead_dim(b), M_ZERO, M_ZERO, & 345 1, k, abstol, m, e(1), v(1, 1), lead_dim(v), work(1), lwork, iwork(1), ifail(1), info) 346 347#else 348 call zhegvx(1, 'V', 'I', 'U', n, a(1, 1), lead_dim(a), b(1, 1), lead_dim(b), M_ZERO, M_ZERO, & 349 1, k, abstol, m, e(1), v(1, 1), lead_dim(v), work(1), -1, rwork(1), iwork(1), ifail(1), info) 350 if(info /= 0) then 351 write(message(1),'(3a,i5)') 'In zlowest_geneigensolve, LAPACK ', & 352 TOSTRING(zhegvx), ' workspace query returned error message ', info 353 call messages_fatal(1) 354 end if 355 lwork = int(real(work(1))) 356 SAFE_DEALLOCATE_A(work) 357 358 SAFE_ALLOCATE(work(1:lwork)) 359 call zhegvx(1, 'V', 'I', 'U', n, a(1, 1), lead_dim(a), b(1, 1), lead_dim(b), M_ZERO, M_ZERO, & 360 1, k, abstol, m, e(1), v(1, 1), lead_dim(v), work(1), lwork, rwork(1), iwork(1), ifail(1), info) 361#endif 362 363 if(preserve_mat) then 364 ! b was destroyed, so we rebuild it 365 do ii = 1, n 366 do jj = 1, ii - 1 367 a(jj, ii) = R_CONJ(a(ii, jj)) 368 b(jj, ii) = R_CONJ(b(ii, jj)) 369 end do 370 a(ii, ii) = diaga(ii) 371 b(ii, ii) = diagb(ii) 372 end do 373 374 SAFE_DEALLOCATE_A(diaga) 375 SAFE_DEALLOCATE_A(diagb) 376 end if 377 378 379 SAFE_DEALLOCATE_A(work) 380 381 if(info /= 0) then 382 if(optional_default(bof, .true.)) then 383#ifdef R_TREAL 384 write(message(1),'(3a,i5)') 'In dlowest_geneigensolve, LAPACK ', & 385 TOSTRING(dsygvx), ' returned error message ', info 386#else 387 write(message(1),'(3a,i5)') 'In zlowest_geneigensolve, LAPACK ', & 388 TOSTRING(zhegvx), ' returned error message ', info 389#endif 390! INFO (output) INTEGER 391!* = 0: successful exit 392!* < 0: if INFO = -i, the i-th argument had an illegal value 393!* > 0: DPOTRF or DSYEVX returned an error code: 394!* <= N: if INFO = i, DSYEVX failed to converge; 395!* i eigenvectors failed to converge. Their indices 396!* are stored in array IFAIL. 397!* > N: if INFO = N + i, for 1 <= i <= N, then the leading 398!* minor of order i of B is not positive definite. 399!* The factorization of B could not be completed and 400!* no eigenvalues or eigenvectors were computed. 401 if(info < 0) then 402 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 403 else if(info <= n) then 404 write(message(2), *) info, ' eigenvectors failed to converge: ', ifail(1:info) 405 else 406 write(message(2), '(a,i5,a)') 'The leading minor of order ', info - n, ' of B is not positive definite.' 407 end if 408 call messages_fatal(2) 409 else 410 if(present(bof)) then 411 bof = .true. 412 end if 413 end if 414 else 415 if(present(bof)) then 416 bof = .false. 417 end if 418 end if 419 if(present(err_code)) then 420 err_code = info 421 end if 422 423 POP_SUB(X(lowest_geneigensolve)) 424end subroutine X(lowest_geneigensolve) 425 426! --------------------------------------------------------- 427!> Computes all eigenvalues and eigenvectors of a real symmetric or hermitian square matrix A. 428subroutine X(eigensolve)(n, a, e, bof, err_code) 429 integer, intent(in) :: n 430 R_TYPE, intent(inout) :: a(:,:) !< (n,n) 431 FLOAT, intent(out) :: e(:) !< (n) 432 logical, optional, intent(inout) :: bof !< Bomb on failure. 433 integer, optional, intent(out) :: err_code 434 435 integer :: info, lwork 436 R_TYPE, allocatable :: work(:) 437#ifndef R_TREAL 438 FLOAT, allocatable :: rwork(:) 439#endif 440 441 PUSH_SUB(X(eigensolve)) 442 call profiling_in(eigensolver_prof, "DENSE_EIGENSOLVER") 443 444 ASSERT(n > 0) 445 446 lwork = 6*n ! query? 447 SAFE_ALLOCATE(work(1:lwork)) 448#ifdef R_TREAL 449 call lapack_syev('V', 'U', n, a(1, 1), lead_dim(a), e(1), work(1), lwork, info) 450#else 451 SAFE_ALLOCATE(rwork(1:max(1, 3*n-2))) 452 call lapack_heev('V','U', n, a(1, 1), lead_dim(a), e(1), work(1), lwork, rwork(1), info) 453 SAFE_DEALLOCATE_A(rwork) 454#endif 455 SAFE_DEALLOCATE_A(work) 456 457 if(info /= 0) then 458 if(optional_default(bof, .true.)) then 459#ifdef R_TREAL 460 write(message(1),'(3a,i5)') 'In eigensolve, LAPACK ', TOSTRING(dsyev), ' returned error message ', info 461#else 462 write(message(1),'(3a,i5)') 'In eigensolve, LAPACK ', TOSTRING(zheev), ' returned error message ', info 463#endif 464!* INFO (output) INTEGER 465!* = 0: successful exit 466!* < 0: if INFO = -i, the i-th argument had an illegal value 467!* > 0: if INFO = i, the algorithm failed to converge; i 468!* off-diagonal elements of an intermediate tridiagonal 469!* form did not converge to zero. 470 if(info < 0) then 471 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 472 else 473 write(message(2), '(i5,a)') info, ' off-diagonal elements of an intermediate tridiagonal did not converge to zero.' 474 end if 475 call messages_fatal(2) 476 else 477 if(present(bof)) then 478 bof = .true. 479 end if 480 end if 481 else 482 if(present(bof)) then 483 bof = .false. 484 end if 485 end if 486 if(present(err_code)) then 487 err_code = info 488 end if 489 490 call profiling_out(eigensolver_prof) 491 POP_SUB(X(eigensolve)) 492end subroutine X(eigensolve) 493 494 495! --------------------------------------------------------- 496!> Computes the k lowest eigenvalues and the eigenvectors of a 497!! standard symmetric-definite eigenproblem, of the form A*x=(lambda)*x. 498!! Here A is assumed to be symmetric. 499subroutine X(lowest_eigensolve)(k, n, a, e, v, preserve_mat) 500 integer, intent(in) :: k, n 501 R_TYPE, intent(inout) :: a(:,:) !< (n, n) 502 FLOAT, intent(out) :: e(:) !< (n) 503 R_TYPE, intent(out) :: v(:,:) !< (n, k) 504 logical, intent(in) :: preserve_mat !< If true, the matrix a and b on exit are the same 505 !< as on input 506 507 integer :: m, iwork(5*n), ifail(n), info, lwork, ii, jj 508 FLOAT :: abstol 509 R_TYPE, allocatable :: work(:), diaga(:) 510 511 PUSH_SUB(X(lowest_eigensolve)) 512 513 ASSERT(n > 0) 514 515 abstol = 2*sfmin() 516 517 if(preserve_mat) then 518 SAFE_ALLOCATE(diaga(1:n)) 519 520 ! store the diagonal of a and b 521 do ii = 1, n 522 diaga(ii) = a(ii, ii) 523 end do 524 end if 525 526 527 ! Work size query. 528 SAFE_ALLOCATE(work(1:1)) 529#ifdef R_TREAL 530 call dsyevx('V', 'I', 'U', n, a(1, 1), n, M_ZERO, M_ZERO, & 531 1, k, abstol, m, e(1), v(1, 1), n, work(1), -1, iwork(1), ifail(1), info) 532 if(info /= 0) then 533 write(message(1),'(3a,i5)') 'In dlowest_eigensolve, LAPACK ', & 534 TOSTRING(dsyevx), ' workspace query returned error message ', info 535 call messages_fatal(1) 536 end if 537 lwork = int(work(1)) 538 SAFE_DEALLOCATE_A(work) 539 540 SAFE_ALLOCATE(work(1:lwork)) 541 call dsyevx('V', 'I', 'U', n, a(1, 1), n, M_ZERO, M_ZERO, & 542 1, k, abstol, m, e(1), v(1, 1), n, work(1), lwork, iwork(1), ifail(1), info) 543#else 544 call zheevx('V', 'I', 'U', n, a(1, 1), n, M_ZERO, M_ZERO, & 545 1, k, abstol, m, e(1), v(1, 1), n, work(1), -1, iwork(1), ifail(1), info) 546 if(info /= 0) then 547 write(message(1),'(3a,i5)') 'In zlowest_eigensolve, LAPACK ', & 548 TOSTRING(zheevx), ' workspace query returned error message ', info 549 call messages_fatal(1) 550 end if 551 lwork = int(work(1)) 552 SAFE_DEALLOCATE_A(work) 553 554 SAFE_ALLOCATE(work(1:lwork)) 555 call zheevx('V', 'I', 'U', n, a(1, 1), n, M_ZERO, M_ZERO, & 556 1, k, abstol, m, e(1), v(1, 1), n, work(1), lwork, iwork(1), ifail(1), info) 557 558#endif 559 560 if(preserve_mat) then 561 ! b was destroyed, so we rebuild it 562 do ii = 1, n 563 do jj = 1, ii - 1 564 a(jj, ii) = R_CONJ(a(ii, jj)) 565 end do 566 a(ii, ii) = diaga(ii) 567 end do 568 569 SAFE_DEALLOCATE_A(diaga) 570 end if 571 572 573 SAFE_DEALLOCATE_A(work) 574 575 if(info /= 0) then 576#ifdef R_TREAL 577 write(message(1),'(3a,i5)') & 578 'In dlowest_eigensolve, LAPACK ', TOSTRING(dsyevx), ' returned error message ', info 579#else 580 write(message(1),'(3a,i5)') & 581 'In zlowest_eigensolve, LAPACK ', TOSTRING(zheevx), ' returned error message ', info 582#endif 583! http://www.netlib.org/lapack/explore-3.1.1-html/dsyevx.f.html 584!* INFO (output) INTEGER 585!* = 0: successful exit 586!* < 0: if INFO = -i, the i-th argument had an illegal value 587!* > 0: if INFO = i, then i eigenvectors failed to converge. 588!* Their indices are stored in array IFAIL. 589 if(info < 0) then 590 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 591 else 592 write(message(2), *) info, ' eigenvectors failed to converge: ', ifail(1:info) 593 end if 594 call messages_fatal(2) 595 end if 596 597 POP_SUB(X(lowest_eigensolve)) 598end subroutine X(lowest_eigensolve) 599 600! --------------------------------------------------------- 601!> Invert a real symmetric or complex Hermitian square matrix a 602R_TYPE function X(determinant)(n, a, preserve_mat) result(d) 603 integer, intent(in) :: n 604 R_TYPE, target, intent(inout) :: a(:,:) !< (n,n) 605 logical, intent(in) :: preserve_mat 606 607 integer :: info, i 608 integer, allocatable :: ipiv(:) 609 R_TYPE, pointer :: tmp_a(:,:) 610 611 ! No PUSH_SUB, called too often 612 613 ASSERT(n > 0) 614 615 SAFE_ALLOCATE(ipiv(1:n)) 616 617 if(preserve_mat) then 618 SAFE_ALLOCATE(tmp_a(1:n, 1:n)) 619 tmp_a(1:n, 1:n) = a(1:n, 1:n) 620 else 621 tmp_a => a 622 end if 623 624 call lapack_getrf(n, n, tmp_a(1, 1), lead_dim(tmp_a), ipiv(1), info) 625 if(info < 0) then 626 write(message(1), '(5a, i5)') 'In ', TOSTRING(X(determinant)), ', LAPACK ', TOSTRING(X(getrf)), ' returned info = ', info 627 call messages_fatal(1) 628 end if 629 630 d = M_ONE 631 do i = 1, n 632 if(ipiv(i) /= i) then 633 d = - d*tmp_a(i, i) 634 else 635 d = d*tmp_a(i, i) 636 end if 637 end do 638 639 SAFE_DEALLOCATE_A(ipiv) 640 if(preserve_mat) then 641 SAFE_DEALLOCATE_P(tmp_a) 642 end if 643 644end function X(determinant) 645 646! --------------------------------------------------------- 647!> Invert a real symmetric or complex Hermitian square matrix a 648subroutine X(inverter)(n, a, det) 649 integer, intent(in) :: n 650 R_TYPE, intent(inout) :: a(:,:) !< (n,n) 651 R_TYPE, optional, intent(out) :: det 652 653 integer :: info, i 654 integer, allocatable :: ipiv(:) 655 R_TYPE, allocatable :: work(:) 656 657 ! No PUSH_SUB, called too often 658 659 ASSERT(n > 0) 660 661 SAFE_ALLOCATE(work(1:n)) ! query? 662 SAFE_ALLOCATE(ipiv(1:n)) 663 664 call lapack_getrf(n, n, a(1, 1), lead_dim(a), ipiv(1), info) 665 if(info < 0) then 666 write(message(1), '(5a, i5)') 'In ', TOSTRING(X(determinant)), ', LAPACK ', TOSTRING(X(getrf)), ' returned info = ', info 667 call messages_fatal(1) 668 end if 669 670 if(present(det)) then 671 det = M_ONE 672 do i = 1, n 673 if(ipiv(i) /= i) then 674 det = - det*a(i, i) 675 else 676 det = det*a(i, i) 677 end if 678 end do 679 end if 680 681 682 call lapack_getri(n, a(1, 1), lead_dim(a), ipiv(1), work(1), n, info) 683 if(info /= 0) then 684 write(message(1), '(5a, i5)') 'In ', TOSTRING(X(determinant)), ', LAPACK ', TOSTRING(X(getri)), ' returned info = ', info 685! http://www.netlib.org/lapack/explore-3.1.1-html/zgetri.f.html 686!* INFO (output) INTEGER 687!* = 0: successful exit 688!* < 0: if INFO = -i, the i-th argument had an illegal value 689!* > 0: if INFO = i, U(i,i) is exactly zero; the matrix is 690!* singular and its inverse could not be computed. 691 if(info < 0) then 692 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 693 else 694 write(message(2), '(a,i5,a)') 'Diagonal element ', info, ' of U is 0; matrix is singular.' 695 end if 696 call messages_fatal(2) 697 end if 698 699 SAFE_DEALLOCATE_A(work) 700 SAFE_DEALLOCATE_A(ipiv) 701 702end subroutine X(inverter) 703 704 705! --------------------------------------------------------- 706!> Invert a real/complex symmetric square matrix a 707subroutine X(sym_inverter)(uplo, n, a) 708 character(1), intent(in) :: uplo 709 integer, intent(in) :: n 710 R_TYPE, intent(inout) :: a(:,:) !< (n,n) 711 712 integer :: info 713 integer, allocatable :: ipiv(:) 714 R_TYPE, allocatable :: work(:) 715 716 PUSH_SUB(X(sym_inverter)) 717 718 ASSERT(n > 0) 719 720 SAFE_ALLOCATE(work(1:n)) ! query? 721 SAFE_ALLOCATE(ipiv(1:n)) 722 723 call lapack_sytrf(uplo, n, a(1, 1), lead_dim(a), ipiv(1), work(1), n, info) 724 if(info < 0) then 725 write(message(1), '(5a, i5)') 'In ', TOSTRING(X(sym_inverter)), ', LAPACK ', TOSTRING(X(sytrf)), ' returned info = ', info 726 call messages_fatal(1) 727 end if 728 729 call lapack_sytri(uplo, n, a(1, 1), lead_dim(a), ipiv(1), work(1), info) 730 if(info /= 0) then 731 write(message(1), '(5a, i5)') 'In ', TOSTRING(X(sym_inverter)), ', LAPACK ', TOSTRING(X(sytri)), ' returned info = ', info 732! http://www.netlib.org/lapack/explore-3.1.1-html/dsytri.f.html 733!* INFO (output) INTEGER 734!* = 0: successful exit 735!* < 0: if INFO = -i, the i-th argument had an illegal value 736!* > 0: if INFO = i, U(i,i) is exactly zero; the matrix is 737!* singular and its inverse could not be computed. 738 if(info < 0) then 739 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 740 else 741 write(message(2), '(a,i5,a)') 'Diagonal element ', info, ' of D is 0; matrix is singular.' 742 end if 743 call messages_fatal(2) 744 end if 745 746 SAFE_DEALLOCATE_A(work) 747 SAFE_DEALLOCATE_A(ipiv) 748 POP_SUB(X(sym_inverter)) 749end subroutine X(sym_inverter) 750 751! MJV 9 nov 2016: why is this stuff explicitly set in cpp instead of using the 752! macros X()??? For the moment I have replicated this strategy in svd below. 753#ifdef R_TREAL 754! --------------------------------------------------------- 755!> compute the solution to a real system of linear equations A*X = B, 756!! where A is an N-by-N matrix and X and B are N-by-NRHS matrices. 757subroutine dlinsyssolve(n, nrhs, a, b, x) 758 integer, intent(in) :: n, nrhs 759 FLOAT, intent(inout) :: a(:,:) !< (n, n) 760 FLOAT, intent(inout) :: b(:,:) !< (n, nrhs) 761 FLOAT, intent(out) :: x(:,:) !< (n, nrhs) 762 763 integer :: info 764 integer, allocatable :: ipiv(:), iwork(:) 765 FLOAT :: rcond 766 FLOAT, allocatable :: ferr(:), berr(:), work(:), r(:), c(:), af(:,:) 767 character(1) :: equed 768 769 ! no PUSH_SUB, called too often 770 771 ASSERT(n > 0) 772 ASSERT(ubound(a, dim=1) >= n) 773 ASSERT(ubound(a, dim=2) >= n) 774 ASSERT(ubound(b, dim=1) >= n) 775 ASSERT(ubound(b, dim=2) >= nrhs) 776 ASSERT(ubound(x, dim=1) >= n) 777 ASSERT(ubound(x, dim=2) >= nrhs) 778 779 SAFE_ALLOCATE(ipiv(1:n)) 780 SAFE_ALLOCATE(iwork(1:n)) ! query? 781 SAFE_ALLOCATE(ferr(1:nrhs)) 782 SAFE_ALLOCATE(berr(1:nrhs)) 783 SAFE_ALLOCATE(work(1:4*n)) 784 SAFE_ALLOCATE(r(1:n)) 785 SAFE_ALLOCATE(c(1:n)) 786 SAFE_ALLOCATE(af(1:n, 1:n)) 787 788 call X(gesvx) ("N", "N", n, nrhs, a(1, 1), lead_dim(a), af(1, 1), n, ipiv(1), equed, r(1), c(1), & 789 b(1, 1), lead_dim(b), x(1, 1), lead_dim(x), rcond, ferr(1), berr(1), work(1), iwork(1), info) 790 791 if(info /= 0) then 792 write(message(1), '(3a, i5)') 'In dlinsyssolve, LAPACK ', TOSTRING(X(gesvx)), ' returned info = ', info 793!* INFO (output) INTEGER 794!* = 0: successful exit 795!* < 0: if INFO = -i, the i-th argument had an illegal value 796!* > 0: if INFO = i, and i is 797!* <= N: U(i,i) is exactly zero. The factorization has 798!* been completed, but the factor U is exactly 799!* singular, so the solution and error bounds 800!* could not be computed. RCOND = 0 is returned. 801!* = N+1: U is nonsingular, but RCOND is less than machine 802!* precision, meaning that the matrix is singular 803!* to working precision. Nevertheless, the 804!* solution and error bounds are computed because 805!* there are a number of situations where the 806!* computed solution can be more accurate than the 807!* value of RCOND would suggest. 808 if(info < 0) then 809 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 810 call messages_fatal(2) 811 else if(info == n+1) then 812 message(2) = '(reciprocal of the condition number is less than machine precision)' 813 call messages_warning(2) 814 else 815 write(message(2), '(a,i5,a)') 'Diagonal element ', info, ' of U is 0; matrix is singular.' 816 call messages_fatal(2) 817 end if 818 end if 819 820 SAFE_DEALLOCATE_A(ipiv) 821 SAFE_DEALLOCATE_A(iwork) 822 SAFE_DEALLOCATE_A(ferr) 823 SAFE_DEALLOCATE_A(berr) 824 SAFE_DEALLOCATE_A(work) 825 SAFE_DEALLOCATE_A(r) 826 SAFE_DEALLOCATE_A(c) 827 SAFE_DEALLOCATE_A(af) 828 829end subroutine dlinsyssolve 830 831#elif R_TCOMPLEX 832 833! --------------------------------------------------------- 834!> compute the solution to a complex system of linear equations A*X = B, 835!! where A is an N-by-N matrix and X and B are N-by-NRHS matrices. 836subroutine zlinsyssolve(n, nrhs, a, b, x) 837 integer, intent(in) :: n, nrhs 838 CMPLX, intent(inout) :: a(:,:) !< (n, n) 839 CMPLX, intent(inout) :: b(:,:) !< (n, nrhs) 840 CMPLX, intent(out) :: x(:,:) !< (n, nrhs) 841 842 integer :: info 843 integer, allocatable :: ipiv(:) 844 FLOAT, allocatable :: rwork(:), ferr(:), berr(:), r(:), c(:) 845 FLOAT :: rcond 846 CMPLX, allocatable :: work(:), af(:,:) 847 character(1) :: equed 848 849 PUSH_SUB(zlinsyssolve) 850 851 ASSERT(n > 0) 852 853 SAFE_ALLOCATE(ipiv(1:n)) ! query? 854 SAFE_ALLOCATE(rwork(1:2*n)) 855 SAFE_ALLOCATE(ferr(1:nrhs)) 856 SAFE_ALLOCATE(berr(1:nrhs)) 857 SAFE_ALLOCATE(work(1:2*n)) 858 SAFE_ALLOCATE(r(1:n)) 859 SAFE_ALLOCATE(c(1:n)) 860 SAFE_ALLOCATE(af(1:n, 1:n)) 861 862 equed = 'N' 863 864 call X(gesvx) ("N", "N", n, nrhs, a(1, 1), lead_dim(a), af(1, 1), lead_dim(af), & 865 ipiv(1), equed, r(1), c(1), b(1, 1), lead_dim(b), x(1, 1), lead_dim(x), & 866 rcond, ferr(1), berr(1), work(1), rwork(1), info) 867 if(info /= 0) then 868 write(message(1), '(3a, i5)') 'In zlinsyssolve, LAPACK ', TOSTRING(X(gesvx)), ' returned info = ', info 869! http://www.netlib.org/lapack/explore-3.1.1-html/zgesvx.f.html 870!* INFO (output) INTEGER 871!* = 0: successful exit 872!* < 0: if INFO = -i, the i-th argument had an illegal value 873!* > 0: if INFO = i, and i is 874!* <= N: U(i,i) is exactly zero. The factorization has 875!* been completed, but the factor U is exactly 876!* singular, so the solution and error bounds 877!* could not be computed. RCOND = 0 is returned. 878!* = N+1: U is nonsingular, but RCOND is less than machine 879!* precision, meaning that the matrix is singular 880!* to working precision. Nevertheless, the 881!* solution and error bounds are computed because 882!* there are a number of situations where the 883!* computed solution can be more accurate than the 884!* value of RCOND would suggest. 885 if(info < 0) then 886 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 887 call messages_fatal(2) 888 else if(info == n+1) then 889 message(2) = '(reciprocal of the condition number is less than machine precision)' 890 call messages_warning(2) 891 else 892 write(message(2), '(a,i5,a)') 'Diagonal element ', info, ' of U is 0; matrix is singular.' 893 call messages_fatal(2) 894 end if 895 end if 896 897 SAFE_DEALLOCATE_A(ipiv) 898 SAFE_DEALLOCATE_A(rwork) 899 SAFE_DEALLOCATE_A(ferr) 900 SAFE_DEALLOCATE_A(berr) 901 SAFE_DEALLOCATE_A(work) 902 SAFE_DEALLOCATE_A(r) 903 SAFE_DEALLOCATE_A(c) 904 SAFE_DEALLOCATE_A(af) 905 906 POP_SUB(zlinsyssolve) 907end subroutine zlinsyssolve 908#endif 909 910#ifdef R_TREAL 911! --------------------------------------------------------- 912!> computes the singular value decomposition of a real NxN matrix a(:,:) 913subroutine dsingular_value_decomp(m, n, a, u, vt, sg_values) 914 integer, intent(in) :: m, n 915 FLOAT, intent(inout) :: a(:,:) !< (m,n) 916 FLOAT, intent(out) :: u(:,:), vt(:,:) !< (m,m) (n,n) 917 FLOAT, intent(out) :: sg_values(:) !< (min(m,n)) 918 919 interface 920 subroutine X(gesvd) ( jobu, jobvt, m, n, a, lda, s, u, ldu, & 921 vt, ldvt, work, lwork, info ) 922 implicit none 923 character(1), intent(in) :: jobu, jobvt 924 integer, intent(in) :: m, n 925 FLOAT, intent(inout) :: a, u, vt ! a(lda,n), u(ldu,m), vt(ldvt,n) 926 FLOAT, intent(out) :: work ! work(lwork) 927 integer, intent(in) :: lda, ldu, ldvt, lwork 928 integer, intent(out) :: info 929 FLOAT, intent(out) :: s ! s(min(m,n)) 930 end subroutine X(gesvd) 931 end interface 932 933 integer :: info, lwork 934 FLOAT, allocatable :: work(:) 935 936 PUSH_SUB(dsingular_value_decomp) 937 938 ASSERT(n > 0) 939 ASSERT(m > 0) 940 941 942 ! double minimum lwork size to increase performance (see manpage) 943 lwork = 2*( 2*min(m, n) + max(m, n) ) 944 945 SAFE_ALLOCATE(work(1:lwork)) ! query? 946 947 call X(gesvd)( 'A', 'A', m, n, a(1, 1), lead_dim(a), sg_values(1), u(1, 1), lead_dim(u), vt(1, 1), & 948 lead_dim(vt), work(1), lwork, info ) 949 950 if(info /= 0) then 951 write(message(1), '(3a, i7)') 'In dsingular_value_decomp, LAPACK ', TOSTRING(X(gesvd)), ' returned info = ', info 952! http://www.netlib.org/lapack/explore-3.1.1-html/dgesvd.f.html 953!* INFO (output) INTEGER 954!* = 0: successful exit. 955!* < 0: if INFO = -i, the i-th argument had an illegal value. 956!* > 0: if ZBDSQR did not converge, INFO specifies how many 957!* superdiagonals of an intermediate bidiagonal form B 958!* did not converge to zero. See the description of WORK 959!* above for details. 960 if(info < 0) then 961 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 962 else 963 write(message(2), '(i5,a)') info, ' superdiagonal elements of an intermediate bidiagonal did not converge to zero.' 964 end if 965 call messages_fatal(2) 966 end if 967 968 SAFE_DEALLOCATE_A(work) 969 POP_SUB(dsingular_value_decomp) 970end subroutine dsingular_value_decomp 971 972 973! --------------------------------------------------------- 974!> computes inverse of a real NxN matrix a(:,:) using the SVD decomposition 975subroutine dsvd_inverse(m, n, a, threshold) 976 integer, intent(in) :: m, n 977 FLOAT, intent(inout) :: a(:,:) !< (m,n); a will be replaced by its inverse 978 FLOAT, intent(in), optional :: threshold 979 980 FLOAT, allocatable :: u(:,:), vt(:,:) 981 FLOAT, allocatable :: sg_values(:) 982 FLOAT :: tmp 983 FLOAT :: sg_inverse, threshold_ 984 integer :: j, k, l, minmn 985 986 ASSERT(n > 0) 987 ASSERT(m > 0) 988 minmn = min(m,n) 989 990 SAFE_ALLOCATE( u(1:m, 1:m)) 991 SAFE_ALLOCATE(vt(1:n, 1:n)) 992 SAFE_ALLOCATE(sg_values(1:minmn)) 993 994 PUSH_SUB(dsvd_inverse) 995 996 call dsingular_value_decomp(m, n, a, u, vt, sg_values) 997 998 threshold_ = CNST(1e-10) 999 if(present(threshold)) threshold_ = threshold 1000 1001 ! build inverse 1002 do j = 1, m 1003 do k = 1, n 1004 tmp = M_ZERO 1005 do l = 1, minmn 1006 if (sg_values(l) < threshold_) then 1007 !write(message(1), '(a)') 'In dsvd_inverse: singular value below threshold.' 1008 !call messages_warning(1) 1009 sg_inverse = M_ZERO 1010 else 1011 sg_inverse = M_ONE/sg_values(l) 1012 end if 1013 tmp = tmp + vt(l, k)*sg_inverse*u(j, l) 1014 end do 1015 a(j, k) = tmp 1016 end do 1017 end do 1018 1019 SAFE_DEALLOCATE_A(sg_values) 1020 SAFE_DEALLOCATE_A(vt) 1021 SAFE_DEALLOCATE_A(u) 1022 POP_SUB(dsvd_inverse) 1023end subroutine dsvd_inverse 1024 1025#elif R_TCOMPLEX 1026! --------------------------------------------------------- 1027!> computes the singular value decomposition of a complex MxN matrix a(:,:) 1028subroutine zsingular_value_decomp(m, n, a, u, vt, sg_values) 1029 integer, intent(in) :: m, n 1030 CMPLX, intent(inout) :: a(:,:) !< (m,n) 1031 CMPLX, intent(out) :: u(:,:), vt(:,:) !< (n,n) and (m,m) 1032 FLOAT, intent(out) :: sg_values(:) !< (n) 1033 1034 interface 1035 subroutine X(gesvd) ( jobu, jobvt, m, n, a, lda, s, u, ldu, & 1036 vt, ldvt, work, lwork, rwork, info ) 1037 implicit none 1038 character(1), intent(in) :: jobu, jobvt 1039 integer, intent(in) :: m, n 1040 CMPLX, intent(inout) :: a, u, vt ! a(lda,n), u(ldu,m), vt(ldvt,n) 1041 CMPLX, intent(out) :: work ! work(lwork) 1042 integer, intent(in) :: lda, ldu, ldvt, lwork 1043 integer, intent(out) :: info 1044 FLOAT, intent(out) :: s ! s(min(m,n)) 1045 FLOAT, intent(inout) :: rwork ! rwork(5*min(m,n)) 1046 end subroutine X(gesvd) 1047 end interface 1048 1049 integer :: info, lwork 1050 CMPLX, allocatable :: work(:) 1051 FLOAT, allocatable :: rwork(:) 1052 1053 PUSH_SUB(zsingular_value_decomp) 1054 1055 ASSERT(n > 0) 1056 ASSERT(m > 0) 1057 1058 ! double minimum lwork size to increase performance (see manpage) 1059 lwork = 2*( 2*min(m, n) + max(m, n) ) 1060 1061 SAFE_ALLOCATE(work(1:lwork)) ! query? 1062 SAFE_ALLOCATE(rwork(1:5*min(m, n))) 1063 1064 call X(gesvd)( 'A', 'A', m, n, a(1, 1), lead_dim(a), sg_values(1), u(1, 1), lead_dim(u), & 1065 vt(1, 1), lead_dim(vt), work(1), lwork, rwork(1), info ) 1066 1067 if(info /= 0) then 1068 write(message(1), '(3a, i5)') 'In zsingular_value_decomp, LAPACK ', TOSTRING(X(gesvd)), ' returned info = ', info 1069! http://www.netlib.org/lapack/explore-3.1.1-html/zgesvd.f.html 1070!* INFO (output) INTEGER 1071!* = 0: successful exit. 1072!* < 0: if INFO = -i, the i-th argument had an illegal value. 1073!* > 0: if ZBDSQR did not converge, INFO specifies how many 1074!* superdiagonals of an intermediate bidiagonal form B 1075!* did not converge to zero. See the description of RWORK 1076!* above for details. 1077 if(info < 0) then 1078 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 1079 else 1080 write(message(2), '(i5,a)') info, ' superdiagonal elements of an intermediate bidiagonal did not converge to zero.' 1081 end if 1082 call messages_fatal(2) 1083 end if 1084 1085 SAFE_DEALLOCATE_A(rwork) 1086 SAFE_DEALLOCATE_A(work) 1087 POP_SUB(zsingular_value_decomp) 1088end subroutine zsingular_value_decomp 1089 1090 1091! --------------------------------------------------------- 1092!> computes inverse of a complex MxN matrix a(:,:) using the SVD decomposition 1093subroutine zsvd_inverse(m, n, a, threshold) 1094 integer, intent(in) :: m, n 1095 CMPLX, intent(inout) :: a(:,:) !< (m,n); a will be replaced by its inverse transposed 1096 FLOAT, intent(in), optional :: threshold 1097 1098 CMPLX, allocatable :: u(:,:), vt(:,:) 1099 FLOAT, allocatable :: sg_values(:) 1100 CMPLX :: tmp 1101 FLOAT :: sg_inverse, threshold_ 1102 integer :: j, k, l, minmn 1103 1104 ASSERT(n > 0) 1105 ASSERT(m > 0) 1106 minmn = min(m,n) 1107 1108 SAFE_ALLOCATE( u(1:m, 1:m)) 1109 SAFE_ALLOCATE(vt(1:n, 1:n)) 1110 SAFE_ALLOCATE(sg_values(1:minmn)) 1111 1112 PUSH_SUB(zsvd_inverse) 1113 1114 call zsingular_value_decomp(m, n, a, u, vt, sg_values) 1115 1116 threshold_ = CNST(1e-10) 1117 if(present(threshold)) threshold_ = threshold 1118 1119 ! build inverse 1120 do j = 1, m 1121 do k = 1, n 1122 tmp = M_ZERO 1123 do l = 1, minmn 1124 if (sg_values(l) < threshold_) then 1125 write(message(1), '(a)') 'In zsvd_inverse: singular value below threshold.' 1126 call messages_warning(1) 1127 sg_inverse = M_ZERO 1128 else 1129 sg_inverse = M_ONE/sg_values(l) 1130 end if 1131 tmp = tmp + conjg(vt(l, k))*sg_inverse*conjg(u(j, l)) 1132 end do 1133 a(j, k) = tmp 1134 end do 1135 end do 1136 1137 SAFE_DEALLOCATE_A(sg_values) 1138 SAFE_DEALLOCATE_A(vt) 1139 SAFE_DEALLOCATE_A(u) 1140 POP_SUB(zsvd_inverse) 1141end subroutine zsvd_inverse 1142#endif 1143 1144! --------------------------------------------------------- 1145!> Calculate the inverse of a real/complex upper triangular matrix (in 1146!! unpacked storage). (lower triangular would be a trivial variant of this) 1147subroutine X(invert_upper_triangular)(n, a) 1148 integer, intent(in) :: n 1149 R_TYPE, intent(inout) :: a(:,:) !< (n,n) 1150 1151 integer :: info 1152 1153 interface 1154 subroutine X(trtri)(uplo, diag, n, a, lda, info) 1155 implicit none 1156 character(1), intent(in) :: uplo 1157 character(1), intent(in) :: diag 1158 integer, intent(in) :: n 1159 R_TYPE, intent(inout) :: a 1160 integer, intent(in) :: lda 1161 integer, intent(out) :: info 1162 end subroutine X(trtri) 1163 end interface 1164 1165 PUSH_SUB(X(invert_upper_triangular)) 1166 1167 ASSERT(n > 0) 1168 1169 call X(trtri)('U', 'N', n, a(1, 1), lead_dim(a), info) 1170 1171 if(info /= 0) then 1172 write(message(1), '(5a,i5)') & 1173 'In ', TOSTRING(Xinvert_upper_triangular), ', LAPACK ', TOSTRING(X(trtri)), ' returned error message ', info 1174!http://www.netlib.org/lapack/explore-3.1.1-html/dtrtri.f.html 1175!* INFO (output) INTEGER 1176!* = 0: successful exit 1177!* < 0: if INFO = -i, the i-th argument had an illegal value 1178!* > 0: if INFO = i, A(i,i) is exactly zero. The triangular 1179!* matrix is singular and its inverse can not be computed. 1180 if(info < 0) then 1181 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 1182 else 1183 write(message(2), '(a,i5,a)') 'Diagonal element ', info, ' is 0; matrix is singular.' 1184 end if 1185 call messages_fatal(2) 1186 end if 1187 1188 POP_SUB(X(invert_upper_triangular)) 1189end subroutine X(invert_upper_triangular) 1190 1191 1192 1193subroutine X(least_squares_vec)(nn, aa, bb, xx, preserve_mat) 1194 integer, intent(in) :: nn 1195 R_TYPE, intent(inout), target :: aa(:, :) 1196 R_TYPE, intent(in) :: bb(:) 1197 R_TYPE, intent(out) :: xx(:) 1198 logical, intent(in) :: preserve_mat 1199 1200 R_TYPE :: dlwork 1201 R_TYPE, allocatable :: work(:) 1202 integer :: rank, info 1203 FLOAT, allocatable :: ss(:) 1204#ifndef R_TREAL 1205 FLOAT, allocatable :: rwork(:) 1206#endif 1207 R_TYPE, pointer :: tmp_aa(:,:) 1208 1209 PUSH_SUB(X(least_squares_vec)) 1210 1211 if(preserve_mat) then 1212 SAFE_ALLOCATE(tmp_aa(1:nn, 1:nn)) 1213 tmp_aa(1:nn, 1:nn) = aa(1:nn, 1:nn) 1214 else 1215 tmp_aa => aa 1216 end if 1217 1218 xx(1:nn) = bb(1:nn) 1219 1220 SAFE_ALLOCATE(ss(1:nn)) 1221 1222#ifdef R_TREAL 1223 call lapack_gelss(nn, nn, 1, tmp_aa(1, 1), lead_dim(tmp_aa), xx(1), nn, ss(1), CNST(-1.0), rank, dlwork, -1, info) 1224 1225 SAFE_ALLOCATE(work(1:int(dlwork))) 1226 1227 call lapack_gelss(nn, nn, 1, tmp_aa(1, 1), lead_dim(tmp_aa), xx(1), nn, ss(1), CNST(-1.0), rank, work(1), int(dlwork), info) 1228#else 1229 SAFE_ALLOCATE(rwork(1:5*nn)) 1230 call lapack_gelss(nn, nn, 1, tmp_aa(1, 1), lead_dim(tmp_aa), xx(1), nn, ss(1), CNST(-1.0), rank, dlwork, -1, rwork(1), info) 1231 1232 SAFE_ALLOCATE(work(1:int(dlwork))) 1233 1234 call lapack_gelss(nn, nn, 1, tmp_aa(1, 1), lead_dim(tmp_aa), xx(1), nn, ss(1), CNST(-1.0), rank, work(1), int(dlwork), rwork(1), info) 1235 SAFE_DEALLOCATE_A(rwork) 1236#endif 1237 1238 SAFE_DEALLOCATE_A(ss) 1239 if(preserve_mat) then 1240 SAFE_DEALLOCATE_P(tmp_aa) 1241 end if 1242 1243 if(info /= 0) then 1244 write(message(1), '(5a,i5)') & 1245 'In ', TOSTRING(X(lalg_least_squares_vec)), ', LAPACK ', TOSTRING(X(gelss)), ' returned error mess age ', info 1246 !https://www.netlib.org/lapack/lapack-3.1.1/html/zgelss.f.html 1247 !* INFO (output) INTEGER 1248 !* = 0: successful exit 1249 !* < 0: if INFO = -i, the i-th argument had an illegal value. 1250 !* > 0: the algorithm for computing the SVD failed to converge; 1251 !* if INFO = i, i off-diagonal elements of an intermediate 1252 !* bidiagonal form did not converge to zero. 1253 if(info < 0) then 1254 write(message(2), '(a,i5,a)') 'Argument number ', -info, ' had an illegal value.' 1255 else 1256 write(message(2), '(a,i5,a)') 'Off-diagonal element ', info, ' of an intermediate bidiagonal form did not converge to zero.' 1257 end if 1258 call messages_fatal(2) 1259 end if 1260 1261 POP_SUB(X(least_squares_vec)) 1262 1263end subroutine X(least_squares_vec) 1264 1265!! Local Variables: 1266!! mode: f90 1267!! coding: utf-8 1268!! End: 1269