@@ -387,6 +387,162 @@ ${loop_variables_end(rank-1," "*12)}$
387
387
end subroutine norm_${rank}$D_to_${rank-1}$D_${ii}$_${ri}$
388
388
389
389
#: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
+
390
546
#:endfor
391
547
#:endfor
392
548
0 commit comments