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.
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']
13from math import sqrt
14import numpy as np
15from . import lapack
18def schur(a, calc_q=True, calc_ev=True, overwrite_a=False):
19 """Compute the Schur form of a square matrix a.
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).
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.
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).
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).
49 (if calc_q == True)
50 q : array, shape (M, M)
51 Unitary transformation matrix.
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.
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)
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.
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.
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
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 """
96 # First find the positions of 2x2-blocks
97 blockpos = np.diagonal(t, -1).nonzero()[0]
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)))
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.
115 a = t[i, i]
116 b = t[i, i+1]
117 c = t[i+1, i]
119 x = 1j * sqrt(-b * c)
120 y = c
121 norm = sqrt(-b * c + c * c)
123 U = np.array([[x / norm, -y / norm], [y / norm, -x / norm]])
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
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:])
133 q2[:, i:i+2] = np.dot(q2[:, i:i+2], U)
135 return t2, q2
138def order_schur(select, t, q, calc_ev=True, overwrite_tq=False):
139 """Reorder the Schur form, selecting a cluster of eigenvalues.
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).
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.
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
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 """
185 t, q = lapack.prepare_for_lapack(overwrite_tq, t, q)
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
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')
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)
214 return lapack.trsen(select, t, q, calc_ev)
217def evecs_from_schur(t, q, select=None, left=False, right=True,
218 overwrite_tq=False):
219 """Compute eigenvectors from Schur form.
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).
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
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 """
258 t, q = lapack.prepare_for_lapack(overwrite_tq, t, q)
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
268 try:
269 select[0]
270 except:
271 isarray = False
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
285 return lapack.trevc(t, q, selectarr, left, right)
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).
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).
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()).
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
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``.
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)
353def order_gen_schur(select, s, t, q=None, z=None, calc_ev=True,
354 overwrite_stqz=False):
355 """Reorder the generalized Schur form.
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).
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.
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.
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``.
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)
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
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')
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)
448 return order_gen_schur(select, s, t, q, z, calc_ev, True)
450 return lapack.tgsen(select, s, t, q, z, calc_ev)
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.
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.
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
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.
488 Raises
489 ------
490 LinAlgError
491 If it fails to convert a 2x2 block into complex form (unlikely).
492 """
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
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")
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")
510 # First, find the positions of 2x2-blocks.
511 blockpos = np.diagonal(s, -1).nonzero()[0]
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)))
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.
533 sb, tb, qb, zb, alphab, betab = gen_schur(s2[i:i+2, i:i+2],
534 t2[i:i+2, i:i+2])
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)
541 s2[i:i+2, i:i+2] = sb
542 t2[i:i+2, i:i+2] = tb
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:])
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)
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
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.
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)).
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.
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.
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.
612 """
614 s, t, q, z = lapack.prepare_for_lapack(overwrite_qz, s, t, q, z)
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")
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")
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
630 try:
631 select[0]
632 except:
633 isarray = False
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
647 return lapack.tgevc(s, t, q, z, selectarr, left, right)