Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Copyright 2011-2013 Kwant authors. 

2# 

3# This file is part of Kwant. It is subject to the license terms in the file 

4# LICENSE.rst found in the top-level directory of this distribution and at 

5# https://kwant-project.org/license. A list of Kwant authors can be found in 

6# the file AUTHORS.rst at the top-level directory of this distribution and at 

7# https://kwant-project.org/authors. 

8 

9__all__ = ['schur', 'convert_r2c_schur', 'order_schur', 'evecs_from_schur', 

10 'gen_schur', 'order_gen_schur', 'convert_r2c_gen_schur', 

11 'evecs_from_gen_schur'] 

12 

13from math import sqrt 

14import numpy as np 

15from . import lapack 

16 

17 

18def schur(a, calc_q=True, calc_ev=True, overwrite_a=False): 

19 """Compute the Schur form of a square matrix a. 

20 

21 The Schur form is a decomposition of the form a = q * t * q^dagger, where q 

22 is a unitary matrix and t a upper triagonal matrix when computing the Schur 

23 form of a complex matrix, and a quasi-upper triagonal matrix with only 1x1 

24 and 2x2 blocks on the diagonal when computing the Schur form of a real 

25 matrix (In the latter case, the 1x1 blocks correspond to real eigenvalues, 

26 the 2x2 blocks to conjugate pairs of complex eigenvalues). 

27 

28 The Schur form is closely related to the eigenvalue problem (the entries of 

29 the diagonal of the complex Schur form are the eigenvalues of the matrix), 

30 and the routine can optionally also return the eigenvalues. 

31 

32 Parameters 

33 ---------- 

34 a : array, shape (M, M) 

35 Matrix for which to compute the Schur form. 

36 calc_q : boolean 

37 Whether to compute the unitary/orthogonal matrix `q`. 

38 calc_ev : boolean 

39 Whether to return the eigenvalues as a separate array. 

40 overwrite_a : boolean 

41 Whether to overwrite data in `a` (may increase performance). 

42 

43 Returns 

44 ------- 

45 t : array, shape (M, M) 

46 Schur form of the original matrix (complex or real, depending on the 

47 input matrix). 

48 

49 (if calc_q == True) 

50 q : array, shape (M, M) 

51 Unitary transformation matrix. 

52 

53 (if calc_ev == True) 

54 ev: array, shape (M,) 

55 Array of eigenvalues of the matrix `a`. Can be complex even if a is 

56 real. In the latter case, the complex eigenvalues come in conjugated 

57 pairs with the eigenvalue with positive imaginary part coming 

58 first. 

59 

60 Raises 

61 ------ 

62 LinAlgError 

63 If the underlying QR iteration fails to converge. 

64 """ 

65 a = lapack.prepare_for_lapack(overwrite_a, a) 

66 return lapack.gees(a, calc_q, calc_ev) 

67 

68 

69def convert_r2c_schur(t, q): 

70 """Convert a real Schur form (with possibly 2x2 blocks on the diagonal) 

71 into a complex Schur form that is completely triangular. 

72 

73 This function is equivalent to the scipy.linalg.rsf2csf pendant (though the 

74 implementation is different), but there is additionally the guarantee that 

75 in the case of a 2x2 block at rows and columns i and i+1, t[i, i] will 

76 contain the eigenvalue with the positive part, and t[i+1, i+1] the one with 

77 the negative part. This ensures that the list of eigenvalues (more 

78 precisely, their order) returned originally from schur() is still valid for 

79 the newly formed complex Schur form. 

80 

81 Parameters 

82 ---------- 

83 t : array, shape (M, M) 

84 Real Schur form of the original matrix 

85 q : array, shape (M, M) 

86 Schur transformation matrix 

87 

88 Returns 

89 ------- 

90 t : array, shape (M, M) 

91 Complex Schur form of the original matrix 

92 q : array, shape (M, M) 

93 Schur transformation matrix corresponding to the complex form 

94 """ 

95 

96 # First find the positions of 2x2-blocks 

97 blockpos = np.diagonal(t, -1).nonzero()[0] 

98 

