Skip to content

Commit 80a7742

Browse files
committed
new test: random SPD matrix (real, complex)
1 parent 513d77b commit 80a7742

File tree

1 file changed

+118
-1
lines changed

1 file changed

+118
-1
lines changed

test/linalg/test_linalg_inverse.fypp

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ module test_linalg_inverse
2424
#:for rk,rt,ri in RC_KINDS_TYPES
2525
#:if rk!="xdp"
2626
tests = [tests,new_unittest("${ri}$_eye_inverse",test_${ri}$_eye_inverse), &
27-
new_unittest("${ri}$_singular_inverse",test_${ri}$_singular_inverse)]
27+
new_unittest("${ri}$_singular_inverse",test_${ri}$_singular_inverse), &
28+
new_unittest("${ri}$_random_spd_inverse",test_${ri}$_random_spd_inverse)]
2829
#:endif
2930
#:endfor
3031

@@ -91,7 +92,53 @@ module test_linalg_inverse
9192
if (allocated(error)) return
9293

9394
end subroutine test_${ri}$_singular_inverse
95+
96+
!> Create a random symmetric positive definite matrix
97+
function random_spd_matrix_${ri}$(n) result(A)
98+
integer(ilp), intent(in) :: n
99+
${rt}$ :: A(n,n)
100+
101+
${rt}$, parameter :: one = 1.0_${rk}$
102+
${rt}$, parameter :: half = 0.5_${rk}$
103+
104+
!> Initialize with randoms
105+
call random_number(A)
106+
107+
!> Make symmetric
108+
A = half*(A+transpose(A))
109+
110+
!> Add diagonally dominant part
111+
A = A + n*eye(n)
112+
113+
end function random_spd_matrix_${ri}$
94114

115+
!> Test random symmetric positive-definite matrix
116+
subroutine test_${ri}$_random_spd_inverse(error)
117+
type(error_type), allocatable, intent(out) :: error
118+
119+
!> Solution tolerance
120+
${rt}$, parameter :: tol = sqrt(epsilon(0.0_${rk}$))
121+
122+
!> Local variables
123+
integer(ilp), parameter :: n = 5_ilp
124+
type(linalg_state_type) :: state
125+
${rt}$ :: A(n,n),Am1(n,n)
126+
127+
!> Generate random SPD matrix
128+
A = random_spd_matrix_${ri}$(n)
129+
130+
!> Invert matrix
131+
call invert(A,Am1,err=state)
132+
133+
!> Check result
134+
call check(error,state%ok(),'random SPD matrix (${rk}$): '//state%print())
135+
if (allocated(error)) return
136+
137+
call check(error,all(abs(matmul(Am1,A)-eye(n))<tol),'random SPD matrix (${rk}$): accuracy test')
138+
if (allocated(error)) return
139+
140+
end subroutine test_${ri}$_random_spd_inverse
141+
95142
#:endif
96143
#:endfor
97144

@@ -160,6 +207,76 @@ module test_linalg_inverse
160207

161208
end subroutine test_${ci}$_eye_inverse
162209

210+
!> Create a random symmetric positive definite matrix
211+
function random_spd_matrix_${ci}$(n) result(A)
212+
integer(ilp), intent(in) :: n
213+
${ct}$ :: A(n,n)
214+
215+
${ct}$, parameter :: half = (0.5_${ck}$,0.0_${ck}$)
216+
real(${ck}$) :: reA(n,n),imA(n,n)
217+
integer(ilp) :: i
218+
219+
!> Initialize with randoms
220+
call random_number(reA)
221+
call random_number(imA)
222+
223+
A = cmplx(reA,imA,kind=${ck}$)
224+
225+
!> Make symmetric
226+
A = half*(A+transpose(A))
227+
228+
!> Add diagonally dominant part
229+
forall(i=1:n) A(i,i) = A(i,i) + n*(1.0_${ck}$,0.0_${ck}$)
230+
231+
end function random_spd_matrix_${ci}$
232+
233+
!> Test random symmetric positive-definite matrix
234+
subroutine test_${ci}$_random_spd_inverse(error)
235+
type(error_type), allocatable, intent(out) :: error
236+
237+
!> Local variables
238+
integer(ilp) :: failed,i,j
239+
integer(ilp), parameter :: n = 5_ilp
240+
type(linalg_state_type) :: state
241+
${ct}$ :: A(n,n),Am1(n,n),AA(n,n)
242+
243+
!> Generate random SPD matrix
244+
A = random_spd_matrix_${ci}$(n)
245+
246+
!> Invert matrix
247+
call invert(A,Am1,err=state)
248+
249+
!> Check result
250+
call check(error,state%ok(),'random complex SPD matrix (${ck}$): '//state%print())
251+
if (allocated(error)) return
252+
253+
failed = 0
254+
AA = matmul(A,Am1)
255+
do i=1,n
256+
do j=1,n
257+
if (.not.is_complex_inverse(AA(i,j),i,j)) failed = failed+1
258+
end do
259+
end do
260+
261+
call check(error,failed==0,'inverse_${ci}$_eye (subroutine): data converged')
262+
if (allocated(error)) return
263+
264+
contains
265+
266+
elemental logical function is_complex_inverse(aij,i,j)
267+
${ct}$, intent(in) :: aij
268+
integer(ilp), intent(in) :: i,j
269+
real(${ck}$), parameter :: tol = sqrt(epsilon(0.0_${ck}$))
270+
if (i/=j) then
271+
is_complex_inverse = abs(aij)<tol
272+
else
273+
! Product should return the real identity
274+
is_complex_inverse = abs(aij - (1.0_${ck}$,0.0_${ck}$))<tol
275+
endif
276+
end function is_complex_inverse
277+
278+
end subroutine test_${ci}$_random_spd_inverse
279+
163280
!> Invert singular matrix
164281
subroutine test_${ci}$_singular_inverse(error)
165282
type(error_type), allocatable, intent(out) :: error

0 commit comments

Comments
 (0)