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