@@ -126,104 +126,164 @@ submodule (stdlib_linalg) stdlib_linalg_schur
126
126
end subroutine get_schur_${ri}$_workspace
127
127
128
128
! Schur decomposition subroutine
129
- pure module subroutine stdlib_linalg_${ri}$_schur(a, t, z, lwork, overwrite_a, sort , err)
130
- !> Input matrix a[m, m]
129
+ subroutine stdlib_linalg_${ri}$_schur(a, t, z, eigvals, storage , err)
130
+ !> Input matrix a[m,m]
131
131
${rt}$, intent(inout), target :: a(:,:)
132
- !> Schur form of the matrix A
132
+ !> Schur form of A: upper-triangular or quasi-upper-triangular matrix T
133
133
${rt}$, intent(out), contiguous, target :: t(:,:)
134
- !> Unitary/orthogonal matrix Z
135
- ${rt}$, intent(out), contiguous, target :: z(:,:)
136
- !> Workspace size (optional)
137
- integer(ilp), optional, intent(inout) :: lwork
138
- !> Overwrite input matrix A? (optional)
139
- logical(lk), optional, intent(in) :: overwrite_a
140
- !> Sorting eigenvalues? (optional)
141
- logical(lk), optional, intent(in) :: sort
142
- !> State return flag. On error if not requested, the code will stop
143
- type(linalg_state_type), optional, intent(out) :: err
134
+ !> Unitary/orthonormal transformation matrix Z
135
+ ${rt}$, optional, intent(out), contiguous, target :: z(:,:)
136
+ !> [optional] Output eigenvalues that appear on the diagonal of T
137
+ complex(${rk}$), optional, intent(out), contiguous, target :: eigvals(:)
138
+ !> [optional] Provide pre-allocated workspace, size to be checked with schur_space
139
+ ${rt}$, optional, intent(inout), target :: storage(:)
140
+ !> [optional] State return flag. On error if not requested, the code will stop
141
+ type(linalg_state), optional, intent(out) :: err
144
142
145
143
! Local variables
146
- type(linalg_state_type) :: err0
147
- integer(ilp) :: m, lda, info, liwork
148
- logical(lk) :: overwrite_a_
149
- logical, pointer :: bwork(:)
150
- integer(ilp), allocatable :: iwork(:)
151
- ${rt}$, pointer :: amat(:,:), tau(:), work(:)
152
- ${rt}$ :: rwork_dummy(1) ! Dummy for real/complex cases
153
- ${rt}$, allocatable :: tmat(:,:), zmat(:,:)
154
- character :: jobz
155
-
144
+ integer(ilp) :: m,n,mt,nt,ldvs,nvs,lde,lwork,sdim,info
145
+ logical(lk), target :: bwork_dummy(1),local_eigs
146
+ logical(lk), pointer :: bwork(:)
147
+ real(${rk}$), allocatable :: rwork(:)
148
+ ${rt}$, target :: vs_dummy(1,1)
149
+ ${rt}$, pointer :: vs(:,:),work(:),eigs(:)#{if rt.startswith('r')}#,eigi(:)#{endif}#
150
+ character :: jobvs,sort
151
+ type(linalg_state) :: err0
152
+
156
153
! Problem size
157
- m = size(a, 1, kind=ilp)
158
- lda = size(a, 1, kind=ilp)
159
-
154
+ m = size(a, 1, kind=ilp)
155
+ n = size(a, 2, kind=ilp)
156
+ mt = size(t, 1, kind=ilp)
157
+ nt = size(t, 2, kind=ilp)
158
+
160
159
! Validate dimensions
161
- if (size(a, 1, kind=ilp) /= size(a, 2, kind=ilp) ) then
162
- err0 = linalg_state_type (this, LINALG_VALUE_ERROR, 'Matrix A must be square: a =', [size(a,1), size(a,2) ])
160
+ if (m/=n .or. m<=0 .or. n<=0 ) then
161
+ err0 = linalg_state (this, LINALG_VALUE_ERROR, 'Matrix A must be square: size(a) =',[m,n ])
163
162
call linalg_error_handling(err0, err)
164
163
return
165
- end if
166
-
167
- ! Set default values
168
- overwrite_a_ = .false._lk
169
- if (present(overwrite_a)) overwrite_a_ = overwrite_a
170
-
171
- ! Job type based on sorting request
172
- if (present(sort) .and. sort) then
173
- jobz = 'S' ! Compute and sort eigenvalues
164
+ end if
165
+ if (mt/=nt .or. mt/=n .or. nt/=n) then
166
+ err0 = linalg_state(this, LINALG_VALUE_ERROR, 'Matrix T must be square: size(T)=',[mt,nt], &
167
+ 'should be',[m,n])
168
+ call linalg_error_handling(err0, err)
169
+ return
170
+ end if
171
+
172
+ !> Copy data into the output array
173
+ t = a
174
+
175
+ !> SORTING: no sorting options are currently supported
176
+ sort = gees_sort_eigs(.false.)
177
+ sdim = 0_ilp
178
+
179
+ if (sort/=GEES_NOT) then
180
+
181
+ allocate(bwork(n),source=.false.)
182
+
174
183
else
175
- jobz = 'N' ! Compute Schur decomposition without sorting
176
- end if
177
-
178
- ! Prepare storage
179
- allocate(tmat(m, m), source=0.0_${rk}$)
180
- allocate(zmat(m, m), source=0.0_${rk}$)
181
-
182
- if (overwrite_a_) then
183
- amat => a
184
+
185
+ bwork => bwork_dummy
186
+
187
+ end if
188
+
189
+ !> Schur vectors
190
+ jobvs = gees_vectors(present(z))
191
+ if (present(z)) then
192
+ vs => z
193
+
194
+ ldvs = size(vs, 1, kind=ilp)
195
+ nvs = size(vs, 2, kind=ilp)
196
+
197
+ if (ldvs<n .or. nvs/=n) then
198
+ err0 = linalg_state(this, LINALG_VALUE_ERROR, 'Schur vectors size=',[ldvs,nvs], &
199
+ 'should be n=',n)
200
+ goto 1
201
+ end if
202
+
184
203
else
185
- allocate(amat(m, m), source=a)
204
+ vs => vs_dummy
205
+ ldvs = size(vs, 1, kind=ilp)
206
+ nvs = size(vs, 2, kind=ilp)
186
207
end if
187
-
188
- ! Allocate workspace
189
- liwork = -1
190
- if (present(lwork)) then
191
- allocate(work(lwork))
208
+
209
+ !> User or self-allocated storage
210
+ if (present(storage)) then
211
+
212
+ work => storage
213
+ lwork = size(work, 1, kind=ilp)
214
+
192
215
else
193
- allocate(work(1)) ! Temporary workspace for querying size
216
+
217
+ ! Query optimal workspace
218
+ call get_schur_${ri}$_workspace(a,lwork,err0)
219
+ if (err0%error()) goto 1
220
+ allocate(work(lwork))
221
+
194
222
end if
195
-
196
- ! Workspace query
197
- call #{if rt.startswith('complex')}# zgees #{else}# gees #{endif}# &
198
- (jobz, 'N', nullify(bwork), m, amat, lda, tau, zmat, lda, work, liwork, iwork, info)
199
- call handle_gees_info(info, m, .false._lk, err0)
200
- if (err0%error()) then
201
- call linalg_error_handling(err0, err)
202
- return
223
+
224
+ !> User or self-allocated eigenvalue storage
225
+ if (present(eigvals)) then
226
+
227
+ lde = size(eigvals, 1, kind=ilp)
228
+
229
+ #:if rt.startswith('c')
230
+ eigs => eigvals
231
+ local_eigs = .false.
232
+ #:else
233
+ allocate(eigs(n),eigi(n))
234
+ local_eigs = .true.
235
+ #:endif
236
+
237
+ else
238
+
239
+ allocate(eigs(n)#{if rt.startswith('r')}#,eigi(n)#{endif}#)
240
+ local_eigs = .true.
241
+ lde = n
242
+
203
243
end if
244
+
245
+ #:if rt.startswith('c')
246
+ allocate(rwork(n))
247
+ #:endif
204
248
205
- ! Update workspace size
206
- if (.not.present(lwork)) then
207
- liwork = ceiling(real(work(1), kind=${rk}$), kind=ilp)
208
- deallocate(work)
209
- allocate(work(liwork))
210
- end if
249
+ if (lde<n) then
250
+ err0 = linalg_state(this, LINALG_VALUE_ERROR, 'Insufficient eigenvalue array size=',lde, &
251
+ 'should be >=',n)
252
+ goto 2
253
+ end if
211
254
212
255
! Compute Schur decomposition
213
- call #{if rt.startswith('complex')}# zgees #{else}# gees #{endif}# &
214
- (jobz, 'N', nullify(bwork), m, amat, lda, tau, zmat, lda, work, liwork, iwork, info)
215
- call handle_gees_info(info, m, present(sort) .and. sort, err0)
216
- if (err0%error()) then
217
- call linalg_error_handling(err0, err)
218
- return
219
- end if
256
+ call gees(jobvs,sort,eig_select,nt,t,mt,sdim,eigs,#{if rt.startswith('r')}#eigi,#{endif}# &
257
+ vs,ldvs,work,lwork,#{if rt.startswith('c')}#rwork,#{endif}#bwork,info)
258
+ call handle_gees_info(info,m,n,m,err0)
220
259
221
- ! Output results
222
- t = amat
223
- z = zmat
260
+ 2 eigenvalue_output: if (local_eigs) then
261
+ #:if rt.startswith('r')
262
+ ! Build complex eigenvalues
263
+ eigvals = cmplx(eigs,eigi,kind=${rk}$)
264
+ deallocate(eigs,eigi)
265
+ #:else
266
+ deallocate(eigs)
267
+ #:endif
268
+ endif eigenvalue_output
269
+ if (.not.present(storage)) deallocate(work)
270
+ 1 if (sort/=GEES_NOT) deallocate(bwork)
271
+ call linalg_error_handling(err0,err)
272
+
273
+ contains
274
+
275
+ ! Dummy select routine: currently, no sorting options are offered
276
+ pure logical(lk) function eig_select(alpha#{if rt.startswith('r')}#r,alphai#{endif}#)
277
+ #:if rt.startswith('r')
278
+ ${rt}$, intent(in) :: alphar,alphai
279
+ complex(${rk}$) :: alpha
280
+ alpha = cmplx(alphar,alphai,kind=${rk}$)
281
+ #:else
282
+ ${rt}$, intent(in) :: alpha
283
+ #:endif
284
+ eig_select = .false.
285
+ end function eig_select
224
286
225
- if (.not.overwrite_a_) deallocate(amat)
226
- if (.not.present(lwork)) deallocate(work)
227
287
end subroutine stdlib_linalg_${ri}$_schur
228
288
229
289
#:endfor
0 commit comments