Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linalg: vector norms #871

Merged
merged 33 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1dbf88e
add `norms` module
perazz Sep 13, 2024
a9f4c7d
fix norms types
perazz Sep 13, 2024
98b9b55
submodule
perazz Sep 13, 2024
c4433cf
add examples
perazz Sep 13, 2024
7d2fb85
add tests
perazz Sep 13, 2024
cd53be4
document interfaces
perazz Sep 13, 2024
edf4757
documentation
perazz Sep 13, 2024
35fadc3
attempt artifact v4
perazz Sep 13, 2024
5ba7ef0
The name of the module procedure conflicts with a name in the encompa…
perazz Sep 13, 2024
fe23d1e
Update doc/specs/stdlib_linalg.md
perazz Sep 15, 2024
7ad3ea8
Update doc/specs/stdlib_linalg.md
perazz Sep 15, 2024
4e772e1
Update doc/specs/stdlib_linalg.md
perazz Sep 15, 2024
b405671
Update doc/specs/stdlib_linalg.md
perazz Sep 15, 2024
aa734de
improve argument descriptions
perazz Sep 15, 2024
437b96e
use intrinsic `norm2` where possible
perazz Sep 15, 2024
de4f8d3
2-norm: use BLAS on contiguous or strided arrays if possible
perazz Sep 17, 2024
37616ad
do not use strides
perazz Sep 18, 2024
93b37ff
interface to, use and test 1-norm `asum` from BLAS
perazz Sep 19, 2024
f271688
drop duplicate descr
perazz Sep 23, 2024
9e020a8
move `get_norm` before `norm`
perazz Sep 23, 2024
0dabeac
Update src/stdlib_linalg_norms.fypp
perazz Sep 23, 2024
54caa7f
Update src/stdlib_linalg_norms.fypp
perazz Sep 23, 2024
07f0525
Update src/stdlib_linalg_norms.fypp
perazz Sep 23, 2024
a94647c
Update src/stdlib_linalg_norms.fypp
perazz Sep 23, 2024
13636a9
Update example/linalg/example_get_norm.f90
perazz Sep 23, 2024
92ab520
Update src/stdlib_linalg_norms.fypp
perazz Sep 23, 2024
91882fa
Update example/linalg/example_get_norm.f90
perazz Sep 23, 2024
1a79128
Update example/linalg/example_norm.f90
perazz Sep 23, 2024
0e798ff
Merge branch 'norms' of github.com:perazz/stdlib into norms
perazz Sep 23, 2024
5f6b5e8
ND arrays: use LAPACK internals via loops
perazz Sep 27, 2024
f6d07f8
streamline ND->1D norm functions
perazz Sep 27, 2024
a65e771
streamline `dim`-med norm functions
perazz Sep 27, 2024
39d6daa
test infinity norm vs. `maxval(abs(.))`
perazz Sep 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: CTest
run: PATH=$PATH:/mingw64/bin/ ctest --test-dir build --output-on-failure --parallel -V -LE quadruple_precision

- uses: actions/upload-artifact@v1
- uses: actions/upload-artifact@v4
if: failure()
with:
name: WindowsCMakeTestlog
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/doc-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
ford -r $(git describe --always) --debug ${MAYBE_SKIP_SEARCH} "${FORD_FILE}"

- name: Upload Documentation
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: FORD-API-docs
path: ./API-doc/
Expand Down
109 changes: 109 additions & 0 deletions doc/specs/stdlib_linalg.md
Original file line number Diff line number Diff line change
Expand Up @@ -1382,3 +1382,112 @@ If `err` is not present, exceptions trigger an `error stop`.
{!example/linalg/example_inverse_function.f90!}
```

## `norm` - Computes the vector norm of a generic-rank array.

### Status

Experimental

### Description

This function computes one of several vector norms of `real` or `complex` array \( A \), depending on
the value of the `order` input argument. \( A \) may be an array of any rank.

Result `x` returns a `real` scalar norm value for the whole array; if `dim` is specified, `x` is an array of rank n-1,
perazz marked this conversation as resolved.
Show resolved Hide resolved
where n equals the rank of ARRAY, and a shape similar to that of \( A \) with dimension `dim` dropped,
containing all norms evaluated along `dim`.

### Syntax

`x = ` [[stdlib_linalg(module):norm(interface)]] `(a, order, [, dim, err])`

### Arguments

`a`: Shall be a rank-n `real` or `complex` array containing the data. It is an `intent(in)` argument.

`order`: Shall be an `integer` value or a `character` flag that specifies the norm type, as follows. It is an `intent(in)` argument.

| Integer input | Character Input | Norm type |
|------------------|------------------|---------------------------------------------------------|
| `-huge(0)` | `'-inf', '-Inf'` | Minimum absolute value \( \min_i{ \left|a_i\right| } \) |
| `1` | `'1'` | 1-norm \( \sum_i{ \left|a_i\right| } \) |
| `2` | `'2'` | Euclidean norm \( \sqrt{\sum_i{ a_i^2 }} \) |
| `>=3` | `'3','4',...` | p-norm \( \left( \sum_i{ \left|a_i\right|^p }\right) ^{1/p} \) |
| `huge(0)` | `'inf', 'Inf'` | Maximum absolute value \( \max_i{ \left|a_i\right| } \) |

`dim` (optional): Shall be a scalar `integer` value with a value in the range from `1` to `n`, where `n` is the rank of the array. It is an `intent(in)` argument.

`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument. If `err` is not present, the function is `pure`.

