Skip to content

linalg: Matrix Inverse #828

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

Merged
merged 34 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f39bf52
add source file
perazz May 23, 2024
c0da712
working implementation
perazz May 23, 2024
92b1ac5
reorganize as `submodule`
perazz May 23, 2024
e9a3f5b
add tests
perazz May 23, 2024
b233156
option for pre-allocated pivot indices
perazz May 23, 2024
dc0127b
add examples
perazz May 23, 2024
75a5a23
document `.inv.A`
perazz May 23, 2024
bf0dfd3
document `invert`
perazz May 23, 2024
db90b37
document `inv`
perazz May 23, 2024
6a1c397
typo
perazz May 23, 2024
e10e4c4
test for singular matrix; activate `complex` matrix tests
perazz May 27, 2024
db714bb
Merge branch 'master' into matrix_inverse
perazz May 28, 2024
5f320f9
subroutine version, non in-place
perazz Jun 5, 2024
47ee61a
test subroutine version, non in-place
perazz Jun 5, 2024
e2159bc
`.inv.` operator: `error stop` on issues
perazz Jun 5, 2024
b23c811
Merge branch 'master' into matrix_inverse
perazz Jun 6, 2024
8b138f7
add non-in-place subroutine example
perazz Jun 21, 2024
513d77b
rename example programs
perazz Jun 21, 2024
5d7d7ba
Update doc/specs/stdlib_linalg.md
perazz Jun 21, 2024
63006d2
Update doc/specs/stdlib_linalg.md
perazz Jun 21, 2024
41f502e
Update doc/specs/stdlib_linalg.md
perazz Jun 21, 2024
860cbb0
Update doc/specs/stdlib_linalg.md
perazz Jun 21, 2024
80a7742
new test: random SPD matrix (real, complex)
perazz Jun 21, 2024
3c0bcdb
Update doc/specs/stdlib_linalg.md
perazz Jun 21, 2024
505f30a
lwork: overflow-safer evaluation
perazz Jun 21, 2024
d0af9be
`operator(.inv.)`: return `NaN`s on exceptions
perazz Jun 21, 2024
40062c4
Merge branch 'matrix_inverse' of github.com:perazz/stdlib into matrix…
perazz Jun 21, 2024
406e170
typo: set complex NaN
perazz Jun 21, 2024
3e7c82e
lstsq: explain singular values better
perazz Jun 21, 2024
a292e9d
Update stdlib_linalg.md
perazz Jun 27, 2024
8b52b1a
Merge branch 'master' into matrix_inverse
perazz Jun 30, 2024
7386d2d
Update src/stdlib_linalg.fypp
perazz Jul 2, 2024
35efbe8
Merge branch 'fortran-lang:master' into matrix_inverse
perazz Jul 5, 2024
bb3f7e4
remove `xdp` restriction
perazz Jul 5, 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
Prev Previous commit
Next Next commit
reorganize as submodule
  • Loading branch information
perazz committed May 23, 2024
commit 92b1ac5987ac2ca4bdf0d7c4e03f175e593e8a43
47 changes: 47 additions & 0 deletions src/stdlib_linalg.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ module stdlib_linalg
public :: operator(.det.)
public :: diag
public :: eye
public :: inv
public :: invert
public :: operator(.inv.)
public :: lstsq
public :: lstsq_space
public :: solve
Expand Down Expand Up @@ -552,6 +555,50 @@ module stdlib_linalg
#:endfor
end interface

! Function interface
interface inv
#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
module function stdlib_linalg_inverse_${ri}$(a,err) result(inva)
!> Input matrix a[n,n]
${rt}$, intent(in) :: a(:,:)
!> Output matrix inverse
${rt}$, allocatable :: inva(:,:)
!> [optional] state return flag. On error if not requested, the code will stop
type(linalg_state_type), optional, intent(out) :: err
end function stdlib_linalg_inverse_${ri}$
#:endif
#:endfor
end interface inv

! Subroutine interface: in-place factorization
interface invert
#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
module subroutine stdlib_linalg_invert_${ri}$(a,err)
!> Input matrix a[n,n]
${rt}$, intent(inout) :: a(:,:)
!> [optional] state return flag. On error if not requested, the code will stop
type(linalg_state_type), optional, intent(out) :: err
end subroutine stdlib_linalg_invert_${ri}$
#:endif
#:endfor
end interface invert

! Operator interface
interface operator(.inv.)
#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
module function stdlib_linalg_inverse_${ri}$_operator(a) result(inva)
!> Input matrix a[n,n]
${rt}$, intent(in) :: a(:,:)
!> Result matrix
${rt}$, allocatable :: inva(:,:)
end function stdlib_linalg_inverse_${ri}$_operator
#:endif
#:endfor
end interface operator(.inv.)

contains


