Skip to content

Commit

Permalink
More docs: eye, diag, schur (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
perazz authored Feb 1, 2025
2 parents 8a030ea + 29519c9 commit 395057c
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 126 deletions.
163 changes: 145 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,73 @@ where \f$ \Sigma^+ \f$ is the inverse of the nonzero singular values in \f$ \Sig
**Description**: Singular values $S$ from $A = U S V^t$.
**Usage**: `s = svdvals(A)` where `s` is a real array with the same precision as `A`.

## `eye(m)`
**Type**: Function
**Description**: Identity matrix of size `m`.
**Optional arguments**:
- `n`: Optional column size.
- `mold`: Optional datatype (default: real64).
- `err`: Error handler.
## [diag](@ref la_eye::diag) - Diagonal matrix.

### Syntax

`d = diag(n, source [, err])` for scalar input
`d = diag(source(:) [, err])` for array input

### Description

This function generates a square diagonal matrix where the diagonal elements are populated either by a scalar value or an array of values. The size of the matrix is determined by the input parameter \f$n\f$ or the size of the input array.
If a scalar is provided, the diagonal elements are all set to the same value. If an array is provided, its length determines the size of the matrix, and its elements are placed along the diagonal.

### Arguments

- `n`: The size of the square matrix (only used if a scalar is provided for the diagonal).
- `source`:
- If a scalar, this value is used to populate all the diagonal elements of the matrix.
- If an array, the elements of the array are used to populate the diagonal of the matrix. The size of the array determines the matrix size.
- `err` (optional): A state return flag of [type(la_state)](@ref la_state_type::la_state). If an error occurs and `err` is not provided, the function will stop execution.

### Return value

The function returns a matrix of size \f$n \times n\f$, where the diagonal elements are either all equal to the scalar `source` or populated by the values from the input array.

### Errors

- Raises [LINALG_VALUE_ERROR](@ref la_state_type::linalg_value_error) if the dimensions of the matrix are invalid or if the array size does not match the expected matrix size.
- If `err` is not provided, the function will stop execution on errors.

### Notes

- The diagonal elements are set to the specified scalar or the array values in the order they appear in the input.
- If the `err` parameter is provided, the error state of the function will be returned.


## [eye](@ref la_eye::eye) - Identity matrix.

### Syntax

`eye = eye(m [, n] [, mold] [, err])`

### Description

This function constructs an identity matrix of size \f$m \times n\f$, where the diagonal elements are set to 1 and all off-diagonal elements are set to 0. If only the number of rows \f$m\f$ is provided, a square matrix of size \f$m \times m\f$ is returned. The matrix is populated with a real data type, by default `real(real64)`, or a type specified by the user.

### Arguments

- `m`: The number of rows of the identity matrix.
- `n` (optional): The number of columns of the identity matrix. If omitted, the matrix is square (\f$m \times m\f$).
- `mold` (optional): The data type to define the return type. Defaults to `real(real64)`.
- `err` (optional): A state return flag of [type(la_state)](@ref la_state_type::la_state). If an error occurs and `err` is not provided, the function will stop execution.

### Return value

The function returns a matrix of size \f$m \times n\f$ (or \f$m \times m\f$ if \f$n\f$ is omitted) with diagonal elements set to 1 and all other elements set to 0.

### Errors

- Raises [LINALG_VALUE_ERROR](@ref la_state_type::linalg_value_error) if the dimensions of the matrix are invalid (e.g., negative values).
- If `err` is not provided, the function will stop execution on errors.

### Notes

- The identity matrix is constructed with the specified data type, which defaults to `real(real64)` if no type is specified.
- The `mold` scalar is used to provide a function return type.
- If the `err` parameter is provided, the error state of the function will be returned.


## `eigvals(A)`
**Type**: Function
Expand Down Expand Up @@ -370,19 +430,9 @@ where \f$ \Sigma^+ \f$ is the inverse of the nonzero singular values in \f$ \Sig
- `overwrite_a`: Option to let A be destroyed.
- `err`: Return state handler.

## `diag(n, source)`
**Type**: Function
**Description**: Diagonal matrix from scalar input value.
**Optional arguments**:
- `err`: Error handler.

## `diag(source)`
**Type**: Function
**Description**: Diagonal matrix from array input values.
**Optional arguments**:
- `err`: Error handler.

## [qr](@ref la_qr::qr) - Compute the QR factorization of a matrix.
## [qr](@ref la_qr::qr) - QR factorization of a matrix.

### Syntax

Expand Down Expand Up @@ -459,6 +509,83 @@ The workspace size \f$ lwork \f$ that should be allocated before calling the QR
- This subroutine is useful for preallocating memory for QR factorization in large systems.
- It is important to ensure that the workspace size is correctly allocated before proceeding with QR factorization to avoid memory issues.

## [schur](@ref la_schur::schur) - Schur decomposition of a matrix.

### Syntax

`call schur(a, t, z [, eigvals] [, overwrite_a] [, storage] [, err])`

### Description

This subroutine computes the Schur decomposition of a `real` or `complex` matrix \f$ A = Z T Z^H \f$, where \f$ Z \f$ is an orthonormal/unitary matrix, and \f$ T \f$ is an upper-triangular or quasi-upper-triangular matrix. The matrix \f$ A \f$ has size \f$ [m,m] \f$.

The decomposition produces:
- \f$ T \f$, which is upper-triangular for `complex` matrices and quasi-upper-triangular for `real` matrices (with possible \f$ 2 \times 2 \f$ blocks on the diagonal).
- \f$ Z \f$, the transformation matrix, which is optional.
- Optionally, the eigenvalues corresponding to the diagonal elements of \f$ T \f$.

If a pre-allocated workspace is provided, no internal memory allocations take place.

### Arguments

- `a`: A `real` or `complex` matrix of size \f$ [m,m] \f$. If `overwrite_a = .false.`, this is an input argument. If `overwrite_a = .true.`, it is an `inout` argument and is overwritten upon return.
- `t`: A rank-2 array of the same type and kind as `a`, representing the Schur form of `a`. This is an output argument with shape \f$ [m,m] \f$.
- `z` (optional): A rank-2 array of the same type and kind as `a`, representing the unitary/orthonormal transformation matrix \f$ Z \f$. This is an output argument with shape \f$ [m,m] \f$.
- `eigvals` (optional): A complex array of size \f$ [m] \f$, representing the eigenvalues that appear on the diagonal of \f$ T \f$. This is an output argument.
- `storage` (optional): A rank-1 array of the same type and kind as `a`, providing working storage for the solver. Its minimum size can be determined by a call to [schur_space](@ref la_schur::schur_space). This is an input argument.
- `overwrite_a` (optional, default = `.false.`): A logical flag that determines whether the input matrix `a` can be overwritten. If `.true.`, the matrix `a` is used as temporary storage and overwritten to avoid internal memory allocation. This is an input argument.
- `err` (optional): A [type(la_state)](@ref la_state_type::la_state) variable that returns the error state. If not provided, the function will stop execution on error.

### Return value

The Schur decomposition matrices \f$ T \f$ and optionally \f$ Z \f$ are returned in the corresponding arguments.

### Errors

- Raises [LINALG_VALUE_ERROR](@ref la_state_type::linalg_value_error) if the sizes of the matrices are incompatible.
- Raises [LINALG_ERROR](@ref la_state_type::linalg_error) if the algorithm did not converge.
- If `err` is not provided, exceptions will trigger an `error stop`.

### Notes

- This subroutine computes the Schur decomposition using LAPACK's Schur decomposition routines ([GEES](@ref la_lapack:gees)).
- Sorting options for eigenvalues can be requested, utilizing LAPACK's eigenvalue sorting mechanism.
- If `overwrite_a` is enabled, the input matrix `a` will be modified during computation.


## [schur_space](@ref la_schur::schur_space) - Workspace size for Schur decomposition.

### Syntax

`call schur_space(a, lwork [, err])`

### Description

This subroutine computes the minimum workspace size required for performing Schur decomposition. The size of the workspace array needed is determined based on the input matrix \f$ A \f$.

The input matrix \f$ A \f$ has size \f$ [m,m] \f$, and the output value \f$ lwork \f$ represents the minimum size of the workspace array that should be allocated for Schur decomposition operations.

### Arguments

- `a`: A `real` or `complex` matrix of size \f$ [m,m] \f$, representing the input matrix used to determine the required workspace size.
- `lwork`: An integer variable that will return the minimum workspace size required for Schur decomposition.
- `err` (optional): A [type(la_state)](@ref la_state_type::la_state) variable that returns the error state. If not provided, the function will stop execution on error.

### Return value

The workspace size \f$ lwork \f$ that should be allocated before calling the Schur decomposition routine is returned.

### Errors

- Raises [LINALG_ERROR](@ref la_state_type::linalg_error) if there is an issue determining the required workspace size.
- If `err` is not provided, exceptions will trigger an `error stop`.

### Notes

- This subroutine is useful for preallocating memory for Schur decomposition in large systems.
- It is important to ensure that the workspace size is correctly allocated before proceeding with Schur decomposition to avoid memory issues.



# BLAS, LAPACK
Modern Fortran modules with full explicit typing features are available as modules `la_blas` and `la_lapack`.
Expand Down
54 changes: 39 additions & 15 deletions fypp/src/la_eye.fypp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#:include "common.fypp"
! Return a 2-D matrix with ones on the diagonal and zeros everywhere else
!> Identity and diagonal matrices.
module la_eye
use la_constants
use la_blas
Expand All @@ -9,21 +9,45 @@ module la_eye
implicit none(type,external)
private

!> Constructs the identity matrix.
!! This interface provides procedures to generate an identity matrix of a given size.
!! The resulting matrix has 1s on the diagonal and 0s elsewhere.
public :: eye

public :: diag

!> @brief Construct an identity matrix of size \f$m \times n\f$.
!!
!! This function returns a diagonal identity matrix of size \f$m \times n\f$, where all diagonal elements
!! are set to 1 and all off-diagonal elements are set to 0. The number of rows and columns can be specified.
!! If only one parameter is provided, a square matrix of size \f$m \times m\f$ is returned.
!!
!! @param[in] m The number of rows of the identity matrix.
!! @param[in] n (Optional) The number of columns of the identity matrix. If omitted, the matrix is square (\f$m \times m\f$).
!! @param[in] mold (Optional) Data type to define the return type. Defaults to `real(real64)`.
!!
!! @return The identity matrix with size \f$m \times n\f$.
!!
!! @note If the `mold` parameter is omitted, the default type is `real(real64)`. If specified, the return type
!! matches the given type.
!!
!! @warning Ensure that the matrix dimensions are valid and consistent with the type definition.
public :: eye

!> @brief Return a square diagonal matrix with diagonal values.
!!
!! This function generates a square diagonal matrix where the diagonal elements are either
!! equal to the specified scalar value or populated by the input array.
!! The size of the matrix is determined by the input parameter \f$n\f$ or the size of the input array.
!!
!! @param[in] n The size of the square matrix (only used if a scalar is provided for the diagonal).
!! @param[in] source If a scalar, this value is used to populate the diagonal of the matrix.
!! If an array, the elements of the array are used for the diagonal.
!! @param[out] err (Optional) State return flag. If not provided, the function will stop on error.
!! @return The diagonal matrix with size \f$n \times n\f$, where the diagonal elements are populated by \f$source\f$.
!!
!! @note If a scalar value is passed, the diagonal elements of the matrix will all be equal to \f$source\f$.
!! If an array is passed, its length determines the size of the matrix, and the array elements are placed
!! along the diagonal. The `err` parameter is optional. If not requested, the code will stop on error.
!! Otherwise, it returns the error state of the function.
!!
public :: diag

! Identity matrix interface
interface eye
!> Procedure for creating an identity matrix.
!! - **Inputs:**
!! - `m` (integer): Number of rows.
!! - `n` (integer, optional): Number of columns. Defaults to `m` if not provided.
!! - `mold` (datatype, optional): Data type used to define the matrix elements. Defaults to `real(real64)`.
!! - **Outputs:**
!! - Identity matrix of specified size and type.
#:for epref,esuf,earg,epresent in FUNCTION_INTERFACES
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure la_eye_${ri}$${esuf}$
Expand Down
101 changes: 55 additions & 46 deletions fypp/src/la_schur.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module la_schur

character(*), parameter :: this = 'schur'

!> List of internal GEES tasks:
! List of internal GEES tasks:

!> No task request
character, parameter :: GEES_NOT = 'N'
Expand All @@ -22,58 +22,67 @@ module la_schur
!> Request Schur vectors to be sorted
character, parameter :: GEES_SORTED_VECTORS = 'S'

! Schur decomposition of rank-2 array A
interface schur
!! version: experimental
!> @brief Compute the Schur decomposition of a matrix.
!!
!! Computes the Schur decomposition of matrix \( A = Z T Z^H \).
!! ([Specification](../page/specs/la_linalg.html#schur-compute-the-schur-decomposition-of-a-matrix))
!! This function computes the Schur decomposition of a real or complex matrix \f$ A \f$:
!!
!!### Summary
!! Compute the Schur decomposition of a `real` or `complex` matrix: \( A = Z T Z^H \), where \( Z \) is
!! orthonormal/unitary and \( T \) is upper-triangular or quasi-upper-triangular. Matrix \( A \) has size `[m,m]`.
!! \f$ A = Z T Z^H \f$
!!
!!### Description
!!
!! This interface provides methods for computing the Schur decomposition of a matrix.
!! Supported data types include `real` and `complex`. If a pre-allocated workspace is provided, no internal
!! memory allocations take place when using this interface.
!! where \f$ Z \f$ is an orthonormal/unitary matrix and \f$ T \f$ is upper-triangular or quasi-upper-triangular.
!! The input matrix \f$ A \f$ has size \f$ [m, m] \f$.
!!
!! The output matrix \( T \) is upper-triangular for `complex` input matrices and quasi-upper-triangular
!! for `real` input matrices (with possible \( 2 \times 2 \) blocks on the diagonal).
!! The user can optionally request sorting of eigenvalues based on conditions, or a custom sorting function.
!! The decomposition is available for both real and complex matrices:
!! - For real matrices, the Schur form \f$ T \f$ may contain 2x2 blocks for complex eigenvalues.
!! - For complex matrices, \f$ T \f$ is always upper-triangular.
!!
!!@note The solution is based on LAPACK's Schur decomposition routines (`*GEES`). Sorting options
!! are implemented using LAPACK's eigenvalue sorting mechanism.
!!
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure la_${ri}$_schur
module procedure la_real_eig_${ri}$_schur
#:endfor
end interface schur
!! @param[in,out] A The input matrix of size \f$ [m, m] \f$. Can be overwritten if `overwrite_a` is set.
!! @param[out] T The upper-triangular or quasi-upper-triangular matrix of size \f$ [m, m] \f$.
!! @param[out] Z (Optional) The unitary/orthonormal transformation matrix of size \f$ [m, m] \f$.
!! @param[out] eigvals (Optional) The eigenvalues that appear on the diagonal of \f$ T \f$.
!! For real matrices, this is a real-valued array.
!! For complex matrices, this is a complex-valued array.
!! @param[in,out] storage (Optional) Pre-allocated workspace array. If provided, no internal allocations occur.
!! @param[in] overwrite_a (Optional) Logical flag indicating whether \f$ A \f$ can be overwritten.
!! @param[out] err (Optional) State return flag. If not provided, the function will stop on error.
!!
!! @note The computation is based on LAPACK's Schur decomposition routines ([GEES](@ref la_lapack::gees)).
!! @warning Ensure that `overwrite_a` is set correctly to avoid unintended modification of \f$ A \f$.
!!
interface schur
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure la_${ri}$_schur
module procedure la_real_eig_${ri}$_schur
#:endfor
end interface schur

! Return the working array space required by the Schur decomposition solver
interface schur_space
!! version: experimental

interface schur
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure la_${ri}$_schur
module procedure la_real_eig_${ri}$_schur
#:endfor
end interface schur

!> @brief Compute the required workspace size for Schur decomposition.
!!
!! Computes the working array space required by the Schur decomposition solver
!! ([Specification](../page/specs/la_linalg.html#schur-space-compute-internal-working-space-requirements-for-the-schur-decomposition))
!! This subroutine determines the minimum workspace size required for the Schur decomposition of a matrix.
!! The required size depends on the matrix dimensions and type (`real` or `complex`).
!!
!!### Description
!!
!! This interface returns the size of the `real` or `complex` working storage required by the
!! Schur decomposition solver. The working size only depends on the kind (`real` or `complex`) and size of
!! the matrix being decomposed. Storage size can be used to pre-allocate a working array in case several
!! repeated Schur decompositions of same-size matrices are sought. If pre-allocated working arrays
!! are provided, no internal allocations will take place during the decomposition.
!!
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure get_schur_${ri}$_workspace
#:endfor
end interface schur_space


!! @param[in] A The input matrix of size \f$ [m, m] \f$.
!! @param[out] lwork The minimum workspace size required for the decomposition.
!! @param[out] err (Optional) State return flag. If provided, it will return an error status in case of failure.
!!
!! @note This routine is useful for pre-allocating workspace when performing multiple decompositions on matrices
!! of the same size, minimizing dynamic memory allocation overhead.
!!
interface schur_space

interface schur_space
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure get_schur_${ri}$_workspace
#:endfor
end interface schur_space

contains

!> Wrapper function for Schur vectors request
Expand Down Expand Up @@ -363,7 +372,7 @@ module la_schur
end subroutine la_${ri}$_schur

! Schur decomposition subroutine: real eigenvalue interface
module subroutine la_real_eig_${ri}$_schur(a,t,z,eigvals,overwrite_a,storage,err)
subroutine la_real_eig_${ri}$_schur(a,t,z,eigvals,overwrite_a,storage,err)
!> Input matrix a[m,m]
${rt}$, intent(inout), target :: a(:,:)
!> Schur form of A: upper-triangular or quasi-upper-triangular matrix T
Expand Down
Loading

0 comments on commit 395057c

Please sign in to comment.