Skip to content

Commit a1522ce

Browse files
authored
Merge branch 'fortran-lang:master' into linalg_schur
2 parents 46a7ec2 + 195d4a5 commit a1522ce

14 files changed

+867
-35
lines changed

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,29 @@ python config/fypp_deployment.py --help
219219
git checkout stdlib-fpm
220220
fpm build --profile release
221221
```
222-
#### Runing the examples
222+
223+
224+
#### Installing with fpm
225+
226+
Either option you chose for building the `stdlib`, you can install it with:
227+
```sh
228+
fpm install --profile release
229+
```
230+
The command above will install the following files:
231+
- `libstdlib.a` into `~/.local/lib/` (Unix) or `C:\Users\<username>\AppData\Roaming\local\lib\` (Windows)
232+
- all the `.[s]mod` files produced by the compiler into `~/.local/include/` (Unix) or `C:\Users\<username>\AppData\Roaming\local\include\` (Windows)
233+
234+
You can change the installation path by setting the prefix option to `fpm`:
235+
```sh
236+
fpm install --profile release --prefix /my/custom/installation/path/
237+
```
238+
239+
You can use the `stdlib` by adding the `-lstdlib` flag to your compiler.
240+
If your prefix is a non standard path, add also:
241+
- `-L/my/custom/installation/path/lib`
242+
- `-I/my/custom/installation/path/include`
243+
244+
#### Running the examples
223245
You can run the examples with `fpm` as:
224246

225247
```sh

doc/specs/stdlib_linalg.md

Lines changed: 181 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -239,37 +239,34 @@ Pure function.
239239

240240
### Description
241241

242-
Construct the identity matrix.
242+
Constructs the identity matrix.
243243

244244
### Syntax
245245

246-
`I = ` [[stdlib_linalg(module):eye(function)]] `(dim1 [, dim2])`
246+
`I = ` [[stdlib_linalg(module):eye(function)]] `(dim1 [, dim2] [, mold])`
247247

248248
### Arguments
249249

250-
`dim1`: Shall be a scalar of default type `integer`.
251-
This is an `intent(in)` argument.
252-
253-
`dim2`: Shall be a scalar of default type `integer`.
254-
This is an `intent(in)` and `optional` argument.
250+
- `dim1`: A scalar of type `integer`. This is an `intent(in)` argument and specifies the number of rows.
251+
- `dim2`: A scalar of type `integer`. This is an optional `intent(in)` argument specifying the number of columns. If not provided, the matrix is square (`dim1 = dim2`).
252+
- `mold`: A scalar of any supported `integer`, `real`, or `complex` type. This is an optional `intent(in)` argument. If provided, the returned identity matrix will have the same type and kind as `mold`. If not provided, the matrix will be of type `real(real64)` by default.
255253

256254
### Return value
257255

258-
Return the identity matrix, i.e. a matrix with ones on the main diagonal and zeros elsewhere. The return value is of type `integer(int8)`.
259-
The use of `int8` was suggested to save storage.
256+
Returns the identity matrix, with ones on the main diagonal and zeros elsewhere.
257+
258+
- By default, the return value is of type `real(real64)`, which is recommended for arithmetic safety.
259+
- If the `mold` argument is provided, the return value will match the type and kind of `mold`, allowing for arbitrary `integer`, `real`, or `complex` return types.
260260

261-
#### Warning
261+
### Example
262262

263-
Since the result of `eye` is of `integer(int8)` type, one should be careful about using it in arithmetic expressions. For example:
264263
```fortran
265-
!> Be careful
266-
A = eye(2,2)/2 !! A == 0.0
267-
!> Recommend
268-
A = eye(2,2)/2.0 !! A == diag([0.5, 0.5])
264+
!> Return default type (real64)
265+
A = eye(2,2)/2 !! A == diag([0.5_dp, 0.5_dp])
266+
!> Return 32-bit complex
267+
A = eye(2,2, mold=(0.0,0.0))/2 !! A == diag([(0.5,0.5), (0.5,0.5)])
269268
```
270269

