Skip to content

Commit f39bf52

Browse files
committed
add source file
1 parent 3d283a7 commit f39bf52

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set(fppFiles
2727
stdlib_linalg_cross_product.fypp
2828
stdlib_linalg_solve.fypp
2929
stdlib_linalg_determinant.fypp
30+
stdlib_linalg_inverse.fypp
3031
stdlib_linalg_state.fypp
3132
stdlib_optval.fypp
3233
stdlib_selection.fypp

src/stdlib_linalg_inverse.fypp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#:include "common.fypp"
2+
! Compute matrix inverse
3+
module stdlib_linalg_inverse
4+
use stdlib_linalg_constants
5+
use stdlib_linalg_blas
6+
use stdlib_linalg_lapack
7+
use stdlib_linalg_state
8+
use iso_fortran_env,only:real32,real64,real128,int8,int16,int32,int64,stderr => error_unit
9+
implicit none(type,external)
10+
private
11+
12+
!> Function interface return the matrix inverse
13+
public :: inv
14+
!> Subroutine interface: invert matrix inplace
15+
public :: invert
16+
!> Operator interface: .inv.A returns the matrix inverse of A
17+
public :: operator(.inv.)
18+
19+
! Numpy: inv(a)
20+
! Scipy: inv(a, overwrite_a=False, check_finite=True)
21+
! IMSL: .i.a
22+
23+
! Function interface
24+
interface inv
25+
#:for rk,rt,ri in ALL_KINDS_TYPES
26+
module procedure stdlib_linalg_inverse_${ri}$
27+
#:endfor
28+
end interface inv
29+
30+
! Subroutine interface: in-place factorization
31+
interface invert
32+
#:for rk,rt,ri in ALL_KINDS_TYPES
33+
module procedure stdlib_linalg_invert_${ri}$
34+
#:endfor
35+
end interface invert
36+
37+
! Operator interface
38+
interface operator(.inv.)
39+
#:for rk,rt,ri in ALL_KINDS_TYPES
40+
module procedure stdlib_linalg_inverse_${ri}$_operator
41+
#:endfor
42+
end interface operator(.inv.)
43+
44+
contains
45+
46+
#:for rk,rt,ri in ALL_KINDS_TYPES
47+
48+
! Compute the in-place square matrix inverse of a
49+
subroutine stdlib_linalg_invert_${ri}$(a,err)
50+
!> Input matrix a[n,n]
51+
${rt}$, intent(inout) :: a(:,:)
52+
!> [optional] state return flag. On error if not requested, the code will stop
53+
type(linalg_state), optional, intent(out) :: err
54+
55+
!> Local variables
56+
type(linalg_state) :: err0
57+
integer(ilp) :: lda,n,info,nb,lwork
58+
integer(ilp), allocatable :: ipiv(:)
59+
${rt}$, allocatable :: work(:)
60+
character(*), parameter :: this = 'invert'
61+
62+
!> Problem sizes
63+
lda = size(a,1,kind=ilp)
64+
n = size(a,2,kind=ilp)
65+
66+
if (lda<1 .or. n<1 .or. lda/=n) then
67+
err0 = linalg_state(this,LINALG_VALUE_ERROR,'invalid matrix size: a=[',lda,',',n,']')
68+
goto 1
69+
end if
70+
71+
! Pivot indices
72+
allocate(ipiv(n))
73+
74+
! Factorize matrix (overwrite result)
75+
call getrf(lda,n,a,lda,ipiv,info)
76+
77+
! Return codes from getrf and getri are identical
78+
if (info==0) then
79+
80+
! Get optimal worksize (returned in work(1)) (apply 2% safety parameter)
81+
nb = stdlib_ilaenv(1,'${ri}$getri',' ',n,-1,-1,-1)
82+
lwork = nint(1.02*n*nb,kind=ilp)
83+
84+
allocate(work(lwork))
85+
86+
! Invert matrix
87+
call getri(n,a,lda,ipiv,work,lwork,info)
88+
89+
endif
90+
91+
select case (info)
92+
case (0)
93+
! Success
94+
case (:-1)
95+
err0 = linalg_state(this,LINALG_ERROR,'invalid matrix size a=[',lda,',',n,']')
96+
case (1:)
97+
! Matrix is singular
98+
err0 = linalg_state(this,LINALG_ERROR,'singular matrix')
99+
case default
100+
err0 = linalg_state(this,LINALG_INTERNAL_ERROR,'catastrophic error')
101+
end select
102+
103+
! Process output and return
104+
1 call linalg_error_handling(err0,err)
105+
106+
end subroutine stdlib_linalg_invert_${ri}$
107+
108+
! Invert matrix in place
109+
function stdlib_linalg_inverse_${ri}$(a,err) result(inva)
110+
!> Input matrix a[n,n]
111+
${rt}$, intent(in) :: a(:,:)
112+
!> Output matrix inverse
113+
${rt}$, allocatable :: inva(:,:)
114+
!> [optional] state return flag. On error if not requested, the code will stop
115+
type(linalg_state), optional, intent(out) :: err
116+
117+
!> Allocate with copy
118+
allocate(inva,source=a)
119+
120+
!> Compute matrix inverse
121+
call stdlib_linalg_invert_${ri}$(inva,err)
122+
123+
end function stdlib_linalg_inverse_${ri}$
124+
125+
! Inverse matrix operator
126+
function stdlib_linalg_inverse_${ri}$_operator(a) result(inva)
127+
!> Input matrix a[n,n]
128+
${rt}$, intent(in) :: a(:,:)
129+
!> Result matrix
130+
${rt}$, allocatable :: inva(:,:)
131+
132+
type(linalg_state) :: err
133+
134+
inva = stdlib_linalg_inverse_${ri}$(a,err)
135+
136+
! On error, return an empty matrix
137+
if (err%error()) then
138+
if (allocated(inva)) deallocate(inva)
139+
allocate(inva(0,0))
140+
endif
141+
142+
end function stdlib_linalg_inverse_${ri}$_operator
143+
144+
#:endfor
145+
146+
end module stdlib_linalg_inverse

0 commit comments

Comments
 (0)