### Return value

By default, the return value `x` is a scalar, and contains the norm as evaluated over all elements of the generic-rank array \( A \).
If the optional `dim` argument is present, `x` is a rank `n-1` array with the same shape as \( A \) except
for dimension `dim`, that is dropped. Each element of `x` contains the 1D norm of the elements of \( A \),
evaluated along dimension `dim` only.

Raises `LINALG_ERROR` if the requested norm type is invalid.
Raises `LINALG_VALUE_ERROR` if any of the arguments has an invalid size.
If `err` is not present, exceptions trigger an `error stop`.

### Example

```fortran
{!example/linalg/example_norm.f90!}
```

## `get_norm` - Computes the vector norm of a generic-rank array.
perazz marked this conversation as resolved.
Show resolved Hide resolved

### Status

Experimental

### Description

This `pure subroutine` interface computes one of several vector norms of `real` or `complex` array \( A \), depending on
the value of the `order` input argument. \( A \) may be an array of any rank.

Result `nrm` returns a `real`, scalar norm value for the whole array; if `dim` is specified, `nrm` is a rank n-1
array with the same shape as \(A \) and dimension `dim` dropped, containing all norms evaluated along `dim`.

### Syntax

`call ` [[stdlib_linalg(module):get_norm(interface)]] `(a, nrm, order, [, dim, err])`

### Arguments

`a`: Shall be a rank-n `real` or `complex` array containing the data. It is an `intent(in)` argument.

`nrm`: if `dim` is absent, shall be a scalar with the norm evaluated over all the elements of the array. Otherwise, an array of rank `n-1`, and a shape similar
to that of `a` with dimension `dim` dropped.

`order`: Shall be an `integer` value or a `character` flag that specifies the norm type, as follows. It is an `intent(in)` argument.

| Integer input | Character Input | Norm type |
|------------------|------------------|---------------------------------------------------------|
| `-huge(0)` | `'-inf', '-Inf'` | Minimum absolute value \( \min_i{ \left|a_i\right| } \) |
| `1` | `'1'` | 1-norm \( \sum_i{ \left|a_i\right| } \) |
| `2` | `'2'` | Euclidean norm \( \sqrt{\sum_i{ a_i^2 }} \) |
| `>=3` | `'3','4',...` | p-norm \( \left( \sum_i{ \left|a_i\right|^p }\right) ^{1/p} \) |
| `huge(0)` | `'inf', 'Inf'` | Maximum absolute value \( \max_i{ \left|a_i\right| } \) |

`dim` (optional): Shall be a scalar `integer` value with a value in the range from `1` to `n`, where `n` is the rank of the array. It is an `intent(in)` argument.