271-
### Example
272-
273270
```fortran
274271
{!example/linalg/example_eye1.f90!}
275272
```
@@ -509,6 +506,37 @@ Returns a `logical` scalar that is `.true.` if the input matrix is skew-symmetri
509506
{!example/linalg/example_is_skew_symmetric.f90!}
510507
```
511508

509+
## `hermitian` - Compute the Hermitian version of a rank-2 matrix
510+
511+
### Status
512+
513+
Experimental
514+
515+
### Description
516+
517+
Compute the Hermitian version of a rank-2 matrix.
518+
For `complex` matrices, the function returns the conjugate transpose (`conjg(transpose(a))`).
519+
For `real` or `integer` matrices, the function returns the transpose (`transpose(a)`).
520+
521+
### Syntax
522+
523+
`h = ` [[stdlib_linalg(module):hermitian(interface)]] `(a)`
524+
525+
### Arguments
526+
527+
`a`: Shall be a rank-2 array of type `integer`, `real`, or `complex`. The input matrix `a` is not modified.
528+
529+
### Return value
530+
531+
Returns a rank-2 array of the same shape and type as `a`. If `a` is of type `complex`, the Hermitian matrix is computed as `conjg(transpose(a))`.
532+
For `real` or `integer` types, it is equivalent to the intrinsic `transpose(a)`.
533+
534+
### Example
535+
536+
```fortran
537+
{!example/linalg/example_hermitian.f90!}
538+
```
539+
512540
## `is_hermitian` - Checks if a matrix is Hermitian
513541

514542
### Status
@@ -1535,6 +1563,142 @@ If `err` is not present, exceptions trigger an `error stop`.
15351563
{!example/linalg/example_inverse_function.f90!}
15361564
```
15371565

