1
1
#:include "common.fypp"
2
+ #:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
3
+ !> Determinant of a rectangular matrix
2
4
module stdlib_linalg_determinant
3
5
use stdlib_linalg_constants
4
- use stdlib_linalg_blas
5
- use stdlib_linalg_lapack
6
- use stdlib_linalg_state
7
- use iso_fortran_env,only:real32,real64,real128,int8,int16,int32,int64,stderr => error_unit
6
+ use stdlib_linalg_lapack, only: getrf
7
+ use stdlib_linalg_state, only: linalg_state_type, linalg_error_handling, LINALG_ERROR, &
8
+ LINALG_INTERNAL_ERROR, LINALG_VALUE_ERROR
8
9
implicit none(type,external)
9
10
private
10
11
11
- !> Determinant of a rectangular matrix
12
+ !> Function interface
12
13
public :: det
13
14
14
15
character(*), parameter :: this = 'determinant'
@@ -18,28 +19,106 @@ module stdlib_linalg_determinant
18
19
! IMSL: DET(a)
19
20
20
21
interface det
21
- #:for rk,rt,ri in ALL_KINDS_TYPES
22
- module procedure stdlib_linalg_${ri}$determinant
22
+ #:for rk,rt in RC_KINDS_TYPES
23
+ module procedure stdlib_linalg_${rt[0]}$${rk}$determinant
24
+ module procedure stdlib_linalg_pure_${rt[0]}$${rk}$determinant
23
25
#:endfor
24
26
end interface det
25
27
26
-
27
28
contains
28
29
29
- #:for rk,rt,ri in ALL_KINDS_TYPES
30
- ! Compute determinant of a square matrix A
31
- function stdlib_linalg_${ri}$determinant(a,overwrite_a,err) result(det)
30
+ #:for rk,rt in RC_KINDS_TYPES
31
+ ! Compute determinant of a square matrix A: pure interface
32
+ function stdlib_linalg_pure_${rt[0]}$${rk}$determinant(a) result(det)
33
+ !> Input matrix a[m,n]
34
+ ${rt}$, intent(in), target :: a(:,:)
35
+ !> Result: matrix determinant
36
+ ${rt}$ :: det
37
+
38
+ !> Local variables
39
+ type(linalg_state_type) :: err0
40
+ integer(ilp) :: m,n,info,perm,k
41
+ integer(ilp), allocatable :: ipiv(:)
42
+ ${rt}$, allocatable :: amat(:,:)
43
+
44
+ !> Matrix determinant size
45
+ m = size(a,1,kind=ilp)
46
+ n = size(a,2,kind=ilp)
47
+
48
+ if (m/=n .or. .not.min(m,n)>=0) then
49
+ err0 = linalg_state_type(this,LINALG_VALUE_ERROR,'invalid or non-square matrix: a=[',m,',',n,']')
50
+ det = 0.0_${rk}$
51
+ goto 1
52
+ end if
53
+
54
+ select case (m)
55
+ case (0)
56
+
57
+ ! Empty array has determinant 1 because math
58
+ det = 1.0_${rk}$
59
+
60
+ case (1)
61
+
62
+ ! Scalar input
63
+ det = a(1,1)
64
+
65
+ case default
66
+
67
+ ! Find determinant from LU decomposition
68
+
69
+ ! Initialize a matrix temporary
70
+ allocate(amat(m,n),source=a)
71
+
72
+ ! Pivot indices
73
+ allocate(ipiv(n))
74
+
75
+ ! Compute determinant from LU factorization, then calculate the
76
+ ! product of all diagonal entries of the U factor.
77
+ call getrf(m,n,amat,m,ipiv,info)
78
+
79
+ select case (info)
80
+ case (0)
81
+ ! Success: compute determinant
82
+
83
+ ! Start with real 1.0
84
+ det = 1.0_${rk}$
85
+ perm = 0
86
+ do k=1,n
87
+ if (ipiv(k)/=k) perm = perm+1
88
+ det = det*amat(k,k)
89
+ end do
90
+ if (mod(perm,2)/=0) det = -det
91
+
92
+ case (:-1)
93
+ err0 = linalg_state_type(this,LINALG_ERROR,'invalid matrix size a=[',m,',',n,']')
94
+ case (1:)
95
+ err0 = linalg_state_type(this,LINALG_ERROR,'singular matrix')
96
+ case default
97
+ err0 = linalg_state_type(this,LINALG_INTERNAL_ERROR,'catastrophic error')
98
+ end select
99
+
100
+ deallocate(amat)
101
+
102
+ end select
103
+
104
+ ! Process output and return
105
+ 1 call linalg_error_handling(err0)
106
+
107
+ end function stdlib_linalg_pure_${rt[0]}$${rk}$determinant
108
+
109
+ ! Compute determinant of a square matrix A, with error control
110
+ function stdlib_linalg_${rt[0]}$${rk}$determinant(a,overwrite_a,err) result(det)
32
111
!> Input matrix a[m,n]
33
112
${rt}$, intent(inout), target :: a(:,:)
34
113
!> [optional] Can A data be overwritten and destroyed?
35
114
logical(lk), optional, intent(in) :: overwrite_a
36
115
!> [optional] state return flag. On error if not requested, the code will stop
37
- type(linalg_state), optional , intent(out) :: err
116
+ type(linalg_state_type) , intent(out) :: err
38
117
!> Result: matrix determinant
39
118
${rt}$ :: det
40
119
41
120
!> Local variables
42
- type(linalg_state ) :: err0
121
+ type(linalg_state_type ) :: err0
43
122
integer(ilp) :: m,n,info,perm,k
44
123
integer(ilp), allocatable :: ipiv(:)
45
124
logical(lk) :: copy_a
@@ -50,7 +129,7 @@ module stdlib_linalg_determinant
50
129
n = size(a,2,kind=ilp)
51
130
52
131
if (m/=n .or. .not.min(m,n)>=0) then
53
- err0 = linalg_state (this,LINALG_VALUE_ERROR,'invalid or non-square matrix: a=[',m,',',n,']')
132
+ err0 = linalg_state_type (this,LINALG_VALUE_ERROR,'invalid or non-square matrix: a=[',m,',',n,']')
54
133
det = 0.0_${rk}$
55
134
goto 1
56
135
end if
@@ -64,11 +143,13 @@ module stdlib_linalg_determinant
64
143
65
144
select case (m)
66
145
case (0)
146
+
67
147
! Empty array has determinant 1 because math
68
148
det = 1.0_${rk}$
69
149
70
150
case (1)
71
- ! Scalar
151
+
152
+ ! Scalar input
72
153
det = a(1,1)
73
154
74
155
case default
@@ -85,8 +166,8 @@ module stdlib_linalg_determinant
85
166
! Pivot indices
86
167
allocate(ipiv(n))
87
168
88
- ! Compute determinant from LU factorization, then calculate the product of
89
- ! all diagonal entries of the U factor.
169
+ ! Compute determinant from LU factorization, then calculate the
170
+ ! product of all diagonal entries of the U factor.
90
171
call getrf(m,n,amat,m,ipiv,info)
91
172
92
173
select case (info)
@@ -103,11 +184,11 @@ module stdlib_linalg_determinant
103
184
if (mod(perm,2)/=0) det = -det
104
185
105
186
case (:-1)
106
- err0 = linalg_state (this,LINALG_ERROR,'invalid matrix size a=[',m,',',n,']')
187
+ err0 = linalg_state_type (this,LINALG_ERROR,'invalid matrix size a=[',m,',',n,']')
107
188
case (1:)
108
- err0 = linalg_state (this,LINALG_ERROR,'singular matrix')
189
+ err0 = linalg_state_type (this,LINALG_ERROR,'singular matrix')
109
190
case default
110
- err0 = linalg_state (this,LINALG_INTERNAL_ERROR,'catastrophic error')
191
+ err0 = linalg_state_type (this,LINALG_INTERNAL_ERROR,'catastrophic error')
111
192
end select
112
193
113
194
if (.not.copy_a) deallocate(amat)
@@ -117,7 +198,7 @@ module stdlib_linalg_determinant
117
198
! Process output and return
118
199
1 call linalg_error_handling(err0,err)
119
200
120
- end function stdlib_linalg_${ri }$determinant
201
+ end function stdlib_linalg_${rt[0]}$${rk }$determinant
121
202
122
203
#:endfor
123
204
0 commit comments