99 # Check if there are actually any 2x2-blocks 

100 if not blockpos.size: 

101 return (t, q) 

102 else: 

103 t2 = t.astype(np.common_type(t, np.array([], np.complex64))) 

104 q2 = q.astype(np.common_type(q, np.array([], np.complex64))) 

105 

106 for i in blockpos: 

107 # Bringing a 2x2 block to complex triangular form is relatively simple: 

108 # the 2x2 blocks are guaranteed to be of the form [[a, b], [c, a]], 

109 # where b*c < 0. The eigenvalues of this matrix are a +/- i sqrt(-b*c), 

110 # the corresponding eigenvectors are [ +/- sqrt(-b*c), c]. The Schur 

111 # form can be achieved by a unitary 2x2 matrix with one of the 

112 # eigenvectors in the first column, and the second column an orthogonal 

113 # vector. 

114 

115 a = t[i, i] 

116 b = t[i, i+1] 

117 c = t[i+1, i] 

118 

119 x = 1j * sqrt(-b * c) 

120 y = c 

121 norm = sqrt(-b * c + c * c) 

122 

123 U = np.array([[x / norm, -y / norm], [y / norm, -x / norm]]) 

124 

125 t2[i, i] = a + x 

126 t2[i+1, i] = 0 

127 t2[i, i+1] = -b - c 

128 t2[i+1, i+1] = a - x 

129 

130 t2[:i, i:i+2] = np.dot(t2[:i, i:i+2], U) 

131 t2[i:i+2, i+2:] = np.dot(np.conj(U.T), t2[i:i+2, i+2:]) 

132 

133 q2[:, i:i+2] = np.dot(q2[:, i:i+2], U) 

134 

135 return t2, q2 

136 

137 

138def order_schur(select, t, q, calc_ev=True, overwrite_tq=False): 

139 """Reorder the Schur form, selecting a cluster of eigenvalues. 

140 

141 This function reorders the generalized Schur form such that the cluster of 

142 eigenvalues determined by select appears in the leading diagonal block of 

143 the Schur form (this is useful, as the Schur vectors corresponding to the 

144 leading diagonal block form an orthogonal basis for the subspace of 

145 eigenvectors). 

146 

147 If a real Schur form is reordered, it is converted to complex form 

148 (eliminating the 2x2 blocks on the diagonal) if in a complex conjugated 

149 pair of eigenvalues only one eigenvalue is chosen. In this case, the real 

150 Schur from cannot be reordered in real form without splitting a 2x2 block 

151 on the diagonal, hence switching to complex form is mandatory. 

152 

153 Parameters 

154 ---------- 

155 t : array, shape (M, M) 

156 Schur form 

157 q : array, shape (M, M) 

158 Unitary/orthogonal transformation matrices. 

159 calc_ev : boolean, optional 

160 Whether to return the reordered generalized eigenvalues of as two 

161 separate arrays. Default: True 

162 overwrite_tq : boolean, optional 

163 Whether to overwrite data in `t` and `q` (may increase performance) 

164 Default: False 

165 

166 Returns 

167 ------- 

168 t : array, shape (M, M) 

169 Reordered Schur form. If the original Schur form is real, and the 

170 desired reordering separates complex conjugated pairs of generalized 

171 eigenvalues, the resulting Schur form will be complex. 

172 q : array, shape (M, M) 

173 Unitary/orthogonal transformation matrix. Only computed if q is 

174 provided (not None) as input. If the Schur form is converted from real 

175 to complex, the transformation matrix is also converted from real 

176 orthogonal to complex unitary 

177 alpha : array, shape (M) 

178 beta : array, shape (M) 

179 Reordered eigenvalues. If the reordered Schur form is real, complex 

180 conjugated pairs of eigenvalues are ordered such that the eigenvalue 

181 with the positive imaginary part comes first. Only computed if 

182 ``calc_ev == True`` 

183 """ 

184 

185 t, q = lapack.prepare_for_lapack(overwrite_tq, t, q) 

186 

187 # Figure out if select is a function or array. 

188 isfun = isarray = True 

189 try: 

190 select(0) 

191 except: 

192 isfun = False 