1566+
## `pinv` - Moore-Penrose pseudo-inverse of a matrix
1567+
1568+
### Status
1569+
1570+
Experimental
1571+
1572+
### Description
1573+
1574+
This function computes the Moore-Penrose pseudo-inverse of a `real` or `complex` matrix.
1575+
The pseudo-inverse, \( A^{+} \), generalizes the matrix inverse and satisfies the conditions:
1576+
- \( A \cdot A^{+} \cdot A = A \)
1577+
- \( A^{+} \cdot A \cdot A^{+} = A^{+} \)
1578+
- \( (A \cdot A^{+})^T = A \cdot A^{+} \)
1579+
- \( (A^{+} \cdot A)^T = A^{+} \cdot A \)
1580+
1581+
The computation is based on singular value decomposition (SVD). Singular values below a relative
1582+
tolerance threshold \( \text{rtol} \cdot \sigma_{\max} \), where \( \sigma_{\max} \) is the largest
1583+
singular value, are treated as zero.
1584+
1585+
### Syntax
1586+
1587+
`b =` [[stdlib_linalg(module):pinv(interface)]] `(a, [, rtol, err])`
1588+
1589+
### Arguments
1590+
1591+
`a`: Shall be a rank-2, `real` or `complex` array of shape `[m, n]` containing the coefficient matrix.
1592+
It is an `intent(in)` argument.
1593+
1594+
`rtol` (optional): Shall be a scalar `real` value specifying the relative tolerance for singular value cutoff.
1595+
If `rtol` is not provided, the default relative tolerance is \( \text{rtol} = \text{max}(m, n) \cdot \epsilon \),
1596+
where \( \epsilon \) is the machine precision for the element type of `a`. It is an `intent(in)` argument.
1597+
1598+
`err` (optional): Shall be a `type(linalg_state_type)` value. It is an `intent(out)` argument.
1599+
1600+
### Return value
1601+
1602+
Returns an array value of the same type, kind, and rank as `a` with shape `[n, m]`, that contains the pseudo-inverse matrix \( A^{+} \).
1603+
1604+
Raises `LINALG_ERROR` if the underlying SVD did not converge.
1605+
Raises `LINALG_VALUE_ERROR` if `a` has invalid size.
1606+
If `err` is not present, exceptions trigger an `error stop`.
1607+
1608+
### Example
1609+
1610+
```fortran
1611+
{!example/linalg/example_pseudoinverse.f90!}
1612+
```
1613+
1614+
## `pseudoinvert` - Moore-Penrose pseudo-inverse of a matrix
1615+
1616+
### Status
1617+
1618+
Experimental
1619+
1620+
### Description
1621+
1622+
This subroutine computes the Moore-Penrose pseudo-inverse of a `real` or `complex` matrix.
1623+
The pseudo-inverse \( A^{+} \) is a generalization of the matrix inverse and satisfies the following properties:
1624+
- \( A \cdot A^{+} \cdot A = A \)
1625+
- \( A^{+} \cdot A \cdot A^{+} = A^{+} \)
1626+
- \( (A \cdot A^{+})^T = A \cdot A^{+} \)
1627+
- \( (A^{+} \cdot A)^T = A^{+} \cdot A \)
1628+
1629+
The computation is based on singular value decomposition (SVD). Singular values below a relative
1630+
tolerance threshold \( \text{rtol} \cdot \sigma_{\max} \), where \( \sigma_{\max} \) is the largest
1631+
singular value, are treated as zero.
1632+
1633+
On return, matrix `pinva` `[n, m]` will store the pseudo-inverse of `a` `[m, n]`.
1634+
1635+
### Syntax
1636+
1637+
`call ` [[stdlib_linalg(module):pseudoinvert(interface)]] `(a, pinva [, rtol] [, err])`
1638+
1639+
### Arguments
1640+
1641+
`a`: Shall be a rank-2, `real` or `complex` array containing the coefficient matrix.
1642+
It is an `intent(in)` argument.
1643+
1644+
`pinva`: Shall be a rank-2 array of the same kind as `a`, and size equal to that of `transpose(a)`.
1645+
On output, it contains the Moore-Penrose pseudo-inverse of `a`.
1646+
1647+
`rtol` (optional): Shall be a scalar `real` value specifying the relative tolerance for singular value cutoff.
1648+
If not provided, the default threshold is \( \text{max}(m, n) \cdot \epsilon \), where \( \epsilon \) is the
1649+
machine precision for the element type of `a`.
1650+
1651+
`err` (optional): Shall be a `type(linalg_state_type)` value. It is an `intent(out)` argument.
1652+
1653+
### Return value
1654+
1655+
Computes the Moore-Penrose pseudo-inverse of the matrix \( A \), \( A^{+} \), and returns it in matrix `pinva`.
1656+
1657+
Raises `LINALG_ERROR` if the underlying SVD did not converge.
1658+
Raises `LINALG_VALUE_ERROR` if `pinva` and `a` have degenerate or incompatible sizes.
1659+
If `err` is not present, exceptions trigger an `error stop`.
1660+
1661+
### Example
1662+
1663+
```fortran
1664+
{!example/linalg/example_pseudoinverse.f90!}
1665+
```
1666+
1667+
## `.pinv.` - Moore-Penrose Pseudo-Inverse operator
1668+
1669+
### Status
1670+
1671+
Experimental
1672+
1673+
### Description
1674+
1675+
This operator returns the Moore-Penrose pseudo-inverse of a `real` or `complex` matrix \( A \).
1676+
The pseudo-inverse \( A^{+} \) is computed using Singular Value Decomposition (SVD), and singular values
1677+
below a given threshold are treated as zero.
1678+
1679+
This interface is equivalent to the function [[stdlib_linalg(module):pinv(interface)]].
1680+
1681+
### Syntax
1682+
1683+
`b = ` [[stdlib_linalg(module):operator(.pinv.)(interface)]] `a`
1684+
1685+
### Arguments
1686+
1687+
`a`: Shall be a rank-2 array of any `real` or `complex` kinds, with arbitrary dimensions \( m \times n \). It is an `intent(in)` argument.
1688+
1689+
### Return value
1690+
1691+
Returns a rank-2 array with the same type, kind, and rank as `a`, that contains the Moore-Penrose pseudo-inverse of `a`.
1692+
1693+
If an exception occurs, or if the input matrix is degenerate (e.g., rank-deficient), the returned matrix will contain `NaN`s.
1694+
For more detailed error handling, it is recommended to use the `subroutine` or `function` interfaces.
1695+
1696+
### Example
1697+
1698+
```fortran
1699+
{!example/linalg/example_pseudoinverse.f90!}
1700+
```
1701+
15381702
## `get_norm` - Computes the vector norm of a generic-rank array.
15391703

15401704
### Status

example/linalg/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ADD_EXAMPLE(diag5)
66
ADD_EXAMPLE(eye1)
77
ADD_EXAMPLE(eye2)
88
ADD_EXAMPLE(is_diagonal)
9+
ADD_EXAMPLE(hermitian)
910
ADD_EXAMPLE(is_hermitian)
1011
ADD_EXAMPLE(is_hessenberg)
1112
ADD_EXAMPLE(is_skew_symmetric)
@@ -16,6 +17,7 @@ ADD_EXAMPLE(inverse_operator)
1617
ADD_EXAMPLE(inverse_function)
1718
ADD_EXAMPLE(inverse_inplace)
1819
ADD_EXAMPLE(inverse_subroutine)
20+
ADD_EXAMPLE(pseudoinverse)
1921
ADD_EXAMPLE(outer_product)
2022
ADD_EXAMPLE(eig)
2123
ADD_EXAMPLE(eigh)

