Skip to content

Commit 106bf23

Browse files
committed
implement 2-norm maxval(svdvals(a))
1 parent a47f478 commit 106bf23

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

doc/specs/stdlib_linalg.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,7 @@ matrix norms are computed over specified dimensions.
15901590
| Integer input | Character Input | Norm type |
15911591
|------------------|---------------------------|---------------------------------------------------------|
15921592
| `1` | `'1'` | 1-norm (maximum column sum) \( \max_j \sum_i{ \left|a_{i,j}\right| } \) |
1593+
| `2` | `'2'` | 2-norm (largest singular value) |
15931594
| (not prov.) | `'Euclidean','Frobenius','Fro'` | Frobenius norm \( \sqrt{\sum_{i,j}{ \left|a_{i,j}\right|^2 }} \) |
15941595
| `huge(0)` | `'inf', 'Inf', 'INF'` | Infinity norm (maximum row sum) \( \max_i \sum_j{ \left|a_{i,j}\right| } \) |
15951596

src/stdlib_linalg.fypp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,7 @@ module stdlib_linalg
13461346
!! This can be provided as either an `integer` value or a `character` string.
13471347
!! Allowed metrics are:
13481348
!! - 1-norm: `order` = 1 or '1'
1349+
!! - 2-norm: `order` = 2 or '2'
13491350
!! - Euclidean/Frobenius: `order` = 'Euclidean','Frobenius', or argument not specified
13501351
!! - Infinity norm: `order` = huge(0) or 'Inf'
13511352
!!

src/stdlib_linalg_norms.fypp

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ submodule(stdlib_linalg) stdlib_linalg_norms
162162

163163
! Check if this input can be read as an integer
164164
read(order,*,iostat=read_err) int_order
165-
if (read_err/=0 .or. all(int_order/=[1,2]) then
165+
if (read_err/=0 .or. all(int_order/=[1,2])) then
166166
! Cannot read as an integer
167167
err = linalg_state_type(this,LINALG_ERROR,'Matrix norm input',order,' is not recognized.')
168168
endif
@@ -482,10 +482,15 @@ ${loop_variables_end(rank-1," "*12)}$
482482
allocate(work(m))
483483
else
484484
work => work1
485-
endif
486-
487-
! LAPACK interface
488-
nrm = lange(mat_task,m,n,a,m,work)
485+
end if
486+
487+
if (mat_task==MAT_NORM_SVD) then
488+
nrm = maxval(svdvals(a,err_),1)
489+
call linalg_error_handling(err_,err)
490+
else
491+
! LAPACK interface
492+
nrm = lange(mat_task,m,n,a,m,work)
493+
end if
489494

490495
if (mat_task==MAT_NORM_INF) deallocate(work)
491496

@@ -507,7 +512,7 @@ ${loop_variables_end(rank-1," "*12)}$
507512
type(linalg_state_type), intent(out), optional :: err
508513

509514
type(linalg_state_type) :: err_
510-
integer(ilp) :: j,m,n,lda,dims(2),norm_request
515+
integer(ilp) :: j,m,n,lda,dims(2),norm_request,svd_errors
511516
integer(ilp), dimension(${rank}$) :: s,spack,perm,iperm
512517
integer(ilp), dimension(${rank}$), parameter :: dim_range = [(m,m=1_ilp,${rank}$_ilp)]
513518
integer(ilp) :: ${loop_variables('j',rank-2,2)}$
@@ -525,6 +530,7 @@ ${loop_variables_end(rank-1," "*12)}$
525530
endif
526531

527532
nullify(apack)
533+
svd_errors = 0
528534

529535
if (dims(1)==dims(2) .or. .not.all(dims>0 .and. dims<=${rank}$)) then
530536
err_ = linalg_state_type(this,LINALG_VALUE_ERROR,'Rank-',${rank}$,' matrix norm has invalid dim=',dims)
@@ -551,6 +557,13 @@ ${loop_variables_end(rank-1," "*12)}$
551557
m = s(dims(1))
552558
n = s(dims(2))
553559

560+
if (m<=0 .or. n<=0) then
561+
err_ = linalg_state_type(this,LINALG_VALUE_ERROR,'invalid matrix shape: a=',[m,n])
562+
allocate(nrm${emptyranksuffix(rank-2)}$)
563+
call linalg_error_handling(err_,err)
564+
return
565+
end if
566+
554567
! Get packed data with norm dimensions as 1:2
555568
if (contiguous_data) then
556569

@@ -570,6 +583,8 @@ ${loop_variables_end(rank-1," "*12)}$
570583

571584
if (mat_task==MAT_NORM_INF) then
572585
allocate(work(m))
586+
elseif (mat_task==MAT_NORM_SVD) then
587+
allocate(work(min(m,n)))
573588
else
574589
work => work1
575590
endif
@@ -581,12 +596,23 @@ ${loop_variables_end(rank-1," "*12)}$
581596

582597
! LAPACK interface
583598
${loop_variables_start('j', 'apack', rank-2, 2)}$
584-
nrm(${loop_variables('j',rank-2,2)}$) = &
585-
lange(mat_task,m,n,apack(:,:,${loop_variables('j',rank-2,2)}$),lda,work)
599+
if (mat_task==MAT_NORM_SVD) then
600+
work(:) = svdvals(apack(:,:,${loop_variables('j',rank-2,2)}$),err_)
601+
nrm(${loop_variables('j',rank-2,2)}$) = maxval(work,1)
602+
if (err_%error()) svd_errors = svd_errors+1
603+
else
604+
nrm(${loop_variables('j',rank-2,2)}$) = &
605+
lange(mat_task,m,n,apack(:,:,${loop_variables('j',rank-2,2)}$),lda,work)
606+
end if
586607
${loop_variables_end(rank-2)}$
587608

588-
if (mat_task==MAT_NORM_INF) deallocate(work)
609+
if (any(mat_task==[MAT_NORM_INF,MAT_NORM_SVD])) deallocate(work)
589610
if (.not.contiguous_data) deallocate(apack)
611+
612+
if (svd_errors>0) then
613+
err_ = linalg_state_type(this,LINALG_VALUE_ERROR,svd_errors,'failed SVDs')
614+
call linalg_error_handling(err_,err)
615+
endif
590616

591617
end function matrix_norm_${rank}$D_to_${rank-2}$D_${ii}$_${ri}$
592618

0 commit comments

Comments
 (0)