@@ -24,7 +24,8 @@ module test_linalg_inverse
24
24
#:for rk,rt,ri in RC_KINDS_TYPES
25
25
#:if rk!="xdp"
26
26
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)]
28
29
#:endif
29
30
#:endfor
30
31
@@ -91,7 +92,53 @@ module test_linalg_inverse
91
92
if (allocated(error)) return
92
93
93
94
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}$
94
114
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
+
95
142
#:endif
96
143
#:endfor
97
144
@@ -160,6 +207,76 @@ module test_linalg_inverse
160
207
161
208
end subroutine test_${ci}$_eye_inverse
162
209
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
+
163
280
!> Invert singular matrix
164
281
subroutine test_${ci}$_singular_inverse(error)
165
282
type(error_type), allocatable, intent(out) :: error
0 commit comments