193 try: 

194 select[0] 

195 except: 

196 isarray = False 

197 

198 if not (isarray or isfun): 198 ↛ 199line 198 didn't jump to line 199, because the condition on line 198 was never true

199 raise ValueError("select must be either a function or an array") 

200 elif isarray: 

201 select = np.array(select, dtype=lapack.logical_dtype, order='F') 

202 else: 

203 select = np.array(np.vectorize(select)(np.arange(t.shape[0])), 

204 dtype=lapack.logical_dtype, order='F') 

205 

206 # Now check if the reordering can actually be done as desired, 

207 # if we have a real Schur form (i.e. if the 2x2 blocks would be 

208 # separated). If this is the case, convert to complex Schur form first. 

209 for i in np.diagonal(t, -1).nonzero()[0]: 

210 if bool(select[i]) != bool(select[i+1]): 

211 t, q = convert_r2c_schur(t, q) 

212 return order_schur(select, t, q, calc_ev, True) 

213 

214 return lapack.trsen(select, t, q, calc_ev) 

215 

216 

217def evecs_from_schur(t, q, select=None, left=False, right=True, 

218 overwrite_tq=False): 

219 """Compute eigenvectors from Schur form. 

220 

221 This function computes either all or selected eigenvectors for the matrix 

222 that is represented by the Schur form t and the unitary matrix q, (not the 

223 eigenvectors of t, but of q*t*q^dagger). 

224 

225 Parameters 

226 ---------- 

227 t : array, shape (M, M) 

228 Schur form 

229 q : array, shape (M, M) 

230 Unitary/orthogonal transformation matrix. 

231 select : boolean function or array, optional 

232 The value of ``select(i)`` or ``select[i]`` is used to decide whether 

233 the eigenvector corresponding to the i-th eigenvalue should be 

234 computed or not. If select is not provided (None), all eigenvectors 

235 are computed. Default: None 

236 left : boolean, optional 

237 Whether to compute left eigenvectors. Default: False 

238 right : boolean, optional 

239 Whether to compute right eigenvectors. Default: True 

240 overwrite_tq : boolean, optional 

241 Whether to overwrite data in `t` and `q` (may increase performance) 

242 Default: False 

243 

244 Returns 

245 ------- 

246 vl : array, shape(M, N) 

247 Left eigenvectors. N is the number of eigenvectors selected b 

248 `select`, or equal to M if select is not provided. The eigenvectors 

249 may be complex, even if `t` and `q` are real. Only computed if 

250 ``left == True``. 

251 vr : array, shape(M, N) 

252 Right eigenvectors. N is the number of eigenvectors selected by 

253 `select`, or equal to M if select is not provided. The eigenvectors 

254 may be complex, even if `t` and `q` are real. Only computed if 

255 ``right == True``. 

256 """ 

257 

258 t, q = lapack.prepare_for_lapack(overwrite_tq, t, q) 

259 

260 # check if select is a function or an array 

261 if select is not None: 

262 isfun = isarray = True 

263 try: 

264 select(0) 

265 except: 

266 isfun = False 

267 

268 try: 

269 select[0] 

270 except: 

271 isarray = False 

272 

273 if not (isarray or isfun): 273 ↛ 274line 273 didn't jump to line 274, because the condition on line 273 was never true

274 raise ValueError("select must be either a function, " 

275 "an array or None") 

276 elif isarray: 

277 selectarr = np.array(select, dtype=lapack.logical_dtype, 

278 order='F') 

279 else: 

280 selectarr = np.array(np.vectorize(select)(np.arange(t.shape[0])), 

281 dtype=lapack.logical_dtype, order='F') 

282 else: 

283 selectarr = None 

284 

285 return lapack.trevc(t, q, selectarr, left, right) 

286 

287 

288def gen_schur(a, b, calc_q=True, calc_z=True, calc_ev=True, 

289 overwrite_ab=False): 