Expand Down
92 changes: 32 additions & 60 deletions src/stdlib_linalg_inverse.fypp
Original file line number Diff line number Diff line change
@@ -1,60 +1,40 @@
#:include "common.fypp"
#:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
module stdlib_linalg_inverse
submodule (stdlib_linalg) stdlib_linalg_inverse
!! Compute inverse of a square matrix
use stdlib_linalg_constants
use stdlib_linalg_lapack, only: getri,getrf,stdlib_ilaenv
use stdlib_linalg_state, only: linalg_state_type, linalg_error_handling, LINALG_ERROR, &
LINALG_INTERNAL_ERROR, LINALG_VALUE_ERROR
implicit none(type,external)
private

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

!> Function interface return the matrix inverse
public :: inv
!> Subroutine interface: invert matrix inplace
public :: invert
!> Operator interface: .inv.A returns the matrix inverse of A
public :: operator(.inv.)

! Numpy: inv(a)
! Scipy: inv(a, overwrite_a=False, check_finite=True)
! IMSL: .i.a

! Function interface
interface inv
#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
module procedure stdlib_linalg_inverse_${ri}$
#:endif
#:endfor
end interface inv

! Subroutine interface: in-place factorization
interface invert
#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
module procedure stdlib_linalg_invert_${ri}$
#:endif
#:endfor
end interface invert

! Operator interface
interface operator(.inv.)
#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
module procedure stdlib_linalg_inverse_${ri}$_operator
#:endif
#:endfor
end interface operator(.inv.)

contains

elemental subroutine handle_getri_info(info,lda,n,err)
integer(ilp), intent(in) :: info,lda,n
type(linalg_state_type), intent(out) :: err

! Process output
select case (info)
case (0)
! Success
case (:-1)
err = linalg_state_type(this,LINALG_ERROR,'invalid matrix size a=',[lda,n])
case (1:)
! Matrix is singular
err = linalg_state_type(this,LINALG_ERROR,'singular matrix')
case default
err = linalg_state_type(this,LINALG_INTERNAL_ERROR,'catastrophic error')
end select

end subroutine handle_getri_info

#:for rk,rt,ri in RC_KINDS_TYPES
#:if rk!="xdp"
! Compute the in-place square matrix inverse of a
subroutine stdlib_linalg_invert_${ri}$(a,err)
module subroutine stdlib_linalg_invert_${ri}$(a,err)
!> Input matrix a[n,n]
${rt}$, intent(inout) :: a(:,:)
!> [optional] state return flag. On error if not requested, the code will stop
Expand All @@ -72,7 +52,8 @@ module stdlib_linalg_inverse

if (lda<1 .or. n<1 .or. lda/=n) then
err0 = linalg_state_type(this,LINALG_VALUE_ERROR,'invalid matrix size: a=[',lda,',',n,']')
goto 1
call linalg_error_handling(err0,err)
return
end if

! Pivot indices
Expand All @@ -84,9 +65,9 @@ module stdlib_linalg_inverse
! Return codes from getrf and getri are identical
if (info==0) then

! Get optimal worksize (returned in work(1)) (inflate by a 2% safety margin)
! Get optimal worksize (returned in work(1)) (inflate by a 5% safety margin)
nb = stdlib_ilaenv(1,'${ri}$getri',' ',n,-1,-1,-1)
lwork = ceiling(1.02*n*nb,kind=ilp)
lwork = ceiling(1.05*n*nb,kind=ilp)

allocate(work(lwork))

Expand All @@ -95,25 +76,16 @@ module stdlib_linalg_inverse

endif

select case (info)
case (0)
! Success
case (:-1)
err0 = linalg_state_type(this,LINALG_ERROR,'invalid matrix size a=[',lda,',',n,']')
case (1:)
! Matrix is singular
err0 = linalg_state_type(this,LINALG_ERROR,'singular matrix')
case default
err0 = linalg_state_type(this,LINALG_INTERNAL_ERROR,'catastrophic error')
end select
! Process output
call handle_getri_info(info,lda,n,err0)

! Process output and return
1 call linalg_error_handling(err0,err)
call linalg_error_handling(err0,err)

end subroutine stdlib_linalg_invert_${ri}$

! Invert matrix in place
function stdlib_linalg_inverse_${ri}$(a,err) result(inva)
module function stdlib_linalg_inverse_${ri}$(a,err) result(inva)
!> Input matrix a[n,n]
${rt}$, intent(in) :: a(:,:)
!> Output matrix inverse
Expand All @@ -130,7 +102,7 @@ module stdlib_linalg_inverse
end function stdlib_linalg_inverse_${ri}$

! Inverse matrix operator
function stdlib_linalg_inverse_${ri}$_operator(a) result(inva)
module function stdlib_linalg_inverse_${ri}$_operator(a) result(inva)
!> Input matrix a[n,n]
${rt}$, intent(in) :: a(:,:)
!> Result matrix
Expand All @@ -140,12 +112,12 @@ module stdlib_linalg_inverse

inva = stdlib_linalg_inverse_${ri}$(a,err0)

! On error, return an empty matrix
! On error, return zeros
if (err0%error()) inva = 0.0_${rk}$

end function stdlib_linalg_inverse_${ri}$_operator

#:endif
#:endfor

end module stdlib_linalg_inverse
end submodule stdlib_linalg_inverse