Skip to content

Commit 921ba4b

Browse files
refactor: use uplo/optval, add error tests
1 parent a90185b commit 921ba4b

2 files changed

Lines changed: 67 additions & 16 deletions

File tree

src/linalg/stdlib_linalg_solve.fypp

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ submodule (stdlib_linalg) stdlib_linalg_solve
165165
! Local variables
166166
type(linalg_state_type) :: err0
167167
integer(ilp) :: lda,n,ldb,ldx,nrhs,nrhsx,info
168-
character :: triangle
168+
character :: uplo
169169
${rt}$, pointer :: xmat(:,:)
170170

171171
! Problem sizes
@@ -176,8 +176,8 @@ submodule (stdlib_linalg) stdlib_linalg_solve
176176
ldx = size(x,1,kind=ilp)
177177
nrhsx = size(x,kind=ilp)/ldx
178178

179-
! Set triangle based on lower flag (REQUIRED argument)
180-
triangle = merge('L','U',lower)
179+
! Set uplo based on lower flag (REQUIRED argument)
180+
uplo = merge('L','U',lower)
181181

182182
! Validate dimensions
183183
if (any([lda,n,ldb]<1) .or. any([lda,ldb,ldx]/=n) .or. nrhsx/=nrhs) then
@@ -194,10 +194,10 @@ submodule (stdlib_linalg) stdlib_linalg_solve
194194
xmat(1:n,1:nrhs) => x
195195

196196
! Solve the system using LAPACK POTRS
197-
call potrs(triangle,n,nrhs,a,lda,xmat,n,info)
197+
call potrs(uplo,n,nrhs,a,lda,xmat,n,info)
198198

199199
! Handle errors using standard handler
200-
call handle_potrs_info(this,info,triangle,n,nrhs,lda,n,err0)
200+
call handle_potrs_info(this,info,uplo,n,nrhs,lda,n,err0)
201201

202202
! Process output and return
203203
call linalg_error_handling(err0,err)
@@ -232,7 +232,7 @@ submodule (stdlib_linalg) stdlib_linalg_solve
232232
type(linalg_state_type) :: err0
233233
integer(ilp) :: lda,n,ldb,ldx,nrhs,nrhsx,info
234234
logical(lk) :: lower_,copy_a
235-
character :: triangle
235+
character :: uplo
236236
${rt}$, pointer :: xmat(:,:),amat(:,:)
237237

238238
! Problem sizes
@@ -244,16 +244,11 @@ submodule (stdlib_linalg) stdlib_linalg_solve
244244
nrhsx = size(x,kind=ilp)/ldx
245245

246246
! Default: use lower triangular
247-
lower_ = .true._lk
248-
if (present(lower)) lower_ = lower
249-
triangle = merge('L','U',lower_)
247+
lower_ = optval(lower, .true._lk)
248+
uplo = merge('L','U',lower_)
250249

251250
! Can A be overwritten? By default, do not overwrite
252-
if (present(overwrite_a)) then
253-
copy_a = .not.overwrite_a
254-
else
255-
copy_a = .true._lk
256-
endif
251+
copy_a = .not. optval(overwrite_a, .false._lk)
257252

258253
! Validate dimensions
259254
if (any([lda,n,ldb]<1) .or. any([lda,ldb,ldx]/=n) .or. nrhsx/=nrhs) then
@@ -277,10 +272,10 @@ submodule (stdlib_linalg) stdlib_linalg_solve
277272
xmat(1:n,1:nrhs) => x
278273

279274
! Factorize AND solve using LAPACK POSV
280-
call posv(triangle,n,nrhs,amat,lda,xmat,n,info)
275+
call posv(uplo,n,nrhs,amat,lda,xmat,n,info)
281276

282277
! Handle errors using standard handler
283-
call handle_posv_info(this,info,triangle,n,nrhs,lda,n,err0)
278+
call handle_posv_info(this,info,uplo,n,nrhs,lda,n,err0)
284279

285280
if (copy_a) deallocate(amat)
286281

test/linalg/test_linalg_solve_chol.fypp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ module test_linalg_solve_chol
2828
call add_test(tests,new_unittest("cholesky_solve_upper_${ri}$",test_cholesky_solve_upper_${ri}$))
2929
call add_test(tests,new_unittest("cholesky_solve_overwrite_${ri}$",test_cholesky_solve_overwrite_${ri}$))
3030
call add_test(tests,new_unittest("solve_chol_multi_rhs_${ri}$",test_solve_chol_multi_rhs_${ri}$))
31+
call add_test(tests,new_unittest("cholesky_solve_indefinite_${ri}$",test_cholesky_solve_indefinite_${ri}$))
32+
call add_test(tests,new_unittest("cholesky_solve_semidefinite_${ri}$",test_cholesky_solve_semidefinite_${ri}$))
3133
#:endfor
3234

3335
end subroutine test_solve_chol_factorization
@@ -277,6 +279,60 @@ module test_linalg_solve_chol
277279

278280
#:endfor
279281

282+
!> Test cholesky_solve with symmetric indefinite matrix (should fail)
283+
#:for rk,rt,ri in RC_KINDS_TYPES
284+
subroutine test_cholesky_solve_indefinite_${ri}$(error)
285+
type(error_type), allocatable, intent(out) :: error
286+
287+
integer(ilp), parameter :: n = 2_ilp
288+
${rt}$ :: a(n,n), b(n), x(n)
289+
type(linalg_state_type) :: state
290+
291+
! Set symmetric INDEFINITE matrix (eigenvalues: 3, -1)
292+
a(1,:) = [1, 2]
293+
a(2,:) = [2, 1]
294+
295+
! Arbitrary RHS
296+
b = [1, 1]
297+
298+
! cholesky_solve should fail for indefinite matrix
299+
call cholesky_solve(a, b, x, lower=.true., err=state)
300+
301+
! Check that it failed (not positive definite)
302+
call check(error, state%error(), 'cholesky_solve should fail for indefinite matrix')
303+
if (allocated(error)) return
304+
305+
end subroutine test_cholesky_solve_indefinite_${ri}$
306+
307+
#:endfor
308+
309+
!> Test cholesky_solve with symmetric positive semi-definite matrix (should fail)
310+
#:for rk,rt,ri in RC_KINDS_TYPES
311+
subroutine test_cholesky_solve_semidefinite_${ri}$(error)
312+
type(error_type), allocatable, intent(out) :: error
313+
314+
integer(ilp), parameter :: n = 2_ilp
315+
${rt}$ :: a(n,n), b(n), x(n)
316+
type(linalg_state_type) :: state
317+
318+
! Set symmetric positive SEMI-DEFINITE matrix (eigenvalues: 2, 0 - singular)
319+
a(1,:) = [1, 1]
320+
a(2,:) = [1, 1]
321+
322+
! Arbitrary RHS
323+
b = [1, 1]
324+
325+
! cholesky_solve should fail for semi-definite (singular) matrix
326+
call cholesky_solve(a, b, x, lower=.true., err=state)
327+
328+
! Check that it failed (not strictly positive definite)
329+
call check(error, state%error(), 'cholesky_solve should fail for positive semi-definite matrix')
330+
if (allocated(error)) return
331+
332+
end subroutine test_cholesky_solve_semidefinite_${ri}$
333+
334+
#:endfor
335+
280336
! gcc-15 bugfix utility
281337
subroutine add_test(tests,new_test)
282338
type(unittest_type), allocatable, intent(inout) :: tests(:)

0 commit comments

Comments
 (0)