290 """Compute the generalized Schur form of a matrix pencil (a, b). 

291 

292 The generalized Schur form is a decomposition of the form a = q * s * 

293 z^dagger and b = q * t * z^dagger, where q and z are unitary matrices 

294 (orthogonal for real input), t is an upper triagonal matrix with 

295 non-negative real diagonal, and s is a upper triangular matrix for complex 

296 matrices, and a quasi-upper triangular matrix with only 1x1 and 2x2 blocks 

297 on the diagonal for real matrices. (In the latter case, the 1x1 blocks 

298 correspond to real generalized eigenvalues, the 2x2 blocks to conjugate 

299 pairs of complex generalized eigenvalues). 

300 

301 The generalized Schur form is closely related to the generalized eigenvalue 

302 problem (the entries of the diagonal of the complex Schur form are the 

303 eigenvalues of the matrix, for example), and the routine can optionally 

304 also return the generalized eigenvalues in the form (alpha, beta), such 

305 that alpha/beta is a generalized eigenvalue of the pencil (a, b) (see also 

306 gen_eig()). 

307 

308 Parameters 

309 ---------- 

310 a : array, shape (M, M) 

311 b : array, shape (M, M) 

312 Matrix pencil for which to compute the generalized Schur form 

313 calc_q : boolean, optional 

314 calc_z : boolean, optional 

315 Whether to compute the unitary/orthogonal matrices `q` and `z`. 

316 Default: True 

317 calc_ev : boolean, optional 

318 Whether to return the generalized eigenvalues as two separate 

319 arrays. Default: True 

320 overwrite_ab : boolean, optional 

321 Whether to overwrite data in `a` and `b` (may increase performance) 

322 Default: False 

323 

324 Returns 

325 ------- 

326 s : array, shape (M, M) 

327 t : array, shape (M, M) 

328 Generalized Schur form of the original matrix pencil (`a`,`b`) 

329 (complex or real, depending on the input matrices) 

330 q : array, shape (M, M) 

331 z : array, shape (M, M) 

332 Unitary/orthogonal transformation matrices. Only computed if 

333 ``calc_q == True`` or ``calc_z == True``, respectively. 

334 alpha : array, shape (M) 

335 beta : array, shape (M) 

336 Generalized eigenvalues of the matrix pencil (`a`, `b`) given 

337 as numerator (`alpha`) and denominator (`beta`), such that the 

338 generalized eigenvalues are given as ``alpha/beta``. alpha can 

339 be complex even if a is real. In the latter case, complex 

340 eigenvalues come in conjugated pairs with the eigenvalue with 

341 positive imaginary part coming first. Only computed if 

342 ``calc_ev == True``. 

343 

344 Raises 

345 ------ 

346 LinAlError 

347 If the underlying QZ iteration fails to converge. 

348 """ 

349 a, b = lapack.prepare_for_lapack(overwrite_ab, a, b) 

350 return lapack.gges(a, b, calc_q, calc_z, calc_ev) 

351 

352 

353def order_gen_schur(select, s, t, q=None, z=None, calc_ev=True, 

354 overwrite_stqz=False): 

