Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4a4b899
import files
perazz Apr 13, 2024
d54cfa3
add `pure` interface
perazz Apr 13, 2024
c987fa1
add operator interface
perazz Apr 13, 2024
b9a3b0e
add tests
perazz Apr 13, 2024
4a29219
make `pure`
perazz Apr 13, 2024
3d05cc3
remove `xdp`
perazz Apr 13, 2024
4beab1f
Documentation
perazz Apr 13, 2024
15023e1
`submodule version`
perazz Apr 14, 2024
5923a54
Update src/stdlib_linalg.fypp
perazz Apr 15, 2024
31cdc84
Update src/stdlib_linalg.fypp
perazz Apr 15, 2024
45a606f
add `det` example
perazz Apr 15, 2024
cacb585
Update src/stdlib_linalg_determinant.fypp
perazz Apr 15, 2024
5c16ff8
Update src/stdlib_linalg_determinant.fypp
perazz Apr 15, 2024
ab030c5
Update src/stdlib_linalg_determinant.fypp
perazz Apr 15, 2024
13bd98a
warn about `xdp`
perazz Apr 15, 2024
7bf7141
Merge branch 'determinant' of github.com:perazz/stdlib into determinant
perazz Apr 15, 2024
504d90d
cleanup xdp notes
perazz Apr 15, 2024
e80b508
spacing
perazz Apr 15, 2024
c6076ea
relax error thresholds
perazz Apr 15, 2024
eaebe5c
restore `pure` attribute
perazz Apr 15, 2024
5d52d48
Update test/linalg/test_linalg_determinant.fypp
perazz Apr 15, 2024
cff995d
add docs
perazz Apr 21, 2024
2fe2428
link to specs
perazz Apr 21, 2024
45447a8
Update doc/specs/stdlib_linalg.md
perazz Apr 21, 2024
3ee20ad
Update doc/specs/stdlib_linalg.md
perazz Apr 21, 2024
1e50115
Update doc/specs/stdlib_linalg.md
perazz Apr 21, 2024
fe933ad
Update doc/specs/stdlib_linalg.md
perazz Apr 21, 2024
59dae89
Update doc/specs/stdlib_linalg.md
perazz Apr 21, 2024
3c72b06
Update doc/specs/stdlib_linalg.md
perazz Apr 21, 2024
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add pure interface
  • Loading branch information
perazz committed Apr 13, 2024
commit d54cfa3c8217b67ce0bf1b55f83d6dd3c16312f4
6 changes: 6 additions & 0 deletions src/stdlib_linalg.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ module stdlib_linalg
int8, int16, int32, int64
use stdlib_error, only: error_stop
use stdlib_optval, only: optval
use stdlib_linalg_state, only: linalg_state_type, linalg_error_handling
use stdlib_linalg_determinant, only: det
implicit none
private

public :: det
public :: diag
public :: eye
public :: trace
Expand All @@ -23,6 +26,9 @@ module stdlib_linalg
public :: is_hermitian
public :: is_triangular
public :: is_hessenberg

! Export linalg error handling
public :: linalg_state_type, linalg_error_handling
Comment on lines +30 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This let me think that we should review the structure of the specs. Currently we have 1 page per module. However, if these become available through stdlib_linalg, the specs should be modified accordingly (probably in another PR; I can start to work on a proposition when this is ready).


interface diag
!! version: experimental
Expand Down
123 changes: 102 additions & 21 deletions src/stdlib_linalg_determinant.fypp
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#:include "common.fypp"
#:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
!> Determinant of a rectangular matrix
module stdlib_linalg_determinant
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be a submdodule of stdblib_linalg, such that users can use it as:

use stdlib_linalg, only: det

instead of:

use stdlib_linalg_determinant, only: det

This will avoid an enormous amount of stdlib_linalg modules.
Inconvenient: this approach will require the compilation of the a large module.

What do you think? What would be the best strategy for the users?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a good approach, everything would fit together smoothly. This might require indeed a large header module but for the end user and even a developer who would like to pick just one method and work on it, it would be easier... I think.

use stdlib_linalg_constants
use stdlib_linalg_blas
use stdlib_linalg_lapack
use stdlib_linalg_state
use iso_fortran_env,only:real32,real64,real128,int8,int16,int32,int64,stderr => error_unit
use stdlib_linalg_lapack, only: getrf
use stdlib_linalg_state, only: linalg_state_type, linalg_error_handling, LINALG_ERROR, &
LINALG_INTERNAL_ERROR, LINALG_VALUE_ERROR
implicit none(type,external)
private

!> Determinant of a rectangular matrix
!> Function interface
public :: det

character(*), parameter :: this = 'determinant'
Expand All @@ -18,28 +19,106 @@ module stdlib_linalg_determinant
! IMSL: DET(a)

interface det
#:for rk,rt,ri in ALL_KINDS_TYPES
module procedure stdlib_linalg_${ri}$determinant
#:for rk,rt in RC_KINDS_TYPES
module procedure stdlib_linalg_${rt[0]}$${rk}$determinant
module procedure stdlib_linalg_pure_${rt[0]}$${rk}$determinant
#:endfor
end interface det


contains

