13 USE ieee_arithmetic,
ONLY: ieee_is_finite
14#if defined(__HAS_IEEE_EXCEPTIONS)
15 USE ieee_exceptions,
ONLY: ieee_all, ieee_get_halting_mode, ieee_set_halting_mode
26 MODULE PROCEDURE localizer_inertia_complex, localizer_inertia_real
48 invariant, gap, metric_ratio, status)
49 COMPLEX(dp),
INTENT(IN) :: h(:, :), s(:, :), r(:, :, :)
50 REAL(
dp),
INTENT(IN) :: point(3), energy, kappa, matrix_tol, &
52 INTEGER,
INTENT(OUT) :: invariant
53 REAL(
dp),
INTENT(OUT) :: gap, metric_ratio
54 INTEGER,
INTENT(OUT) :: status
56 COMPLEX(dp),
PARAMETER :: ii = cmplx(0.0_dp, 1.0_dp,
dp)
58 COMPLEX(dp),
ALLOCATABLE :: block(:, :), shifted(:, :, :)
66 IF (n < 2 .OR. mod(n, 2) /= 0 .OR.
SIZE(h, 2) /= n)
RETURN
67 IF (any(shape(s) /= [n, n]) .OR. any(shape(r) /= [n, n, 3]))
RETURN
68 IF (.NOT. all(ieee_is_finite([point, energy, kappa, matrix_tol, metric_tol, gap_tol])))
RETURN
69 IF (kappa <= 0.0_dp .OR. matrix_tol <= 0.0_dp .OR. matrix_tol >= 1.0_dp)
RETURN
70 IF (metric_tol <= 0.0_dp .OR. metric_tol >= 1.0_dp .OR. gap_tol < 0.0_dp)
RETURN
71 IF (.NOT. hermitian(h, matrix_tol) .OR. .NOT. hermitian(s, matrix_tol))
RETURN
73 IF (.NOT. hermitian(r(:, :, j), matrix_tol))
RETURN
76 IF (.NOT. self_dual(h, matrix_tol) .OR. .NOT. self_dual(s, matrix_tol))
RETURN
78 IF (.NOT. self_dual(r(:, :, j), matrix_tol))
RETURN
80 ALLOCATE (block(2*n, 2*n), shifted(n, n, 3))
82 shifted(:, :, j) = kappa*(r(:, :, j) - point(j)*s)
85 block(:n, :n) = h - energy*s - ii*shifted(:, :, 3)
86 block(n + 1:, n + 1:) = h - energy*s + ii*shifted(:, :, 3)
87 block(:n, n + 1:) = -ii*shifted(:, :, 1) - shifted(:, :, 2)
88 block(n + 1:, :n) = -ii*shifted(:, :, 1) + shifted(:, :, 2)
107 invariant, gap, metric_ratio, status)
108 COMPLEX(dp),
INTENT(IN) :: block(:, :), s(:, :)
109 REAL(
dp),
INTENT(IN) :: matrix_tol, metric_tol, gap_tol
110 INTEGER,
INTENT(OUT) :: invariant, status
111 REAL(
dp),
INTENT(OUT) :: gap, metric_ratio
112 COMPLEX(dp),
ALLOCATABLE :: pencil(:, :), metric(:, :)
114 REAL(
dp),
ALLOCATABLE :: real_block(:, :)
115 REAL(
dp) :: residual, scale, metric_scale, error_budget
116 INTEGER :: n, m, q, i, j, pi, pj, si, sj, signature, determinant
117#if defined(__HAS_IEEE_EXCEPTIONS)
118 LOGICAL :: halt(size(ieee_all))
124 metric_ratio = 0.0_dp
126 IF (n < 2 .OR. mod(n, 2) /= 0 .OR.
SIZE(s, 2) /= n)
RETURN
128 IF (any(shape(block) /= [m, m]))
RETURN
129 IF (.NOT. all(ieee_is_finite([matrix_tol, metric_tol, gap_tol])))
RETURN
130 IF (matrix_tol <= 0.0_dp .OR. matrix_tol >= 1.0_dp)
RETURN
131 IF (metric_tol <= 0.0_dp .OR. metric_tol >= 1.0_dp .OR. gap_tol < 0.0_dp)
RETURN
132 IF (.NOT. hermitian(s, matrix_tol))
RETURN
133 IF (.NOT. all(ieee_is_finite(real(block,
dp))) .OR. .NOT. all(ieee_is_finite(aimag(block))))
RETURN
135 IF (.NOT. self_dual(s, matrix_tol))
RETURN
136 ALLOCATE (real_block(m, m))
141 pj = (3 - (j - 1)/q)*q +
modulo(j - 1, q) + 1
142 sj = merge(1, -1, j <= q .OR. j > 3*q)
144 pi = (3 - (i - 1)/q)*q +
modulo(i - 1, q) + 1
145 si = merge(1, -1, i <= q .OR. i > 3*q)
146 value = 0.5_dp*(block(i, j) + si*sj*block(pi, pj) + &
147 cmplx(0.0_dp, 1.0_dp,
dp)*(si*block(pi, j) - sj*block(i, pj)))
148 residual = max(residual, abs(aimag(
value)))
149 real_block(i, j) = real(
value,
dp)
152 scale = max(tiny(1.0_dp), maxval(abs(block)))
153 IF (.NOT. all(ieee_is_finite(real_block)) .OR. .NOT. ieee_is_finite(residual))
RETURN
154 IF (residual > matrix_tol*scale)
RETURN
156 ALLOCATE (pencil(2*m, 2*m), metric(m, m))
158 pencil(:m, m + 1:) = block
159 pencil(m + 1:, :m) = conjg(transpose(block))
162 metric(n + 1:, n + 1:) = s
164 signature, gap, metric_ratio, status)
165 IF (status /= 0)
RETURN
167 IF (signature /= 0)
RETURN
169 metric_scale = metric_ratio*maxval(abs(s))
171 IF (gap <= real(m,
dp)*(residual + 100.0_dp*epsilon(1.0_dp)*scale)/metric_scale)
RETURN
172 DEALLOCATE (pencil, metric)
173 real_block = real_block/scale
175 error_budget = gap*metric_scale/scale - real(m,
dp)*(residual/scale + 100.0_dp*epsilon(1.0_dp))
176#if defined(__HAS_IEEE_EXCEPTIONS)
177 CALL ieee_get_halting_mode(ieee_all, halt)
178 CALL ieee_set_halting_mode(ieee_all, .false.)
180 CALL real_determinant_sign(real_block, error_budget, determinant, status)
181#if defined(__HAS_IEEE_EXCEPTIONS)
182 CALL ieee_set_halting_mode(ieee_all, halt)
184 IF (status /= 0)
RETURN
185 invariant = (1 - determinant)/2
197 SUBROUTINE real_determinant_sign(matrix, error_budget, determinant, status)
198 REAL(
dp),
INTENT(IN) :: matrix(:, :), error_budget
199 INTEGER,
INTENT(OUT) :: determinant, status
201 INTEGER :: i, info, method, n
202 INTEGER,
ALLOCATABLE :: pivots(:)
203 REAL(
dp) :: error, roundoff
204 REAL(
dp),
ALLOCATABLE :: factors(:, :), permuted(:, :), &
205 product(:, :), row(:), tau(:), work(:)
208 ALLOCATE (factors(n, n), product(n, n), permuted(n, n), row(n), pivots(n), tau(n), work(64*n))
212 factors(:, :) = matrix
213 permuted(:, :) = matrix
214 IF (method == 1)
THEN
215 CALL dgetrf(n, n, factors, n, pivots, info)
217 CALL dgeqrf(n, n, factors, n, tau, work,
SIZE(work), info)
219 IF (info /= 0 .OR. .NOT. all(ieee_is_finite(factors))) cycle
220 product(:, :) = factors
222 product(i + 1:, i) = 0.0_dp
225 roundoff = 8.0_dp*epsilon(1.0_dp)*real(n,
dp)*sqrt(sum(product**2))
226 IF (method == 1)
THEN
227 CALL dtrmm(
'L',
'L',
'N',
'U', n, n, 1.0_dp, factors, n, product, n)
229 row(:) = permuted(i, :)
230 permuted(i, :) = permuted(pivots(i), :)
231 permuted(pivots(i), :) = row
234 CALL dormqr(
'L',
'N', n, n, n, factors, n, tau, product, n, work,
SIZE(work), info)
237 IF (.NOT. all(ieee_is_finite(product))) cycle
238 error = sqrt(sum((product - permuted)**2))
239 IF (method == 1)
THEN
241 permuted(:, :) = abs(factors)
242 product(:, :) = permuted
244 product(i + 1:, i) = 0.0_dp
246 CALL dtrmm(
'L',
'L',
'N',
'U', n, n, 1.0_dp, permuted, n, product, n)
247 roundoff = 8.0_dp*epsilon(1.0_dp)*real(n,
dp)*sqrt(sum(product**2))
249 error = error + roundoff
251 IF (.NOT. ieee_is_finite(error) .OR. error >= error_budget) cycle
254 IF (factors(i, i) == 0.0_dp)
EXIT
255 IF (factors(i, i) < 0.0_dp) determinant = -determinant
256 IF (method == 1)
THEN
257 IF (pivots(i) /= i) determinant = -determinant
259 IF (tau(i) /= 0.0_dp) determinant = -determinant
267 END SUBROUTINE real_determinant_sign
291 matrix_tol, metric_tol, gap_tol, invariant, gap, metric_ratio, status)
292 COMPLEX(dp),
INTENT(IN) :: h(:, :), s(:, :), cosine(:, :, :), &
294 REAL(
dp),
INTENT(IN) :: origin(2), energy, eta
295 LOGICAL,
INTENT(IN) :: aii
296 REAL(
dp),
INTENT(IN) :: matrix_tol, metric_tol, gap_tol
297 INTEGER,
INTENT(OUT) :: invariant
298 REAL(
dp),
INTENT(OUT) :: gap, metric_ratio
299 INTEGER,
INTENT(OUT) :: status
301 COMPLEX(dp),
ALLOCATABLE :: l(:, :), mass(:, :), &
302 shifted_sine(:, :, :)
308 metric_ratio = 0.0_dp
310 IF (n < 1 .OR.
SIZE(h, 2) /= n)
RETURN
311 IF (any(shape(s) /= [n, n]))
RETURN
312 IF (any(shape(cosine) /= [n, n, 2]) .OR. any(shape(sine) /= [n, n, 2]))
RETURN
313 IF (.NOT. all(ieee_is_finite([origin, energy, eta, matrix_tol])))
RETURN
314 IF (eta <= 0.0_dp .OR. matrix_tol <= 0.0_dp .OR. matrix_tol >= 1.0_dp)
RETURN
315 IF (.NOT. hermitian(h, matrix_tol) .OR. .NOT. hermitian(s, matrix_tol))
RETURN
317 IF (.NOT. hermitian(cosine(:, :, j), matrix_tol))
RETURN
318 IF (.NOT. hermitian(sine(:, :, j), matrix_tol))
RETURN
322 IF (mod(n, 2) /= 0)
RETURN
323 IF (.NOT. self_dual(h, matrix_tol) .OR. .NOT. self_dual(s, matrix_tol))
RETURN
325 IF (.NOT. self_dual(cosine(:, :, j), matrix_tol))
RETURN
326 IF (.NOT. self_dual(sine(:, :, j), matrix_tol))
RETURN
329 ALLOCATE (mass(n, n), shifted_sine(n, n, 2), l(2*n, 2*n))
330 mass(:, :) = h - energy*s
332 mass(:, :) = mass - eta*(s - cos(origin(j))*cosine(:, :, j) - sin(origin(j))*sine(:, :, j))
333 shifted_sine(:, :, j) = eta*(cos(origin(j))*sine(:, :, j) - sin(origin(j))*cosine(:, :, j))
336 l(n + 1:, n + 1:) = -mass
337 l(:n, n + 1:) = shifted_sine(:, :, 1) - cmplx(0.0_dp, 1.0_dp,
dp)*shifted_sine(:, :, 2)
338 l(n + 1:, :n) = conjg(transpose(l(:n, n + 1:)))
340 invariant, gap, metric_ratio, status)
363 gap_tol, invariant, gap, metric_ratio, status)
364 COMPLEX(KIND=dp),
INTENT(IN) :: h(:, :), s(:, :), r(:, :, :)
365 REAL(kind=
dp),
INTENT(IN) :: point(2), energy, kappa
366 LOGICAL,
INTENT(IN) :: aii
367 REAL(kind=
dp),
INTENT(IN) :: matrix_tol, metric_tol, gap_tol
368 INTEGER,
INTENT(OUT) :: invariant
369 REAL(kind=
dp),
INTENT(OUT) :: gap, metric_ratio
370 INTEGER,
INTENT(OUT) :: status
372 COMPLEX(KIND=dp),
ALLOCATABLE :: localizer(:, :)
378 metric_ratio = 0.0_dp
380 IF (n < 1 .OR.
SIZE(h, 2) /= n)
RETURN
381 IF (any(shape(s) /= [n, n]) .OR. any(shape(r) /= [n, n, 2]))
RETURN
382 IF (.NOT. all(ieee_is_finite([point, energy, kappa, matrix_tol, metric_tol, gap_tol])))
RETURN
383 IF (kappa <= 0.0_dp .OR. matrix_tol <= 0.0_dp .OR. matrix_tol >= 1.0_dp)
RETURN
384 IF (metric_tol <= 0.0_dp .OR. metric_tol >= 1.0_dp .OR. gap_tol < 0.0_dp)
RETURN
385 IF (.NOT. hermitian(h, matrix_tol) .OR. .NOT. hermitian(s, matrix_tol))
RETURN
387 IF (.NOT. hermitian(r(:, :, i), matrix_tol))
RETURN
391 IF (mod(n, 2) /= 0)
RETURN
392 IF (.NOT. self_dual(h, matrix_tol) .OR. .NOT. self_dual(s, matrix_tol))
RETURN
394 IF (.NOT. self_dual(r(:, :, i), matrix_tol))
RETURN
398 ALLOCATE (localizer(2*n, 2*n))
399 localizer(:n, :n) = h - energy*s
400 localizer(n + 1:, n + 1:) = -localizer(:n, :n)
401 localizer(:n, n + 1:) = kappa*((r(:, :, 1) - point(1)*s) - &
402 cmplx(0.0_dp, 1.0_dp,
dp)*(r(:, :, 2) - point(2)*s))
403 localizer(n + 1:, :n) = conjg(transpose(localizer(:n, n + 1:)))
405 invariant, gap, metric_ratio, status)
422 invariant, gap, metric_ratio, status)
423 COMPLEX(KIND=dp),
INTENT(IN) :: localizer(:, :), s(:, :)
424 LOGICAL,
INTENT(IN) :: aii
425 REAL(kind=
dp),
INTENT(IN) :: matrix_tol, metric_tol, gap_tol
426 INTEGER,
INTENT(OUT) :: invariant, status
427 REAL(kind=
dp),
INTENT(OUT) :: gap, metric_ratio
429 COMPLEX(KIND=dp),
ALLOCATABLE :: a(:, :), b(:, :), work(:)
430 INTEGER :: info, n, negative, pf, pf_reference, &
431 positive, ldl_positive, ldl_negative
432#if defined(__HAS_IEEE_EXCEPTIONS)
433 LOGICAL :: halt(size(ieee_all))
435 REAL(kind=
dp) :: metric_min, residual, threshold
436 REAL(kind=
dp),
ALLOCATABLE :: eigenvalues(:), rwork(:), skew(:, :)
441 metric_ratio = 0.0_dp
443 IF (n < 1 .OR.
SIZE(s, 2) /= n)
RETURN
444 IF (any(shape(localizer) /= [2*n, 2*n]))
RETURN
445 IF (.NOT. all(ieee_is_finite([matrix_tol, metric_tol, gap_tol])))
RETURN
446 IF (matrix_tol <= 0.0_dp .OR. matrix_tol >= 1.0_dp)
RETURN
447 IF (metric_tol <= 0.0_dp .OR. metric_tol >= 1.0_dp .OR. gap_tol < 0.0_dp)
RETURN
448 IF (.NOT. hermitian(s, matrix_tol) .OR. .NOT. hermitian(localizer, matrix_tol))
RETURN
451 IF (mod(n, 2) /= 0)
RETURN
452 IF (.NOT. self_dual(s, matrix_tol))
RETURN
455 ALLOCATE (a(n, n), eigenvalues(n), work(max(1, 2*n)), rwork(max(1, 3*n)))
458#if defined(__HAS_IEEE_EXCEPTIONS)
459 CALL ieee_get_halting_mode(ieee_all, halt)
460 CALL ieee_set_halting_mode(ieee_all, .false.)
462 CALL zheev(
'N',
'U', n, a, n, eigenvalues, work,
SIZE(work), rwork, info)
463#if defined(__HAS_IEEE_EXCEPTIONS)
464 CALL ieee_set_halting_mode(ieee_all, halt)
466 status = abs(info) + 2
467 IF (info /= 0 .OR. .NOT. all(ieee_is_finite(eigenvalues)))
RETURN
469 IF (maxval(eigenvalues) <= 0.0_dp)
RETURN
470 metric_ratio = minval(eigenvalues)/maxval(eigenvalues)
471 IF (metric_ratio <= metric_tol)
RETURN
472 metric_min = minval(eigenvalues)
473 DEALLOCATE (a, eigenvalues, work, rwork)
475 ALLOCATE (a(2*n, 2*n), b(2*n, 2*n))
476 ALLOCATE (eigenvalues(2*n), work(4*n), rwork(6*n))
478 IF (.NOT. all(ieee_is_finite(real(localizer,
dp))) .OR. &
479 .NOT. all(ieee_is_finite(aimag(localizer))))
RETURN
481 b(:, :) = cmplx(0.0_dp, 0.0_dp,
dp)
483 b(n + 1:, n + 1:) = s
485#if defined(__HAS_IEEE_EXCEPTIONS)
486 CALL ieee_get_halting_mode(ieee_all, halt)
487 CALL ieee_set_halting_mode(ieee_all, .false.)
489 CALL zhegv(1,
'N',
'U', 2*n, a, 2*n, b, 2*n, eigenvalues, work,
SIZE(work), rwork, info)
490#if defined(__HAS_IEEE_EXCEPTIONS)
491 CALL ieee_set_halting_mode(ieee_all, halt)
493 status = abs(info) + 2
494 IF (info /= 0 .OR. .NOT. all(ieee_is_finite(eigenvalues)))
RETURN
495 gap = minval(abs(eigenvalues))
497 residual = real(2*n,
dp)*maxval(abs(localizer - conjg(transpose(localizer))))/metric_min + &
498 REAL(n,
dp)*maxval(abs(eigenvalues))*maxval(abs(s - conjg(transpose(s))))/metric_min
499 threshold = max(gap_tol, residual + 100.0_dp*epsilon(1.0_dp)*real(2*n,
dp)* &
500 max(maxval(abs(eigenvalues)), maxval(abs(localizer))/metric_min))
502 IF (gap <= threshold)
RETURN
503 positive = count(eigenvalues > threshold)
504 negative = count(eigenvalues < -threshold)
507 IF (info /= 0)
RETURN
508 IF (positive /= ldl_positive .OR. negative /= ldl_negative)
RETURN
510 invariant = (ldl_positive - ldl_negative)/2
513 IF (positive /= negative)
RETURN
514 ALLOCATE (skew(2*n, 2*n))
516 IF (info /= 0)
RETURN
518 IF (gap <= threshold + real(2*n,
dp)*residual/metric_min)
RETURN
521 IF (info /= 0)
RETURN
523 a(:, :) = cmplx(0.0_dp, 0.0_dp,
dp)
525 a(n + 1:, n + 1:) = -s
527 IF (info /= 0)
RETURN
528 IF (real(2*n,
dp)*residual >= metric_min)
RETURN
530 IF (info /= 0)
RETURN
531 invariant = (1 - pf*pf_reference)/2
544 SUBROUTINE localizer_inertia_complex(matrix, positive, negative, status)
545 COMPLEX(KIND=dp),
INTENT(IN) :: matrix(:, :)
546 INTEGER,
INTENT(OUT) :: positive, negative, status
548 COMPLEX(KIND=dp),
ALLOCATABLE :: a(:, :), work(:)
549 INTEGER :: i, info, n
550 INTEGER,
ALLOCATABLE :: pivots(:)
551 REAL(KIND=
dp) :: scale
552#if defined(__HAS_IEEE_EXCEPTIONS)
553 LOGICAL :: halt(SIZE(IEEE_ALL))
560 IF (n < 1 .OR.
SIZE(matrix, 2) /= n)
RETURN
561 IF (.NOT. hermitian(matrix, 1.e-10_dp))
RETURN
563 IF (all(aimag(matrix) == 0.0_dp))
THEN
564 CALL localizer_inertia_real(real(matrix,
dp), positive, negative, status)
567 scale = maxval(abs(matrix))
569 IF (scale <= tiny(1.0_dp))
RETURN
570 ALLOCATE (a(n, n), pivots(n), work(max(1, 64*n)))
571 a(:, :) = matrix/scale
572#if defined(__HAS_IEEE_EXCEPTIONS)
573 CALL ieee_get_halting_mode(ieee_all, halt)
574 CALL ieee_set_halting_mode(ieee_all, .false.)
576 CALL zhetrf(
'L', n, a, n, pivots, work,
SIZE(work), info)
577#if defined(__HAS_IEEE_EXCEPTIONS)
578 CALL ieee_set_halting_mode(ieee_all, halt)
583 IF (.NOT. all(ieee_is_finite(real(a,
dp))) .OR. .NOT. all(ieee_is_finite(aimag(a))))
RETURN
584 CALL block_inertia([(real(a(i, i),
dp), i=1, n)], [(abs(a(i + 1, i)), i=1, n - 1)], &
585 pivots, positive, negative, status)
586 END SUBROUTINE localizer_inertia_complex
595 SUBROUTINE localizer_inertia_real(matrix, positive, negative, status)
596 REAL(dp),
INTENT(IN) :: matrix(:, :)
597 INTEGER,
INTENT(OUT) :: positive, negative, status
598 REAL(dp),
ALLOCATABLE :: a(:, :), work(:)
599 INTEGER,
ALLOCATABLE :: pivots(:)
600 INTEGER :: i, info, n
602#if defined(__HAS_IEEE_EXCEPTIONS)
603 LOGICAL :: halt(SIZE(IEEE_ALL))
610 IF (n < 1 .OR.
SIZE(matrix, 2) /= n)
RETURN
611 IF (.NOT. all(ieee_is_finite(matrix)))
RETURN
612 scale = maxval(abs(matrix))
613 IF (maxval(abs(matrix - transpose(matrix))) > 1.e-10_dp*max(tiny(1.0_dp), scale))
RETURN
615 IF (scale <= tiny(1.0_dp))
RETURN
616 ALLOCATE (a(n, n), pivots(n), work(max(1, 64*n)))
617 a(:, :) = matrix/scale
618#if defined(__HAS_IEEE_EXCEPTIONS)
619 CALL ieee_get_halting_mode(ieee_all, halt)
620 CALL ieee_set_halting_mode(ieee_all, .false.)
622 CALL dsytrf(
'L', n, a, n, pivots, work,
SIZE(work), info)
623#if defined(__HAS_IEEE_EXCEPTIONS)
624 CALL ieee_set_halting_mode(ieee_all, halt)
628 IF (info < 0 .OR. .NOT. all(ieee_is_finite(a)))
RETURN
629 CALL block_inertia([(a(i, i), i=1, n)], [(abs(a(i + 1, i)), i=1, n - 1)], &
630 pivots, positive, negative, status)
631 END SUBROUTINE localizer_inertia_real
643 SUBROUTINE block_inertia(diagonal, coupling, pivots, positive, negative, status)
644 REAL(dp),
INTENT(IN) :: diagonal(:), coupling(:)
645 INTEGER,
INTENT(IN) :: pivots(:)
646 INTEGER,
INTENT(OUT) :: positive, negative, status
649 REAL(dp) :: values(2)
651 SUBROUTINE dlae2(a, b, c, rt1, rt2)
653 REAL(dp),
INTENT(IN) :: a, b, c
654 REAL(dp),
INTENT(OUT) :: rt1, rt2
664 IF (pivots(i) == 0)
RETURN
665 IF (pivots(i) > 0)
THEN
666 values = [diagonal(i), 0.0_dp]
667 IF (values(1) == 0.0_dp)
THEN
674 IF (pivots(i + 1) /= pivots(i))
RETURN
676 CALL dlae2(diagonal(i), coupling(i), diagonal(i + 1), values(1), values(2))
677 IF (any(values == 0.0_dp))
THEN
683 positive = positive + count(values > 0.0_dp)
684 negative = negative + count(values < 0.0_dp)
687 END SUBROUTINE block_inertia
695 LOGICAL FUNCTION hermitian(a, tolerance)
696 COMPLEX(KIND=dp),
INTENT(IN) :: a(:, :)
697 REAL(KIND=
dp),
INTENT(IN) :: tolerance
700 IF (.NOT. all(ieee_is_finite(real(a,
dp))) .OR. .NOT. all(ieee_is_finite(aimag(a))))
RETURN
701 hermitian = maxval(abs(a - conjg(transpose(a)))) <= tolerance*max(tiny(1.0_dp), maxval(abs(a)))
702 END FUNCTION hermitian
710 LOGICAL FUNCTION self_dual(a, tolerance)
711 COMPLEX(KIND=dp),
INTENT(IN) :: a(:, :)
712 REAL(KIND=
dp),
INTENT(IN) :: tolerance
715 REAL(KIND=
dp) :: scale
718 scale = max(tiny(1.0_dp), maxval(abs(a)))
719 self_dual = maxval(abs(a(:n, :n) - conjg(a(n + 1:, n + 1:)))) <= tolerance*scale .AND. &
720 maxval(abs(a(:n, n + 1:) + conjg(a(n + 1:, :n)))) <= tolerance*scale
721 END FUNCTION self_dual
732 COMPLEX(KIND=dp),
INTENT(IN) :: localizer(:, :)
733 REAL(kind=
dp),
INTENT(OUT) :: skew(:, :)
734 REAL(kind=
dp),
INTENT(IN) :: tolerance
735 REAL(kind=
dp),
INTENT(OUT) :: residual
736 INTEGER,
INTENT(OUT) :: status
738 COMPLEX(KIND=dp) :: value
739 INTEGER :: i, j, m, n, pi, pj, si, sj
740 REAL(kind=
dp) :: antisymmetric, scale, skew_residual
742 m =
SIZE(localizer, 1)
744 residual = huge(1.0_dp)
745 IF (m < 4 .OR. mod(m, 4) /= 0)
RETURN
746 IF (
SIZE(localizer, 2) /= m .OR. any(shape(skew) /= [m, m]))
RETURN
747 IF (.NOT. ieee_is_finite(tolerance))
RETURN
748 IF (tolerance <= 0.0_dp .OR. tolerance >= 1.0_dp)
RETURN
749 IF (.NOT. all(ieee_is_finite(real(localizer,
dp))) .OR. &
750 .NOT. all(ieee_is_finite(aimag(localizer))))
RETURN
755 pj = (3 - (j - 1)/n)*n +
modulo(j - 1, n) + 1
756 sj = merge(1, -1, j <= n .OR. j > 3*n)
758 pi = (3 - (i - 1)/n)*n +
modulo(i - 1, n) + 1
759 si = merge(1, -1, i <= n .OR. i > 3*n)
760 value = 0.5_dp*(localizer(i, j) + si*sj*localizer(pi, pj) + &
761 cmplx(0.0_dp, 1.0_dp,
dp)*(si*localizer(pi, j) - sj*localizer(i, pj)))
762 IF (.NOT. ieee_is_finite(real(
value,
dp)) .OR. .NOT. ieee_is_finite(aimag(
value)))
THEN
763 residual = huge(1.0_dp)
766 residual = max(residual, abs(real(
value,
dp)))
767 skew(i, j) = -aimag(
value)
770 scale = max(tiny(1.0_dp), maxval(abs(localizer)))
771 IF (residual > tolerance*scale)
RETURN
772 skew_residual = 0.0_dp
775 skew_residual = max(skew_residual, abs(0.5_dp*skew(i, j) + 0.5_dp*skew(j, i)))
778 IF (skew_residual > 0.5_dp*tolerance*scale)
RETURN
780 residual = residual + skew_residual
783 antisymmetric = 0.5_dp*skew(i, j) - 0.5_dp*skew(j, i)
784 skew(i, j) = antisymmetric
785 skew(j, i) = -antisymmetric
799 REAL(kind=
dp),
INTENT(IN) :: matrix(:, :)
800 INTEGER,
INTENT(OUT) :: pf_sign, status
802 INTEGER :: i, j, k, n, p, sign_accum
803 REAL(kind=
dp) :: pivot, scale
804 REAL(kind=
dp),
ALLOCATABLE :: a(:, :), row(:)
809 IF (n < 2 .OR. mod(n, 2) /= 0 .OR.
SIZE(matrix, 2) /= n)
RETURN
810 IF (.NOT. all(ieee_is_finite(matrix)))
RETURN
811 scale = maxval(abs(matrix))
812 IF (maxval(abs(matrix + transpose(matrix))) > 100.0_dp*epsilon(1.0_dp)*scale)
RETURN
814 IF (scale <= tiny(1.0_dp))
RETURN
815 ALLOCATE (a(n, n), row(n))
816 a(:, :) = matrix/scale
819 p = k + maxloc(abs(a(k, k + 1:)), dim=1)
822 a(k + 1, :) = a(p, :)
825 a(:, k + 1) = a(:, p)
827 sign_accum = -sign_accum
830 IF (abs(pivot) <= 100.0_dp*epsilon(1.0_dp)*maxval(abs(a(k:, k:))))
RETURN
831 IF (pivot < 0.0_dp) sign_accum = -sign_accum
834 a(i, j) = a(i, j) + (a(k + 1, i)*a(k, j) - a(k, i)*a(k + 1, j))/pivot
838 IF (.NOT. all(ieee_is_finite(a(k:, k:))))
RETURN
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
Defines the basic variable types.
integer, parameter, public dp
Dense reference spectral localizers in a nonorthogonal finite basis.
subroutine, public localizer_matrix_evaluate(localizer, s, aii, matrix_tol, metric_tol, gap_tol, invariant, gap, metric_ratio, status)
Dense reference evaluation of an assembled localizer with metric diag(S,S).
subroutine, public localizer_3d_evaluate(h, s, r, point, energy, kappa, matrix_tol, metric_tol, gap_tol, invariant, gap, metric_ratio, status)
Finite three-dimensional class AII localizer, using all three Cartesian moments.
subroutine, public localizer_aii_skew(localizer, skew, tolerance, residual, status)
Convert the class AII localizer to a real skew matrix using Q=(I-i C)/sqrt(2).
subroutine, public localizer_3d_matrix_evaluate(block, s, matrix_tol, metric_tol, gap_tol, invariant, gap, metric_ratio, status)
Metric gap and real determinant sign of a three-dimensional AII chiral block.
subroutine, public localizer_periodic_evaluate(h, s, cosine, sine, origin, energy, eta, aii, matrix_tol, metric_tol, gap_tol, invariant, gap, metric_ratio, status)
Two-dimensional periodic localizer from covariant trigonometric position operators.
subroutine, public localizer_pfaffian_sign(matrix, pf_sign, status)
Dense pivoted skew elimination, accumulating only the sign of the Pfaffian.
subroutine, public localizer_evaluate(h, s, r, point, energy, kappa, aii, matrix_tol, metric_tol, gap_tol, invariant, gap, metric_ratio, status)
Evaluate the 2D class A or AII localizer without projecting onto occupied states.