355 """Reorder the generalized Schur form. 

356 

357 This function reorders the generalized Schur form such that the cluster of 

358 eigenvalues determined by select appears in the leading diagonal blocks of 

359 the Schur form (this is useful, as the Schur vectors corresponding to the 

360 leading diagonal blocks form an orthogonal basis for the subspace of 

361 eigenvectors). 

362 

363 If a real generalized Schur form is reordered, it is converted to complex 

364 form (eliminating the 2x2 blocks on the diagonal) if in a complex 

365 conjugated pair of eigenvalues only one eigenvalue is chosen. In this 

366 case, the real Schur from cannot be reordered in real form without 

367 splitting a 2x2 block on the diagonal, hence switching to complex form is 

368 mandatory. 

369 

370 Parameters 

371 ---------- 

372 s : array, shape (M, M) 

373 t : array, shape (M, M) 

374 Matrices describing the generalized Schur form. 

375 q : array, shape (M, M), optional 

376 z : array, shape (M, M), optional 

377 Unitary/orthogonal transformation matrices. Default: None. 

378 calc_ev : boolean, optional 

379 Whether to return the reordered generalized eigenvalues of as two 

380 separate arrays. Default: True. 

381 overwrite_stqz : boolean, optional 

382 Whether to overwrite data in `s`, `t`, `q`, and `z` (may 

383 increase performance) Default: False. 

384 

385 Returns 

386 ------- 

387 s : array, shape (M, M) 

388 t : array, shape (M, M) 

389 Reordered general Schur form. If the original Schur form is real, and 

390 the desired reordering separates complex conjugated pairs of 

391 generalized eigenvalues, the resulting Schur form will be complex. 

392 q : array, shape (M, M) 

393 z : array, shape (M, M) 

394 Unitary/orthogonal transformation matrices. Only computed if 

395 `q` and `z` are provided (not None) on entry, respectively. If 

396 the generalized Schur form is converted from real to complex, 

397 the transformation matrices are also converted from real 

398 orthogonal to complex unitary 

399 alpha : array, shape (M) 

400 beta : array, shape (M) 

401 Reordered generalized eigenvalues. If the reordered Schur form is real, 

402 complex conjugated pairs of eigenvalues are ordered such that the 

403 eigenvalue with the positive imaginary part comes first. Only computed 

404 if ``calc_ev == True``. 

405 

406 Raises 

407 ------ 

408 LinAlError 

409 If the problem is too ill-conditioned. 

410 """ 

411 s, t, q, z = lapack.prepare_for_lapack(overwrite_stqz, s, t, q, z) 

412 

413 

414 # Figure out if select is a function or array. 

415 isfun = isarray = True 

416 try: 

417 select(0) 

418 except: 

419 isfun = False 

420 try: 

421 select[0] 

422 except: 

423 isarray = False 

424 

425 if not (isarray or isfun): 425 ↛ 426line 425 didn't jump to line 426, because the condition on line 425 was never true

426 raise ValueError("select must be either a function or an array") 

427 elif isarray: 

428 select = np.array(select, dtype=lapack.logical_dtype, order='F') 

429 else: 

430 select = np.array(np.vectorize(select)(np.arange(t.shape[0])), 

431 dtype=lapack.logical_dtype, order='F') 

432 

433 # Now check if the reordering can actually be done as desired, if we have a 

434 # real Schur form (i.e. if the 2x2 blocks would be separated). If this is 

435 # the case, convert to complex Schur form first. 

436 for i in np.diagonal(s, -1).nonzero()[0]: 

437 if bool(select[i]) != bool(select[i+1]): 

438 # Convert to complex Schur form 

439 if q is not None and z is not None: 439 ↛ 441line 439 didn't jump to line 441, because the condition on line 439 was never false

440 s, t, q, z = convert_r2c_gen_schur(s, t, q, z) 

441 elif q is not None: 

442 s, t, q = convert_r2c_gen_schur(s, t, q=q, z=None) 

443 elif z is not None: 

444 s, t, z = convert_r2c_gen_schur(s, t, q=None, z=z) 

445 else: 

446 s, t = convert_r2c_gen_schur(s, t) 

447 

448 return order_gen_schur(select, s, t, q, z, calc_ev, True) 

449 

450 return lapack.tgsen(select, s, t, q, z, calc_ev) 

451 

452 

453def convert_r2c_gen_schur(s, t, q=None, z=None): 

454 """Convert a real generallzed Schur form (with possibly 2x2 blocks on the 

455 diagonal) into a complex Schur form that is completely triangular. If the 

456 input is already completely triagonal (real or complex), the input is 

457 returned unchanged. 

458 

459 This function guarantees that in the case of a 2x2 block at rows and 

460 columns i and i+1, the converted, complex Schur form will contain the 

461 generalized eigenvalue with the positive imaginary part in s[i,i] and 

462 t[i,i], and the one with the negative imaginary part in s[i+1,i+1] and 

463 t[i+1,i+1]. This ensures that the list of eigenvalues (more precisely, 

464 their order) returned originally from gen_schur() is still valid for the 

465 newly formed complex Schur form. 

466 

467 Parameters 

468 ---------- 

469 s : array, shape (M, M) 

470 t : array, shape (M, M) 

471 Real generalized Schur form of the original matrix 

472 q : array, shape (M, M), optional 

473 z : array, shape (M, M), optional 

474 Schur transformation matrix. Default: None 

475 

476 Returns 

477 ------- 

478 s : array, shape (M, M) 

479 t : array, shape (M, M) 

480 Complex generalized Schur form of the original matrix, 

481 completely triagonal 

482 q : array, shape (M, M) 

483 z : array, shape (M, M) 

484 Schur transformation matrices corresponding to the complex 

485 form. `q` or `z` are only computed if they are provided (not 

486 None) on input. 

487 

488 Raises 

489 ------ 

490 LinAlgError 

491 If it fails to convert a 2x2 block into complex form (unlikely). 

492 """ 