`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument. If `err` is not present, the function is `pure`.

### Return value

By default, the return value `nrm` is a scalar, and contains the norm as evaluated over all elements of the generic-rank array \( A \).
If the optional `dim` argument is present, `nrm` is a rank `n-1` array with the same shape as \( A \) except
for dimension `dim`, that is collapsed. Each element of `nrm` contains the 1D norm of the elements of \( A \),
evaluated along dimension `dim` only.

Raises `LINALG_ERROR` if the requested norm type is invalid.
Raises `LINALG_VALUE_ERROR` if any of the arguments has an invalid size.
If `err` is not present, exceptions trigger an `error stop`.

### Example

```fortran
{!example/linalg/example_get_norm.f90!}
```
2 changes: 2 additions & 0 deletions example/linalg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ ADD_EXAMPLE(blas_gemv)
ADD_EXAMPLE(lapack_getrf)
ADD_EXAMPLE(lstsq1)
ADD_EXAMPLE(lstsq2)
ADD_EXAMPLE(norm)
ADD_EXAMPLE(get_norm)
ADD_EXAMPLE(solve1)
ADD_EXAMPLE(solve2)
ADD_EXAMPLE(solve3)
Expand Down
51 changes: 51 additions & 0 deletions example/linalg/example_get_norm.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
! Vector norm: demonstrate usage of the function interface
program example_get_norm
use stdlib_linalg, only: get_norm, linalg_state_type
implicit none

real :: a(3,3),nrm,nrmd(3)
perazz marked this conversation as resolved.
Show resolved Hide resolved
integer :: j
type(linalg_state_type) :: err

! a = [ -3.00000000 0.00000000 3.00000000
! -2.00000000 1.00000000 4.00000000
! -1.00000000 2.00000000 5.00000000 ]
a = reshape([(j-4,j=1,9)], [3,3])

print "(' a = [ ',3(g0,3x),2(/9x,3(g0,3x)),']')", transpose(a)

! Norm with integer input
call get_norm(a, nrm, 2)
print *, 'Euclidean norm = ',nrm ! 8.30662346

! Norm with character input
call get_norm(a, nrm, '2')
print *, 'Euclidean norm = ',nrm ! 8.30662346

! Euclidean norm of row arrays, a(i,:)
call get_norm(a, nrmd, 2, dim=2)
print *, 'Rows norms = ',nrmd ! 4.24264050 4.58257580 5.47722578

! Euclidean norm of columns arrays, a(:,i)
call get_norm(a, nrmd, 2, dim=1)
print *, 'Columns norms = ',nrmd ! 3.74165750 2.23606801 7.07106781

! Infinity norms
call get_norm(a, nrm, 'inf')
print *, 'maxval(||a||) = ',nrm ! 5.00000000

call get_norm(a, nrmd, 'inf', dim=2)
print *, 'maxval(||a(i,:)||) = ',nrmd ! 3.00000000 4.00000000 5.00000000

call get_norm(a, nrm, '-inf')
print *, 'minval(||a||) = ',nrm ! 0.00000000

call get_norm(a, nrmd, '-inf', dim=1)
print *, 'minval(||a(:,i)||) = ',nrmd ! 1.00000000 0.00000000 3.00000000

! Catch Error:
! [norm] returned Value Error: dimension 4 is out of rank for shape(a)= [3 3]
perazz marked this conversation as resolved.
Show resolved Hide resolved
call get_norm(a, nrmd, 'inf', dim=4, err=err)
print *, 'invalid: ',err%print()

end program example_get_norm
40 changes: 40 additions & 0 deletions example/linalg/example_norm.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
! Vector norm: demonstrate usage of the function interface
program example_norm
use stdlib_linalg, only: norm, linalg_state_type
implicit none

real :: a(3,3),na
integer :: j
type(linalg_state_type) :: err

! a = [ -3.00000000 0.00000000 3.00000000
! -2.00000000 1.00000000 4.00000000
! -1.00000000 2.00000000 5.00000000 ]
a = reshape([(j-4,j=1,9)], [3,3])

print "(' a = [ ',3(g0,3x),2(/9x,3(g0,3x)),']')", transpose(a)

! Norm with integer input
print *, 'Euclidean norm = ',norm(a, 2) ! 8.30662346

! Norm with character input
print *, 'Euclidean norm = ',norm(a, '2') ! 8.30662346

! Euclidean norm of row arrays, a(i,:)
print *, 'Rows norms = ',norm(a, 2, dim=2) ! 4.24264050 4.58257580 5.47722578

! Euclidean norm of columns arrays, a(:,i)
print *, 'Columns norms = ',norm(a, 2, dim=1) ! 3.74165750 2.23606801 7.07106781

! Infinity norms
print *, 'maxval(||a||) = ',norm(a, 'inf') ! 5.00000000
print *, 'maxval(||a(i,:)||) = ',norm(a, 'inf', dim=2) ! 3.00000000 4.00000000 5.00000000
print *, 'minval(||a||) = ',norm(a, '-inf') ! 0.00000000
print *, 'minval(||a(:,i)||) = ',norm(a, '-inf', dim=1) ! 1.00000000 0.00000000 3.00000000

! Catch Error:
! [norm] returned Value Error: dimension 4 is out of rank for shape(a)= [3 3]
perazz marked this conversation as resolved.
Show resolved Hide resolved
print *, 'invalid: ',norm(a,'inf', dim=4, err=err)
print *, 'error = ',err%print()

end program example_norm
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ set(fppFiles
stdlib_linalg_solve.fypp
stdlib_linalg_determinant.fypp
stdlib_linalg_inverse.fypp
stdlib_linalg_norms.fypp
stdlib_linalg_state.fypp
stdlib_linalg_svd.fypp
stdlib_linalg_cholesky.fypp
Expand Down
Loading
Loading