#:for rk,rt,ri in ALL_KINDS_TYPES
! Compute determinant of a square matrix A
function stdlib_linalg_${ri}$determinant(a,overwrite_a,err) result(det)
#:for rk,rt in RC_KINDS_TYPES
! Compute determinant of a square matrix A: pure interface
function stdlib_linalg_pure_${rt[0]}$${rk}$determinant(a) result(det)
!> Input matrix a[m,n]
${rt}$, intent(in), target :: a(:,:)
!> Result: matrix determinant
${rt}$ :: det

!> Local variables
type(linalg_state_type) :: err0
integer(ilp) :: m,n,info,perm,k
integer(ilp), allocatable :: ipiv(:)
${rt}$, allocatable :: amat(:,:)

!> Matrix determinant size
m = size(a,1,kind=ilp)
n = size(a,2,kind=ilp)

if (m/=n .or. .not.min(m,n)>=0) then
err0 = linalg_state_type(this,LINALG_VALUE_ERROR,'invalid or non-square matrix: a=[',m,',',n,']')
det = 0.0_${rk}$
goto 1
end if

select case (m)
case (0)

! Empty array has determinant 1 because math
det = 1.0_${rk}$

case (1)

! Scalar input
det = a(1,1)

case default

! Find determinant from LU decomposition

! Initialize a matrix temporary
allocate(amat(m,n),source=a)

! Pivot indices
allocate(ipiv(n))

! Compute determinant from LU factorization, then calculate the
! product of all diagonal entries of the U factor.
call getrf(m,n,amat,m,ipiv,info)

select case (info)
case (0)
! Success: compute determinant

! Start with real 1.0
det = 1.0_${rk}$
perm = 0
do k=1,n
if (ipiv(k)/=k) perm = perm+1
det = det*amat(k,k)
end do
if (mod(perm,2)/=0) det = -det

case (:-1)
err0 = linalg_state_type(this,LINALG_ERROR,'invalid matrix size a=[',m,',',n,']')
case (1:)
err0 = linalg_state_type(this,LINALG_ERROR,'singular matrix')
case default
err0 = linalg_state_type(this,LINALG_INTERNAL_ERROR,'catastrophic error')
end select

deallocate(amat)

end select

! Process output and return
1 call linalg_error_handling(err0)

end function stdlib_linalg_pure_${rt[0]}$${rk}$determinant

! Compute determinant of a square matrix A, with error control
function stdlib_linalg_${rt[0]}$${rk}$determinant(a,overwrite_a,err) result(det)
!> Input matrix a[m,n]
${rt}$, intent(inout), target :: a(:,:)
!> [optional] Can A data be overwritten and destroyed?
logical(lk), optional, intent(in) :: overwrite_a
!> [optional] state return flag. On error if not requested, the code will stop
type(linalg_state), optional, intent(out) :: err
type(linalg_state_type), intent(out) :: err
!> Result: matrix determinant
${rt}$ :: det

!> Local variables
type(linalg_state) :: err0
type(linalg_state_type) :: err0
integer(ilp) :: m,n,info,perm,k
integer(ilp), allocatable :: ipiv(:)
logical(lk) :: copy_a
Expand All @@ -50,7 +129,7 @@ module stdlib_linalg_determinant
n = size(a,2,kind=ilp)

if (m/=n .or. .not.min(m,n)>=0) then
err0 = linalg_state(this,LINALG_VALUE_ERROR,'invalid or non-square matrix: a=[',m,',',n,']')
err0 = linalg_state_type(this,LINALG_VALUE_ERROR,'invalid or non-square matrix: a=[',m,',',n,']')
det = 0.0_${rk}$
goto 1
end if
Expand All @@ -64,11 +143,13 @@ module stdlib_linalg_determinant

select case (m)
case (0)

! Empty array has determinant 1 because math
det = 1.0_${rk}$

case (1)
! Scalar

! Scalar input
det = a(1,1)

case default
Expand All @@ -85,8 +166,8 @@ module stdlib_linalg_determinant
! Pivot indices
allocate(ipiv(n))

! Compute determinant from LU factorization, then calculate the product of
! all diagonal entries of the U factor.
! Compute determinant from LU factorization, then calculate the
! product of all diagonal entries of the U factor.
call getrf(m,n,amat,m,ipiv,info)

select case (info)
Expand All @@ -103,11 +184,11 @@ module stdlib_linalg_determinant
if (mod(perm,2)/=0) det = -det

case (:-1)
err0 = linalg_state(this,LINALG_ERROR,'invalid matrix size a=[',m,',',n,']')
err0 = linalg_state_type(this,LINALG_ERROR,'invalid matrix size a=[',m,',',n,']')
case (1:)
err0 = linalg_state(this,LINALG_ERROR,'singular matrix')
err0 = linalg_state_type(this,LINALG_ERROR,'singular matrix')
case default
err0 = linalg_state(this,LINALG_INTERNAL_ERROR,'catastrophic error')
err0 = linalg_state_type(this,LINALG_INTERNAL_ERROR,'catastrophic error')
end select

if (.not.copy_a) deallocate(amat)
Expand All @@ -117,7 +198,7 @@ module stdlib_linalg_determinant
! Process output and return
1 call linalg_error_handling(err0,err)

end function stdlib_linalg_${ri}$determinant
end function stdlib_linalg_${rt[0]}$${rk}$determinant

#:endfor

Expand Down