493 

494 s, t, q, z = lapack.prepare_for_lapack(True, s, t, q, z) 

495 # Note: overwrite=True does not mean much here, the arrays are all copied 

496 

497 if (s.ndim != 2 or t.ndim != 2 or 497 ↛ 500line 497 didn't jump to line 500, because the condition on line 497 was never true

498 (q is not None and q.ndim != 2) or 

499 (z is not None and z.ndim != 2)): 

500 raise ValueError("Expect matrices as input") 

501 

502 if ((s.shape[0] != s.shape[1] or t.shape[0] != t.shape[1] or 502 ↛ 508line 502 didn't jump to line 508, because the condition on line 502 was never true

503 s.shape[0] != t.shape[0]) or 

504 (q is not None and (q.shape[0] != q.shape[1] or 

505 s.shape[0] != q.shape[0])) or 

506 (z is not None and (z.shape[0] != z.shape[1] or 

507 s.shape[0] != z.shape[0]))): 

508 raise ValueError("Invalid Schur decomposition as input") 

509 

510 # First, find the positions of 2x2-blocks. 

511 blockpos = np.diagonal(s, -1).nonzero()[0] 

512 

513 # Check if there are actually any 2x2-blocks. 

514 if not blockpos.size: 

515 s2 = s 

516 t2 = t 

517 q2 = q 

518 z2 = z 

519 else: 

520 s2 = s.astype(np.common_type(s, np.array([], np.complex64))) 

521 t2 = t.astype(np.common_type(t, np.array([], np.complex64))) 

522 if q is not None: 522 ↛ 524line 522 didn't jump to line 524, because the condition on line 522 was never false

523 q2 = q.astype(np.common_type(q, np.array([], np.complex64))) 

524 if z is not None: 524 ↛ 527line 524 didn't jump to line 527, because the condition on line 524 was never false

525 z2 = z.astype(np.common_type(z, np.array([], np.complex64))) 

526 

527 for i in blockpos: 

528 # In the following, we use gen_schur on individual 2x2 blocks (that are 

529 # promoted to complex form) to compute the complex generalized Schur 

530 # form. If necessary, order_gen_schur is used to ensure the desired 

531 # order of eigenvalues. 

532 

533 sb, tb, qb, zb, alphab, betab = gen_schur(s2[i:i+2, i:i+2], 

534 t2[i:i+2, i:i+2]) 

535 

536 # Ensure order of eigenvalues. (betab is positive) 

537 if alphab[0].imag < alphab[1].imag: 537 ↛ 541line 537 didn't jump to line 541, because the condition on line 537 was never false

538 sb, tb, qb, zb, alphab, betab = order_gen_schur([False, True], 

539 sb, tb, qb, zb) 

540 

541 s2[i:i+2, i:i+2] = sb 

542 t2[i:i+2, i:i+2] = tb 

543 

544 s2[:i, i:i+2] = np.dot(s2[:i, i:i+2], zb) 

545 s2[i:i+2, i+2:] = np.dot(qb.T.conj(), s2[i:i+2, i+2:]) 

546 t2[:i, i:i+2] = np.dot(t2[:i, i:i+2], zb) 

547 t2[i:i+2, i+2:] = np.dot(qb.T.conj(), t2[i:i+2, i+2:]) 

548 

549 if q is not None: 549 ↛ 551line 549 didn't jump to line 551, because the condition on line 549 was never false

550 q2[:, i:i+2] = np.dot(q[:, i:i+2], qb) 

