Skip to content

Commit 7b3b140

Browse files
committed
introduce internal implementation
1 parent 5532ded commit 7b3b140

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

src/stdlib_linalg_norms.fypp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,162 @@ ${loop_variables_end(rank-1," "*12)}$
387387
end subroutine norm_${rank}$D_to_${rank-1}$D_${ii}$_${ri}$
388388

389389
#:endfor
390+
391+
!====================================================================
392+
! Matrix norms
393+
!====================================================================
394+
395+
! Internal implementation
396+
module function matrix_norm_${ii}$_${ri}$(a, order, err) result(nrm)
397+
!> Input matrix a(m,n)
398+
${rt}$, intent(in), target :: a(:,:)
399+
!> Norm of the matrix.
400+
real(${rk}$) :: nrm
401+
!> Order of the matrix norm being computed.
402+
${it}$, intent(in) :: order
403+
!> [optional] state return flag. On error if not requested, the code will stop
404+
type(linalg_state_type), intent(out), optional :: err
405+
406+
type(linalg_state_type) :: err_
407+
integer(ilp) :: m,n,norm_request
408+
character :: lange_task
409+
real(${rk}$), target :: work1(1)
410+
real(${rk}$), pointer :: work(:)
411+
412+
m = size(a,dim=1,kind=ilp)
413+
n = size(a,dim=2,kind=ilp)
414+
415+
! Initialize norm to zero
416+
nrm = 0.0_${rk}$
417+
418+
if (m<=0 .or. n<=0) then
419+
err_ = linalg_state_type(this,LINALG_VALUE_ERROR,'invalid matrix shape: a=',[m,n])
420+
call linalg_error_handling(err_,err)
421+
return
422+
end if
423+
424+
! Check norm request: user + *LANGE support
425+
call parse_norm_type(order,norm_request,err_)
426+
call lange_task_request(norm_request,lange_task,err_)
427+
if (err_%error()) then
428+
call linalg_error_handling(err_,err)
429+
return
430+
endif
431+
432+
if (lange_task==LANGE_NORM_INF) then
433+
allocate(work(m))
434+
else
435+
work => work1
436+
endif
437+
438+
! LAPACK interface
439+
nrm = lange(lange_task,m,n,a,m,work)
440+
441+
if (lange_task==LANGE_NORM_INF) deallocate(work)
442+
443+
end function matrix_norm_${ii}$_${ri}$
444+
445+
#:for rank in range(3, MAXRANK + 1)
446+
447+
! Pure function interface with DIM specifier. On error, the code will stop
448+
module function matrix_norm_${rank}$D_to_${rank-2}$D_${ii}$_${ri}$(a, order, dim, err) result(nrm)
449+
!> Input matrix a(m,n)
450+
${rt}$, intent(in), contiguous, target :: a${ranksuffix(rank)}$
451+
!> Norm of the matrix.
452+
real(${rk}$), allocatable :: nrm${ranksuffix(rank-2)}$
453+
!> Order of the matrix norm being computed.
454+
${it}$, intent(in) :: order
455+
!> [optional] dimensions of the sub-matrices the norms should be evaluated at (default = [1,2])
456+
integer(ilp), optional, intent(in) :: dim(2)
457+
!> [optional] state return flag. On error if not requested, the code will stop
458+
type(linalg_state_type), intent(out), optional :: err
459+
460+
type(linalg_state_type) :: err_
461+
integer(ilp) :: j,m,n,lda,dims(2),norm_request
462+
integer(ilp), dimension(${rank}$) :: s,spack,perm
463+
integer(ilp), dimension(${rank}$), parameter :: dim_range = [(m,m=1_ilp,${rank}$_ilp)]
464+
integer(ilp) :: ${loop_variables('j',rank-2,2)}$
465+
logical :: contiguous_data
466+
character :: lange_task
467+
real(${rk}$), target :: work1(1)
468+
real(${rk}$), pointer :: work(:)
469+
${rt}$, pointer :: apack${ranksuffix(rank)}$
470+
471+
! Get dimensions
472+
if (present(dim)) then
473+
dims = dim
474+
else
475+
dims = [1,2]
476+
endif
477+
478+
nullify(apack)
479+
480+
if (dims(1)==dims(2) .or. .not.all(dims>0 .and. dims<=${rank}$)) then
481+
err_ = linalg_state_type(this,LINALG_VALUE_ERROR,'Rank-',${rank}$,' matrix norm has invalid dim=',dims)
482+
allocate(nrm${emptyranksuffix(rank-2)}$)
483+
call linalg_error_handling(err_,err)
484+
return
485+
endif
486+
487+
! Check norm request: user + *LANGE support
488+
call parse_norm_type(order,norm_request,err_)
489+
call lange_task_request(norm_request,lange_task,err_)
490+
if (err_%error()) then
491+
call linalg_error_handling(err_,err)
492+
return
493+
endif
494+
495+
! Input matrix properties
496+
s = shape(a,kind=ilp)
497+
498+
! Check if input column data is contiguous
499+
contiguous_data = dims(1)==1
500+
501+
! Matrix norm size
502+
m = s(dims(1))
503+
n = s(dims(2))
504+
505+
! Get packed data with norm dimensions as 1:2
506+
if (contiguous_data) then
507+
508+
! Collapse everything before the 1st dimension as apack's dim #1
509+
! Set size==1 for all unused trailing dimensions
510+
spack = [product(s(1:dims(2)-1)),s(dims(2):),(1_ilp,j=1,dims(2)-2)]
511+
512+
! Reshape without moving data
513+
apack${shape_from_array_data('spack',rank)}$ => a
514+
515+
else
516+
517+
! Dimension permutations to map dims(1),dims(2) => 1:2
518+
perm = [dims,pack(dim_range, dim_range/=dims(1) .and. dim_range/=dims(2))]
519+
spack = s(perm)
520+
apack = reshape(a, shape=spack, order=perm)
521+
522+
endif
523+
524+
if (lange_task==LANGE_NORM_INF) then
525+
allocate(work(m))
526+
else
527+
work => work1
528+
endif
529+
530+
! Allocate norm
531+
allocate(nrm${shape_from_array_size('apack',rank-2, 2)}$)
532+
533+
lda = size(apack,dim=1,kind=ilp)
534+
535+
! LAPACK interface
536+
${loop_variables_start('j', 'apack', rank-2, 2)}$
537+
nrm(${loop_variables('j',rank-2,2)}$) = &
538+
lange(lange_task,m,n,apack(:,:,${loop_variables('j',rank-2,2)}$),lda,work)
539+
${loop_variables_end(rank-2)}$
540+
541+
if (lange_task==LANGE_NORM_INF) deallocate(work)
542+
if (.not.contiguous_data) deallocate(apack)
543+
544+
end function matrix_norm_${rank}$D_to_${rank-2}$D_${ii}$_${ri}$
545+
390546
#:endfor
391547
#:endfor
392548

0 commit comments

Comments
 (0)