11#:include "common.fypp"
2+ #:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES
3+ !> Determinant of a rectangular matrix
24module stdlib_linalg_determinant
35 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
89 implicit none(type,external)
910 private
1011
11- !> Determinant of a rectangular matrix
12+ !> Function interface
1213 public :: det
1314
1415 character(*), parameter :: this = 'determinant'
@@ -18,28 +19,106 @@ module stdlib_linalg_determinant
1819 ! IMSL: DET(a)
1920
2021 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
2325 #:endfor
2426 end interface det
2527
26-
2728 contains
2829
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)
32111 !> Input matrix a[m,n]
33112 ${rt}$, intent(inout), target :: a(:,:)
34113 !> [optional] Can A data be overwritten and destroyed?
35114 logical(lk), optional, intent(in) :: overwrite_a
36115 !> [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
38117 !> Result: matrix determinant
39118 ${rt}$ :: det
40119
41120 !> Local variables
42- type(linalg_state ) :: err0
121+ type(linalg_state_type ) :: err0
43122 integer(ilp) :: m,n,info,perm,k
44123 integer(ilp), allocatable :: ipiv(:)
45124 logical(lk) :: copy_a
@@ -50,7 +129,7 @@ module stdlib_linalg_determinant
50129 n = size(a,2,kind=ilp)
51130
52131 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,']')
54133 det = 0.0_${rk}$
55134 goto 1
56135 end if
@@ -64,11 +143,13 @@ module stdlib_linalg_determinant
64143
65144 select case (m)
66145 case (0)
146+
67147 ! Empty array has determinant 1 because math
68148 det = 1.0_${rk}$
69149
70150 case (1)
71- ! Scalar
151+
152+ ! Scalar input
72153 det = a(1,1)
73154
74155 case default
@@ -85,8 +166,8 @@ module stdlib_linalg_determinant
85166 ! Pivot indices
86167 allocate(ipiv(n))
87168
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.
90171 call getrf(m,n,amat,m,ipiv,info)
91172
92173 select case (info)
@@ -103,11 +184,11 @@ module stdlib_linalg_determinant
103184 if (mod(perm,2)/=0) det = -det
104185
105186 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,']')
107188 case (1:)
108- err0 = linalg_state (this,LINALG_ERROR,'singular matrix')
189+ err0 = linalg_state_type (this,LINALG_ERROR,'singular matrix')
109190 case default
110- err0 = linalg_state (this,LINALG_INTERNAL_ERROR,'catastrophic error')
191+ err0 = linalg_state_type (this,LINALG_INTERNAL_ERROR,'catastrophic error')
111192 end select
112193
113194 if (.not.copy_a) deallocate(amat)
@@ -117,7 +198,7 @@ module stdlib_linalg_determinant
117198 ! Process output and return
118199 1 call linalg_error_handling(err0,err)
119200
120- end function stdlib_linalg_${ri }$determinant
201+ end function stdlib_linalg_${rt[0]}$${rk }$determinant
121202
122203 #:endfor
123204
0 commit comments