example/linalg/example_eye1.f90

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ program example_eye1
55
real :: a(3, 3)
66
real :: b(2, 3) !! Matrix is non-square.
77
complex :: c(2, 2)
8-
I = eye(2) !! [1,0; 0,1]
9-
A = eye(3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
10-
A = eye(3, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
11-
B = eye(2, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0]
12-
C = eye(2, 2) !! [(1.0,0.0),(0.0,0.0); (0.0,0.0),(1.0,0.0)]
8+
I = eye(2) !! [1,0; 0,1]
9+
A = eye(3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
10+
A = eye(3, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
11+
B = eye(2, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0]
12+
C = eye(2, 2) !! [(1.0,0.0),(0.0,0.0); (0.0,0.0),(1.0,0.0)]
1313
C = (1.0, 1.0)*eye(2, 2) !! [(1.0,1.0),(0.0,0.0); (0.0,0.0),(1.0,1.0)]
1414
end program example_eye1

example/linalg/example_hermitian.f90

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
! Example program demonstrating the usage of hermitian
2+
program example_hermitian
3+
use stdlib_linalg, only: hermitian
4+
implicit none
5+
6+
complex, dimension(2, 2) :: A, AT
7+
8+
! Define input matrices
9+
A = reshape([(1,2),(3,4),(5,6),(7,8)],[2,2])
10+
11+
! Compute Hermitian matrices
12+
AT = hermitian(A)
13+
14+
print *, "Original Complex Matrix:"
15+
print *, A
16+
print *, "Hermitian Complex Matrix:"
17+
print *, AT
18+
19+
end program example_hermitian
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
! Matrix pseudo-inversion example: function, subroutine, and operator interfaces
2+
program example_pseudoinverse
3+
use stdlib_linalg, only: pinv, pseudoinvert, operator(.pinv.), linalg_state_type
4+
implicit none(type,external)
5+
6+
real :: A(15,5), Am1(5,15)
7+
type(linalg_state_type) :: state
8+
integer :: i, j
9+
real, parameter :: tol = sqrt(epsilon(0.0))
10+
11+
! Generate random matrix A (15x15)
12+
call random_number(A)
13+
14+
! Pseudo-inverse: Function interfcae
15+
Am1 = pinv(A, err=state)
16+
print *, 'Max error (function) : ', maxval(abs(A-matmul(A, matmul(Am1,A))))
17+
18+
! User threshold
19+
Am1 = pinv(A, rtol=0.001, err=state)
20+
print *, 'Max error (rtol=0.001): ', maxval(abs(A-matmul(A, matmul(Am1,A))))
21+
22+
! Pseudo-inverse: Subroutine interface
23+
call pseudoinvert(A, Am1, err=state)
24+
25+
print *, 'Max error (subroutine): ', maxval(abs(A-matmul(A, matmul(Am1,A))))
26+
27+
! Operator interface
28+
Am1 = .pinv.A
29+
30+
print *, 'Max error (operator) : ', maxval(abs(A-matmul(A, matmul(Am1,A))))
31+
32+
end program example_pseudoinverse

fpm.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ version = "VERSION"
33
license = "MIT"
44
author = "stdlib contributors"
55
maintainer = "@fortran-lang/stdlib"
6-
copyright = "2019-2021 stdlib contributors"
6+
copyright = "2019-2024 stdlib contributors"
7+
8+
[install]
9+
library = true
710

811
[dev-dependencies]
912
test-drive.git = "https://github.com/fortran-lang/test-drive"

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ set(fppFiles
3232
stdlib_linalg_determinant.fypp
3333
stdlib_linalg_qr.fypp
3434
stdlib_linalg_inverse.fypp
35+
stdlib_linalg_pinv.fypp
3536
stdlib_linalg_norms.fypp
3637
stdlib_linalg_state.fypp
3738
stdlib_linalg_svd.fypp

0 commit comments

Comments
 (0)