551 if z is not None: 551 ↛ 527line 551 didn't jump to line 527, because the condition on line 551 was never false

552 z2[:, i:i+2] = np.dot(z[:, i:i+2], zb) 

553 

554 if q is not None and z is not None: 554 ↛ 556line 554 didn't jump to line 556, because the condition on line 554 was never false

555 return s2, t2, q2, z2 

556 elif q is not None: 

557 return s2, t2, q2 

558 elif z is not None: 

559 return s2, t2, z2 

560 else: 

561 return s2, t2 

562 

563 

564def evecs_from_gen_schur(s, t, q=None, z=None, select=None, 

565 left=False, right=True, overwrite_qz=False): 

566 """Compute eigenvectors from Schur form. 

567 

568 This function computes either all or selected eigenvectors for the matrix 

569 that is represented by the generalized Schur form (s, t) and the unitary 

570 matrices q and z, (not the generalized eigenvectors of (s,t), but of 

571 (q*s*z^dagger, q*t*z^dagger)). 

572 

573 Parameters 

574 ---------- 

575 s : array, shape (M, M) 

576 t : array, shape (M, M) 

577 Generalized Schur form. 

578 q : array, shape (M, M), optional 

579 z : array, shape (M, M), optional 

580 Unitary/orthogonal transformation matrices. If the left eigenvectors 

581 are to be computed, `q` must be provided, if the right eigenvectors are 

582 to be computed, `z` must be provided. 

583 select : boolean function or array, optional 

584 The value of ``select(i)`` or ``select[i]`` is used to decide 

585 whether the eigenvector corresponding to the i-th eigenvalue 

586 should be computed or not. If select is not provided, all 

587 eigenvectors are computed. Default: None. 

588 left : boolean, optional 

589 Whether to compute left eigenvectors. Default: False. 

590 right : boolean, optional 

591 Whether to compute right eigenvectors. Default: True. 

592 overwrite_qz : boolean, optional 

593 Whether to overwrite data in `q` and `z` (may increase performance). 

594 Note that s and t remain always unchanged Default: False. 

595 

596 Returns 

597 ------- 

598 (if left == True) 

599 vl : array, shape(M, N) 

600 Left generalized eigenvectors. N is the number of eigenvectors 

601 selected by select, or equal to M if select is not 

602 provided. The eigenvectors may be complex, even if `s`, `t`, 

603 `q` and `z` are real. 

604 

605 (if right == True) 

606 vr : array, shape(M, N) 

607 Right generalized eigenvectors. N is the number of 

608 eigenvectors selected by select, or equal to M if select is 

609 not provided. The eigenvectors may be complex, even if `s`, 

610 `t`, `q` and `z` are real. 

611 

612 """ 

613 

614 s, t, q, z = lapack.prepare_for_lapack(overwrite_qz, s, t, q, z) 

615 

616 if left and q is None: 616 ↛ 617line 616 didn't jump to line 617, because the condition on line 616 was never true

617 raise ValueError("Matrix q must be provided for left eigenvectors") 

618 

619 if right and z is None: 619 ↛ 620line 619 didn't jump to line 620, because the condition on line 619 was never true

620 raise ValueError("Matrix z must be provided for right eigenvectors") 

621 

622 # Check if select is a function or an array. 

623 if select is not None: 

624 isfun = isarray = True 

625 try: 

626 select(0) 

627 except: 

628 isfun = False 

629 

630 try: 

631 select[0] 

632 except: 

633 isarray = False 

634 

635 if not (isarray or isfun): 635 ↛ 636line 635 didn't jump to line 636, because the condition on line 635 was never true

636 raise ValueError("select must be either a function, " 

637 "an array or None") 

638 elif isarray: 

639 selectarr = np.array(select, dtype=lapack.logical_dtype, 

640 order='F') 

641 else: 

642 selectarr = np.array(np.vectorize(select)(np.arange(t.shape[0])), 

643 dtype=lapack.logical_dtype, order='F') 

644 else: 

645 selectarr = None 

646 

647 return lapack.tgevc(s, t, q, z, selectarr, left, right)