linalg 1.8.2
A linear algebra library that provides a user-friendly interface to several BLAS and LAPACK routines.
Loading...
Searching...
No Matches
linalg_eigen.f90
1! linalg_eigen.f90
2
7submodule(linalg) linalg_eigen
8 use lapack
9 implicit none
10contains
11! ------------------------------------------------------------------------------
12 module subroutine eigen_symm(vecs, a, vals, work, olwork, err)
13 ! Arguments
14 logical, intent(in) :: vecs
15 real(real64), intent(inout), dimension(:,:) :: a
16 real(real64), intent(out), dimension(:) :: vals
17 real(real64), intent(out), pointer, optional, dimension(:) :: work
18 integer(int32), intent(out), optional :: olwork
19 class(errors), intent(inout), optional, target :: err
20
21 ! Local Variables
22 character :: jobz
23 integer(int32) :: n, istat, flag, lwork
24 real(real64), pointer, dimension(:) :: wptr
25 real(real64), allocatable, target, dimension(:) :: wrk
26 real(real64), dimension(1) :: temp
27 class(errors), pointer :: errmgr
28 type(errors), target :: deferr
29 character(len = :), allocatable :: errmsg
30
31 ! Initialization
32 n = size(a, 1)
33 if (vecs) then
34 jobz = 'V'
35 else
36 jobz = 'N'
37 end if
38 if (present(err)) then
39 errmgr => err
40 else
41 errmgr => deferr
42 end if
43
44 ! Input Check
45 flag = 0
46 if (size(a, 2) /= n) then
47 flag = 2
48 else if (size(vals) /= n) then
49 flag = 3
50 end if
51 if (flag /= 0) then
52 ! ERROR: One of the input arrays is not sized correctly
53 allocate(character(len = 256) :: errmsg)
54 write(errmsg, 100) "Input number ", flag, &
55 " is not sized correctly."
56 call errmgr%report_error("eigen_symm", trim(errmsg), &
57 la_array_size_error)
58 return
59 end if
60
61 ! Workspace Query
62 call dsyev(jobz, 'L', n, a, n, vals, temp, -1, flag)
63 lwork = int(temp(1), int32)
64 if (present(olwork)) then
65 olwork = lwork
66 return
67 end if
68
69 ! Local Memory Allocation
70 if (present(work)) then
71 if (size(work) < lwork) then
72 ! ERROR: WORK not sized correctly
73 call errmgr%report_error("eigen_symm", &
74 "Incorrectly sized input array WORK, argument 5.", &
75 la_array_size_error)
76 return
77 end if
78 wptr => work(1:lwork)
79 else
80 allocate(wrk(lwork), stat = istat)
81 if (istat /= 0) then
82 ! ERROR: Out of memory
83 call errmgr%report_error("eigen_symm", &
84 "Insufficient memory available.", &
85 la_out_of_memory_error)
86 return
87 end if
88 wptr => wrk
89 end if
90
91 ! Process
92 call dsyev(jobz, 'L', n, a, n, vals, wptr, lwork, flag)
93 if (flag > 0) then
94 call errmgr%report_error("eigen_symm", &
95 "The algorithm failed to converge.", la_convergence_error)
96 end if
97
98 ! Formatting
99100 format(a, i0, a)
100 end subroutine
101
102! ------------------------------------------------------------------------------
103 module subroutine eigen_asymm(a, vals, vecs, work, olwork, err)
104 ! Arguments
105 real(real64), intent(inout), dimension(:,:) :: a
106 complex(real64), intent(out), dimension(:) :: vals
107 complex(real64), intent(out), optional, dimension(:,:) :: vecs
108 real(real64), intent(out), pointer, optional, dimension(:) :: work
109 integer(int32), intent(out), optional :: olwork
110 class(errors), intent(inout), optional, target :: err
111
112 ! Parameters
113 real(real64), parameter :: zero = 0.0d0
114 real(real64), parameter :: two = 2.0d0
115
116 ! Local Variables
117 character :: jobvl, jobvr
118 integer(int32) :: i, j, jp1, n, n1, n2a, n2b, n3a, n3b, istat, flag, &
119 lwork, lwork1
120 real(real64) :: eps
121 real(real64), dimension(1) :: dummy, temp
122 real(real64), dimension(1,1) :: dummy_mtx
123 real(real64), pointer, dimension(:) :: wr, wi, wptr, w
124 real(real64), pointer, dimension(:,:) :: vr
125 real(real64), allocatable, target, dimension(:) :: wrk
126 class(errors), pointer :: errmgr
127 type(errors), target :: deferr
128 character(len = :), allocatable :: errmsg
129
130 ! Initialization
131 jobvl = 'N'
132 if (present(vecs)) then
133 jobvr = 'V'
134 else
135 jobvr = 'N'
136 end if
137 n = size(a, 1)
138 eps = two * epsilon(eps)
139 if (present(err)) then
140 errmgr => err
141 else
142 errmgr => deferr
143 end if
144
145 ! Input Check
146 flag = 0
147 if (size(a, 2) /= n) then
148 flag = 1
149 else if (size(vals) /= n) then
150 flag = 2
151 else if (present(vecs)) then
152 if (size(vecs, 1) /= n .or. size(vecs, 2) /= n) then
153 flag = 3
154 end if
155 end if
156 if (flag /= 0) then
157 ! ERROR: One of the input arrays is not sized correctly
158 allocate(character(len = 256) :: errmsg)
159 write(errmsg, 100) "Input number ", flag, &
160 " is not sized correctly."
161 call errmgr%report_error("eigen_asymm", trim(errmsg), &
162 la_array_size_error)
163 return
164 end if
165
166 ! Workspace Query
167 call dgeev(jobvl, jobvr, n, a, n, dummy, dummy, dummy_mtx, n, &
168 dummy_mtx, n, temp, -1, flag)
169 lwork1 = int(temp(1), int32)
170 if (present(vecs)) then
171 lwork = lwork1 + 2 * n + n * n
172 else
173 lwork = lwork1 + 2 * n
174 end if
175 if (present(olwork)) then
176 olwork = lwork
177 return
178 end if
179
180 ! Local Memory Allocation
181 if (present(work)) then
182 if (size(work) < lwork) then
183 ! ERROR: WORK not sized correctly
184 call errmgr%report_error("eigen_asymm", &
185 "Incorrectly sized input array WORK, argument 5.", &
186 la_array_size_error)
187 return
188 end if
189 wptr => work(1:lwork)
190 else
191 allocate(wrk(lwork), stat = istat)
192 if (istat /= 0) then
193 ! ERROR: Out of memory
194 call errmgr%report_error("eigen_asymm", &
195 "Insufficient memory available.", &
196 la_out_of_memory_error)
197 return
198 end if
199 wptr => wrk
200 end if
201
202 ! Locate each array within the workspace array
203 n1 = n
204 n2a = n1 + 1
205 n2b = n2a + n - 1
206 n3a = n2b + 1
207 n3b = n3a + lwork1 - 1
208
209 ! Assign pointers
210 wr => wptr(1:n1)
211 wi => wptr(n2a:n2b)
212 w => wptr(n3a:n3b)
213
214 ! Process
215 if (present(vecs)) then
216 ! Assign a pointer to the eigenvector matrix
217 vr(1:n,1:n) => wptr(n3b+1:lwork)
218
219 ! Compute the eigenvectors and eigenvalues
220 call dgeev(jobvl, jobvr, n, a, n, wr, wi, dummy_mtx, n, vr, n, &
221 w, lwork1, flag)
222
223 ! Check for convergence
224 if (flag > 0) then
225 call errmgr%report_error("eigen_asymm", &
226 "The algorithm failed to converge.", la_convergence_error)
227 return
228 end if
229
230 ! Store the eigenvalues and eigenvectors
231 j = 1
232 do while (j <= n)
233 if (abs(wi(j)) < eps) then
234 ! We've got a real-valued eigenvalue
235 vals(j) = cmplx(wr(j), zero, real64)
236 do i = 1, n
237 vecs(i,j) = cmplx(vr(i,j), zero, real64)
238 end do
239 else
240 ! We've got a complex cojugate pair of eigenvalues
241 jp1 = j + 1
242 vals(j) = cmplx(wr(j), wi(j), real64)
243 vals(jp1) = conjg(vals(j))
244 do i = 1, n
245 vecs(i,j) = cmplx(vr(i,j), vr(i,jp1), real64)
246 vecs(i,jp1) = conjg(vecs(i,j))
247 end do
248
249 ! Increment j and continue the loop
250 j = j + 2
251 cycle
252 end if
253
254 ! Increment j
255 j = j + 1
256 end do
257 else
258 ! Compute just the eigenvalues
259 call dgeev(jobvl, jobvr, n, a, n, wr, wi, dummy_mtx, n, &
260 dummy_mtx, n, w, lwork1, flag)
261
262 ! Check for convergence
263 if (flag > 0) then
264 call errmgr%report_error("eigen_asymm", &
265 "The algorithm failed to converge.", la_convergence_error)
266 return
267 end if
268
269 ! Store the eigenvalues
270 do i = 1, n
271 vals(i) = cmplx(wr(i), wi(i), real64)
272 end do
273 end if
274
275 ! Formatting
276100 format(a, i0, a)
277 end subroutine
278
279! ------------------------------------------------------------------------------
280 module subroutine eigen_gen(a, b, alpha, beta, vecs, work, olwork, err)
281 ! Arguments
282 real(real64), intent(inout), dimension(:,:) :: a, b
283 complex(real64), intent(out), dimension(:) :: alpha
284 real(real64), intent(out), optional, dimension(:) :: beta
285 complex(real64), intent(out), optional, dimension(:,:) :: vecs
286 real(real64), intent(out), optional, pointer, dimension(:) :: work
287 integer(int32), intent(out), optional :: olwork
288 class(errors), intent(inout), optional, target :: err
289
290 ! Parameters
291 real(real64), parameter :: zero = 0.0d0
292 real(real64), parameter :: two = 2.0d0
293
294 ! Local Variables
295 character :: jobvl, jobvr
296 integer(int32) :: i, j, jp1, n, n1, n2a, n2b, n3a, n3b, n4a, n4b, &
297 istat, flag, lwork, lwork1
298 real(real64), dimension(1) :: temp
299 real(real64), dimension(1,1) :: dummy
300 real(real64), pointer, dimension(:) :: wptr, w, alphar, alphai, bptr
301 real(real64), pointer, dimension(:,:) :: vr
302 real(real64), allocatable, target, dimension(:) :: wrk
303 real(real64) :: eps
304 class(errors), pointer :: errmgr
305 type(errors), target :: deferr
306 character(len = :), allocatable :: errmsg
307
308 ! Initialization
309 jobvl = 'N'
310 jobvr = 'N'
311 if (present(vecs)) then
312 jobvr = 'V'
313 else
314 jobvr = 'N'
315 end if
316 n = size(a, 1)
317 eps = two * epsilon(eps)
318 if (present(err)) then
319 errmgr => err
320 else
321 errmgr => deferr
322 end if
323
324 ! Input Check
325 flag = 0
326 if (size(a, 2) /= n) then
327 flag = 1
328 else if (size(b, 1) /= n .or. size(b, 2) /= n) then
329 flag = 2
330 else if (size(alpha) /= n) then
331 flag = 3
332 else if (present(beta)) then
333 if (size(beta) /= n) flag = 4
334 else if (present(vecs)) then
335 if (size(vecs, 1) /= n .or. size(vecs, 2) /= n) flag = 5
336 end if
337 if (flag /= 0) then
338 ! ERROR: One of the input arrays is not sized correctly
339 allocate(character(len = 256) :: errmsg)
340 write(errmsg, 100) "Input number ", flag, &
341 " is not sized correctly."
342 call errmgr%report_error("eigen_gen", trim(errmsg), &
343 la_array_size_error)
344 return
345 end if
346
347 ! Workspace Query
348 call dggev(jobvl, jobvr, n, a, n, b, n, temp, temp, temp, dummy, n, &
349 dummy, n, temp, -1, flag)
350 lwork1 = int(temp(1), int32)
351 lwork = lwork1 + 2 * n
352 if (.not.present(beta)) then
353 lwork = lwork + n
354 end if
355 if (present(vecs)) then
356 lwork = lwork + n * n
357 end if
358 if (present(olwork)) then
359 olwork = lwork
360 return
361 end if
362
363 ! Local Memory Allocation
364 if (present(work)) then
365 if (size(work) < lwork) then
366 ! ERROR: WORK not sized correctly
367 call errmgr%report_error("eigen_gen", &
368 "Incorrectly sized input array WORK, argument 5.", &
369 la_array_size_error)
370 return
371 end if
372 wptr => work(1:lwork)
373 else
374 allocate(wrk(lwork), stat = istat)
375 if (istat /= 0) then
376 ! ERROR: Out of memory
377 call errmgr%report_error("eigen_gen", &
378 "Insufficient memory available.", &
379 la_out_of_memory_error)
380 return
381 end if
382 wptr => wrk
383 end if
384
385 ! Locate each array within the workspace array & assign pointers
386 n1 = n
387 n2a = n1 + 1
388 n2b = n2a + n - 1
389 n3a = n2b + 1
390 n3b = n3a + lwork1 - 1
391 n4b = n3b
392 alphar => wptr(1:n1)
393 alphai => wptr(n2a:n2b)
394 w => wptr(n3a:n3b)
395 if (.not.present(beta)) then
396 n4a = n3b + 1
397 n4b = n4a + n - 1
398 bptr => wptr(n4a:n4b)
399 end if
400
401 ! Process
402 if (present(vecs)) then
403 ! Assign a pointer to the eigenvector matrix
404 vr(1:n,1:n) => wptr(n4b+1:lwork)
405
406 ! Compute the eigenvalues and eigenvectors
407 if (present(beta)) then
408 call dggev(jobvl, jobvr, n, a, n, b, n, alphar, alphai, &
409 beta, dummy, n, vr, n, w, lwork1, flag)
410 else
411 call dggev(jobvl, jobvr, n, a, n, b, n, alphar, alphai, &
412 bptr, dummy, n, vr, n, w, lwork1, flag)
413 end if
414
415 ! Check for convergence
416 if (flag > 0) then
417 call errmgr%report_error("eigen_gen", &
418 "The algorithm failed to converge.", la_convergence_error)
419 return
420 end if
421
422 ! Store the eigenvalues and eigenvectors
423 j = 1
424 do while (j <= n)
425 if (abs(alphai(j)) < eps) then
426 ! Real-Valued
427 alpha(j) = cmplx(alphar(j), zero, real64)
428 do i = 1, n
429 vecs(i,j) = cmplx(vr(i,j), zero, real64)
430 end do
431 else
432 ! Complex-Valued
433 jp1 = j + 1
434 alpha(j) = cmplx(alphar(j), alphai(j), real64)
435 alpha(jp1) = cmplx(alphar(jp1), alphai(jp1), real64)
436 do i = 1, n
437 vecs(i,j) = cmplx(vr(i,j), vr(i,jp1), real64)
438 vecs(i,jp1) = conjg(vecs(i,j))
439 end do
440
441 ! Increment j and continue
442 j = j + 2
443 cycle
444 end if
445
446 ! Increment j
447 j = j + 1
448 end do
449 if (.not.present(beta)) alpha = alpha / bptr
450 else
451 ! Compute just the eigenvalues
452 if (present(beta)) then
453 call dggev(jobvl, jobvr, n, a, n, b, n, alphar, alphai, &
454 beta, dummy, n, dummy, n, w, lwork1, flag)
455 else
456 call dggev(jobvl, jobvr, n, a, n, b, n, alphar, alphai, &
457 bptr, dummy, n, dummy, n, w, lwork1, flag)
458 end if
459
460 ! Check for convergence
461 if (flag > 0) then
462 call errmgr%report_error("eigen_gen", &
463 "The algorithm failed to converge.", la_convergence_error)
464 return
465 end if
466
467 ! Store the eigenvalues
468 do i = 1, n
469 alpha(i) = cmplx(alphar(i), alphai(i), real64)
470 end do
471 if (.not.present(beta)) alpha = alpha / bptr
472 end if
473
474 ! Formatting
475100 format(a, i0, a)
476 end subroutine
477
478! ------------------------------------------------------------------------------
479 module subroutine eigen_cmplx(a, vals, vecs, work, olwork, rwork, err)
480 ! Arguments
481 complex(real64), intent(inout), dimension(:,:) :: a
482 complex(real64), intent(out), dimension(:) :: vals
483 complex(real64), intent(out), optional, dimension(:,:) :: vecs
484 complex(real64), intent(out), target, optional, dimension(:) :: work
485 real(real64), intent(out), target, optional, dimension(:) :: rwork
486 integer(int32), intent(out), optional :: olwork
487 class(errors), intent(inout), optional, target :: err
488
489 ! Local Variables
490 character :: jobvl, jobvr
491 character(len = :), allocatable :: errmsg
492 integer(int32) :: n, flag, lwork, lrwork
493 real(real64) :: rdummy(1)
494 complex(real64) :: temp(1), dummy(1), dummy_mtx(1,1)
495 complex(real64), allocatable, target, dimension(:) :: wrk
496 complex(real64), pointer, dimension(:) :: wptr
497 real(real64), allocatable, target, dimension(:) :: rwrk
498 real(real64), pointer, dimension(:) :: rwptr
499 class(errors), pointer :: errmgr
500 type(errors), target :: deferr
501
502 ! Initialization
503 if (present(err)) then
504 errmgr => err
505 else
506 errmgr => deferr
507 end if
508 jobvl = 'N'
509 if (present(vecs)) then
510 jobvr = 'V'
511 else
512 jobvr = 'N'
513 end if
514 n = size(a, 1)
515 lrwork = 2 * n
516
517 ! Input Check
518 flag = 0
519 if (size(a, 2) /= n) then
520 flag = 1
521 else if (size(vals) /= n) then
522 flag = 2
523 else if (present(vecs)) then
524 if (size(vecs, 1) /= n .or. size(vecs, 2) /= n) then
525 flag = 3
526 end if
527 end if
528 if (flag /= 0) then
529 ! ERROR: One of the input arrays is not sized correctly
530 allocate(character(len = 256) :: errmsg)
531 write(errmsg, 100) "Input number ", flag, &
532 " is not sized correctly."
533 call errmgr%report_error("eigen_cmplx", trim(errmsg), &
534 la_array_size_error)
535 return
536 end if
537
538 ! Workspace Query
539 call zgeev(jobvl, jobvr, n, a, n, dummy, dummy_mtx, n, dummy_mtx, n, temp, &
540 -1, rdummy, flag)
541 lwork = int(temp(1), int32)
542 if (present(olwork)) then
543 olwork = lwork
544 return
545 end if
546
547 ! Local Memory Allocation
548 if (present(work)) then
549 if (size(work) < lwork) then
550 ! ERROR: WORK not sized correctly
551 call errmgr%report_error("eigen_cmplx", &
552 "Incorrectly sized input array WORK.", &
553 la_array_size_error)
554 return
555 end if
556 wptr => work
557 else
558 allocate(wrk(lwork), stat = flag)
559 if (flag /= 0) then
560 ! ERROR: Out of memory
561 call errmgr%report_error("eigen_cmplx", &
562 "Insufficient memory available.", &
563 la_out_of_memory_error)
564 return
565 end if
566 wptr => wrk
567 end if
568
569 if (present(rwork)) then
570 if (size(work) < lrwork) then
571 ! ERROR: RWORK not sized correctly
572 call errmgr%report_error("eigen_cmplx", &
573 "Incorrectly sized input array RWORK.", &
574 la_array_size_error)
575 return
576 end if
577 rwptr => rwork
578 else
579 allocate(rwrk(lrwork), stat = flag)
580 if (flag /= 0) then
581 ! ERROR: Out of memory
582 call errmgr%report_error("eigen_cmplx", &
583 "Insufficient memory available.", &
584 la_out_of_memory_error)
585 return
586 end if
587 rwptr => rwrk
588 end if
589
590 ! Process
591 if (present(vecs)) then
592 call zgeev(jobvl, jobvr, n, a, n, vals, dummy_mtx, n, vecs, n, &
593 wptr, lwork, rwptr, flag)
594 else
595 call zgeev(jobvl, jobvr, n, a, n, vals, dummy_mtx, n, dummy_mtx, n, &
596 wptr, lwork, rwptr, flag)
597 end if
598
599 if (flag > 0) then
600 call errmgr%report_error("eigen_cmplx", &
601 "The algorithm failed to converge.", &
602 la_convergence_error)
603 return
604 end if
605
606 ! Formatting
607100 format(a, i0, a)
608 end subroutine
609
610! ------------------------------------------------------------------------------
611end submodule
Provides a set of common linear algebra routines.
Definition linalg.f90:145