PDL-LinearAlgebra-0.38/0000755000175000017500000000000014565105647014514 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/Real/0000755000175000017500000000000014565105646015376 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/Real/real.pd0000644000175000017500000115376114565105125016654 0ustar osboxesosboxesdo('../Config'); our $VERSION = '0.14'; pp_setversion($VERSION); $VERSION = eval $VERSION; use PDL::Exporter; use PDL::Types qw(ppdefs_all); sub generate_code($){ if ($config{WITHOUT_THREAD}){ return ' #if 0 threadloop%{ %} #endif'.$_[0]; } else{ return $_[0]; } } if ($config{CBLAS}){ pp_addhdr('#include '); } if ($^O =~ /MSWin/) { pp_addhdr(' #include '); } pp_addhdr(' #include #define CONCAT_(A, B) A ## B #define CONCAT(A, B) CONCAT_(A, B) #define FORTRAN(name) CONCAT(name, F77_USCORE) /* avoid annoying warnings */ typedef PDL_Long logical; typedef PDL_Long integer; typedef PDL_Long ftnlen; #ifdef __cplusplus typedef logical (*L_fp)(...); #else typedef logical (*L_fp)(); #endif #ifndef min #define min(a,b) ((a) <= (b) ? (a) : (b)) #endif #ifndef max #define max(a,b) ((a) >= (b) ? (a) : (b)) #endif static integer c_zero = 0; static integer c_nine = 9; extern integer FORTRAN(ilaenv)(integer *ispec, char *name__, char *opts, integer *n1, integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen opts_len); #define PDL_MAYBE_SIZE(flagpdltype, flagpdl, flagcond, outpdl, outdim, indim) \ if (outpdl->state & PDL_MYDIMS_TRANS) { \ PDL_Indx i; \ char gobig = 0; \ flagpdltype *datap = PDL_REPRP(flagpdl); \ for (i=0; invals; i++) { \ flagpdltype tmp = datap[i]; /* [phys] means ignore incs and offs */ \ if (!(flagcond)) continue; \ gobig = 1; \ break; \ } \ outdim = gobig ? indim : 1; \ } '); pp_addpm({At=>'Top'},<<'EOD'); use strict; { package # hide from CPAN PDL; my $warningFlag; BEGIN{ $warningFlag = $^W; $^W = 0; } use overload ( 'x' => sub { !(grep ref($_) && !$_->type->real, @_[0,1]) ? PDL::mmult($_[0], $_[1]) : PDL::cmmult($_[0], $_[1]) }, ); BEGIN{ $^W = $warningFlag;} } =encoding Latin-1 =head1 NAME PDL::LinearAlgebra::Real - PDL interface to the real lapack linear algebra programming library =head1 SYNOPSIS use PDL::LinearAlgebra::Real; $a = random (100,100); $s = zeroes(100); $u = zeroes(100,100); $v = zeroes(100,100); $info = 0; $job = 0; gesdd($a, $job, $info, $s , $u, $v); =head1 DESCRIPTION This module provides an interface to parts of the real lapack library. These routines accept either float or double ndarrays. =cut EOD pp_def("gtsv", HandleBad => 0, Pars => '[phys]DL(n); [phys]D(n); [phys]DU(n); [io,phys]B(n,nrhs); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' extern int FORTRAN($TFD(s,d)gtsv)(integer *n, integer *nrhs, $GENERIC() *dl, $GENERIC() *d, $GENERIC() *du, $GENERIC() *b, integer *ldb, integer *info); FORTRAN($TFD(s,d)gtsv)( &(integer){$SIZE(n)}, &(integer){$SIZE(nrhs)}, $P(DL), $P(D), $P(DU), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Solves the equation A * X = B where A is an C by C tridiagonal matrix, by Gaussian elimination with partial pivoting, and B is an C by C matrix. Note that the equation C may be solved by interchanging the order of the arguments DU and DL. B This differs from the LINPACK function C in that C
starts from its first element, while the LINPACK equivalent starts from its second element. Arguments ========= DL: On entry, DL must contain the (n-1) sub-diagonal elements of A. On exit, DL is overwritten by the (n-2) elements of the second super-diagonal of the upper triangular matrix U from the LU factorization of A, in DL(1), ..., DL(n-2). D: On entry, D must contain the diagonal elements of A. On exit, D is overwritten by the n diagonal elements of U. DU: On entry, DU must contain the (n-1) super-diagonal elements of A. On exit, DU is overwritten by the (n-1) elements of the first super-diagonal of the U. B: On entry, the n by nrhs matrix of right hand side matrix B. On exit, if info = 0, the n by nrhs solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero, and the solution has not been computed. The factorization has not been completed unless i = n. =for example $dl = random(float, 9); $d = random(float, 10); $du = random(float, 9); $b = random(10,5); gtsv($dl, $d, $du, $b, ($info=null)); print "X is:\n$b" unless $info; '); pp_def("gesvd", HandleBad => 0, Pars => '[io]A(m,n); int jobu(); int jobvt(); [o]s(minmn); [o]U(p,p); [o]VT(s,s); int [o]info()', RedoDimsCode => ' $SIZE(minmn) = PDLMIN($SIZE(m),$SIZE(n)); PDL_MAYBE_SIZE(PDL_Long, $PDL(jobu), tmp==1 || tmp==2, $PDL(U), $SIZE(p), $SIZE(m)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvt), tmp==1 || tmp==2, $PDL(VT), $SIZE(s), $SIZE(n)) ', GenericTypes => [F,D], Code => generate_code ' extern int FORTRAN($TFD(s,d)gesvd)(char *jobu, char *jobvt, integer *m, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *s, $GENERIC() *u, int *ldu, $GENERIC() *vt, integer *ldvt, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; integer lwork = -1; char trau, travt; switch ($jobu()) { case 1: trau = \'A\'; break; case 2: trau = \'S\'; break; case 3: trau = \'O\'; break; default: trau = \'N\'; } switch ($jobvt()) { case 1: travt = \'A\'; break; case 2: travt = \'S\'; break; case 3: travt = \'O\'; break; default: travt = \'N\'; } FORTRAN($TFD(s,d)gesvd)( &trau, &travt, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gesvd)( &trau, &travt, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes the singular value decomposition (SVD) of a real M-by-N matrix A. The SVD is written A = U * SIGMA * V\' where SIGMA is an M-by-N matrix which is zero except for its min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA are the singular values of A; they are real and non-negative, and are returned in descending order. The first min(m,n) columns of U and V are the left and right singular vectors of A. Note that the routine returns VT = V\', not V. jobu: Specifies options for computing all or part of the matrix U: = 0: no columns of U (no left singular vectors) are computed. = 1: all M columns of U are returned in array U: = 2: the first min(m,n) columns of U (the left singular vectors) are returned in the array U; = 3: the first min(m,n) columns of U (the left singular vectors) are overwritten on the array A; jobvt: Specifies options for computing all or part of the matrix V\': = 0: no rows of V\' (no right singular vectors) are computed. = 1: all N rows of V\' are returned in the array VT; = 2: the first min(m,n) rows of V\' (the right singular vectors) are returned in the array VT; = 3: the first min(m,n) rows of V\' (the right singular vectors) are overwritten on the array A; jobvt and jobu cannot both be 3. A: On entry, the M-by-N matrix A. On exit, if jobu = 3, A is overwritten with the first min(m,n) columns of U (the left singular vectors, stored columnwise); if jobvt = 3, A is overwritten with the first min(m,n) rows of V\' (the right singular vectors, stored rowwise); if jobu != 3 and jobvt != 3, the contents of A are destroyed. s: The singular values of A, sorted so that s(i) >= s(i+1). U: If jobu = 1, U contains the M-by-M orthogonal matrix U; if jobu = 3, U contains the first min(m,n) columns of U (the left singular vectors, stored columnwise); if jobu = 0 or 3, U is not referenced. Min size = [1,1]. VT: If jobvt = 1, VT contains the N-by-N orthogonal matrix V\'; if jobvt = 2, VT contains the first min(m,n) rows of V\' (the right singular vectors, stored rowwise); if jobvt = 0 or 3, VT is not referenced. Min size = [1,1]. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. > 0: if bdsqr did not converge, info specifies how many superdiagonals of an intermediate bidiagonal form B did not converge to zero. =for example $a = random (float, 100,100); $s = zeroes(float, 100); $u = zeroes(float, 100,100); $vt = zeroes(float, 100,100); $info = pdl(long, 0); gesvd($a, 2, 2, $s , $u, $vt, $info); '); pp_def("gesdd", HandleBad => 0, RedoDimsCode => '$SIZE(r) = PDLMIN($SIZE(m),$SIZE(n));', Pars => '[io]A(m,n); int jobz(); [o]s(minmn); [o]U(p,p); [o]VT(s,s); int [o]info(); int [t]iwork(iworkn);', RedoDimsCode => ' $SIZE(minmn) = PDLMIN($SIZE(m),$SIZE(n)); PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp==1 || (tmp==2) || (tmp==3 && $SIZE(m)<$SIZE(n)), $PDL(U), $SIZE(p), $SIZE(minmn)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp==1 || (tmp==2) || (tmp==3 && $SIZE(m)>=$SIZE(n)), $PDL(VT), $SIZE(s), $SIZE(minmn)) $SIZE(iworkn) = 8*$SIZE(minmn); ', GenericTypes => [F,D], Code => generate_code ' integer lwork; integer smlsiz; char tra; extern int FORTRAN($TFD(s,d)gesdd)(char *jobz, integer *m, integer *n, $GENERIC() * a, integer *lda, $GENERIC() *s, $GENERIC() *u, int *ldu, $GENERIC() *vt, integer *ldvt, $GENERIC() *work, integer *lwork, integer *iwork, integer *info); $GENERIC() tmp_work; lwork = -1; switch ($jobz()) { case 1: tra = \'A\'; break; case 2: tra = \'S\'; break; case 3: tra = \'O\'; break; default: tra = \'N\'; break; } FORTRAN($TFD(s,d)gesdd)( &tra, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, &tmp_work, &lwork, $P(iwork), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work; if (tra == \'N\'){ smlsiz = FORTRAN(ilaenv)(&c_nine, "SGESDD", " ", &c_zero, &c_zero, &c_zero, &c_zero, (ftnlen)6, (ftnlen)1); lwork = max(14*min($SIZE(m),$SIZE(n))+4, 10*min($SIZE(m), $SIZE(n))+2+ smlsiz*(smlsiz+8)) + max($SIZE(m),$SIZE(n)); } work = ($GENERIC() *) malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gesdd)( &tra, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, work, &lwork, $P(iwork), $P(info)); free(work); } ', Doc => ' =for ref Computes the singular value decomposition (SVD) of a real M-by-N matrix A. This routine use the Coppen\'s divide and conquer algorithm. It is much faster than the simple driver for large matrices, but uses more workspace. jobz: Specifies options for computing all or part of matrix: = 0: no columns of U or rows of V\' are computed; = 1: all M columns of U and all N rows of V\' are returned in the arrays U and VT; = 2: the first min(M,N) columns of U and the first min(M,N) rows of V\' are returned in the arrays U and VT; = 3: If M >= N, the first N columns of U are overwritten on the array A and all rows of V\' are returned in the array VT; otherwise, all columns of U are returned in the array U and the first M rows of V\' are overwritten on the array A. A: On entry, the M-by-N matrix A. On exit, if jobz = 3, A is overwritten with the first N columns of U (the left singular vectors, stored columnwise) if M >= N; A is overwritten with the first M rows of V\' (the right singular vectors, stored rowwise) otherwise. if jobz != 3, the contents of A are destroyed. s: The singular values of A, sorted so that s(i) >= s(i+1). U: If jobz = 1 or jobz = 3 and M < N, U contains the M-by-M orthogonal matrix U; if jobz = 2, U contains the first min(M,N) columns of U (the left singular vectors, stored columnwise); if jobz = 3 and M >= N, or jobz = 0, U is not referenced. Min size = [1,1]. VT: If jobz = 1 or jobz = 3 and M >= N, VT contains the N-by-N orthogonal matrix V\'; if jobz = 2, VT contains the first min(M,N) rows of V\' (the right singular vectors, stored rowwise); if jobz = 3 and M < N, or jobz = 0, VT is not referenced. Min size = [1,1]. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. > 0: bdsdc did not converge, updating process failed. =for example $lines = 50; $columns = 100; $a = random (float, $lines, $columns); $min = $lines < $columns ? $lines : $columns; $s = zeroes(float, $min); $u = zeroes(float, $lines, $lines); $vt = zeroes(float, $columns, $columns); $info = long (0); gesdd($a, 1, $s , $u, $vt, $info); '); pp_def("ggsvd", HandleBad => 0, Pars => '[io]A(m,n); int jobu(); int jobv(); int jobq(); [io]B(p,n); int [o]k(); int [o]l();[o]alpha(n);[o]beta(n); [o]U(q,q); [o]V(r,r); [o]Q(s,s); int [o]iwork(n); int [o]info()', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobu), tmp, $PDL(U), $SIZE(q), $SIZE(m)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobv), tmp, $PDL(V), $SIZE(r), $SIZE(p)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobq), tmp, $PDL(Q), $SIZE(s), $SIZE(n)) ', GenericTypes => [F,D], Code => generate_code ' char pjobu = \'N\'; char pjobv = \'N\'; char pjobq = \'N\'; extern int FORTRAN($TFD(s,d)ggsvd3)(char *jobu, char *jobv, char *jobq, integer *m, integer *n, integer *p, integer *k, integer *l, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *alpha, $GENERIC() *beta, $GENERIC() *u, integer *ldu, $GENERIC() *v, integer *ldv, $GENERIC() *q, integer *ldq, $GENERIC() *work, integer *lwork, integer *iwork, integer *info); $GENERIC() *work, twork[1]; integer lwork = -1; // = ($SIZE (m) < $SIZE (n)) ? $SIZE (n): $SIZE (m); //if ($SIZE (p) > lwork) // lwork = $SIZE (p); if ($jobu()) pjobu = \'U\'; if ($jobv()) pjobv = \'V\'; if ($jobq()) pjobq = \'Q\'; FORTRAN($TFD(s,d)ggsvd3)( &pjobu, &pjobv, &pjobq, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(k), $P(l), $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(alpha), $P(beta), $P(U), &(integer){$SIZE(q)}, $P(V), &(integer){$SIZE(r)}, $P(Q), &(integer){$SIZE(s)}, &twork[0], &lwork, $P(iwork), $P(info)); lwork = (integer) twork[0]; work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ggsvd3)( &pjobu, &pjobv, &pjobq, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(k), $P(l), $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(alpha), $P(beta), $P(U), &(integer){$SIZE(q)}, $P(V), &(integer){$SIZE(r)}, $P(Q), &(integer){$SIZE(s)}, work, &lwork, $P(iwork), $P(info)); free(work); ', Doc => ' =for ref Computes the generalized singular value decomposition (GSVD) of an M-by-N real matrix A and P-by-N real matrix B: U\'*A*Q = D1*( 0 R ), V\'*B*Q = D2*( 0 R ) where U, V and Q are orthogonal matrices, and Z\' is the transpose of Z. Let K+L = the effective numerical rank of the matrix (A\',B\')\', then R is a K+L-by-K+L nonsingular upper triangular matrix, D1 and D2 are M-by-(K+L) and P-by-(K+L) "diagonal" matrices and of the following structures, respectively: If M-K-L >= 0, K L D1 = K ( I 0 ) L ( 0 C ) M-K-L ( 0 0 ) K L D2 = L ( 0 S ) P-L ( 0 0 ) N-K-L K L ( 0 R ) = K ( 0 R11 R12 ) L ( 0 0 R22 ) where C = diag( ALPHA(K+1), ... , ALPHA(K+L) ), S = diag( BETA(K+1), ... , BETA(K+L) ), C**2 + S**2 = I. R is stored in A(1:K+L,N-K-L+1:N) on exit. If M-K-L < 0, K M-K K+L-M D1 = K ( I 0 0 ) M-K ( 0 C 0 ) K M-K K+L-M D2 = M-K ( 0 S 0 ) K+L-M ( 0 0 I ) P-L ( 0 0 0 ) N-K-L K M-K K+L-M ( 0 R ) = K ( 0 R11 R12 R13 ) M-K ( 0 0 R22 R23 ) K+L-M ( 0 0 0 R33 ) where C = diag( ALPHA(K+1), ... , ALPHA(M) ), S = diag( BETA(K+1), ... , BETA(M) ), C**2 + S**2 = I. (R11 R12 R13 ) is stored in A(1:M, N-K-L+1:N), and R33 is stored ( 0 R22 R23 ) in B(M-K+1:L,N+M-K-L+1:N) on exit. The routine computes C, S, R, and optionally the orthogonal transformation matrices U, V and Q. In particular, if B is an N-by-N nonsingular matrix, then the GSVD of A and B implicitly gives the SVD of A*inv(B): A*inv(B) = U*(D1*inv(D2))*V\'. If ( A\',B\')\' has orthonormal columns, then the GSVD of A and B is also equal to the CS decomposition of A and B. Furthermore, the GSVD can be used to derive the solution of the eigenvalue problem: A\'*A x = lambda* B\'*B x. In some literature, the GSVD of A and B is presented in the form U\'*A*X = ( 0 D1 ), V\'*B*X = ( 0 D2 ) where U and V are orthogonal and X is nonsingular, D1 and D2 are "diagonal". The former GSVD form can be converted to the latter form by taking the nonsingular matrix X as X = Q*( I 0 ) ( 0 inv(R) ). Arguments ========= jobu: = 0: U is not computed. = 1: Orthogonal matrix U is computed; jobv: = 0: V is not computed. = 1: Orthogonal matrix V is computed; jobq: = 0: Q is not computed. = 1: Orthogonal matrix Q is computed; k: l: On exit, k and l specify the dimension of the subblocks described in the Purpose section. k + l = effective numerical rank of (A\',B\')\'. A: On entry, the M-by-N matrix A. On exit, A contains the triangular matrix R, or part of R. B: On entry, the P-by-N matrix B. On exit, B contains the triangular matrix R if M-k-l < 0. alpha: beta: On exit, alpha and beta contain the generalized singular value pairs of A and B; alpha(1:k) = 1, beta(1:k) = 0, and if M-k-l >= 0, alpha(k+1:k+l) = C, beta(k+1:k+l) = S, or if M-k-l < 0, alpha(k+1:M)=C, alpha(M+1:k+l)=0 beta(k+1:M) =S, beta(M+1:k+l) =1 and alpha(k+l+1:N) = 0 beta(k+l+1:N) = 0 U: If jobu = 1, U contains the M-by-M orthogonal matrix U. If jobu = 0, U is not referenced. Need a minimum array of (1,1) if jobu = 0; V: If jobv = 1, V contains the P-by-P orthogonal matrix V. If jobv = 0, V is not referenced. Need a minimum array of (1,1) if jobv = 0; Q: If jobq = 1, Q contains the N-by-N orthogonal matrix Q. If jobq = 0, Q is not referenced. Need a minimum array of (1,1) if jobq = 0; iwork: On exit, iwork stores the sorting information. More precisely, the following loop will sort alpha for I = k+1, min(M,k+l) swap alpha(I) and alpha(iwork(I)) endfor such that alpha(1) >= alpha(2) >= ... >= alpha(N). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = 1, the Jacobi-type procedure failed to converge. For further details, see subroutine tgsja. =for example $k = null; $l = null; $A = random(5,6); $B = random(7,6); $alpha = zeroes(6); $beta = zeroes(6); $U = zeroes(5,5); $V = zeroes(7,7); $Q = zeroes(6,6); $iwork = zeroes(long, 6); $info = null; ggsvd($A,1,1,1,$B,$k,$l,$alpha, $beta,$U, $V, $Q, $iwork,$info); '); pp_def("geev", HandleBad => 0, Pars => 'A(n,n); int jobvl(); int jobvr(); [o]wr(n); [o]wi(n); [o]vl(m,m); [o]vr(p,p); int [o]info()', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(vl), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(vr), $SIZE(p), $SIZE(n)) ', GenericTypes => [F,D], Code => generate_code ' char jvl = \'N\'; char jvr = \'N\'; extern int FORTRAN($TFD(s,d)geev)(char *jobvl, char *jobvr, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *wr, $GENERIC() *wi, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; integer lwork = -1; if ($jobvl()) jvl = \'V\'; if ($jobvr()) jvr = \'V\'; FORTRAN($TFD(s,d)geev)( &jvl, &jvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(wr), $P(wi), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)geev)( &jvl, &jvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(wr), $P(wi), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues and, optionally, the left and/or right eigenvectors. The right eigenvector v(j) of A satisfies: A * v(j) = lambda(j) * v(j) where lambda(j) is its eigenvalue. The left eigenvector u(j) of A satisfies: u(j)**H * A = lambda(j) * u(j)**H where u(j)**H denotes the conjugate transpose of u(j). The computed eigenvectors are normalized to have Euclidean norm equal to 1 and largest component real. Arguments ========= jobvl: = 0: left eigenvectors of A are not computed; = 1: left eigenvectors of A are computed. jobvr: = 0: right eigenvectors of A are not computed; = 1: right eigenvectors of A are computed. A: A is overwritten. wr: wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues. Complex conjugate pairs of eigenvalues appear consecutively with the eigenvalue having the positive imaginary part first. vl: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of vl, in the same order as their eigenvalues else vl is not referenced. If the j-th eigenvalue is real, then u(j) = vl(:,j), the j-th column of vl. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and u(j+1) = vl(:,j) - i*vl(:,j+1). Min size = [1]. vr: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of vr, in the same order as their eigenvalues else vr is not referenced. If the j-th eigenvalue is real, then v(j) = vr(:,j), the j-th column of vr. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and v(j+1) = vr(:,j) - i*vr(:,j+1). Min size = [1]. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, the QR algorithm failed to compute all the eigenvalues, and no eigenvectors have been computed; elements i+1:N of wr and wi contain eigenvalues which have converged. =for example $a = random (5, 5); $wr = zeroes(5); $wi = zeroes($wr); $vl = zeroes($a); $vr = zeroes($a); $info = null; geev($a, 1, 1, $wr, $wi, $vl, $vr, $info); '); pp_def("geevx", HandleBad => 0, Pars => '[io]A(n,n); int jobvl(); int jobvr(); int balance(); int sense(); [o]wr(n); [o]wi(n); [o]vl(m,m); [o]vr(p,p); int [o]ilo(); int [o]ihi(); [o]scale(n); [o]abnrm(); [o]rconde(q); [o]rcondv(r); int [o]info(); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(vl), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(vr), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 1 || tmp == 3, $PDL(rconde), $SIZE(q), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 2 || tmp == 3, $PDL(rcondv), $SIZE(r), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 2 || tmp == 3, $PDL(iwork), $SIZE(iworkn), 2*$SIZE(n)-2) ', GenericTypes => [F,D], Code => generate_code ' char jvl = \'N\'; char jvr = \'N\'; char balanc, sens; integer lwork = -1; extern int FORTRAN($TFD(s,d)geevx)(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *wr, $GENERIC() *wi, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, integer *ilo, integer *ihi, $GENERIC() *scale, $GENERIC() *abnrm, $GENERIC() *rconde, $GENERIC() *rcondv, $GENERIC() *work, integer *lwork, integer *iwork, integer *info); $GENERIC() tmp_work; if ($jobvl()) jvl = \'V\'; if ($jobvr()) jvr = \'V\'; switch ($balance()) { case 1: balanc = \'P\'; break; case 2: balanc = \'S\'; break; case 3: balanc = \'B\'; break; default: balanc = \'N\'; } switch ($sense()) { case 1: sens = \'E\'; break; case 2: sens = \'V\'; break; case 3: sens = \'B\'; break; default: sens = \'N\'; } FORTRAN($TFD(s,d)geevx)( &balanc, &jvl, &jvr, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(wr), $P(wi), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(scale), $P(abnrm), $P(rconde), $P(rcondv), &tmp_work, &lwork, $P(iwork), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)geevx)( &balanc, &jvl, &jvr, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(wr), $P(wi), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(scale), $P(abnrm), $P(rconde), $P(rcondv), work, &lwork, $P(iwork), $P(info)); free(work); } ', Doc => ' =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues and, optionally, the left and/or right eigenvectors. Optionally also, it computes a balancing transformation to improve the conditioning of the eigenvalues and eigenvectors (ilo, ihi, scale, and abnrm), reciprocal condition numbers for the eigenvalues (rconde), and reciprocal condition numbers for the right eigenvectors (rcondv). The right eigenvector v(j) of A satisfies: A * v(j) = lambda(j) * v(j) where lambda(j) is its eigenvalue. The left eigenvector u(j) of A satisfies: u(j)**H * A = lambda(j) * u(j)**H where u(j)**H denotes the conjugate transpose of u(j). The computed eigenvectors are normalized to have Euclidean norm equal to 1 and largest component real. Balancing a matrix means permuting the rows and columns to make it more nearly upper triangular, and applying a diagonal similarity transformation D * A * D**(-1), where D is a diagonal matrix, to make its rows and columns closer in norm and the condition numbers of its eigenvalues and eigenvectors smaller. The computed reciprocal condition numbers correspond to the balanced matrix. Permuting rows and columns will not change the condition numbers (in exact arithmetic) but diagonal scaling will. For further explanation of balancing, see section 4.10.2 of the LAPACK Users\' Guide. Arguments ========= balance: Indicates how the input matrix should be diagonally scaled and/or permuted to improve the conditioning of its eigenvalues. = 0: Do not diagonally scale or permute; = 1: Perform permutations to make the matrix more nearly upper triangular. Do not diagonally scale; = 2: Diagonally scale the matrix, i.e. replace A by D*A*D**(-1), where D is a diagonal matrix chosen to make the rows and columns of A more equal in norm. Do not permute; = 3: Both diagonally scale and permute A. Computed reciprocal condition numbers will be for the matrix after balancing and/or permuting. Permuting does not change condition numbers (in exact arithmetic), but balancing does. jobvl: = 0: left eigenvectors of A are not computed; = 1: left eigenvectors of A are computed. If sense = 1 or 3, jobvl must = 1. jobvr; = 0: right eigenvectors of A are not computed; = 1: right eigenvectors of A are computed. If sense = 1 or 3, jobvr must = 1. sense: Determines which reciprocal condition numbers are computed. = 0: None are computed; = 1: Computed for eigenvalues only; = 2: Computed for right eigenvectors only; = 3: Computed for eigenvalues and right eigenvectors. If sense = 1 or 3, both left and right eigenvectors must also be computed (jobvl = 1 and jobvr = 1). A: The N-by-N matrix. It is overwritten. If jobvl = 1 or jobvr = 1, A contains the real Schur form of the balanced version of the input matrix A. wr wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues. Complex conjugate pairs of eigenvalues will appear consecutively with the eigenvalue having the positive imaginary part first. vl: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of vl, in the same order as their eigenvalues else vl is not referenced. If the j-th eigenvalue is real, then u(j) = vl(:,j), the j-th column of vl. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and u(j+1) = vl(:,j) - i*vl(:,j+1). Min size = [1]. vr: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of vr, in the same order as their eigenvalues else vr is not referenced. If the j-th eigenvalue is real, then v(j) = vr(:,j), the j-th column of vr. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and v(j+1) = vr(:,j) - i*vr(:,j+1). Min size = [1]. ilo,ihi:Integer values determined when A was balanced. The balanced A(i,j) = 0 if I > J and J = 1,...,ilo-1 or I = ihi+1,...,N. scale: Details of the permutations and scaling factors applied when balancing A. If P(j) is the index of the row and column interchanged with row and column j, and D(j) is the scaling factor applied to row and column j, then scale(J) = P(J), for J = 1,...,ilo-1 = D(J), for J = ilo,...,ihi = P(J) for J = ihi+1,...,N. The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. abnrm: The one-norm of the balanced matrix (the maximum of the sum of absolute values of elements of any column). rconde: rconde(j) is the reciprocal condition number of the j-th eigenvalue. rcondv: rcondv(j) is the reciprocal condition number of the j-th right eigenvector. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, the QR algorithm failed to compute all the eigenvalues, and no eigenvectors or condition numbers have been computed; elements 1:ilo-1 and i+1:N of wr and wi contain eigenvalues which have converged. =for example $a = random (5,5); $wr = zeroes(5); $wi = zeroes(5); $vl = zeroes(5,5); $vr = zeroes(5,5); $ilo = null; $ihi = null; $scale = zeroes(5); $abnrm = null; $rconde = zeroes(5); $rcondv = zeroes(5); $info = null; geevx($a, 1,1,3,3,$wr, $wi, $vl, $vr, $ilo, $ihi, $scale, $abnrm,$rconde, $rcondv, $info); '); pp_def("ggev", HandleBad => 0, Pars => 'A(n,n); int [phys]jobvl();int [phys]jobvr();B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VL(m,m);[o]VR(p,p);int [o]info()', GenericTypes => [F,D], RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(VR), $SIZE(p), $SIZE(n)) ', Code => generate_code ' integer lwork = -1; char pjobvl = \'N\', pjobvr = \'N\'; extern int FORTRAN($TFD(s,d)ggev)(char *jobvl, char *jobvr, integer *n, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *alphar, $GENERIC() *alphai, $GENERIC() *beta, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if ($jobvl()) pjobvl = \'V\'; if ($jobvr()) pjobvr = \'V\'; FORTRAN($TFD(s,d)ggev)( &pjobvl, &pjobvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alphar), $P(alphai), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ggev)( &pjobvl, &pjobvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alphar), $P(alphai), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B) the generalized eigenvalues, and optionally, the left and/or right generalized eigenvectors. A generalized eigenvalue for a pair of matrices (A,B) is a scalar lambda or a ratio alpha/beta = lambda, such that A - lambda*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0, and even for both being zero. The right eigenvector v(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies A * v(j) = lambda(j) * B * v(j). The left eigenvector u(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies u(j)**H * A = lambda(j) * u(j)**H * B . where u(j)**H is the conjugate-transpose of u(j). Arguments ========= jobvl: = 0: do not compute the left generalized eigenvectors; = 1: compute the left generalized eigenvectors. jobvr: = 0: do not compute the right generalized eigenvectors; = 1: compute the right generalized eigenvectors. A: On entry, the matrix A in the pair (A,B). On exit, A has been overwritten. B: On entry, the matrix B in the pair (A,B). On exit, B has been overwritten. alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio alpha/beta. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). VL: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of VL, in the same order as their eigenvalues. If the j-th eigenvalue is real, then u(j) = VL(:,j), the j-th column of VL. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then u(j) = VL(:,j)+i*VL(:,j+1) and u(j+1) = VL(:,j)-i*VL(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part)+abs(imag. part)=1. Not referenced if jobvl = 0. VR: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of VR, in the same order as their eigenvalues. If the j-th eigenvalue is real, then v(j) = VR(:,j), the j-th column of VR. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then v(j) = VR(:,j)+i*VR(:,j+1) and v(j+1) = VR(:,j)-i*VR(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part)+abs(imag. part)=1. Not referenced if jobvr = 0. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. No eigenvectors have been calculated, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: error return from tgevc. =for example $a = random(5,5); $b = random(5,5); $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vl = zeroes(5,5); $vr = zeroes(5,5); ggev($a, 1, 1, $b, $alphar, $alphai, $beta, $vl, $vr, ($info=null)); '); pp_def("ggevx", HandleBad => 0, Pars => '[io,phys]A(n,n);int balanc();int jobvl();int jobvr();int sense();[io,phys]B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VL(m,m);[o]VR(p,p);int [o]ilo();int [o]ihi();[o]lscale(n);[o]rscale(n);[o]abnrm();[o]bbnrm();[o]rconde(r);[o]rcondv(s);int [o]info(); int [t]bwork(bworkn); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(VR), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp != 2, $PDL(rconde), $SIZE(r), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp != 1, $PDL(rcondv), $SIZE(s), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp != 1, $PDL(iwork), $SIZE(iworkn), $SIZE(n) + 6) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 1 || tmp == 2 || tmp == 3, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; char pjobvl = \'N\', pjobvr = \'N\'; char pbalanc, psens; extern int FORTRAN($TFD(s,d)ggevx)(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *alphar, $GENERIC() *alphai, $GENERIC() * beta, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, integer *ilo, integer *ihi, $GENERIC() *lscale, $GENERIC() *rscale, $GENERIC() *abnrm, $GENERIC() *bbnrm, $GENERIC() *rconde, $GENERIC() * rcondv, $GENERIC() *work, integer *lwork, integer *iwork, logical * bwork, integer *info); $GENERIC() tmp_work; if ($jobvl()) pjobvl = \'V\'; if ($jobvr()) pjobvr = \'V\'; switch ($balanc()) { case 1: pbalanc = \'P\'; break; case 2: pbalanc = \'S\'; break; case 3: pbalanc = \'B\'; break; default: pbalanc = \'N\'; } switch ($sense()) { case 1: psens = \'E\'; break; case 2: psens = \'V\'; break; case 3: psens = \'B\'; break; default: psens = \'N\'; } FORTRAN($TFD(s,d)ggevx)( &pbalanc, &pjobvl, &pjobvr, &psens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alphar), $P(alphai), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(lscale), $P(rscale), $P(abnrm), $P(bbnrm), $P(rconde), $P(rcondv), &tmp_work, &lwork, $P(iwork), $P(bwork), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ggevx)( &pbalanc, &pjobvl, &pjobvr, &psens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alphar), $P(alphai), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(lscale), $P(rscale), $P(abnrm), $P(bbnrm), $P(rconde), $P(rcondv), work, &lwork, $P(iwork), $P(bwork), $P(info)); free(work); } ', Doc => ' =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B) the generalized eigenvalues, and optionally, the left and/or right generalized eigenvectors. Optionally also, it computes a balancing transformation to improve the conditioning of the eigenvalues and eigenvectors (ilo, ihi, lscale, rscale, abnrm, and bbnrm), reciprocal condition numbers for the eigenvalues (rconde), and reciprocal condition numbers for the right eigenvectors (rcondv). A generalized eigenvalue for a pair of matrices (A,B) is a scalar lambda or a ratio alpha/beta = lambda, such that A - lambda*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0, and even for both being zero. The right eigenvector v(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies A * v(j) = lambda(j) * B * v(j) . The left eigenvector u(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies u(j)**H * A = lambda(j) * u(j)**H * B. where u(j)**H is the conjugate-transpose of u(j). Further Details =============== Balancing a matrix pair (A,B) includes, first, permuting rows and columns to isolate eigenvalues, second, applying diagonal similarity transformation to the rows and columns to make the rows and columns as close in norm as possible. The computed reciprocal condition numbers correspond to the balanced matrix. Permuting rows and columns will not change the condition numbers (in exact arithmetic) but diagonal scaling will. For further explanation of balancing, see section 4.11.1.2 of LAPACK Users\' Guide. An approximate error bound on the chordal distance between the i-th computed generalized eigenvalue w and the corresponding exact eigenvalue lambda is chord(w, lambda) <= EPS * norm(abnrm, bbnrm) / rconde(I) An approximate error bound for the angle between the i-th computed eigenvector vl(i) or vr(i) is given by EPS * norm(abnrm, bbnrm) / DIF(i). For further explanation of the reciprocal condition numbers rconde and rcondv, see section 4.11 of LAPACK User\'s Guide. Arguments ========= balanc: Specifies the balance option to be performed. = 0: do not diagonally scale or permute; = 1: permute only; = 2: scale only; = 3: both permute and scale. Computed reciprocal condition numbers will be for the matrices after permuting and/or balancing. Permuting does not change condition numbers (in exact arithmetic), but balancing does. jobvl: = 0: do not compute the left generalized eigenvectors; = 1: compute the left generalized eigenvectors. jobvr: = 0: do not compute the right generalized eigenvectors; = 1: compute the right generalized eigenvectors. sense: Determines which reciprocal condition numbers are computed. = 0: none are computed; = 1: computed for eigenvalues only; = 2: computed for eigenvectors only; = 3: computed for eigenvalues and eigenvectors. A: On entry, the matrix A in the pair (A,B). On exit, A has been overwritten. If jobvl=1 or jobvr=1 or both, then A contains the first part of the real Schur form of the "balanced" versions of the input A and B. B: On entry, the matrix B in the pair (A,B). On exit, B has been overwritten. If jobvl=1 or jobvr=1 or both, then B contains the second part of the real Schur form of the "balanced" versions of the input A and B. alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio ALPHA/beta. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). vl: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of vl, in the same order as their eigenvalues. If the j-th eigenvalue is real, then u(j) = vl(:,j), the j-th column of vl. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then u(j) = vl(:,j)+i*vl(:,j+1) and u(j+1) = vl(:,j)-i*vl(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part) + abs(imag. part) = 1. Not referenced if jobvl = 0. vr: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of vr, in the same order as their eigenvalues. If the j-th eigenvalue is real, then v(j) = vr(:,j), the j-th column of vr. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then v(j) = vr(:,j)+i*vr(:,j+1) and v(j+1) = vr(:,j)-i*vr(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part) + abs(imag. part) = 1. Not referenced if jobvr = 0. ilo,ihi:ilo and ihi are integer values such that on exit A(i,j) = 0 and B(i,j) = 0 if i > j and j = 1,...,ilo-1 or i = ihi+1,...,N. If balanc = 0 or 2, ilo = 1 and ihi = N. lscale: Details of the permutations and scaling factors applied to the left side of A and B. If PL(j) is the index of the row interchanged with row j, and DL(j) is the scaling factor applied to row j, then lscale(j) = PL(j) for j = 1,...,ilo-1 = DL(j) for j = ilo,...,ihi = PL(j) for j = ihi+1,...,N. The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. rscale: Details of the permutations and scaling factors applied to the right side of A and B. If PR(j) is the index of the column interchanged with column j, and DR(j) is the scaling factor applied to column j, then rscale(j) = PR(j) for j = 1,...,ilo-1 = DR(j) for j = ilo,...,ihi = PR(j) for j = ihi+1,...,N The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. abnrm: The one-norm of the balanced matrix A. bbnrm: The one-norm of the balanced matrix B. rconde: If sense = 1 or 3, the reciprocal condition numbers of the selected eigenvalues, stored in consecutive elements of the array. For a complex conjugate pair of eigenvalues two consecutive elements of rconde are set to the same value. Thus rconde(j), rcondv(j), and the j-th columns of vl and vr all correspond to the same eigenpair (but not in general the j-th eigenpair, unless all eigenpairs are selected). If sense = 2, rconde is not referenced. rcondv: If sense = 2 or 3, the estimated reciprocal condition numbers of the selected eigenvectors, stored in consecutive elements of the array. For a complex eigenvector two consecutive elements of rcondv are set to the same value. If the eigenvalues cannot be reordered to compute rcondv(j), rcondv(j) is set to 0; this can only occur when the true value would be very small anyway. If sense = 1, rcondv is not referenced. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. No eigenvectors have been calculated, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: error return from tgevc. =for example $a = random(5,5); $b = random(5,5); $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vl = zeroes(5,5); $vr = zeroes(5,5); $lscale = zeroes(5); $rscale = zeroes(5); $ilo = null; $ihi = null; $abnrm = null; $bbnrm = null; $rconde = zeroes(5); $rcondv = zeroes(5); ggevx($a, 3, 1, 1, 3, $b, $alphar, $alphai, $beta, $vl, $vr, $ilo, $ihi, $lscale, $rscale, $abnrm, $bbnrm, $rconde,$rcondv,($info=null)); '); pp_addhdr(' void fselect_func_set(SV* func); void dselect_func_set(SV* func); PDL_Long fselect_wrapper(float *wr, float *wi); PDL_Long dselect_wrapper(double *wr, double *wi); '); pp_def("gees", HandleBad => 0, Pars => '[io]A(n,n); int jobvs(); int sort(); [o]wr(n); [o]wi(n); [o]vs(p,p); int [o]sdim(); int [o]info(); int [t]bwork(bworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvs), tmp, $PDL(vs), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', OtherPars => "SV* select_func", GenericTypes => [F,D], Code => generate_code ' char jvs = \'N\'; char psort = \'N\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)gees)(char *jobvs, char *sort, L_fp select, integer *n, $GENERIC() *a, integer *lda, integer *sdim, $GENERIC() *wr, $GENERIC() *wi, $GENERIC() *vs, integer *ldvs, $GENERIC() *work, integer *lwork, logical *bwork, integer *info); $GENERIC() tmp_work; $TFD(f,d)select_func_set($COMP(select_func)); if ($jobvs()) jvs = \'V\'; if ($sort()){ psort = \'S\'; } FORTRAN($TFD(s,d)gees)( &jvs, &psort, $TFD(f,d)select_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(wr), $P(wi), $P(vs), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(bwork), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gees)( &jvs, &psort, $TFD(f,d)select_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(wr), $P(wi), $P(vs), &(integer){$SIZE(p)}, work, &lwork, $P(bwork), $P(info)); free(work); } ', Doc => ' =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues, the real Schur form T, and, optionally, the matrix of Schur vectors Z. This gives the Schur factorization A = Z*T*Z\'. Optionally, it also orders the eigenvalues on the diagonal of the real Schur form so that selected eigenvalues are at the top left. The leading columns of Z then form an orthonormal basis for the invariant subspace corresponding to the selected eigenvalues. A matrix is in real Schur form if it is upper quasi-triangular with 1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the form [ a b ] [ c a ] where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). Arguments ========= jobvs: = 0: Schur vectors are not computed; = 1: Schur vectors are computed. sort: Specifies whether or not to order the eigenvalues on the diagonal of the Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see select_func). select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An eigenvalue wr(j)+sqrt(-1)*wi(j) is selected if select_func(SCALAR(wr(j)), SCALAR(wi(j))) is true; i.e., if either one of a complex conjugate pair of eigenvalues is selected, then both complex eigenvalues are selected. Note that a selected complex eigenvalue may no longer satisfy select_func(wr(j),wi(j)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2 (see info below). A: The N-by-N matrix A. On exit, A has been overwritten by its real Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which select_func is true. (Complex conjugate pairs for which select_func is true for either eigenvalue count as 2.) wr: wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues in the same order that they appear on the diagonal of the output Schur form T. Complex conjugate pairs of eigenvalues will appear consecutively with the eigenvalue having the positive imaginary part first. vs: If jobvs = 1, vs contains the orthogonal matrix Z of Schur vectors else vs is not referenced. info = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, and i is <= N: the QR algorithm failed to compute all the eigenvalues; elements 1:ILO-1 and i+1:N of wr and wi contain those eigenvalues which have converged; if jobvs = 1, vs contains the matrix which reduces A to its partially converged Schur form. = N+1: the eigenvalues could not be reordered because some eigenvalues were too close to separate (the problem is very ill-conditioned); = N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Schur form no longer satisfy select_func = 1 This could also be caused by underflow due to scaling. =for example sub select_function{ my ($a, $b ) = @_; # Stable "continuous time" eigenspace return $a < 0 ? 1 : 0; } $A = random (5,5); $wr= zeroes(5); $wi = zeroes(5); $vs = zeroes(5,5); $sdim = null; $info = null; gees($A, 1,1, $wr, $wi, $vs, $sdim, $info,\&select_function); '); pp_def("geesx", HandleBad => 0, Pars => '[io]A(n,n); int jobvs(); int sort(); int sense(); [o]wr(n); [o]wi(n); [o]vs(p,p); int [o]sdim(); [o]rconde();[o]rcondv(); int [o]info(); int [t]bwork(bworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvs), tmp, $PDL(vs), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', OtherPars => "SV* select_func" , GenericTypes => [F,D], Code => generate_code ' char jvs = \'N\'; char psort = \'N\'; integer lwork = 0; integer liwork = 1; integer *iwork; char sens; extern int FORTRAN($TFD(s,d)geesx)(char *jobvs, char *sort, L_fp select, char * sense, integer *n, $GENERIC() *a, integer *lda, integer *sdim, $GENERIC() *wr, $GENERIC() *wi, $GENERIC() *vs, integer *ldvs, $GENERIC() *rconde, $GENERIC() *rcondv, $GENERIC() *work, integer *lwork, integer *iwork, integer *liwork, logical *bwork, integer *info); $GENERIC() *work; $TFD(f,d)select_func_set($COMP(select_func)); if ($jobvs()) jvs = \'V\'; if ($sort()) psort = \'S\'; switch ($sense()) { case 1: sens = \'E\'; lwork = (integer ) ($SIZE(n) + $SIZE(n) * ($SIZE(n)/2+1)); iwork = (integer *) malloc (liwork * sizeof (integer)); break; case 2: sens = \'V\'; lwork = (integer ) ($SIZE(n) + $SIZE(n) * ($SIZE(n)/2+1)); if ($sort()){ liwork = (integer )(pow((($SIZE(n)/2)+1), 2)); iwork = (integer *) malloc (liwork * sizeof (integer)); } else{iwork = (integer *) malloc (liwork * sizeof (integer));} break; case 3: sens = \'B\'; lwork = (integer ) ($SIZE(n) + $SIZE(n) * ($SIZE(n)/2+1)); if ($sort()){ liwork = (integer )(pow((($SIZE(n)/2)+1), 2)); iwork = (integer *) malloc (liwork * sizeof (integer)); } else{iwork = (integer *) malloc (liwork * sizeof (integer));} break; default: sens = \'N\'; lwork = (integer ) ($SIZE(n) * 3); iwork = (integer *) malloc (liwork * sizeof (integer)); } work = ($GENERIC() * )malloc(lwork * sizeof ($GENERIC())); FORTRAN($TFD(s,d)geesx)( &jvs, &psort, $TFD(f,d)select_wrapper, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(wr), $P(wi), $P(vs), &(integer){$SIZE(p)}, $P(rconde), $P(rcondv), work, &lwork, iwork, &liwork, $P(bwork), $P(info)); free(work); free(iwork); ', Doc => ' =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues, the real Schur form T, and, optionally, the matrix of Schur vectors Z. This gives the Schur factorization A = Z*T*Z\'. Optionally, it also orders the eigenvalues on the diagonal of the real Schur form so that selected eigenvalues are at the top left; computes a reciprocal condition number for the average of the selected eigenvalues (rconde); and computes a reciprocal condition number for the right invariant subspace corresponding to the selected eigenvalues (rcondv). The leading columns of Z form an orthonormal basis for this invariant subspace. For further explanation of the reciprocal condition numbers rconde and rcondv, see Section 4.10 of the LAPACK Users\' Guide (where these quantities are called s and sep respectively). A real matrix is in real Schur form if it is upper quasi-triangular with 1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the form [ a b ] [ c a ] where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). Arguments ========= jobvs: = 0: Schur vectors are not computed; = 1: Schur vectors are computed. sort: Specifies whether or not to order the eigenvalues on the diagonal of the Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see select_func). select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form else select_func is not referenced. An eigenvalue wr(j)+sqrt(-1)*wi(j) is selected if select_func(wr(j),wi(j)) is true; i.e., if either one of a complex conjugate pair of eigenvalues is selected, then both are. Note that a selected complex eigenvalue may no longer satisfy select_func(wr(j),wi(j)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info may be set to N+3 (see info below). sense: Determines which reciprocal condition numbers are computed. = 0: None are computed; = 1: Computed for average of selected eigenvalues only; = 2: Computed for selected right invariant subspace only; = 3: Computed for both. If sense = 1, 2 or 3, sort must equal 1. A: On entry, the N-by-N matrix A. On exit, A is overwritten by its real Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which select_func is 1. (Complex conjugate pairs for which select_func is 1 for either eigenvalue count as 2.) wr: wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues, in the same order that they appear on the diagonal of the output Schur form T. Complex conjugate pairs of eigenvalues appear consecutively with the eigenvalue having the positive imaginary part first. vs If jobvs = 1, vs contains the orthogonal matrix Z of Schur vectors else vs is not referenced. rconde: If sense = 1 or 3, rconde contains the reciprocal condition number for the average of the selected eigenvalues. Not referenced if sense = 0 or 2. rcondv: If sense = 2 or 3, rcondv contains the reciprocal condition number for the selected right invariant subspace. Not referenced if sense = 0 or 1. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, and i is <= N: the QR algorithm failed to compute all the eigenvalues; elements 1:ilo-1 and i+1:N of wr and wi contain those eigenvalues which have converged; if jobvs = 1, vs contains the transformation which reduces A to its partially converged Schur form. = N+1: the eigenvalues could not be reordered because some eigenvalues were too close to separate (the problem is very ill-conditioned); = N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Schur form no longer satisfy select_func=1 This could also be caused by underflow due to scaling. =for example sub select_function{ my ($a, $b) = @_; # Stable "discrete time" eigenspace return sqrt($a**2 + $b**2) < 1 ? 1 : 0; } $A = random (5,5); $wr= zeroes(5); $wi = zeroes(5); $vs = zeroes(5,5); $sdim = null; $rconde = null; $rcondv = null; $info = null; geesx($A, 1,1, 3, $wr, $wi, $vs, $sdim, $rconde, $rcondv, $info, \&select_function); '); pp_addhdr(' void fgselect_func_set(SV* func); void dgselect_func_set(SV* func); PDL_Long fgselect_wrapper(float *zr, float *zi, float *d); PDL_Long dgselect_wrapper(double *zr, double *zi, double *d); '); pp_def("gges", HandleBad => 0, Pars => '[io]A(n,n); int jobvsl();int jobvsr();int sort();[io]B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VSL(m,m);[o]VSR(p,p);int [o]sdim();int [o]info(); int [t]bwork(bworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsl), tmp, $PDL(VSL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsr), tmp, $PDL(VSR), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', OtherPars => "SV* select_func" , GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; char pjobvsl = \'N\', pjobvsr = \'N\', psort = \'N\'; extern int FORTRAN($TFD(s,d)gges)(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer *sdim, $GENERIC() *alphar, $GENERIC() *alphai, $GENERIC() *beta, $GENERIC() *vsl, integer *ldvsl, $GENERIC() *vsr, integer *ldvsr, $GENERIC() *work, integer *lwork, logical *bwork, integer *info); $GENERIC() tmp_work; $TFD(f,d)gselect_func_set($COMP(select_func)); if ($jobvsl()) pjobvsl = \'V\'; if ($jobvsr()) pjobvsr = \'V\'; if ($sort()){ psort = \'S\'; } FORTRAN($TFD(s,d)gges)( &pjobvsl, &pjobvsr, &psort, $TFD(f,d)gselect_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(sdim), $P(alphar), $P(alphai), $P(beta), $P(VSL), &(integer){$SIZE(m)}, $P(VSR), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(bwork), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gges)( &pjobvsl, &pjobvsr, &psort, $TFD(f,d)gselect_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(sdim), $P(alphar), $P(alphai), $P(beta), $P(VSL), &(integer){$SIZE(m)}, $P(VSR), &(integer){$SIZE(p)}, work, &lwork, $P(bwork), $P(info)); free(work); } ', Doc => ' =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B), the generalized eigenvalues, the generalized real Schur form (S,T), optionally, the left and/or right matrices of Schur vectors (VSL and VSR). This gives the generalized Schur factorization (A,B) = ( (VSL)*S*(VSR)\', (VSL)*T*(VSR)\' ) Optionally, it also orders the eigenvalues so that a selected cluster of eigenvalues appears in the leading diagonal blocks of the upper quasi-triangular matrix S and the upper triangular matrix T.The leading columns of VSL and VSR then form an orthonormal basis for the corresponding left and right eigenspaces (deflating subspaces). (If only the generalized eigenvalues are needed, use the driver ggev instead, which is faster.) A generalized eigenvalue for a pair of matrices (A,B) is a scalar w or a ratio alpha/beta = w, such that A - w*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0 or both being zero. A pair of matrices (S,T) is in generalized real Schur form if T is upper triangular with non-negative diagonal and S is block upper triangular with 1-by-1 and 2-by-2 blocks. 1-by-1 blocks correspond to real generalized eigenvalues, while 2-by-2 blocks of S will be "standardized" by making the corresponding elements of T have the form: [ a 0 ] [ 0 b ] and the pair of corresponding 2-by-2 blocks in S and T will have a complex conjugate pair of generalized eigenvalues. Arguments ========= jobvsl: = 0: do not compute the left Schur vectors; = 1: compute the left Schur vectors. jobvsr: = 0: do not compute the right Schur vectors; = 1: compute the right Schur vectors. sort: Specifies whether or not to order the eigenvalues on the diagonal of the generalized Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see delztg); delztg: If sort = 0, delztg is not referenced. If sort = 1, delztg is used to select eigenvalues to sort to the top left of the Schur form. An eigenvalue (alphar(j)+alphai(j))/beta(j) is selected if delztg(alphar(j),alphai(j),beta(j)) is true; i.e. if either one of a complex conjugate pair of eigenvalues is selected, then both complex eigenvalues are selected. Note that in the ill-conditioned case, a selected complex eigenvalue may no longer satisfy delztg(alphar(j),alphai(j), beta(j)) = 1 after ordering. info is to be set to N+2 in this case. A: On entry, the first of the pair of matrices. On exit, A has been overwritten by its generalized Schur form S. B: On entry, the second of the pair of matrices. On exit, B has been overwritten by its generalized Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which delztg is true. (Complex conjugate pairs for which delztg is true for either eigenvalue count as 2.) alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. alphar(j) + alphai(j)*i, and beta(j),j=1,...,N are the diagonals of the complex Schur form (S,T) that would result if the 2-by-2 diagonal blocks of the real Schur form of (A,B) were further reduced to triangular form using 2-by-2 complex unitary transformations. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). VSL: If jobvsl = 1, VSL will contain the left Schur vectors. Not referenced if jobvsl = 0. The leading dimension must always be >=1. VSR: If jobvsr = 1, VSR will contain the right Schur vectors. Not referenced if jobvsr = 0. The leading dimension must always be >=1. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. (A,B) are not in Schur form, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Generalized Schur form no longer satisfy delztg=1 This could also be caused due to scaling. =N+3: reordering failed in tgsen. =for example sub my_select{ my ($zr, $zi, $d) = @_; # stable generalized eigenvalues for continuous time return ( ($zr < 0 && $d > 0 ) || ($zr > 0 && $d < 0) ) ? 1 : 0; } $a = random(5,5); $b = random(5,5); $sdim = null; $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vsl = zeroes(5,5); $vsr = zeroes(5,5); gges($a, 1, 1, 1, $b, $alphar, $alphai, $beta, $vsl, $vsr, $sdim,($info=null), \&my_select); '); pp_def("ggesx", HandleBad => 0, Pars => '[io]A(n,n); int jobvsl();int jobvsr();int sort();int sense();[io]B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VSL(m,m);[o]VSR(p,p);int [o]sdim();[o]rconde(q=2);[o]rcondv(q=2);int [o]info(); int [t]bwork(bworkn); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsl), tmp, $PDL(VSL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsr), tmp, $PDL(VSR), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) $SIZE(iworkn) = $SIZE(n) + 6; // Bug in Lapack ????? ', OtherPars => "SV* select_func" , GenericTypes => [F,D], Code => generate_code ' integer maxwrk, lwork; integer minwrk = 1; static integer c__0 = 0; static integer c__1 = 1; static integer c_n1 = -1; char pjobvsl = \'N\'; char pjobvsr = \'N\'; char psort = \'N\'; char psens = \'N\'; integer *iwork; extern int FORTRAN($TFD(s,d)ggesx)(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, char *sense, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer *sdim, $GENERIC() *alphar, $GENERIC() *alphai, $GENERIC() *beta, $GENERIC() *vsl, integer *ldvsl, $GENERIC() *vsr, integer *ldvsr, $GENERIC() *rconde, $GENERIC() *rcondv, $GENERIC() *work, integer *lwork, integer *iwork, integer *liwork, logical *bwork, integer *info); $TFD(f,d)gselect_func_set($COMP(select_func)); if ($jobvsr()) pjobvsr = \'V\'; if ($sort()){ psort = \'S\'; } switch ($sense()) { case 1: psens = \'E\'; break; case 2: psens = \'V\'; break; case 3: psens = \'B\'; break; default: psens = \'N\'; } // Code modified from Lapack // TODO other schur form above // The actual updated release (clapack 09/20/2000) do not allow // querying the workspace. See release notes of Lapack // for this feature. minwrk = ($SIZE(n) + 1 << 3) + 16; maxwrk = ($SIZE(n) + 1) * 7 + $SIZE(n) * (integer)FORTRAN(ilaenv)(&c__1, "DGEQRF", " ", &(integer){$SIZE(n)}, &c__1, &(integer){$SIZE(n)}, &c__0, (ftnlen)6, (ftnlen)1) + 16; if ($jobvsl()) { integer i__1 = maxwrk; integer i__2 = minwrk + $SIZE(n) * (integer)FORTRAN(ilaenv)(&c__1, "DORGQR" , " ", &(integer){$SIZE(n)}, &c__1, &(integer){$SIZE(n)}, &c_n1, (ftnlen)6, (ftnlen)1); maxwrk = (integer ) max(i__1,i__2); pjobvsl = \'V\'; } lwork = (integer ) max(maxwrk,minwrk); { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ggesx)( &pjobvsl, &pjobvsr, &psort, $TFD(f,d)gselect_wrapper, &psens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(sdim), $P(alphar), $P(alphai), $P(beta), $P(VSL), &(integer){$SIZE(m)}, $P(VSR), &(integer){$SIZE(p)}, $P(rconde), $P(rcondv), work, &lwork, $P(iwork), &(integer){$SIZE(iworkn)}, $P(bwork), $P(info)); free(work); } ', Doc => ' =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B), the generalized eigenvalues, the real Schur form (S,T), and, optionally, the left and/or right matrices of Schur vectors (VSL and VSR). This gives the generalized Schur factorization (A,B) = ( (VSL) S (VSR)\', (VSL) T (VSR)\' ) Optionally, it also orders the eigenvalues so that a selected cluster of eigenvalues appears in the leading diagonal blocks of the upper quasi-triangular matrix S and the upper triangular matrix T; computes a reciprocal condition number for the average of the selected eigenvalues (RCONDE); and computes a reciprocal condition number for the right and left deflating subspaces corresponding to the selected eigenvalues (RCONDV). The leading columns of VSL and VSR then form an orthonormal basis for the corresponding left and right eigenspaces (deflating subspaces). A generalized eigenvalue for a pair of matrices (A,B) is a scalar w or a ratio alpha/beta = w, such that A - w*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0 or for both being zero. A pair of matrices (S,T) is in generalized real Schur form if T is upper triangular with non-negative diagonal and S is block upper triangular with 1-by-1 and 2-by-2 blocks. 1-by-1 blocks correspond to real generalized eigenvalues, while 2-by-2 blocks of S will be "standardized" by making the corresponding elements of T have the form: [ a 0 ] [ 0 b ] and the pair of corresponding 2-by-2 blocks in S and T will have a complex conjugate pair of generalized eigenvalues. Further details =============== An approximate (asymptotic) bound on the average absolute error of the selected eigenvalues is EPS * norm((A, B)) / RCONDE( 1 ). An approximate (asymptotic) bound on the maximum angular error in the computed deflating subspaces is EPS * norm((A, B)) / RCONDV( 2 ). See LAPACK User\'s Guide, section 4.11 for more information. Arguments ========= jobvsl: = 0: do not compute the left Schur vectors; = 1: compute the left Schur vectors. jobvsr: = 0: do not compute the right Schur vectors; = 1: compute the right Schur vectors. sort: Specifies whether or not to order the eigenvalues on the diagonal of the generalized Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see delztg); delztg: If sort = 0, delztg is not referenced. If sort = 1, delztg is used to select eigenvalues to sort to the top left of the Schur form. An eigenvalue (alphar(j)+alphai(j))/beta(j) is selected if delztg(alphar(j),alphai(j),beta(j)) is true; i.e. if either one of a complex conjugate pair of eigenvalues is selected, then both complex eigenvalues are selected. Note that in the ill-conditioned case, a selected complex eigenvalue may no longer satisfy delztg(alphar(j),alphai(j), beta(j)) = 1 after ordering. info is to be set to N+2 in this case. sense: Determines which reciprocal condition numbers are computed. = 0 : None are computed; = 1 : Computed for average of selected eigenvalues only; = 2 : Computed for selected deflating subspaces only; = 3 : Computed for both. If sense = 1, 2, or 3, sort must equal 1. A: On entry, the first of the pair of matrices. On exit, A has been overwritten by its generalized Schur form S. B: On entry, the second of the pair of matrices. On exit, B has been overwritten by its generalized Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which delztg is true. (Complex conjugate pairs for which delztg is true for either eigenvalue count as 2.) alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. alphar(j) + alphai(j)*i, and beta(j),j=1,...,N are the diagonals of the complex Schur form (S,T) that would result if the 2-by-2 diagonal blocks of the real Schur form of (A,B) were further reduced to triangular form using 2-by-2 complex unitary transformations. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). VSL: If jobvsl = 1, VSL will contain the left Schur vectors. Not referenced if jobvsl = 0. The leading dimension must always be >=1. VSR: If jobvsr = 1, VSR will contain the right Schur vectors. Not referenced if jobvsr = 0. The leading dimension must always be >=1. rconde: If sense = 1 or 3, rconde(1) and rconde(2) contain the reciprocal condition numbers for the average of the selected eigenvalues. Not referenced if sense = 0 or 2. rcondv: If sense = 2 or 3, rcondv(1) and rcondv(2) contain the reciprocal condition numbers for the selected deflating subspaces. Not referenced if sense = 0 or 1. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. (A,B) are not in Schur form, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Generalized Schur form no longer satisfy delztg=1 This could also be caused due to scaling. =N+3: reordering failed in tgsen. =for example sub my_select{ my ($zr, $zi, $d) = @_; # Eigenvalue : (ZR/D) + sqrt(-1)*(ZI/D) # stable generalized eigenvalues for discrete time return (sqrt($zr**2 + $zi**2) < abs($d) ) ? 1 : 0; } $a = random(5,5); $b = random(5,5); $sdim = null; $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vsl = zeroes(5,5); $vsr = zeroes(5,5); $rconde = zeroes(2); $rcondv = zeroes(2); ggesx($a, 1, 1, 1, 3,$b, $alphar, $alphai, $beta, $vsl, $vsr, $sdim, $rconde, $rcondv, ($info=null), \&my_select); '); pp_def("syev", HandleBad => 0, Pars => '[io,phys]A(n,n); int jobz(); int uplo(); [o,phys]w(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)syev)(char *jobz, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *w, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)syev)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)syev)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes all eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the orthonormal eigenvectors of the matrix A. If jobz = 0, then on exit the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. w: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the algorithm failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero. =for example # Assume $a is symmetric ;) $a = random (5,5); syev($a, 1,1, (my $w = zeroes(5)), (my $info=null)); '); pp_def("syevd", HandleBad => 0, Pars => '[io,phys]A(n,n); int jobz(); int uplo(); [o,phys]w(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; integer liwork = -1; integer tmp_liwork; integer *iwork; extern int FORTRAN($TFD(s,d)syevd)(char *jobz, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *w, $GENERIC() *work, integer *lwork, integer *iwork, integer *liwork, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)syevd)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), &tmp_work, &lwork, &tmp_liwork, &liwork, $P(info)); lwork = (integer )tmp_work; liwork = (integer )tmp_liwork; iwork = (integer *)malloc(liwork * sizeof(integer)); { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)syevd)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), work, &lwork, iwork, &liwork, $P(info)); free(work); free(iwork); } ', Doc => ' =for ref Computes all eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. If eigenvectors are desired, it uses a divide and conquer algorithm. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Because of large use of BLAS of level 3, syevd needs N**2 more workspace than syevx. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the orthonormal eigenvectors of the matrix A. If jobz = 0, then on exit the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. w: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the algorithm failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero. =for example # Assume $a is symmetric ;) $a = random (5,5); syevd($a, 1,1, (my $w = zeroes(5)), (my $info=null)); '); pp_def("syevx", HandleBad => 0, Pars => 'A(n,n); int jobz(); int range(); int uplo(); vl(); vu(); int il(); int iu(); abstol(); int [o]m(); [o]w(n); [o]z(p,p);int [o]ifail(n); int [o]info(); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp, $PDL(z), $SIZE(p), $SIZE(n)) $SIZE(iworkn) = 5 * $SIZE(n); ', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; char prange = \'A\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)syevx)(char *jobz, char *range, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *vl, $GENERIC() *vu, integer * il, integer *iu, $GENERIC() *abstol, integer *m, $GENERIC() *w, $GENERIC() *z__, integer *ldz, $GENERIC() *work, integer *lwork, integer *iwork, integer *ifail, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; switch ($range()) { case 1: prange = \'V\'; break; case 2: prange = \'I\'; break; default: prange = \'A\'; } FORTRAN($TFD(s,d)syevx)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(iwork), $P(ifail), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)syevx)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, work, &lwork, $P(iwork), $P(ifail), $P(info)); free(work); } ', Doc => ' =for ref Computes selected eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. Eigenvalues and eigenvectors can be selected by specifying either a range of values or a range of indices for the desired eigenvalues. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. range: = 0: all eigenvalues will be found. = 1: all eigenvalues in the half-open interval (vl,vu] will be found. = 1: the il-th through iu-th eigenvalues will be found. uplo = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. vl: vu: If range=1, the lower and upper bounds of the interval to be searched for eigenvalues. vl < vu. Not referenced if range = 0 or 2. il: iu: If range=2, the indices (in ascending order) of the smallest and largest eigenvalues to be returned. 1 <= il <= iu <= N, if N > 0; il = 1 and iu = 0 if N = 0. Not referenced if range = 0 or 1. abstol: The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when it is determined to lie in an interval [a,b] of width less than or equal to abstol + EPS * max( |a|,|b| ) , where EPS is the machine precision. If abstol is less than or equal to zero, then EPS*|T| will be used in its place, where |T| is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form. Eigenvalues will be computed most accurately when abstol is set to twice the underflow threshold 2*lamch(1), not zero. If this routine returns with info>0, indicating that some eigenvectors did not converge, try setting abstol to 2*lamch(1). See "Computing Small Singular Values of Bidiagonal Matrices with Guaranteed High Relative Accuracy," by Demmel and Kahan, LAPACK Working Note #3. m: The total number of eigenvalues found. 0 <= m <= N. If range = 0, m = N, and if range = 2, m = iu-il+1. w: On normal exit, the first M elements contain the selected eigenvalues in ascending order. z: If jobz = 1, then if info = 0, the first m columns of z contain the orthonormal eigenvectors of the matrix A corresponding to the selected eigenvalues, with the i-th column of z holding the eigenvector associated with w(i). If an eigenvector fails to converge, then that column of z contains the latest approximation to the eigenvector, and the index of the eigenvector is returned in ifail. If jobz = 0, then z is not referenced. Note: the user must ensure that at least max(1,m) columns are supplied in the array z; if range = 1, the exact value of m is not known in advance and an upper bound must be used. ifail: If jobz = 1, then if info = 0, the first m elements of ifail are zero. If info > 0, then ifail contains the indices of the eigenvectors that failed to converge. If jobz = 0, then ifail is not referenced. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, then i eigenvectors failed to converge. Their indices are stored in array ifail. =for example # Assume $a is symmetric ;) $a = random (5,5); $unfl = lamch(1); $ovfl = lamch(9); labad($unfl, $ovfl); $abstol = $unfl + $unfl; $m = null; $info = null; $ifail = zeroes(5); $w = zeroes(5); $z = zeroes(5,5); syevx($a, 1,0,1,0,0,0,0,$abstol, $m, $w, $z ,$ifail, $info); '); pp_def("syevr", HandleBad => 0, Pars => '[phys]A(n,n); int jobz(); int range(); int uplo(); [phys]vl(); [phys]vu(); int [phys]il(); int [phys]iu();[phys]abstol();int [o,phys]m();[o,phys]w(n); [o,phys]z(p,q);int [o,phys]isuppz(r); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; char prange = \'A\'; integer lwork = -1; integer liwork = -1; integer *iwork; integer tmp_iwork; extern int FORTRAN($TFD(s,d)syevr)(char *jobz, char *range, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *vl, $GENERIC() *vu, integer * il, integer *iu, $GENERIC() *abstol, integer *m, $GENERIC() *w, $GENERIC() *z__, integer *ldz, integer *isuppz, $GENERIC() *work, integer *lwork, integer *iwork, integer *liwork, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; switch ($range()) { case 1: prange = \'V\'; break; case 2: prange = \'I\'; break; default: prange = \'A\'; } FORTRAN($TFD(s,d)syevr)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, $P(isuppz), &tmp_work, &lwork, &tmp_iwork, &liwork, $P(info)); lwork = (integer )tmp_work; liwork = (integer )tmp_iwork; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); iwork = (integer *)malloc(liwork * sizeof(integer)); FORTRAN($TFD(s,d)syevr)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, $P(isuppz), work, &lwork, iwork, &liwork, $P(info)); free(work); free(iwork); } ', Doc => ' =for ref Computes selected eigenvalues and, optionally, eigenvectors of a real symmetric matrix T. Eigenvalues and eigenvectors can be selected by specifying either a range of values or a range of indices for the desired eigenvalues. Whenever possible, syevr calls stegr to compute the eigenspectrum using Relatively Robust Representations. stegr computes eigenvalues by the dqds algorithm, while orthogonal eigenvectors are computed from various "good" L D L^T representations (also known as Relatively Robust Representations). Gram-Schmidt orthogonalization is avoided as far as possible. More specifically, the various steps of the algorithm are as follows. For the i-th unreduced block of T, (a) Compute T - sigma_i = L_i D_i L_i^T, such that L_i D_i L_i^T is a relatively robust representation, (b) Compute the eigenvalues, lambda_j, of L_i D_i L_i^T to high relative accuracy by the dqds algorithm, (c) If there is a cluster of close eigenvalues, "choose" sigma_i close to the cluster, and go to step (a), (d) Given the approximate eigenvalue lambda_j of L_i D_i L_i^T, compute the corresponding eigenvector by forming a rank-revealing twisted factorization. The desired accuracy of the output can be specified by the input parameter abstol. For more details, see "A new O(n^2) algorithm for the symmetric tridiagonal eigenvalue/eigenvector problem", by Inderjit Dhillon, Computer Science Division Technical Report No. UCB//CSD-97-971, UC Berkeley, May 1997. Note 1 : syevr calls stegr when the full spectrum is requested on machines which conform to the ieee-754 floating point standard. syevr calls stebz and stein on non-ieee machines and when partial spectrum requests are made. Normal execution of stegr may create NaNs and infinities and hence may abort due to a floating point exception in environments which do not handle NaNs and infinities in the ieee standard default manner. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. range: = 0: all eigenvalues will be found. = 1: all eigenvalues in the half-open interval (vl,vu] will be found. = 2: the il-th through iu-th eigenvalues will be found. ********* For range = 1 or 2 and iu - il < N - 1, stebz and ********* stein are called uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. vl: vu: If range=1, the lower and upper bounds of the interval to be searched for eigenvalues. vl < vu. Not referenced if range = 0 or 2. il: iu: If range=2, the indices (in ascending order) of the smallest and largest eigenvalues to be returned. 1 <= il <= iu <= N, if N > 0; il = 1 and iu = 0 if N = 0. Not referenced if range = 0 or 1. abstol: The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when it is determined to lie in an interval [a,b] of width less than or equal to abstol + EPS * max( |a|,|b| ) , where EPS is the machine precision. If abstol is less than or equal to zero, then EPS*|T| will be used in its place, where |T| is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form. See "Computing Small Singular Values of Bidiagonal Matrices with Guaranteed High Relative Accuracy," by Demmel and Kahan, LAPACK Working Note #3. If high relative accuracy is important, set abstol to lamch(1). Doing so will guarantee that eigenvalues are computed to high relative accuracy when possible in future releases. The current code does not make any guarantees about high relative accuracy, but future releases will. See J. Barlow and J. Demmel, "Computing Accurate Eigensystems of Scaled Diagonally Dominant Matrices", LAPACK Working Note #7, for a discussion of which matrices define their eigenvalues to high relative accuracy. m: The total number of eigenvalues found. 0 <= m <= N. If range = 0, m = N, and if range = 2, m = iu-il+1. w: The first m elements contain the selected eigenvalues in ascending order. z: If jobz = 1, then if info = 0, the first m columns of z contain the orthonormal eigenvectors of the matrix A corresponding to the selected eigenvalues, with the i-th column of z holding the eigenvector associated with w(i). If jobz = 0, then z is not referenced. Note: the user must ensure that at least max(1,m) columns are supplied in the array z; if range = 1, the exact value of m is not known in advance and an upper bound must be used. isuppz: array of int, dimension ( 2*max(1,m) ) The support of the eigenvectors in z, i.e., the indices indicating the nonzero elements in z. The i-th eigenvector is nonzero only in elements isuppz( 2*i-1 ) through isuppz( 2*i ). ********* Implemented only for range = 0 or 2 and iu - il = N - 1 info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: Internal error =for example # Assume $a is symmetric ;) $a = random (5,5); $unfl = lamch(1); $ovfl = lamch(9); labad($unfl, $ovfl); $abstol = $unfl + $unfl; $m = null; $info = null; $isuppz = zeroes(10); $w = zeroes(5); $z = zeroes(5,5); syevr($a, 1,0,1,0,0,0,0,$abstol, $m, $w, $z ,$isuppz, $info); '); pp_def("sygv", HandleBad => 0, Pars => '[io,phys]A(n,n);int [phys]itype();int jobz(); int uplo();[io,phys]B(n,n);[o,phys]w(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)sygv)(integer *itype, char *jobz, char *uplo, integer * n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *w, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sygv)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)sygv)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes all the eigenvalues, and optionally, the eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric and B is also positive definite. Arguments ========= itype: Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo: = 0: Upper triangles of A and B are stored; = 1: Lower triangles of A and B are stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the matrix Z of eigenvectors. The eigenvectors are normalized as follows: if itype = 1 or 2, Z\'*B*Z = I; if itype = 3, Z\'*inv(B)*Z = I. If jobz = 0, then on exit the upper triangle (if uplo=0) or the lower triangle (if uplo=1) of A, including the diagonal, is destroyed. B: On entry, the symmetric positive definite matrix B. If uplo = 0, the leading N-by-N upper triangular part of B contains the upper triangular part of the matrix B. If uplo = 1, the leading N-by-N lower triangular part of B contains the lower triangular part of the matrix B. On exit, if info <= N, the part of B containing the matrix is overwritten by the triangular factor U or L from the Cholesky factorization B = U\'*U or B = L*L\'. W: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: potrf or syev returned an error code: <= N: if info = i, syev failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero; > N: if info = N + i, for 1 <= i <= N, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. =for example # Assume $a is symmetric ;) $a = random (5,5); # Assume $a is symmetric and positive definite ;) $b = random (5,5); sygv($a, 1,1, 0, $b, (my $w = zeroes(5)), (my $info=null)); '); pp_def("sygvd", HandleBad => 0, Pars => '[io,phys]A(n,n);int [phys]itype();int jobz(); int uplo();[io,phys]B(n,n);[o,phys]w(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; integer liwork = -1; integer *iwork; integer tmp_iwork; extern int FORTRAN($TFD(s,d)sygvd)(integer *itype, char *jobz, char *uplo, integer * n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *w, $GENERIC() *work, integer *lwork, integer *iwork, integer *liwork, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sygvd)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), &tmp_work, &lwork, &tmp_iwork, &liwork, $P(info)); lwork = (integer )tmp_work; liwork = (integer )tmp_iwork; iwork = (integer *)malloc(liwork * sizeof(integer)); { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)sygvd)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), work, &lwork, iwork, &liwork, $P(info)); free(work); } free(iwork); ', Doc => ' =for ref Computes all the eigenvalues, and optionally, the eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric and B is also positive definite. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Arguments ========= itype: Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo: = 0: Upper triangles of A and B are stored; = 1: Lower triangles of A and B are stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the matrix Z of eigenvectors. The eigenvectors are normalized as follows: if itype = 1 or 2, Z\'*B*Z = I; if itype = 3, Z\'*inv(B)*Z = I. If jobz = 0, then on exit the upper triangle (if uplo=0) or the lower triangle (if uplo=1) of A, including the diagonal, is destroyed. B: On entry, the symmetric positive definite matrix B. If uplo = 0, the leading N-by-N upper triangular part of B contains the upper triangular part of the matrix B. If uplo = 1, the leading N-by-N lower triangular part of B contains the lower triangular part of the matrix B. On exit, if info <= N, the part of B containing the matrix is overwritten by the triangular factor U or L from the Cholesky factorization B = U\'*U or B = L*L\'. W: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: potrf or syev returned an error code: <= N: if info = i, syevd failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero; > N: if info = N + i, for 1 <= i <= N, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. =for example # Assume $a is symmetric ;) $a = random (5,5); # Assume $b is symmetric positive definite ;) $b = random (5,5); sygvd($a, 1,1, 0, $b, (my $w = zeroes(5)), (my $info=null)); '); pp_def("sygvx", HandleBad => 0, Pars => '[io]A(n,n); int itype(); int jobz(); int range(); int uplo(); [io]B(n,n); vl(); vu(); int il(); int iu(); abstol(); int [o]m(); [o]w(n); [o]Z(p,p); int [o]ifail(n); int [o]info(); int [t]iwork(iworkn); ', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp, $PDL(Z), $SIZE(p), $SIZE(n)) $SIZE(iworkn) = 5 * $SIZE(n); ', GenericTypes => [F,D], Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; char prange; integer lwork = -1; extern int FORTRAN($TFD(s,d)sygvx)(integer *itype, char *jobz, char *range, char * uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *vl, $GENERIC() *vu, integer *il, integer *iu, $GENERIC() *abstol, integer *m, $GENERIC() *w, $GENERIC() *z__, integer *ldz, $GENERIC() *work, integer *lwork, integer *iwork, integer *ifail, integer *info); $GENERIC() tmp_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; switch ($range()) { case 1: prange = \'V\'; break; case 2: prange = \'I\'; break; default: prange = \'A\'; } FORTRAN($TFD(s,d)sygvx)( $P(itype), &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(Z), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(iwork), $P(ifail), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)sygvx)( $P(itype), &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(Z), &(integer){$SIZE(p)}, work, &lwork, $P(iwork), $P(ifail), $P(info)); free(work); } ', Doc => ' =for ref Computes selected eigenvalues, and optionally, eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric and B is also positive definite. Eigenvalues and eigenvectors can be selected by specifying either a range of values or a range of indices for the desired eigenvalues. Arguments ========= itype: Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. range: = 0: all eigenvalues will be found. = 1: all eigenvalues in the half-open interval (vl,vu] will be found. = 2: the il-th through iu-th eigenvalues will be found. uplo: = 0: Upper triangle of A and B are stored; = 1: Lower triangle of A and B are stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. B: On entry, the symmetric matrix B. If uplo = 0, the leading N-by-N upper triangular part of B contains the upper triangular part of the matrix B. If uplo = 1, the leading N-by-N lower triangular part of B contains the lower triangular part of the matrix B. On exit, if info <= N, the part of B containing the matrix is overwritten by the triangular factor U or L from the Cholesky factorization B = U\'*U or B = L*L\'. vl: vu: If range=1, the lower and upper bounds of the interval to be searched for eigenvalues. vl < vu. Not referenced if range = 0 or 2. il: iu: If range=2, the indices (in ascending order) of the smallest and largest eigenvalues to be returned. 1 <= il <= iu <= N, if N > 0; il = 1 and iu = 0 if N = 0. Not referenced if range = 0 or 1. abstol: The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when it is determined to lie in an interval [a,b] of width less than or equal to abstol + EPS * max( |a|,|b| ) , where EPS is the machine precision. If abstol is less than or equal to zero, then EPS*|T| will be used in its place, where |T| is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form. Eigenvalues will be computed most accurately when abstol is set to twice the underflow threshold 2*lamch(1), not zero. If this routine returns with info>0, indicating that some eigenvectors did not converge, try setting abstol to 2* lamch(1). m: The total number of eigenvalues found. 0 <= m <= N. If range = 0, m = N, and if range = 2, m = iu-il+1. w: On normal exit, the first m elements contain the selected eigenvalues in ascending order. Z: If jobz = 0, then Z is not referenced. If jobz = 1, then if info = 0, the first m columns of Z contain the orthonormal eigenvectors of the matrix A corresponding to the selected eigenvalues, with the i-th column of Z holding the eigenvector associated with w(i). The eigenvectors are normalized as follows: if itype = 1 or 2, Z\'*B*Z = I; if itype = 3, Z\'*inv(B)*Z = I. If an eigenvector fails to converge, then that column of Z contains the latest approximation to the eigenvector, and the index of the eigenvector is returned in ifail. Note: the user must ensure that at least max(1,m) columns are supplied in the array Z; if range = 1, the exact value of m is not known in advance and an upper bound must be used. ifail: If jobz = 1, then if info = 0, the first M elements of ifail are zero. If info > 0, then ifail contains the indices of the eigenvectors that failed to converge. If jobz = 0, then ifail is not referenced. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: potrf or syevx returned an error code: <= N: if info = i, syevx failed to converge; i eigenvectors failed to converge. Their indices are stored in array ifail. > N: if info = N + i, for 1 <= i <= N, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. =for example # Assume $a is symmetric ;) $a = random (5,5); # Assume $b is symmetric positive definite ;) $b = random (5,5); $unfl = lamch(1); $ovfl = lamch(9); labad($unfl, $ovfl); $abstol = $unfl + $unfl; $m = null; $w=zeroes(5); $z = zeroes(5,5); $ifail = zeroes(5); sygvx($a, 1,1, 0,0, $b, 0, 0, 0, 0, $abstol, $m, $w, $z,$ifail,(my $info=null)); '); pp_def("gesv", HandleBad => 0, Pars => '[io,phys]A(n,n); [io,phys]B(n,m); int [o,phys]ipiv(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' extern int FORTRAN($TFD(s,d)gesv)(integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer *ldb, integer *info); FORTRAN($TFD(s,d)gesv)( &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the solution to a real system of linear equations A * X = B, where A is an N-by-N matrix and X and B are N-by-NRHS matrices. The LU decomposition with partial pivoting and row interchanges is used to factor A as A = P * L * U, where P is a permutation matrix, L is unit lower triangular, and U is upper triangular. The factored form of A is then used to solve the system of equations A * X = B. Arguments ========= A: On entry, the N-by-N coefficient matrix A. On exit, the factors L and U from the factorization A = P*L*U; the unit diagonal elements of L are not stored. ipiv: The pivot indices that define the permutation matrix P; row i of the matrix was interchanged with row ipiv(i). B: On entry, the N-by-NRHS matrix of right hand side matrix B. On exit, if info = 0, the N-by-NRHS solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, so the solution could not be computed. =for example $a = random (5,5); $a = transpose($a); $b = random (5,5); $b = transpose($b); gesv($a,$b, (my $ipiv=zeroes(5)),(my $info=null)); print "The solution matrix X is :". transpose($b)."\n" unless $info; '); pp_def("gesvx", HandleBad => 0, Pars => '[io]A(n,n); int trans(); int fact(); [io]B(n,m); [io]af(n,n); int [io]ipiv(n); int [io]equed(); [o]r(p); [o]c(q); [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m);[o]rpvgrw();int [o]info(); [t]work(workn); int [t]iwork(n);', RedoDimsCode => ' $SIZE(p) = $SIZE(n); /* Ubuntu LAPACK 3 writes to r anyway */ $SIZE(q) = $SIZE(n); /* Ubuntu LAPACK 3 writes to c anyway */ $SIZE(workn) = 4 * $SIZE(n); ', GenericTypes => [F,D], Code => generate_code ' char ptrans, pfact, pequed; extern int FORTRAN($TFD(s,d)gesvx)(char *fact, char *trans, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, integer *ipiv, char *equed, $GENERIC() *r__, $GENERIC() *c__, $GENERIC() *b, integer *ldb, $GENERIC() *x, integer *ldx, $GENERIC() * rcond, $GENERIC() *ferr, $GENERIC() *berr, $GENERIC() *work, integer * iwork, integer *info); switch ($trans()) { case 1: ptrans = \'T\'; break; case 2: ptrans = \'C\'; break; default: ptrans = \'N\'; } switch ($fact()) { case 1: pfact = \'N\'; break; case 2: pfact = \'E\'; break; default: pfact = \'F\'; } switch ($equed()) { case 1: pequed = \'R\'; break; case 2: pequed = \'C\'; break; case 3: pequed = \'B\'; break; default: pequed = \'N\'; } FORTRAN($TFD(s,d)gesvx)( &pfact, &ptrans, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), &pequed, $P(r), $P(c), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), $P(work), $P(iwork), $P(info)); switch (pequed) { case \'R\': $equed() = 1; break; case \'C\': $equed() = 2; break; case \'B\': $equed() = 3; break; default: $equed()= 0; } $rpvgrw()=$work(workn=>0); ', Doc => ' =for ref Uses the LU factorization to compute the solution to a real system of linear equations A * X = B, where A is an N-by-N matrix and X and B are N-by-NRHS matrices. Error bounds on the solution and a condition estimate are also provided. =for desc The following steps are performed: =over 3 =item 1 If fact = 2, real scaling factors are computed to equilibrate the system: trans = 0: diag(r)*A*diag(c) *inv(diag(c))*X = diag(c)*B trans = 1: (diag(r)*A*diag(c))\' *inv(diag(r))*X = diag(c)*B trans = 2: (diag(r)*A*diag(c))**H *inv(diag(r))*X = diag(c)*B Whether or not the system will be equilibrated depends on the scaling of the matrix A, but if equilibration is used, A is overwritten by diag(r)*A*diag(c) and B by diag(r)*B (if trans=0) or diag(c)*B (if trans = 1 or 2). =item 2 If fact = 1 or 2, the LU decomposition is used to factor the matrix A (after equilibration if fact = 2) as A = P * L * U, where P is a permutation matrix, L is a unit lower triangular matrix, and U is upper triangular. =item 3 If some U(i,i)=0, so that U is exactly singular, then the routine returns with info = i. Otherwise, the factored form of A is used to estimate the condition number of the matrix A. If the reciprocal of the condition number is less than machine precision, info = N+1 is returned as a warning, but the routine still goes on to solve for X and compute error bounds as described below. =item 4 The system of equations is solved for X using the factored form of A. =item 5 Iterative refinement is applied to improve the computed solution matrix and calculate error bounds and backward error estimates for it. =item 6 If equilibration was used, the matrix X is premultiplied by diag(c) (if trans = 0) or diag(r) (if trans = 1 or 2) so that it solves the original system before equilibration. =back Arguments ========= fact: Specifies whether or not the factored form of the matrix A is supplied on entry, and if not, whether the matrix A should be equilibrated before it is factored. = 0: On entry, af and ipiv contain the factored form of A. If equed is not 0, the matrix A has been equilibrated with scaling factors given by r and c. A, af, and ipiv are not modified. = 1: The matrix A will be copied to af and factored. = 2: The matrix A will be equilibrated if necessary, then copied to af and factored. trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A\' * X = B (Transpose) = 2: A**H * X = B (Transpose) A: On entry, the N-by-N matrix A. If fact = 0 and equed is not 0, then A must have been equilibrated by the scaling factors in r and/or c. A is not modified if fact = 0 or 1, or if fact = 2 and equed = 0 on exit. On exit, if equed != 0, A is scaled as follows: equed = 1: A := diag(r) * A equed = 2: A := A * diag(c) equed = 3: A := diag(r) * A * diag(c). af: If fact = 0, then af is an input argument and on entry contains the factors L and U from the factorization A = P*L*U as computed by getrf. If equed != 0, then af is the factored form of the equilibrated matrix A. If fact = 1, then af is an output argument and on exit returns the factors L and U from the factorization A = P*L*U of the original matrix A. If fact = 2, then af is an output argument and on exit returns the factors L and U from the factorization A = P*L*U of the equilibrated matrix A (see the description of A for the form of the equilibrated matrix). ipiv: If fact = 0, then ipiv is an input argument and on entry contains the pivot indices from the factorization A = P*L*U as computed by getrf; row i of the matrix was interchanged with row ipiv(i). If fact = 1, then ipiv is an output argument and on exit contains the pivot indices from the factorization A = P*L*U of the original matrix A. If fact = 2, then ipiv is an output argument and on exit contains the pivot indices from the factorization A = P*L*U of the equilibrated matrix A. equed: Specifies the form of equilibration that was done. = 0: No equilibration (always true if fact = 1). = 1: Row equilibration, i.e., A has been premultiplied by diag(r). = 2: Column equilibration, i.e., A has been postmultiplied by diag(c). = 3: Both row and column equilibration, i.e., A has been replaced by diag(r) * A * diag(c). equed is an input argument if fact = 0; otherwise, it is an output argument. r: The row scale factors for A. If equed = 1 or 3, A is multiplied on the left by diag(r); if equed = 0 or 2, r is not accessed. r is an input argument if fact = 0; otherwise, r is an output argument. If fact = 0 and equed = 1 or 3, each element of r must be positive. c: The column scale factors for A. If equed = 2 or 3, A is multiplied on the right by diag(c); if equed = 0 or 1, c is not accessed. c is an input argument if fact = 0; otherwise, c is an output argument. If fact = 0 and equed = 2 or 3, each element of c must be positive. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if equed = 0, B is not modified; if trans = 0 and equed = 1 or 3, B is overwritten by diag(r)*B; if trans = 1 or 2 and equed = 2 or 3, B is overwritten by diag(c)*B. X: If info = 0 or info = N+1, the N-by-NRHS solution matrix X to the original system of equations. Note that A and B are modified on exit if equed != 0, and the solution to the equilibrated system is inv(diag(c))*X if trans = 0 and equed = 2 or 3, or inv(diag(r))*X if trans = 1 or 2 and equed = 1 or 3. rcond: The estimate of the reciprocal condition number of the matrix A after equilibration (if done). If rcond is less than the machine precision (in particular, if rcond = 0), the matrix is singular to working precision. This condition is indicated by a return code of info > 0. ferr: The estimated forward error bound for each solution vector X(j) (the j-th column of the solution matrix X). If XTRUE is the true solution corresponding to X(j), ferr(j) is an estimated upper bound for the magnitude of the largest element in (X(j) - XTRUE) divided by the magnitude of the largest element in X(j). The estimate is as reliable as the estimate for rcond, and is almost always a slight overestimate of the true error. berr: The componentwise relative backward error of each solution vector X(j) (i.e., the smallest relative change in any element of A or B that makes X(j) an exact solution). rpvgrw: Contains the reciprocal pivot growth factor norm(A)/norm(U). The "max absolute element" norm is used. If it is much less than 1, then the stability of the LU factorization of the (equilibrated) matrix A could be poor. This also means that the solution X, condition estimator rcond, and forward error bound ferr could be unreliable. If factorization fails with 0 0: if info = i, and i is <= N: U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, so the solution and error bounds could not be computed. rcond = 0 is returned. = N+1: U is nonsingular, but rcond is less than machine precision, meaning that the matrix is singular to working precision. Nevertheless, the solution and error bounds are computed because there are a number of situations where the computed solution can be more accurate than the value of rcond would suggest. =for example $a= random(5,5); $b = random(5,5); $a = transpose($a); $b = transpose($b); $rcond = pdl(0); $rpvgrw = pdl(0); $equed = pdl(long,0); $info = pdl(long,0); $berr = zeroes(5); $ipiv = zeroes(5); $ferr = zeroes(5); $r = zeroes(5); $c = zeroes(5); $X = zeroes(5,5); $af = zeroes(5,5); gesvx($a,0, 2, $b, $af, $ipiv, $equed, $r, $c, $X, $rcond, $ferr, $berr, $rpvgrw, $info); print "The solution matrix X is :". transpose($X)."\n" unless $info; '); pp_def("sysv", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); [io,phys]B(n,m); int [o]ipiv(n); int [o]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)sysv)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer *ldb, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sysv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)sysv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric matrix and X and B are N-by-NRHS matrices. The diagonal pivoting method is used to factor A as A = U * D * U\', if uplo = 0, or A = L * D * L\', if uplo = 1, where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. The factored form of A is then used to solve the system of equations A * X = B. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the block diagonal matrix D and the multipliers used to obtain the factor U or L from the factorization A = U*D*U\' or A = L*D*L\' as computed by sytrf. ipiv: Details of the interchanges and the block structure of D, as determined by sytrf. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged, and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if info = 0, the N-by-NRHS solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) is exactly zero. The factorization has been completed, but the block diagonal matrix D is exactly singular, so the solution could not be computed. =for example # Assume $a is symmetric ;) $a = random (5,5); $a = transpose($a); $b = random(4,5); $b = transpose($b); sysv($a, 1, $b, (my $ipiv=zeroes(5)),(my $info=null)); print "The solution matrix X is :". transpose($b)."\n" unless $info; '); pp_def("sysvx", HandleBad => 0, Pars => '[phys]A(n,n); int uplo(); int fact(); [phys]B(n,m); [io,phys]af(n,n); int [io,phys]ipiv(n); [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); int [t]iwork(n);', GenericTypes => [F,D], Code => generate_code ' char pfact = \'N\'; char puplo = \'U\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)sysvx)(char *fact, char *uplo, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, integer *ipiv, $GENERIC() *b, integer *ldb, $GENERIC() *x, integer * ldx, $GENERIC() *rcond, $GENERIC() *ferr, $GENERIC() *berr, $GENERIC() *work, integer *lwork, integer *iwork, integer *info); $GENERIC() tmp_work; if($fact()) pfact = \'F\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sysvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), &tmp_work, &lwork, $P(iwork), $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)sysvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), work, &lwork, $P(iwork), $P(info)); free(work); } ', Doc => ' =for ref Uses the diagonal pivoting factorization to compute the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric matrix and X and B are N-by-NRHS matrices. Error bounds on the solution and a condition estimate are also provided. The following steps are performed: =over 3 =item 1 If fact = 0, the diagonal pivoting method is used to factor A. The form of the factorization is A = U * D * U\', if uplo = 0, or A = L * D * L\', if uplo = 1, where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. =item 2 If some D(i,i)=0, so that D is exactly singular, then the routine returns with info = i. Otherwise, the factored form of A is used to estimate the condition number of the matrix A. If the reciprocal of the condition number is less than machine precision, info = N+1 is returned as a warning, but the routine still goes on to solve for X and compute error bounds as described below. =item 3 The system of equations is solved for X using the factored form of A. =item 4 Iterative refinement is applied to improve the computed solution matrix and calculate error bounds and backward error estimates for it. =back Arguments ========= fact: Specifies whether or not the factored form of A has been supplied on entry. = 0: The matrix A will be copied to af and factored. = 1: On entry, af and ipiv contain the factored form of A. af and ipiv will not be modified. uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: The symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. af: If fact = 1, then af is an input argument and on entry contains the block diagonal matrix D and the multipliers used to obtain the factor U or L from the factorization A = U*D*U\' or A = L*D*L\' as computed by sytrf. If fact = 0, then af is an output argument and on exit returns the block diagonal matrix D and the multipliers used to obtain the factor U or L from the factorization A = U*D*U\' or A = L*D*L\'. ipiv: If fact = 1, then ipiv is an input argument and on entry contains details of the interchanges and the block structure of D, as determined by sytrf. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. If fact = 0, then ipiv is an output argument and on exit contains details of the interchanges and the block structure of D, as determined by sytrf. B: The N-by-NRHS right hand side matrix B. X: If info = 0 or info = N+1, the N-by-NRHS solution matrix X. rcond: The estimate of the reciprocal condition number of the matrix A. If rcond is less than the machine precision (in particular, if rcond = 0), the matrix is singular to working precision. This condition is indicated by a return code of info > 0. ferr: The estimated forward error bound for each solution vector X(j) (the j-th column of the solution matrix X). If XTRUE is the true solution corresponding to X(j), ferr(j) is an estimated upper bound for the magnitude of the largest element in (X(j) - XTRUE) divided by the magnitude of the largest element in X(j). The estimate is as reliable as the estimate for rcond, and is almost always a slight overestimate of the true error. berr: The componentwise relative backward error of each solution vector X(j) (i.e., the smallest relative change in any element of A or B that makes X(j) an exact solution). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, and i is <= N: D(i,i) is exactly zero. The factorization has been completed but the factor D is exactly singular, so the solution and error bounds could not be computed. rcond = 0 is returned. = N+1: D is nonsingular, but rcond is less than machine precision, meaning that the matrix is singular to working precision. Nevertheless, the solution and error bounds are computed because there are a number of situations where the computed solution can be more accurate than the value of rcond would suggest. =for example $a= random(5,5); $b = random(10,5); $a = transpose($a); $b = transpose($b); $X = zeroes($b); $af = zeroes($a); $ipiv = zeroes(long, 5); $rcond = pdl(0); $ferr = zeroes(10); $berr = zeroes(10); $info = pdl(long, 0); # Assume $a is symmetric sysvx($a, 0, 0, $b,$af, $ipiv, $X, $rcond, $ferr, $berr,$info); print "The solution matrix X is :". transpose($X)."\n"; '); pp_def("posv", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); [io,phys]B(n,m); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)posv)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer *info); if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)posv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric positive definite matrix and X and B are N-by-NRHS matrices. The Cholesky decomposition is used to factor A as A = U\'* U, if uplo = 0, or A = L * L\', if uplo = 1, where U is an upper triangular matrix and L is a lower triangular matrix. The factored form of A is then used to solve the system of equations A * X = B. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the factor U or L from the Cholesky factorization A = U\'*U or A = L*L\'. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if info = 0, the N-by-NRHS solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the leading minor of order i of A is not positive definite, so the factorization could not be completed, and the solution has not been computed. =for example # Assume $a is symmetric positive definite ;) $a = random (5,5); $a = transpose($a); $b = random(4,5); $b = transpose($b); posv($a, 1, $b, (my $info=null)); print "The solution matrix X is :". transpose($b)."\n" unless $info; '); pp_def("posvx", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int fact(); [io,phys]B(n,m); [io,phys]af(n,n); int [io]equed(); [o]s(p); [o,phys]X(n,m); [o,phys]rcond(); [o,phys]ferr(m); [o,phys]berr(m); int [o,phys]info(); int [t]iwork(n); [t]work(workn);', RedoDimsCode => ' $SIZE(p) = $SIZE(n); /* Ubuntu LAPACK 3 writes to s anyway */ $SIZE(workn) = 3 * $SIZE(n); ', GenericTypes => [F,D], Code => generate_code ' char pfact; char pequed = \'N\'; char puplo = \'U\'; extern int FORTRAN($TFD(s,d)posvx)(char *fact, char *uplo, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, char *equed, $GENERIC() *s, $GENERIC() *b, integer *ldb, $GENERIC() * x, integer *ldx, $GENERIC() *rcond, $GENERIC() *ferr, $GENERIC() * berr, $GENERIC() *work, integer *iwork, integer *info); switch ($fact()) { case 1: pfact = \'N\'; break; case 2: pfact = \'E\'; break; default: pfact = \'F\'; } if ($equed()) pequed = \'Y\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)posvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, &pequed, $P(s), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), $P(work), $P(iwork), $P(info)); switch (pequed) { case \'Y\': $equed() = 1; break; default: $equed()= 0; } ', Doc => ' =for ref Uses the Cholesky factorization A = U\'*U or A = L*L\' to compute the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric positive definite matrix and X and B are N-by-NRHS matrices. Error bounds on the solution and a condition estimate are also provided. The following steps are performed: =over 3 =item 1 If fact = 2, real scaling factors are computed to equilibrate the system: diag(s) * A * diag(s) * inv(diag(s)) * X = diag(s) * B Whether or not the system will be equilibrated depends on the scaling of the matrix A, but if equilibration is used, A is overwritten by diag(s)*A*diag(s) and B by diag(s)*B. =item 2 If fact = 1 or 2, the Cholesky decomposition is used to factor the matrix A (after equilibration if fact = 2) as A = U\'* U, if uplo = 0, or A = L * L\', if uplo = 1, where U is an upper triangular matrix and L is a lower triangular matrix. =item 3 If the leading i-by-i principal minor is not positive definite, then the routine returns with info = i. Otherwise, the factored form of A is used to estimate the condition number of the matrix A. If the reciprocal of the condition number is less than machine precision, info = N+1 is returned as a warning, but the routine still goes on to solve for X and compute error bounds as described below. =item 4 The system of equations is solved for X using the factored form of A. =item 5 Iterative refinement is applied to improve the computed solution matrix and calculate error bounds and backward error estimates for it. =item 6 If equilibration was used, the matrix X is premultiplied by diag(s) so that it solves the original system before equilibration. =back Arguments ========= fact: Specifies whether or not the factored form of the matrix A is supplied on entry, and if not, whether the matrix A should be equilibrated before it is factored. = 0: On entry, af contains the factored form of A. If equed = 1, the matrix A has been equilibrated with scaling factors given by s. A and af will not be modified. = 1: The matrix A will be copied to af and factored. = 2: The matrix A will be equilibrated if necessary, then copied to af and factored. uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A, except if fact = 0 and equed = 1, then A must contain the equilibrated matrix diag(s)*A*diag(s). If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. A is not modified if fact = 0 or 1, or if fact = 2 and equed = 0 on exit. On exit, if fact = 2 and equed = 1, A is overwritten by diag(s)*A*diag(s). af: If fact = 0, then af is an input argument and on entry contains the triangular factor U or L from the Cholesky factorization A = U\'*U or A = L*L\', in the same storage format as A. If equed != 0, then af is the factored form of the equilibrated matrix diag(s)*A*diag(s). If fact = 1, then af is an output argument and on exit returns the triangular factor U or L from the Cholesky factorization A = U\'*U or A = L*L\' of the original matrix A. If fact = 2, then af is an output argument and on exit returns the triangular factor U or L from the Cholesky factorization A = U\'*U or A = L*L\' of the equilibrated matrix A (see the description of A for the form of the equilibrated matrix). equed: Specifies the form of equilibration that was done. = 0: No equilibration (always true if fact = 1). = 1: Equilibration was done, i.e., A has been replaced by diag(s) * A * diag(s). equed is an input argument if fact = 0; otherwise, it is an output argument. s: The scale factors for A; not accessed if equed = 0. s is an input argument if fact = 0; otherwise, s is an output argument. If fact = 0 and equed = 1, each element of s must be positive. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if equed = 0, B is not modified; if equed = 1, B is overwritten by diag(s) * B. X: If info = 0 or info = N+1, the N-by-NRHS solution matrix X to the original system of equations. Note that if equed = 1, A and B are modified on exit, and the solution to the equilibrated system is inv(diag(s))*X. rcond: The estimate of the reciprocal condition number of the matrix A after equilibration (if done). If rcond is less than the machine precision (in particular, if rcond = 0), the matrix is singular to working precision. This condition is indicated by a return code of info > 0. ferr: The estimated forward error bound for each solution vector X(j) (the j-th column of the solution matrix X). If XTRUE is the true solution corresponding to X(j), FERR(j) is an estimated upper bound for the magnitude of the largest element in (X(j) - XTRUE) divided by the magnitude of the largest element in X(j). The estimate is as reliable as the estimate for rcond, and is almost always a slight overestimate of the true error. berr: The componentwise relative backward error of each solution vector X(j) (i.e., the smallest relative change in any element of A or B that makes X(j) an exact solution). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, and i is <= N: the leading minor of order i of A is not positive definite, so the factorization could not be completed, and the solution has not been computed. rcond = 0 is returned. = N+1: U is nonsingular, but rcond is less than machine precision, meaning that the matrix is singular to working precision. Nevertheless, the solution and error bounds are computed because there are a number of situations where the computed solution can be more accurate than the value of rcond would suggest. =for example $a= random(5,5); $b = random(5,5); $a = transpose($a); $b = transpose($b); # Assume $a is symmetric positive definite $rcond = pdl(0); $equed = pdl(long,0); $info = pdl(long,0); $berr = zeroes(5); $ferr = zeroes(5); $s = zeroes(5); $X = zeroes(5,5); $af = zeroes(5,5); posvx($a,0,2,$b,$af, $equed, $s, $X, $rcond, $ferr, $berr,$info); print "The solution matrix X is :". transpose($X)."\n" unless $info; '); pp_def("gels", HandleBad => 0, Pars => '[io,phys]A(m,n); int trans(); [io,phys]B(p,q);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char ptrans = \'N\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)gels)(char *trans, integer *m, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($trans()) ptrans = \'T\'; FORTRAN($TFD(s,d)gels)( &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gels)( &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Solves overdetermined or underdetermined real linear systems involving an M-by-N matrix A, or its transpose, using a QR or LQ factorization of A. It is assumed that A has full rank. The following options are provided: =over 3 =item 1 If trans = 0 and m >= n: find the least squares solution of an overdetermined system, i.e., solve the least squares problem minimize || B - A*X ||. =item 2 If trans = 0 and m < n: find the minimum norm solution of an underdetermined system A * X = B. =item 3 If trans = 1 and m >= n: find the minimum norm solution of an undetermined system A\' * X = B. =item 4 If trans = 1 and m < n: find the least squares solution of an overdetermined system, i.e., solve the least squares problem minimize || B - A\' * X ||. =back Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. Arguments ========= trans: = 0: the linear system involves A; = 1: the linear system involves A\'. A: On entry, the M-by-N matrix A. On exit, if M >= N, A is overwritten by details of its QR factorization as returned by geqrf; if M < N, A is overwritten by details of its LQ factorization as returned by gelqf. B: On entry, the matrix B of right hand side vectors, stored columnwise; B is M-by-NRHS if trans = 0, or N-by-NRHS if trans = 1. On exit, B is overwritten by the solution vectors, stored columnwise: if trans = 0 and m >= n, rows 1 to n of B contain the least squares solution vectors; the residual sum of squares for the solution in each column is given by the sum of squares of elements N+1 to M in that column; if trans = 0 and m < n, rows 1 to N of B contain the minimum norm solution vectors; if trans = 1 and m >= n, rows 1 to M of B contain the minimum norm solution vectors; if trans = 1 and m < n, rows 1 to M of B contain the least squares solution vectors; the residual sum of squares for the solution in each column is given by the sum of squares of elements M+1 to N in that column. The leading dimension of the array B >= max(1,M,N). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); gels($a, 1, $b, ($info = null)); '); pp_def("gelsy", HandleBad => 0, Pars => '[io,phys]A(m,n); [io,phys]B(p,q); [phys]rcond(); int [io,phys]jpvt(n); int [o,phys]rank();int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)gelsy)(integer *m, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer * jpvt, $GENERIC() *rcond, integer *rank, $GENERIC() *work, integer * lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gelsy)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(jpvt), $P(rcond), $P(rank), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gelsy)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(jpvt), $P(rcond), $P(rank), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes the minimum-norm solution to a real linear least squares problem: minimize || A * X - B || using a complete orthogonal factorization of A. A is an M-by-N matrix which may be rank-deficient. Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. The routine first computes a QR factorization with column pivoting: A * P = Q * [ R11 R12 ] [ 0 R22 ] with R11 defined as the largest leading submatrix whose estimated condition number is less than 1/rcond. The order of R11, rank, is the effective rank of A. Then, R22 is considered to be negligible, and R12 is annihilated by orthogonal transformations from the right, arriving at the complete orthogonal factorization: A * P = Q * [ T11 0 ] * Z [ 0 0 ] The minimum-norm solution is then X = P * Z\' [ inv(T11)*Q1\'*B ] [ 0 ] where Q1 consists of the first rank columns of Q. Arguments ========= A: On entry, the M-by-N matrix A. On exit, A has been overwritten by details of its complete orthogonal factorization. B: On entry, the M-by-NRHS right hand side matrix B. On exit, the N-by-NRHS solution matrix X. The leading dimension of the array B >= max(1,M,N). jpvt: On entry, if jpvt(i) != 0, the i-th column of A is permuted to the front of AP, otherwise column i is a free column. On exit, if jpvt(i) = k, then the i-th column of AP was the k-th column of A. rcond: rcond is used to determine the effective rank of A, which is defined as the order of the largest leading triangular submatrix R11 in the QR factorization with pivoting of A, whose estimated condition number < 1/rcond. rank: The effective rank of A, i.e., the order of the submatrix R11. This is the same as the order of the submatrix T11 in the complete orthogonal factorization of A. info: = 0: successful exit < 0: If info = -i, the i-th argument had an illegal value. =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); $jpvt = zeroes(long, 5); $eps = lamch(0); #Threshold for rank estimation $rcond = sqrt($eps) - (sqrt($eps) - $eps) / 2; gelsy($a, $b, $rcond, $jpvt,($rank=null),($info = null)); '); pp_def("gelss", HandleBad => 0, Pars => '[io,phys]A(m,n); [io,phys]B(p,q); [phys]rcond(); [o,phys]s(r); int [o,phys]rank();int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)gelss)(integer *m, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *s, $GENERIC() *rcond, integer *rank, $GENERIC() *work, integer * lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gelss)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gelss)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes the minimum norm solution to a real linear least squares problem: Minimize 2-norm(| b - A*x |). using the singular value decomposition (SVD) of A. A is an M-by-N matrix which may be rank-deficient. Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. The effective rank of A is determined by treating as zero those singular values which are less than rcond times the largest singular value. Arguments ========= A: On entry, the M-by-N matrix A. On exit, the first min(m,n) rows of A are overwritten with its right singular vectors, stored rowwise. B: On entry, the M-by-NRHS right hand side matrix B. On exit, B is overwritten by the N-by-NRHS solution matrix X. If m >= n and rank = n, the residual sum-of-squares for the solution in the i-th column is given by the sum of squares of elements n+1:m in that column. The leading dimension of the array B >= max(1,M,N). s: The singular values of A in decreasing order. The condition number of A in the 2-norm = s(1)/s(min(m,n)). rcond: rcond is used to determine the effective rank of A. Singular values s(i) <= rcond*s(1) are treated as zero. If rcond < 0, machine precision is used instead. rank: The effective rank of A, i.e., the number of singular values which are greater than rcond*s(1). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: the algorithm for computing the SVD failed to converge; if info = i, i off-diagonal elements of an intermediate bidiagonal form did not converge to zero. =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); $eps = lamch(0); $s =zeroes(5); #Threshold for rank estimation $rcond = sqrt($eps) - (sqrt($eps) - $eps) / 2; gelss($a, $b, $rcond, $s, ($rank=null),($info = null)); '); pp_def("gelsd", HandleBad => 0, Pars => '[io]A(m,n); [io]B(p,q); rcond(); [o]s(minmn); int [o]rank();int [o]info(); int [t]iwork(iworkn);', GenericTypes => [F,D], RedoDimsCode => ' $SIZE(minmn) = PDLMAX(1,PDLMIN($SIZE(m),$SIZE(n))); integer smlsiz = FORTRAN(ilaenv)(&c_nine, "DGELSD", " ", &c_zero, &c_zero, &c_zero, &c_zero, (ftnlen)6, (ftnlen)1); integer size_i = (integer) (log((double) $SIZE(minmn) / (double) (smlsiz + 1)) /log(2.)) + 1; $SIZE(iworkn) = $SIZE(minmn) * (3 * PDLMAX(size_i,0) + 11); ', Code => generate_code ' integer lwork = -1; integer minmn = $SIZE(minmn); extern int FORTRAN($TFD(s,d)gelsd)(integer *m, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *s, $GENERIC() *rcond, integer *rank, $GENERIC() *work, integer * lwork, integer *iwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gelsd)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), &tmp_work, &lwork, $P(iwork), $P(info)); if ($info() != 0) $CROAK("workspace query failed: info=%d", $info()); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gelsd)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), work, &lwork, $P(iwork), $P(info)); free(work); } ', Doc => ' =for ref Computes the minimum-norm solution to a real linear least squares problem: minimize 2-norm(| b - A*x |) using the singular value decomposition (SVD) of A. A is an M-by-N matrix which may be rank-deficient. Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. The problem is solved in three steps: =over 3 =item 1 Reduce the coefficient matrix A to bidiagonal form with Householder transformations, reducing the original problem into a "bidiagonal least squares problem" (BLS) =item 2 Solve the BLS using a divide and conquer approach. =item 3 Apply back all the Householder transformations to solve the original least squares problem. =back The effective rank of A is determined by treating as zero those singular values which are less than rcond times the largest singular value. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Arguments ========= A: On entry, the M-by-N matrix A. On exit, A has been destroyed. B: On entry, the M-by-NRHS right hand side matrix B. On exit, B is overwritten by the N-by-NRHS solution matrix X. If m >= n and rank = n, the residual sum-of-squares for the solution in the i-th column is given by the sum of squares of elements n+1:m in that column. The leading dimension of the array B >= max(1,M,N). s: The singular values of A in decreasing order. The condition number of A in the 2-norm = s(1)/s(min(m,n)). rcond: rcond is used to determine the effective rank of A. Singular values s(i) <= rcond*s(1) are treated as zero. If rcond < 0, machine precision is used instead. rank: The effective rank of A, i.e., the number of singular values which are greater than rcond*s(1). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: the algorithm for computing the SVD failed to converge; if info = i, i off-diagonal elements of an intermediate bidiagonal form did not converge to zero. =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); $eps = lamch(0); $s =zeroes(5); #Threshold for rank estimation $rcond = sqrt($eps) - (sqrt($eps) - $eps) / 2; gelsd($a, $b, $rcond, $s, ($rank=null),($info = null)); '); pp_def("gglse", HandleBad => 0, Pars => '[phys]A(m,n); [phys]B(p,n);[io,phys]c(m);[phys]d(p);[o,phys]x(n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)gglse)(integer *m, integer *n, integer *p, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *c__, $GENERIC() *d__, $GENERIC() *x, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gglse)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(c), $P(d), $P(x), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gglse)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(c), $P(d), $P(x), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Solves the linear equality-constrained least squares (LSE) problem: minimize || c - A*x ||_2 subject to B*x = d where A is an M-by-N matrix, B is a P-by-N matrix, c is a given M-vector, and d is a given P-vector. It is assumed that P <= N <= M+P, and rank(B) = P and rank( ( A ) ) = N. ( ( B ) ) These conditions ensure that the LSE problem has a unique solution, which is obtained using a GRQ factorization of the matrices B and A. Arguments ========= A: On entry, the M-by-N matrix A. On exit, A is destroyed. B: On entry, the P-by-N matrix B. On exit, B is destroyed. c: On entry, c contains the right hand side vector for the least squares part of the LSE problem. On exit, the residual sum of squares for the solution is given by the sum of squares of elements N-P+1 to M of vector c. d: On entry, d contains the right hand side vector for the constrained equation. On exit, d is destroyed. x: On exit, x is the solution of the LSE problem. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random(7,5); $b = random(4,5); $c = random(7); $d = random(4); $x = zeroes(5); gglse($a, $b, $c, $d, $x, ($info=null)); '); pp_def("ggglm", HandleBad => 0, Pars => '[phys]A(n,m); [phys]B(n,p);[phys]d(n);[o,phys]x(m);[o,phys]y(p);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)ggglm)(integer *n, integer *m, integer *p, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *d__, $GENERIC() *x, $GENERIC() *y, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)ggglm)( &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(d), $P(x), $P(y), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ggglm)( &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(d), $P(x), $P(y), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Solves a general Gauss-Markov linear model (GLM) problem: minimize || y ||_2 subject to d = A*x + B*y x where A is an N-by-M matrix, B is an N-by-P matrix, and d is a given N-vector. It is assumed that M <= N <= M+P, and rank(A) = M and rank( A B ) = N. Under these assumptions, the constrained equation is always consistent, and there is a unique solution x and a minimal 2-norm solution y, which is obtained using a generalized QR factorization of A and B. In particular, if matrix B is square nonsingular, then the problem GLM is equivalent to the following weighted linear least squares problem minimize || inv(B)*(d-A*x) ||_2 x where inv(B) denotes the inverse of B. Arguments ========= A: On entry, the N-by-M matrix A. On exit, A is destroyed. B: On entry, the N-by-P matrix B. On exit, B is destroyed. d: On entry, d is the left hand side of the GLM equation. On exit, d is destroyed. x: y: On exit, x and y are the solutions of the GLM problem. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random(7,5); $b = random(7,4); $d = random(7); $x = zeroes(5); $y = zeroes(4); ggglm($a, $b, $d, $x, $y,($info=null)); '); ################################################################################ # # COMPUTATIONAL LEVEL ROUTINES # ################################################################################ # TODO IPIV = min(m,n) pp_def("getrf", HandleBad => 0, RedoDimsCode => '$SIZE(p) = PDLMIN($SIZE(m),$SIZE(n));', Pars => '[io]A(m,n); int [o]ipiv(p); int [o]info()', GenericTypes => [F,D], Code => generate_code ' extern int FORTRAN($TFD(s,d)getrf)(integer *m, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); FORTRAN($TFD(s,d)getrf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(ipiv), $P(info)); ', Doc => ' =for ref Computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges. The factorization has the form A = P * L * U where P is a permutation matrix, L is lower triangular with unit diagonal elements (lower trapezoidal if m > n), and U is upper triangular (upper trapezoidal if m < n). This is the right-looking Level 3 BLAS version of the algorithm. Arguments ========= A: On entry, the M-by-N matrix to be factored. On exit, the factors L and U from the factorization A = P*L*U; the unit diagonal elements of L are not stored. ipiv: The pivot indices; for 1 <= i <= min(M,N), row i of the matrix was interchanged with row ipiv(i). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, and division by zero will occur if it is used to solve a system of equations. =for example $a = random (float, 100,50); $ipiv = zeroes(long, 50); $info = null; getrf($a, $ipiv, $info); '); pp_def("getf2", HandleBad => 0, RedoDimsCode => '$SIZE(p) = PDLMIN($SIZE(m),$SIZE(n));', Pars => '[io]A(m,n); int [o]ipiv(p); int [o]info()', GenericTypes => [F,D], Code => generate_code ' extern int FORTRAN($TFD(s,d)getf2)(integer *m, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); FORTRAN($TFD(s,d)getf2)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(ipiv), $P(info)); ', Doc => ' =for ref Computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges. The factorization has the form A = P * L * U where P is a permutation matrix, L is lower triangular with unit diagonal elements (lower trapezoidal if m > n), and U is upper triangular (upper trapezoidal if m < n). This is the right-looking Level 2 BLAS version of the algorithm. Arguments ========= A: On entry, the M-by-N matrix to be factored. On exit, the factors L and U from the factorization A = P*L*U; the unit diagonal elements of L are not stored. ipiv: The pivot indices; for 1 <= i <= min(M,N), row i of the matrix was interchanged with row ipiv(i). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, and division by zero will occur if it is used to solve a system of equations. =for example $a = random (float, 100,50); $ipiv = zeroes(long, 50); $info = null; getf2($a, $ipiv, $info); '); pp_def("sytrf", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)sytrf)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sytrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)sytrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), work, &lwork, $P(info)); free (work); } ', Doc => ' =for ref Computes the factorization of a real symmetric matrix A using the Bunch-Kaufman diagonal pivoting method. The form of the factorization is A = U*D*U\' or A = L*D*L\' where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. This is the blocked version of the algorithm, calling Level 3 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, the block diagonal matrix D and the multipliers used to obtain the factor U or L (see below for further details). ipiv: Details of the interchanges and the block structure of D. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) is exactly zero. The factorization has been completed, but the block diagonal matrix D is exactly singular, and division by zero will occur if it is used to solve a system of equations. Further Details =============== If uplo = 0, then A = U*D*U\', where U = P(n)*U(n)* ... *P(k)U(k)* ..., i.e., U is a product of terms P(k)*U(k), where k decreases from n to 1 in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1 and 2-by-2 diagonal blocks D(k). P(k) is a permutation matrix as defined by ipiv(k), and U(k) is a unit upper triangular matrix, such that if the diagonal block D(k) is of order s (s = 1 or 2), then ( I v 0 ) k-s U(k) = ( 0 I 0 ) s ( 0 0 I ) n-k k-s s n-k If s = 1, D(k) overwrites A(k,k), and v overwrites A(1:k-1,k). If s = 2, the upper triangle of D(k) overwrites A(k-1,k-1), A(k-1,k), and A(k,k), and v overwrites A(1:k-2,k-1:k). If uplo = 1, then A = L*D*L\', where L = P(1)*L(1)* ... *P(k)*L(k)* ..., i.e., L is a product of terms P(k)*L(k), where k increases from 1 to n in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1 and 2-by-2 diagonal blocks D(k). P(k) is a permutation matrix as defined by ipiv(k), and L(k) is a unit lower triangular matrix, such that if the diagonal block D(k) is of order s (s = 1 or 2), then ( I 0 0 ) k-1 L(k) = ( 0 I 0 ) s ( 0 v I ) n-k-s+1 k-1 s n-k-s+1 If s = 1, D(k) overwrites A(k,k), and v overwrites A(k+1:n,k). If s = 2, the lower triangle of D(k) overwrites A(k,k), A(k+1,k), and A(k+1,k+1), and v overwrites A(k+2:n,k:k+1). =for example $a = random(100,100); $ipiv = zeroes(100); $info = null; # Assume $a is symmetric sytrf($a, 0, $ipiv, $info); '); pp_def("sytf2", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)sytf2)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sytf2)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(info)); ', Doc => ' =for ref Computes the factorization of a real symmetric matrix A using the Bunch-Kaufman diagonal pivoting method. The form of the factorization is A = U*D*U\' or A = L*D*L\' where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. This is the unblocked version of the algorithm, calling Level 2 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, the block diagonal matrix D and the multipliers used to obtain the factor U or L (see below for further details). ipiv: Details of the interchanges and the block structure of D. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) is exactly zero. The factorization has been completed, but the block diagonal matrix D is exactly singular, and division by zero will occur if it is used to solve a system of equations. For further details see sytrf =for example $a = random(100,100); $ipiv = zeroes(100); $info = null; # Assume $a is symmetric sytf2($a, 0, $ipiv, $info); '); pp_def("potrf", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)potrf)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *info); if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)potrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the Cholesky factorization of a real symmetric positive definite matrix A. The factorization has the form A = U\' * U, if uplo = 0, or A = L * L\', if uplo = 1, where U is an upper triangular matrix and L is lower triangular. This is the block version of the algorithm, calling Level 3 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the factor U or L from the Cholesky factorization A = U\'*U or A = L*L\'. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the leading minor of order i is not positive definite, and the factorization could not be completed. =for example $a = random(100,100); # Assume $a is symmetric positive definite potrf($a, 0, ($info = null)); '); pp_def("potf2", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)potf2)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *info); if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)potf2)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the Cholesky factorization of a real symmetric positive definite matrix A. The factorization has the form A = U\' * U, if uplo = 0, or A = L * L\', if uplo = 1, where U is an upper triangular matrix and L is lower triangular. This is the unblocked version of the algorithm, calling Level 2 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the factor U or L from the Cholesky factorization A = U\'*U or A = L*L\'. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the leading minor of order i is not positive definite, and the factorization could not be completed. =for example $a = random(100,100); # Assume $a is symmetric positive definite potf2($a, 0, ($info = null)); '); pp_def("getri", HandleBad => 0, Pars => '[io,phys]A(n,n); int [phys]ipiv(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)getri)(integer *n, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)getri)( &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)getri)( &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes the inverse of a matrix using the LU factorization computed by C. This method inverts U and then computes inv(A) by solving the system inv(A)*L = inv(U) for inv(A). Arguments ========= A: On entry, the factors L and U from the factorization A = P*L*U as computed by getrf. On exit, if info = 0, the inverse of the original matrix A. ipiv: The pivot indices from getrf; for 1<=i<=N, row i of the matrix was interchanged with row ipiv(i). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero; the matrix is singular and its inverse could not be computed. =for example $a = random (float, 100, 100); $ipiv = zeroes(long, 100); $info = null; getrf($a, $ipiv, $info); if ($info == 0){ getri($a, $ipiv, $info); } print "Inverse of \$a is :\n $a" unless $info; '); pp_def("sytri", HandleBad => 0, Pars => '[io]A(n,n); int uplo(); int ipiv(n); int [o]info(); [t]work(n);', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)sytri)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *work, integer *info); if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sytri)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(work), $P(info)); ', Doc => ' =for ref Computes the inverse of a real symmetric indefinite matrix A using the factorization A = U*D*U\' or A = L*D*L\' computed by C. Arguments ========= uplo: Specifies whether the details of the factorization are stored as an upper or lower triangular matrix. = 0: Upper triangular, form is A = U*D*U\'; = 1: Lower triangular, form is A = L*D*L\'. A: On entry, the block diagonal matrix D and the multipliers used to obtain the factor U or L as computed by sytrf. On exit, if info = 0, the (symmetric) inverse of the original matrix. If uplo = 0, the upper triangular part of the inverse is formed and the part of A below the diagonal is not referenced; if uplo = 1 the lower triangular part of the inverse is formed and the part of A above the diagonal is not referenced. ipiv: Details of the interchanges and the block structure of D as determined by sytrf. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) = 0; the matrix is singular and its inverse could not be computed. =for example $a = random (float, 100, 100); # assume $a is symmetric $ipiv = zeroes(long, 100); sytrf($a, 0, $ipiv, ($info=null)); if ($info == 0){ sytri($a, 0, $ipiv, $info); } print "Inverse of \$a is :\n $a" unless $info; '); pp_def("potri", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)potri)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *info); if ($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)potri)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the inverse of a real symmetric positive definite matrix A using the Cholesky factorization A = U\'*U or A = L*L\' computed by C. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the triangular factor U or L from the Cholesky factorization A = U\'*U or A = L*L\', as computed by potrf. On exit, the upper or lower triangle of the (symmetric) inverse of A, overwriting the input factor U or L. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the (i,i) element of the factor U or L is zero, and the inverse could not be computed. =for example $a = random (float, 100, 100); # Assume $a is symmetric positive definite potrf($a, 0, ($info = null)); if ($info == 0){ # Hum... is it positive definite???? potri($a, 0,$info); } print "Inverse of \$a is :\n $a" unless $info; '); pp_def("trtri", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int diag(); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; char pdiag = \'N\'; extern int FORTRAN($TFD(s,d)trtri)(char *uplo, char *diag, integer *n, $GENERIC() *a, integer * lda, integer *info); if ($uplo()) puplo = \'L\'; if ($diag()) pdiag = \'U\'; FORTRAN($TFD(s,d)trtri)( &puplo, &pdiag, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the inverse of a real upper or lower triangular matrix A. This is the Level 3 BLAS version of the algorithm. Arguments ========= uplo: = 0: A is upper triangular; = 1: A is lower triangular. diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: On entry, the triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. On exit, the (triangular) inverse of the original matrix, in the same storage format. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, A(i,i) is exactly zero. The triangular matrix is singular and its inverse can not be computed. =for example $a = random (float, 100, 100); # assume $a is upper triangular trtri($a, 1, ($info=null)); print "Inverse of \$a is :\n transpose($a)" unless $info; '); pp_def("trti2", HandleBad => 0, Pars => '[io,phys]A(n,n); int uplo(); int diag(); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; char pdiag = \'N\'; extern int FORTRAN($TFD(s,d)trti2)(char *uplo, char *diag, integer *n, $GENERIC() *a, integer * lda, integer *info); if ($uplo()) puplo = \'L\'; if ($diag()) pdiag = \'U\'; FORTRAN($TFD(s,d)trti2)( &puplo, &pdiag, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Computes the inverse of a real upper or lower triangular matrix A. This is the Level 2 BLAS version of the algorithm. Arguments ========= uplo: = 0: A is upper triangular; = 1: A is lower triangular. diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: On entry, the triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. On exit, the (triangular) inverse of the original matrix, in the same storage format. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); # assume $a is upper triangular trtri2($a, 1, ($info=null)); print "Inverse of \$a is :\n transpose($a)" unless $info; '); pp_def("getrs", HandleBad => 0, Pars => '[phys]A(n,n); int trans(); [io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char transp = \'N\'; extern int FORTRAN($TFD(s,d)getrs)(char *trans, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer * ldb, integer *info); if($trans()) transp = \'T\'; FORTRAN($TFD(s,d)getrs)( &transp, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Solves a system of linear equations A * X = B or A\' * X = B with a general N-by-N matrix A using the LU factorization computed by getrf. Arguments ========= trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A\'* X = B (Transpose) A: The factors L and U from the factorization A = P*L*U as computed by getrf. ipiv: The pivot indices from getrf; for 1<=i<=N, row i of the matrix was interchanged with row ipiv(i). B: On entry, the right hand side matrix B. On exit, the solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $ipiv = zeroes(long, 100); $b = random(100,50); getrf($a, $ipiv, ($info=null)); if ($info == 0){ getrs($a, 0, $b, $ipiv, $info); } print "X is :\n $b" unless $info; '); pp_def("sytrs", HandleBad => 0, Pars => '[phys]A(n,n); int uplo();[io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)sytrs)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer * ldb, integer *info); if($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sytrs)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Solves a system of linear equations A*X = B with a real symmetric matrix A using the factorization A = U*D*U\' or A = L*D*L\' computed by C. Arguments ========= uplo: Specifies whether the details of the factorization are stored as an upper or lower triangular matrix. = 0: Upper triangular, form is A = U*D*U\'; = 1: Lower triangular, form is A = L*D*L\'. A: The block diagonal matrix D and the multipliers used to obtain the factor U or L as computed by sytrf. ipiv: Details of the interchanges and the block structure of D as determined by sytrf. B: On entry, the right hand side matrix B. On exit, the solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $b = random(50,100); $a = transpose($a); $b = transpose($b); # Assume $a is symmetric sytrf($a, 0, ($ipiv=zeroes(100)), ($info=null)); if ($info == 0){ sytrs($a, 0, $b, $ipiv, $info); } print("X is :\n".transpose($b))unless $info; '); pp_def("potrs", HandleBad => 0, Pars => '[phys]A(n,n); int uplo(); [io,phys]B(n,m); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)potrs)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer * info); if($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)potrs)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Solves a system of linear equations A*X = B with a symmetric positive definite matrix A using the Cholesky factorization A = U\'*U or A = L*L\' computed by C. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: The triangular factor U or L from the Cholesky factorization A = U\'*U or A = L*L\', as computed by potrf. B: On entry, the right hand side matrix B. On exit, the solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $b = random(50,100); $a = transpose($a); $b = transpose($b); # Assume $a is symmetric positive definite potrf($a, 0, ($info=null)); if ($info == 0){ potrs($a, 0, $b, $info); } print("X is :\n".transpose($b))unless $info; '); pp_def("trtrs", HandleBad => 0, Pars => '[phys]A(n,n); int uplo(); int trans(); int diag();[io,phys]B(n,m); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; char ptrans = \'N\'; char pdiag = \'N\'; extern int FORTRAN($TFD(s,d)trtrs)(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer * ldb, integer *info); if($uplo()) puplo = \'L\'; if($trans()) ptrans = \'T\'; if($diag()) pdiag = \'U\'; FORTRAN($TFD(s,d)trtrs)( &puplo, &ptrans, &pdiag, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Solves a triangular system of the form A * X = B or A\' * X = B, where A is a triangular matrix of order N, and B is an N-by-NRHS matrix. A check is made to verify that A is nonsingular. Arguments ========= uplo: = 0: A is upper triangular; = 1: A is lower triangular. trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A**T * X = B (Transpose) diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: The triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. B: On entry, the right hand side matrix B. On exit, if info = 0, the solution matrix X. info = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the i-th diagonal element of A is zero, indicating that the matrix is singular and the solutions X have not been computed. =for example # Assume $a is upper triangular $a = random (float, 100, 100); $b = random(50,100); $a = transpose($a); $b = transpose($b); $info = null; trtrs($a, 0, 0, 0, $b, $info); print("X is :\n".transpose($b))unless $info; '); pp_def("latrs", HandleBad => 0, Pars => '[phys]A(n,n); int uplo(); int trans(); int diag(); int normin();[io,phys]x(n); [o,phys]scale();[io,phys]cnorm(n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; char ptrans = \'N\'; char pdiag = \'N\'; char pnormin = \'N\'; extern int FORTRAN($TFD(s,d)latrs)(char *uplo, char *trans, char *diag, char * normin, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *x, $GENERIC() *scale, $GENERIC() *cnorm, integer *info); if($uplo()) puplo = \'L\'; if($trans()) ptrans = \'T\'; if($diag()) pdiag = \'U\'; if($normin()) pnormin = \'Y\'; FORTRAN($TFD(s,d)latrs)( &puplo, &ptrans, &pdiag, &pnormin, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(x), $P(scale), $P(cnorm), $P(info)); ', Doc => ' =for ref Solves one of the triangular systems A *x = s*b or A\'*x = s*b with scaling to prevent overflow. Here A is an upper or lower triangular matrix, A\' denotes the transpose of A, x and b are n-element vectors, and s is a scaling factor, usually less than or equal to 1, chosen so that the components of x will be less than the overflow threshold. If the unscaled problem will not cause overflow, the Level 2 BLAS routine C is called. If the matrix A is singular (A(j,j) = 0 for some j), then s is set to 0 and a non-trivial solution to A*x = 0 is returned. Further Details ======= ======= A rough bound on x is computed; if that is less than overflow, trsv is called, otherwise, specific code is used which checks for possible overflow or divide-by-zero at every operation. A columnwise scheme is used for solving A*x = b. The basic algorithm if A is lower triangular is x[1:n] := b[1:n] for j = 1, ..., n x(j) := x(j) / A(j,j) x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] end Define bounds on the components of x after j iterations of the loop: M(j) = bound on x[1:j] G(j) = bound on x[j+1:n] Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. Then for iteration j+1 we have M(j+1) <= G(j) / | A(j+1,j+1) | G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | <= G(j) ( 1 + cnorm(j+1) / | A(j+1,j+1) | ) where cnorm(j+1) is greater than or equal to the infinity-norm of column j+1 of A, not counting the diagonal. Hence G(j) <= G(0) product ( 1 + cnorm(i) / | A(i,i) | ) 1<=i<=j and |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + cnorm(i) / |A(i,i)| ) 1<=i< j Since |x(j)| <= M(j), we use the Level 2 BLAS routine DTRSV if the reciprocal of the largest M(j), j=1,..,n, is larger than max(underflow, 1/overflow). The bound on x(j) is also used to determine when a step in the columnwise method can be performed without fear of overflow. If the computed bound is greater than a large constant, x is scaled to prevent overflow, but if the bound overflows, x is set to 0, x(j) to 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. Similarly, a row-wise scheme is used to solve A\'*x = b. The basic algorithm for A upper triangular is for j = 1, ..., n x(j) := ( b(j) - A[1:j-1,j]\' * x[1:j-1] ) / A(j,j) end We simultaneously compute two bounds G(j) = bound on ( b(i) - A[1:i-1,i]\' * x[1:i-1] ), 1<=i<=j M(j) = bound on x(i), 1<=i<=j The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. Then the bound on x(j) is M(j) <= M(j-1) * ( 1 + cnorm(j) ) / | A(j,j) | <= M(0) * product ( ( 1 + cnorm(i) ) / |A(i,i)| ) 1<=i<=j and we can safely call trsv if 1/M(n) and 1/G(n) are both greater than max(underflow, 1/overflow). Arguments ========= uplo: Specifies whether the matrix A is upper or lower triangular. = 0: Upper triangular = 1: Lower triangular trans: Specifies the operation applied to A. = 0: Solve A * x = s*b (No transpose) = 1: Solve A\'* x = s*b (Transpose) diag: Specifies whether or not the matrix A is unit triangular. = 0: Non-unit triangular = 1: Unit triangular normin: Specifies whether cnorm has been set or not. = 1: cnorm contains the column norms on entry = 0: cnorm is not set on entry. On exit, the norms will be computed and stored in cnorm. A: The triangular matrix A. If uplo = 0, the leading n by n upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading n by n lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. x: On entry, the right hand side b of the triangular system. On exit, x is overwritten by the solution vector x. scale: The scaling factor s for the triangular system A * x = s*b or A\'* x = s*b. If scale = 0, the matrix A is singular or badly scaled, and the vector x is an exact or approximate solution to A*x = 0. cnorm: If normin = 0, cnorm is an output argument and cnorm(j) returns the 1-norm of the offdiagonal part of the j-th column of A. If normin = 1, cnorm is an input argument and cnorm(j) contains the norm of the off-diagonal part of the j-th column of A. If trans = 0, cnorm(j) must be greater than or equal to the infinity-norm, and if trans = 1, cnorm(j) must be greater than or equal to the 1-norm. info: = 0: successful exit < 0: if info = -k, the k-th argument had an illegal value =for example # Assume $a is upper triangular $a = random (float, 100, 100); $b = random(100); $a = transpose($a); $info = null; $scale= null; $cnorm = zeroes(100); latrs($a, 0, 0, 0, 0,$b, $scale, $cnorm,$info); '); pp_def("gecon", HandleBad => 0, Pars => 'A(n,n); int norm(); anorm(); [o]rcond();int [o]info(); int [t]iwork(n); [t]work(workn);', RedoDimsCode => '$SIZE(workn) = 4 * $SIZE(n);', GenericTypes => [F,D], Code => generate_code ' char pnorm = \'I\'; extern int FORTRAN($TFD(s,d)gecon)(char *norm, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() *work, integer * iwork, integer *info); if($norm()) pnorm = \'O\'; FORTRAN($TFD(s,d)gecon)( &pnorm, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(anorm), $P(rcond), $P(work), $P(iwork), $P(info)); ', Doc => ' =for ref Estimates the reciprocal of the condition number of a general real matrix A, in either the 1-norm or the infinity-norm, using the LU factorization computed by C. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as rcond = 1 / ( norm(A) * norm(inv(A)) ). Arguments ========= norm: Specifies whether the 1-norm condition number or the infinity-norm condition number is required: = 0: Infinity-norm. = 1: 1-norm; A: The factors L and U from the factorization A = P*L*U as computed by getrf. anorm: If norm = 0, the infinity-norm of the original matrix A. If norm = 1, the 1-norm of the original matrix A. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(norm(A) * norm(inv(A))). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $anorm = $a->lange(1); $ipiv = zeroes(long, 100); $info = null; getrf($a, $ipiv, $info); ($rcond, $info) = gecon($a, 1, $anorm) unless $info != 0; '); pp_def("sycon", HandleBad => 0, Pars => '[phys]A(n,n); int uplo(); int ipiv(n); [phys]anorm(); [o,phys]rcond();int [o,phys]info(); int [t]iwork(n); [t]work(workn);', RedoDimsCode => '$SIZE(workn) = 2 * $SIZE(n);', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)sycon)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() * work, integer *iwork, integer *info); if($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)sycon)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(anorm), $P(rcond), $P(work), $P(iwork), $P(info)); ', Doc => ' =for ref Estimates the reciprocal of the condition number (in the 1-norm) of a real symmetric matrix A using the factorization A = U*D*U\' or A = L*D*L\' computed by C. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as rcond = 1 / (anorm * norm(inv(A))). Arguments ========= uplo: Specifies whether the details of the factorization are stored as an upper or lower triangular matrix. = 0: Upper triangular, form is A = U*D*U\'; = 1: Lower triangular, form is A = L*D*L\'. A: The block diagonal matrix D and the multipliers used to obtain the factor U or L as computed by sytrf. ipiv: Details of the interchanges and the block structure of D as determined by sytrf. anorm: The 1-norm of the original matrix A. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(anorm * aimvnm), where ainvnm is an estimate of the 1-norm of inv(A) computed in this routine. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. =for example # Assume $a is symmetric $a = random (float, 100, 100); $anorm = $a->lansy(1,1); $ipiv = zeroes(long, 100); $info = null; sytrf($a, 1,$ipiv, $info); ($rcond, $info) = sycon($a, 1, $anorm) unless $info != 0; '); pp_def("pocon", HandleBad => 0, Pars => 'A(n,n); int uplo(); anorm(); [o]rcond();int [o]info(); int [t]iwork(n); [t]work(workn);', RedoDimsCode => '$SIZE(workn) = 3 * $SIZE(n);', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; extern int FORTRAN($TFD(s,d)pocon)(char *uplo, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() *work, integer * iwork, integer *info); if($uplo()) puplo = \'L\'; FORTRAN($TFD(s,d)pocon)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(anorm), $P(rcond), $P(work), $P(iwork), $P(info)); ', Doc => ' =for ref Estimates the reciprocal of the condition number (in the 1-norm) of a real symmetric positive definite matrix using the Cholesky factorization A = U\'*U or A = L*L\' computed by C. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as rcond = 1 / (anorm * norm(inv(A))). Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: The triangular factor U or L from the Cholesky factorization A = U\'*U or A = L*L\', as computed by potrf. anorm: The 1-norm of the matrix A. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(anorm * ainvnm), where ainvnm is an estimate of the 1-norm of inv(A) computed in this routine. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example # Assume $a is symmetric positive definite $a = random (float, 100, 100); $anorm = $a->lansy(1,1); $info = null; potrf($a, 0, $info); ($rcond, $info) = pocon($a, 1, $anorm) unless $info != 0; '); pp_def("trcon", HandleBad => 0, Pars => 'A(n,n); int norm();int uplo();int diag(); [o]rcond();int [o]info(); int [t]iwork(n); [t]work(workn);', RedoDimsCode => '$SIZE(workn) = 3 * $SIZE(n);', GenericTypes => [F,D], Code => generate_code ' char puplo = \'U\'; char pdiag = \'N\'; char pnorm = \'I\'; extern int FORTRAN($TFD(s,d)trcon)(char *norm, char *uplo, char *diag,integer *n, $GENERIC() *a, integer * lda, $GENERIC() *rcond, $GENERIC() *work, integer *iwork, integer *info); if($uplo()) puplo = \'L\'; if($diag()) pdiag = \'U\'; if($norm()) pnorm = \'O\'; FORTRAN($TFD(s,d)trcon)( &pnorm, &puplo, &pdiag, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(rcond), $P(work), $P(iwork), $P(info)); ', Doc => ' =for ref Estimates the reciprocal of the condition number of a triangular matrix A, in either the 1-norm or the infinity-norm. The norm of A is computed and an estimate is obtained for norm(inv(A)), then the reciprocal of the condition number is computed as rcond = 1 / ( norm(A) * norm(inv(A)) ). Arguments ========= norm: Specifies whether the 1-norm condition number or the infinity-norm condition number is required: = 0: Infinity-norm. = 1: 1-norm; uplo: = 0: A is upper triangular; = 1: A is lower triangular. diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: The triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(norm(A) * norm(inv(A))). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example # Assume $a is upper triangular $a = random (float, 100, 100); $info = null; ($rcond, $info) = trcon($a, 1, 1, 0) unless $info != 0; '); pp_def("geqp3", HandleBad => 0, Pars => '[io,phys]A(m,n); int [io,phys]jpvt(n); [o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)geqp3)(integer *m, integer *n, $GENERIC() *a, integer * lda, integer *jpvt, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)geqp3)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(jpvt), $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)geqp3)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(jpvt), $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref geqp3 computes a QR factorization using Level 3 BLAS with column pivoting of a matrix A: A*P = Q*R The matrix Q is represented as a product of elementary reflectors Q = H(1) H(2) . . . H(k), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v\' where tau is a real/complex scalar, and v is a real/complex vector with v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), and tau in tau(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, the upper triangle of the array contains the min(M,N)-by-N upper trapezoidal matrix R; the elements below the diagonal, together with the array tau, represent the orthogonal matrix Q as a product of min(M,N) elementary reflectors. jpvt: On entry, if jpvt(J)!=0, the J-th column of A is permuted to the front of A*P (a leading column); if jpvt(J)=0, the J-th column of A is a free column. On exit, if jpvt(J)=K, then the J-th column of A*P was the the K-th column of A. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); $jpvt = zeroes(long, 50); geqp3($a, $jpvt, $tau, $info); '); pp_def("geqrf", HandleBad => 0, Pars => '[io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)geqrf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)geqrf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)geqrf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref geqrf computes a QR factorization of a matrix A: A = Q * R The matrix Q is represented as a product of elementary reflectors Q = H(1) H(2) . . . H(k), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v\' where tau is a real/complex scalar, and v is a real/complex vector with v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), and tau in tau(i). Arguments ========= A: On exit, the elements on and above the diagonal of the array contain the min(M,N)-by-N upper trapezoidal matrix R (R is upper triangular if m >= n); the elements below the diagonal, with the array TAU, represent the orthogonal matrix Q as a product of min(m,n) elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqrf($a, $tau, $info); '); pp_def("orgqr", HandleBad => 0, Pars => '[io,phys]A(m,n); [phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)orgqr)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)orgqr)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)orgqr)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Generates an M-by-N real matrix Q with orthonormal columns, which is defined as the first N columns of a product of K elementary reflectors of order M Q = H(1) H(2) . . . H(k) as returned by geqrf or geqp3. Arguments ========= A: On entry, the i-th column must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqrf or geqp3 in the first k columns of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqrf or geqp3. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqrf($a, $tau, $info); orgqr($a, $tau, $info) unless $info != 0; '); pp_def("ormqr", HandleBad => 0, Pars => '[phys]A(p,k); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)ormqr)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($trans()) ptrans = \'T\'; if($side()) pside = \'R\'; FORTRAN($TFD(s,d)ormqr)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ormqr)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q\' * C C * Q\' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(1) H(2) . . . H(k) as returned by geqrf or geqp3. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q\' from the Left; = 1: apply Q or Q\' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q\'. A: The i-th column must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqrf or geqp3 in the first k columns of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqrf or geqp3. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q\'*C or C*Q\' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); geqrf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormqr($a, $tau, $c, $info); '); pp_def("gelqf", HandleBad => 0, Pars => '[io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)gelqf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gelqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gelqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes an LQ factorization of a real M-by-N matrix A: A = L * Q. The matrix Q is represented as a product of elementary reflectors Q = H(k) . . . H(2) H(1), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v\' where tau is a real scalar, and v is a real vector with v(1:i-1) = 0 and v(i) = 1; v(i+1:n) is stored on exit in A(i,i+1:n), and tau in tau(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, the elements on and below the diagonal of the array contain the m-by-min(m,n) lower trapezoidal matrix L (L is lower triangular if m <= n); the elements above the diagonal, with the array tau, represent the orthogonal matrix Q as a product of elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gelqf($a, $tau, $info); '); pp_def("orglq", HandleBad => 0, Pars => '[io,phys]A(m,n); [phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)orglq)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)orglq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)orglq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Generates an M-by-N real matrix Q with orthonormal rows, which is defined as the first M rows of a product of K elementary reflectors of order N Q = H(k) . . . H(2) H(1) as returned by gelqf. Arguments ========= A: On entry, the i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gelqf in the first k rows of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gelqf. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gelqf($a, $tau, $info); orglq($a, $tau, $info) unless $info != 0; '); pp_def("ormlq", HandleBad => 0, Pars => '[phys]A(k,p); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)ormlq)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($trans()) ptrans = \'T\'; if($side()) pside = \'R\'; FORTRAN($TFD(s,d)ormlq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ormlq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q\' * C C * Q\' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(k) . . . H(2) H(1) as returned by gelqf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q\' from the Left; = 1: apply Q or Q\' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q\'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gelqf in the first k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gelqf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q\'*C or C*Q\' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); gelqf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormlq($a, $tau, $c, $info); '); pp_def("geqlf", HandleBad => 0, Pars => '[io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)geqlf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)geqlf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)geqlf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes a QL factorization of a real M-by-N matrix A: A = Q * L The matrix Q is represented as a product of elementary reflectors Q = H(k) . . . H(2) H(1), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v\' where tau is a real scalar, and v is a real vector with v(m-k+i+1:m) = 0 and v(m-k+i) = 1; v(1:m-k+i-1) is stored on exit in A(1:m-k+i-1,n-k+i), and tau in TAU(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, if m >= n, the lower triangle of the subarray A(m-n+1:m,1:n) contains the N-by-N lower triangular matrix L; if m <= n, the elements on and below the (n-m)-th superdiagonal contain the M-by-N lower trapezoidal matrix L; the remaining elements, with the array tau, represent the orthogonal matrix Q as a product of elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqlf($a, $tau, $info); '); pp_def("orgql", HandleBad => 0, Pars => '[io,phys]A(m,n); [phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)orgql)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)orgql)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)orgql)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Generates an M-by-N real matrix Q with orthonormal columns, which is defined as the last N columns of a product of K elementary reflectors of order M Q = H(k) . . . H(2) H(1) as returned by geqlf. Arguments ========= A: On entry, the (n-k+i)-th column must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqlf in the last k columns of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqlf. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqlf($a, $tau, $info); orgql($a, $tau, $info) unless $info != 0; '); pp_def("ormql", HandleBad => 0, Pars => '[phys]A(p,k); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)ormql)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($trans()) ptrans = \'T\'; if($side()) pside = \'R\'; FORTRAN($TFD(s,d)ormql)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ormql)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q\' * C C * Q\' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(k) . . . H(2) H(1) as returned by geqlf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q\' from the Left; = 1: apply Q or Q\' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q\'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqlf in the last k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqlf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q\'*C or C*Q\' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); geqlf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormql($a, $tau, $c, $info); '); pp_def("gerqf", HandleBad => 0, Pars => '[io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)gerqf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gerqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gerqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes an RQ factorization of a real M-by-N matrix A: A = R * Q. The matrix Q is represented as a product of elementary reflectors Q = H(1) H(2) . . . H(k), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v\' where tau is a real scalar, and v is a real vector with v(n-k+i+1:n) = 0 and v(n-k+i) = 1; v(1:n-k+i-1) is stored on exit in A(m-k+i,1:n-k+i-1), and tau in TAU(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, if m <= n, the upper triangle of the subarray A(1:m,n-m+1:n) contains the M-by-M upper triangular matrix R; if m >= n, the elements on and above the (m-n)-th subdiagonal contain the M-by-N upper trapezoidal matrix R; the remaining elements, with the array tau, represent the orthogonal matrix Q as a product of min(m,n) elementary reflectors (see Further Details). tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gerqf($a, $tau, $info); '); pp_def("orgrq", HandleBad => 0, Pars => '[io,phys]A(m,n); [phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)orgrq)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)orgrq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)orgrq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Generates an M-by-N real matrix Q with orthonormal rows, which is defined as the last M rows of a product of K elementary reflectors of order N Q = H(1) H(2) . . . H(k) as returned by gerqf. Arguments ========= A: On entry, the (m-k+i)-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gerqf in the last k rows of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gerqf. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gerqf($a, $tau, $info); orgrq($a, $tau, $info) unless $info != 0; '); pp_def("ormrq", HandleBad => 0, Pars => '[phys]A(k,p); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)ormrq)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($trans()) ptrans = \'T\'; if($side()) pside = \'R\'; FORTRAN($TFD(s,d)ormrq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ormrq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q\' * C C * Q\' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(1) H(2) . . . H(k) as returned by gerqf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q\' from the Left; = 1: apply Q or Q\' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q\'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gerqf in the last k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gerqf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q\'*C or C*Q\' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); gerqf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormrq($a, $tau, $c, $info); '); pp_def("tzrzf", HandleBad => 0, Pars => '[io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)tzrzf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)tzrzf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)tzrzf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Reduces the M-by-N ( M <= N ) real upper trapezoidal matrix A to upper triangular form by means of orthogonal transformations. The upper trapezoidal matrix A is factored as A = ( R 0 ) * Z, where Z is an N-by-N orthogonal matrix and R is an M-by-M upper triangular matrix. The factorization is obtained by Householder\'s method. The kth transformation matrix, Z( k ), which is used to introduce zeros into the ( m - k + 1 )th row of A, is given in the form Z( k ) = ( I 0 ), ( 0 T( k ) ) where T( k ) = I - tau*u( k )*u( k )\', u( k ) = ( 1 ), ( 0 ) ( z( k ) ) tau is a scalar and z( k ) is an ( n - m ) element vector. tau and z( k ) are chosen to annihilate the elements of the kth row of X. The scalar tau is returned in the kth element of C and the vector u( k ) in the kth row of A, such that the elements of z( k ) are in a( k, m + 1 ), ..., a( k, n ). The elements of R are returned in the upper triangular part of A. Z is given by Z = Z( 1 ) * Z( 2 ) * ... * Z( m ). Arguments ========= A: On entry, the leading M-by-N upper trapezoidal part of the array A must contain the matrix to be factorized. On exit, the leading M-by-M upper triangular part of A contains the upper triangular matrix R, and elements M+1 to N of the first M rows of A, with the array tau, represent the orthogonal matrix Z as a product of M elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $info = null; $tau = zeroes(float, 50); tzrzf($a, $tau, $info); '); pp_def("ormrz", HandleBad => 0, Pars => '[phys]A(k,p); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; integer kk = $SIZE(p) - $SIZE(k); extern int FORTRAN($TFD(s,d)ormrz)(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($trans()) ptrans = \'T\'; if($side()) pside = \'R\'; FORTRAN($TFD(s,d)ormrz)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, &kk, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)ormrz)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, &kk, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q\' * C C * Q\' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(1) H(2) . . . H(k) as returned by tzrzf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q\' from the Left; = 1: apply Q or Q\' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q\'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by tzrzf in the last k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by tzrzf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q\'*C or C*Q\' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); tzrzf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormrz($a, $tau, $c, $info); '); pp_def("gehrd", HandleBad => 0, Pars => '[io,phys]A(n,n); int [phys]ilo();int [phys]ihi();[o,phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)gehrd)(integer *n, integer *ilo, integer *ihi, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)gehrd)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)gehrd)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Reduces a real general matrix A to upper Hessenberg form H by an orthogonal similarity transformation: Q\' * A * Q = H . Further Details =============== The matrix Q is represented as a product of (ihi-ilo) elementary reflectors Q = H(ilo) H(ilo+1) . . . H(ihi-1). Each H(i) has the form H(i) = I - tau * v * v\' where tau is a real scalar, and v is a real vector with v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on exit in A(i+2:ihi,i), and tau in tau(i). The contents of A are illustrated by the following example, with n = 7, ilo = 2 and ihi = 6: on entry, on exit, ( a a a a a a a ) ( a a h h h h a ) ( a a a a a a ) ( a h h h h a ) ( a a a a a a ) ( h h h h h h ) ( a a a a a a ) ( v2 h h h h h ) ( a a a a a a ) ( v2 v3 h h h h ) ( a a a a a a ) ( v2 v3 v4 h h h ) ( a ) ( a ) where a denotes an element of the original matrix A, h denotes a modified element of the upper Hessenberg matrix H, and vi denotes an element of the vector defining H(i). Arguments ========= ilo: ihi: It is assumed that A is already upper triangular in rows and columns 1:ilo-1 and ihi+1:N. ilo and ihi are normally set by a previous call to gebal; otherwise they should be set to 1 and N respectively. See Further Details. 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. A: On entry, the N-by-N general matrix to be reduced. On exit, the upper triangle and the first subdiagonal of A are overwritten with the upper Hessenberg matrix H, and the elements below the first subdiagonal, with the array tau, represent the orthogonal matrix Q as a product of elementary reflectors. See Further Details. tau: The scalar factors of the elementary reflectors (see Further Details). Elements 1:ilo-1 and ihi:N-1 of tau are set to zero. (dimension (N-1)) info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (50, 50); $info = null; $tau = zeroes(50); gehrd($a, 1, 50, $tau, $info); '); pp_def("orghr", HandleBad => 0, Pars => '[io,phys]A(n,n); int [phys]ilo();int [phys]ihi();[phys]tau(k); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' integer lwork = -1; extern int FORTRAN($TFD(s,d)orghr)(integer *n, integer *ilo, integer *ihi, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; FORTRAN($TFD(s,d)orghr)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)orghr)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Generates a real orthogonal matrix Q which is defined as the product of ihi-ilo elementary reflectors of order N, as returned by C: Q = H(ilo) H(ilo+1) . . . H(ihi-1). Arguments ========= ilo: ihi: ilo and ihi must have the same values as in the previous call of gehrd. Q is equal to the unit matrix except in the submatrix Q(ilo+1:ihi,ilo+1:ihi). 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. A: On entry, the vectors which define the elementary reflectors, as returned by gehrd. On exit, the N-by-N orthogonal matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gehrd.(dimension (N-1)) info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (50, 50); $info = null; $tau = zeroes(50); gehrd($a, 1, 50, $tau, $info); orghr($a, 1, 50, $tau, $info); '); pp_def("hseqr", HandleBad => 0, Pars => '[io,phys]H(n,n); int job();int compz();int [phys]ilo();int [phys]ihi();[o,phys]wr(n); [o,phys]wi(n);[o,phys]Z(m,m); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char pcompz; char pjob = \'E\'; integer lwork = -1; extern int FORTRAN($TFD(s,d)hseqr)(char *job, char *compz, integer *n, integer *ilo, integer *ihi, $GENERIC() *h__, integer *ldh, $GENERIC() *wr, $GENERIC() *wi, $GENERIC() *z__, integer *ldz, $GENERIC() *work, integer *lwork, integer *info); $GENERIC() tmp_work; if($job()) pjob = \'S\'; switch ($compz()) { case 1: pcompz = \'I\'; break; case 2: pcompz = \'V\'; break; default: pcompz = \'N\'; } FORTRAN($TFD(s,d)hseqr)( &pjob, &pcompz, &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(H), &(integer){$SIZE(n)}, $P(wr), $P(wi), $P(Z), &(integer){$SIZE(m)}, &tmp_work, &lwork, $P(info)); lwork = (integer )tmp_work; { $GENERIC() *work = ($GENERIC() *)malloc(lwork * sizeof($GENERIC())); FORTRAN($TFD(s,d)hseqr)( &pjob, &pcompz, &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(H), &(integer){$SIZE(n)}, $P(wr), $P(wi), $P(Z), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc => ' =for ref Computes the eigenvalues of a real upper Hessenberg matrix H and, optionally, the matrices T and Z from the Schur decomposition H = Z T Z**T, where T is an upper quasi-triangular matrix (the Schur form), and Z is the orthogonal matrix of Schur vectors. Optionally Z may be postmultiplied into an input orthogonal matrix Q, so that this routine can give the Schur factorization of a matrix A which has been reduced to the Hessenberg form H by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. Arguments ========= job: = 0: compute eigenvalues only; = 1: compute eigenvalues and the Schur form T. compz: = 0: no Schur vectors are computed; = 1: Z is initialized to the unit matrix and the matrix Z of Schur vectors of H is returned; = 2: Z must contain an orthogonal matrix Q on entry, and the product Q*Z is returned. ilo: ihi: It is assumed that H is already upper triangular in rows and columns 1:ilo-1 and ihi+1:N. ilo and ihi are normally set by a previous call to gebal, and then passed to gehrd when the matrix output by gebal is reduced to Hessenberg form. Otherwise ilo and ihi should be set to 1 and N respectively. 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. H: On entry, the upper Hessenberg matrix H. On exit, if job = 1, H contains the upper quasi-triangular matrix T from the Schur decomposition (the Schur form); 2-by-2 diagonal blocks (corresponding to complex conjugate pairs of eigenvalues) are returned in standard form, with H(i,i) = H(i+1,i+1) and H(i+1,i)*H(i,i+1) < 0. If job = 0, the contents of H are unspecified on exit. wr: wi: The real and imaginary parts, respectively, of the computed eigenvalues. If two eigenvalues are computed as a complex conjugate pair, they are stored in consecutive elements of wr and wi, say the i-th and (i+1)th, with wi(i) > 0 and wi(i+1) < 0. If job = 1, the eigenvalues are stored in the same order as on the diagonal of the Schur form returned in H, with wr(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal block, wi(i) = sqrt(H(i+1,i)*H(i,i+1)) and wi(i+1) = -wi(i). Z: If compz = 0: Z is not referenced. If compz = 1: on entry, Z need not be set, and on exit, Z contains the orthogonal matrix Z of the Schur vectors of H. If compz = 2: on entry Z must contain an N-by-N matrix Q, which is assumed to be equal to the unit matrix except for the submatrix Z(ilo:ihi,ilo:ihi); on exit Z contains Q*Z. Normally Q is the orthogonal matrix generated by orghr after the call to gehrd which formed the Hessenberg matrix H. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, hseqr failed to compute all of the eigenvalues in a total of 30*(ihi-ilo+1) iterations; elements 1:ilo-1 and i+1:n of wr and wi contain those eigenvalues which have been successfully computed. =for example $a = random (50, 50); $info = null; $tau = zeroes(50); $z= zeroes(1,1); gehrd($a, 1, 50, $tau, $info); hseqr($a,0,0,1,50,($wr=null),($wi=null),$z,$info); '); pp_def("trevc", HandleBad => 0, Pars => '[io]T(n,n); int side();int howmny();int select(q);[o]VL(m,m); [o]VR(p,p);int [o]m(); int [o]info(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 1, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 2, $PDL(VR), $SIZE(p), $SIZE(n)) $SIZE(workn) = 3 * $SIZE(n); ', GenericTypes => [F,D], Code => generate_code ' char pside,phowmny; integer mm = PDLMAX($SIZE(m),$SIZE(p)); extern int FORTRAN($TFD(s,d)trevc)(char *side, char *howmny, logical *select, integer *n, $GENERIC() *t, integer *ldt, $GENERIC() *vl, integer * ldvl, $GENERIC() *vr, integer *ldvr, integer *mm, integer *m, $GENERIC() *work, integer *info); switch ($howmny()) { case 1: phowmny = \'B\'; break; case 2: phowmny = \'S\'; break; default: phowmny = \'A\'; } switch ($side()) { case 1: pside = \'R\'; break; case 2: pside = \'L\'; break; default:pside = \'B\'; } FORTRAN($TFD(s,d)trevc)( &pside, &phowmny, $P(select), &(integer){$SIZE(n)}, $P(T), &(integer){$SIZE(n)}, $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, &mm, $P(m), $P(work), $P(info)); ', Doc => ' =for ref Computes some or all of the right and/or left eigenvectors of a real upper quasi-triangular matrix T. The right eigenvector x and the left eigenvector y of T corresponding to an eigenvalue w are defined by: T*x = w*x, y\'*T = w*y\' where y\' denotes the conjugate transpose of the vector y. If all eigenvectors are requested, the routine may either return the matrices X and/or Y of right or left eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an input orthogonal matrix. If T was obtained from the real-Schur factorization of an original matrix A = Q*T*Q\', then Q*X and Q*Y are the matrices of right or left eigenvectors of A. T must be in Schur canonical form (as returned by hseqr), that is, block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each 2-by-2 diagonal block has its diagonal elements equal and its off-diagonal elements of opposite sign. Corresponding to each 2-by-2 diagonal block is a complex conjugate pair of eigenvalues and eigenvectors; only one eigenvector of the pair is computed, namely the one corresponding to the eigenvalue with positive imaginary part. Further Details =============== The algorithm used in this program is basically backward (forward) substitution, with scaling to make the the code robust against possible overflow. Each eigenvector is normalized so that the element of largest magnitude has magnitude 1; here the magnitude of a complex number (x,y) is taken to be |x| + |y|. Arguments ========= side: = 0 : compute both right and left eigenvectors; = 1 : compute right eigenvectors only; = 2 : compute left eigenvectors only. howmny: = 0: compute all right and/or left eigenvectors; = 1: compute all right and/or left eigenvectors, and backtransform them using the input matrices supplied in VR and/or VL; = 2: compute selected right and/or left eigenvectors, specified by the logical array select. select: If howmny = 2, select specifies the eigenvectors to be computed. If howmny = 0 or 1, select is not referenced. To select the real eigenvector corresponding to a real eigenvalue w(j), select(j) must be set to TRUE. To select the complex eigenvector corresponding to a complex conjugate pair w(j) and w(j+1), either select(j) or select(j+1) must be set to TRUE; then on exit select(j) is TRUE and select(j+1) is FALSE. T: The upper quasi-triangular matrix T in Schur canonical form. VL: On entry, if side = 2 or 0 and howmny = 1, VL must contain an N-by-N matrix Q (usually the orthogonal matrix Q of Schur vectors returned by hseqr). On exit, if side = 2 or 0, VL contains: if howmny = 0, the matrix Y of left eigenvectors of T; VL has the same quasi-lower triangular form as T\'. If T(i,i) is a real eigenvalue, then the i-th column VL(i) of VL is its corresponding eigenvector. If T(i:i+1,i:i+1) is a 2-by-2 block whose eigenvalues are complex-conjugate eigenvalues of T, then VL(i)+sqrt(-1)*VL(i+1) is the complex eigenvector corresponding to the eigenvalue with positive real part. if howmny = 1, the matrix Q*Y; if howmny = 2, the left eigenvectors of T specified by select, stored consecutively in the columns of VL, in the same order as their eigenvalues. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part, and the second the imaginary part. If side = 1, VL is not referenced. VR: On entry, if side = 1 or 0 and howmny = 1, VR must contain an N-by-N matrix Q (usually the orthogonal matrix Q of Schur vectors returned by hseqr). On exit, if side = 1 or 0, VR contains: if howmny = 0, the matrix X of right eigenvectors of T; VR has the same quasi-upper triangular form as T. If T(i,i) is a real eigenvalue, then the i-th column VR(i) of VR is its corresponding eigenvector. If T(i:i+1,i:i+1) is a 2-by-2 block whose eigenvalues are complex-conjugate eigenvalues of T, then VR(i)+sqrt(-1)*VR(i+1) is the complex eigenvector corresponding to the eigenvalue with positive real part. if howmny = 1, the matrix Q*X; if howmny = 2, the right eigenvectors of T specified by select, stored consecutively in the columns of VR, in the same order as their eigenvalues. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part and the second the imaginary part. If side = 2, VR is not referenced. m: The number of columns in the arrays VL and/or VR actually used to store the eigenvectors. If howmny = 0 or 1, m is set to N. Each selected real eigenvector occupies one column and each selected complex eigenvector occupies two columns. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (50, 50); $info = null; $tau = zeroes(50); $z= zeroes(1,1); gehrd($a, 1, 50, $tau, $info); hseqr($a,0,0,1,50,($wr=null),($wi=null),$z,$info); '); pp_def("tgevc", HandleBad => 0, Pars => '[io]A(n,n); int side();int howmny();[io]B(n,n);int select(q);[o]VL(m,m); [o]VR(p,p);int [o]m(); int [o]info(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 1, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 2, $PDL(VR), $SIZE(p), $SIZE(n)) $SIZE(workn) = 6 * $SIZE(n); ', GenericTypes => [F,D], Code => generate_code ' char pside,phowmny; integer mm = PDLMAX($SIZE(m),$SIZE(p)); extern int FORTRAN($TFD(s,d)tgevc)(char *side, char *howmny, logical *select, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b,integer *ldb, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, integer *mm, integer *m, $GENERIC() *work, integer *info); switch ($howmny()) { case 1: phowmny = \'B\'; break; case 2: phowmny = \'S\'; break; default: phowmny = \'A\'; } switch ($side()) { case 1: pside = \'R\'; break; case 2: pside = \'L\'; break; default:pside = \'B\'; } FORTRAN($TFD(s,d)tgevc)( &pside, &phowmny, $P(select), &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, &mm, $P(m), $P(work), $P(info)); ', Doc => ' =for ref Computes some or all of the right and/or left generalized eigenvectors of a pair of real upper triangular matrices (A,B). The right generalized eigenvector x and the left generalized eigenvector y of (A,B) corresponding to a generalized eigenvalue w are defined by: (A - wB) * x = 0 and y**H * (A - wB) = 0 where y**H denotes the conjugate transpose of y. If an eigenvalue w is determined by zero diagonal elements of both A and B, a unit vector is returned as the corresponding eigenvector. If all eigenvectors are requested, the routine may either return the matrices X and/or Y of right or left eigenvectors of (A,B), or the products Z*X and/or Q*Y, where Z and Q are input orthogonal matrices. If (A,B) was obtained from the generalized real-Schur factorization of an original pair of matrices (A0,B0) = (Q*A*Z**H,Q*B*Z**H), then Z*X and Q*Y are the matrices of right or left eigenvectors of A. A must be block upper triangular, with 1-by-1 and 2-by-2 diagonal blocks. Corresponding to each 2-by-2 diagonal block is a complex conjugate pair of eigenvalues and eigenvectors; only one eigenvector of the pair is computed, namely the one corresponding to the eigenvalue with positive imaginary part. Arguments ========= side: = 0 : compute both right and left eigenvectors; = 1 : compute right eigenvectors only; = 2 : compute left eigenvectors only. howmny: = 0 : compute all right and/or left eigenvectors; = 1 : compute all right and/or left eigenvectors, and backtransform them using the input matrices supplied in VR and/or VL; = 2 : compute selected right and/or left eigenvectors, specified by the logical array select. select: If howmny=2, select specifies the eigenvectors to be computed. If howmny=0 or 1, select is not referenced. To select the real eigenvector corresponding to the real eigenvalue w(j), select(j) must be set to TRUE To select the complex eigenvector corresponding to a complex conjugate pair w(j) and w(j+1), either select(j) or select(j+1) must be set to TRUE. A: The upper quasi-triangular matrix A. B: The upper triangular matrix B. If A has a 2-by-2 diagonal block, then the corresponding 2-by-2 block of B must be diagonal with positive elements. VL: On entry, if side = 2 or 0 and howmny = 1, VL must contain an N-by-N matrix Q (usually the orthogonal matrix Q of left Schur vectors returned by hgqez). On exit, if side = 2 or 0, VL contains: if howmny = 0, the matrix Y of left eigenvectors of (A,B); if howmny = 1, the matrix Q*Y; if howmny = 2, the left eigenvectors of (A,B) specified by select, stored consecutively in the columns of VL, in the same order as their eigenvalues. If side = 1, VL is not referenced. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part, and the second the imaginary part. VR: On entry, if side = 1 or 0 and howmny = 1, VR must contain an N-by-N matrix Q (usually the orthogonal matrix Z of right Schur vectors returned by hgeqz). On exit, if side = 1 or 0, VR contains: if howmny = 0, the matrix X of right eigenvectors of (A,B); if howmny = 1, the matrix Z*X; if howmny = 2, the right eigenvectors of (A,B) specified by select, stored consecutively in the columns of VR, in the same order as their eigenvalues. If side = 2, VR is not referenced. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part and the second the imaginary part. M: The number of columns in the arrays VL and/or VR actually used to store the eigenvectors. If howmny = 0 or 1, M is set to N. Each selected real eigenvector occupies one column and each selected complex eigenvector occupies two columns. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. > 0: the 2-by-2 block (info:info+1) does not have a complex eigenvalue. =for example $a = random (50, 50); $info = null; $tau = zeroes(50); $z= zeroes(1,1); gehrd($a, 1, 50, $tau, $info); hseqr($a,0,0,1,50,($wr=null),($wi=null),$z,$info); '); pp_def("gebal", HandleBad => 0, Pars => '[io,phys]A(n,n); int job(); int [o,phys]ilo();int [o,phys]ihi();[o,phys]scale(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char pjob; extern int FORTRAN($TFD(s,d)gebal)(char *job, integer *n, $GENERIC() *a, integer * lda, integer *ilo, integer *ihi, $GENERIC() *scale, integer *info); switch ($job()) { case 1: pjob = \'P\'; break; case 2: pjob = \'S\'; break; case 3: pjob = \'B\'; break; default: pjob = \'N\'; } FORTRAN($TFD(s,d)gebal)( &pjob, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(scale), $P(info)); ', Doc => ' =for ref Balances a general real matrix A. This involves, first, permuting A by a similarity transformation to isolate eigenvalues in the first 1 to ilo-1 and last ihi+1 to N elements on the diagonal; and second, applying a diagonal similarity transformation to rows and columns ilo to ihi to make the rows and columns as close in norm as possible. Both steps are optional. Balancing may reduce the 1-norm of the matrix, and improve the accuracy of the computed eigenvalues and/or eigenvectors. Further Details =============== The permutations consist of row and column interchanges which put the matrix in the form ( T1 X Y ) P A P = ( 0 B Z ) ( 0 0 T2 ) where T1 and T2 are upper triangular matrices whose eigenvalues lie along the diagonal. The column indices ilo and ihi mark the starting and ending columns of the submatrix B. Balancing consists of applying a diagonal similarity transformation inv(D) * B * D to make the 1-norms of each row of B and its corresponding column nearly equal. The output matrix is ( T1 X*D Y ) ( 0 inv(D)*B*D inv(D)*Z ). ( 0 0 T2 ) Information about the permutations P and the diagonal matrix D is returned in the vector C. Arguments ========= job: Specifies the operations to be performed on A: = 0: none: simply set ilo = 1, ihi = N, scale(I) = 1.0 for i = 1,...,N; = 1: permute only; = 2: scale only; = 3: both permute and scale. A: On entry, the input matrix A. On exit, A is overwritten by the balanced matrix. If job = 0, A is not referenced. See Further Details. ilo: ihi: ilo and ihi are set to integers such that on exit A(i,j) = 0 if i > j and j = 1,...,ilo-1 or I = ihi+1,...,N. If job = 0 or 2, ilo = 1 and ihi = N. scale: Details of the permutations and scaling factors applied to A. If P(j) is the index of the row and column interchanged with row and column j and D(j) is the scaling factor applied to row and column j, then scale(j) = P(j) for j = 1,...,ilo-1 = D(j) for j = ilo,...,ihi = P(j) for j = ihi+1,...,N. The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (50, 50); $scale = zeroes(50); $info = null; $ilo = null; $ihi = null; gebal($a, $ilo, $ihi, $scale, $info); '); pp_def("gebak", HandleBad => 0, Pars => '[io,phys]A(n,m); int job(); int side();int [phys]ilo();int [phys]ihi();[phys]scale(n); int [o,phys]info()', GenericTypes => [F,D], Code => generate_code ' char pjob; char pside =\'L\' ; extern int FORTRAN($TFD(s,d)gebak)(char *job, char *side, integer *n, integer *ilo, integer *ihi, $GENERIC() *scale, integer *m, $GENERIC() *v, integer * ldv, integer *info); switch ($job()) { case 1: pjob = \'P\'; break; case 2: pjob = \'S\'; break; case 3: pjob = \'B\'; break; default: pjob = \'N\'; } if ($side()) pside = \'R\'; FORTRAN($TFD(s,d)gebak)( &pjob, &pside, &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(scale), &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref gebak forms the right or left eigenvectors of a real general matrix by backward transformation on the computed eigenvectors of the balanced matrix output by gebal. Arguments ========= A: On entry, the matrix of right or left eigenvectors to be transformed, as returned by hsein or trevc. On exit, A is overwritten by the transformed eigenvectors. job: Specifies the type of backward transformation required: = 0 , do nothing, return immediately; = 1, do backward transformation for permutation only; = 2, do backward transformation for scaling only; = 3, do backward transformations for both permutation and scaling. job must be the same as the argument job supplied to gebal. side: = 0: V contains left eigenvectors. = 1: V contains right eigenvectors; ilo: ihi: The integers ilo and ihi determined by gebal. 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. Here N is the the number of rows of the matrix A. scale: Details of the permutation and scaling factors, as returned by gebal. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (50, 50); $scale = zeroes(50); $info = null; $ilo = null; $ihi = null; gebal($a, $ilo, $ihi, $scale, $info); # Compute eigenvectors ($ev) gebak($ev, $ilo, $ihi, $scale, $info); '); pp_def("lange", HandleBad => 0, Pars => '[phys]A(n,m); int norm(); [o]b(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(norm), tmp == 2, $PDL(work), $SIZE(workn), $SIZE(n)) ', GenericTypes => [F,D], Code => ' char pnorm; extern $GENERIC() FORTRAN($TFD(s,d)lange)(char *norm, integer *m, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *work); switch ($norm()) { case 1: pnorm = \'O\'; break; case 2: pnorm = \'I\'; break; case 3: pnorm = \'F\'; break; default: pnorm = \'M\'; } $b() = FORTRAN($TFD(s,d)lange)( &pnorm, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(work)); ', Doc => ' =for ref Computes the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a real matrix A. Description =========== returns the value lange = ( max(abs(A(i,j))), norm = 0 ( ( norm1(A), norm = 1 ( ( normI(A), norm = 2 ( ( normF(A), norm = 3 where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. Arguments ========= norm: Specifies the value to be returned in lange as described above. A: The n by m matrix A. =for example $a = random (float, 100, 100); $norm = $a->lange(1); '); pp_def("lansy", HandleBad => 0, Pars => 'A(n,n); int uplo(); int norm(); [o]b(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(norm), tmp == 1 || tmp == 2, $PDL(work), $SIZE(workn), $SIZE(n)) ', GenericTypes => [F,D], Code => ' char pnorm, puplo = \'U\'; extern $GENERIC() FORTRAN($TFD(s,d)lansy)(char *norm, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *work); switch ($norm()) { case 1: pnorm = \'O\'; break; case 2: pnorm = \'I\'; break; case 3: pnorm = \'F\'; break; default: pnorm = \'M\'; } if($uplo()) puplo = \'L\'; $b() = FORTRAN($TFD(s,d)lansy)( &pnorm, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(work)); ', Doc => ' =for ref Computes the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a real symmetric matrix A. Description =========== returns the value lansy = ( max(abs(A(i,j))), norm = 0 ( ( norm1(A), norm = 1 ( ( normI(A), norm = 2 ( ( normF(A), norm = 3 where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. norm: Specifies the value to be returned in lansy as described above. uplo: Specifies whether the upper or lower triangular part of the symmetric matrix A is to be referenced. = 0: Upper triangular part of A is referenced = 1: Lower triangular part of A is referenced A: The symmetric matrix A. If uplo = 0, the leading n by n upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading n by n lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. =for example # Assume $a is symmetric $a = random (float, 100, 100); $norm = $a->lansy(1, 1); '); pp_def("lantr", HandleBad => 0, Pars => 'A(m,n);int uplo();int norm();int diag();[o]b(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(norm), tmp == 2, $PDL(work), $SIZE(workn), $SIZE(m)) ', GenericTypes => [F,D], Code => ' char pnorm, puplo = \'U\'; char pdiag = \'N\'; extern $GENERIC() FORTRAN($TFD(s,d)lantr)(char *norm, char *uplo, char *diag, integer *m, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *work); switch ($norm()) { case 1: pnorm = \'O\'; break; case 2: pnorm = \'I\'; break; case 3: pnorm = \'F\'; break; default: pnorm = \'M\'; } if($uplo()) puplo = \'L\'; if($diag()) pdiag = \'U\'; $b() = FORTRAN($TFD(s,d)lantr)( &pnorm, &puplo, &pdiag, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(work)); ', Doc => ' =for ref Computes the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a trapezoidal or triangular matrix A. Description =========== returns the value lantr = ( max(abs(A(i,j))), norm = 0 ( ( norm1(A), norm = 1 ( ( normI(A), norm = 2 ( ( normF(A), norm = 3 where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. norm: Specifies the value to be returned in lantr as described above. uplo: Specifies whether the matrix A is upper or lower trapezoidal. = 0: Upper triangular part of A is referenced = 1: Lower triangular part of A is referenced Note that A is triangular instead of trapezoidal if M = N. diag: Specifies whether or not the matrix A has unit diagonal. = 0: Non-unit diagonal = 1: Unit diagonal A: The trapezoidal matrix A (A is triangular if m = n). If uplo = 0, the leading m by n upper trapezoidal part of the array A contains the upper trapezoidal matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading m by n lower trapezoidal part of the array A contains the lower trapezoidal matrix, and the strictly upper triangular part of A is not referenced. Note that when diag = 1, the diagonal elements of A are not referenced and are assumed to be one. =for example # Assume $a is upper triangular $a = random (float, 100, 100); $norm = $a->lantr(1, 1, 0); '); ################################################################################ # # BLAS ROUTINES # ################################################################################ pp_def("gemm", HandleBad => 0, Pars => '[phys]A(m,n); int transa(); int transb(); [phys]B(p,q);[phys]alpha(); [phys]beta(); [io,phys]C(r,s)', GenericTypes => [F,D], Code => ' char ptransa = \'N\'; char ptransb = \'N\'; extern int FORTRAN($TFD(s,d)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); integer kk = $transa() ? $SIZE(m) : $SIZE(n); if ($transa()) ptransa = \'T\'; if ($transb()) ptransb = \'T\'; FORTRAN($TFD(s,d)gemm)( &ptransa, &ptransb, &(integer){$SIZE(r)}, &(integer){$SIZE(s)}, &kk, $P(alpha), $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(beta), $P(C), &(integer){$SIZE(r)}); ', Doc => ' =for ref Performs one of the matrix-matrix operations C := alpha*op( A )*op( B ) + beta*C, where op( X ) is one of p( X ) = X or op( X ) = X\', alpha and beta are scalars, and A, B and C are matrices, with op( A ) an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. Parameters ========== transa: On entry, transa specifies the form of op( A ) to be used in the matrix multiplication as follows: transa = 0, op( A ) = A. transa = 1, op( A ) = A\'. transb: On entry, transb specifies the form of op( B ) to be used in the matrix multiplication as follows: transb = 0, op( B ) = B. transb = 1, op( B ) = B\'. alpha: On entry, alpha specifies the scalar alpha. A: Before entry with transa = 0, the leading m by k part of the array A must contain the matrix A, otherwise the leading k by m part of the array A must contain the matrix A. B: Before entry with transb = 0, the leading k by n part of the array B must contain the matrix B, otherwise the leading n by k part of the array B must contain the matrix B. beta: On entry, beta specifies the scalar beta. When beta is supplied as zero then C need not be set on input. C: Before entry, the leading m by n part of the array C must contain the matrix C, except when beta is zero, in which case C need not be set on entry. On exit, the array C is overwritten by the m by n matrix ( alpha*op( A )*op( B ) + beta*C ). =for example $a = random(5,4); $b = random(5,4); $alpha = pdl(0.5); $beta = pdl(0); $c = zeroes(5,5); gemm($a, 0, 1,$b, $alpha, $beta, $c); '); if ($config{CBLAS}){ pp_def("rmgemm", HandleBad => 0, Pars => '[phys]A(m,n); int transa(); int transb(); [phys]B(p,q);[phys]alpha(); [phys]beta(); [io,phys]C(r,s)', GenericTypes => [F,D], Code => ' int ptransa = CblasNoTrans; int ptransb = CblasNoTrans; extern void cblas_$TFD(s,d)gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const $GENERIC() alpha, const $GENERIC() *A, const int lda, const $GENERIC() *B, const int ldb, const $GENERIC() beta, $GENERIC() *C, const int ldc); integer kk = $transa() ? $SIZE(n) : $SIZE(m); if ($transa()) ptransa = CblasTrans; if ($transb()) ptransb = CblasTrans; $TFD(cblas_sgemm,cblas_dgemm)( CblasRowMajor, ptransa, ptransb, $SIZE(s), $SIZE(r), kk, $alpha(), $P(A), $SIZE(m), $P(B), $SIZE(p), $beta(), $P(C), $SIZE(r)); ', Doc => ' =for ref Row major version of gemm =for example $a = random(5,4); $b = random(5,4); $alpha = pdl(0.5); $beta = pdl(0); $c = zeroes(4,4); rmgemm($a, 0, 1,$b, $alpha, $beta, $c); '); } pp_def("mmult", HandleBad => 0, Pars => '[phys]A(m,n); [phys]B(p,m); [o,phys]C(p,n)', GenericTypes => [F,D], Code => ' char ptrans = \'N\'; extern int FORTRAN($TFD(s,d)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); $GENERIC() alpha = 1; $GENERIC() beta = 0; FORTRAN($TFD(s,d)gemm)( &ptrans, &ptrans, &(integer){$SIZE(p)}, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &alpha, $P(B), &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, &beta, $P(C), &(integer){$SIZE(p)}); ', Doc => ' =for ref Blas matrix multiplication based on gemm '); if ($config{STRASSEN}){ pp_def("smmult", HandleBad => 0, Pars => '[phys]A(m,n); [phys]B(p,m); [o,phys]C(p,n)', GenericTypes => [F,D], Code => ' char ptrans = \'N\'; extern int FORTRAN($TFD(s,d)gemmb)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); $GENERIC() alpha = 1; $GENERIC() beta = 0; FORTRAN($TFD(s,d)gemmb)( &ptrans, &ptrans, &(integer){$SIZE(p)}, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &alpha, $P(B), &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, &beta, $P(C), &(integer){$SIZE(p)}); ', Doc => ' =for ref Blas matrix multiplication based on Strassen Algorithm. '); } pp_def("crossprod", HandleBad => 0, Pars => '[phys]A(n,m); [phys]B(p,m); [o,phys]C(p,n)', GenericTypes => [F,D], Code => ' char btrans = \'N\'; char atrans = \'T\'; extern int FORTRAN($TFD(s,d)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); $GENERIC() alpha = 1; $GENERIC() beta = 0; FORTRAN($TFD(s,d)gemm)( &btrans, &atrans, &(integer){$SIZE(p)}, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &alpha, $P(B), &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(n)}, &beta, $P(C), &(integer){$SIZE(p)}); ', Doc => ' =for ref Blas matrix cross product based on gemm '); pp_def("syrk", HandleBad => 0, Pars => '[phys]A(m,n); int uplo(); int trans(); [phys]alpha(); [phys]beta(); [io,phys]C(p,p)', GenericTypes => [F,D], Code => ' char puplo = \'U\'; char ptrans = \'N\'; extern int FORTRAN($TFD(s,d)syrk)(char *uplo, char *trans, integer *n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); integer kk = $trans() ? $SIZE(m) : $SIZE(n); if ($uplo()) puplo = \'L\'; if ($trans()) ptrans = \'T\'; FORTRAN($TFD(s,d)syrk)( &puplo, &ptrans, &(integer){$SIZE(p)}, &kk, $P(alpha), $P(A), &(integer){$SIZE(m)}, $P(beta), $P(C), &(integer){$SIZE(p)}); ', Doc => ' =for ref Performs one of the symmetric rank k operations C := alpha*A*A\' + beta*C, or C := alpha*A\'*A + beta*C, where alpha and beta are scalars, C is an n by n symmetric matrix and A is an n by k matrix in the first case and a k by n matrix in the second case. Parameters ========== uplo: On entry, uplo specifies whether the upper or lower triangular part of the array C is to be referenced as follows: uplo = 0 Only the upper triangular part of C is to be referenced. uplo = 1 Only the lower triangular part of C is to be referenced. Unchanged on exit. trans: On entry, trans specifies the operation to be performed as follows: trans = 0 C := alpha*A*A\' + beta*C. trans = 1 C := alpha*A\'*A + beta*C. alpha: On entry, alpha specifies the scalar alpha. Unchanged on exit. A: Before entry with trans = 0, the leading n by k part of the array A must contain the matrix A, otherwise the leading k by n part of the array A must contain the matrix A. beta: On entry, beta specifies the scalar beta. C: Before entry with uplo = 0, the leading n by n upper triangular part of the array C must contain the upper triangular part of the symmetric matrix and the strictly lower triangular part of C is not referenced. On exit, the upper triangular part of the array C is overwritten by the upper triangular part of the updated matrix. Before entry with uplo = 1, the leading n by n lower triangular part of the array C must contain the lower triangular part of the symmetric matrix and the strictly upper triangular part of C is not referenced. On exit, the lower triangular part of the array C is overwritten by the lower triangular part of the updated matrix. =for example $a = random(5,4); $b = zeroes(5,5); $alpha = 1; $beta = 0; syrk ($a, 1,0,$alpha, $beta , $b); '); if ($config{CBLAS}){ pp_def("rmsyrk", HandleBad => 0, Pars => '[phys]A(m,n); int uplo(); int trans(); [phys]alpha(); [phys]beta(); [io,phys]C(p,p)', GenericTypes => [F,D], Code => ' int puplo = 121; int ptrans = 111; extern void cblas_$TFD(s,d)syrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE Trans, const int N, const int K, const $GENERIC() alpha, const $GENERIC() *A, const int lda, const $GENERIC() beta, $GENERIC() *C, const int ldc); integer kk = $trans() ? $SIZE(n) : $SIZE(m); if ($uplo()) puplo = 122; if ($trans()) ptrans = 112; $TFD(cblas_ssyrk,cblas_dsyrk)( 101, puplo, ptrans, $SIZE(p), kk, $alpha(), $P(A), $SIZE(m), $beta(), $P(C), $SIZE(p)); ', Doc => ' =for ref Row major version of syrk =for example $a = random(5,4); $b = zeroes(4,4); $alpha = 1; $beta = 0; rmsyrk ($a, 1,0,$alpha, $beta , $b); '); } pp_def("dot", HandleBad => 0, Pars => '[phys]a(n);[phys]b(n);[o,phys]c()', GenericTypes => [F,D], Code => ' extern $GENERIC() FORTRAN($TFD(s,d)dot)(integer *n, $GENERIC() *dx, integer *incx, $GENERIC() *dy, integer *incy); $c() = FORTRAN($TFD(s,d)dot)( &(integer){$SIZE(n)}, $P(a), &(integer){1}, $P(b), &(integer){1}); ', Doc => ' =for ref Dot product of two vectors using Blas. =for example $a = random(5); $b = random(5); $c = dot($a, $b) '); pp_def("axpy", HandleBad => 0, Pars => '[phys]a(n);[phys] alpha();[io,phys]b(m)', GenericTypes => [F,D], Code => ' extern int FORTRAN($TFD(s,d)axpy)(integer *n, $GENERIC() *da, $GENERIC() *dx, integer *incx, $GENERIC() *dy, integer *incy); FORTRAN($TFD(s,d)axpy)( &(integer){$SIZE(n)}, $P(alpha), $P(a), &(integer){1}, $P(b), &(integer){1}); ', Doc => ' =for ref Linear combination of vectors ax + b using Blas. Returns result in b. =for example $a = random(5); $b = random(5); axpy($a, 12, $b) '); pp_def("nrm2", HandleBad => 0, Pars => '[phys]a(n);[o]b()', GenericTypes => [F,D], Code => ' extern $GENERIC() FORTRAN($TFD(s,d)nrm2)(integer *n, $GENERIC() *dx, integer *incx); $b() = FORTRAN($TFD(s,d)nrm2)( &(integer){$SIZE(n)}, $P(a), &(integer){1}); ', Doc => ' =for ref Euclidean norm of a vector using Blas. =for example $a = random(5); $norm2 = norm2($a) '); pp_def("asum", HandleBad => 0, Pars => '[phys]a(n);[o]b()', GenericTypes => [F,D], Code => ' extern $GENERIC() FORTRAN($TFD(s,d)asum)(integer *n, $GENERIC() *dx, integer *incx); $b() = FORTRAN($TFD(s,d)asum)( &(integer){$SIZE(n)}, $P(a), &(integer){1}); ', Doc => ' =for ref Sum of absolute values of a vector using Blas. =for example $a = random(5); $absum = asum($a) '); pp_def("scal", HandleBad => 0, Pars => '[io,phys]a(n);scale()', GenericTypes => [F,D], Code => ' extern int FORTRAN($TFD(s,d)scal)(integer *n, $GENERIC() *sa, $GENERIC() *dx, integer *incx); FORTRAN($TFD(s,d)scal)( &(integer){$SIZE(n)}, $P(scale), $P(a), &(integer){1}); ', Doc => ' =for ref Scale a vector by a constant using Blas. =for example $a = random(5); $a->scal(0.5) '); pp_def("rot", HandleBad => 0, Pars => '[io,phys]a(n);[phys]c(); [phys]s();[io,phys]b(n)', GenericTypes => [F,D], Code => ' extern int FORTRAN($TFD(s,d)rot)(integer *n, $GENERIC() *dx, integer *incx, $GENERIC() *dy, integer *incy, $GENERIC() *c, $GENERIC() *s); FORTRAN($TFD(s,d)rot)( &(integer){$SIZE(n)}, $P(a), &(integer){1}, $P(b), &(integer){1}, $P(c), $P(s) ); ', Doc => ' =for ref Applies plane rotation using Blas. =for example $a = random(5); $b = random(5); rot($a, 0.5, 0.7, $b) '); pp_def("rotg", HandleBad => 0, Pars => '[io,phys]a();[io,phys]b();[o,phys]c(); [o,phys]s()', GenericTypes => [F,D], Code => ' extern int FORTRAN($TFD(s,d)rotg)($GENERIC() *dx, $GENERIC() *dy, $GENERIC() *c, $GENERIC() *s); FORTRAN($TFD(s,d)rotg)( $P(a), $P(b), $P(c), $P(s) ); ', Doc => ' =for ref Generates plane rotation using Blas. =for example $a = sequence(4); rotg($a(0), $a(1),$a(2),$a(3)) '); ################################################################################ # # LAPACK AUXILIARY ROUTINES # ################################################################################ pp_def("lasrt", HandleBad => 0, Pars => '[io,phys]d(n); int id();int [o,phys]info()', GenericTypes => [F,D], Code => ' char pwork = \'I\'; extern int FORTRAN($TFD(s,d)lasrt)(char *id, integer *n, $GENERIC() *d__, integer * info); if ($id()) pwork = \'D\'; FORTRAN($TFD(s,d)lasrt)( &pwork, &(integer){$SIZE(n)}, $P(d), $P(info)); ', Doc => ' =for ref Sort the numbers in d in increasing order (if id = 0) or in decreasing order (if id = 1 ). Use Quick Sort, reverting to Insertion sort on arrays of size <= 20. Dimension of stack limits N to about 2**32. Arguments ========= id: = 0: sort d in increasing order; = 1: sort d in decreasing order. d: On entry, the array to be sorted. On exit, d has been sorted into increasing order (d(1) <= ... <= d(N) ) or into decreasing order (d(1) >= ... >= d(N) ), depending on id. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random(5); lasrt ($a, 0, ($info = null)); '); pp_def("lacpy", HandleBad => 0, Pars => '[phys]A(m,n); int uplo(); [o,phys]B(p,n)', GenericTypes => [F,D], Code => ' char puplo; extern int FORTRAN($TFD(s,d)lacpy)(char *uplo, integer *m, integer *n, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb); switch ($uplo()) { case 0: puplo = \'U\'; break; case 1: puplo = \'L\'; break; default: puplo = \'A\'; } FORTRAN($TFD(s,d)lacpy)( &puplo, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}); ', Doc => ' =for ref Copies all or part of a two-dimensional matrix A to another matrix B. Arguments ========= uplo: Specifies the part of the matrix A to be copied to B. = 0: Upper triangular part = 1: Lower triangular part Otherwise: All of the matrix A A: The m by n matrix A. If uplo = 0, only the upper triangle or trapezoid is accessed; if uplo = 1, only the lower triangle or trapezoid is accessed. B: On exit, B = A in the locations specified by uplo. =for example $a = random(5,5); $b = zeroes($a); lacpy ($a, 0, $b); '); pp_def("laswp", HandleBad => 0, Pars => '[io,phys]A(m,n);int [phys]k1();int [phys] k2(); int [phys]ipiv(p);int [phys]inc()', GenericTypes => [F,D], Code => ' extern int FORTRAN($TFD(s,d)laswp)(integer *n, $GENERIC() *a, integer *lda, integer *k1, integer *k2, integer *ipiv, integer *incx); FORTRAN($TFD(s,d)laswp)( &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(k1), $P(k2), $P(ipiv), $P(inc)); ', Doc => ' =for ref Performs a series of row interchanges on the matrix A. One row interchange is initiated for each of rows k1 through k2 of A. Doesn\'t use PDL indices (start = 1). Arguments ========= A: On entry, the matrix of column dimension N to which the row interchanges will be applied. On exit, the permuted matrix. k1: The first element of ipiv for which a row interchange will be done. k2: The last element of ipiv for which a row interchange will be done. ipiv: The vector of pivot indices. Only the elements in positions k1 through k2 of ipiv are accessed. ipiv(k) = l implies rows k and l are to be interchanged. inc: The increment between successive values of ipiv. If ipiv is negative, the pivots are applied in reverse order. =for example $a = random(5,5); # reverse row (col for PDL) $b = pdl([5,4,3,2,1]); $a->laswp(1,2,$b,1); '); pp_def("lamch", HandleBad => 0, Pars => 'cmach(); [o]precision()', GenericTypes => [F,D], Inplace => 1, Code => ' char pcmach; int tmp; extern $GENERIC() FORTRAN($TFD(s,d)lamch)(char *cmach); tmp = (int ) $cmach(); switch (tmp) { case 1: pcmach = \'S\'; break; case 2: pcmach = \'B\'; break; case 3: pcmach = \'P\'; break; case 4: pcmach = \'N\'; break; case 5: pcmach = \'R\'; break; case 6: pcmach = \'M\'; break; case 7: pcmach = \'U\'; break; case 8: pcmach = \'L\'; break; case 9: pcmach = \'O\'; break; default: pcmach = \'E\'; } $precision() = FORTRAN($TFD(s,d)lamch)(&pcmach); ', Doc => ' =for ref Determines precision machine parameters. Works inplace. Arguments ========= cmach: Specifies the value to be returned by lamch: = 0 LAMCH := eps = 1 LAMCH := sfmin = 2 LAMCH := base = 3 LAMCH := eps*base = 4 LAMCH := t = 5 LAMCH := rnd = 6 LAMCH := emin = 7 LAMCH := rmin = 8 LAMCH := emax = 9 LAMCH := rmax where eps = relative machine precision sfmin = safe minimum, such that 1/sfmin does not overflow base = base of the machine prec = eps*base t = number of (base) digits in the mantissa rnd = 1.0 when rounding occurs in addition, 0.0 otherwise emin = minimum exponent before (gradual) underflow rmin = underflow threshold - base**(emin-1) emax = largest exponent before overflow rmax = overflow threshold - (base**emax)*(1-eps) =for example $a = lamch (0); print "EPS is $a for double\n"; '); pp_def("labad", HandleBad => 0, Pars => '[io,phys]small(); [io,phys]large()', GenericTypes => [F,D], Code => ' extern int FORTRAN($TFD(s,d)labad)($GENERIC() *small, $GENERIC() *large); FORTRAN($TFD(s,d)labad)($P(small),$P(large)); ', Doc => ' =for ref Takes as input the values computed by C for underflow and overflow, and returns the square root of each of these values if the log of large is sufficiently large. This subroutine is intended to identify machines with a large exponent range, such as the Crays, and redefine the underflow and overflow limits to be the square roots of the values computed by C. This subroutine is needed because lamch does not compensate for poor arithmetic in the upper half of the exponent range, as is found on a Cray. Arguments ========= small: On entry, the underflow threshold as computed by lamch. On exit, if LOG10(large) is sufficiently large, the square root of small, otherwise unchanged. large: On entry, the overflow threshold as computed by lamch. On exit, if LOG10(large) is sufficiently large, the square root of large, otherwise unchanged. =for example $underflow = lamch(7); $overflow = lamch(9); labad ($underflow, $overflow); '); ################################################################################ # # OTHER AUXILIARY ROUTINES # ################################################################################ pp_def( 'tricpy', Pars => 'A(m,n);[o] C(m,n)', OtherPars => 'int uplo', OtherParsDefaults => {uplo => 0}, ArgOrder => [qw(A uplo C)], GenericTypes => [ppdefs_all()], Code => ' if ($COMP(uplo)) { broadcastloop %{ loop(n,m) %{ $C() = $A(); if (m >= n) break; %} %} } else { broadcastloop %{ loop(m,n) %{ $C() = $A(); if (n >= m) break; %} %} } ', Doc => <<'EOT' =for usage tricpy(PDL(A), int(uplo), PDL(C)) =for example use PDL::LinearAlgebra; $c = $a->tricpy($uplo); # explicit uplo $c = $a->tricpy; # default upper or use PDL::LinearAlgebra::Real; tricpy($a, $uplo, $c); # modify c =for ref Copy triangular part to another matrix. If uplo == 0 copy upper triangular part. =cut EOT ); pp_def( 'cplx_eigen', Pars => 'eigreval(n);eigimval(n); eigvec(n,p);int fortran();[o]cplx_val(c=2,n);[o]cplx_vec(c=2,n,p)', Code => ' register PDL_Indx i; if ($fortran() && $SIZE(n) != $SIZE(p)) $CROAK("Fortran storage type needs square eigvec, but n=%"IND_FLAG", p=%"IND_FLAG, $SIZE(n), $SIZE(p)); if ($fortran()) { for(i = 0; i < $SIZE(n);i++) { $cplx_val(c=>0,n=>i) = $eigreval(n=>i); $cplx_val(c=>1,n=>i) = $eigimval(n=>i); if ($eigimval(n=>i) == 0) { loop(p) %{ $cplx_vec(c=>0,n=>p,p=>i) = $eigvec(n=>p,p=>i); $cplx_vec(c=>1,n=>p,p=>i) = 0; %} } else { PDL_Indx index = i+1; $cplx_val(c=>0,n=>index) = $eigreval(n=>index); $cplx_val(c=>1,n=>index) = $eigimval(n=>index); loop(p) %{ $cplx_vec(c=>0,n=>p,p=>i) = $cplx_vec(c=>0,n=>p,p=>index) = $eigvec(n=>p,p=>i); $cplx_vec(c=>1,n=>p,p=>i) = $eigvec(n=>p,p=>index); $cplx_vec(c=>1,n=>p,p=>index) = - $eigvec(n=>p,p=>index); %} i = index; } } } else { for(i = 0; i < $SIZE(n);i++) { $cplx_val(c=>0,n=>i) = $eigreval(n=>i); $cplx_val(c=>1,n=>i) = $eigimval(n=>i); if ($eigimval(n=>i) == 0) { loop(p) %{ $cplx_vec(c=>0,n=>i) = $eigvec(n=>i); $cplx_vec(c=>1,n=>i) = 0; %} } else { PDL_Indx index = i+1; $cplx_val(c=>0,n=>index) = $eigreval(n=>index); $cplx_val(c=>1,n=>index) = $eigimval(n=>index); loop(p) %{ $cplx_vec(c=>0,n=>i) = $cplx_vec(c=>0,n=>index) = $eigvec(n=>i); $cplx_vec(c=>1,n=>i) = $eigvec(n=>index); $cplx_vec(c=>1,n=>index) = - $eigvec(n=>index); %} i = index; } } } ', PMCode => <<'EOF', sub PDL::cplx_eigen { my ($eigre, $eigim, $eigvec, $fortran, @outs) = @_; my ($outval, $outvec) = @outs ? @outs : (null, null); PDL::_cplx_eigen_int($eigre, $eigim, $eigvec, $fortran, $outval, $outvec); if (defined $PDL::Complex::VERSION) { $_ = bless($_, 'PDL::Complex') for $outval, $outvec; } else { $_ = $_->slice('(0)')->czip($_->slice('(1)')) for $outval, $outvec; } ($outval, $outvec); } EOF Doc => < 1, TwoWay => 1, Pars => 'x(n); y(p);[o]out(q)', RedoDimsCode => '$SIZE(q) = $SIZE(n) + $SIZE(p);', Code => ' loop(n) %{ $out(q=>n) = $x(); %} register PDL_Indx i,j = 0; for (i=$SIZE(n); i < $SIZE(q); i++,j++) $out(q=>i) = $y(p=>j); ', BackCode => ' loop(n) %{ $x() = $out(q=>n); %} register PDL_Indx i,j = 0; for (i=$SIZE(n); i < $SIZE(q); i++,j++) $y(p=>j) = $out(q=>i); ', Doc => < 1, TwoWay => 1, Pars => 'x(n,m);y(n,p);[o]out(n,q);', RedoDimsCode => '$SIZE(q) = $SIZE(m) + $SIZE(p);', Code => ' register PDL_Indx i,j; loop(m,n) %{ $out(q=>m) = $x(); %} j=0; for (i = $SIZE(m); i < $SIZE(q) ;i++,j++) { loop(n)%{ $out(q=>i) = $y(p=>j); %} } ', BackCode => ' register PDL_Indx i,j; loop(m,n) %{ $x() = $out(q=>m); %} j=0; for (i = $SIZE(m); i < $SIZE(q) ;i++,j++) { loop(n)%{ $y(p=>j) = $out(q=>i); %} } ', Doc => < '$SIZE(p) = $SIZE(n) + 1;', Pars => 'A(n,n);[o]Y(n,n);[o]out(p);', GenericTypes => [F,D], Code => ' int i,k; $GENERIC() *p, b; //$GENERIC() *tmp; char ptrans = \'N\'; extern int FORTRAN($TFD(s,d)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); $GENERIC() alpha = 1; $GENERIC() beta = 0; p = ($GENERIC() * ) malloc ( $SIZE(n) * $SIZE(n) * sizeof($GENERIC())); loop(n0,n1) %{ $Y() = (n0 == n1) ? ($GENERIC()) 1.0 : ($GENERIC()) 0.0; %} $out(p=>0) = 1; i = 0; for (;;) { i++; FORTRAN($TFD(s,d)gemm)(&ptrans,&ptrans,&(integer){$SIZE(n)},&(integer){$SIZE(n)}, &(integer){$SIZE(n)},&alpha,$P(A),&(integer){$SIZE(n)}, $P(Y), &(integer){$SIZE(n)}, &beta, p, &(integer){$SIZE(n)}); if (i == $SIZE(n)) break; //tmp = $P(Y); //$P(Y) = p; //p = tmp; memmove($P(Y), p, $SIZE(n) * $SIZE(n) * sizeof($GENERIC())); // loop(n1,n0) %{ // $Y() = p[(n1*$SIZE(n))+n0]; // %} b = $out(p=>i) = - $TFD(ftrace,dtrace)($SIZE(n), $P(Y)) / i; loop(n0) %{ $Y(n1=>n0) += b; %} } k = $SIZE(n); $out(p=>k) = - $TFD(ftrace,dtrace)(k, p) / k; if ((k+1) & 1) { loop(n0,n1) %{ $Y() = -$Y(); %} } free(p); ', Doc => <'Bot'},<<'EOD'); =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut EOD pp_done(); # you will need this to finish pp processing PDL-LinearAlgebra-0.38/Real/selectfunc.c0000644000175000017500000000331114410675450017665 0ustar osboxesosboxes#include "EXTERN.h" #include "perl.h" #include "pdl.h" #include "pdlcore.h" #define PDL PDL_LinearAlgebra_Real extern Core *PDL; /* replace BLAS one so don't terminate on bad input */ int xerbla_(char *sub, int *info) { return 0; } #define SEL_FUNC2(letter, letter2, type, args, push) \ static SV* letter ## letter2 ## select_func = NULL; \ void letter ## letter2 ## select_func_set(SV* func) { \ if (letter ## letter2 ## select_func) SvREFCNT_dec(letter ## letter2 ## select_func); \ SvREFCNT_inc(letter ## letter2 ## select_func = func); \ } \ PDL_Long letter ## letter2 ## select_wrapper args \ { \ dSP ; \ ENTER ; \ SAVETMPS ; \ PUSHMARK(sp) ; \ push \ PUTBACK ; \ int count = perl_call_sv(letter ## select_func, G_SCALAR); \ SPAGAIN; \ if (count != 1) croak("Error calling perl function\n"); \ long retval = (long ) POPl ; /* Return value */ \ PUTBACK ; \ FREETMPS ; \ LEAVE ; \ return retval; \ } #define SEL_FUNC(letter, type) \ SEL_FUNC2(letter, , type, (type *wr, type *wi), \ XPUSHs(sv_2mortal(newSVnv((double ) *wr))); \ XPUSHs(sv_2mortal(newSVnv((double ) *wi))); \ ) SEL_FUNC(f, float) SEL_FUNC(d, double) #define GSEL_FUNC(letter, type) \ SEL_FUNC2(letter, g, type, (type *zr, type *zi, type *d), \ XPUSHs(sv_2mortal(newSVnv((double) *zr))); \ XPUSHs(sv_2mortal(newSVnv((double) *zi))); \ XPUSHs(sv_2mortal(newSVnv((double) *d))); \ ) GSEL_FUNC(f, float) GSEL_FUNC(d, double) #define TRACE(letter, type) \ type letter ## trace(int n, type *mat) { \ PDL_Indx i; \ type sum = mat[0]; \ for (i = 1; i < n; i++) \ sum += mat[i*(n+1)]; \ return sum; \ } TRACE(f, float) TRACE(d, double) PDL-LinearAlgebra-0.38/Real/Makefile.PL0000755000175000017500000000067214224144746017354 0ustar osboxesosboxesuse ExtUtils::MakeMaker; use PDL::Core::Dev; our (%ldloadlibs, $libs0, $inc); my $pkg = 'Real'; my $file = lc($pkg).".pd"; my @pack = ([$file, $pkg, "PDL::LinearAlgebra::$pkg",undef,1]); my %hash = pdlpp_stdargs(@pack); $hash{LIBS}[0] .= $libs0; $hash{OBJECT} .= ' selectfunc$(OBJ_EXT)'; $hash{INC} .= " $inc"; WriteMakefile( %hash, %ldloadlibs, VERSION_FROM => $file, NO_MYMETA => 1, ); sub MY::postamble { pdlpp_postamble(@pack); } PDL-LinearAlgebra-0.38/Artistic_20000644000175000017500000002072613301072104016423 0ustar osboxesosboxes Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PDL-LinearAlgebra-0.38/META.json0000644000175000017500000000277314565105646016145 0ustar osboxesosboxes{ "abstract" : "PDL bindings to some BLAS and LAPACK library routines", "author" : [ "Grégory Vanuxem " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "PDL-LinearAlgebra", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "Devel::CheckLib" : "0", "ExtUtils::F77" : "1.26", "PDL" : "2.078" } }, "runtime" : { "requires" : { "PDL" : "2.078" } }, "test" : { "requires" : { "Test::More" : "0.88" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/PDLPorters/pdl-linearalgebra/issues" }, "homepage" : "http://pdl.perl.org/", "repository" : { "type" : "git", "url" : "git://github.com/PDLPorters/pdl-linearalgebra.git", "web" : "https://github.com/PDLPorters/pdl-linearalgebra" } }, "version" : "0.38", "x_IRC" : "irc://irc.perl.org/#pdl", "x_serialization_backend" : "JSON::PP version 4.04" } PDL-LinearAlgebra-0.38/pp_defc.pl0000644000175000017500000000237614352734251016452 0ustar osboxesosboxessub pp_defc { my ($function, %hash) = @_; $hash{GenericTypes} ||= [qw(F D)]; my $doc = $hash{Doc} || "\n=for ref\n\nComplex version of L\n\n"; $hash{Doc} = undef; my $decl = delete $hash{_decl}; $decl =~ s/\$GENERIC\(\)\s*\*/void */g; # dodge float vs float complex ptr problem $hash{Code} = "$decl\n$hash{Code}"; pp_def("__Cc$function", %hash); my %hash2 = %hash; $hash2{Pars} = join ';', map s/\(2(?:,|(?=\)))/(/ ? "complex $_" : $_, split /;/, $hash2{Pars}; if ($hash2{RedoDimsCode}) { # decrement numbers being compared to, or dims offsets $hash2{RedoDimsCode} =~ s/(>\s*)(\d+)|(\[\s*)(\d+)(\s*\])/ $1 ? $1.($2 - 1) : $3.($4 - 1).$5 /ge; } pp_def("__Nc$function", %hash2); pp_add_exported("c$function"); my $sig = join ';', grep defined, @hash2{qw(Pars OtherPars)}; pp_addpm(<type->real, \@_); goto &PDL::__Cc$function if grep ref(\$_) eq 'PDL::Complex', \@_; goto &PDL::__Nc$function; } *c$function = \\&PDL::c$function; EOF } PDL-LinearAlgebra-0.38/t/0000755000175000017500000000000014565105646014756 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/t/common.pl0000644000175000017500000002075114352734251016602 0ustar osboxesosboxesruntest(sequence(2,2), 'issym', 0); my $a = pdl([[1.7,3.2],[9.2,7.3]]); runtest($a, 't', $a->xchg(0,1)); my $x = pdl([0.43,0.03],[0.75,0.72]); my $wide = pdl([0.43,0.03,0.7],[0.75,0.72,0.2]); my $rank2 = pdl([1,0,1],[-2,-3,1],[3,3,0]); my $schur_soln = pdl([0.36637354,-0.72],[0,0.78362646]); $schur_soln = [$schur_soln,[pdl([0.36637354,0.72],[0,0.78362646]),$schur_soln]]; runtest($x, 'mschur', $schur_soln); runtest($x, 'mschur', $schur_soln, [1,1,1,sub {1}]); runtest($x, 'mschur', $schur_soln, [1,1,1,undef]); runtest($x, 'mschur', $schur_soln, [0,1,2,sub {1},0,0]); runtest($x, 'mschur', $schur_soln, [2,2,2,sub {1},0]); runtest($x, 'mschur', $schur_soln, [2,2,2,sub {1},1]); runtest($x, 'mschur', $schur_soln, [2,2,2,sub {1},0,0]); runtest($x, 'mschur', $schur_soln, [2,2,2,undef,0,0]); runtest($x, 'mschur', $schur_soln, [0,2,2,undef,0,0]); runtest(sequence(2,2), 'diag', pdl(0,3)); runtest(sequence(2,2), 'diag', pdl(1), [1]); runtest(sequence(2,2), 'diag', pdl(2), [-1]); runtest(sequence(2,2), 'diag', pdl([[0,0],[0,1]],[[2,0],[0,3]]), [0,1]); runtest(sequence(3,3), 'tritosym', pdl [0,1,2],[1,4,5],[2,5,8]); runtest(pdl([1,2],[1,0]), 'mrcond', 1/3); runtest($x, 'mtriinv', pdl([2.3255814,-0.096899225],[0.75,1.3888889])); runtest($x, 'msyminv', pdl([2.3323615,-0.09718173],[-0.09718173,1.3929381])); runtest($x->crossprod($x), 'mchol', pdl([0.86452299,0.63954343],[0,0.33209065])); my $schurx_soln = [pdl([-1.605735,-6],[0,10.605735]),pdl([-1.605735,6],[0,10.605735])]; runtest($a, 'mschurx', $schurx_soln); runtest($a, 'mschurx', $schurx_soln, [1,1,1,sub {1}]); runtest($a, 'mschurx', $schurx_soln, [2,2,2,sub {1},0,0]); runtest($a, 'mschurx', $schurx_soln, [2,2,2,undef,0,0]); runtest($a, 'mschurx', $schurx_soln, [0,2,2,sub {1},1,0]); runtest($a, 'mschurx', $schurx_soln, [0,2,2,undef,1,1]); runtest($a, 'mschurx', $schurx_soln, [0,2,2,sub {1},1,1]); runtest($a, 'mschurx', $schurx_soln, [0,2,2,sub {1},3,1]); my @mgschur_exp = (pdl([-0.35099581,-0.68880032],[0,0.81795847]), pdl([1.026674, -0.366662], [0, -0.279640])); runtest($x, 'mgschur', \@mgschur_exp, [sequence(2,2)]); runtest($x, 'mgschur', \@mgschur_exp, [sequence(2,2),1,1,1,1,sub {1}]); runtest($x, 'mgschur', \@mgschur_exp, [sequence(2,2),2,2,2,2,sub {1},0]); runtest($x, 'mgschur', \@mgschur_exp, [sequence(2,2),2,2,2,2,undef,0]); runtest($x, 'mgschur', \@mgschur_exp, [sequence(2,2),0,0,2,2,sub {1},1,0]); runtest($x, 'mgschur', \@mgschur_exp, [sequence(2,2),0,0,2,2,undef]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2)]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),1,1,1,1,sub {1}]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),2,2,2,2,sub {1},0,0,0]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),2,2,2,2,undef,0,0,0]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),1,1,1,1,sub {1},2]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),1,1,1,1,sub {1},3]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),0,0,1,1,sub {1},1,1,0]); runtest($x, 'mgschurx', \@mgschur_exp, [sequence(2,2),0,0,2,2,undef]); runtest($x, 'mqr', pdl([-0.49738411,-0.86753043],[-0.86753043,0.49738411])); runtest($wide->t, 'mqr', pdl([-0.523069,-0.5023351],[-0.0364932,-0.793903],[-0.851508,0.34260173])); runtest($x, 'mrq', pdl([0.27614707,-0.3309725],[0,-1.0396634])); runtest($wide, 'mrq', pdl([0,0.68317233,-0.45724782],[0,0,-1.0587256]), [1]); runtest($wide->t, 'mrq', pdl([-0.603012,-0.619496],[-0.684055,-0.226644],[0,-0.728010])); runtest($x, 'mql', pdl([0.99913307,-0.041630545],[-0.041630545,-0.99913307])); runtest($wide, 'mql', pdl([0.274721,-0.961523],[-0.961523,-0.274721])); runtest($wide->t, 'mql', pdl([0.6885185,0.155284,-0.708398],[-0.606947,-0.411253,-0.680062],[-0.396935,0.898196,-0.188906]), [1]); runtest($x, 'mlq', pdl([-0.43104524,0],[-0.79829207,0.66605538])); runtest($wide, 'mlq', pdl([-0.822070,0,0],[-0.588878,-0.879841,0]), [1]); runtest($wide, 'mlq', pdl([-0.822070,0],[-0.588878,-0.879841]), [0]); runtest($wide->t, 'mlq', pdl([-0.864522,0],[-0.639543,0.332090],[-0.521674,-0.507794])); my $x_soln = pdl([-0.20898642,2.1943574],[2.995472,1.8808777]); runtest($x, 'msolve', $x_soln, [sequence(2,2)]); runtest($x, 'msolvex', $x_soln, [sequence(2,2), equilibrate=>1]); runtest($x, 'mtrisolve', pdl([0,2.3255814],[2.7777778,1.744186]), [1,sequence(2,2)]); my $x_symsoln = pdl([5.9311981,6.0498221],[-3.4005536,-2.1352313]); runtest($x, 'msymsolve', $x_symsoln, [1,sequence(2,2)]); runtest($x, 'msymsolvex', $x_symsoln, [1,sequence(2,2),1]); runtest($x, 'mlls', $x_soln, [sequence(2,2)]); my $wide_soln = pdl([1.712813,2.511051,3.30928],[2.706977,3.007326,3.30767],[-1.168170,-0.242816,0.682536]); my $tall_soln = pdl([4.055021,4.995087],[0.247090,1.330964]); runtest($wide, 'mlls', $wide_soln, [sequence(3,2)]); runtest($wide->t, 'mlls', $tall_soln, [sequence(2,3)]); runtest($x, 'mllsy', $x_soln, [sequence(2,2)]); runtest($wide, 'mllsy', $wide_soln, [sequence(3,2)]); runtest($wide->t, 'mllsy', pdl([4.055021,4.995087],[0.247090,1.330964]), [sequence(2,3)]); runtest($x, 'mllss', $x_soln, [sequence(2,2)]); runtest($wide, 'mllss', $wide_soln, [sequence(3,2)]); runtest($wide->t, 'mllss', $tall_soln, [sequence(2,3)]); runtest(pdl([1,2,3],[2,3,5],[3,4,7],[4,5,9]), 'mllss', pdl([3.333333,2.333333],[-2.666666,-1.666666],[0.666666,0.666666]), [sequence(2,4)]); runtest($x, 'mlse', pdl([-1,1]), [sequence(2,2),ones(2),ones(2)]); my ($posdef, $possoln) = (pdl([2,-1,0],[-1,2,-1],[0,-1,2]), pdl([3,4.5,6],[6,8,10],[6,7.5,9])); runtest($posdef, 'mpossolve', $possoln, [1,sequence(3,3)]); runtest($posdef, 'mpossolvex', $possoln, [1,sequence(3,3), equilibrate=>1]); my $x_symgeigen = pdl([-0.271308,0.216112,17.055195]); runtest(sequence(3,3), 'msymgeigen', $x_symgeigen, [$posdef]); runtest(sequence(3,3), 'msymgeigenx', $x_symgeigen, [$posdef]); runtest(sequence(3,3), 'msymgeigenx', $x_symgeigen, [$posdef,0,1]); runtest($x, 'mglm', pdl([-0.10449321,1.497736],[30.95841,-44.976237]), [sequence(2,2),sequence(2,2)]); my $x_eigen = pdl([0.366373539549749,0.783626460450251]); runtest($x, 'meigen', $x_eigen, [1,1]); runtest($x, 'meigenx', $x_eigen); runtest($x, 'meigenx', $x_eigen, [rcondition=>'value', vector=>'left']); runtest($x, 'meigenx', $x_eigen, [rcondition=>'vector', vector=>'right']); runtest($x, 'meigenx', $x_eigen, [rcondition=>'all', permute=>1, vector=>'all']); my $x_geigen = [pdl([-0.350995,0.817958]), pdl([1.026674,-0.279640])]; runtest($x, 'mgeigen', $x_geigen, [sequence(2,2),1,1]); runtest($x, 'mgeigenx', $x_geigen, [sequence(2,2)]); runtest($x, 'mgeigenx', $x_geigen, [sequence(2,2), rcondition=>'value', vector=>'left']); runtest($x, 'mgeigenx', $x_geigen, [sequence(2,2), rcondition=>'vector', vector=>'right']); runtest($x, 'mgeigenx', $x_geigen, [sequence(2,2), rcondition=>'all', error=>1, permute=>1, vector=>'all']); my $x_symeigen = pdl([0.42692907,0.72307093]); runtest($x, 'msymeigen', $x_symeigen); runtest($x, 'msymeigenx', $x_symeigen); runtest($x, 'msymeigenx', $x_symeigen, [0,1]); runtest($x, 'msymeigenx', pdl(-0.188888,1.338888), [1]); runtest($x, 'mdsvd', pdl([0.775249,0.631655],[0.631655,-0.775249])); runtest($x, 'mgsvd', pdl(0.16914549,0.64159379), [sequence(2,2), all=>1]); runtest(sequence(5,3)->t+1, 'mgsvd', pdl(0.980672,0.315531,0), [pdl([8,1,6],[3,5,7],[4,9,2]), all=>1]); runtest($a, 'mdet', -17.03); my $a_mexp = pdl([10927.432,10577.72],[30410.945,29438.441]); runtest($a_mexp, 'mlog', $a); my $a_mpow2 = pdl([32.33,28.8],[82.8,82.73]); runtest($a, 'mpow', $a_mpow2, [2]); runtest($a, 'mpow', identity(2), [0]); runtest($a_mpow2, 'msqrt', pdl([4.042101,2.358438],[6.780510,8.169368])); runtest($a, 'mexp', $a_mexp); my $a_mcos = pdl([-0.128354,-0.090435],[-0.260001,-0.286616]); runtest($a, 'mcos', $a_mcos); my $a_msin = pdl([-0.979243,0.019501],[0.056066,-0.945116]); runtest($a, 'msin', $a_msin); runtest($a_mcos, 'macos', pdl([[1.7018092, 0.093001244],[0.26737858,1.8645614]])); runtest($a_msin, 'masin', pdl([[-1.4397834,0.093001244],[0.26737858,-1.2770313]])); runtest($a, 'morth', pdl([-0.762586,-0.646886],[-0.646886,0.762586])); my $mnull_soln = pdl(-0.751304,0.319700,0.577350)->t; runtest($rank2, 'mnull', [$mnull_soln, [pdl(-0.751304,0.319700,-0.577350)->t,$mnull_soln]]); runtest($a, 'mpinv', pdl([0.463087,-0.511014],[0.0678448,-0.201667])); runtest($a, 'mlu', pdl([1,0],[0.184782,1])); runtest($wide->t, 'mlu', pdl([1,0],[0.042857,1],[0.614285,0.881526])); runtest(sequence(3,3), 'mhessen', pdl([0,-2.236068,0],[-6.708203,12,3],[0,1,0])); runtest($a, 'mrank', 2); runtest($rank2, 'mrank', 2); runtest($a, 'mnorm', 12.211267); runtest($a, 'msvd', pdl(12.211267,1.3946136), [0,0]); runtest($a, 'mcond', 8.756021); runtest(pdl([0,1]), 'mtoeplitz', pdl([0,1],[1,0])); PDL-LinearAlgebra-0.38/t/legacy.t0000644000175000017500000000312714565105125016402 0ustar osboxesosboxesuse strict; use warnings; use PDL::LiteF; use PDL::MatrixOps qw(identity); use PDL::Complex; use PDL::LinearAlgebra; use PDL::LinearAlgebra::Trans qw //; use PDL::LinearAlgebra::Complex; use Test::More; sub fapprox { my($a,$b) = @_; ($a-$b)->abs->max < 0.001; } # PDL::Complex only sub runtest { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($in, $method, $expected_cplx, $extra) = @_; $expected_cplx = $expected_cplx->[1] if ref $expected_cplx eq 'ARRAY'; my @cplx = ref($expected_cplx) eq 'ARRAY' ? @$expected_cplx : $expected_cplx; $_ = PDL::Complex::r2C($_) for $in; my ($got) = $in->$method(map ref() && ref() ne 'CODE' ? PDL::Complex::r2C($_) : $_, @{$extra||[]}); my $ok = grep fapprox($got, PDL::Complex::r2C($_)), @cplx; ok $ok, "PDL::Complex $method" or diag "got(".ref($got)."):$got\nexpected:@cplx"; } my $aa = cplx random(2,2,2); runtest($aa, 't', $aa->xchg(1,2)); $aa = sequence(2,2,2)->cplx + 1; runtest($aa, '_norm', my $aa_exp = PDL::Complex->from_native(pdl <<'EOF')); [ [0.223606+0.223606i 0.670820+0.670820i] [0.410997+0.410997i 0.575396+0.575396i] ] EOF runtest($aa, '_norm', $aa_exp->abs, [1]); runtest($aa, '_norm', $aa_exp->t, [0,1]); $aa = pdl('[[[0 1] [2 3] [4 5]] [[6 7] [8 9] [10 11]] [[12 13] [14 15] [16 17]]] ')->cplx; my $up = pdl('[[[0 1] [2 3] [4 5]] [[0 0] [8 9] [10 11]] [[0 0] [0 0] [16 17]]]')->cplx; my $lo = pdl('[[[0 1] [0 0] [0 0]] [[6 7] [8 9] [0 0]] [[12 13] [14 15] [16 17]]]')->cplx; runtest($aa, 'ctricpy', $up, [0]); runtest($aa, 'ctricpy', $up); runtest($aa, 'ctricpy', $lo, [1]); do './t/common.pl'; die if $@; done_testing; PDL-LinearAlgebra-0.38/t/1.t0000644000175000017500000000700214565105125015272 0ustar osboxesosboxesuse strict; use warnings; use PDL::LiteF; use PDL::MatrixOps qw(identity); use PDL::LinearAlgebra; use PDL::LinearAlgebra::Trans qw //; use PDL::LinearAlgebra::Real; use Test::More; sub fapprox { my($a,$b) = @_; (PDL->topdl($a)-$b)->abs->max < 0.001; } sub runtest { local $Test::Builder::Level = $Test::Builder::Level + 1; my ($in, $method, $expected, $extra) = @_; ($expected, my $expected_cplx) = ref($expected) eq 'ARRAY' ? @$expected : ($expected, $expected); if (defined $expected) { my ($got) = $in->$method(@{$extra||[]}); ok fapprox($got, $expected), $method or diag "got(".ref($got)."): $got"; } $_ = PDL->topdl($_)->r2C for $in; my ($got) = $in->$method(map ref() && ref() ne 'CODE' ? $_->r2C : $_, @{$extra||[]}); my @cplx = ref($expected_cplx) eq 'ARRAY' ? @$expected_cplx : $expected_cplx; my $ok = grep fapprox($got, PDL->topdl($_)->r2C), @cplx; ok $ok, "native complex $method" or diag "got(".ref($got)."): $got\nexpected:@cplx"; } my $aa = random(2,2,2); $aa = czip($aa->slice('(0)'), $aa->slice('(1)')); runtest($aa, 't', [undef,$aa->xchg(0,1)->conj], [1]); do './t/common.pl'; die if $@; ok all(approx pdl([1,1,-1],[-1,-1,2])->positivise, pdl([1,1,-1],[1,1,-2])), 'positivise'; # real only my $a = pdl([[1.7,3.2],[9.2,7.3]]); my $id = identity(2); ok(fapprox($a->minv x $a,$id)); ok(fapprox($a->mcrossprod->mposinv->tritosym x $a->mcrossprod,$id)); ok($a->mcrossprod->mposdet !=0); my $A = identity(4) + ones(4, 4); $A->slice('2,0') .= 0; # if don't break symmetry, don't show need transpose my $B = sequence(2, 4); getrf(my $lu=$A->copy, my $ipiv=null, my $info=null); # if don't transpose the $B input, get memory crashes getrs($lu, 1, my $x=$B->xchg(0,1)->copy, $ipiv, $info=null); $x = $x->inplace->xchg(0,1); my $got = $A x $x; ok fapprox($got, $B) or diag "got: $got"; $A=pdl cdouble, <<'EOF'; [ [ 1 0 0 0 0 0] [0.5 1 0 0.5 0 0] [0.5 0 1 0 0 0.5] [ 0 0 0 1 0 0] [ 0 0 0 0.5 1 0.5] [ 0 0 0 0 0 1] ] EOF PDL::LinearAlgebra::Complex::cgetrf($lu=$A->copy, $ipiv=null, $info=null); is $info, 0, 'cgetrf native worked'; is $ipiv->nelem, 6, 'cgetrf gave right-sized ipiv'; $B=pdl q[0.233178433563939+0.298197173371207i 1.09431208340166+1.30493506686269i 1.09216041861621+0.794394153882734i 0.55609433247125+0.515431151337765i 0.439100406078467+1.39139453403467i 0.252359761958406+0.570614019329113i]; PDL::LinearAlgebra::Complex::cgetrs($lu, 1, $x=$B->copy, $ipiv, $info=null); is $info, 0; $x = $x->dummy(0); # transpose; xchg rightly fails if 1-D $got = $A x $x; ok fapprox($got, $B->dummy(0)) or diag "got: $got"; my $i=pdl('i'); # Can't use i() as it gets confused by PDL::Complex's i() my $complex_matrix=(1+sequence(2,2))*$i; $got=$complex_matrix->mdet; ok(fapprox($got, 2), "Complex mdet") or diag "got $got"; $A = pdl '[[1+i 2+i][3+i 4+i]]'; $B = identity(2); ok fapprox($got = $A x $B, $A), 'complex first' or diag "got: $got"; ok fapprox($got = $B x $A, $A), 'complex second' or diag "got: $got"; $A = pdl '[[1 2 3] [4 5 6] [7 8 9]]'; my $up = pdl '[[1 2 3] [0 5 6] [0 0 9]]'; my $lo = pdl '[[1 0 0] [4 5 0] [7 8 9]]'; ok fapprox($got = $A->tricpy(0), $up), 'upper triangle #1' or diag "got: $got"; tricpy($A, 0, $got = null); ok fapprox($got, $up), 'upper triangle #2' or diag "got: $got"; ok fapprox($got = $A->tricpy, $up), 'upper triangle #3' or diag "got: $got"; ok fapprox($got = $A->tricpy(1), $lo), 'lower triangle #1' or diag "got: $got"; tricpy($A, 1, $got = null); ok fapprox($got, $lo), 'lower triangle #2' or diag "got: $got"; done_testing; PDL-LinearAlgebra-0.38/t/cgtsv.t0000644000175000017500000000321514224144274016262 0ustar osboxesosboxes# modified from t/cgtsl.t in Photonic by W. Luis Mochán use strict; use warnings; use PDL; use PDL::Complex (); use PDL::NiceSlice; use PDL::LinearAlgebra::Complex; use constant N=>10; use Test::More; my $PCi = PDL::Complex::i(); for my $D (3..N+2) { #first differences #solve (1+i)(b_{n+1}-b_n)=1-i with homogeneous BCs my $c=zeroes(2, $D)->complex; my $d=-ones($D)*(1+$PCi); my $e=ones($D)*(1+$PCi); $e->(,(-1)).=0; my $b=ones($D)*(1-$PCi); $b->(,(-1)).=(1-$D)*(1-$PCi); my $info=pdl(short,0); cgtsv($c, $d, $e, $b, $info); my $r=sequence($D)*(1-$PCi)/(1+$PCi); ok($b->complex->approx($r)->all, "1st diff. cgtsv in D=$D") or diag "info: ", $info, "\nGot: ", $b, "\nExpected: ", $r; $c=zeroes(cdouble, $D); $d=-ones($D)*czip(1, 1); $e=ones($D)*czip(1, 1); $e->((-1)).=0; $b=ones($D)*czip(1, -1); $b->((-1)).=(1-$D)*czip(1, -1); $info=pdl(short,0); cgtsv($c, $d, $e, $b, $info); $r=sequence($D)*czip(1, -1)/czip(1, 1); ok($b->approx($r)->all, "1st diff. native cgtsv in D=$D") or diag "info: ", $info, "\nGot: ", $b, "\nExpected: ", $r; } for my $D (3..N+2){ #second differences #solve b_{n+1}-2{b_n}+b_{n-1}=1 with kinda homogeneous BCs my $c=ones($D)*(1+$PCi); $c->(,(-1)).=0; my $d=-2*ones($D)*(1+$PCi); my $e=ones($D)*(1+$PCi); $e->(,(-1)).=0; my $b=ones($D)*(1-$PCi); my $info=pdl(short,0); cgtsv($c, $d, $e, $b, $info); my $x=sequence($D)+0*$PCi; my $r=(-$D/2-($D-1)/2*$x+1/2*$x*$x)*(1-$PCi)/(1+$PCi); ok($b->complex->approx($r)->all, "2nd diff. cgtsv in D=$D") or diag "info: ", $info, "\nGot: ", $b, "\nExpected: ", $r; } done_testing; PDL-LinearAlgebra-0.38/t/gtsv.t0000644000175000017500000000203714224144274016120 0ustar osboxesosboxes# modified from t/dgtsl.t in Photonic by W. Luis Mochán use strict; use warnings; use PDL; use PDL::NiceSlice; use PDL::LinearAlgebra::Real; use constant N=>10; use Test::More tests => 2*N; for my $D (3..N+2) { #first differences #solve b_{n+1}-b_n=1 with homogeneous BCs my $c=zeroes($D); $c->((-1)).=0; my $d=-ones($D); my $e=ones($D); $e->((-1)).=0; my $b=ones($D); $b->((-1)).=1-$D; my $info=pdl(short,0); gtsv($c, $d, $e, $b, $info); my $r=sequence($D); ok($b->approx($r)->all, "1st diff in D=$D") or diag "info: ", $info, "\nGot: ", $b, "\nExpected: ", $r; } for my $D (3..N+2) { #second differences #solve b_{n+1}-2{b_n}+b_{n-1}=1 with kinda homogeneous BCs my $c=ones($D); $c->((-1)).=0; my $d=-2*ones($D); my $e=ones($D); $e->((-1)).=0; my $b=ones($D); my $info=pdl(short,0); gtsv($c, $d, $e, $b, $info); my $x=sequence($D); my $r=-$D/2-($D-1)/2*$x+1/2*$x*$x; ok($b->approx($r)->all, "2nd diff in D=$D") or diag "info: ", $info, "\nGot: ", $b, "\nExpected: ", $r; } PDL-LinearAlgebra-0.38/Complex/0000755000175000017500000000000014565105646016122 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/Complex/complex.pd0000644000175000017500000034413414565105125020117 0ustar osboxesosboxesdo('../Config'); our $VERSION = '0.14'; pp_setversion($VERSION); $VERSION = eval $VERSION; use PDL::Exporter; if ($config{CBLAS}){ pp_addhdr('#include '); } if ($^O =~ /MSWin/) { pp_addhdr(' #include '); } pp_addhdr(' #include #define CONCAT_(A, B) A ## B #define CONCAT(A, B) CONCAT_(A, B) #define FORTRAN(name) CONCAT(name, F77_USCORE) typedef PDL_Long logical; typedef PDL_Long integer; typedef PDL_Long ftnlen; #ifdef __cplusplus typedef logical (*L_fp)(...); #else typedef logical (*L_fp)(); #endif #ifndef min #define min(a,b) ((a) <= (b) ? (a) : (b)) #endif #ifndef max #define max(a,b) ((a) >= (b) ? (a) : (b)) #endif extern integer FORTRAN(ilaenv)(integer *ispec, char *name__, char *opts, integer *n1, integer *n2, integer *n3, integer *n4, ftnlen name_len, ftnlen opts_len); static integer c_zero = 0; static integer c_nine = 9; #define PDL_MAYBE_SIZE(flagpdltype, flagpdl, flagcond, outpdl, outdim, indim) \ if (outpdl->state & PDL_MYDIMS_TRANS) { \ PDL_Indx i; \ char gobig = 0; \ flagpdltype *datap = PDL_REPRP(flagpdl); \ for (i=0; invals; i++) { \ flagpdltype tmp = datap[i]; /* [phys] means ignore incs and offs */ \ if (!(flagcond)) continue; \ gobig = 1; \ break; \ } \ outdim = gobig ? indim : 1; \ } '); sub generate_code($){ if ($config{WITHOUT_THREAD}){ return ' #if 0 threadloop%{ %} #endif'.$_[0]; } else{ return $_[0]; } } do '../pp_defc.pl'; die if $@; pp_addpm({At=>'Top'},<<'EOD'); use strict; use PDL::LinearAlgebra::Real; { package # hide from CPAN PDL::Complex; my $warningFlag; BEGIN{ $warningFlag = $^W; $^W = 0; } use overload ( 'x' => sub {UNIVERSAL::isa($_[1],'PDL::Complex') ? PDL::cmmult($_[0], $_[1]) : PDL::cmmult($_[0], PDL::Complex::r2C($_[1])); }, ); BEGIN{ $^W = $warningFlag ; } } =encoding Latin-1 =head1 NAME PDL::LinearAlgebra::Complex - PDL interface to the lapack linear algebra programming library (complex number) =head1 SYNOPSIS use PDL; use PDL::LinearAlgebra::Complex; $a = random(cdouble, 100, 100); $s = zeroes(cdouble, 100); $u = zeroes(cdouble, 100, 100); $v = zeroes(cdouble, 100, 100); $info = 0; $job = 0; cgesdd($a, $job, $info, $s , $u, $v); =head1 DESCRIPTION This module provides an interface to parts of the lapack library (complex numbers). These routines accept either float or double ndarrays. =cut EOD pp_defc("gtsv", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gtsv)(integer *n, integer *nrhs, $GENERIC() *dl, $GENERIC() *d, $GENERIC() *du, $GENERIC() *b, integer *ldb, integer *info); EOF HandleBad => 0, Pars => '[phys]DL(2,n); [phys]D(2,n); [phys]DU(2,n); [io,phys]B(2,n,nrhs); int [o,phys]info()', Code => generate_code ' FORTRAN($TFD(c,z)gtsv)( &(integer){$SIZE(n)}, &(integer){$SIZE(nrhs)}, $P(DL), $P(D), $P(DU), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Solves the equation A * X = B where A is an C by C tridiagonal matrix, by Gaussian elimination with partial pivoting, and B is an C by C matrix. Note that the equation C may be solved by interchanging the order of the arguments DU and DL. B This differs from the LINPACK function C in that C
starts from its first element, while the LINPACK equivalent starts from its second element. Arguments ========= DL: On entry, DL must contain the (n-1) sub-diagonal elements of A. On exit, DL is overwritten by the (n-2) elements of the second super-diagonal of the upper triangular matrix U from the LU factorization of A, in DL(1), ..., DL(n-2). D: On entry, D must contain the diagonal elements of A. On exit, D is overwritten by the n diagonal elements of U. DU: On entry, DU must contain the (n-1) super-diagonal elements of A. On exit, DU is overwritten by the (n-1) elements of the first super-diagonal of the U. B: On entry, the n by nrhs matrix of right hand side matrix B. On exit, if info = 0, the n by nrhs solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero, and the solution has not been computed. The factorization has not been completed unless i = n. =for example $dl = random(float, 9) + random(float, 9) * i; $d = random(float, 10) + random(float, 10) * i; $du = random(float, 9) + random(float, 9) * i; $b = random(10,5) + random(10,5) * i; cgtsv($dl, $d, $du, $b, ($info=null)); print "X is:\n$b" unless $info; '); pp_defc("gesvd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gesvd)(char *jobu, char *jobvt, integer *m, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *s, $GENERIC() *u, int *ldu, $GENERIC() *vt, integer *ldvt, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); int jobu(); int jobvt(); [o]s(minmn); [o]U(2,p,p); [o]VT(2,s,s); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(minmn) = PDLMIN($SIZE(m),$SIZE(n)); PDL_MAYBE_SIZE(PDL_Long, $PDL(jobu), tmp==1 || tmp==2, $PDL(U), $SIZE(p), $SIZE(m)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvt), tmp==1 || tmp==2, $PDL(VT), $SIZE(s), $SIZE(n)) $SIZE(rworkn) = 5 * $SIZE(minmn); ', Code => generate_code ' integer lwork = -1; char trau, travt; $GENERIC() *rwork; $GENERIC() tmp_work[2]; switch ($jobu()) { case 1: trau = \'A\'; break; case 2: trau = \'S\'; break; case 3: trau = \'O\'; break; default: trau = \'N\'; } switch ($jobvt()) { case 1: travt = \'A\'; break; case 2: travt = \'S\'; break; case 3: travt = \'O\'; break; default: travt = \'N\'; } FORTRAN($TFD(c,z)gesvd)( &trau, &travt, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gesvd)( &trau, &travt, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, work, &lwork, $P(rwork), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. The SVD is written A = U * SIGMA * ConjugateTranspose(V) '); pp_defc("gesdd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gesdd)(char *jobz, integer *m, integer *n, $GENERIC() * a, integer *lda, $GENERIC() *s, $GENERIC() *u, int *ldu, $GENERIC() *vt, integer *ldvt, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *iwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); int jobz(); [o]s(minmn); [o]U(2,p,p); [o]VT(2,s,s); int [o]info(); int [t]iwork(iworkn);', RedoDimsCode => ' $SIZE(minmn) = PDLMIN($SIZE(m),$SIZE(n)); PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp==1 || (tmp==2) || (tmp==3 && $SIZE(m)<$SIZE(n)), $PDL(U), $SIZE(p), $SIZE(minmn)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp==1 || (tmp==2) || (tmp==3 && $SIZE(m)>=$SIZE(n)), $PDL(VT), $SIZE(s), $SIZE(minmn)) $SIZE(iworkn) = 8 * $SIZE(minmn); ', Code => generate_code ' integer lwork; char tra; $GENERIC() *rwork; $GENERIC() tmp_work[2]; lwork = $SIZE(minmn); switch ($jobz()) { case 1: tra = \'A\'; rwork = ($GENERIC() *)malloc( (5 * lwork *lwork + 5 * lwork) * sizeof($GENERIC())); break; case 2: tra = \'S\'; rwork = ($GENERIC() *)malloc( (5 * lwork *lwork + 5 * lwork) * sizeof($GENERIC())); break; case 3: tra = \'O\'; rwork = ($GENERIC() *)malloc( (5 * lwork *lwork + 5 * lwork) * sizeof($GENERIC())); break; default: tra = \'N\'; rwork = ($GENERIC() *)malloc( 7 * lwork * sizeof($GENERIC())); break; } lwork = -1; FORTRAN($TFD(c,z)gesdd)( &tra, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, &tmp_work[0], &lwork, rwork, $P(iwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gesdd)( &tra, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(s), $P(U), &(integer){$SIZE(p)}, $P(VT), &(integer){$SIZE(s)}, work, &lwork, rwork, $P(iwork), $P(info)); free(work); } free(rwork); ', Doc=>' =for ref Complex version of L. The SVD is written A = U * SIGMA * ConjugateTranspose(V) '); pp_defc("ggsvd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ggsvd3)(char *jobu, char *jobv, char *jobq, integer *m, integer *n, integer *p, integer *k, integer *l, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *alpha, $GENERIC() *beta, $GENERIC() *u, integer *ldu, $GENERIC() *v, integer *ldv, $GENERIC() *q, integer *ldq, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *iwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); int jobu(); int jobv(); int jobq(); [io]B(2,p,n); int [o]k(); int [o]l();[o]alpha(n);[o]beta(n); [o]U(2,q,q); [o]V(2,r,r); [o]Q(2,s,s); int [o]iwork(n); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobu), tmp, $PDL(U), $SIZE(q), $SIZE(m)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobv), tmp, $PDL(V), $SIZE(r), $SIZE(p)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobq), tmp, $PDL(Q), $SIZE(s), $SIZE(n)) $SIZE(rworkn) = 2 * $SIZE(n); ', Code => generate_code ' char pjobu = \'N\'; char pjobv = \'N\'; char pjobq = \'N\'; $GENERIC() *work, twork[2]; integer lwork = -1; if ($jobu()) pjobu = \'U\'; if ($jobv()) pjobv = \'V\'; if ($jobq()) pjobq = \'Q\'; FORTRAN($TFD(c,z)ggsvd3)( &pjobu, &pjobv, &pjobq, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(k), $P(l), $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(alpha), $P(beta), $P(U), &(integer){$SIZE(q)}, $P(V), &(integer){$SIZE(r)}, $P(Q), &(integer){$SIZE(s)}, &twork[0], &lwork, $P(rwork), $P(iwork), $P(info)); lwork = (integer) twork[0]; work = ($GENERIC() *)malloc(2*(lwork * sizeof($GENERIC()))); FORTRAN($TFD(c,z)ggsvd3)( &pjobu, &pjobv, &pjobq, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(k), $P(l), $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(alpha), $P(beta), $P(U), &(integer){$SIZE(q)}, $P(V), &(integer){$SIZE(r)}, $P(Q), &(integer){$SIZE(s)}, work, &lwork, $P(rwork), $P(iwork), $P(info)); free(work); '); pp_defc("geev", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)geev)(char *jobvl, char *jobvr, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *w, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int jobvl(); int jobvr(); [o]w(2,n); [o]vl(2,m,m); [o]vr(2,p,p); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(vl), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(vr), $SIZE(p), $SIZE(n)) $SIZE(rworkn) = 2 * $SIZE(n); ', Code => generate_code ' char jvl = \'N\'; char jvr = \'N\'; $GENERIC() tmp_work[2]; integer lwork = -1; if ($jobvl()) jvl = \'V\'; if ($jobvr()) jvr = \'V\'; FORTRAN($TFD(c,z)geev)( &jvl, &jvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)geev)( &jvl, &jvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, work, &lwork, $P(rwork), $P(info)); free(work); } '); pp_defc("geevx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)geevx)(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *w, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, integer *ilo, integer *ihi, $GENERIC() *scale, $GENERIC() *abnrm, $GENERIC() *rconde, $GENERIC() *rcondv, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int jobvl(); int jobvr(); int balance(); int sense(); [o]w(2,n); [o]vl(2,m,m); [o]vr(2,p,p); int [o]ilo(); int [o]ihi(); [o]scale(n); [o]abnrm(); [o]rconde(q); [o]rcondv(r); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(vl), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(vr), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 1 || tmp == 3, $PDL(rconde), $SIZE(q), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 2 || tmp == 3, $PDL(rcondv), $SIZE(r), $SIZE(n)) $SIZE(rworkn) = 2 * $SIZE(n); ', Code => generate_code ' char jvl = \'N\'; char jvr = \'N\'; char balanc, sens; integer lwork = -1; $GENERIC() tmp_work[2]; if ($jobvl()) jvl = \'V\'; if ($jobvr()) jvr = \'V\'; switch ($balance()) { case 1: balanc = \'P\'; break; case 2: balanc = \'S\'; break; case 3: balanc = \'B\'; break; default: balanc = \'N\'; } switch ($sense()) { case 1: sens = \'E\'; break; case 2: sens = \'V\'; break; case 3: sens = \'B\'; break; default: sens = \'N\'; } FORTRAN($TFD(c,z)geevx)( &balanc, &jvl, &jvr, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(scale), $P(abnrm), $P(rconde), $P(rcondv), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)geevx)( &balanc, &jvl, &jvr, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), $P(vl), &(integer){$SIZE(m)}, $P(vr), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(scale), $P(abnrm), $P(rconde), $P(rcondv), work, &lwork, $P(rwork), $P(info)); free(work); } '); pp_defc("ggev", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ggev)(char *jobvl, char *jobvr, integer *n, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *alpha, $GENERIC() *beta, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int [phys]jobvl();int [phys]jobvr();B(2,n,n);[o]alpha(2,n);[o]beta(2,n);[o]VL(2,m,m);[o]VR(2,p,p);int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(VR), $SIZE(p), $SIZE(n)) $SIZE(rworkn) = 8 * $SIZE(n); ', Code => generate_code ' integer lwork = -1; char pjobvl = \'N\', pjobvr = \'N\'; $GENERIC() tmp_work[2]; if ($jobvl()) pjobvl = \'V\'; if ($jobvr()) pjobvr = \'V\'; FORTRAN($TFD(c,z)ggev)( &pjobvl, &pjobvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alpha), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ggev)( &pjobvl, &pjobvr, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alpha), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, work, &lwork, $P(rwork), $P(info)); free(work); } '); pp_defc("ggevx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ggevx)(char *balanc, char *jobvl, char *jobvr, char * sense, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *alpha, $GENERIC() * beta, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, integer *ilo, integer *ihi, $GENERIC() *lscale, $GENERIC() *rscale, $GENERIC() *abnrm, $GENERIC() *bbnrm, $GENERIC() *rconde, $GENERIC() * rcondv, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *iwork, logical * bwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n);int balanc();int jobvl();int jobvr();int sense();[io,phys]B(2,n,n);[o]alpha(2,n);[o]beta(2,n);[o]VL(2,m,m);[o]VR(2,p,p);int [o]ilo();int [o]ihi();[o]lscale(n);[o]rscale(n);[o]abnrm();[o]bbnrm();[o]rconde(r);[o]rcondv(s);int [o]info(); [t]rwork(rworkn); int [t]bwork(bworkn); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvl), tmp, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvr), tmp, $PDL(VR), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp != 2, $PDL(rconde), $SIZE(r), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp != 1, $PDL(rcondv), $SIZE(s), $SIZE(n)) $SIZE(rworkn) = 6 * $SIZE(n); PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp != 1, $PDL(iwork), $SIZE(iworkn), $SIZE(n) + 2) PDL_MAYBE_SIZE(PDL_Long, $PDL(sense), tmp == 1 || tmp == 2 || tmp == 3, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', Code => generate_code ' integer lwork = -1; char pjobvl = \'N\', pjobvr = \'N\'; char pbalanc, psens; $GENERIC() tmp_work[2]; if ($jobvl()) pjobvl = \'V\'; if ($jobvr()) pjobvr = \'V\'; switch ($balanc()) { case 1: pbalanc = \'P\'; break; case 2: pbalanc = \'S\'; break; case 3: pbalanc = \'B\'; break; default: pbalanc = \'N\'; } switch ($sense()) { case 1: psens = \'E\'; break; case 2: psens = \'V\'; break; case 3: psens = \'B\'; break; default: psens = \'N\'; } FORTRAN($TFD(c,z)ggevx)( &pbalanc, &pjobvl, &pjobvr, &psens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alpha), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(lscale), $P(rscale), $P(abnrm), $P(bbnrm), $P(rconde), $P(rcondv), &tmp_work[0], &lwork, $P(rwork), $P(iwork), $P(bwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ggevx)( &pbalanc, &pjobvl, &pjobvr, &psens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(alpha), $P(beta), $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, $P(ilo), $P(ihi), $P(lscale), $P(rscale), $P(abnrm), $P(bbnrm), $P(rconde), $P(rcondv), work, &lwork, $P(rwork), $P(iwork), $P(bwork), $P(info)); free(work); } '); pp_addhdr(' void fselect_func_set(SV* func); void dselect_func_set(SV* func); PDL_Long fselect_wrapper(float *p); PDL_Long dselect_wrapper(double *p); '); pp_defc("gees", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gees)(char *jobvs, char *sort, L_fp select, integer *n, $GENERIC() *a, integer *lda, integer *sdim, $GENERIC() *w, $GENERIC() *vs, integer *ldvs, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, logical *bwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int jobvs(); int sort(); [o]w(2,n); [o]vs(2,p,p); int [o]sdim(); int [o]info(); [t]rwork(n); int [t]bwork(bworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvs), tmp, $PDL(vs), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', OtherPars => "SV* select_func" , Code => generate_code ' char jvs = \'N\'; char psort = \'N\'; integer lwork = -1; $GENERIC() tmp_work[2]; $GENERIC() *work; $TFD(f,d)select_func_set($COMP(select_func)); if ($jobvs()) jvs = \'V\'; if ($sort()){ psort = \'S\'; } FORTRAN($TFD(c,z)gees)( &jvs, &psort, $TFD(f,d)select_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(w), $P(vs), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(rwork), $P(bwork), $P(info)); lwork = (integer )tmp_work[0]; work = ($GENERIC() *) malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gees)( &jvs, &psort, $TFD(f,d)select_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(w), $P(vs), &(integer){$SIZE(p)}, work, &lwork, $P(rwork), $P(bwork), $P(info)); free(work); ', Doc=>' =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An complex eigenvalue w is selected if select_func(PDL::Complex(w)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2. '); pp_defc("geesx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)geesx)(char *jobvs, char *sort, L_fp select, char * sense, integer *n, $GENERIC() *a, integer *lda, integer *sdim, $GENERIC() *w, $GENERIC() *vs, integer *ldvs, $GENERIC() *rconde, $GENERIC() *rcondv, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, logical *bwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int jobvs(); int sort(); int sense(); [o]w(2,n);[o]vs(2,p,p); int [o]sdim(); [o]rconde();[o]rcondv(); int [o]info(); [t]rwork(n); int [t]bwork(bworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvs), tmp, $PDL(vs), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) ', OtherPars => "SV* select_func" , Code => generate_code ' char jvs = \'N\'; char psort = \'N\'; integer lwork = -1; char sens; $GENERIC() *work; $TFD(f,d)select_func_set($COMP(select_func)); if ($jobvs()) jvs = \'V\'; if ($sort()) psort = \'S\'; switch ($sense()) { case 1: sens = \'E\'; break; case 2: sens = \'V\'; break; case 3: sens = \'B\'; break; default: sens = \'N\'; } $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)geesx)( &jvs, &psort, $TFD(f,d)select_wrapper, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(w), $P(vs), &(integer){$SIZE(p)}, $P(rconde), $P(rcondv), &tmp_work[0], &lwork, $P(rwork), $P(bwork), $P(info)); lwork = (integer )tmp_work[0]; work = ($GENERIC() * )malloc(2*lwork * sizeof ($GENERIC())); FORTRAN($TFD(c,z)geesx)( &jvs, &psort, $TFD(f,d)select_wrapper, &sens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(sdim), $P(w), $P(vs), &(integer){$SIZE(p)}, $P(rconde), $P(rcondv), work, &lwork, $P(rwork), $P(bwork), $P(info)); free(work); ', Doc => ' =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An complex eigenvalue w is selected if select_func(PDL::Complex(w)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2. '); pp_addhdr(' void fgselect_func_set(SV* func); void dgselect_func_set(SV* func); PDL_Long fgselect_wrapper(float *p); PDL_Long dgselect_wrapper(double *p); '); pp_defc("gges", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gges)(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer *sdim, $GENERIC() *alpha, $GENERIC() *beta, $GENERIC() *vsl, integer *ldvsl, $GENERIC() *vsr, integer *ldvsr, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, logical *bwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int jobvsl();int jobvsr();int sort();[io]B(2,n,n);[o]alpha(2,n);[o]beta(2,n);[o]VSL(2,m,m);[o]VSR(2,p,p);int [o]sdim();int [o]info(); [t]rwork(rworkn); int [t]bwork(bworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsl), tmp, $PDL(VSL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsr), tmp, $PDL(VSR), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) $SIZE(rworkn) = 8 * $SIZE(n); ', OtherPars => "SV* select_func" , Code => generate_code ' integer lwork = -1; char pjobvsl = \'N\', pjobvsr = \'N\', psort = \'N\'; $GENERIC() tmp_work[2]; $TFD(f,d)gselect_func_set($COMP(select_func)); if ($jobvsl()) pjobvsl = \'V\'; if ($jobvsr()) pjobvsr = \'V\'; if ($sort()) psort = \'S\'; FORTRAN($TFD(c,z)gges)( &pjobvsl, &pjobvsr, &psort, $TFD(f,d)gselect_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(sdim), $P(alpha), $P(beta), $P(VSL), &(integer){$SIZE(m)}, $P(VSR), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(rwork), $P(bwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gges)( &pjobvsl, &pjobvsr, &psort, $TFD(f,d)gselect_wrapper, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(sdim), $P(alpha), $P(beta), $P(VSL), &(integer){$SIZE(m)}, $P(VSR), &(integer){$SIZE(p)}, work, &lwork, $P(rwork), $P(bwork), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An eigenvalue w = w/beta is selected if select_func(PDL::Complex(w), PDL::Complex(beta)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w),PDL::Complex(beta)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2. '); pp_defc("ggesx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ggesx)(char *jobvsl, char *jobvsr, char *sort, L_fp delctg, char *sense, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer *sdim, $GENERIC() *alpha, $GENERIC() *beta, $GENERIC() *vsl, integer *ldvsl, $GENERIC() *vsr, integer *ldvsr, $GENERIC() *rconde, $GENERIC() *rcondv, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *iwork, integer *liwork, logical *bwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int jobvsl();int jobvsr();int sort();int sense();[io]B(2,n,n);[o]alpha(2,n);[o]beta(2,n);[o]VSL(2,m,m);[o]VSR(2,p,p);int [o]sdim();[o]rconde(q=2);[o]rcondv(q=2);int [o]info(); [t]rwork(rworkn); int [t]bwork(bworkn); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsl), tmp, $PDL(VSL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(jobvsr), tmp, $PDL(VSR), $SIZE(p), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(sort), tmp, $PDL(bwork), $SIZE(bworkn), $SIZE(n)) $SIZE(rworkn) = 8 * $SIZE(n); $SIZE(iworkn) = $SIZE(n) + 2; ', OtherPars => "SV* select_func" , Code => generate_code ' integer lwork, maxwrk; integer minwrk = 1; static integer c__0 = 0; static integer c__1 = 1; static integer c_n1 = -1; char pjobvsl = \'N\'; char pjobvsr = \'N\'; char psort = \'N\'; char psens = \'N\'; $TFD(f,d)gselect_func_set($COMP(select_func)); if ($jobvsr()) pjobvsr = \'V\'; if ($sort()) psort = \'S\'; switch ($sense()) { case 1: psens = \'E\'; break; case 2: psens = \'V\'; break; case 3: psens = \'B\'; break; default: psens = \'N\'; } // Code modified from Lapack // TODO other schur form above // The actual updated release (clapack 09/20/2000) do not allow // the workspace query. See release notes of Lapack // for this feature. minwrk = $SIZE(n) << 1; maxwrk = $SIZE(n) + $SIZE(n) * FORTRAN(ilaenv)(&c__1, "ZGEQRF", " ", &(integer){$SIZE(n)}, &c__1, &(integer){$SIZE(n)}, &c__0, (ftnlen)6, (ftnlen)1); if ($jobvsl()) { integer i__1 = maxwrk; integer i__2 = $SIZE(n) + $SIZE(n) * FORTRAN(ilaenv)(&c__1, "ZUNGQR" , " ", &(integer){$SIZE(n)}, &c__1, &(integer){$SIZE(n)}, &c_n1, (ftnlen)6, (ftnlen)1); maxwrk = max(i__1,i__2); pjobvsl = \'V\'; } lwork = max(maxwrk,minwrk); { $GENERIC() *work = ($GENERIC() *)malloc( 2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ggesx)( &pjobvsl, &pjobvsr, &psort, $TFD(f,d)gselect_wrapper, &psens, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(sdim), $P(alpha), $P(beta), $P(VSL), &(integer){$SIZE(m)}, $P(VSR), &(integer){$SIZE(p)}, $P(rconde), $P(rcondv), work, &lwork, $P(rwork), $P(iwork), &(integer){$SIZE(iworkn)}, $P(bwork), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An eigenvalue w = w/beta is selected if select_func(PDL::Complex(w), PDL::Complex(beta)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w),PDL::Complex(beta)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+3. '); pp_defc("heev", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)heev)(char *jobz, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *w, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int jobz(); int uplo(); [o]w(n); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(rworkn) = 3*($SIZE(n)-2); ', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)heev)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)heev)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), work, &lwork, $P(rwork), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("heevd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)heevd)(char *jobz, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *w, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int jobz(); int uplo(); [o,phys]w(n); int [o,phys]info()', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; integer lrwork, liwork; integer tmpi_work; integer *iwork; $GENERIC() tmp_work[2]; $GENERIC() tmpr_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)heevd)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), &tmp_work[0], &lwork, &tmpr_work, &lwork, &tmpi_work, &lwork, $P(info)); lwork = (integer )tmp_work[0]; lrwork = (integer )tmpr_work; liwork = (integer )tmpi_work; iwork = (integer *)malloc(liwork * sizeof(integer)); { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); $GENERIC() *rwork = ($GENERIC() *)malloc(lrwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)heevd)( &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(w), work, &lwork, rwork, &lrwork, iwork, &liwork, $P(info)); free(rwork); free(work); } free(iwork); ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("heevx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)heevx)(char *jobz, char *range, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *vl, $GENERIC() *vu, integer * il, integer *iu, $GENERIC() *abstol, integer *m, $GENERIC() *w, $GENERIC() *z__, integer *ldz, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *iwork, integer *ifail, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int jobz(); int range(); int uplo(); vl(); vu(); int il(); int iu(); abstol(); int [o]m(); [o]w(n); [o]z(2,p,p);int [o]ifail(n); int [o]info(); [t]rwork(rworkn); int [t]iwork(iworkn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp, $PDL(z), $SIZE(p), $SIZE(n)) $SIZE(rworkn) = 7 * $SIZE(n); $SIZE(iworkn) = 5 * $SIZE(n); ', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; char prange = \'A\'; integer lwork = -1; $GENERIC() tmp_work[2]; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; switch ($range()) { case 1: prange = \'V\'; break; case 2: prange = \'I\'; break; default: prange = \'A\'; } FORTRAN($TFD(c,z)heevx)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(rwork), $P(iwork), $P(ifail), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2* lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)heevx)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, work, &lwork, $P(rwork), $P(iwork), $P(ifail), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("heevr", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)heevr)(char *jobz, char *range, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *vl, $GENERIC() *vu, integer * il, integer *iu, $GENERIC() *abstol, integer *m, $GENERIC() *w, $GENERIC() *z__, integer *ldz, integer *isuppz, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int jobz(); int range(); int uplo(); [phys]vl(); [phys]vu(); int [phys]il(); int [phys]iu(); [phys]abstol(); int [o,phys]m(); [o,phys]w(n); [o,phys]z(2,p,q);int [o,phys]isuppz(r); int [o,phys]info()', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; char prange = \'A\'; integer lwork = -1; integer liwork,lrwork; integer tmpi_work; $GENERIC() tmp_work[2]; $GENERIC() tmpr_work; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; switch ($range()) { case 1: prange = \'V\'; break; case 2: prange = \'I\'; break; default: prange = \'A\'; } FORTRAN($TFD(c,z)heevr)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, $P(isuppz), &tmp_work[0], &lwork, &tmpr_work, &lwork, &tmpi_work, &lwork, $P(info)); lwork = (integer )tmp_work[0]; lrwork = (integer )tmpr_work; liwork = (integer )tmpi_work; { $GENERIC() *work = ($GENERIC() *)malloc(2* lwork * sizeof($GENERIC())); $GENERIC() *rwork = ($GENERIC() *)malloc(lrwork * sizeof($GENERIC())); integer *iwork = (integer *)malloc(liwork * sizeof(integer)); FORTRAN($TFD(c,z)heevr)( &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(z), &(integer){$SIZE(p)}, $P(isuppz), work, &lwork, rwork, &lrwork, iwork, &liwork, $P(info)); free(work); free(iwork); free(rwork); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("hegv", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hegv)(integer *itype, char *jobz, char *uplo, integer * n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *w, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n);int itype();int jobz(); int uplo();[io]B(2,n,n);[o]w(n); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(rworkn) = 3*($SIZE(n)-2); ', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hegv)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)hegv)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), work, &lwork, $P(rwork), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("hegvd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hegvd)(integer *itype, char *jobz, char *uplo, integer * n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *w, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *lrwork, integer *iwork, integer *liwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n);int [phys]itype();int jobz(); int uplo();[io,phys]B(2,n,n);[o,phys]w(n); int [o,phys]info()', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; integer lwork = -1; integer liwork = -1; integer lrwork = -1; integer *iwork; integer tmp_iwork; $GENERIC() tmp_work[2], tmp_rwork; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hegvd)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), &tmp_work[0], &lwork, &tmp_rwork, &lrwork, &tmp_iwork, &liwork, $P(info)); lwork = (integer )tmp_work[0]; lrwork = (integer )tmp_rwork; liwork = (integer )tmp_iwork; iwork = (integer *)malloc(liwork * sizeof(integer)); { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); $GENERIC() *rwork = ($GENERIC() *)malloc(lrwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)hegvd)( $P(itype), &jz, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(w), work, &lwork, rwork, &lrwork, iwork, &liwork, $P(info)); free(work); free(rwork); } free(iwork); ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("hegvx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hegvx)(integer *itype, char *jobz, char *range, char * uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *vl, $GENERIC() *vu, integer *il, integer *iu, $GENERIC() *abstol, integer *m, $GENERIC() *w, $GENERIC() *z__, integer *ldz, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *iwork, integer *ifail, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n);int itype();int jobz();int range(); int uplo();[io]B(2,n,n);vl();vu();int il(); int iu();abstol();int [o]m();[o]w(n); [o]Z(2,p,p);int [o]ifail(n);int [o]info(); [t]rwork(rworkn); int [t]iwork(iworkn); ', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(jobz), tmp, $PDL(Z), $SIZE(p), $SIZE(n)) $SIZE(rworkn) = 7 * $SIZE(n); $SIZE(iworkn) = 5 * $SIZE(n); ', Code => generate_code ' char jz = \'N\'; char puplo = \'U\'; char prange; integer lwork = -1; $GENERIC() tmp_work[2]; if ($jobz()) jz = \'V\'; if ($uplo()) puplo = \'L\'; switch ($range()) { case 1: prange = \'V\'; break; case 2: prange = \'I\'; break; default: prange = \'A\'; } FORTRAN($TFD(c,z)hegvx)( $P(itype), &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(Z), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(rwork), $P(iwork), $P(ifail), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc( 2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)hegvx)( $P(itype), &jz, &prange, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(vl), $P(vu), $P(il), $P(iu), $P(abstol), $P(m), $P(w), $P(Z), &(integer){$SIZE(p)}, work, &lwork, $P(rwork), $P(iwork), $P(ifail), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("gesv", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gesv)(integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer *ldb, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); [io,phys]B(2,n,m); int [o,phys]ipiv(n); int [o,phys]info()', Code => generate_code ' FORTRAN($TFD(c,z)gesv)( &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); '); pp_defc("gesvx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gesvx)(char *fact, char *trans, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, integer *ipiv, char *equed, $GENERIC() *r__, $GENERIC() *c__, $GENERIC() *b, integer *ldb, $GENERIC() *x, integer *ldx, $GENERIC() * rcond, $GENERIC() *ferr, $GENERIC() *berr, $GENERIC() *work, $GENERIC() * rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int trans(); int fact(); [io]B(2,n,m); [io]af(2,n,n); int [io]ipiv(n); int [io]equed(); [o]r(p); [o]c(q); [o]X(2,n,m); [o]rcond(); [o]ferr(m); [o]berr(m); [o]rpvgrw(); int [o]info(); [t]rwork(rworkn); [t]work(rworkn);', RedoDimsCode => ' $SIZE(p) = $SIZE(n); /* Ubuntu LAPACK 3 writes to r anyway */ $SIZE(q) = $SIZE(n); /* Ubuntu LAPACK 3 writes to c anyway */ $SIZE(rworkn) = 4 * $SIZE(n); ', Code => generate_code ' char ptrans, pfact, pequed; switch ($trans()) { case 1: ptrans = \'T\'; break; case 2: ptrans = \'C\'; break; default: ptrans = \'N\'; } switch ($fact()) { case 1: pfact = \'N\'; break; case 2: pfact = \'E\'; break; default: pfact = \'F\'; } switch ($equed()) { case 1: pequed = \'R\'; break; case 2: pequed = \'C\'; break; case 3: pequed = \'B\'; break; default: pequed = \'N\'; } FORTRAN($TFD(c,z)gesvx)( &pfact, &ptrans, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), &pequed, $P(r), $P(c), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), $P(work), $P(rwork), $P(info)); switch (pequed) { case \'R\': $equed() = 1; break; case \'C\': $equed() = 2; break; case \'B\': $equed() = 3; break; default: $equed()= 0; } $rpvgrw()=$rwork(rworkn=>0); ', Doc => ' =for ref Complex version of L. trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A\' * X = B (Transpose) = 2: A**H * X = B (Conjugate transpose) '); pp_defc("sysv", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sysv)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer *ldb, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); [io,phys]B(2,n,m); int [o]ipiv(n); int [o]info()', Code => generate_code ' char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sysv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)sysv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, work, &lwork, $P(info)); free(work); } '); pp_defc("sysvx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sysvx)(char *fact, char *uplo, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, integer *ipiv, $GENERIC() *b, integer *ldb, $GENERIC() *x, integer * ldx, $GENERIC() *rcond, $GENERIC() *ferr, $GENERIC() *berr, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int uplo(); int fact(); [phys]B(2,n,m); [io,phys]af(2,n,n); int [io,phys]ipiv(n); [o]X(2,n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); [t]rwork(n);', Code => generate_code ' char pfact = \'N\'; char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($fact()) pfact = \'F\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sysvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)sysvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), work, &lwork, $P(rwork), $P(info)); free(work); } '); pp_defc("hesv", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hesv)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer *ldb, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); [io,phys]B(2,n,m); int [o,phys]ipiv(n); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hesv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)hesv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, work, &lwork, $P(info)); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("hesvx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hesvx)(char *fact, char *uplo, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, integer *ipiv, $GENERIC() *b, integer *ldb, $GENERIC() *x, integer * ldx, $GENERIC() *rcond, $GENERIC() *ferr, $GENERIC() *berr, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int uplo(); int fact(); B(2,n,m); [io]af(2,n,n); int [io]ipiv(n); [o]X(2,n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); [t]rwork(n);', Code => generate_code ' char pfact = \'N\'; char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($fact()) pfact = \'F\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hesvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)hesvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), work, &lwork, $P(rwork), $P(info)); free(work); } ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("posv", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)posv)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); [io,phys]B(2,n,m); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)posv)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc=>' =for ref Complex version of L for Hermitian positive definite matrix '); pp_defc("posvx", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)posvx)(char *fact, char *uplo, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *af, integer *ldaf, char *equed, $GENERIC() *s, $GENERIC() *b, integer *ldb, $GENERIC() * x, integer *ldx, $GENERIC() *rcond, $GENERIC() *ferr, $GENERIC() * berr, $GENERIC() *work, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int uplo(); int fact(); [io]B(2,n,m); [io]af(2,n,n); int [io]equed(); [o]s(p); [o]X(2,n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); [t]rwork(rworkn); [t]work(workn);', RedoDimsCode => ' $SIZE(p) = $SIZE(n); /* Ubuntu LAPACK 3 writes to s anyway */ $SIZE(rworkn) = 2 * $SIZE(n); $SIZE(workn) = 4 * $SIZE(n); ', Code => generate_code ' char pfact; char pequed = \'N\'; char puplo = \'U\'; switch ($fact()) { case 1: pfact = \'N\'; break; case 2: pfact = \'E\'; break; default: pfact = \'F\'; } if ($equed()) pequed = \'Y\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)posvx)( &pfact, &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(af), &(integer){$SIZE(n)}, &pequed, $P(s), $P(B), &(integer){$SIZE(n)}, $P(X), &(integer){$SIZE(n)}, $P(rcond), $P(ferr), $P(berr), $P(work), $P(rwork), $P(info)); switch (pequed) { case \'Y\': $equed() = 1; break; default: $equed()= 0; } ', Doc => ' =for ref Complex version of L for Hermitian positive definite matrix '); pp_defc("gels", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gels)(char *trans, integer *m, integer *n, integer * nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); int trans(); [io,phys]B(2,p,q);int [o,phys]info()', Code => generate_code ' char ptrans = \'N\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($trans()) ptrans = \'C\'; FORTRAN($TFD(c,z)gels)( &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gels)( &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Solves overdetermined or underdetermined complex linear systems involving an M-by-N matrix A, or its conjugate-transpose. Complex version of L. trans: = 0: the linear system involves A; = 1: the linear system involves A**H. '); pp_defc("gelsy", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gelsy)(integer *m, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer * jpvt, $GENERIC() *rcond, integer *rank, $GENERIC() *work, integer * lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); [io]B(2,p,q); rcond(); int [io]jpvt(n); int [o]rank();int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(rworkn) = 2 * $SIZE(n); ', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gelsy)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(jpvt), $P(rcond), $P(rank), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gelsy)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(jpvt), $P(rcond), $P(rank), work, &lwork, $P(rwork), $P(info)); free(work); } '); pp_defc("gelss", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gelss)(integer *m, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *s, $GENERIC() *rcond, integer *rank, $GENERIC() *work, integer * lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); [io]B(2,p,q); rcond(); [o]s(r); int [o]rank();int [o]info(); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(rworkn) = 5 * PDLMIN($SIZE(m),$SIZE(n)); ', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gelss)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gelss)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), work, &lwork, $P(rwork), $P(info)); free(work); } '); pp_defc("gelsd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gelsd)(integer *m, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *s, $GENERIC() *rcond, integer *rank, $GENERIC() *work, integer * lwork, $GENERIC() *rwork, integer *iwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); [io]B(2,p,q); rcond(); [o]s(minmn); int [o]rank();int [o]info(); int [t]iwork(iworkn); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(minmn) = PDLMAX(1,PDLMIN($SIZE(m),$SIZE(n))); integer smlsiz = FORTRAN(ilaenv)(&c_nine, "CGELSD", " ", &c_zero, &c_zero, &c_zero, &c_zero, (ftnlen)6, (ftnlen)1); integer size_i = (integer) (log((double) $SIZE(minmn) / (double) (smlsiz + 1)) /log(2.)) + 1; $SIZE(iworkn) = $SIZE(minmn) * (3 * PDLMAX(size_i,0) + 11); $SIZE(rworkn) = $SIZE(minmn) * (10 + 2 * smlsiz + 8 * size_i) + 3 * smlsiz * $SIZE(q) + pow(smlsiz+1,2); ', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gelsd)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), &tmp_work[0], &lwork, $P(rwork), $P(iwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gelsd)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(q)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(s), $P(rcond), $P(rank), work, &lwork, $P(rwork), $P(iwork), $P(info)); free(work); } '); pp_defc("gglse", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gglse)(integer *m, integer *n, integer *p, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *c__, $GENERIC() *d__, $GENERIC() *x, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,m,n); [phys]B(2,p,n);[io,phys]c(2,m);[phys]d(2,p);[o,phys]x(2,n);int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gglse)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(c), $P(d), $P(x), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gglse)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(c), $P(d), $P(x), work, &lwork, $P(info)); free(work); } '); pp_defc("ggglm", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ggglm)(integer *n, integer *m, integer *p, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *d__, $GENERIC() *x, $GENERIC() *y, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,m); [phys]B(2,n,p);[phys]d(2,n);[o,phys]x(2,m);[o,phys]y(2,p);int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)ggglm)( &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(d), $P(x), $P(y), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ggglm)( &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(d), $P(x), $P(y), work, &lwork, $P(info)); free(work); } '); ################################################################################ # # COMPUTATIONAL LEVEL ROUTINES # ################################################################################ # TODO IPIV = min(m,n) pp_defc("getrf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)getrf)(integer *m, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); EOF HandleBad => 0, RedoDimsCode => '$SIZE(p) = PDLMIN($SIZE(m),$SIZE(n));', Pars => '[io]A(2,m,n); int [o]ipiv(p); int [o]info()', Code => generate_code ' FORTRAN($TFD(c,z)getrf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(ipiv), $P(info)); '); pp_defc("getf2", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)getf2)(integer *m, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); EOF HandleBad => 0, RedoDimsCode => '$SIZE(p) = PDLMIN($SIZE(m),$SIZE(n));', Pars => '[io]A(2,m,n); int [o]ipiv(p); int [o]info()', Code => generate_code ' FORTRAN($TFD(c,z)getf2)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(ipiv), $P(info)); '); pp_defc("sytrf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sytrf)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; integer lwork = -1; $GENERIC() tmp_work[2]; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sytrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)sytrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), work, &lwork, $P(info)); free (work); } '); pp_defc("sytf2", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sytf2)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sytf2)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(info)); '); pp_defc("chetrf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hetrf)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int uplo(); int [o]ipiv(n); int [o]info(); [t]work(workn);', RedoDimsCode => ' $SIZE(workn) = 2 * $SIZE(n) * FORTRAN(ilaenv)(&c_nine, "CHETRF", " ", &c_zero, &c_zero, &c_zero, &c_zero, (ftnlen)6, (ftnlen)1); ', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hetrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(work), &(integer){$SIZE(workn)}, $P(info)); ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("hetf2", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hetf2)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int uplo(); int [o]ipiv(n); int [o]info()', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hetf2)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(info)); ', Doc=>' =for ref Complex version of L for Hermitian matrix '); pp_defc("potrf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)potrf)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)potrf)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc=>' =for ref Complex version of L for Hermitian positive definite matrix '); pp_defc("potf2", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)potf2)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)potf2)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Complex version of L for Hermitian positive definite matrix '); pp_defc("getri", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)getri)(integer *n, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int [phys]ipiv(n); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)getri)( &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)getri)( &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), work, &lwork, $P(info)); free(work); } '); pp_defc("sytri", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sytri)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *work, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int uplo(); int ipiv(n); int [o]info(); [t]work(workn);', RedoDimsCode => ' $SIZE(workn) = 2 * $SIZE(n); ', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sytri)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(work), $P(info)); '); pp_defc("hetri", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hetri)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *work, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int uplo(); int ipiv(n); int [o]info(); [t]work(workn);', RedoDimsCode => ' $SIZE(workn) = 2 * $SIZE(n); ', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hetri)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(work), $P(info)); ', Doc => ' =for ref Complex version of L for Hermitian matrix '); pp_defc("potri", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)potri)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if ($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)potri)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); '); pp_defc("trtri", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)trtri)(char *uplo, char *diag, integer *n, $GENERIC() *a, integer * lda, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int diag(); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; char pdiag = \'N\'; if ($uplo()) puplo = \'L\'; if ($diag()) pdiag = \'U\'; FORTRAN($TFD(c,z)trtri)( &puplo, &pdiag, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); '); pp_defc("trti2", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)trti2)(char *uplo, char *diag, integer *n, $GENERIC() *a, integer * lda, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int uplo(); int diag(); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; char pdiag = \'N\'; if ($uplo()) puplo = \'L\'; if ($diag()) pdiag = \'U\'; FORTRAN($TFD(c,z)trti2)( &puplo, &pdiag, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(info)); '); pp_defc("getrs", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)getrs)(char *trans, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer * ldb, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int trans(); [io,phys]B(2,n,m); int [phys]ipiv(n); int [o,phys]info()', Code => generate_code ' char transp = \'N\'; if($trans() == 1) transp = \'T\'; else if($trans() == 2) transp = \'C\'; FORTRAN($TFD(c,z)getrs)( &transp, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc=>' =for ref Complex version of L Arguments ========= trans: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; '); pp_defc("sytrs", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sytrs)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer * ldb, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int uplo();[io,phys]B(2,n,m); int [phys]ipiv(n); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sytrs)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); '); pp_defc("hetrs", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hetrs)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, integer *ipiv, $GENERIC() *b, integer * ldb, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int uplo();[io,phys]B(2,n,m); int [phys]ipiv(n); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hetrs)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc => ' =for ref Complex version of L for Hermitian matrix '); pp_defc("potrs", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)potrs)(char *uplo, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, integer * info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int uplo(); [io,phys]B(2,n,m); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; if($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)potrs)( &puplo, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc=>' =for ref Complex version of L for Hermitian positive definite matrix '); pp_defc("trtrs", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)trtrs)(char *uplo, char *trans, char *diag, integer *n, integer *nrhs, $GENERIC() *a, integer *lda, $GENERIC() *b, integer * ldb, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int uplo(); int trans(); int diag();[io,phys]B(2,n,m); int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; char ptrans = \'N\'; char pdiag = \'N\'; if($uplo()) puplo = \'L\'; if($trans() == 1) ptrans = \'T\'; else if($trans() == 2) ptrans = \'C\'; if($diag()) pdiag = \'U\'; FORTRAN($TFD(c,z)trtrs)( &puplo, &ptrans, &pdiag, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(info)); ', Doc=>' =for ref Complex version of L Arguments ========= trans: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; '); pp_defc("latrs", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)latrs)(char *uplo, char *trans, char *diag, char * normin, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *x, $GENERIC() *scale, $GENERIC() *cnorm, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,n,n); int uplo(); int trans(); int diag(); int normin();[io,phys]x(2,n); [o,phys]scale();[io,phys]cnorm(n);int [o,phys]info()', Code => generate_code ' char puplo = \'U\'; char ptrans = \'N\'; char pdiag = \'N\'; char pnormin = \'N\'; if($uplo()) puplo = \'L\'; if($trans()) ptrans = \'T\'; else if($trans() == 2) ptrans = \'C\'; if($diag()) pdiag = \'U\'; if($normin()) pnormin = \'Y\'; FORTRAN($TFD(c,z)latrs)( &puplo, &ptrans, &pdiag, &pnormin, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(x), $P(scale), $P(cnorm), $P(info)); ', Doc=>' =for ref Complex version of L Arguments ========= trans: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; '); pp_defc("gecon", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gecon)(char *norm, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() *work, $GENERIC() * rwork, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int norm(); anorm(); [o]rcond();int [o]info(); [t]rwork(rworkn); [t]work(workn);', RedoDimsCode => ' $SIZE(rworkn) = 2 * $SIZE(n); $SIZE(workn) = 4 * $SIZE(n); ', Code => generate_code ' char pnorm = \'I\'; if($norm()) pnorm = \'O\'; FORTRAN($TFD(c,z)gecon)( &pnorm, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(anorm), $P(rcond), $P(work), $P(rwork), $P(info)); '); pp_defc("sycon", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)sycon)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() * work, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int uplo(); int ipiv(n); anorm(); [o]rcond();int [o]info(); [t]work(workn);', RedoDimsCode => '$SIZE(workn) = 4 * $SIZE(n);', Code => generate_code ' char puplo = \'U\'; if($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)sycon)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(anorm), $P(rcond), $P(work), $P(info)); '); pp_defc("hecon", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hecon)(char *uplo, integer *n, $GENERIC() *a, integer * lda, integer *ipiv, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() * work, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int uplo(); int ipiv(n); anorm(); [o]rcond();int [o]info(); [t]work(workn);', RedoDimsCode => '$SIZE(workn) = 4 * $SIZE(n);', Code => generate_code ' char puplo = \'U\'; if($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)hecon)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ipiv), $P(anorm), $P(rcond), $P(work), $P(info)); ', Doc => ' =for ref Complex version of L for Hermitian matrix '); pp_defc("pocon", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)pocon)(char *uplo, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *anorm, $GENERIC() *rcond, $GENERIC() *work, $GENERIC() * rwork, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int uplo(); anorm(); [o]rcond();int [o]info(); [t]work(workn); [t]rwork(n);', RedoDimsCode => '$SIZE(workn) = 4 * $SIZE(n);', Code => generate_code ' char puplo = \'U\'; if($uplo()) puplo = \'L\'; FORTRAN($TFD(c,z)pocon)( &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(anorm), $P(rcond), $P(work), $P(rwork), $P(info)); ', Doc => ' =for ref Complex version of L for Hermitian positive definite matrix '); pp_defc("trcon", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)trcon)(char *norm, char *uplo, char *diag,integer *n, $GENERIC() *a, integer * lda, $GENERIC() *rcond, $GENERIC() *work, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => 'A(2,n,n); int norm();int uplo();int diag(); [o]rcond();int [o]info(); [t]work(workn); [t]rwork(n);', RedoDimsCode => '$SIZE(workn) = 4 * $SIZE(n);', Code => generate_code ' char puplo = \'U\'; char pdiag = \'N\'; char pnorm = \'I\'; if($uplo()) puplo = \'L\'; if($diag()) pdiag = \'U\'; if($norm()) pnorm = \'O\'; FORTRAN($TFD(c,z)trcon)( &pnorm, &puplo, &pdiag, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(rcond), $P(work), $P(rwork), $P(info)); '); pp_defc("geqp3", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)geqp3)(integer *m, integer *n, $GENERIC() *a, integer * lda, integer *jpvt, $GENERIC() *tau, $GENERIC() *work, integer *lwork, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,m,n); int [io]jpvt(n); [o]tau(2,k); int [o]info(); [t]rwork(rworkn);', RedoDimsCode => '$SIZE(rworkn) = 2 * $SIZE(n);', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)geqp3)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(jpvt), $P(tau), &tmp_work[0], &lwork, $P(rwork), $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)geqp3)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(jpvt), $P(tau), work, &lwork, $P(rwork), $P(info)); free(work); } ' ); pp_defc("geqrf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)geqrf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [o,phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)geqrf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)geqrf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } '); pp_defc("ungqr", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ungqr)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)ungqr)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ungqr)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L '); pp_defc("unmqr", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unmqr)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,p,k); int side(); int trans(); [phys]tau(2,k); [io,phys]C(2,m,n);int [o,phys]info()', Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($trans()) ptrans = \'C\'; if($side()) pside = \'R\'; FORTRAN($TFD(c,z)unmqr)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unmqr)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. Here trans = 1 means conjugate transpose. '); pp_defc("gelqf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gelqf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [o,phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gelqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gelqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } '); pp_defc("unglq", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unglq)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)unglq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unglq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L '); pp_defc("unmlq", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unmlq)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,k,p); int side(); int trans(); [phys]tau(2,k); [io,phys]C(2,m,n);int [o,phys]info()', Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($trans()) ptrans = \'C\'; if($side()) pside = \'R\'; FORTRAN($TFD(c,z)unmlq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unmlq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. Here trans = 1 means conjugate transpose. '); pp_defc("geqlf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)geqlf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [o,phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)geqlf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)geqlf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } '); pp_defc("ungql", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ungql)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)ungql)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ungql)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. '); pp_defc("unmql", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unmql)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,p,k); int side(); int trans(); [phys]tau(2,k); [io,phys]C(2,m,n);int [o,phys]info()', Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($trans()) ptrans = \'C\'; if($side()) pside = \'R\'; FORTRAN($TFD(c,z)unmql)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unmql)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(p)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. Here trans = 1 means conjugate transpose. '); pp_defc("gerqf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gerqf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [o,phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gerqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gerqf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } '); pp_defc("ungrq", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)ungrq)(integer *m, integer *n, integer *k, $GENERIC() * a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)ungrq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)ungrq)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. '); pp_defc("unmrq", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unmrq)(char *side, char *trans, integer *m, integer *n, integer *k, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,k,p); int side(); int trans(); [phys]tau(2,k); [io,phys]C(2,m,n);int [o,phys]info()', Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($trans()) ptrans = \'C\'; if($side()) pside = \'R\'; FORTRAN($TFD(c,z)unmrq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unmrq)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. Here trans = 1 means conjugate transpose. '); pp_defc("tzrzf", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)tzrzf)(integer *m, integer *n, $GENERIC() *a, integer * lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); [o,phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)tzrzf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)tzrzf)( &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(tau), work, &lwork, $P(info)); free(work); } '); pp_defc("unmrz", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unmrz)(char *side, char *trans, integer *m, integer *n, integer *k, integer *l, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() * c__, integer *ldc, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[phys]A(2,k,p); int side(); int trans(); [phys]tau(2,k); [io,phys]C(2,m,n);int [o,phys]info()', Code => generate_code ' char ptrans = \'N\', pside = \'L\'; integer lwork = -1; integer kk = $SIZE(p) - $SIZE(k); $GENERIC() tmp_work[2]; if($trans()) ptrans = \'C\'; if($side()) pside = \'R\'; FORTRAN($TFD(c,z)unmrz)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, &kk, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unmrz)( &pside, &ptrans, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, &(integer){$SIZE(k)}, &kk, $P(A), &(integer){$SIZE(k)}, $P(tau), $P(C), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L. Here trans = 1 means conjugate transpose. '); pp_defc("gehrd", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gehrd)(integer *n, integer *ilo, integer *ihi, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int [phys]ilo();int [phys]ihi();[o,phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)gehrd)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)gehrd)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), work, &lwork, $P(info)); free(work); } '); pp_defc("unghr", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)unghr)(integer *n, integer *ilo, integer *ihi, $GENERIC() *a, integer *lda, $GENERIC() *tau, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int [phys]ilo();int [phys]ihi();[phys]tau(2,k); int [o,phys]info()', Code => generate_code ' integer lwork = -1; $GENERIC() tmp_work[2]; FORTRAN($TFD(c,z)unghr)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2*lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)unghr)( &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(A), &(integer){$SIZE(n)}, $P(tau), work, &lwork, $P(info)); free(work); } ', Doc=>' =for ref Complex version of L '); pp_defc("hseqr", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)hseqr)(char *job, char *compz, integer *n, integer *ilo, integer *ihi, $GENERIC() *h__, integer *ldh, $GENERIC() *w, $GENERIC() *z__, integer *ldz, $GENERIC() *work, integer *lwork, integer *info); EOF HandleBad => 0, Pars => '[io,phys]H(2,n,n); int job();int compz();int [phys]ilo();int [phys]ihi();[o,phys]w(2,n); [o,phys]Z(2,m,m); int [o,phys]info()', Code => generate_code ' char pcompz; char pjob = \'E\'; integer lwork = -1; $GENERIC() tmp_work[2]; if($job()) pjob = \'S\'; switch ($compz()) { case 1: pcompz = \'I\'; break; case 2: pcompz = \'V\'; break; default: pcompz = \'N\'; } FORTRAN($TFD(c,z)hseqr)( &pjob, &pcompz, &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(H), &(integer){$SIZE(n)}, $P(w), $P(Z), &(integer){$SIZE(m)}, &tmp_work[0], &lwork, $P(info)); lwork = (integer )tmp_work[0]; { $GENERIC() *work = ($GENERIC() *)malloc(2 * lwork * sizeof($GENERIC())); FORTRAN($TFD(c,z)hseqr)( &pjob, &pcompz, &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(H), &(integer){$SIZE(n)}, $P(w), $P(Z), &(integer){$SIZE(m)}, work, &lwork, $P(info)); free(work); } '); pp_defc("trevc", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)trevc)(char *side, char *howmny, logical *select, integer *n, $GENERIC() *t, integer *ldt, $GENERIC() *vl, integer * ldvl, $GENERIC() *vr, integer *ldvr, integer *mm, integer *m, $GENERIC() *work, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]T(2,n,n); int side();int howmny();int select(q);[o]VL(2,m,m); [o]VR(2,p,p);int [o]m(); int [o]info(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 1, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 2, $PDL(VR), $SIZE(p), $SIZE(n)) $SIZE(workn) = 5 * $SIZE(n); ', Code => generate_code ' char pside,phowmny; integer mm = PDLMAX($SIZE(m),$SIZE(p)); switch ($howmny()) { case 1: phowmny = \'B\'; break; case 2: phowmny = \'S\'; break; default: phowmny = \'A\'; } switch ($side()) { case 1: pside = \'R\'; break; case 2: pside = \'L\'; break; default:pside = \'B\'; } FORTRAN($TFD(c,z)trevc)( &pside, &phowmny, $P(select), &(integer){$SIZE(n)}, $P(T), &(integer){$SIZE(n)}, $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, &mm, $P(m), $P(work) + $SIZE(n), $P(work), $P(info)); '); pp_defc("tgevc", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)tgevc)(char *side, char *howmny, logical *select, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *vl, integer *ldvl, $GENERIC() *vr, integer *ldvr, integer *mm, integer *m, $GENERIC() *work, $GENERIC() *rwork, integer *info); EOF HandleBad => 0, Pars => '[io]A(2,n,n); int side();int howmny(); [io]B(2,n,n);int select(q);[o]VL(2,m,m); [o]VR(2,p,p);int [o]m(); int [o]info(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 1, $PDL(VL), $SIZE(m), $SIZE(n)) PDL_MAYBE_SIZE(PDL_Long, $PDL(side), tmp != 2, $PDL(VR), $SIZE(p), $SIZE(n)) $SIZE(workn) = 6 * $SIZE(n); ', Code => generate_code ' char pside,phowmny; integer mm = PDLMAX($SIZE(m),$SIZE(p)); switch ($howmny()) { case 1: phowmny = \'B\'; break; case 2: phowmny = \'S\'; break; default: phowmny = \'A\'; } switch ($side()) { case 1: pside = \'R\'; break; case 2: pside = \'L\'; break; default:pside = \'B\'; } FORTRAN($TFD(c,z)tgevc)( &pside, &phowmny, $P(select), &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(B), &(integer){$SIZE(n)}, $P(VL), &(integer){$SIZE(m)}, $P(VR), &(integer){$SIZE(p)}, &mm, $P(m), $P(work)+2*$SIZE(n), $P(work), $P(info)); '); pp_defc("gebal", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gebal)(char *job, integer *n, $GENERIC() *a, integer * lda, integer *ilo, integer *ihi, $GENERIC() *scale, integer *info); EOF HandleBad => 0, Pars => '[io,phys]A(2,n,n); int job(); int [o,phys]ilo();int [o,phys]ihi();[o,phys]scale(n); int [o,phys]info()', Code => generate_code ' char pjob; switch ($job()) { case 1: pjob = \'P\'; break; case 2: pjob = \'S\'; break; case 3: pjob = \'B\'; break; default: pjob = \'N\'; } FORTRAN($TFD(c,z)gebal)( &pjob, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(ilo), $P(ihi), $P(scale), $P(info)); '); ################################################################################# pp_defc("lange", _decl => <<'EOF', extern $GENERIC() FORTRAN($TFD(c,z)lange)(char *norm, integer *m, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *work); EOF HandleBad => 0, Pars => 'A(2,n,m); int norm(); [o]b(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(norm), tmp == 2, $PDL(work), $SIZE(workn), $SIZE(n)) ', Code => ' char pnorm; switch ($norm()) { case 1: pnorm = \'O\'; break; case 2: pnorm = \'I\'; break; case 3: pnorm = \'F\'; break; default: pnorm = \'M\'; } $b() = FORTRAN($TFD(c,z)lange)( &pnorm, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, $P(A), &(integer){$SIZE(n)}, $P(work)); '); pp_defc("lansy", _decl => <<'EOF', extern $GENERIC() FORTRAN($TFD(c,z)lansy)(char *norm, char *uplo, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *work); EOF HandleBad => 0, Pars => 'A(2,n,n); int uplo(); int norm(); [o]b(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(norm), tmp == 1 || tmp == 2, $PDL(work), $SIZE(workn), $SIZE(n)) ', Code => ' char pnorm, puplo = \'U\'; switch ($norm()) { case 1: pnorm = \'O\'; break; case 2: pnorm = \'I\'; break; case 3: pnorm = \'F\'; break; default: pnorm = \'M\'; } if($uplo()) puplo = \'L\'; $b() = FORTRAN($TFD(c,z)lansy)( &pnorm, &puplo, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(work)); '); pp_defc("lantr", _decl => <<'EOF', extern $GENERIC() FORTRAN($TFD(c,z)lantr)(char *norm, char *uplo, char *diag, integer *m, integer *n, $GENERIC() *a, integer *lda, $GENERIC() *work); EOF HandleBad => 0, Pars => 'A(2,m,n); int uplo(); int norm();int diag(); [o]b(); [t]work(workn);', RedoDimsCode => ' PDL_MAYBE_SIZE(PDL_Long, $PDL(norm), tmp == 2, $PDL(work), $SIZE(workn), $SIZE(n)) ', Code => ' char pnorm, puplo = \'U\'; char pdiag = \'N\'; switch ($norm()) { case 1: pnorm = \'O\'; break; case 2: pnorm = \'I\'; break; case 3: pnorm = \'F\'; break; default: pnorm = \'M\'; } if($uplo()) puplo = \'L\'; if($diag()) pdiag = \'U\'; $b() = FORTRAN($TFD(c,z)lantr)( &pnorm, &puplo, &pdiag, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, $P(work)); '); ################################################################################ # # BLAS ROUTINES # ################################################################################ pp_defc("gemm", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); EOF HandleBad => 0, Pars => '[phys]A(2,m,n); int transa(); int transb(); [phys]B(2,p,q);[phys]alpha(2); [phys]beta(2); [io,phys]C(2,r,s)', Code => ' char ptransa = \'N\'; char ptransb = \'N\'; integer kk = $transa() ? $SIZE(m) : $SIZE(n); if ($transa() == 1) ptransa = \'T\'; else if ($transa() == 2) ptransa = \'C\'; if ($transb()) ptransb = \'T\'; else if ($transb() == 2) ptransb = \'C\'; FORTRAN($TFD(c,z)gemm)( &ptransa, &ptransb, &(integer){$SIZE(r)}, &(integer){$SIZE(s)}, &kk, $P(alpha), $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}, $P(beta), $P(C), &(integer){$SIZE(r)}); ', Doc=>' =for ref Complex version of L. Arguments ========= transa: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; transb: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; '); if ($config{CBLAS}){ pp_def("rmcgemm", HandleBad => 0, Pars => '[phys]A(2,m,n); int transa(); int transb(); [phys]B(2,p,q);[phys]alpha(2); [phys]beta(2); [io,phys]C(2,r,s)', Code => ' int ptransa, ptransb; extern void cblas_$TFD(c,z)gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const void *alpha, const void *A, const int lda, const void *B, const int ldb, const void *beta, void *C, const int ldc); integer kk = $transa() ? $SIZE(n) : $SIZE(m); switch($transa()){ case 1: ptransa = CblasTrans; break; case 2: ptransa = CblasConjTrans; break; default:ptransa = CblasNoTrans; } switch($transb()){ case 1: ptransb = CblasTrans; break; case 2: ptransb = CblasConjTrans; break; default:ptransb = CblasNoTrans; } cblas_$TFD(c,z)gemm( CblasRowMajor, ptransa, ptransb, $SIZE(s), $SIZE(r), kk, $P(alpha), $P(A), $SIZE(m), $P(B), $SIZE(p), $P(beta), $P(C), $SIZE(r)); ', Doc=>' =for ref Complex version of L. Arguments ========= transa: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; transb: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; '); } pp_defc("mmult", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); EOF HandleBad => 0, Pars => '[phys]A(2,m,n); [phys]B(2,p,m); [o,phys]C(2,p,n)', Code => ' char ptrans = \'N\'; $GENERIC() alpha[2] = {1,0}; $GENERIC() beta[2] = {0,0}; FORTRAN($TFD(c,z)gemm)( &ptrans, &ptrans, &(integer){$SIZE(p)}, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &alpha[0], $P(B), &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, &beta[0], $P(C), &(integer){$SIZE(p)}); '); if ($config{STRASSEN}){ pp_defc("smmult", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gemmb)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); EOF HandleBad => 0, Pars => '[phys]A(2,m,n); [phys]B(2,p,m); [o,phys]C(2,p,n)', Code => ' char ptrans = \'N\'; $GENERIC() alpha[2] = {1,0}; $GENERIC() beta[2] = {0,0}; FORTRAN($TFD(c,z)gemmb)( &ptrans, &ptrans, &(integer){$SIZE(p)}, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &alpha[0], $P(B), &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(m)}, &beta[0], $P(C), &(integer){$SIZE(p)}); '); } pp_defc("crossprod", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); EOF HandleBad => 0, Pars => '[phys]A(2,n,m); [phys]B(2,p,m); [o,phys]C(2,p,n)', Code => ' char btrans = \'N\'; char atrans = \'C\'; $GENERIC() alpha[2] = {1,0}; $GENERIC() beta[2] = {0,0}; FORTRAN($TFD(c,z)gemm)( &btrans, &atrans, &(integer){$SIZE(p)}, &(integer){$SIZE(n)}, &(integer){$SIZE(m)}, &alpha[0], $P(B), &(integer){$SIZE(p)}, $P(A), &(integer){$SIZE(n)}, &beta[0], $P(C), &(integer){$SIZE(p)}); '); pp_defc("syrk", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)syrk)(char *uplo, char *trans, integer *n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); EOF HandleBad => 0, Pars => '[phys]A(2,m,n); int uplo(); int trans(); [phys]alpha(2); [phys]beta(2); [io,phys]C(2,p,p)', RedoDimsCode => '$SIZE(p) = $trans() ? $SIZE(n) : $SIZE(m);', Code => ' char puplo = \'U\'; char ptrans = \'N\'; integer kk = $trans() ? $SIZE(m) : $SIZE(n); if ($uplo()) puplo = \'L\'; if ($trans()) ptrans = \'T\'; FORTRAN($TFD(c,z)syrk)( &puplo, &ptrans, &(integer){$SIZE(p)}, &kk, $P(alpha), $P(A), &(integer){$SIZE(m)}, $P(beta), $P(C), &(integer){$SIZE(p)}); '); if ($config{CBLAS}){ pp_def("rmcsyrk", HandleBad => 0, Pars => '[phys]A(2,m,n); int uplo(); int trans(); [phys]alpha(2); [phys]beta(2); [io,phys]C(2,p,p)', Code => ' int puplo = CblasUpper; int ptrans; extern void cblas_$TFD(c,z)syrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE Trans, const int N, const int K, const void *alpha, const void *A, const int lda, const void *beta, void *C, const int ldc); integer kk = $trans() ? $SIZE(n) : $SIZE(m); if ($uplo()) puplo = CblasLower; switch($trans()){ case 1: ptrans = CblasTrans; break; case 2: ptrans = CblasConjTrans; break; default:ptrans = CblasNoTrans; } cblas_$TFD(c,z)syrk( CblasRowMajor, puplo, ptrans, $SIZE(p), kk, $P(alpha), $P(A), $SIZE(m), $P(beta), $P(C), $SIZE(p)); ', Doc=>' =for ref Complex version of L '); } pp_defc("dot", _decl => <<'EOF', extern complex $TFD(float,double) FORTRAN($TFD(c,z)dotu)(integer *n, $GENERIC() *dx, integer *incx, $GENERIC() *dy, integer *incy); EOF HandleBad => 0, Pars => '[phys]a(2,n);[phys]b(2,n);[o]c(2)', Code => ' complex $TFD(float,double) *cptr = (void*)$P(c); *cptr = FORTRAN($TFD(c,z)dotu)( &(integer){$SIZE(n)}, $P(a), &(integer){1}, $P(b), &(integer){1}); '); pp_defc("dotc", _decl => <<'EOF', extern $GENERIC() FORTRAN($TFD(c,z)dotc)(integer *n, $GENERIC() *dx, integer *incx, $GENERIC() *dy, integer *incy); EOF HandleBad => 0, Pars => '[phys]a(2,n);[phys]b(2,n);[o,phys]c(2)', Code => ' complex $TFD(float,double) *cptr = (void*)$P(c); *cptr = FORTRAN($TFD(c,z)dotc)( &(integer){$SIZE(n)}, $P(a), &(integer){1}, $P(b), &(integer){1}); ', Doc=>' =for ref Forms the dot product of two vectors, conjugating the first vector. '); pp_defc("axpy", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)axpy)(integer *n, $GENERIC() *da, $GENERIC() *dx, integer *incx, $GENERIC() *dy, integer *incy); EOF HandleBad => 0, Pars => '[phys]a(2,n);[phys] alpha(2);[io,phys]b(2,n)', Code => ' FORTRAN($TFD(c,z)axpy)( &(integer){$SIZE(n)}, $P(alpha), $P(a), &(integer){1}, $P(b), &(integer){1}); '); pp_defc("nrm2", _decl => <<'EOF', extern $GENERIC() FORTRAN($TFD(sc,dz)nrm2)(integer *n, $GENERIC() *dx, integer *incx); EOF HandleBad => 0, Pars => '[phys]a(2,n);[o]b()', Code => ' $b() = FORTRAN($TFD(sc,dz)nrm2)( &(integer){$SIZE(n)}, $P(a), &(integer){1}); '); pp_defc("asum", _decl => <<'EOF', extern $GENERIC() FORTRAN($TFD(sc,dz)asum)(integer *n, $GENERIC() *dx, integer *incx); EOF HandleBad => 0, Pars => '[phys]a(2,n);[o]b()', Code => ' $b() = FORTRAN($TFD(sc,dz)asum)( &(integer){$SIZE(n)}, $P(a), &(integer){1}); '); pp_defc("scal", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)scal)(integer *n, $GENERIC() *sa, $GENERIC() *dx, integer *incx); EOF HandleBad => 0, Pars => '[io,phys]a(2,n);scale(2)', Code => ' FORTRAN($TFD(c,z)scal)( &(integer){$SIZE(n)}, $P(scale), $P(a), &(integer){1}); '); pp_defc("sscal", _decl => <<'EOF', extern int FORTRAN($TFD(cs,zd)scal)(integer *n, $GENERIC() *sa, $GENERIC() *dx, integer *incx); EOF HandleBad => 0, Pars => '[io,phys]a(2,n);scale()', Code => ' FORTRAN($TFD(cs,zd)scal)( &(integer){$SIZE(n)}, $P(scale), $P(a), &(integer){1}); ', Doc=>' =for ref Scales a complex vector by a real constant. '); pp_defc("rotg", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)rotg)($GENERIC() *dx, $GENERIC() *dy, $GENERIC() *c, $GENERIC() *s); EOF HandleBad => 0, Pars => '[io,phys]a(2);[phys]b(2);[o,phys]c(); [o,phys]s(2)', Code => ' FORTRAN($TFD(c,z)rotg)( $P(a), $P(b), $P(c), $P(s) ); '); ################################################################################ # # LAPACK AUXILIARY ROUTINES # ################################################################################ pp_defc("lacpy", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)lacpy)(char *uplo, integer *m, integer *n, $GENERIC() * a, integer *lda, $GENERIC() *b, integer *ldb); EOF HandleBad => 0, Pars => '[phys]A(2,m,n); int uplo(); [o,phys]B(2,p,n)', Code => ' char puplo; switch ($uplo()) { case 0: puplo = \'U\'; break; case 1: puplo = \'L\'; break; default: puplo = \'A\'; } FORTRAN($TFD(c,z)lacpy)( &puplo, &(integer){$SIZE(m)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(B), &(integer){$SIZE(p)}); '); pp_defc("laswp", _decl => <<'EOF', extern int FORTRAN($TFD(c,z)laswp)(integer *n, $GENERIC() *a, integer *lda, integer *k1, integer *k2, integer *ipiv, integer *incx); EOF HandleBad => 0, Pars => '[io,phys]A(2,m,n); int [phys]k1(); int [phys]k2(); int [phys]ipiv(p)', Code => ' FORTRAN($TFD(c,z)laswp)( &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(m)}, $P(k1), $P(k2), $P(ipiv), &(integer){1}); '); ################################################################################ # # OTHER AUXILIARY ROUTINES # ################################################################################ pp_def( 'ctricpy', Pars => 'A(c=2,m,n);[o] C(c=2,m,n)', OtherPars => 'int uplo', OtherParsDefaults => {uplo => 0}, ArgOrder => [qw(A uplo C)], Code => ' if ($COMP(uplo)) { broadcastloop %{ loop (n,m) %{ loop(c) %{ $C() = $A(); %} if (m >= n) break; %} %} } else { broadcastloop %{ loop (m,n) %{ loop(c) %{ $C() = $A(); %} if (n >= m) break; %} %} } ', Doc => undef ); pp_bless('PDL'); pp_def( 'cmstack', DefaultFlow => 1, TwoWay => 1, Pars => 'x(c,n,m);y(c,n,p);[o]out(c,n,q);', RedoDimsCode => '$SIZE(q) = $SIZE(m) + $SIZE(n);', Code => ' loop(m,n,c) %{ $out(q=>m) = $x(); %} register PDL_Indx i,j=0; for (i = $SIZE(m); i < $SIZE(q); i++,j++) { loop(n,c) %{ $out(q=>i) = $y(p=>j); %} } ', BackCode => ' loop(m,n,c) %{ $x() = $out(q=>m); %} register PDL_Indx i,j=0; for (i = $SIZE(m); i < $SIZE(q) ;i++,j++) { loop(n,c)%{ $y(p=>j) = $out(q=>i); %} } ', Doc => < <<'EOF', extern int FORTRAN($TFD(c,z)gemm)(char *transa, char *transb, integer *m, integer * n, integer *k, $GENERIC() *alpha, $GENERIC() *a, integer *lda, $GENERIC() *b, integer *ldb, $GENERIC() *beta, $GENERIC() *c__, integer *ldc); EOF Pars => 'A(c=2,n,n);[o]Y(c=2,n,n);[o]out(c=2,p); [t]rwork(rworkn);', RedoDimsCode => ' $SIZE(p) = $SIZE(n) + 1; $SIZE(rworkn) = 2 * $SIZE(n) * $SIZE(n); ', Code => ' int i,j,k; $GENERIC() tr[2], b[2]; //$GENERIC() *tmp; char ptrans = \'N\'; $GENERIC() alpha[2] = {1,0}; $GENERIC() beta[2] = {0,0}; loop(n0,n1) %{ $Y(c=>0) = (n0 == n1) ? ($GENERIC()) 1.0 : ($GENERIC()) 0.0; $Y(c=>1) = ($GENERIC()) 0.0; %} $out(c=>0,p=>0) = 1; $out(c=>1,p=>0) = 0; i = 0; for (;;) { i++; FORTRAN($TFD(c,z)gemm)(&ptrans,&ptrans,&(integer){$SIZE(n)},&(integer){$SIZE(n)}, &(integer){$SIZE(n)},&alpha[0],$P(Y),&(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, &beta[0], $P(rwork), &(integer){$SIZE(n)}); if (i == $SIZE(n)) break; // if (k+1) & 1 without the copy below => return diagonal matrix // with determinant (on my 5-year-old-pentium (windows)) !!!??? // tmp = $P(Y); // $P(Y) = $P(rwork); // $P(rwork) = tmp; memmove($P(Y), $P(rwork), 2* $SIZE(n) * $SIZE(n) * sizeof($GENERIC())); // loop(n1,n0,c) %{ // $Y() = $P(rwork)[((n1*$SIZE(n))+n0)*2+c]; // %} c$TFD(f,d)trace($SIZE(n), $P(Y), &tr[0]); loop(c) %{ b[c] = $out(p=>i) = - tr[c] / i; %} loop (n0,c) %{ $Y(n1=>n0) += b[c]; %} } k = $SIZE(n); c$TFD(f,d)trace(k, $P(rwork), &tr[0]); loop(c) %{ $out(p=>k) = - tr[c] / k; %} if ((k+1) & 1) { loop(n0,n1,c) %{ $Y() = -$Y(); %} } ' ); pp_addpm({At=>'Bot'},<<'EOD'); =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut EOD pp_done(); # you will need this to finish pp processing PDL-LinearAlgebra-0.38/Complex/selectfunc.c0000644000175000017500000000555714410675450020427 0ustar osboxesosboxes#include "EXTERN.h" #include "perl.h" #include "pdl.h" #include "pdlcore.h" #define PDL PDL_LinearAlgebra_Complex extern Core *PDL; #define PDL_LA_COMPLEX_INIT_PUSH(pdlvar, type, valp, svpdl) \ pdl *pdlvar = PDL->pdlnew(); \ PDL->setdims(pdlvar, dims, ndims); \ pdlvar->datatype = type + type_add; \ pdlvar->data = valp; \ pdlvar->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED; \ ENTER; SAVETMPS; PUSHMARK(sp); \ SV *svpdl = sv_newmortal(); \ PDL->SetSV_PDL(svpdl, pdlvar); \ svpdl = sv_bless(svpdl, bless_stash); /* bless in PDL::Complex */ \ XPUSHs(svpdl); \ PUTBACK; #define PDL_LA_COMPLEX_UNINIT(pdl) \ PDL->setdims(pdl, odims, sizeof(odims)/sizeof(odims[0])); \ pdl->state &= ~ (PDL_ALLOCATED |PDL_DONTTOUCHDATA); \ pdl->data=NULL; /* replace BLAS one so don't terminate on bad input */ int xerbla_(char *sub, int *info) { return 0; } #define SEL_FUNC2(letter, letter2, type, pdl_type, args, init, uninit) \ static SV* letter ## letter2 ## select_func = NULL; \ void letter ## letter2 ## select_func_set(SV* func) { \ if (letter ## letter2 ## select_func) SvREFCNT_dec(letter ## letter2 ## select_func); \ SvREFCNT_inc(letter ## letter2 ## select_func = func); \ } \ PDL_Long letter ## letter2 ## select_wrapper args \ { \ dSP; \ PDL_Indx odims[] = {0}; \ PDL_Indx pc_dims[] = {2}; \ SV *pcv = perl_get_sv("PDL::Complex::VERSION", 0); \ char use_native = !pcv || !SvOK(pcv); \ PDL_Indx *dims = use_native ? NULL : pc_dims; \ PDL_Indx ndims = use_native ? 0 : sizeof(dims)/sizeof(dims[0]); \ int type_add = use_native ? PDL_CF - PDL_F : 0; \ HV *bless_stash = gv_stashpv(use_native ? "PDL" : "PDL::Complex", 0); \ init \ int count = perl_call_sv(letter ## select_func, G_SCALAR); \ SPAGAIN; \ uninit \ if (count !=1) croak("Error calling perl function\n"); \ long ret = (long ) POPl ; \ PUTBACK ; FREETMPS ; LEAVE ; \ return ret; \ } #define SEL_FUNC(letter, type, pdl_type) \ SEL_FUNC2(letter, , type, pdl_type, (type *p), \ PDL_LA_COMPLEX_INIT_PUSH(pdl, pdl_type, p, svpdl), \ PDL_LA_COMPLEX_UNINIT(pdl) \ ) SEL_FUNC(f, float, PDL_F) SEL_FUNC(d, double, PDL_D) #define GSEL_FUNC(letter, type, pdl_type) \ SEL_FUNC2(letter, g, type, pdl_type, (type *p, type *q), \ PDL_LA_COMPLEX_INIT_PUSH(pdl1, pdl_type, p, svpdl1) \ PDL_LA_COMPLEX_INIT_PUSH(pdl2, pdl_type, q, svpdl2), \ PDL_LA_COMPLEX_UNINIT(pdl1) \ PDL_LA_COMPLEX_UNINIT(pdl2) \ ) GSEL_FUNC(f, float, PDL_F) GSEL_FUNC(d, double, PDL_D) #define TRACE(letter, type) \ void c ## letter ## trace(int n, void *a1, void *a2) { \ type *mat = a1, *res = a2; \ PDL_Indx i; \ res[0] = mat[0]; \ res[1] = mat[1]; \ for (i = 1; i < n; i++) \ { \ res[0] += mat[(i*(n+1))*2]; \ res[1] += mat[(i*(n+1))*2+1]; \ } \ } TRACE(f, float) TRACE(d, double) PDL-LinearAlgebra-0.38/Complex/Makefile.PL0000755000175000017500000000067514224144746020103 0ustar osboxesosboxesuse ExtUtils::MakeMaker; use PDL::Core::Dev; our (%ldloadlibs, $libs0, $inc); my $pkg = 'Complex'; my $file = lc($pkg).".pd"; my @pack = ([$file, $pkg, "PDL::LinearAlgebra::$pkg",undef,1]); my %hash = pdlpp_stdargs(@pack); $hash{LIBS}[0] .= $libs0; $hash{OBJECT} .= ' selectfunc$(OBJ_EXT)'; $hash{INC} .= " $inc"; WriteMakefile( %hash, %ldloadlibs, VERSION_FROM => $file, NO_MYMETA => 1, ); sub MY::postamble { pdlpp_postamble(@pack); } PDL-LinearAlgebra-0.38/GENERATED/0000755000175000017500000000000014565105647016012 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/GENERATED/PDL/0000755000175000017500000000000014565105647016431 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/GENERATED/PDL/LinearAlgebra/0000755000175000017500000000000014565105656021121 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/GENERATED/PDL/LinearAlgebra/Real.pm0000644000175000017500000074421614565105656022360 0ustar osboxesosboxes# # GENERATED WITH PDL::PP! Don't modify! # package PDL::LinearAlgebra::Real; our @EXPORT_OK = qw(gtsv gesvd gesdd ggsvd geev geevx ggev ggevx gees geesx gges ggesx syev syevd syevx syevr sygv sygvd sygvx gesv gesvx sysv sysvx posv posvx gels gelsy gelss gelsd gglse ggglm getrf getf2 sytrf sytf2 potrf potf2 getri sytri potri trtri trti2 getrs sytrs potrs trtrs latrs gecon sycon pocon trcon geqp3 geqrf orgqr ormqr gelqf orglq ormlq geqlf orgql ormql gerqf orgrq ormrq tzrzf ormrz gehrd orghr hseqr trevc tgevc gebal gebak lange lansy lantr gemm mmult crossprod syrk dot axpy nrm2 asum scal rot rotg lasrt lacpy laswp lamch labad tricpy cplx_eigen augment mstack charpol ); our %EXPORT_TAGS = (Func=>\@EXPORT_OK); use PDL::Core; use PDL::Exporter; use DynaLoader; our $VERSION = '0.14'; our @ISA = ( 'PDL::Exporter','DynaLoader' ); push @PDL::Core::PP, __PACKAGE__; bootstrap PDL::LinearAlgebra::Real $VERSION; #line 79 "real.pd" use strict; { package # hide from CPAN PDL; my $warningFlag; BEGIN{ $warningFlag = $^W; $^W = 0; } use overload ( 'x' => sub { !(grep ref($_) && !$_->type->real, @_[0,1]) ? PDL::mmult($_[0], $_[1]) : PDL::cmmult($_[0], $_[1]) }, ); BEGIN{ $^W = $warningFlag;} } =encoding Latin-1 =head1 NAME PDL::LinearAlgebra::Real - PDL interface to the real lapack linear algebra programming library =head1 SYNOPSIS use PDL::LinearAlgebra::Real; $a = random (100,100); $s = zeroes(100); $u = zeroes(100,100); $v = zeroes(100,100); $info = 0; $job = 0; gesdd($a, $job, $info, $s , $u, $v); =head1 DESCRIPTION This module provides an interface to parts of the real lapack library. These routines accept either float or double ndarrays. =cut #line 74 "Real.pm" =head1 FUNCTIONS =cut =head2 gtsv =for sig Signature: ([phys]DL(n); [phys]D(n); [phys]DU(n); [io,phys]B(n,nrhs); int [o,phys]info()) =for ref Solves the equation A * X = B where A is an C by C tridiagonal matrix, by Gaussian elimination with partial pivoting, and B is an C by C matrix. Note that the equation C may be solved by interchanging the order of the arguments DU and DL. B This differs from the LINPACK function C in that C
starts from its first element, while the LINPACK equivalent starts from its second element. Arguments ========= DL: On entry, DL must contain the (n-1) sub-diagonal elements of A. On exit, DL is overwritten by the (n-2) elements of the second super-diagonal of the upper triangular matrix U from the LU factorization of A, in DL(1), ..., DL(n-2). D: On entry, D must contain the diagonal elements of A. On exit, D is overwritten by the n diagonal elements of U. DU: On entry, DU must contain the (n-1) super-diagonal elements of A. On exit, DU is overwritten by the (n-1) elements of the first super-diagonal of the U. B: On entry, the n by nrhs matrix of right hand side matrix B. On exit, if info = 0, the n by nrhs solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero, and the solution has not been computed. The factorization has not been completed unless i = n. =for example $dl = random(float, 9); $d = random(float, 10); $du = random(float, 9); $b = random(10,5); gtsv($dl, $d, $du, $b, ($info=null)); print "X is:\n$b" unless $info; =for bad gtsv ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gtsv = \&PDL::gtsv; =head2 gesvd =for sig Signature: ([io]A(m,n); int jobu(); int jobvt(); [o]s(minmn); [o]U(p,p); [o]VT(s,s); int [o]info()) =for ref Computes the singular value decomposition (SVD) of a real M-by-N matrix A. The SVD is written A = U * SIGMA * V' where SIGMA is an M-by-N matrix which is zero except for its min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA are the singular values of A; they are real and non-negative, and are returned in descending order. The first min(m,n) columns of U and V are the left and right singular vectors of A. Note that the routine returns VT = V', not V. jobu: Specifies options for computing all or part of the matrix U: = 0: no columns of U (no left singular vectors) are computed. = 1: all M columns of U are returned in array U: = 2: the first min(m,n) columns of U (the left singular vectors) are returned in the array U; = 3: the first min(m,n) columns of U (the left singular vectors) are overwritten on the array A; jobvt: Specifies options for computing all or part of the matrix V': = 0: no rows of V' (no right singular vectors) are computed. = 1: all N rows of V' are returned in the array VT; = 2: the first min(m,n) rows of V' (the right singular vectors) are returned in the array VT; = 3: the first min(m,n) rows of V' (the right singular vectors) are overwritten on the array A; jobvt and jobu cannot both be 3. A: On entry, the M-by-N matrix A. On exit, if jobu = 3, A is overwritten with the first min(m,n) columns of U (the left singular vectors, stored columnwise); if jobvt = 3, A is overwritten with the first min(m,n) rows of V' (the right singular vectors, stored rowwise); if jobu != 3 and jobvt != 3, the contents of A are destroyed. s: The singular values of A, sorted so that s(i) >= s(i+1). U: If jobu = 1, U contains the M-by-M orthogonal matrix U; if jobu = 3, U contains the first min(m,n) columns of U (the left singular vectors, stored columnwise); if jobu = 0 or 3, U is not referenced. Min size = [1,1]. VT: If jobvt = 1, VT contains the N-by-N orthogonal matrix V'; if jobvt = 2, VT contains the first min(m,n) rows of V' (the right singular vectors, stored rowwise); if jobvt = 0 or 3, VT is not referenced. Min size = [1,1]. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. > 0: if bdsqr did not converge, info specifies how many superdiagonals of an intermediate bidiagonal form B did not converge to zero. =for example $a = random (float, 100,100); $s = zeroes(float, 100); $u = zeroes(float, 100,100); $vt = zeroes(float, 100,100); $info = pdl(long, 0); gesvd($a, 2, 2, $s , $u, $vt, $info); =for bad gesvd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gesvd = \&PDL::gesvd; =head2 gesdd =for sig Signature: ([io]A(m,n); int jobz(); [o]s(minmn); [o]U(p,p); [o]VT(s,s); int [o]info(); int [t]iwork(iworkn)) =for ref Computes the singular value decomposition (SVD) of a real M-by-N matrix A. This routine use the Coppen's divide and conquer algorithm. It is much faster than the simple driver for large matrices, but uses more workspace. jobz: Specifies options for computing all or part of matrix: = 0: no columns of U or rows of V' are computed; = 1: all M columns of U and all N rows of V' are returned in the arrays U and VT; = 2: the first min(M,N) columns of U and the first min(M,N) rows of V' are returned in the arrays U and VT; = 3: If M >= N, the first N columns of U are overwritten on the array A and all rows of V' are returned in the array VT; otherwise, all columns of U are returned in the array U and the first M rows of V' are overwritten on the array A. A: On entry, the M-by-N matrix A. On exit, if jobz = 3, A is overwritten with the first N columns of U (the left singular vectors, stored columnwise) if M >= N; A is overwritten with the first M rows of V' (the right singular vectors, stored rowwise) otherwise. if jobz != 3, the contents of A are destroyed. s: The singular values of A, sorted so that s(i) >= s(i+1). U: If jobz = 1 or jobz = 3 and M < N, U contains the M-by-M orthogonal matrix U; if jobz = 2, U contains the first min(M,N) columns of U (the left singular vectors, stored columnwise); if jobz = 3 and M >= N, or jobz = 0, U is not referenced. Min size = [1,1]. VT: If jobz = 1 or jobz = 3 and M >= N, VT contains the N-by-N orthogonal matrix V'; if jobz = 2, VT contains the first min(M,N) rows of V' (the right singular vectors, stored rowwise); if jobz = 3 and M < N, or jobz = 0, VT is not referenced. Min size = [1,1]. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. > 0: bdsdc did not converge, updating process failed. =for example $lines = 50; $columns = 100; $a = random (float, $lines, $columns); $min = $lines < $columns ? $lines : $columns; $s = zeroes(float, $min); $u = zeroes(float, $lines, $lines); $vt = zeroes(float, $columns, $columns); $info = long (0); gesdd($a, 1, $s , $u, $vt, $info); =for bad gesdd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gesdd = \&PDL::gesdd; =head2 ggsvd =for sig Signature: ([io]A(m,n); int jobu(); int jobv(); int jobq(); [io]B(p,n); int [o]k(); int [o]l();[o]alpha(n);[o]beta(n); [o]U(q,q); [o]V(r,r); [o]Q(s,s); int [o]iwork(n); int [o]info()) =for ref Computes the generalized singular value decomposition (GSVD) of an M-by-N real matrix A and P-by-N real matrix B: U'*A*Q = D1*( 0 R ), V'*B*Q = D2*( 0 R ) where U, V and Q are orthogonal matrices, and Z' is the transpose of Z. Let K+L = the effective numerical rank of the matrix (A',B')', then R is a K+L-by-K+L nonsingular upper triangular matrix, D1 and D2 are M-by-(K+L) and P-by-(K+L) "diagonal" matrices and of the following structures, respectively: If M-K-L >= 0, K L D1 = K ( I 0 ) L ( 0 C ) M-K-L ( 0 0 ) K L D2 = L ( 0 S ) P-L ( 0 0 ) N-K-L K L ( 0 R ) = K ( 0 R11 R12 ) L ( 0 0 R22 ) where C = diag( ALPHA(K+1), ... , ALPHA(K+L) ), S = diag( BETA(K+1), ... , BETA(K+L) ), C**2 + S**2 = I. R is stored in A(1:K+L,N-K-L+1:N) on exit. If M-K-L < 0, K M-K K+L-M D1 = K ( I 0 0 ) M-K ( 0 C 0 ) K M-K K+L-M D2 = M-K ( 0 S 0 ) K+L-M ( 0 0 I ) P-L ( 0 0 0 ) N-K-L K M-K K+L-M ( 0 R ) = K ( 0 R11 R12 R13 ) M-K ( 0 0 R22 R23 ) K+L-M ( 0 0 0 R33 ) where C = diag( ALPHA(K+1), ... , ALPHA(M) ), S = diag( BETA(K+1), ... , BETA(M) ), C**2 + S**2 = I. (R11 R12 R13 ) is stored in A(1:M, N-K-L+1:N), and R33 is stored ( 0 R22 R23 ) in B(M-K+1:L,N+M-K-L+1:N) on exit. The routine computes C, S, R, and optionally the orthogonal transformation matrices U, V and Q. In particular, if B is an N-by-N nonsingular matrix, then the GSVD of A and B implicitly gives the SVD of A*inv(B): A*inv(B) = U*(D1*inv(D2))*V'. If ( A',B')' has orthonormal columns, then the GSVD of A and B is also equal to the CS decomposition of A and B. Furthermore, the GSVD can be used to derive the solution of the eigenvalue problem: A'*A x = lambda* B'*B x. In some literature, the GSVD of A and B is presented in the form U'*A*X = ( 0 D1 ), V'*B*X = ( 0 D2 ) where U and V are orthogonal and X is nonsingular, D1 and D2 are "diagonal". The former GSVD form can be converted to the latter form by taking the nonsingular matrix X as X = Q*( I 0 ) ( 0 inv(R) ). Arguments ========= jobu: = 0: U is not computed. = 1: Orthogonal matrix U is computed; jobv: = 0: V is not computed. = 1: Orthogonal matrix V is computed; jobq: = 0: Q is not computed. = 1: Orthogonal matrix Q is computed; k: l: On exit, k and l specify the dimension of the subblocks described in the Purpose section. k + l = effective numerical rank of (A',B')'. A: On entry, the M-by-N matrix A. On exit, A contains the triangular matrix R, or part of R. B: On entry, the P-by-N matrix B. On exit, B contains the triangular matrix R if M-k-l < 0. alpha: beta: On exit, alpha and beta contain the generalized singular value pairs of A and B; alpha(1:k) = 1, beta(1:k) = 0, and if M-k-l >= 0, alpha(k+1:k+l) = C, beta(k+1:k+l) = S, or if M-k-l < 0, alpha(k+1:M)=C, alpha(M+1:k+l)=0 beta(k+1:M) =S, beta(M+1:k+l) =1 and alpha(k+l+1:N) = 0 beta(k+l+1:N) = 0 U: If jobu = 1, U contains the M-by-M orthogonal matrix U. If jobu = 0, U is not referenced. Need a minimum array of (1,1) if jobu = 0; V: If jobv = 1, V contains the P-by-P orthogonal matrix V. If jobv = 0, V is not referenced. Need a minimum array of (1,1) if jobv = 0; Q: If jobq = 1, Q contains the N-by-N orthogonal matrix Q. If jobq = 0, Q is not referenced. Need a minimum array of (1,1) if jobq = 0; iwork: On exit, iwork stores the sorting information. More precisely, the following loop will sort alpha for I = k+1, min(M,k+l) swap alpha(I) and alpha(iwork(I)) endfor such that alpha(1) >= alpha(2) >= ... >= alpha(N). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = 1, the Jacobi-type procedure failed to converge. For further details, see subroutine tgsja. =for example $k = null; $l = null; $A = random(5,6); $B = random(7,6); $alpha = zeroes(6); $beta = zeroes(6); $U = zeroes(5,5); $V = zeroes(7,7); $Q = zeroes(6,6); $iwork = zeroes(long, 6); $info = null; ggsvd($A,1,1,1,$B,$k,$l,$alpha, $beta,$U, $V, $Q, $iwork,$info); =for bad ggsvd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ggsvd = \&PDL::ggsvd; =head2 geev =for sig Signature: (A(n,n); int jobvl(); int jobvr(); [o]wr(n); [o]wi(n); [o]vl(m,m); [o]vr(p,p); int [o]info()) =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues and, optionally, the left and/or right eigenvectors. The right eigenvector v(j) of A satisfies: A * v(j) = lambda(j) * v(j) where lambda(j) is its eigenvalue. The left eigenvector u(j) of A satisfies: u(j)**H * A = lambda(j) * u(j)**H where u(j)**H denotes the conjugate transpose of u(j). The computed eigenvectors are normalized to have Euclidean norm equal to 1 and largest component real. Arguments ========= jobvl: = 0: left eigenvectors of A are not computed; = 1: left eigenvectors of A are computed. jobvr: = 0: right eigenvectors of A are not computed; = 1: right eigenvectors of A are computed. A: A is overwritten. wr: wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues. Complex conjugate pairs of eigenvalues appear consecutively with the eigenvalue having the positive imaginary part first. vl: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of vl, in the same order as their eigenvalues else vl is not referenced. If the j-th eigenvalue is real, then u(j) = vl(:,j), the j-th column of vl. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and u(j+1) = vl(:,j) - i*vl(:,j+1). Min size = [1]. vr: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of vr, in the same order as their eigenvalues else vr is not referenced. If the j-th eigenvalue is real, then v(j) = vr(:,j), the j-th column of vr. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and v(j+1) = vr(:,j) - i*vr(:,j+1). Min size = [1]. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, the QR algorithm failed to compute all the eigenvalues, and no eigenvectors have been computed; elements i+1:N of wr and wi contain eigenvalues which have converged. =for example $a = random (5, 5); $wr = zeroes(5); $wi = zeroes($wr); $vl = zeroes($a); $vr = zeroes($a); $info = null; geev($a, 1, 1, $wr, $wi, $vl, $vr, $info); =for bad geev ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geev = \&PDL::geev; =head2 geevx =for sig Signature: ([io]A(n,n); int jobvl(); int jobvr(); int balance(); int sense(); [o]wr(n); [o]wi(n); [o]vl(m,m); [o]vr(p,p); int [o]ilo(); int [o]ihi(); [o]scale(n); [o]abnrm(); [o]rconde(q); [o]rcondv(r); int [o]info(); int [t]iwork(iworkn)) =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues and, optionally, the left and/or right eigenvectors. Optionally also, it computes a balancing transformation to improve the conditioning of the eigenvalues and eigenvectors (ilo, ihi, scale, and abnrm), reciprocal condition numbers for the eigenvalues (rconde), and reciprocal condition numbers for the right eigenvectors (rcondv). The right eigenvector v(j) of A satisfies: A * v(j) = lambda(j) * v(j) where lambda(j) is its eigenvalue. The left eigenvector u(j) of A satisfies: u(j)**H * A = lambda(j) * u(j)**H where u(j)**H denotes the conjugate transpose of u(j). The computed eigenvectors are normalized to have Euclidean norm equal to 1 and largest component real. Balancing a matrix means permuting the rows and columns to make it more nearly upper triangular, and applying a diagonal similarity transformation D * A * D**(-1), where D is a diagonal matrix, to make its rows and columns closer in norm and the condition numbers of its eigenvalues and eigenvectors smaller. The computed reciprocal condition numbers correspond to the balanced matrix. Permuting rows and columns will not change the condition numbers (in exact arithmetic) but diagonal scaling will. For further explanation of balancing, see section 4.10.2 of the LAPACK Users' Guide. Arguments ========= balance: Indicates how the input matrix should be diagonally scaled and/or permuted to improve the conditioning of its eigenvalues. = 0: Do not diagonally scale or permute; = 1: Perform permutations to make the matrix more nearly upper triangular. Do not diagonally scale; = 2: Diagonally scale the matrix, i.e. replace A by D*A*D**(-1), where D is a diagonal matrix chosen to make the rows and columns of A more equal in norm. Do not permute; = 3: Both diagonally scale and permute A. Computed reciprocal condition numbers will be for the matrix after balancing and/or permuting. Permuting does not change condition numbers (in exact arithmetic), but balancing does. jobvl: = 0: left eigenvectors of A are not computed; = 1: left eigenvectors of A are computed. If sense = 1 or 3, jobvl must = 1. jobvr; = 0: right eigenvectors of A are not computed; = 1: right eigenvectors of A are computed. If sense = 1 or 3, jobvr must = 1. sense: Determines which reciprocal condition numbers are computed. = 0: None are computed; = 1: Computed for eigenvalues only; = 2: Computed for right eigenvectors only; = 3: Computed for eigenvalues and right eigenvectors. If sense = 1 or 3, both left and right eigenvectors must also be computed (jobvl = 1 and jobvr = 1). A: The N-by-N matrix. It is overwritten. If jobvl = 1 or jobvr = 1, A contains the real Schur form of the balanced version of the input matrix A. wr wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues. Complex conjugate pairs of eigenvalues will appear consecutively with the eigenvalue having the positive imaginary part first. vl: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of vl, in the same order as their eigenvalues else vl is not referenced. If the j-th eigenvalue is real, then u(j) = vl(:,j), the j-th column of vl. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and u(j+1) = vl(:,j) - i*vl(:,j+1). Min size = [1]. vr: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of vr, in the same order as their eigenvalues else vr is not referenced. If the j-th eigenvalue is real, then v(j) = vr(:,j), the j-th column of vr. If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and v(j+1) = vr(:,j) - i*vr(:,j+1). Min size = [1]. ilo,ihi:Integer values determined when A was balanced. The balanced A(i,j) = 0 if I > J and J = 1,...,ilo-1 or I = ihi+1,...,N. scale: Details of the permutations and scaling factors applied when balancing A. If P(j) is the index of the row and column interchanged with row and column j, and D(j) is the scaling factor applied to row and column j, then scale(J) = P(J), for J = 1,...,ilo-1 = D(J), for J = ilo,...,ihi = P(J) for J = ihi+1,...,N. The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. abnrm: The one-norm of the balanced matrix (the maximum of the sum of absolute values of elements of any column). rconde: rconde(j) is the reciprocal condition number of the j-th eigenvalue. rcondv: rcondv(j) is the reciprocal condition number of the j-th right eigenvector. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, the QR algorithm failed to compute all the eigenvalues, and no eigenvectors or condition numbers have been computed; elements 1:ilo-1 and i+1:N of wr and wi contain eigenvalues which have converged. =for example $a = random (5,5); $wr = zeroes(5); $wi = zeroes(5); $vl = zeroes(5,5); $vr = zeroes(5,5); $ilo = null; $ihi = null; $scale = zeroes(5); $abnrm = null; $rconde = zeroes(5); $rcondv = zeroes(5); $info = null; geevx($a, 1,1,3,3,$wr, $wi, $vl, $vr, $ilo, $ihi, $scale, $abnrm,$rconde, $rcondv, $info); =for bad geevx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geevx = \&PDL::geevx; =head2 ggev =for sig Signature: (A(n,n); int [phys]jobvl();int [phys]jobvr();B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VL(m,m);[o]VR(p,p);int [o]info()) =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B) the generalized eigenvalues, and optionally, the left and/or right generalized eigenvectors. A generalized eigenvalue for a pair of matrices (A,B) is a scalar lambda or a ratio alpha/beta = lambda, such that A - lambda*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0, and even for both being zero. The right eigenvector v(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies A * v(j) = lambda(j) * B * v(j). The left eigenvector u(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies u(j)**H * A = lambda(j) * u(j)**H * B . where u(j)**H is the conjugate-transpose of u(j). Arguments ========= jobvl: = 0: do not compute the left generalized eigenvectors; = 1: compute the left generalized eigenvectors. jobvr: = 0: do not compute the right generalized eigenvectors; = 1: compute the right generalized eigenvectors. A: On entry, the matrix A in the pair (A,B). On exit, A has been overwritten. B: On entry, the matrix B in the pair (A,B). On exit, B has been overwritten. alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio alpha/beta. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). VL: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of VL, in the same order as their eigenvalues. If the j-th eigenvalue is real, then u(j) = VL(:,j), the j-th column of VL. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then u(j) = VL(:,j)+i*VL(:,j+1) and u(j+1) = VL(:,j)-i*VL(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part)+abs(imag. part)=1. Not referenced if jobvl = 0. VR: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of VR, in the same order as their eigenvalues. If the j-th eigenvalue is real, then v(j) = VR(:,j), the j-th column of VR. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then v(j) = VR(:,j)+i*VR(:,j+1) and v(j+1) = VR(:,j)-i*VR(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part)+abs(imag. part)=1. Not referenced if jobvr = 0. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. No eigenvectors have been calculated, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: error return from tgevc. =for example $a = random(5,5); $b = random(5,5); $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vl = zeroes(5,5); $vr = zeroes(5,5); ggev($a, 1, 1, $b, $alphar, $alphai, $beta, $vl, $vr, ($info=null)); =for bad ggev ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ggev = \&PDL::ggev; =head2 ggevx =for sig Signature: ([io,phys]A(n,n);int balanc();int jobvl();int jobvr();int sense();[io,phys]B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VL(m,m);[o]VR(p,p);int [o]ilo();int [o]ihi();[o]lscale(n);[o]rscale(n);[o]abnrm();[o]bbnrm();[o]rconde(r);[o]rcondv(s);int [o]info(); int [t]bwork(bworkn); int [t]iwork(iworkn)) =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B) the generalized eigenvalues, and optionally, the left and/or right generalized eigenvectors. Optionally also, it computes a balancing transformation to improve the conditioning of the eigenvalues and eigenvectors (ilo, ihi, lscale, rscale, abnrm, and bbnrm), reciprocal condition numbers for the eigenvalues (rconde), and reciprocal condition numbers for the right eigenvectors (rcondv). A generalized eigenvalue for a pair of matrices (A,B) is a scalar lambda or a ratio alpha/beta = lambda, such that A - lambda*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0, and even for both being zero. The right eigenvector v(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies A * v(j) = lambda(j) * B * v(j) . The left eigenvector u(j) corresponding to the eigenvalue lambda(j) of (A,B) satisfies u(j)**H * A = lambda(j) * u(j)**H * B. where u(j)**H is the conjugate-transpose of u(j). Further Details =============== Balancing a matrix pair (A,B) includes, first, permuting rows and columns to isolate eigenvalues, second, applying diagonal similarity transformation to the rows and columns to make the rows and columns as close in norm as possible. The computed reciprocal condition numbers correspond to the balanced matrix. Permuting rows and columns will not change the condition numbers (in exact arithmetic) but diagonal scaling will. For further explanation of balancing, see section 4.11.1.2 of LAPACK Users' Guide. An approximate error bound on the chordal distance between the i-th computed generalized eigenvalue w and the corresponding exact eigenvalue lambda is chord(w, lambda) <= EPS * norm(abnrm, bbnrm) / rconde(I) An approximate error bound for the angle between the i-th computed eigenvector vl(i) or vr(i) is given by EPS * norm(abnrm, bbnrm) / DIF(i). For further explanation of the reciprocal condition numbers rconde and rcondv, see section 4.11 of LAPACK User's Guide. Arguments ========= balanc: Specifies the balance option to be performed. = 0: do not diagonally scale or permute; = 1: permute only; = 2: scale only; = 3: both permute and scale. Computed reciprocal condition numbers will be for the matrices after permuting and/or balancing. Permuting does not change condition numbers (in exact arithmetic), but balancing does. jobvl: = 0: do not compute the left generalized eigenvectors; = 1: compute the left generalized eigenvectors. jobvr: = 0: do not compute the right generalized eigenvectors; = 1: compute the right generalized eigenvectors. sense: Determines which reciprocal condition numbers are computed. = 0: none are computed; = 1: computed for eigenvalues only; = 2: computed for eigenvectors only; = 3: computed for eigenvalues and eigenvectors. A: On entry, the matrix A in the pair (A,B). On exit, A has been overwritten. If jobvl=1 or jobvr=1 or both, then A contains the first part of the real Schur form of the "balanced" versions of the input A and B. B: On entry, the matrix B in the pair (A,B). On exit, B has been overwritten. If jobvl=1 or jobvr=1 or both, then B contains the second part of the real Schur form of the "balanced" versions of the input A and B. alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio ALPHA/beta. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). vl: If jobvl = 1, the left eigenvectors u(j) are stored one after another in the columns of vl, in the same order as their eigenvalues. If the j-th eigenvalue is real, then u(j) = vl(:,j), the j-th column of vl. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then u(j) = vl(:,j)+i*vl(:,j+1) and u(j+1) = vl(:,j)-i*vl(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part) + abs(imag. part) = 1. Not referenced if jobvl = 0. vr: If jobvr = 1, the right eigenvectors v(j) are stored one after another in the columns of vr, in the same order as their eigenvalues. If the j-th eigenvalue is real, then v(j) = vr(:,j), the j-th column of vr. If the j-th and (j+1)-th eigenvalues form a complex conjugate pair, then v(j) = vr(:,j)+i*vr(:,j+1) and v(j+1) = vr(:,j)-i*vr(:,j+1). Each eigenvector will be scaled so the largest component have abs(real part) + abs(imag. part) = 1. Not referenced if jobvr = 0. ilo,ihi:ilo and ihi are integer values such that on exit A(i,j) = 0 and B(i,j) = 0 if i > j and j = 1,...,ilo-1 or i = ihi+1,...,N. If balanc = 0 or 2, ilo = 1 and ihi = N. lscale: Details of the permutations and scaling factors applied to the left side of A and B. If PL(j) is the index of the row interchanged with row j, and DL(j) is the scaling factor applied to row j, then lscale(j) = PL(j) for j = 1,...,ilo-1 = DL(j) for j = ilo,...,ihi = PL(j) for j = ihi+1,...,N. The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. rscale: Details of the permutations and scaling factors applied to the right side of A and B. If PR(j) is the index of the column interchanged with column j, and DR(j) is the scaling factor applied to column j, then rscale(j) = PR(j) for j = 1,...,ilo-1 = DR(j) for j = ilo,...,ihi = PR(j) for j = ihi+1,...,N The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. abnrm: The one-norm of the balanced matrix A. bbnrm: The one-norm of the balanced matrix B. rconde: If sense = 1 or 3, the reciprocal condition numbers of the selected eigenvalues, stored in consecutive elements of the array. For a complex conjugate pair of eigenvalues two consecutive elements of rconde are set to the same value. Thus rconde(j), rcondv(j), and the j-th columns of vl and vr all correspond to the same eigenpair (but not in general the j-th eigenpair, unless all eigenpairs are selected). If sense = 2, rconde is not referenced. rcondv: If sense = 2 or 3, the estimated reciprocal condition numbers of the selected eigenvectors, stored in consecutive elements of the array. For a complex eigenvector two consecutive elements of rcondv are set to the same value. If the eigenvalues cannot be reordered to compute rcondv(j), rcondv(j) is set to 0; this can only occur when the true value would be very small anyway. If sense = 1, rcondv is not referenced. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. No eigenvectors have been calculated, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: error return from tgevc. =for example $a = random(5,5); $b = random(5,5); $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vl = zeroes(5,5); $vr = zeroes(5,5); $lscale = zeroes(5); $rscale = zeroes(5); $ilo = null; $ihi = null; $abnrm = null; $bbnrm = null; $rconde = zeroes(5); $rcondv = zeroes(5); ggevx($a, 3, 1, 1, 3, $b, $alphar, $alphai, $beta, $vl, $vr, $ilo, $ihi, $lscale, $rscale, $abnrm, $bbnrm, $rconde,$rcondv,($info=null)); =for bad ggevx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ggevx = \&PDL::ggevx; =head2 gees =for sig Signature: ([io]A(n,n); int jobvs(); int sort(); [o]wr(n); [o]wi(n); [o]vs(p,p); int [o]sdim(); int [o]info(); int [t]bwork(bworkn); SV* select_func) =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues, the real Schur form T, and, optionally, the matrix of Schur vectors Z. This gives the Schur factorization A = Z*T*Z'. Optionally, it also orders the eigenvalues on the diagonal of the real Schur form so that selected eigenvalues are at the top left. The leading columns of Z then form an orthonormal basis for the invariant subspace corresponding to the selected eigenvalues. A matrix is in real Schur form if it is upper quasi-triangular with 1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the form [ a b ] [ c a ] where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). Arguments ========= jobvs: = 0: Schur vectors are not computed; = 1: Schur vectors are computed. sort: Specifies whether or not to order the eigenvalues on the diagonal of the Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see select_func). select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An eigenvalue wr(j)+sqrt(-1)*wi(j) is selected if select_func(SCALAR(wr(j)), SCALAR(wi(j))) is true; i.e., if either one of a complex conjugate pair of eigenvalues is selected, then both complex eigenvalues are selected. Note that a selected complex eigenvalue may no longer satisfy select_func(wr(j),wi(j)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2 (see info below). A: The N-by-N matrix A. On exit, A has been overwritten by its real Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which select_func is true. (Complex conjugate pairs for which select_func is true for either eigenvalue count as 2.) wr: wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues in the same order that they appear on the diagonal of the output Schur form T. Complex conjugate pairs of eigenvalues will appear consecutively with the eigenvalue having the positive imaginary part first. vs: If jobvs = 1, vs contains the orthogonal matrix Z of Schur vectors else vs is not referenced. info = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, and i is <= N: the QR algorithm failed to compute all the eigenvalues; elements 1:ILO-1 and i+1:N of wr and wi contain those eigenvalues which have converged; if jobvs = 1, vs contains the matrix which reduces A to its partially converged Schur form. = N+1: the eigenvalues could not be reordered because some eigenvalues were too close to separate (the problem is very ill-conditioned); = N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Schur form no longer satisfy select_func = 1 This could also be caused by underflow due to scaling. =for example sub select_function{ my ($a, $b ) = @_; # Stable "continuous time" eigenspace return $a < 0 ? 1 : 0; } $A = random (5,5); $wr= zeroes(5); $wi = zeroes(5); $vs = zeroes(5,5); $sdim = null; $info = null; gees($A, 1,1, $wr, $wi, $vs, $sdim, $info,\&select_function); =for bad gees ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gees = \&PDL::gees; =head2 geesx =for sig Signature: ([io]A(n,n); int jobvs(); int sort(); int sense(); [o]wr(n); [o]wi(n); [o]vs(p,p); int [o]sdim(); [o]rconde();[o]rcondv(); int [o]info(); int [t]bwork(bworkn); SV* select_func) =for ref Computes for an N-by-N real nonsymmetric matrix A, the eigenvalues, the real Schur form T, and, optionally, the matrix of Schur vectors Z. This gives the Schur factorization A = Z*T*Z'. Optionally, it also orders the eigenvalues on the diagonal of the real Schur form so that selected eigenvalues are at the top left; computes a reciprocal condition number for the average of the selected eigenvalues (rconde); and computes a reciprocal condition number for the right invariant subspace corresponding to the selected eigenvalues (rcondv). The leading columns of Z form an orthonormal basis for this invariant subspace. For further explanation of the reciprocal condition numbers rconde and rcondv, see Section 4.10 of the LAPACK Users' Guide (where these quantities are called s and sep respectively). A real matrix is in real Schur form if it is upper quasi-triangular with 1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the form [ a b ] [ c a ] where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). Arguments ========= jobvs: = 0: Schur vectors are not computed; = 1: Schur vectors are computed. sort: Specifies whether or not to order the eigenvalues on the diagonal of the Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see select_func). select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form else select_func is not referenced. An eigenvalue wr(j)+sqrt(-1)*wi(j) is selected if select_func(wr(j),wi(j)) is true; i.e., if either one of a complex conjugate pair of eigenvalues is selected, then both are. Note that a selected complex eigenvalue may no longer satisfy select_func(wr(j),wi(j)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info may be set to N+3 (see info below). sense: Determines which reciprocal condition numbers are computed. = 0: None are computed; = 1: Computed for average of selected eigenvalues only; = 2: Computed for selected right invariant subspace only; = 3: Computed for both. If sense = 1, 2 or 3, sort must equal 1. A: On entry, the N-by-N matrix A. On exit, A is overwritten by its real Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which select_func is 1. (Complex conjugate pairs for which select_func is 1 for either eigenvalue count as 2.) wr: wi: wr and wi contain the real and imaginary parts, respectively, of the computed eigenvalues, in the same order that they appear on the diagonal of the output Schur form T. Complex conjugate pairs of eigenvalues appear consecutively with the eigenvalue having the positive imaginary part first. vs If jobvs = 1, vs contains the orthogonal matrix Z of Schur vectors else vs is not referenced. rconde: If sense = 1 or 3, rconde contains the reciprocal condition number for the average of the selected eigenvalues. Not referenced if sense = 0 or 2. rcondv: If sense = 2 or 3, rcondv contains the reciprocal condition number for the selected right invariant subspace. Not referenced if sense = 0 or 1. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: if info = i, and i is <= N: the QR algorithm failed to compute all the eigenvalues; elements 1:ilo-1 and i+1:N of wr and wi contain those eigenvalues which have converged; if jobvs = 1, vs contains the transformation which reduces A to its partially converged Schur form. = N+1: the eigenvalues could not be reordered because some eigenvalues were too close to separate (the problem is very ill-conditioned); = N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Schur form no longer satisfy select_func=1 This could also be caused by underflow due to scaling. =for example sub select_function{ my ($a, $b) = @_; # Stable "discrete time" eigenspace return sqrt($a**2 + $b**2) < 1 ? 1 : 0; } $A = random (5,5); $wr= zeroes(5); $wi = zeroes(5); $vs = zeroes(5,5); $sdim = null; $rconde = null; $rcondv = null; $info = null; geesx($A, 1,1, 3, $wr, $wi, $vs, $sdim, $rconde, $rcondv, $info, \&select_function); =for bad geesx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geesx = \&PDL::geesx; =head2 gges =for sig Signature: ([io]A(n,n); int jobvsl();int jobvsr();int sort();[io]B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VSL(m,m);[o]VSR(p,p);int [o]sdim();int [o]info(); int [t]bwork(bworkn); SV* select_func) =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B), the generalized eigenvalues, the generalized real Schur form (S,T), optionally, the left and/or right matrices of Schur vectors (VSL and VSR). This gives the generalized Schur factorization (A,B) = ( (VSL)*S*(VSR)', (VSL)*T*(VSR)' ) Optionally, it also orders the eigenvalues so that a selected cluster of eigenvalues appears in the leading diagonal blocks of the upper quasi-triangular matrix S and the upper triangular matrix T.The leading columns of VSL and VSR then form an orthonormal basis for the corresponding left and right eigenspaces (deflating subspaces). (If only the generalized eigenvalues are needed, use the driver ggev instead, which is faster.) A generalized eigenvalue for a pair of matrices (A,B) is a scalar w or a ratio alpha/beta = w, such that A - w*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0 or both being zero. A pair of matrices (S,T) is in generalized real Schur form if T is upper triangular with non-negative diagonal and S is block upper triangular with 1-by-1 and 2-by-2 blocks. 1-by-1 blocks correspond to real generalized eigenvalues, while 2-by-2 blocks of S will be "standardized" by making the corresponding elements of T have the form: [ a 0 ] [ 0 b ] and the pair of corresponding 2-by-2 blocks in S and T will have a complex conjugate pair of generalized eigenvalues. Arguments ========= jobvsl: = 0: do not compute the left Schur vectors; = 1: compute the left Schur vectors. jobvsr: = 0: do not compute the right Schur vectors; = 1: compute the right Schur vectors. sort: Specifies whether or not to order the eigenvalues on the diagonal of the generalized Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see delztg); delztg: If sort = 0, delztg is not referenced. If sort = 1, delztg is used to select eigenvalues to sort to the top left of the Schur form. An eigenvalue (alphar(j)+alphai(j))/beta(j) is selected if delztg(alphar(j),alphai(j),beta(j)) is true; i.e. if either one of a complex conjugate pair of eigenvalues is selected, then both complex eigenvalues are selected. Note that in the ill-conditioned case, a selected complex eigenvalue may no longer satisfy delztg(alphar(j),alphai(j), beta(j)) = 1 after ordering. info is to be set to N+2 in this case. A: On entry, the first of the pair of matrices. On exit, A has been overwritten by its generalized Schur form S. B: On entry, the second of the pair of matrices. On exit, B has been overwritten by its generalized Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which delztg is true. (Complex conjugate pairs for which delztg is true for either eigenvalue count as 2.) alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. alphar(j) + alphai(j)*i, and beta(j),j=1,...,N are the diagonals of the complex Schur form (S,T) that would result if the 2-by-2 diagonal blocks of the real Schur form of (A,B) were further reduced to triangular form using 2-by-2 complex unitary transformations. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). VSL: If jobvsl = 1, VSL will contain the left Schur vectors. Not referenced if jobvsl = 0. The leading dimension must always be >=1. VSR: If jobvsr = 1, VSR will contain the right Schur vectors. Not referenced if jobvsr = 0. The leading dimension must always be >=1. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. (A,B) are not in Schur form, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Generalized Schur form no longer satisfy delztg=1 This could also be caused due to scaling. =N+3: reordering failed in tgsen. =for example sub my_select{ my ($zr, $zi, $d) = @_; # stable generalized eigenvalues for continuous time return ( ($zr < 0 && $d > 0 ) || ($zr > 0 && $d < 0) ) ? 1 : 0; } $a = random(5,5); $b = random(5,5); $sdim = null; $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vsl = zeroes(5,5); $vsr = zeroes(5,5); gges($a, 1, 1, 1, $b, $alphar, $alphai, $beta, $vsl, $vsr, $sdim,($info=null), \&my_select); =for bad gges ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gges = \&PDL::gges; =head2 ggesx =for sig Signature: ([io]A(n,n); int jobvsl();int jobvsr();int sort();int sense();[io]B(n,n);[o]alphar(n);[o]alphai(n);[o]beta(n);[o]VSL(m,m);[o]VSR(p,p);int [o]sdim();[o]rconde(q=2);[o]rcondv(q=2);int [o]info(); int [t]bwork(bworkn); int [t]iwork(iworkn); SV* select_func) =for ref Computes for a pair of N-by-N real nonsymmetric matrices (A,B), the generalized eigenvalues, the real Schur form (S,T), and, optionally, the left and/or right matrices of Schur vectors (VSL and VSR). This gives the generalized Schur factorization (A,B) = ( (VSL) S (VSR)', (VSL) T (VSR)' ) Optionally, it also orders the eigenvalues so that a selected cluster of eigenvalues appears in the leading diagonal blocks of the upper quasi-triangular matrix S and the upper triangular matrix T; computes a reciprocal condition number for the average of the selected eigenvalues (RCONDE); and computes a reciprocal condition number for the right and left deflating subspaces corresponding to the selected eigenvalues (RCONDV). The leading columns of VSL and VSR then form an orthonormal basis for the corresponding left and right eigenspaces (deflating subspaces). A generalized eigenvalue for a pair of matrices (A,B) is a scalar w or a ratio alpha/beta = w, such that A - w*B is singular. It is usually represented as the pair (alpha,beta), as there is a reasonable interpretation for beta=0 or for both being zero. A pair of matrices (S,T) is in generalized real Schur form if T is upper triangular with non-negative diagonal and S is block upper triangular with 1-by-1 and 2-by-2 blocks. 1-by-1 blocks correspond to real generalized eigenvalues, while 2-by-2 blocks of S will be "standardized" by making the corresponding elements of T have the form: [ a 0 ] [ 0 b ] and the pair of corresponding 2-by-2 blocks in S and T will have a complex conjugate pair of generalized eigenvalues. Further details =============== An approximate (asymptotic) bound on the average absolute error of the selected eigenvalues is EPS * norm((A, B)) / RCONDE( 1 ). An approximate (asymptotic) bound on the maximum angular error in the computed deflating subspaces is EPS * norm((A, B)) / RCONDV( 2 ). See LAPACK User's Guide, section 4.11 for more information. Arguments ========= jobvsl: = 0: do not compute the left Schur vectors; = 1: compute the left Schur vectors. jobvsr: = 0: do not compute the right Schur vectors; = 1: compute the right Schur vectors. sort: Specifies whether or not to order the eigenvalues on the diagonal of the generalized Schur form. = 0: Eigenvalues are not ordered; = 1: Eigenvalues are ordered (see delztg); delztg: If sort = 0, delztg is not referenced. If sort = 1, delztg is used to select eigenvalues to sort to the top left of the Schur form. An eigenvalue (alphar(j)+alphai(j))/beta(j) is selected if delztg(alphar(j),alphai(j),beta(j)) is true; i.e. if either one of a complex conjugate pair of eigenvalues is selected, then both complex eigenvalues are selected. Note that in the ill-conditioned case, a selected complex eigenvalue may no longer satisfy delztg(alphar(j),alphai(j), beta(j)) = 1 after ordering. info is to be set to N+2 in this case. sense: Determines which reciprocal condition numbers are computed. = 0 : None are computed; = 1 : Computed for average of selected eigenvalues only; = 2 : Computed for selected deflating subspaces only; = 3 : Computed for both. If sense = 1, 2, or 3, sort must equal 1. A: On entry, the first of the pair of matrices. On exit, A has been overwritten by its generalized Schur form S. B: On entry, the second of the pair of matrices. On exit, B has been overwritten by its generalized Schur form T. sdim: If sort = 0, sdim = 0. If sort = 1, sdim = number of eigenvalues (after sorting) for which delztg is true. (Complex conjugate pairs for which delztg is true for either eigenvalue count as 2.) alphar: alphai: beta: On exit, (alphar(j) + alphai(j)*i)/beta(j), j=1,...,N, will be the generalized eigenvalues. alphar(j) + alphai(j)*i, and beta(j),j=1,...,N are the diagonals of the complex Schur form (S,T) that would result if the 2-by-2 diagonal blocks of the real Schur form of (A,B) were further reduced to triangular form using 2-by-2 complex unitary transformations. If alphai(j) is zero, then the j-th eigenvalue is real; if positive, then the j-th and (j+1)-st eigenvalues are a complex conjugate pair, with alphai(j+1) negative. Note: the quotients alphar(j)/beta(j) and alphai(j)/beta(j) may easily over- or underflow, and beta(j) may even be zero. Thus, the user should avoid naively computing the ratio. However, alphar and alphai will be always less than and usually comparable with norm(A) in magnitude, and beta always less than and usually comparable with norm(B). VSL: If jobvsl = 1, VSL will contain the left Schur vectors. Not referenced if jobvsl = 0. The leading dimension must always be >=1. VSR: If jobvsr = 1, VSR will contain the right Schur vectors. Not referenced if jobvsr = 0. The leading dimension must always be >=1. rconde: If sense = 1 or 3, rconde(1) and rconde(2) contain the reciprocal condition numbers for the average of the selected eigenvalues. Not referenced if sense = 0 or 2. rcondv: If sense = 2 or 3, rcondv(1) and rcondv(2) contain the reciprocal condition numbers for the selected deflating subspaces. Not referenced if sense = 0 or 1. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. = 1,...,N: The QZ iteration failed. (A,B) are not in Schur form, but alphar(j), alphai(j), and beta(j) should be correct for j=info+1,...,N. > N: =N+1: other than QZ iteration failed in hgeqz. =N+2: after reordering, roundoff changed values of some complex eigenvalues so that leading eigenvalues in the Generalized Schur form no longer satisfy delztg=1 This could also be caused due to scaling. =N+3: reordering failed in tgsen. =for example sub my_select{ my ($zr, $zi, $d) = @_; # Eigenvalue : (ZR/D) + sqrt(-1)*(ZI/D) # stable generalized eigenvalues for discrete time return (sqrt($zr**2 + $zi**2) < abs($d) ) ? 1 : 0; } $a = random(5,5); $b = random(5,5); $sdim = null; $alphar = zeroes(5); $alphai = zeroes(5); $beta = zeroes(5); $vsl = zeroes(5,5); $vsr = zeroes(5,5); $rconde = zeroes(2); $rcondv = zeroes(2); ggesx($a, 1, 1, 1, 3,$b, $alphar, $alphai, $beta, $vsl, $vsr, $sdim, $rconde, $rcondv, ($info=null), \&my_select); =for bad ggesx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ggesx = \&PDL::ggesx; =head2 syev =for sig Signature: ([io,phys]A(n,n); int jobz(); int uplo(); [o,phys]w(n); int [o,phys]info()) =for ref Computes all eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the orthonormal eigenvectors of the matrix A. If jobz = 0, then on exit the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. w: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the algorithm failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero. =for example # Assume $a is symmetric ;) $a = random (5,5); syev($a, 1,1, (my $w = zeroes(5)), (my $info=null)); =for bad syev ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *syev = \&PDL::syev; =head2 syevd =for sig Signature: ([io,phys]A(n,n); int jobz(); int uplo(); [o,phys]w(n); int [o,phys]info()) =for ref Computes all eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. If eigenvectors are desired, it uses a divide and conquer algorithm. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Because of large use of BLAS of level 3, syevd needs N**2 more workspace than syevx. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the orthonormal eigenvectors of the matrix A. If jobz = 0, then on exit the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. w: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the algorithm failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero. =for example # Assume $a is symmetric ;) $a = random (5,5); syevd($a, 1,1, (my $w = zeroes(5)), (my $info=null)); =for bad syevd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *syevd = \&PDL::syevd; =head2 syevx =for sig Signature: (A(n,n); int jobz(); int range(); int uplo(); vl(); vu(); int il(); int iu(); abstol(); int [o]m(); [o]w(n); [o]z(p,p);int [o]ifail(n); int [o]info(); int [t]iwork(iworkn)) =for ref Computes selected eigenvalues and, optionally, eigenvectors of a real symmetric matrix A. Eigenvalues and eigenvectors can be selected by specifying either a range of values or a range of indices for the desired eigenvalues. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. range: = 0: all eigenvalues will be found. = 1: all eigenvalues in the half-open interval (vl,vu] will be found. = 1: the il-th through iu-th eigenvalues will be found. uplo = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. vl: vu: If range=1, the lower and upper bounds of the interval to be searched for eigenvalues. vl < vu. Not referenced if range = 0 or 2. il: iu: If range=2, the indices (in ascending order) of the smallest and largest eigenvalues to be returned. 1 <= il <= iu <= N, if N > 0; il = 1 and iu = 0 if N = 0. Not referenced if range = 0 or 1. abstol: The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when it is determined to lie in an interval [a,b] of width less than or equal to abstol + EPS * max( |a|,|b| ) , where EPS is the machine precision. If abstol is less than or equal to zero, then EPS*|T| will be used in its place, where |T| is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form. Eigenvalues will be computed most accurately when abstol is set to twice the underflow threshold 2*lamch(1), not zero. If this routine returns with info>0, indicating that some eigenvectors did not converge, try setting abstol to 2*lamch(1). See "Computing Small Singular Values of Bidiagonal Matrices with Guaranteed High Relative Accuracy," by Demmel and Kahan, LAPACK Working Note #3. m: The total number of eigenvalues found. 0 <= m <= N. If range = 0, m = N, and if range = 2, m = iu-il+1. w: On normal exit, the first M elements contain the selected eigenvalues in ascending order. z: If jobz = 1, then if info = 0, the first m columns of z contain the orthonormal eigenvectors of the matrix A corresponding to the selected eigenvalues, with the i-th column of z holding the eigenvector associated with w(i). If an eigenvector fails to converge, then that column of z contains the latest approximation to the eigenvector, and the index of the eigenvector is returned in ifail. If jobz = 0, then z is not referenced. Note: the user must ensure that at least max(1,m) columns are supplied in the array z; if range = 1, the exact value of m is not known in advance and an upper bound must be used. ifail: If jobz = 1, then if info = 0, the first m elements of ifail are zero. If info > 0, then ifail contains the indices of the eigenvectors that failed to converge. If jobz = 0, then ifail is not referenced. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, then i eigenvectors failed to converge. Their indices are stored in array ifail. =for example # Assume $a is symmetric ;) $a = random (5,5); $unfl = lamch(1); $ovfl = lamch(9); labad($unfl, $ovfl); $abstol = $unfl + $unfl; $m = null; $info = null; $ifail = zeroes(5); $w = zeroes(5); $z = zeroes(5,5); syevx($a, 1,0,1,0,0,0,0,$abstol, $m, $w, $z ,$ifail, $info); =for bad syevx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *syevx = \&PDL::syevx; =head2 syevr =for sig Signature: ([phys]A(n,n); int jobz(); int range(); int uplo(); [phys]vl(); [phys]vu(); int [phys]il(); int [phys]iu();[phys]abstol();int [o,phys]m();[o,phys]w(n); [o,phys]z(p,q);int [o,phys]isuppz(r); int [o,phys]info()) =for ref Computes selected eigenvalues and, optionally, eigenvectors of a real symmetric matrix T. Eigenvalues and eigenvectors can be selected by specifying either a range of values or a range of indices for the desired eigenvalues. Whenever possible, syevr calls stegr to compute the eigenspectrum using Relatively Robust Representations. stegr computes eigenvalues by the dqds algorithm, while orthogonal eigenvectors are computed from various "good" L D L^T representations (also known as Relatively Robust Representations). Gram-Schmidt orthogonalization is avoided as far as possible. More specifically, the various steps of the algorithm are as follows. For the i-th unreduced block of T, (a) Compute T - sigma_i = L_i D_i L_i^T, such that L_i D_i L_i^T is a relatively robust representation, (b) Compute the eigenvalues, lambda_j, of L_i D_i L_i^T to high relative accuracy by the dqds algorithm, (c) If there is a cluster of close eigenvalues, "choose" sigma_i close to the cluster, and go to step (a), (d) Given the approximate eigenvalue lambda_j of L_i D_i L_i^T, compute the corresponding eigenvector by forming a rank-revealing twisted factorization. The desired accuracy of the output can be specified by the input parameter abstol. For more details, see "A new O(n^2) algorithm for the symmetric tridiagonal eigenvalue/eigenvector problem", by Inderjit Dhillon, Computer Science Division Technical Report No. UCB//CSD-97-971, UC Berkeley, May 1997. Note 1 : syevr calls stegr when the full spectrum is requested on machines which conform to the ieee-754 floating point standard. syevr calls stebz and stein on non-ieee machines and when partial spectrum requests are made. Normal execution of stegr may create NaNs and infinities and hence may abort due to a floating point exception in environments which do not handle NaNs and infinities in the ieee standard default manner. Arguments ========= jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. range: = 0: all eigenvalues will be found. = 1: all eigenvalues in the half-open interval (vl,vu] will be found. = 2: the il-th through iu-th eigenvalues will be found. ********* For range = 1 or 2 and iu - il < N - 1, stebz and ********* stein are called uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. vl: vu: If range=1, the lower and upper bounds of the interval to be searched for eigenvalues. vl < vu. Not referenced if range = 0 or 2. il: iu: If range=2, the indices (in ascending order) of the smallest and largest eigenvalues to be returned. 1 <= il <= iu <= N, if N > 0; il = 1 and iu = 0 if N = 0. Not referenced if range = 0 or 1. abstol: The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when it is determined to lie in an interval [a,b] of width less than or equal to abstol + EPS * max( |a|,|b| ) , where EPS is the machine precision. If abstol is less than or equal to zero, then EPS*|T| will be used in its place, where |T| is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form. See "Computing Small Singular Values of Bidiagonal Matrices with Guaranteed High Relative Accuracy," by Demmel and Kahan, LAPACK Working Note #3. If high relative accuracy is important, set abstol to lamch(1). Doing so will guarantee that eigenvalues are computed to high relative accuracy when possible in future releases. The current code does not make any guarantees about high relative accuracy, but future releases will. See J. Barlow and J. Demmel, "Computing Accurate Eigensystems of Scaled Diagonally Dominant Matrices", LAPACK Working Note #7, for a discussion of which matrices define their eigenvalues to high relative accuracy. m: The total number of eigenvalues found. 0 <= m <= N. If range = 0, m = N, and if range = 2, m = iu-il+1. w: The first m elements contain the selected eigenvalues in ascending order. z: If jobz = 1, then if info = 0, the first m columns of z contain the orthonormal eigenvectors of the matrix A corresponding to the selected eigenvalues, with the i-th column of z holding the eigenvector associated with w(i). If jobz = 0, then z is not referenced. Note: the user must ensure that at least max(1,m) columns are supplied in the array z; if range = 1, the exact value of m is not known in advance and an upper bound must be used. isuppz: array of int, dimension ( 2*max(1,m) ) The support of the eigenvectors in z, i.e., the indices indicating the nonzero elements in z. The i-th eigenvector is nonzero only in elements isuppz( 2*i-1 ) through isuppz( 2*i ). ********* Implemented only for range = 0 or 2 and iu - il = N - 1 info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: Internal error =for example # Assume $a is symmetric ;) $a = random (5,5); $unfl = lamch(1); $ovfl = lamch(9); labad($unfl, $ovfl); $abstol = $unfl + $unfl; $m = null; $info = null; $isuppz = zeroes(10); $w = zeroes(5); $z = zeroes(5,5); syevr($a, 1,0,1,0,0,0,0,$abstol, $m, $w, $z ,$isuppz, $info); =for bad syevr ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *syevr = \&PDL::syevr; =head2 sygv =for sig Signature: ([io,phys]A(n,n);int [phys]itype();int jobz(); int uplo();[io,phys]B(n,n);[o,phys]w(n); int [o,phys]info()) =for ref Computes all the eigenvalues, and optionally, the eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric and B is also positive definite. Arguments ========= itype: Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo: = 0: Upper triangles of A and B are stored; = 1: Lower triangles of A and B are stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the matrix Z of eigenvectors. The eigenvectors are normalized as follows: if itype = 1 or 2, Z'*B*Z = I; if itype = 3, Z'*inv(B)*Z = I. If jobz = 0, then on exit the upper triangle (if uplo=0) or the lower triangle (if uplo=1) of A, including the diagonal, is destroyed. B: On entry, the symmetric positive definite matrix B. If uplo = 0, the leading N-by-N upper triangular part of B contains the upper triangular part of the matrix B. If uplo = 1, the leading N-by-N lower triangular part of B contains the lower triangular part of the matrix B. On exit, if info <= N, the part of B containing the matrix is overwritten by the triangular factor U or L from the Cholesky factorization B = U'*U or B = L*L'. W: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: potrf or syev returned an error code: <= N: if info = i, syev failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero; > N: if info = N + i, for 1 <= i <= N, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. =for example # Assume $a is symmetric ;) $a = random (5,5); # Assume $a is symmetric and positive definite ;) $b = random (5,5); sygv($a, 1,1, 0, $b, (my $w = zeroes(5)), (my $info=null)); =for bad sygv ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sygv = \&PDL::sygv; =head2 sygvd =for sig Signature: ([io,phys]A(n,n);int [phys]itype();int jobz(); int uplo();[io,phys]B(n,n);[o,phys]w(n); int [o,phys]info()) =for ref Computes all the eigenvalues, and optionally, the eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric and B is also positive definite. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Arguments ========= itype: Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. uplo: = 0: Upper triangles of A and B are stored; = 1: Lower triangles of A and B are stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, if jobz = 1, then if info = 0, A contains the matrix Z of eigenvectors. The eigenvectors are normalized as follows: if itype = 1 or 2, Z'*B*Z = I; if itype = 3, Z'*inv(B)*Z = I. If jobz = 0, then on exit the upper triangle (if uplo=0) or the lower triangle (if uplo=1) of A, including the diagonal, is destroyed. B: On entry, the symmetric positive definite matrix B. If uplo = 0, the leading N-by-N upper triangular part of B contains the upper triangular part of the matrix B. If uplo = 1, the leading N-by-N lower triangular part of B contains the lower triangular part of the matrix B. On exit, if info <= N, the part of B containing the matrix is overwritten by the triangular factor U or L from the Cholesky factorization B = U'*U or B = L*L'. W: If info = 0, the eigenvalues in ascending order. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: potrf or syev returned an error code: <= N: if info = i, syevd failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero; > N: if info = N + i, for 1 <= i <= N, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. =for example # Assume $a is symmetric ;) $a = random (5,5); # Assume $b is symmetric positive definite ;) $b = random (5,5); sygvd($a, 1,1, 0, $b, (my $w = zeroes(5)), (my $info=null)); =for bad sygvd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sygvd = \&PDL::sygvd; =head2 sygvx =for sig Signature: ([io]A(n,n); int itype(); int jobz(); int range(); int uplo(); [io]B(n,n); vl(); vu(); int il(); int iu(); abstol(); int [o]m(); [o]w(n); [o]Z(p,p); int [o]ifail(n); int [o]info(); int [t]iwork(iworkn); ) =for ref Computes selected eigenvalues, and optionally, eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric and B is also positive definite. Eigenvalues and eigenvectors can be selected by specifying either a range of values or a range of indices for the desired eigenvalues. Arguments ========= itype: Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x jobz: = 0: Compute eigenvalues only; = 1: Compute eigenvalues and eigenvectors. range: = 0: all eigenvalues will be found. = 1: all eigenvalues in the half-open interval (vl,vu] will be found. = 2: the il-th through iu-th eigenvalues will be found. uplo: = 0: Upper triangle of A and B are stored; = 1: Lower triangle of A and B are stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A. On exit, the lower triangle (if uplo=1) or the upper triangle (if uplo=0) of A, including the diagonal, is destroyed. B: On entry, the symmetric matrix B. If uplo = 0, the leading N-by-N upper triangular part of B contains the upper triangular part of the matrix B. If uplo = 1, the leading N-by-N lower triangular part of B contains the lower triangular part of the matrix B. On exit, if info <= N, the part of B containing the matrix is overwritten by the triangular factor U or L from the Cholesky factorization B = U'*U or B = L*L'. vl: vu: If range=1, the lower and upper bounds of the interval to be searched for eigenvalues. vl < vu. Not referenced if range = 0 or 2. il: iu: If range=2, the indices (in ascending order) of the smallest and largest eigenvalues to be returned. 1 <= il <= iu <= N, if N > 0; il = 1 and iu = 0 if N = 0. Not referenced if range = 0 or 1. abstol: The absolute error tolerance for the eigenvalues. An approximate eigenvalue is accepted as converged when it is determined to lie in an interval [a,b] of width less than or equal to abstol + EPS * max( |a|,|b| ) , where EPS is the machine precision. If abstol is less than or equal to zero, then EPS*|T| will be used in its place, where |T| is the 1-norm of the tridiagonal matrix obtained by reducing A to tridiagonal form. Eigenvalues will be computed most accurately when abstol is set to twice the underflow threshold 2*lamch(1), not zero. If this routine returns with info>0, indicating that some eigenvectors did not converge, try setting abstol to 2* lamch(1). m: The total number of eigenvalues found. 0 <= m <= N. If range = 0, m = N, and if range = 2, m = iu-il+1. w: On normal exit, the first m elements contain the selected eigenvalues in ascending order. Z: If jobz = 0, then Z is not referenced. If jobz = 1, then if info = 0, the first m columns of Z contain the orthonormal eigenvectors of the matrix A corresponding to the selected eigenvalues, with the i-th column of Z holding the eigenvector associated with w(i). The eigenvectors are normalized as follows: if itype = 1 or 2, Z'*B*Z = I; if itype = 3, Z'*inv(B)*Z = I. If an eigenvector fails to converge, then that column of Z contains the latest approximation to the eigenvector, and the index of the eigenvector is returned in ifail. Note: the user must ensure that at least max(1,m) columns are supplied in the array Z; if range = 1, the exact value of m is not known in advance and an upper bound must be used. ifail: If jobz = 1, then if info = 0, the first M elements of ifail are zero. If info > 0, then ifail contains the indices of the eigenvectors that failed to converge. If jobz = 0, then ifail is not referenced. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: potrf or syevx returned an error code: <= N: if info = i, syevx failed to converge; i eigenvectors failed to converge. Their indices are stored in array ifail. > N: if info = N + i, for 1 <= i <= N, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. =for example # Assume $a is symmetric ;) $a = random (5,5); # Assume $b is symmetric positive definite ;) $b = random (5,5); $unfl = lamch(1); $ovfl = lamch(9); labad($unfl, $ovfl); $abstol = $unfl + $unfl; $m = null; $w=zeroes(5); $z = zeroes(5,5); $ifail = zeroes(5); sygvx($a, 1,1, 0,0, $b, 0, 0, 0, 0, $abstol, $m, $w, $z,$ifail,(my $info=null)); =for bad sygvx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sygvx = \&PDL::sygvx; =head2 gesv =for sig Signature: ([io,phys]A(n,n); [io,phys]B(n,m); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Computes the solution to a real system of linear equations A * X = B, where A is an N-by-N matrix and X and B are N-by-NRHS matrices. The LU decomposition with partial pivoting and row interchanges is used to factor A as A = P * L * U, where P is a permutation matrix, L is unit lower triangular, and U is upper triangular. The factored form of A is then used to solve the system of equations A * X = B. Arguments ========= A: On entry, the N-by-N coefficient matrix A. On exit, the factors L and U from the factorization A = P*L*U; the unit diagonal elements of L are not stored. ipiv: The pivot indices that define the permutation matrix P; row i of the matrix was interchanged with row ipiv(i). B: On entry, the N-by-NRHS matrix of right hand side matrix B. On exit, if info = 0, the N-by-NRHS solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, so the solution could not be computed. =for example $a = random (5,5); $a = transpose($a); $b = random (5,5); $b = transpose($b); gesv($a,$b, (my $ipiv=zeroes(5)),(my $info=null)); print "The solution matrix X is :". transpose($b)."\n" unless $info; =for bad gesv ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gesv = \&PDL::gesv; =head2 gesvx =for sig Signature: ([io]A(n,n); int trans(); int fact(); [io]B(n,m); [io]af(n,n); int [io]ipiv(n); int [io]equed(); [o]r(p); [o]c(q); [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m);[o]rpvgrw();int [o]info(); [t]work(workn); int [t]iwork(n)) =for ref Uses the LU factorization to compute the solution to a real system of linear equations A * X = B, where A is an N-by-N matrix and X and B are N-by-NRHS matrices. Error bounds on the solution and a condition estimate are also provided. =for desc The following steps are performed: =over 3 =item 1 If fact = 2, real scaling factors are computed to equilibrate the system: trans = 0: diag(r)*A*diag(c) *inv(diag(c))*X = diag(c)*B trans = 1: (diag(r)*A*diag(c))' *inv(diag(r))*X = diag(c)*B trans = 2: (diag(r)*A*diag(c))**H *inv(diag(r))*X = diag(c)*B Whether or not the system will be equilibrated depends on the scaling of the matrix A, but if equilibration is used, A is overwritten by diag(r)*A*diag(c) and B by diag(r)*B (if trans=0) or diag(c)*B (if trans = 1 or 2). =item 2 If fact = 1 or 2, the LU decomposition is used to factor the matrix A (after equilibration if fact = 2) as A = P * L * U, where P is a permutation matrix, L is a unit lower triangular matrix, and U is upper triangular. =item 3 If some U(i,i)=0, so that U is exactly singular, then the routine returns with info = i. Otherwise, the factored form of A is used to estimate the condition number of the matrix A. If the reciprocal of the condition number is less than machine precision, info = N+1 is returned as a warning, but the routine still goes on to solve for X and compute error bounds as described below. =item 4 The system of equations is solved for X using the factored form of A. =item 5 Iterative refinement is applied to improve the computed solution matrix and calculate error bounds and backward error estimates for it. =item 6 If equilibration was used, the matrix X is premultiplied by diag(c) (if trans = 0) or diag(r) (if trans = 1 or 2) so that it solves the original system before equilibration. =back Arguments ========= fact: Specifies whether or not the factored form of the matrix A is supplied on entry, and if not, whether the matrix A should be equilibrated before it is factored. = 0: On entry, af and ipiv contain the factored form of A. If equed is not 0, the matrix A has been equilibrated with scaling factors given by r and c. A, af, and ipiv are not modified. = 1: The matrix A will be copied to af and factored. = 2: The matrix A will be equilibrated if necessary, then copied to af and factored. trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A' * X = B (Transpose) = 2: A**H * X = B (Transpose) A: On entry, the N-by-N matrix A. If fact = 0 and equed is not 0, then A must have been equilibrated by the scaling factors in r and/or c. A is not modified if fact = 0 or 1, or if fact = 2 and equed = 0 on exit. On exit, if equed != 0, A is scaled as follows: equed = 1: A := diag(r) * A equed = 2: A := A * diag(c) equed = 3: A := diag(r) * A * diag(c). af: If fact = 0, then af is an input argument and on entry contains the factors L and U from the factorization A = P*L*U as computed by getrf. If equed != 0, then af is the factored form of the equilibrated matrix A. If fact = 1, then af is an output argument and on exit returns the factors L and U from the factorization A = P*L*U of the original matrix A. If fact = 2, then af is an output argument and on exit returns the factors L and U from the factorization A = P*L*U of the equilibrated matrix A (see the description of A for the form of the equilibrated matrix). ipiv: If fact = 0, then ipiv is an input argument and on entry contains the pivot indices from the factorization A = P*L*U as computed by getrf; row i of the matrix was interchanged with row ipiv(i). If fact = 1, then ipiv is an output argument and on exit contains the pivot indices from the factorization A = P*L*U of the original matrix A. If fact = 2, then ipiv is an output argument and on exit contains the pivot indices from the factorization A = P*L*U of the equilibrated matrix A. equed: Specifies the form of equilibration that was done. = 0: No equilibration (always true if fact = 1). = 1: Row equilibration, i.e., A has been premultiplied by diag(r). = 2: Column equilibration, i.e., A has been postmultiplied by diag(c). = 3: Both row and column equilibration, i.e., A has been replaced by diag(r) * A * diag(c). equed is an input argument if fact = 0; otherwise, it is an output argument. r: The row scale factors for A. If equed = 1 or 3, A is multiplied on the left by diag(r); if equed = 0 or 2, r is not accessed. r is an input argument if fact = 0; otherwise, r is an output argument. If fact = 0 and equed = 1 or 3, each element of r must be positive. c: The column scale factors for A. If equed = 2 or 3, A is multiplied on the right by diag(c); if equed = 0 or 1, c is not accessed. c is an input argument if fact = 0; otherwise, c is an output argument. If fact = 0 and equed = 2 or 3, each element of c must be positive. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if equed = 0, B is not modified; if trans = 0 and equed = 1 or 3, B is overwritten by diag(r)*B; if trans = 1 or 2 and equed = 2 or 3, B is overwritten by diag(c)*B. X: If info = 0 or info = N+1, the N-by-NRHS solution matrix X to the original system of equations. Note that A and B are modified on exit if equed != 0, and the solution to the equilibrated system is inv(diag(c))*X if trans = 0 and equed = 2 or 3, or inv(diag(r))*X if trans = 1 or 2 and equed = 1 or 3. rcond: The estimate of the reciprocal condition number of the matrix A after equilibration (if done). If rcond is less than the machine precision (in particular, if rcond = 0), the matrix is singular to working precision. This condition is indicated by a return code of info > 0. ferr: The estimated forward error bound for each solution vector X(j) (the j-th column of the solution matrix X). If XTRUE is the true solution corresponding to X(j), ferr(j) is an estimated upper bound for the magnitude of the largest element in (X(j) - XTRUE) divided by the magnitude of the largest element in X(j). The estimate is as reliable as the estimate for rcond, and is almost always a slight overestimate of the true error. berr: The componentwise relative backward error of each solution vector X(j) (i.e., the smallest relative change in any element of A or B that makes X(j) an exact solution). rpvgrw: Contains the reciprocal pivot growth factor norm(A)/norm(U). The "max absolute element" norm is used. If it is much less than 1, then the stability of the LU factorization of the (equilibrated) matrix A could be poor. This also means that the solution X, condition estimator rcond, and forward error bound ferr could be unreliable. If factorization fails with 0 0: if info = i, and i is <= N: U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, so the solution and error bounds could not be computed. rcond = 0 is returned. = N+1: U is nonsingular, but rcond is less than machine precision, meaning that the matrix is singular to working precision. Nevertheless, the solution and error bounds are computed because there are a number of situations where the computed solution can be more accurate than the value of rcond would suggest. =for example $a= random(5,5); $b = random(5,5); $a = transpose($a); $b = transpose($b); $rcond = pdl(0); $rpvgrw = pdl(0); $equed = pdl(long,0); $info = pdl(long,0); $berr = zeroes(5); $ipiv = zeroes(5); $ferr = zeroes(5); $r = zeroes(5); $c = zeroes(5); $X = zeroes(5,5); $af = zeroes(5,5); gesvx($a,0, 2, $b, $af, $ipiv, $equed, $r, $c, $X, $rcond, $ferr, $berr, $rpvgrw, $info); print "The solution matrix X is :". transpose($X)."\n" unless $info; =for bad gesvx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gesvx = \&PDL::gesvx; =head2 sysv =for sig Signature: ([io,phys]A(n,n); int uplo(); [io,phys]B(n,m); int [o]ipiv(n); int [o]info()) =for ref Computes the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric matrix and X and B are N-by-NRHS matrices. The diagonal pivoting method is used to factor A as A = U * D * U', if uplo = 0, or A = L * D * L', if uplo = 1, where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. The factored form of A is then used to solve the system of equations A * X = B. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the block diagonal matrix D and the multipliers used to obtain the factor U or L from the factorization A = U*D*U' or A = L*D*L' as computed by sytrf. ipiv: Details of the interchanges and the block structure of D, as determined by sytrf. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged, and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if info = 0, the N-by-NRHS solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) is exactly zero. The factorization has been completed, but the block diagonal matrix D is exactly singular, so the solution could not be computed. =for example # Assume $a is symmetric ;) $a = random (5,5); $a = transpose($a); $b = random(4,5); $b = transpose($b); sysv($a, 1, $b, (my $ipiv=zeroes(5)),(my $info=null)); print "The solution matrix X is :". transpose($b)."\n" unless $info; =for bad sysv ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sysv = \&PDL::sysv; =head2 sysvx =for sig Signature: ([phys]A(n,n); int uplo(); int fact(); [phys]B(n,m); [io,phys]af(n,n); int [io,phys]ipiv(n); [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); int [t]iwork(n)) =for ref Uses the diagonal pivoting factorization to compute the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric matrix and X and B are N-by-NRHS matrices. Error bounds on the solution and a condition estimate are also provided. The following steps are performed: =over 3 =item 1 If fact = 0, the diagonal pivoting method is used to factor A. The form of the factorization is A = U * D * U', if uplo = 0, or A = L * D * L', if uplo = 1, where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. =item 2 If some D(i,i)=0, so that D is exactly singular, then the routine returns with info = i. Otherwise, the factored form of A is used to estimate the condition number of the matrix A. If the reciprocal of the condition number is less than machine precision, info = N+1 is returned as a warning, but the routine still goes on to solve for X and compute error bounds as described below. =item 3 The system of equations is solved for X using the factored form of A. =item 4 Iterative refinement is applied to improve the computed solution matrix and calculate error bounds and backward error estimates for it. =back Arguments ========= fact: Specifies whether or not the factored form of A has been supplied on entry. = 0: The matrix A will be copied to af and factored. = 1: On entry, af and ipiv contain the factored form of A. af and ipiv will not be modified. uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: The symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. af: If fact = 1, then af is an input argument and on entry contains the block diagonal matrix D and the multipliers used to obtain the factor U or L from the factorization A = U*D*U' or A = L*D*L' as computed by sytrf. If fact = 0, then af is an output argument and on exit returns the block diagonal matrix D and the multipliers used to obtain the factor U or L from the factorization A = U*D*U' or A = L*D*L'. ipiv: If fact = 1, then ipiv is an input argument and on entry contains details of the interchanges and the block structure of D, as determined by sytrf. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. If fact = 0, then ipiv is an output argument and on exit contains details of the interchanges and the block structure of D, as determined by sytrf. B: The N-by-NRHS right hand side matrix B. X: If info = 0 or info = N+1, the N-by-NRHS solution matrix X. rcond: The estimate of the reciprocal condition number of the matrix A. If rcond is less than the machine precision (in particular, if rcond = 0), the matrix is singular to working precision. This condition is indicated by a return code of info > 0. ferr: The estimated forward error bound for each solution vector X(j) (the j-th column of the solution matrix X). If XTRUE is the true solution corresponding to X(j), ferr(j) is an estimated upper bound for the magnitude of the largest element in (X(j) - XTRUE) divided by the magnitude of the largest element in X(j). The estimate is as reliable as the estimate for rcond, and is almost always a slight overestimate of the true error. berr: The componentwise relative backward error of each solution vector X(j) (i.e., the smallest relative change in any element of A or B that makes X(j) an exact solution). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, and i is <= N: D(i,i) is exactly zero. The factorization has been completed but the factor D is exactly singular, so the solution and error bounds could not be computed. rcond = 0 is returned. = N+1: D is nonsingular, but rcond is less than machine precision, meaning that the matrix is singular to working precision. Nevertheless, the solution and error bounds are computed because there are a number of situations where the computed solution can be more accurate than the value of rcond would suggest. =for example $a= random(5,5); $b = random(10,5); $a = transpose($a); $b = transpose($b); $X = zeroes($b); $af = zeroes($a); $ipiv = zeroes(long, 5); $rcond = pdl(0); $ferr = zeroes(10); $berr = zeroes(10); $info = pdl(long, 0); # Assume $a is symmetric sysvx($a, 0, 0, $b,$af, $ipiv, $X, $rcond, $ferr, $berr,$info); print "The solution matrix X is :". transpose($X)."\n"; =for bad sysvx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sysvx = \&PDL::sysvx; =head2 posv =for sig Signature: ([io,phys]A(n,n); int uplo(); [io,phys]B(n,m); int [o,phys]info()) =for ref Computes the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric positive definite matrix and X and B are N-by-NRHS matrices. The Cholesky decomposition is used to factor A as A = U'* U, if uplo = 0, or A = L * L', if uplo = 1, where U is an upper triangular matrix and L is a lower triangular matrix. The factored form of A is then used to solve the system of equations A * X = B. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the factor U or L from the Cholesky factorization A = U'*U or A = L*L'. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if info = 0, the N-by-NRHS solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the leading minor of order i of A is not positive definite, so the factorization could not be completed, and the solution has not been computed. =for example # Assume $a is symmetric positive definite ;) $a = random (5,5); $a = transpose($a); $b = random(4,5); $b = transpose($b); posv($a, 1, $b, (my $info=null)); print "The solution matrix X is :". transpose($b)."\n" unless $info; =for bad posv ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *posv = \&PDL::posv; =head2 posvx =for sig Signature: ([io,phys]A(n,n); int uplo(); int fact(); [io,phys]B(n,m); [io,phys]af(n,n); int [io]equed(); [o]s(p); [o,phys]X(n,m); [o,phys]rcond(); [o,phys]ferr(m); [o,phys]berr(m); int [o,phys]info(); int [t]iwork(n); [t]work(workn)) =for ref Uses the Cholesky factorization A = U'*U or A = L*L' to compute the solution to a real system of linear equations A * X = B, where A is an N-by-N symmetric positive definite matrix and X and B are N-by-NRHS matrices. Error bounds on the solution and a condition estimate are also provided. The following steps are performed: =over 3 =item 1 If fact = 2, real scaling factors are computed to equilibrate the system: diag(s) * A * diag(s) * inv(diag(s)) * X = diag(s) * B Whether or not the system will be equilibrated depends on the scaling of the matrix A, but if equilibration is used, A is overwritten by diag(s)*A*diag(s) and B by diag(s)*B. =item 2 If fact = 1 or 2, the Cholesky decomposition is used to factor the matrix A (after equilibration if fact = 2) as A = U'* U, if uplo = 0, or A = L * L', if uplo = 1, where U is an upper triangular matrix and L is a lower triangular matrix. =item 3 If the leading i-by-i principal minor is not positive definite, then the routine returns with info = i. Otherwise, the factored form of A is used to estimate the condition number of the matrix A. If the reciprocal of the condition number is less than machine precision, info = N+1 is returned as a warning, but the routine still goes on to solve for X and compute error bounds as described below. =item 4 The system of equations is solved for X using the factored form of A. =item 5 Iterative refinement is applied to improve the computed solution matrix and calculate error bounds and backward error estimates for it. =item 6 If equilibration was used, the matrix X is premultiplied by diag(s) so that it solves the original system before equilibration. =back Arguments ========= fact: Specifies whether or not the factored form of the matrix A is supplied on entry, and if not, whether the matrix A should be equilibrated before it is factored. = 0: On entry, af contains the factored form of A. If equed = 1, the matrix A has been equilibrated with scaling factors given by s. A and af will not be modified. = 1: The matrix A will be copied to af and factored. = 2: The matrix A will be equilibrated if necessary, then copied to af and factored. uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A, except if fact = 0 and equed = 1, then A must contain the equilibrated matrix diag(s)*A*diag(s). If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. A is not modified if fact = 0 or 1, or if fact = 2 and equed = 0 on exit. On exit, if fact = 2 and equed = 1, A is overwritten by diag(s)*A*diag(s). af: If fact = 0, then af is an input argument and on entry contains the triangular factor U or L from the Cholesky factorization A = U'*U or A = L*L', in the same storage format as A. If equed != 0, then af is the factored form of the equilibrated matrix diag(s)*A*diag(s). If fact = 1, then af is an output argument and on exit returns the triangular factor U or L from the Cholesky factorization A = U'*U or A = L*L' of the original matrix A. If fact = 2, then af is an output argument and on exit returns the triangular factor U or L from the Cholesky factorization A = U'*U or A = L*L' of the equilibrated matrix A (see the description of A for the form of the equilibrated matrix). equed: Specifies the form of equilibration that was done. = 0: No equilibration (always true if fact = 1). = 1: Equilibration was done, i.e., A has been replaced by diag(s) * A * diag(s). equed is an input argument if fact = 0; otherwise, it is an output argument. s: The scale factors for A; not accessed if equed = 0. s is an input argument if fact = 0; otherwise, s is an output argument. If fact = 0 and equed = 1, each element of s must be positive. B: On entry, the N-by-NRHS right hand side matrix B. On exit, if equed = 0, B is not modified; if equed = 1, B is overwritten by diag(s) * B. X: If info = 0 or info = N+1, the N-by-NRHS solution matrix X to the original system of equations. Note that if equed = 1, A and B are modified on exit, and the solution to the equilibrated system is inv(diag(s))*X. rcond: The estimate of the reciprocal condition number of the matrix A after equilibration (if done). If rcond is less than the machine precision (in particular, if rcond = 0), the matrix is singular to working precision. This condition is indicated by a return code of info > 0. ferr: The estimated forward error bound for each solution vector X(j) (the j-th column of the solution matrix X). If XTRUE is the true solution corresponding to X(j), FERR(j) is an estimated upper bound for the magnitude of the largest element in (X(j) - XTRUE) divided by the magnitude of the largest element in X(j). The estimate is as reliable as the estimate for rcond, and is almost always a slight overestimate of the true error. berr: The componentwise relative backward error of each solution vector X(j) (i.e., the smallest relative change in any element of A or B that makes X(j) an exact solution). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, and i is <= N: the leading minor of order i of A is not positive definite, so the factorization could not be completed, and the solution has not been computed. rcond = 0 is returned. = N+1: U is nonsingular, but rcond is less than machine precision, meaning that the matrix is singular to working precision. Nevertheless, the solution and error bounds are computed because there are a number of situations where the computed solution can be more accurate than the value of rcond would suggest. =for example $a= random(5,5); $b = random(5,5); $a = transpose($a); $b = transpose($b); # Assume $a is symmetric positive definite $rcond = pdl(0); $equed = pdl(long,0); $info = pdl(long,0); $berr = zeroes(5); $ferr = zeroes(5); $s = zeroes(5); $X = zeroes(5,5); $af = zeroes(5,5); posvx($a,0,2,$b,$af, $equed, $s, $X, $rcond, $ferr, $berr,$info); print "The solution matrix X is :". transpose($X)."\n" unless $info; =for bad posvx ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *posvx = \&PDL::posvx; =head2 gels =for sig Signature: ([io,phys]A(m,n); int trans(); [io,phys]B(p,q);int [o,phys]info()) =for ref Solves overdetermined or underdetermined real linear systems involving an M-by-N matrix A, or its transpose, using a QR or LQ factorization of A. It is assumed that A has full rank. The following options are provided: =over 3 =item 1 If trans = 0 and m >= n: find the least squares solution of an overdetermined system, i.e., solve the least squares problem minimize || B - A*X ||. =item 2 If trans = 0 and m < n: find the minimum norm solution of an underdetermined system A * X = B. =item 3 If trans = 1 and m >= n: find the minimum norm solution of an undetermined system A' * X = B. =item 4 If trans = 1 and m < n: find the least squares solution of an overdetermined system, i.e., solve the least squares problem minimize || B - A' * X ||. =back Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. Arguments ========= trans: = 0: the linear system involves A; = 1: the linear system involves A'. A: On entry, the M-by-N matrix A. On exit, if M >= N, A is overwritten by details of its QR factorization as returned by geqrf; if M < N, A is overwritten by details of its LQ factorization as returned by gelqf. B: On entry, the matrix B of right hand side vectors, stored columnwise; B is M-by-NRHS if trans = 0, or N-by-NRHS if trans = 1. On exit, B is overwritten by the solution vectors, stored columnwise: if trans = 0 and m >= n, rows 1 to n of B contain the least squares solution vectors; the residual sum of squares for the solution in each column is given by the sum of squares of elements N+1 to M in that column; if trans = 0 and m < n, rows 1 to N of B contain the minimum norm solution vectors; if trans = 1 and m >= n, rows 1 to M of B contain the minimum norm solution vectors; if trans = 1 and m < n, rows 1 to M of B contain the least squares solution vectors; the residual sum of squares for the solution in each column is given by the sum of squares of elements M+1 to N in that column. The leading dimension of the array B >= max(1,M,N). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); gels($a, 1, $b, ($info = null)); =for bad gels ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gels = \&PDL::gels; =head2 gelsy =for sig Signature: ([io,phys]A(m,n); [io,phys]B(p,q); [phys]rcond(); int [io,phys]jpvt(n); int [o,phys]rank();int [o,phys]info()) =for ref Computes the minimum-norm solution to a real linear least squares problem: minimize || A * X - B || using a complete orthogonal factorization of A. A is an M-by-N matrix which may be rank-deficient. Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. The routine first computes a QR factorization with column pivoting: A * P = Q * [ R11 R12 ] [ 0 R22 ] with R11 defined as the largest leading submatrix whose estimated condition number is less than 1/rcond. The order of R11, rank, is the effective rank of A. Then, R22 is considered to be negligible, and R12 is annihilated by orthogonal transformations from the right, arriving at the complete orthogonal factorization: A * P = Q * [ T11 0 ] * Z [ 0 0 ] The minimum-norm solution is then X = P * Z' [ inv(T11)*Q1'*B ] [ 0 ] where Q1 consists of the first rank columns of Q. Arguments ========= A: On entry, the M-by-N matrix A. On exit, A has been overwritten by details of its complete orthogonal factorization. B: On entry, the M-by-NRHS right hand side matrix B. On exit, the N-by-NRHS solution matrix X. The leading dimension of the array B >= max(1,M,N). jpvt: On entry, if jpvt(i) != 0, the i-th column of A is permuted to the front of AP, otherwise column i is a free column. On exit, if jpvt(i) = k, then the i-th column of AP was the k-th column of A. rcond: rcond is used to determine the effective rank of A, which is defined as the order of the largest leading triangular submatrix R11 in the QR factorization with pivoting of A, whose estimated condition number < 1/rcond. rank: The effective rank of A, i.e., the order of the submatrix R11. This is the same as the order of the submatrix T11 in the complete orthogonal factorization of A. info: = 0: successful exit < 0: If info = -i, the i-th argument had an illegal value. =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); $jpvt = zeroes(long, 5); $eps = lamch(0); #Threshold for rank estimation $rcond = sqrt($eps) - (sqrt($eps) - $eps) / 2; gelsy($a, $b, $rcond, $jpvt,($rank=null),($info = null)); =for bad gelsy ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gelsy = \&PDL::gelsy; =head2 gelss =for sig Signature: ([io,phys]A(m,n); [io,phys]B(p,q); [phys]rcond(); [o,phys]s(r); int [o,phys]rank();int [o,phys]info()) =for ref Computes the minimum norm solution to a real linear least squares problem: Minimize 2-norm(| b - A*x |). using the singular value decomposition (SVD) of A. A is an M-by-N matrix which may be rank-deficient. Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. The effective rank of A is determined by treating as zero those singular values which are less than rcond times the largest singular value. Arguments ========= A: On entry, the M-by-N matrix A. On exit, the first min(m,n) rows of A are overwritten with its right singular vectors, stored rowwise. B: On entry, the M-by-NRHS right hand side matrix B. On exit, B is overwritten by the N-by-NRHS solution matrix X. If m >= n and rank = n, the residual sum-of-squares for the solution in the i-th column is given by the sum of squares of elements n+1:m in that column. The leading dimension of the array B >= max(1,M,N). s: The singular values of A in decreasing order. The condition number of A in the 2-norm = s(1)/s(min(m,n)). rcond: rcond is used to determine the effective rank of A. Singular values s(i) <= rcond*s(1) are treated as zero. If rcond < 0, machine precision is used instead. rank: The effective rank of A, i.e., the number of singular values which are greater than rcond*s(1). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: the algorithm for computing the SVD failed to converge; if info = i, i off-diagonal elements of an intermediate bidiagonal form did not converge to zero. =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); $eps = lamch(0); $s =zeroes(5); #Threshold for rank estimation $rcond = sqrt($eps) - (sqrt($eps) - $eps) / 2; gelss($a, $b, $rcond, $s, ($rank=null),($info = null)); =for bad gelss ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gelss = \&PDL::gelss; =head2 gelsd =for sig Signature: ([io]A(m,n); [io]B(p,q); rcond(); [o]s(minmn); int [o]rank();int [o]info(); int [t]iwork(iworkn)) =for ref Computes the minimum-norm solution to a real linear least squares problem: minimize 2-norm(| b - A*x |) using the singular value decomposition (SVD) of A. A is an M-by-N matrix which may be rank-deficient. Several right hand side vectors b and solution vectors x can be handled in a single call; they are stored as the columns of the M-by-NRHS right hand side matrix B and the N-by-NRHS solution matrix X. The problem is solved in three steps: =over 3 =item 1 Reduce the coefficient matrix A to bidiagonal form with Householder transformations, reducing the original problem into a "bidiagonal least squares problem" (BLS) =item 2 Solve the BLS using a divide and conquer approach. =item 3 Apply back all the Householder transformations to solve the original least squares problem. =back The effective rank of A is determined by treating as zero those singular values which are less than rcond times the largest singular value. The divide and conquer algorithm makes very mild assumptions about floating point arithmetic. It will work on machines with a guard digit in add/subtract, or on those binary machines without guard digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or Cray-2. It could conceivably fail on hexadecimal or decimal machines without guard digits, but we know of none. Arguments ========= A: On entry, the M-by-N matrix A. On exit, A has been destroyed. B: On entry, the M-by-NRHS right hand side matrix B. On exit, B is overwritten by the N-by-NRHS solution matrix X. If m >= n and rank = n, the residual sum-of-squares for the solution in the i-th column is given by the sum of squares of elements n+1:m in that column. The leading dimension of the array B >= max(1,M,N). s: The singular values of A in decreasing order. The condition number of A in the 2-norm = s(1)/s(min(m,n)). rcond: rcond is used to determine the effective rank of A. Singular values s(i) <= rcond*s(1) are treated as zero. If rcond < 0, machine precision is used instead. rank: The effective rank of A, i.e., the number of singular values which are greater than rcond*s(1). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. > 0: the algorithm for computing the SVD failed to converge; if info = i, i off-diagonal elements of an intermediate bidiagonal form did not converge to zero. =for example $a= random(7,5); # $b will contain X # TODO better example with slice $b = random(7,6); $eps = lamch(0); $s =zeroes(5); #Threshold for rank estimation $rcond = sqrt($eps) - (sqrt($eps) - $eps) / 2; gelsd($a, $b, $rcond, $s, ($rank=null),($info = null)); =for bad gelsd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gelsd = \&PDL::gelsd; =head2 gglse =for sig Signature: ([phys]A(m,n); [phys]B(p,n);[io,phys]c(m);[phys]d(p);[o,phys]x(n);int [o,phys]info()) =for ref Solves the linear equality-constrained least squares (LSE) problem: minimize || c - A*x ||_2 subject to B*x = d where A is an M-by-N matrix, B is a P-by-N matrix, c is a given M-vector, and d is a given P-vector. It is assumed that P <= N <= M+P, and rank(B) = P and rank( ( A ) ) = N. ( ( B ) ) These conditions ensure that the LSE problem has a unique solution, which is obtained using a GRQ factorization of the matrices B and A. Arguments ========= A: On entry, the M-by-N matrix A. On exit, A is destroyed. B: On entry, the P-by-N matrix B. On exit, B is destroyed. c: On entry, c contains the right hand side vector for the least squares part of the LSE problem. On exit, the residual sum of squares for the solution is given by the sum of squares of elements N-P+1 to M of vector c. d: On entry, d contains the right hand side vector for the constrained equation. On exit, d is destroyed. x: On exit, x is the solution of the LSE problem. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random(7,5); $b = random(4,5); $c = random(7); $d = random(4); $x = zeroes(5); gglse($a, $b, $c, $d, $x, ($info=null)); =for bad gglse ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gglse = \&PDL::gglse; =head2 ggglm =for sig Signature: ([phys]A(n,m); [phys]B(n,p);[phys]d(n);[o,phys]x(m);[o,phys]y(p);int [o,phys]info()) =for ref Solves a general Gauss-Markov linear model (GLM) problem: minimize || y ||_2 subject to d = A*x + B*y x where A is an N-by-M matrix, B is an N-by-P matrix, and d is a given N-vector. It is assumed that M <= N <= M+P, and rank(A) = M and rank( A B ) = N. Under these assumptions, the constrained equation is always consistent, and there is a unique solution x and a minimal 2-norm solution y, which is obtained using a generalized QR factorization of A and B. In particular, if matrix B is square nonsingular, then the problem GLM is equivalent to the following weighted linear least squares problem minimize || inv(B)*(d-A*x) ||_2 x where inv(B) denotes the inverse of B. Arguments ========= A: On entry, the N-by-M matrix A. On exit, A is destroyed. B: On entry, the N-by-P matrix B. On exit, B is destroyed. d: On entry, d is the left hand side of the GLM equation. On exit, d is destroyed. x: y: On exit, x and y are the solutions of the GLM problem. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random(7,5); $b = random(7,4); $d = random(7); $x = zeroes(5); $y = zeroes(4); ggglm($a, $b, $d, $x, $y,($info=null)); =for bad ggglm ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ggglm = \&PDL::ggglm; =head2 getrf =for sig Signature: ([io]A(m,n); int [o]ipiv(p); int [o]info()) =for ref Computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges. The factorization has the form A = P * L * U where P is a permutation matrix, L is lower triangular with unit diagonal elements (lower trapezoidal if m > n), and U is upper triangular (upper trapezoidal if m < n). This is the right-looking Level 3 BLAS version of the algorithm. Arguments ========= A: On entry, the M-by-N matrix to be factored. On exit, the factors L and U from the factorization A = P*L*U; the unit diagonal elements of L are not stored. ipiv: The pivot indices; for 1 <= i <= min(M,N), row i of the matrix was interchanged with row ipiv(i). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, and division by zero will occur if it is used to solve a system of equations. =for example $a = random (float, 100,50); $ipiv = zeroes(long, 50); $info = null; getrf($a, $ipiv, $info); =for bad getrf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *getrf = \&PDL::getrf; =head2 getf2 =for sig Signature: ([io]A(m,n); int [o]ipiv(p); int [o]info()) =for ref Computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges. The factorization has the form A = P * L * U where P is a permutation matrix, L is lower triangular with unit diagonal elements (lower trapezoidal if m > n), and U is upper triangular (upper trapezoidal if m < n). This is the right-looking Level 2 BLAS version of the algorithm. Arguments ========= A: On entry, the M-by-N matrix to be factored. On exit, the factors L and U from the factorization A = P*L*U; the unit diagonal elements of L are not stored. ipiv: The pivot indices; for 1 <= i <= min(M,N), row i of the matrix was interchanged with row ipiv(i). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero. The factorization has been completed, but the factor U is exactly singular, and division by zero will occur if it is used to solve a system of equations. =for example $a = random (float, 100,50); $ipiv = zeroes(long, 50); $info = null; getf2($a, $ipiv, $info); =for bad getf2 ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *getf2 = \&PDL::getf2; =head2 sytrf =for sig Signature: ([io,phys]A(n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Computes the factorization of a real symmetric matrix A using the Bunch-Kaufman diagonal pivoting method. The form of the factorization is A = U*D*U' or A = L*D*L' where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. This is the blocked version of the algorithm, calling Level 3 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, the block diagonal matrix D and the multipliers used to obtain the factor U or L (see below for further details). ipiv: Details of the interchanges and the block structure of D. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) is exactly zero. The factorization has been completed, but the block diagonal matrix D is exactly singular, and division by zero will occur if it is used to solve a system of equations. Further Details =============== If uplo = 0, then A = U*D*U', where U = P(n)*U(n)* ... *P(k)U(k)* ..., i.e., U is a product of terms P(k)*U(k), where k decreases from n to 1 in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1 and 2-by-2 diagonal blocks D(k). P(k) is a permutation matrix as defined by ipiv(k), and U(k) is a unit upper triangular matrix, such that if the diagonal block D(k) is of order s (s = 1 or 2), then ( I v 0 ) k-s U(k) = ( 0 I 0 ) s ( 0 0 I ) n-k k-s s n-k If s = 1, D(k) overwrites A(k,k), and v overwrites A(1:k-1,k). If s = 2, the upper triangle of D(k) overwrites A(k-1,k-1), A(k-1,k), and A(k,k), and v overwrites A(1:k-2,k-1:k). If uplo = 1, then A = L*D*L', where L = P(1)*L(1)* ... *P(k)*L(k)* ..., i.e., L is a product of terms P(k)*L(k), where k increases from 1 to n in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1 and 2-by-2 diagonal blocks D(k). P(k) is a permutation matrix as defined by ipiv(k), and L(k) is a unit lower triangular matrix, such that if the diagonal block D(k) is of order s (s = 1 or 2), then ( I 0 0 ) k-1 L(k) = ( 0 I 0 ) s ( 0 v I ) n-k-s+1 k-1 s n-k-s+1 If s = 1, D(k) overwrites A(k,k), and v overwrites A(k+1:n,k). If s = 2, the lower triangle of D(k) overwrites A(k,k), A(k+1,k), and A(k+1,k+1), and v overwrites A(k+2:n,k:k+1). =for example $a = random(100,100); $ipiv = zeroes(100); $info = null; # Assume $a is symmetric sytrf($a, 0, $ipiv, $info); =for bad sytrf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sytrf = \&PDL::sytrf; =head2 sytf2 =for sig Signature: ([io,phys]A(n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Computes the factorization of a real symmetric matrix A using the Bunch-Kaufman diagonal pivoting method. The form of the factorization is A = U*D*U' or A = L*D*L' where U (or L) is a product of permutation and unit upper (lower) triangular matrices, and D is symmetric and block diagonal with 1-by-1 and 2-by-2 diagonal blocks. This is the unblocked version of the algorithm, calling Level 2 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, the block diagonal matrix D and the multipliers used to obtain the factor U or L (see below for further details). ipiv: Details of the interchanges and the block structure of D. If ipiv(k) > 0, then rows and columns k and ipiv(k) were interchanged and D(k,k) is a 1-by-1 diagonal block. If uplo = 0 and ipiv(k) = ipiv(k-1) < 0, then rows and columns k-1 and -ipiv(k) were interchanged and D(k-1:k,k-1:k) is a 2-by-2 diagonal block. If uplo = 1 and ipiv(k) = ipiv(k+1) < 0, then rows and columns k+1 and -ipiv(k) were interchanged and D(k:k+1,k:k+1) is a 2-by-2 diagonal block. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) is exactly zero. The factorization has been completed, but the block diagonal matrix D is exactly singular, and division by zero will occur if it is used to solve a system of equations. For further details see sytrf =for example $a = random(100,100); $ipiv = zeroes(100); $info = null; # Assume $a is symmetric sytf2($a, 0, $ipiv, $info); =for bad sytf2 ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sytf2 = \&PDL::sytf2; =head2 potrf =for sig Signature: ([io,phys]A(n,n); int uplo(); int [o,phys]info()) =for ref Computes the Cholesky factorization of a real symmetric positive definite matrix A. The factorization has the form A = U' * U, if uplo = 0, or A = L * L', if uplo = 1, where U is an upper triangular matrix and L is lower triangular. This is the block version of the algorithm, calling Level 3 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the factor U or L from the Cholesky factorization A = U'*U or A = L*L'. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the leading minor of order i is not positive definite, and the factorization could not be completed. =for example $a = random(100,100); # Assume $a is symmetric positive definite potrf($a, 0, ($info = null)); =for bad potrf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *potrf = \&PDL::potrf; =head2 potf2 =for sig Signature: ([io,phys]A(n,n); int uplo(); int [o,phys]info()) =for ref Computes the Cholesky factorization of a real symmetric positive definite matrix A. The factorization has the form A = U' * U, if uplo = 0, or A = L * L', if uplo = 1, where U is an upper triangular matrix and L is lower triangular. This is the unblocked version of the algorithm, calling Level 2 BLAS. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the symmetric matrix A. If uplo = 0, the leading N-by-N upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. On exit, if info = 0, the factor U or L from the Cholesky factorization A = U'*U or A = L*L'. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the leading minor of order i is not positive definite, and the factorization could not be completed. =for example $a = random(100,100); # Assume $a is symmetric positive definite potf2($a, 0, ($info = null)); =for bad potf2 ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *potf2 = \&PDL::potf2; =head2 getri =for sig Signature: ([io,phys]A(n,n); int [phys]ipiv(n); int [o,phys]info()) =for ref Computes the inverse of a matrix using the LU factorization computed by C. This method inverts U and then computes inv(A) by solving the system inv(A)*L = inv(U) for inv(A). Arguments ========= A: On entry, the factors L and U from the factorization A = P*L*U as computed by getrf. On exit, if info = 0, the inverse of the original matrix A. ipiv: The pivot indices from getrf; for 1<=i<=N, row i of the matrix was interchanged with row ipiv(i). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero; the matrix is singular and its inverse could not be computed. =for example $a = random (float, 100, 100); $ipiv = zeroes(long, 100); $info = null; getrf($a, $ipiv, $info); if ($info == 0){ getri($a, $ipiv, $info); } print "Inverse of \$a is :\n $a" unless $info; =for bad getri ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *getri = \&PDL::getri; =head2 sytri =for sig Signature: ([io]A(n,n); int uplo(); int ipiv(n); int [o]info(); [t]work(n)) =for ref Computes the inverse of a real symmetric indefinite matrix A using the factorization A = U*D*U' or A = L*D*L' computed by C. Arguments ========= uplo: Specifies whether the details of the factorization are stored as an upper or lower triangular matrix. = 0: Upper triangular, form is A = U*D*U'; = 1: Lower triangular, form is A = L*D*L'. A: On entry, the block diagonal matrix D and the multipliers used to obtain the factor U or L as computed by sytrf. On exit, if info = 0, the (symmetric) inverse of the original matrix. If uplo = 0, the upper triangular part of the inverse is formed and the part of A below the diagonal is not referenced; if uplo = 1 the lower triangular part of the inverse is formed and the part of A above the diagonal is not referenced. ipiv: Details of the interchanges and the block structure of D as determined by sytrf. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, D(i,i) = 0; the matrix is singular and its inverse could not be computed. =for example $a = random (float, 100, 100); # assume $a is symmetric $ipiv = zeroes(long, 100); sytrf($a, 0, $ipiv, ($info=null)); if ($info == 0){ sytri($a, 0, $ipiv, $info); } print "Inverse of \$a is :\n $a" unless $info; =for bad sytri ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sytri = \&PDL::sytri; =head2 potri =for sig Signature: ([io,phys]A(n,n); int uplo(); int [o,phys]info()) =for ref Computes the inverse of a real symmetric positive definite matrix A using the Cholesky factorization A = U'*U or A = L*L' computed by C. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: On entry, the triangular factor U or L from the Cholesky factorization A = U'*U or A = L*L', as computed by potrf. On exit, the upper or lower triangle of the (symmetric) inverse of A, overwriting the input factor U or L. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the (i,i) element of the factor U or L is zero, and the inverse could not be computed. =for example $a = random (float, 100, 100); # Assume $a is symmetric positive definite potrf($a, 0, ($info = null)); if ($info == 0){ # Hum... is it positive definite???? potri($a, 0,$info); } print "Inverse of \$a is :\n $a" unless $info; =for bad potri ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *potri = \&PDL::potri; =head2 trtri =for sig Signature: ([io,phys]A(n,n); int uplo(); int diag(); int [o,phys]info()) =for ref Computes the inverse of a real upper or lower triangular matrix A. This is the Level 3 BLAS version of the algorithm. Arguments ========= uplo: = 0: A is upper triangular; = 1: A is lower triangular. diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: On entry, the triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. On exit, the (triangular) inverse of the original matrix, in the same storage format. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, A(i,i) is exactly zero. The triangular matrix is singular and its inverse can not be computed. =for example $a = random (float, 100, 100); # assume $a is upper triangular trtri($a, 1, ($info=null)); print "Inverse of \$a is :\n transpose($a)" unless $info; =for bad trtri ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *trtri = \&PDL::trtri; =head2 trti2 =for sig Signature: ([io,phys]A(n,n); int uplo(); int diag(); int [o,phys]info()) =for ref Computes the inverse of a real upper or lower triangular matrix A. This is the Level 2 BLAS version of the algorithm. Arguments ========= uplo: = 0: A is upper triangular; = 1: A is lower triangular. diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: On entry, the triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. On exit, the (triangular) inverse of the original matrix, in the same storage format. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); # assume $a is upper triangular trtri2($a, 1, ($info=null)); print "Inverse of \$a is :\n transpose($a)" unless $info; =for bad trti2 ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *trti2 = \&PDL::trti2; =head2 getrs =for sig Signature: ([phys]A(n,n); int trans(); [io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()) =for ref Solves a system of linear equations A * X = B or A' * X = B with a general N-by-N matrix A using the LU factorization computed by getrf. Arguments ========= trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A'* X = B (Transpose) A: The factors L and U from the factorization A = P*L*U as computed by getrf. ipiv: The pivot indices from getrf; for 1<=i<=N, row i of the matrix was interchanged with row ipiv(i). B: On entry, the right hand side matrix B. On exit, the solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $ipiv = zeroes(long, 100); $b = random(100,50); getrf($a, $ipiv, ($info=null)); if ($info == 0){ getrs($a, 0, $b, $ipiv, $info); } print "X is :\n $b" unless $info; =for bad getrs ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *getrs = \&PDL::getrs; =head2 sytrs =for sig Signature: ([phys]A(n,n); int uplo();[io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()) =for ref Solves a system of linear equations A*X = B with a real symmetric matrix A using the factorization A = U*D*U' or A = L*D*L' computed by C. Arguments ========= uplo: Specifies whether the details of the factorization are stored as an upper or lower triangular matrix. = 0: Upper triangular, form is A = U*D*U'; = 1: Lower triangular, form is A = L*D*L'. A: The block diagonal matrix D and the multipliers used to obtain the factor U or L as computed by sytrf. ipiv: Details of the interchanges and the block structure of D as determined by sytrf. B: On entry, the right hand side matrix B. On exit, the solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $b = random(50,100); $a = transpose($a); $b = transpose($b); # Assume $a is symmetric sytrf($a, 0, ($ipiv=zeroes(100)), ($info=null)); if ($info == 0){ sytrs($a, 0, $b, $ipiv, $info); } print("X is :\n".transpose($b))unless $info; =for bad sytrs ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sytrs = \&PDL::sytrs; =head2 potrs =for sig Signature: ([phys]A(n,n); int uplo(); [io,phys]B(n,m); int [o,phys]info()) =for ref Solves a system of linear equations A*X = B with a symmetric positive definite matrix A using the Cholesky factorization A = U'*U or A = L*L' computed by C. Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: The triangular factor U or L from the Cholesky factorization A = U'*U or A = L*L', as computed by potrf. B: On entry, the right hand side matrix B. On exit, the solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $b = random(50,100); $a = transpose($a); $b = transpose($b); # Assume $a is symmetric positive definite potrf($a, 0, ($info=null)); if ($info == 0){ potrs($a, 0, $b, $info); } print("X is :\n".transpose($b))unless $info; =for bad potrs ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *potrs = \&PDL::potrs; =head2 trtrs =for sig Signature: ([phys]A(n,n); int uplo(); int trans(); int diag();[io,phys]B(n,m); int [o,phys]info()) =for ref Solves a triangular system of the form A * X = B or A' * X = B, where A is a triangular matrix of order N, and B is an N-by-NRHS matrix. A check is made to verify that A is nonsingular. Arguments ========= uplo: = 0: A is upper triangular; = 1: A is lower triangular. trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A**T * X = B (Transpose) diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: The triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. B: On entry, the right hand side matrix B. On exit, if info = 0, the solution matrix X. info = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, the i-th diagonal element of A is zero, indicating that the matrix is singular and the solutions X have not been computed. =for example # Assume $a is upper triangular $a = random (float, 100, 100); $b = random(50,100); $a = transpose($a); $b = transpose($b); $info = null; trtrs($a, 0, 0, 0, $b, $info); print("X is :\n".transpose($b))unless $info; =for bad trtrs ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *trtrs = \&PDL::trtrs; =head2 latrs =for sig Signature: ([phys]A(n,n); int uplo(); int trans(); int diag(); int normin();[io,phys]x(n); [o,phys]scale();[io,phys]cnorm(n);int [o,phys]info()) =for ref Solves one of the triangular systems A *x = s*b or A'*x = s*b with scaling to prevent overflow. Here A is an upper or lower triangular matrix, A' denotes the transpose of A, x and b are n-element vectors, and s is a scaling factor, usually less than or equal to 1, chosen so that the components of x will be less than the overflow threshold. If the unscaled problem will not cause overflow, the Level 2 BLAS routine C is called. If the matrix A is singular (A(j,j) = 0 for some j), then s is set to 0 and a non-trivial solution to A*x = 0 is returned. Further Details ======= ======= A rough bound on x is computed; if that is less than overflow, trsv is called, otherwise, specific code is used which checks for possible overflow or divide-by-zero at every operation. A columnwise scheme is used for solving A*x = b. The basic algorithm if A is lower triangular is x[1:n] := b[1:n] for j = 1, ..., n x(j) := x(j) / A(j,j) x[j+1:n] := x[j+1:n] - x(j) * A[j+1:n,j] end Define bounds on the components of x after j iterations of the loop: M(j) = bound on x[1:j] G(j) = bound on x[j+1:n] Initially, let M(0) = 0 and G(0) = max{x(i), i=1,...,n}. Then for iteration j+1 we have M(j+1) <= G(j) / | A(j+1,j+1) | G(j+1) <= G(j) + M(j+1) * | A[j+2:n,j+1] | <= G(j) ( 1 + cnorm(j+1) / | A(j+1,j+1) | ) where cnorm(j+1) is greater than or equal to the infinity-norm of column j+1 of A, not counting the diagonal. Hence G(j) <= G(0) product ( 1 + cnorm(i) / | A(i,i) | ) 1<=i<=j and |x(j)| <= ( G(0) / |A(j,j)| ) product ( 1 + cnorm(i) / |A(i,i)| ) 1<=i< j Since |x(j)| <= M(j), we use the Level 2 BLAS routine DTRSV if the reciprocal of the largest M(j), j=1,..,n, is larger than max(underflow, 1/overflow). The bound on x(j) is also used to determine when a step in the columnwise method can be performed without fear of overflow. If the computed bound is greater than a large constant, x is scaled to prevent overflow, but if the bound overflows, x is set to 0, x(j) to 1, and scale to 0, and a non-trivial solution to A*x = 0 is found. Similarly, a row-wise scheme is used to solve A'*x = b. The basic algorithm for A upper triangular is for j = 1, ..., n x(j) := ( b(j) - A[1:j-1,j]' * x[1:j-1] ) / A(j,j) end We simultaneously compute two bounds G(j) = bound on ( b(i) - A[1:i-1,i]' * x[1:i-1] ), 1<=i<=j M(j) = bound on x(i), 1<=i<=j The initial values are G(0) = 0, M(0) = max{b(i), i=1,..,n}, and we add the constraint G(j) >= G(j-1) and M(j) >= M(j-1) for j >= 1. Then the bound on x(j) is M(j) <= M(j-1) * ( 1 + cnorm(j) ) / | A(j,j) | <= M(0) * product ( ( 1 + cnorm(i) ) / |A(i,i)| ) 1<=i<=j and we can safely call trsv if 1/M(n) and 1/G(n) are both greater than max(underflow, 1/overflow). Arguments ========= uplo: Specifies whether the matrix A is upper or lower triangular. = 0: Upper triangular = 1: Lower triangular trans: Specifies the operation applied to A. = 0: Solve A * x = s*b (No transpose) = 1: Solve A'* x = s*b (Transpose) diag: Specifies whether or not the matrix A is unit triangular. = 0: Non-unit triangular = 1: Unit triangular normin: Specifies whether cnorm has been set or not. = 1: cnorm contains the column norms on entry = 0: cnorm is not set on entry. On exit, the norms will be computed and stored in cnorm. A: The triangular matrix A. If uplo = 0, the leading n by n upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading n by n lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. x: On entry, the right hand side b of the triangular system. On exit, x is overwritten by the solution vector x. scale: The scaling factor s for the triangular system A * x = s*b or A'* x = s*b. If scale = 0, the matrix A is singular or badly scaled, and the vector x is an exact or approximate solution to A*x = 0. cnorm: If normin = 0, cnorm is an output argument and cnorm(j) returns the 1-norm of the offdiagonal part of the j-th column of A. If normin = 1, cnorm is an input argument and cnorm(j) contains the norm of the off-diagonal part of the j-th column of A. If trans = 0, cnorm(j) must be greater than or equal to the infinity-norm, and if trans = 1, cnorm(j) must be greater than or equal to the 1-norm. info: = 0: successful exit < 0: if info = -k, the k-th argument had an illegal value =for example # Assume $a is upper triangular $a = random (float, 100, 100); $b = random(100); $a = transpose($a); $info = null; $scale= null; $cnorm = zeroes(100); latrs($a, 0, 0, 0, 0,$b, $scale, $cnorm,$info); =for bad latrs ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *latrs = \&PDL::latrs; =head2 gecon =for sig Signature: (A(n,n); int norm(); anorm(); [o]rcond();int [o]info(); int [t]iwork(n); [t]work(workn)) =for ref Estimates the reciprocal of the condition number of a general real matrix A, in either the 1-norm or the infinity-norm, using the LU factorization computed by C. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as rcond = 1 / ( norm(A) * norm(inv(A)) ). Arguments ========= norm: Specifies whether the 1-norm condition number or the infinity-norm condition number is required: = 0: Infinity-norm. = 1: 1-norm; A: The factors L and U from the factorization A = P*L*U as computed by getrf. anorm: If norm = 0, the infinity-norm of the original matrix A. If norm = 1, the 1-norm of the original matrix A. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(norm(A) * norm(inv(A))). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 100); $anorm = $a->lange(1); $ipiv = zeroes(long, 100); $info = null; getrf($a, $ipiv, $info); ($rcond, $info) = gecon($a, 1, $anorm) unless $info != 0; =for bad gecon ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gecon = \&PDL::gecon; =head2 sycon =for sig Signature: ([phys]A(n,n); int uplo(); int ipiv(n); [phys]anorm(); [o,phys]rcond();int [o,phys]info(); int [t]iwork(n); [t]work(workn)) =for ref Estimates the reciprocal of the condition number (in the 1-norm) of a real symmetric matrix A using the factorization A = U*D*U' or A = L*D*L' computed by C. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as rcond = 1 / (anorm * norm(inv(A))). Arguments ========= uplo: Specifies whether the details of the factorization are stored as an upper or lower triangular matrix. = 0: Upper triangular, form is A = U*D*U'; = 1: Lower triangular, form is A = L*D*L'. A: The block diagonal matrix D and the multipliers used to obtain the factor U or L as computed by sytrf. ipiv: Details of the interchanges and the block structure of D as determined by sytrf. anorm: The 1-norm of the original matrix A. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(anorm * aimvnm), where ainvnm is an estimate of the 1-norm of inv(A) computed in this routine. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. =for example # Assume $a is symmetric $a = random (float, 100, 100); $anorm = $a->lansy(1,1); $ipiv = zeroes(long, 100); $info = null; sytrf($a, 1,$ipiv, $info); ($rcond, $info) = sycon($a, 1, $anorm) unless $info != 0; =for bad sycon ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *sycon = \&PDL::sycon; =head2 pocon =for sig Signature: (A(n,n); int uplo(); anorm(); [o]rcond();int [o]info(); int [t]iwork(n); [t]work(workn)) =for ref Estimates the reciprocal of the condition number (in the 1-norm) of a real symmetric positive definite matrix using the Cholesky factorization A = U'*U or A = L*L' computed by C. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as rcond = 1 / (anorm * norm(inv(A))). Arguments ========= uplo: = 0: Upper triangle of A is stored; = 1: Lower triangle of A is stored. A: The triangular factor U or L from the Cholesky factorization A = U'*U or A = L*L', as computed by potrf. anorm: The 1-norm of the matrix A. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(anorm * ainvnm), where ainvnm is an estimate of the 1-norm of inv(A) computed in this routine. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example # Assume $a is symmetric positive definite $a = random (float, 100, 100); $anorm = $a->lansy(1,1); $info = null; potrf($a, 0, $info); ($rcond, $info) = pocon($a, 1, $anorm) unless $info != 0; =for bad pocon ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *pocon = \&PDL::pocon; =head2 trcon =for sig Signature: (A(n,n); int norm();int uplo();int diag(); [o]rcond();int [o]info(); int [t]iwork(n); [t]work(workn)) =for ref Estimates the reciprocal of the condition number of a triangular matrix A, in either the 1-norm or the infinity-norm. The norm of A is computed and an estimate is obtained for norm(inv(A)), then the reciprocal of the condition number is computed as rcond = 1 / ( norm(A) * norm(inv(A)) ). Arguments ========= norm: Specifies whether the 1-norm condition number or the infinity-norm condition number is required: = 0: Infinity-norm. = 1: 1-norm; uplo: = 0: A is upper triangular; = 1: A is lower triangular. diag: = 0: A is non-unit triangular; = 1: A is unit triangular. A: The triangular matrix A. If uplo = 0, the leading N-by-N upper triangular part of the array A contains the upper triangular matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading N-by-N lower triangular part of the array A contains the lower triangular matrix, and the strictly upper triangular part of A is not referenced. If diag = 1, the diagonal elements of A are also not referenced and are assumed to be 1. rcond: The reciprocal of the condition number of the matrix A, computed as rcond = 1/(norm(A) * norm(inv(A))). info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example # Assume $a is upper triangular $a = random (float, 100, 100); $info = null; ($rcond, $info) = trcon($a, 1, 1, 0) unless $info != 0; =for bad trcon ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *trcon = \&PDL::trcon; =head2 geqp3 =for sig Signature: ([io,phys]A(m,n); int [io,phys]jpvt(n); [o,phys]tau(k); int [o,phys]info()) =for ref geqp3 computes a QR factorization using Level 3 BLAS with column pivoting of a matrix A: A*P = Q*R The matrix Q is represented as a product of elementary reflectors Q = H(1) H(2) . . . H(k), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real/complex scalar, and v is a real/complex vector with v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), and tau in tau(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, the upper triangle of the array contains the min(M,N)-by-N upper trapezoidal matrix R; the elements below the diagonal, together with the array tau, represent the orthogonal matrix Q as a product of min(M,N) elementary reflectors. jpvt: On entry, if jpvt(J)!=0, the J-th column of A is permuted to the front of A*P (a leading column); if jpvt(J)=0, the J-th column of A is a free column. On exit, if jpvt(J)=K, then the J-th column of A*P was the the K-th column of A. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); $jpvt = zeroes(long, 50); geqp3($a, $jpvt, $tau, $info); =for bad geqp3 ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geqp3 = \&PDL::geqp3; =head2 geqrf =for sig Signature: ([io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()) =for ref geqrf computes a QR factorization of a matrix A: A = Q * R The matrix Q is represented as a product of elementary reflectors Q = H(1) H(2) . . . H(k), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real/complex scalar, and v is a real/complex vector with v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), and tau in tau(i). Arguments ========= A: On exit, the elements on and above the diagonal of the array contain the min(M,N)-by-N upper trapezoidal matrix R (R is upper triangular if m >= n); the elements below the diagonal, with the array TAU, represent the orthogonal matrix Q as a product of min(m,n) elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqrf($a, $tau, $info); =for bad geqrf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geqrf = \&PDL::geqrf; =head2 orgqr =for sig Signature: ([io,phys]A(m,n); [phys]tau(k); int [o,phys]info()) =for ref Generates an M-by-N real matrix Q with orthonormal columns, which is defined as the first N columns of a product of K elementary reflectors of order M Q = H(1) H(2) . . . H(k) as returned by geqrf or geqp3. Arguments ========= A: On entry, the i-th column must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqrf or geqp3 in the first k columns of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqrf or geqp3. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqrf($a, $tau, $info); orgqr($a, $tau, $info) unless $info != 0; =for bad orgqr ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *orgqr = \&PDL::orgqr; =head2 ormqr =for sig Signature: ([phys]A(p,k); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()) =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q' * C C * Q' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(1) H(2) . . . H(k) as returned by geqrf or geqp3. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q' from the Left; = 1: apply Q or Q' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q'. A: The i-th column must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqrf or geqp3 in the first k columns of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqrf or geqp3. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); geqrf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormqr($a, $tau, $c, $info); =for bad ormqr ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ormqr = \&PDL::ormqr; =head2 gelqf =for sig Signature: ([io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()) =for ref Computes an LQ factorization of a real M-by-N matrix A: A = L * Q. The matrix Q is represented as a product of elementary reflectors Q = H(k) . . . H(2) H(1), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(1:i-1) = 0 and v(i) = 1; v(i+1:n) is stored on exit in A(i,i+1:n), and tau in tau(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, the elements on and below the diagonal of the array contain the m-by-min(m,n) lower trapezoidal matrix L (L is lower triangular if m <= n); the elements above the diagonal, with the array tau, represent the orthogonal matrix Q as a product of elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gelqf($a, $tau, $info); =for bad gelqf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gelqf = \&PDL::gelqf; =head2 orglq =for sig Signature: ([io,phys]A(m,n); [phys]tau(k); int [o,phys]info()) =for ref Generates an M-by-N real matrix Q with orthonormal rows, which is defined as the first M rows of a product of K elementary reflectors of order N Q = H(k) . . . H(2) H(1) as returned by gelqf. Arguments ========= A: On entry, the i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gelqf in the first k rows of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gelqf. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gelqf($a, $tau, $info); orglq($a, $tau, $info) unless $info != 0; =for bad orglq ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *orglq = \&PDL::orglq; =head2 ormlq =for sig Signature: ([phys]A(k,p); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()) =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q' * C C * Q' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(k) . . . H(2) H(1) as returned by gelqf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q' from the Left; = 1: apply Q or Q' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gelqf in the first k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gelqf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); gelqf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormlq($a, $tau, $c, $info); =for bad ormlq ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ormlq = \&PDL::ormlq; =head2 geqlf =for sig Signature: ([io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()) =for ref Computes a QL factorization of a real M-by-N matrix A: A = Q * L The matrix Q is represented as a product of elementary reflectors Q = H(k) . . . H(2) H(1), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(m-k+i+1:m) = 0 and v(m-k+i) = 1; v(1:m-k+i-1) is stored on exit in A(1:m-k+i-1,n-k+i), and tau in TAU(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, if m >= n, the lower triangle of the subarray A(m-n+1:m,1:n) contains the N-by-N lower triangular matrix L; if m <= n, the elements on and below the (n-m)-th superdiagonal contain the M-by-N lower trapezoidal matrix L; the remaining elements, with the array tau, represent the orthogonal matrix Q as a product of elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqlf($a, $tau, $info); =for bad geqlf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geqlf = \&PDL::geqlf; =head2 orgql =for sig Signature: ([io,phys]A(m,n); [phys]tau(k); int [o,phys]info()) =for ref Generates an M-by-N real matrix Q with orthonormal columns, which is defined as the last N columns of a product of K elementary reflectors of order M Q = H(k) . . . H(2) H(1) as returned by geqlf. Arguments ========= A: On entry, the (n-k+i)-th column must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqlf in the last k columns of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqlf. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); geqlf($a, $tau, $info); orgql($a, $tau, $info) unless $info != 0; =for bad orgql ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *orgql = \&PDL::orgql; =head2 ormql =for sig Signature: ([phys]A(p,k); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()) =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q' * C C * Q' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(k) . . . H(2) H(1) as returned by geqlf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q' from the Left; = 1: apply Q or Q' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by geqlf in the last k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by geqlf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); geqlf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormql($a, $tau, $c, $info); =for bad ormql ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ormql = \&PDL::ormql; =head2 gerqf =for sig Signature: ([io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()) =for ref Computes an RQ factorization of a real M-by-N matrix A: A = R * Q. The matrix Q is represented as a product of elementary reflectors Q = H(1) H(2) . . . H(k), where k = min(m,n). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(n-k+i+1:n) = 0 and v(n-k+i) = 1; v(1:n-k+i-1) is stored on exit in A(m-k+i,1:n-k+i-1), and tau in TAU(i). Arguments ========= A: On entry, the M-by-N matrix A. On exit, if m <= n, the upper triangle of the subarray A(1:m,n-m+1:n) contains the M-by-M upper triangular matrix R; if m >= n, the elements on and above the (m-n)-th subdiagonal contain the M-by-N upper trapezoidal matrix R; the remaining elements, with the array tau, represent the orthogonal matrix Q as a product of min(m,n) elementary reflectors (see Further Details). tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gerqf($a, $tau, $info); =for bad gerqf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gerqf = \&PDL::gerqf; =head2 orgrq =for sig Signature: ([io,phys]A(m,n); [phys]tau(k); int [o,phys]info()) =for ref Generates an M-by-N real matrix Q with orthonormal rows, which is defined as the last M rows of a product of K elementary reflectors of order N Q = H(1) H(2) . . . H(k) as returned by gerqf. Arguments ========= A: On entry, the (m-k+i)-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gerqf in the last k rows of its array argument A. On exit, the M-by-N matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gerqf. info: = 0: successful exit < 0: if info = -i, the i-th argument has an illegal value =for example $a = random (float, 100, 50); $info = null; $tau = zeroes(float, 50); gerqf($a, $tau, $info); orgrq($a, $tau, $info) unless $info != 0; =for bad orgrq ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *orgrq = \&PDL::orgrq; =head2 ormrq =for sig Signature: ([phys]A(k,p); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()) =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q' * C C * Q' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(1) H(2) . . . H(k) as returned by gerqf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q' from the Left; = 1: apply Q or Q' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by gerqf in the last k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gerqf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); gerqf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormrq($a, $tau, $c, $info); =for bad ormrq ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ormrq = \&PDL::ormrq; =head2 tzrzf =for sig Signature: ([io,phys]A(m,n); [o,phys]tau(k); int [o,phys]info()) =for ref Reduces the M-by-N ( M <= N ) real upper trapezoidal matrix A to upper triangular form by means of orthogonal transformations. The upper trapezoidal matrix A is factored as A = ( R 0 ) * Z, where Z is an N-by-N orthogonal matrix and R is an M-by-M upper triangular matrix. The factorization is obtained by Householder's method. The kth transformation matrix, Z( k ), which is used to introduce zeros into the ( m - k + 1 )th row of A, is given in the form Z( k ) = ( I 0 ), ( 0 T( k ) ) where T( k ) = I - tau*u( k )*u( k )', u( k ) = ( 1 ), ( 0 ) ( z( k ) ) tau is a scalar and z( k ) is an ( n - m ) element vector. tau and z( k ) are chosen to annihilate the elements of the kth row of X. The scalar tau is returned in the kth element of C and the vector u( k ) in the kth row of A, such that the elements of z( k ) are in a( k, m + 1 ), ..., a( k, n ). The elements of R are returned in the upper triangular part of A. Z is given by Z = Z( 1 ) * Z( 2 ) * ... * Z( m ). Arguments ========= A: On entry, the leading M-by-N upper trapezoidal part of the array A must contain the matrix to be factorized. On exit, the leading M-by-M upper triangular part of A contains the upper triangular matrix R, and elements M+1 to N of the first M rows of A, with the array tau, represent the orthogonal matrix Z as a product of M elementary reflectors. tau: The scalar factors of the elementary reflectors. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $info = null; $tau = zeroes(float, 50); tzrzf($a, $tau, $info); =for bad tzrzf ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *tzrzf = \&PDL::tzrzf; =head2 ormrz =for sig Signature: ([phys]A(k,p); int side(); int trans(); [phys]tau(k); [io,phys]C(m,n);int [o,phys]info()) =for ref Overwrites the general real M-by-N matrix C with side = 0 side = 1 trans = 0: Q * C C * Q trans = 1: Q' * C C * Q' where Q is a real orthogonal matrix defined as the product of k elementary reflectors Q = H(1) H(2) . . . H(k) as returned by tzrzf. Q is of order M if C = 0 and of order N if C = 1. Arguments ========= side: = 0: apply Q or Q' from the Left; = 1: apply Q or Q' from the Right. trans: = 0: No transpose, apply Q; = 1: Transpose, apply Q'. A: The i-th row must contain the vector which defines the elementary reflector H(i), for i = 1,2,...,k, as returned by tzrzf in the last k rows of its array argument A. A is modified by the routine but restored on exit. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by tzrzf. C: On entry, the M-by-N matrix C. On exit, C is overwritten by Q*C or Q'*C or C*Q' or C*Q. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (float, 50, 100); $a = transpose($a); $info = null; $tau = zeroes(float, 50); tzrzf($a, $tau, $info); $c = random(70,50); # $c will contain the result $c->reshape(70,100); $c = transpose($c); ormrz($a, $tau, $c, $info); =for bad ormrz ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *ormrz = \&PDL::ormrz; =head2 gehrd =for sig Signature: ([io,phys]A(n,n); int [phys]ilo();int [phys]ihi();[o,phys]tau(k); int [o,phys]info()) =for ref Reduces a real general matrix A to upper Hessenberg form H by an orthogonal similarity transformation: Q' * A * Q = H . Further Details =============== The matrix Q is represented as a product of (ihi-ilo) elementary reflectors Q = H(ilo) H(ilo+1) . . . H(ihi-1). Each H(i) has the form H(i) = I - tau * v * v' where tau is a real scalar, and v is a real vector with v(1:i) = 0, v(i+1) = 1 and v(ihi+1:n) = 0; v(i+2:ihi) is stored on exit in A(i+2:ihi,i), and tau in tau(i). The contents of A are illustrated by the following example, with n = 7, ilo = 2 and ihi = 6: on entry, on exit, ( a a a a a a a ) ( a a h h h h a ) ( a a a a a a ) ( a h h h h a ) ( a a a a a a ) ( h h h h h h ) ( a a a a a a ) ( v2 h h h h h ) ( a a a a a a ) ( v2 v3 h h h h ) ( a a a a a a ) ( v2 v3 v4 h h h ) ( a ) ( a ) where a denotes an element of the original matrix A, h denotes a modified element of the upper Hessenberg matrix H, and vi denotes an element of the vector defining H(i). Arguments ========= ilo: ihi: It is assumed that A is already upper triangular in rows and columns 1:ilo-1 and ihi+1:N. ilo and ihi are normally set by a previous call to gebal; otherwise they should be set to 1 and N respectively. See Further Details. 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. A: On entry, the N-by-N general matrix to be reduced. On exit, the upper triangle and the first subdiagonal of A are overwritten with the upper Hessenberg matrix H, and the elements below the first subdiagonal, with the array tau, represent the orthogonal matrix Q as a product of elementary reflectors. See Further Details. tau: The scalar factors of the elementary reflectors (see Further Details). Elements 1:ilo-1 and ihi:N-1 of tau are set to zero. (dimension (N-1)) info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (50, 50); $info = null; $tau = zeroes(50); gehrd($a, 1, 50, $tau, $info); =for bad gehrd ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gehrd = \&PDL::gehrd; =head2 orghr =for sig Signature: ([io,phys]A(n,n); int [phys]ilo();int [phys]ihi();[phys]tau(k); int [o,phys]info()) =for ref Generates a real orthogonal matrix Q which is defined as the product of ihi-ilo elementary reflectors of order N, as returned by C: Q = H(ilo) H(ilo+1) . . . H(ihi-1). Arguments ========= ilo: ihi: ilo and ihi must have the same values as in the previous call of gehrd. Q is equal to the unit matrix except in the submatrix Q(ilo+1:ihi,ilo+1:ihi). 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. A: On entry, the vectors which define the elementary reflectors, as returned by gehrd. On exit, the N-by-N orthogonal matrix Q. tau: tau(i) must contain the scalar factor of the elementary reflector H(i), as returned by gehrd.(dimension (N-1)) info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (50, 50); $info = null; $tau = zeroes(50); gehrd($a, 1, 50, $tau, $info); orghr($a, 1, 50, $tau, $info); =for bad orghr ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *orghr = \&PDL::orghr; =head2 hseqr =for sig Signature: ([io,phys]H(n,n); int job();int compz();int [phys]ilo();int [phys]ihi();[o,phys]wr(n); [o,phys]wi(n);[o,phys]Z(m,m); int [o,phys]info()) =for ref Computes the eigenvalues of a real upper Hessenberg matrix H and, optionally, the matrices T and Z from the Schur decomposition H = Z T Z**T, where T is an upper quasi-triangular matrix (the Schur form), and Z is the orthogonal matrix of Schur vectors. Optionally Z may be postmultiplied into an input orthogonal matrix Q, so that this routine can give the Schur factorization of a matrix A which has been reduced to the Hessenberg form H by the orthogonal matrix Q: A = Q*H*Q**T = (QZ)*T*(QZ)**T. Arguments ========= job: = 0: compute eigenvalues only; = 1: compute eigenvalues and the Schur form T. compz: = 0: no Schur vectors are computed; = 1: Z is initialized to the unit matrix and the matrix Z of Schur vectors of H is returned; = 2: Z must contain an orthogonal matrix Q on entry, and the product Q*Z is returned. ilo: ihi: It is assumed that H is already upper triangular in rows and columns 1:ilo-1 and ihi+1:N. ilo and ihi are normally set by a previous call to gebal, and then passed to gehrd when the matrix output by gebal is reduced to Hessenberg form. Otherwise ilo and ihi should be set to 1 and N respectively. 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. H: On entry, the upper Hessenberg matrix H. On exit, if job = 1, H contains the upper quasi-triangular matrix T from the Schur decomposition (the Schur form); 2-by-2 diagonal blocks (corresponding to complex conjugate pairs of eigenvalues) are returned in standard form, with H(i,i) = H(i+1,i+1) and H(i+1,i)*H(i,i+1) < 0. If job = 0, the contents of H are unspecified on exit. wr: wi: The real and imaginary parts, respectively, of the computed eigenvalues. If two eigenvalues are computed as a complex conjugate pair, they are stored in consecutive elements of wr and wi, say the i-th and (i+1)th, with wi(i) > 0 and wi(i+1) < 0. If job = 1, the eigenvalues are stored in the same order as on the diagonal of the Schur form returned in H, with wr(i) = H(i,i) and, if H(i:i+1,i:i+1) is a 2-by-2 diagonal block, wi(i) = sqrt(H(i+1,i)*H(i,i+1)) and wi(i+1) = -wi(i). Z: If compz = 0: Z is not referenced. If compz = 1: on entry, Z need not be set, and on exit, Z contains the orthogonal matrix Z of the Schur vectors of H. If compz = 2: on entry Z must contain an N-by-N matrix Q, which is assumed to be equal to the unit matrix except for the submatrix Z(ilo:ihi,ilo:ihi); on exit Z contains Q*Z. Normally Q is the orthogonal matrix generated by orghr after the call to gehrd which formed the Hessenberg matrix H. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, hseqr failed to compute all of the eigenvalues in a total of 30*(ihi-ilo+1) iterations; elements 1:ilo-1 and i+1:n of wr and wi contain those eigenvalues which have been successfully computed. =for example $a = random (50, 50); $info = null; $tau = zeroes(50); $z= zeroes(1,1); gehrd($a, 1, 50, $tau, $info); hseqr($a,0,0,1,50,($wr=null),($wi=null),$z,$info); =for bad hseqr ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *hseqr = \&PDL::hseqr; =head2 trevc =for sig Signature: ([io]T(n,n); int side();int howmny();int select(q);[o]VL(m,m); [o]VR(p,p);int [o]m(); int [o]info(); [t]work(workn)) =for ref Computes some or all of the right and/or left eigenvectors of a real upper quasi-triangular matrix T. The right eigenvector x and the left eigenvector y of T corresponding to an eigenvalue w are defined by: T*x = w*x, y'*T = w*y' where y' denotes the conjugate transpose of the vector y. If all eigenvectors are requested, the routine may either return the matrices X and/or Y of right or left eigenvectors of T, or the products Q*X and/or Q*Y, where Q is an input orthogonal matrix. If T was obtained from the real-Schur factorization of an original matrix A = Q*T*Q', then Q*X and Q*Y are the matrices of right or left eigenvectors of A. T must be in Schur canonical form (as returned by hseqr), that is, block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; each 2-by-2 diagonal block has its diagonal elements equal and its off-diagonal elements of opposite sign. Corresponding to each 2-by-2 diagonal block is a complex conjugate pair of eigenvalues and eigenvectors; only one eigenvector of the pair is computed, namely the one corresponding to the eigenvalue with positive imaginary part. Further Details =============== The algorithm used in this program is basically backward (forward) substitution, with scaling to make the the code robust against possible overflow. Each eigenvector is normalized so that the element of largest magnitude has magnitude 1; here the magnitude of a complex number (x,y) is taken to be |x| + |y|. Arguments ========= side: = 0 : compute both right and left eigenvectors; = 1 : compute right eigenvectors only; = 2 : compute left eigenvectors only. howmny: = 0: compute all right and/or left eigenvectors; = 1: compute all right and/or left eigenvectors, and backtransform them using the input matrices supplied in VR and/or VL; = 2: compute selected right and/or left eigenvectors, specified by the logical array select. select: If howmny = 2, select specifies the eigenvectors to be computed. If howmny = 0 or 1, select is not referenced. To select the real eigenvector corresponding to a real eigenvalue w(j), select(j) must be set to TRUE. To select the complex eigenvector corresponding to a complex conjugate pair w(j) and w(j+1), either select(j) or select(j+1) must be set to TRUE; then on exit select(j) is TRUE and select(j+1) is FALSE. T: The upper quasi-triangular matrix T in Schur canonical form. VL: On entry, if side = 2 or 0 and howmny = 1, VL must contain an N-by-N matrix Q (usually the orthogonal matrix Q of Schur vectors returned by hseqr). On exit, if side = 2 or 0, VL contains: if howmny = 0, the matrix Y of left eigenvectors of T; VL has the same quasi-lower triangular form as T'. If T(i,i) is a real eigenvalue, then the i-th column VL(i) of VL is its corresponding eigenvector. If T(i:i+1,i:i+1) is a 2-by-2 block whose eigenvalues are complex-conjugate eigenvalues of T, then VL(i)+sqrt(-1)*VL(i+1) is the complex eigenvector corresponding to the eigenvalue with positive real part. if howmny = 1, the matrix Q*Y; if howmny = 2, the left eigenvectors of T specified by select, stored consecutively in the columns of VL, in the same order as their eigenvalues. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part, and the second the imaginary part. If side = 1, VL is not referenced. VR: On entry, if side = 1 or 0 and howmny = 1, VR must contain an N-by-N matrix Q (usually the orthogonal matrix Q of Schur vectors returned by hseqr). On exit, if side = 1 or 0, VR contains: if howmny = 0, the matrix X of right eigenvectors of T; VR has the same quasi-upper triangular form as T. If T(i,i) is a real eigenvalue, then the i-th column VR(i) of VR is its corresponding eigenvector. If T(i:i+1,i:i+1) is a 2-by-2 block whose eigenvalues are complex-conjugate eigenvalues of T, then VR(i)+sqrt(-1)*VR(i+1) is the complex eigenvector corresponding to the eigenvalue with positive real part. if howmny = 1, the matrix Q*X; if howmny = 2, the right eigenvectors of T specified by select, stored consecutively in the columns of VR, in the same order as their eigenvalues. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part and the second the imaginary part. If side = 2, VR is not referenced. m: The number of columns in the arrays VL and/or VR actually used to store the eigenvectors. If howmny = 0 or 1, m is set to N. Each selected real eigenvector occupies one column and each selected complex eigenvector occupies two columns. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random (50, 50); $info = null; $tau = zeroes(50); $z= zeroes(1,1); gehrd($a, 1, 50, $tau, $info); hseqr($a,0,0,1,50,($wr=null),($wi=null),$z,$info); =for bad trevc ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *trevc = \&PDL::trevc; =head2 tgevc =for sig Signature: ([io]A(n,n); int side();int howmny();[io]B(n,n);int select(q);[o]VL(m,m); [o]VR(p,p);int [o]m(); int [o]info(); [t]work(workn)) =for ref Computes some or all of the right and/or left generalized eigenvectors of a pair of real upper triangular matrices (A,B). The right generalized eigenvector x and the left generalized eigenvector y of (A,B) corresponding to a generalized eigenvalue w are defined by: (A - wB) * x = 0 and y**H * (A - wB) = 0 where y**H denotes the conjugate transpose of y. If an eigenvalue w is determined by zero diagonal elements of both A and B, a unit vector is returned as the corresponding eigenvector. If all eigenvectors are requested, the routine may either return the matrices X and/or Y of right or left eigenvectors of (A,B), or the products Z*X and/or Q*Y, where Z and Q are input orthogonal matrices. If (A,B) was obtained from the generalized real-Schur factorization of an original pair of matrices (A0,B0) = (Q*A*Z**H,Q*B*Z**H), then Z*X and Q*Y are the matrices of right or left eigenvectors of A. A must be block upper triangular, with 1-by-1 and 2-by-2 diagonal blocks. Corresponding to each 2-by-2 diagonal block is a complex conjugate pair of eigenvalues and eigenvectors; only one eigenvector of the pair is computed, namely the one corresponding to the eigenvalue with positive imaginary part. Arguments ========= side: = 0 : compute both right and left eigenvectors; = 1 : compute right eigenvectors only; = 2 : compute left eigenvectors only. howmny: = 0 : compute all right and/or left eigenvectors; = 1 : compute all right and/or left eigenvectors, and backtransform them using the input matrices supplied in VR and/or VL; = 2 : compute selected right and/or left eigenvectors, specified by the logical array select. select: If howmny=2, select specifies the eigenvectors to be computed. If howmny=0 or 1, select is not referenced. To select the real eigenvector corresponding to the real eigenvalue w(j), select(j) must be set to TRUE To select the complex eigenvector corresponding to a complex conjugate pair w(j) and w(j+1), either select(j) or select(j+1) must be set to TRUE. A: The upper quasi-triangular matrix A. B: The upper triangular matrix B. If A has a 2-by-2 diagonal block, then the corresponding 2-by-2 block of B must be diagonal with positive elements. VL: On entry, if side = 2 or 0 and howmny = 1, VL must contain an N-by-N matrix Q (usually the orthogonal matrix Q of left Schur vectors returned by hgqez). On exit, if side = 2 or 0, VL contains: if howmny = 0, the matrix Y of left eigenvectors of (A,B); if howmny = 1, the matrix Q*Y; if howmny = 2, the left eigenvectors of (A,B) specified by select, stored consecutively in the columns of VL, in the same order as their eigenvalues. If side = 1, VL is not referenced. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part, and the second the imaginary part. VR: On entry, if side = 1 or 0 and howmny = 1, VR must contain an N-by-N matrix Q (usually the orthogonal matrix Z of right Schur vectors returned by hgeqz). On exit, if side = 1 or 0, VR contains: if howmny = 0, the matrix X of right eigenvectors of (A,B); if howmny = 1, the matrix Z*X; if howmny = 2, the right eigenvectors of (A,B) specified by select, stored consecutively in the columns of VR, in the same order as their eigenvalues. If side = 2, VR is not referenced. A complex eigenvector corresponding to a complex eigenvalue is stored in two consecutive columns, the first holding the real part and the second the imaginary part. M: The number of columns in the arrays VL and/or VR actually used to store the eigenvectors. If howmny = 0 or 1, M is set to N. Each selected real eigenvector occupies one column and each selected complex eigenvector occupies two columns. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. > 0: the 2-by-2 block (info:info+1) does not have a complex eigenvalue. =for example $a = random (50, 50); $info = null; $tau = zeroes(50); $z= zeroes(1,1); gehrd($a, 1, 50, $tau, $info); hseqr($a,0,0,1,50,($wr=null),($wi=null),$z,$info); =for bad tgevc ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *tgevc = \&PDL::tgevc; =head2 gebal =for sig Signature: ([io,phys]A(n,n); int job(); int [o,phys]ilo();int [o,phys]ihi();[o,phys]scale(n); int [o,phys]info()) =for ref Balances a general real matrix A. This involves, first, permuting A by a similarity transformation to isolate eigenvalues in the first 1 to ilo-1 and last ihi+1 to N elements on the diagonal; and second, applying a diagonal similarity transformation to rows and columns ilo to ihi to make the rows and columns as close in norm as possible. Both steps are optional. Balancing may reduce the 1-norm of the matrix, and improve the accuracy of the computed eigenvalues and/or eigenvectors. Further Details =============== The permutations consist of row and column interchanges which put the matrix in the form ( T1 X Y ) P A P = ( 0 B Z ) ( 0 0 T2 ) where T1 and T2 are upper triangular matrices whose eigenvalues lie along the diagonal. The column indices ilo and ihi mark the starting and ending columns of the submatrix B. Balancing consists of applying a diagonal similarity transformation inv(D) * B * D to make the 1-norms of each row of B and its corresponding column nearly equal. The output matrix is ( T1 X*D Y ) ( 0 inv(D)*B*D inv(D)*Z ). ( 0 0 T2 ) Information about the permutations P and the diagonal matrix D is returned in the vector C. Arguments ========= job: Specifies the operations to be performed on A: = 0: none: simply set ilo = 1, ihi = N, scale(I) = 1.0 for i = 1,...,N; = 1: permute only; = 2: scale only; = 3: both permute and scale. A: On entry, the input matrix A. On exit, A is overwritten by the balanced matrix. If job = 0, A is not referenced. See Further Details. ilo: ihi: ilo and ihi are set to integers such that on exit A(i,j) = 0 if i > j and j = 1,...,ilo-1 or I = ihi+1,...,N. If job = 0 or 2, ilo = 1 and ihi = N. scale: Details of the permutations and scaling factors applied to A. If P(j) is the index of the row and column interchanged with row and column j and D(j) is the scaling factor applied to row and column j, then scale(j) = P(j) for j = 1,...,ilo-1 = D(j) for j = ilo,...,ihi = P(j) for j = ihi+1,...,N. The order in which the interchanges are made is N to ihi+1, then 1 to ilo-1. info: = 0: successful exit. < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (50, 50); $scale = zeroes(50); $info = null; $ilo = null; $ihi = null; gebal($a, $ilo, $ihi, $scale, $info); =for bad gebal ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gebal = \&PDL::gebal; =head2 gebak =for sig Signature: ([io,phys]A(n,m); int job(); int side();int [phys]ilo();int [phys]ihi();[phys]scale(n); int [o,phys]info()) =for ref gebak forms the right or left eigenvectors of a real general matrix by backward transformation on the computed eigenvectors of the balanced matrix output by gebal. Arguments ========= A: On entry, the matrix of right or left eigenvectors to be transformed, as returned by hsein or trevc. On exit, A is overwritten by the transformed eigenvectors. job: Specifies the type of backward transformation required: = 0 , do nothing, return immediately; = 1, do backward transformation for permutation only; = 2, do backward transformation for scaling only; = 3, do backward transformations for both permutation and scaling. job must be the same as the argument job supplied to gebal. side: = 0: V contains left eigenvectors. = 1: V contains right eigenvectors; ilo: ihi: The integers ilo and ihi determined by gebal. 1 <= ilo <= ihi <= N, if N > 0; ilo=1 and ihi=0, if N=0. Here N is the the number of rows of the matrix A. scale: Details of the permutation and scaling factors, as returned by gebal. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value. =for example $a = random (50, 50); $scale = zeroes(50); $info = null; $ilo = null; $ihi = null; gebal($a, $ilo, $ihi, $scale, $info); # Compute eigenvectors ($ev) gebak($ev, $ilo, $ihi, $scale, $info); =for bad gebak ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gebak = \&PDL::gebak; =head2 lange =for sig Signature: ([phys]A(n,m); int norm(); [o]b(); [t]work(workn)) =for ref Computes the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a real matrix A. Description =========== returns the value lange = ( max(abs(A(i,j))), norm = 0 ( ( norm1(A), norm = 1 ( ( normI(A), norm = 2 ( ( normF(A), norm = 3 where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. Arguments ========= norm: Specifies the value to be returned in lange as described above. A: The n by m matrix A. =for example $a = random (float, 100, 100); $norm = $a->lange(1); =for bad lange ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *lange = \&PDL::lange; =head2 lansy =for sig Signature: (A(n,n); int uplo(); int norm(); [o]b(); [t]work(workn)) =for ref Computes the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a real symmetric matrix A. Description =========== returns the value lansy = ( max(abs(A(i,j))), norm = 0 ( ( norm1(A), norm = 1 ( ( normI(A), norm = 2 ( ( normF(A), norm = 3 where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. norm: Specifies the value to be returned in lansy as described above. uplo: Specifies whether the upper or lower triangular part of the symmetric matrix A is to be referenced. = 0: Upper triangular part of A is referenced = 1: Lower triangular part of A is referenced A: The symmetric matrix A. If uplo = 0, the leading n by n upper triangular part of A contains the upper triangular part of the matrix A, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading n by n lower triangular part of A contains the lower triangular part of the matrix A, and the strictly upper triangular part of A is not referenced. =for example # Assume $a is symmetric $a = random (float, 100, 100); $norm = $a->lansy(1, 1); =for bad lansy ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *lansy = \&PDL::lansy; =head2 lantr =for sig Signature: (A(m,n);int uplo();int norm();int diag();[o]b(); [t]work(workn)) =for ref Computes the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a trapezoidal or triangular matrix A. Description =========== returns the value lantr = ( max(abs(A(i,j))), norm = 0 ( ( norm1(A), norm = 1 ( ( normI(A), norm = 2 ( ( normF(A), norm = 3 where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. norm: Specifies the value to be returned in lantr as described above. uplo: Specifies whether the matrix A is upper or lower trapezoidal. = 0: Upper triangular part of A is referenced = 1: Lower triangular part of A is referenced Note that A is triangular instead of trapezoidal if M = N. diag: Specifies whether or not the matrix A has unit diagonal. = 0: Non-unit diagonal = 1: Unit diagonal A: The trapezoidal matrix A (A is triangular if m = n). If uplo = 0, the leading m by n upper trapezoidal part of the array A contains the upper trapezoidal matrix, and the strictly lower triangular part of A is not referenced. If uplo = 1, the leading m by n lower trapezoidal part of the array A contains the lower trapezoidal matrix, and the strictly upper triangular part of A is not referenced. Note that when diag = 1, the diagonal elements of A are not referenced and are assumed to be one. =for example # Assume $a is upper triangular $a = random (float, 100, 100); $norm = $a->lantr(1, 1, 0); =for bad lantr ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *lantr = \&PDL::lantr; =head2 gemm =for sig Signature: ([phys]A(m,n); int transa(); int transb(); [phys]B(p,q);[phys]alpha(); [phys]beta(); [io,phys]C(r,s)) =for ref Performs one of the matrix-matrix operations C := alpha*op( A )*op( B ) + beta*C, where op( X ) is one of p( X ) = X or op( X ) = X', alpha and beta are scalars, and A, B and C are matrices, with op( A ) an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. Parameters ========== transa: On entry, transa specifies the form of op( A ) to be used in the matrix multiplication as follows: transa = 0, op( A ) = A. transa = 1, op( A ) = A'. transb: On entry, transb specifies the form of op( B ) to be used in the matrix multiplication as follows: transb = 0, op( B ) = B. transb = 1, op( B ) = B'. alpha: On entry, alpha specifies the scalar alpha. A: Before entry with transa = 0, the leading m by k part of the array A must contain the matrix A, otherwise the leading k by m part of the array A must contain the matrix A. B: Before entry with transb = 0, the leading k by n part of the array B must contain the matrix B, otherwise the leading n by k part of the array B must contain the matrix B. beta: On entry, beta specifies the scalar beta. When beta is supplied as zero then C need not be set on input. C: Before entry, the leading m by n part of the array C must contain the matrix C, except when beta is zero, in which case C need not be set on entry. On exit, the array C is overwritten by the m by n matrix ( alpha*op( A )*op( B ) + beta*C ). =for example $a = random(5,4); $b = random(5,4); $alpha = pdl(0.5); $beta = pdl(0); $c = zeroes(5,5); gemm($a, 0, 1,$b, $alpha, $beta, $c); =for bad gemm ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *gemm = \&PDL::gemm; =head2 mmult =for sig Signature: ([phys]A(m,n); [phys]B(p,m); [o,phys]C(p,n)) =for ref Blas matrix multiplication based on gemm =for bad mmult ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *mmult = \&PDL::mmult; =head2 crossprod =for sig Signature: ([phys]A(n,m); [phys]B(p,m); [o,phys]C(p,n)) =for ref Blas matrix cross product based on gemm =for bad crossprod ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *crossprod = \&PDL::crossprod; =head2 syrk =for sig Signature: ([phys]A(m,n); int uplo(); int trans(); [phys]alpha(); [phys]beta(); [io,phys]C(p,p)) =for ref Performs one of the symmetric rank k operations C := alpha*A*A' + beta*C, or C := alpha*A'*A + beta*C, where alpha and beta are scalars, C is an n by n symmetric matrix and A is an n by k matrix in the first case and a k by n matrix in the second case. Parameters ========== uplo: On entry, uplo specifies whether the upper or lower triangular part of the array C is to be referenced as follows: uplo = 0 Only the upper triangular part of C is to be referenced. uplo = 1 Only the lower triangular part of C is to be referenced. Unchanged on exit. trans: On entry, trans specifies the operation to be performed as follows: trans = 0 C := alpha*A*A' + beta*C. trans = 1 C := alpha*A'*A + beta*C. alpha: On entry, alpha specifies the scalar alpha. Unchanged on exit. A: Before entry with trans = 0, the leading n by k part of the array A must contain the matrix A, otherwise the leading k by n part of the array A must contain the matrix A. beta: On entry, beta specifies the scalar beta. C: Before entry with uplo = 0, the leading n by n upper triangular part of the array C must contain the upper triangular part of the symmetric matrix and the strictly lower triangular part of C is not referenced. On exit, the upper triangular part of the array C is overwritten by the upper triangular part of the updated matrix. Before entry with uplo = 1, the leading n by n lower triangular part of the array C must contain the lower triangular part of the symmetric matrix and the strictly upper triangular part of C is not referenced. On exit, the lower triangular part of the array C is overwritten by the lower triangular part of the updated matrix. =for example $a = random(5,4); $b = zeroes(5,5); $alpha = 1; $beta = 0; syrk ($a, 1,0,$alpha, $beta , $b); =for bad syrk ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *syrk = \&PDL::syrk; =head2 dot =for sig Signature: ([phys]a(n);[phys]b(n);[o,phys]c()) =for ref Dot product of two vectors using Blas. =for example $a = random(5); $b = random(5); $c = dot($a, $b) =for bad dot ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *dot = \&PDL::dot; =head2 axpy =for sig Signature: ([phys]a(n);[phys] alpha();[io,phys]b(m)) =for ref Linear combination of vectors ax + b using Blas. Returns result in b. =for example $a = random(5); $b = random(5); axpy($a, 12, $b) =for bad axpy ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *axpy = \&PDL::axpy; =head2 nrm2 =for sig Signature: ([phys]a(n);[o]b()) =for ref Euclidean norm of a vector using Blas. =for example $a = random(5); $norm2 = norm2($a) =for bad nrm2 ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *nrm2 = \&PDL::nrm2; =head2 asum =for sig Signature: ([phys]a(n);[o]b()) =for ref Sum of absolute values of a vector using Blas. =for example $a = random(5); $absum = asum($a) =for bad asum ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *asum = \&PDL::asum; =head2 scal =for sig Signature: ([io,phys]a(n);scale()) =for ref Scale a vector by a constant using Blas. =for example $a = random(5); $a->scal(0.5) =for bad scal ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *scal = \&PDL::scal; =head2 rot =for sig Signature: ([io,phys]a(n);[phys]c(); [phys]s();[io,phys]b(n)) =for ref Applies plane rotation using Blas. =for example $a = random(5); $b = random(5); rot($a, 0.5, 0.7, $b) =for bad rot ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *rot = \&PDL::rot; =head2 rotg =for sig Signature: ([io,phys]a();[io,phys]b();[o,phys]c(); [o,phys]s()) =for ref Generates plane rotation using Blas. =for example $a = sequence(4); rotg($a(0), $a(1),$a(2),$a(3)) =for bad rotg ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *rotg = \&PDL::rotg; =head2 lasrt =for sig Signature: ([io,phys]d(n); int id();int [o,phys]info()) =for ref Sort the numbers in d in increasing order (if id = 0) or in decreasing order (if id = 1 ). Use Quick Sort, reverting to Insertion sort on arrays of size <= 20. Dimension of stack limits N to about 2**32. Arguments ========= id: = 0: sort d in increasing order; = 1: sort d in decreasing order. d: On entry, the array to be sorted. On exit, d has been sorted into increasing order (d(1) <= ... <= d(N) ) or into decreasing order (d(1) >= ... >= d(N) ), depending on id. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value =for example $a = random(5); lasrt ($a, 0, ($info = null)); =for bad lasrt ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *lasrt = \&PDL::lasrt; =head2 lacpy =for sig Signature: ([phys]A(m,n); int uplo(); [o,phys]B(p,n)) =for ref Copies all or part of a two-dimensional matrix A to another matrix B. Arguments ========= uplo: Specifies the part of the matrix A to be copied to B. = 0: Upper triangular part = 1: Lower triangular part Otherwise: All of the matrix A A: The m by n matrix A. If uplo = 0, only the upper triangle or trapezoid is accessed; if uplo = 1, only the lower triangle or trapezoid is accessed. B: On exit, B = A in the locations specified by uplo. =for example $a = random(5,5); $b = zeroes($a); lacpy ($a, 0, $b); =for bad lacpy ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *lacpy = \&PDL::lacpy; =head2 laswp =for sig Signature: ([io,phys]A(m,n);int [phys]k1();int [phys] k2(); int [phys]ipiv(p);int [phys]inc()) =for ref Performs a series of row interchanges on the matrix A. One row interchange is initiated for each of rows k1 through k2 of A. Doesn't use PDL indices (start = 1). Arguments ========= A: On entry, the matrix of column dimension N to which the row interchanges will be applied. On exit, the permuted matrix. k1: The first element of ipiv for which a row interchange will be done. k2: The last element of ipiv for which a row interchange will be done. ipiv: The vector of pivot indices. Only the elements in positions k1 through k2 of ipiv are accessed. ipiv(k) = l implies rows k and l are to be interchanged. inc: The increment between successive values of ipiv. If ipiv is negative, the pivots are applied in reverse order. =for example $a = random(5,5); # reverse row (col for PDL) $b = pdl([5,4,3,2,1]); $a->laswp(1,2,$b,1); =for bad laswp ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *laswp = \&PDL::laswp; =head2 lamch =for sig Signature: (cmach(); [o]precision()) =for ref Determines precision machine parameters. Works inplace. Arguments ========= cmach: Specifies the value to be returned by lamch: = 0 LAMCH := eps = 1 LAMCH := sfmin = 2 LAMCH := base = 3 LAMCH := eps*base = 4 LAMCH := t = 5 LAMCH := rnd = 6 LAMCH := emin = 7 LAMCH := rmin = 8 LAMCH := emax = 9 LAMCH := rmax where eps = relative machine precision sfmin = safe minimum, such that 1/sfmin does not overflow base = base of the machine prec = eps*base t = number of (base) digits in the mantissa rnd = 1.0 when rounding occurs in addition, 0.0 otherwise emin = minimum exponent before (gradual) underflow rmin = underflow threshold - base**(emin-1) emax = largest exponent before overflow rmax = overflow threshold - (base**emax)*(1-eps) =for example $a = lamch (0); print "EPS is $a for double\n"; =for bad lamch ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *lamch = \&PDL::lamch; =head2 labad =for sig Signature: ([io,phys]small(); [io,phys]large()) =for ref Takes as input the values computed by C for underflow and overflow, and returns the square root of each of these values if the log of large is sufficiently large. This subroutine is intended to identify machines with a large exponent range, such as the Crays, and redefine the underflow and overflow limits to be the square roots of the values computed by C. This subroutine is needed because lamch does not compensate for poor arithmetic in the upper half of the exponent range, as is found on a Cray. Arguments ========= small: On entry, the underflow threshold as computed by lamch. On exit, if LOG10(large) is sufficiently large, the square root of small, otherwise unchanged. large: On entry, the overflow threshold as computed by lamch. On exit, if LOG10(large) is sufficiently large, the square root of large, otherwise unchanged. =for example $underflow = lamch(7); $overflow = lamch(9); labad ($underflow, $overflow); =for bad labad ignores the bad-value flag of the input ndarrays. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *labad = \&PDL::labad; =head2 tricpy =for sig Signature: (A(m,n);[o] C(m,n); int uplo) =for usage tricpy(PDL(A), int(uplo), PDL(C)) =for example use PDL::LinearAlgebra; $c = $a->tricpy($uplo); # explicit uplo $c = $a->tricpy; # default upper or use PDL::LinearAlgebra::Real; tricpy($a, $uplo, $c); # modify c =for ref Copy triangular part to another matrix. If uplo == 0 copy upper triangular part. =for bad tricpy does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *tricpy = \&PDL::tricpy; =head2 cplx_eigen =for sig Signature: (eigreval(n);eigimval(n); eigvec(n,p);int fortran();[o]cplx_val(c=2,n);[o]cplx_vec(c=2,n,p)) =for ref Output complex eigen-values/vectors from eigen-values/vectors as computed by geev or geevx. 'fortran' means fortran storage type. =for bad cplx_eigen does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut sub PDL::cplx_eigen { my ($eigre, $eigim, $eigvec, $fortran, @outs) = @_; my ($outval, $outvec) = @outs ? @outs : (null, null); PDL::_cplx_eigen_int($eigre, $eigim, $eigvec, $fortran, $outval, $outvec); if (defined $PDL::Complex::VERSION) { $_ = bless($_, 'PDL::Complex') for $outval, $outvec; } else { $_ = $_->slice('(0)')->czip($_->slice('(1)')) for $outval, $outvec; } ($outval, $outvec); } *cplx_eigen = \&PDL::cplx_eigen; =head2 augment =for sig Signature: (x(n); y(p);[o]out(q)) =for ref Combine two ndarrays into a single ndarray. This routine does backward and forward dataflow automatically. =for bad augment does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *augment = \&PDL::augment; =head2 mstack =for sig Signature: (x(n,m);y(n,p);[o]out(n,q)) =for ref Combine two ndarrays into a single ndarray. This routine does backward and forward dataflow automatically. =for bad mstack does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *mstack = \&PDL::mstack; =head2 charpol =for sig Signature: (A(n,n);[o]Y(n,n);[o]out(p)) =for ref Compute adjoint matrix and characteristic polynomial. =for bad charpol does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *charpol = \&PDL::charpol; #line 10755 "real.pd" =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut #line 8206 "Real.pm" # Exit with OK status 1; PDL-LinearAlgebra-0.38/GENERATED/PDL/LinearAlgebra/Trans.pm0000644000175000017500000005324314565105656022555 0ustar osboxesosboxes# # GENERATED WITH PDL::PP! Don't modify! # package PDL::LinearAlgebra::Trans; our @EXPORT_OK = qw( mexp mexpts mlog msqrt mpow mcos msin mtan msec mcsc mcot mcosh msinh mtanh msech mcsch mcoth macos masin matan masec macsc macot macosh masinh matanh masech macsch macoth sec asec sech asech cot acot acoth coth mfun csc acsc csch acsch toreal pi geexp __Ccgeexp __Ncgeexp cgeexp __Cctrsqrt __Nctrsqrt ctrsqrt __Cctrfun __Nctrfun ctrfun ); our %EXPORT_TAGS = (Func=>\@EXPORT_OK); use PDL::Core; use PDL::Exporter; use DynaLoader; our $VERSION = '0.14'; our @ISA = ( 'PDL::Exporter','DynaLoader' ); push @PDL::Core::PP, __PACKAGE__; bootstrap PDL::LinearAlgebra::Trans $VERSION; #line 30 "trans.pd" use PDL::Func; use PDL::Core; use PDL::Slices; use PDL::Ops qw//; use PDL::Math qw/floor/; use PDL::MatrixOps qw/identity/; use PDL::LinearAlgebra; use PDL::LinearAlgebra::Real qw //; use PDL::LinearAlgebra::Complex qw //; use strict; =encoding Latin-1 =head1 NAME PDL::LinearAlgebra::Trans - Linear Algebra based transcendental functions for PDL =head1 SYNOPSIS use PDL::LinearAlgebra::Trans; $a = random (100,100); $sqrt = msqrt($a); =head1 DESCRIPTION This module provides some transcendental functions for matrices. Moreover it provides sec, asec, sech, asech, cot, acot, acoth, coth, csc, acsc, csch, acsch. Beware, importing this module will overwrite the hidden PDL routine sec. If you need to call it specify its origin module : PDL::Basic::sec(args) =cut #line 67 "Trans.pm" =head1 FUNCTIONS =cut =head2 geexp =for sig Signature: ([io,phys]A(n,n);int deg();scale();[io]trace();int [o]ns();int [o]info(); int [t]ipiv(n); [t]wsp(wspn)) =for ref Computes exp(t*A), the matrix exponential of a general matrix, using the irreducible rational Pade approximation to the exponential function exp(x) = r(x) = (+/-)( I + 2*(q(x)/p(x)) ), combined with scaling-and-squaring and optionally normalization of the trace. The algorithm is described in Roger B. Sidje (rbs.uq.edu.au) "EXPOKIT: Software Package for Computing Matrix Exponentials". ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 A: On input argument matrix. On output exp(t*A). Use Fortran storage type. deg: the degre of the diagonal Pade to be used. a value of 6 is generally satisfactory. scale: time-scale (can be < 0). trace: on input, boolean value indicating whether or not perform a trace normalization. On output value used. ns: on output number of scaling-squaring used. info: exit flag. 0 - no problem > 0 - Singularity in LU factorization when solving Pade approximation =for example = random(5,5); = pdl(1); ->t->geexp(6,1,, ( = null), ( = null)); =for bad geexp does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *geexp = \&PDL::geexp; *__Ccgeexp = \&PDL::__Ccgeexp; *__Ncgeexp = \&PDL::__Ncgeexp; #line 23 "../pp_defc.pl" =head2 cgeexp =for sig Signature: (complex [io,phys]A(n,n);int deg();scale();int trace();int [o]ns();int [o]info(); int [t] ipiv(n)) =for ref Complex version of geexp. The value used for trace normalization is not returned. The algorithm is described in Roger B. Sidje (rbs@maths.uq.edu.au) "EXPOKIT: Software Package for Computing Matrix Exponentials". ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 =cut sub PDL::cgeexp { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeexp if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeexp; } *cgeexp = \&PDL::cgeexp; #line 170 "Trans.pm" *__Cctrsqrt = \&PDL::__Cctrsqrt; *__Nctrsqrt = \&PDL::__Nctrsqrt; #line 23 "../pp_defc.pl" =head2 ctrsqrt =for sig Signature: (complex [io,phys]A(n,n);int uplo();complex [phys,o] B(n,n);int [o]info()) =for ref Root square of complex triangular matrix. Uses a recurrence of Björck and Hammarling. (See Nicholas J. Higham. A new sqrtm for MATLAB. Numerical Analysis Report No. 336, Manchester Centre for Computational Mathematics, Manchester, England, January 1999. It's available at http://www.ma.man.ac.uk/~higham/pap-mf.html) If uplo is true, A is lower triangular. =cut sub PDL::ctrsqrt { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrsqrt if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrsqrt; } *ctrsqrt = \&PDL::ctrsqrt; #line 209 "Trans.pm" *__Cctrfun = \&PDL::__Cctrfun; *__Nctrfun = \&PDL::__Nctrfun; #line 23 "../pp_defc.pl" =head2 ctrfun =for sig Signature: (complex [io]A(n,n);int uplo();complex [o] B(n,n);int [o]info(); complex [t]diag(n);SV* func) =for ref Apply an arbitrary function to a complex triangular matrix. Uses a recurrence of Parlett. If uplo is true, A is lower triangular. =cut sub PDL::ctrfun { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrfun if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrfun; } *ctrfun = \&PDL::ctrfun; #line 807 "trans.pd" my $pi; BEGIN { $pi = pdl(3.1415926535897932384626433832795029) } sub pi () { $pi->copy }; *sec = \&PDL::sec; sub PDL::sec{1/cos($_[0])} *csc = \&PDL::csc; sub PDL::csc($) {1/sin($_[0])} *cot = \&PDL::cot; sub PDL::cot($) {1/(sin($_[0])/cos($_[0]))} *sech = \&PDL::sech; sub PDL::sech($){1/pdl($_[0])->cosh} *csch = \&PDL::csch; sub PDL::csch($) {1/pdl($_[0])->sinh} *coth = \&PDL::coth; sub PDL::coth($) {1/pdl($_[0])->tanh} *asec = \&PDL::asec; sub PDL::asec($) {my $tmp = 1/pdl($_[0]) ; $tmp->acos} *acsc = \&PDL::acsc; sub PDL::acsc($) {my $tmp = 1/pdl($_[0]) ; $tmp->asin} *acot = \&PDL::acot; sub PDL::acot($) {my $tmp = 1/pdl($_[0]) ; $tmp->atan} *asech = \&PDL::asech; sub PDL::asech($) {my $tmp = 1/pdl($_[0]) ; $tmp->acosh} *acsch = \&PDL::acsch; sub PDL::acsch($) {my $tmp = 1/pdl($_[0]) ; $tmp->asinh} *acoth = \&PDL::acoth; sub PDL::acoth($) {my $tmp = 1/pdl($_[0]) ; $tmp->atanh} my $_tol = 9.99999999999999e-15; sub toreal{ return $_[0] if $_[0]->isempty; $_tol = $_[1] if defined $_[1]; my ($min, $max, $tmp); ($min, $max) = $_[0]->im->minmax; return $_[0]->re->sever unless (abs($min) > $_tol || abs($max) > $_tol); $_[0]; } =head2 mlog =for ref Return matrix logarithm of a square matrix. =for usage PDL = mlog(PDL(A)) =for example my $a = random(10,10); my $log = mlog($a); =cut *mlog = \&PDL::mlog; sub PDL::mlog { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; mfun($m, sub{$_[0].=log $_[0]} , 0, $tol); } =head2 msqrt =for ref Return matrix square root (principal) of a square matrix. =for usage PDL = msqrt(PDL(A)) =for example my $a = random(10,10); my $sqrt = msqrt($a); =cut *msqrt = \&PDL::msqrt; sub PDL::msqrt { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; $m = $m->r2C unless $m->_is_complex; my ($t, undef, $z, undef, $info) = $m->mschur(1); if ($info){ warn "msqrt: Can't compute Schur form\n"; return; } ($t, $info) = $t->ctrsqrt(0); if($info){ warn "msqrt: can't compute square root\n"; return; } $m = $z x $t x $z->t(1); return $m->_is_complex ? $m : toreal($m, $tol); } =head2 mexp =for ref Return matrix exponential of a square matrix. =for usage PDL = mexp(PDL(A)) =for example my $a = random(10,10); my $exp = mexp($a); =cut *mexp = \&PDL::mexp; sub PDL::mexp { &PDL::LinearAlgebra::_square; my ($m, $order, $trace) = @_; $trace = 1 unless defined $trace; $order = 6 unless defined $order; $m = $m->copy; $m->t->_call_method('geexp', $order, 1, $trace, my $ns = PDL->null, my $info = PDL->null); if ($info){ warn "mexp: Error $info"; } else{ return $m; } } *mexpts = \&PDL::mexpts; sub PDL::mexpts { &PDL::LinearAlgebra::_square; my ($m, $order, $tol) = @_; my @dims = $m->dims; my ($em, $trm); $order = 20 unless defined $order; $em = $m->_is_complex ? diag(r2C(ones($dims[1]))) : diag(ones($dims[1])); $trm = $em->copy; for (1..($order - 1)){ $trm = $trm x ($m / $_); $em += $trm; } return $m->_is_complex ? $em : toreal($em, $tol); } =head2 mpow =for ref Return matrix power of a square matrix. =for usage PDL = mpow(PDL(A), SCALAR(exponent)) =for example my $a = random(10,10); my $powered = mpow($a,2.5); =cut *mpow = \&PDL::mpow; sub PDL::mpow { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $power, $tol, $eigen) = @_; my @dims = $m->dims; my $ret; if (UNIVERSAL::isa($power,'PDL') and $power->dims > 1){ my ($e, $v) = $m->meigen(0,1); $ret = $v * ($e**$power) x $v->minv; } elsif( 1/$dims[$di] * 1000 > abs($power) and !$eigen){ $ret = identity($dims[$di]); $ret = $ret->r2C if $m->_is_complex; my $pow = floor($power); $pow++ if ($power < 0 and $power != $pow); # TODO: what a beautiful thing (is it a game ?) for(my $i = 0; $i < abs($pow); $i++){$ret x= $m;} $ret = $ret->minv if $power < 0; if ($power = $power - $pow){ if($power == 0.5){ my $v = $m->msqrt; $ret = ($pow == 0) ? $v : $ret x $v; } else{ my ($e, $v) = $m->meigen(0,1); $ret = ($pow == 0) ? ($v * $e**$power x $v->minv) : $ret->r2C x ($v * $e**$power x $v->minv); } } } else{ my ($e, $v) = $m->meigen(0,1); $ret = $v * $e**$power x $v->minv; } return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 mcos =for ref Return matrix cosine of a square matrix. =for usage PDL = mcos(PDL(A)) =for example my $a = random(10,10); my $cos = mcos($a); =cut sub _i { defined $PDL::Complex::VERSION ? PDL::Complex::i() : i(); } *mcos = \&PDL::mcos; sub PDL::mcos { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); return $m->_is_complex ? (mexp($i*$m) + mexp(- $i*$m)) / 2 : mexp($i*$m)->re->sever; } =head2 macos =for ref Return matrix inverse cosine of a square matrix. =for usage PDL = macos(PDL(A)) =for example my $a = random(10,10); my $acos = macos($a); =cut *macos = \&PDL::macos; sub PDL::macos { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $i = _i(); my $ret = $i * mlog( ($m->r2C - $i * msqrt( ($id - $m x $m), $tol))); return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 msin =for ref Return matrix sine of a square matrix. =for usage PDL = msin(PDL(A)) =for example my $a = random(10,10); my $sin = msin($a); =cut *msin = \&PDL::msin; sub PDL::msin { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); $m->_is_complex ? (mexp($i*$m) - mexp(- $i*$m))/(2*$i) : mexp($i*$m)->im->sever; } =head2 masin =for ref Return matrix inverse sine of a square matrix. =for usage PDL = masin(PDL(A)) =for example my $a = random(10,10); my $asin = masin($a); =cut *masin = \&PDL::masin; sub PDL::masin { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $i = _i(); my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = (-$i) * mlog((($i*$m) + msqrt($id - $m x $m, $tol))); return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 mtan =for ref Return matrix tangent of a square matrix. =for usage PDL = mtan(PDL(A)) =for example my $a = random(10,10); my $tan = mtan($a); =cut *mtan = \&PDL::mtan; sub PDL::mtan { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; return scalar msolvex(mcos($m), msin($m),equilibrate=>1) unless $id; my $i = _i(); if ($m->_is_complex){ my $di = $_[0]->dims_internal; $id = identity($dims[$di])->r2C; $m = mexp(-2*$i*$m); return scalar msolvex( ($id + $m ),( (- $i) * ($id - $m)),equilibrate=>1); } else{ $m = mexp($i * $m); return scalar $m->re->msolvex($m->im,equilibrate=>1); } } =head2 matan =for ref Return matrix inverse tangent of a square matrix. =for usage PDL = matan(PDL(A)) =for example my $a = random(10,10); my $atan = matan($a); =cut *matan = \&PDL::matan; sub PDL::matan { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $i = _i(); my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = -$i/2 * mlog( scalar PDL::msolvex( ($id - $i*$m) ,($id + $i*$m),equilibrate=>1 )); return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 mcot =for ref Return matrix cotangent of a square matrix. =for usage PDL = mcot(PDL(A)) =for example my $a = random(10,10); my $cot = mcot($a); =cut *mcot = \&PDL::mcot; sub PDL::mcot { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; return scalar msolvex(msin($m),mcos($m),equilibrate=>1) unless $id; my $i = _i(); if ($m->_is_complex){ my $di = $_[0]->dims_internal; $id = identity($dims[$di])->r2C; $m = mexp(-2*$i*$m); return scalar msolvex( ($id - $m), ($i * ($id + $m)), equilibrate=>1); } else{ $m = mexp($i * $m); return scalar $m->im->msolvex($m->re,equilibrate=>1); } } =head2 macot =for ref Return matrix inverse cotangent of a square matrix. =for usage PDL = macot(PDL(A)) =for example my $a = random(10,10); my $acot = macot($a); =cut *macot = \&PDL::macot; sub PDL::macot { &PDL::LinearAlgebra::_square; my ($m, $tol, $id) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macot: singular matrix"; return; } return matan($inv,$tol); } =head2 msec =for ref Return matrix secant of a square matrix. =for usage PDL = msec(PDL(A)) =for example my $a = random(10,10); my $sec = msec($a); =cut *msec = \&PDL::msec; sub PDL::msec { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); return $m->_is_complex ? PDL::minv(mexp($i*$m) + mexp(- $i*$m)) * 2 : scalar PDL::minv(re(mexp($i*$m))); } =head2 masec =for ref Return matrix inverse secant of a square matrix. =for usage PDL = masec(PDL(A)) =for example my $a = random(10,10); my $asec = masec($a); =cut *masec = \&PDL::masec; sub PDL::masec { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "masec: singular matrix"; return; } return macos($inv,$tol); } =head2 mcsc =for ref Return matrix cosecant of a square matrix. =for usage PDL = mcsc(PDL(A)) =for example my $a = random(10,10); my $csc = mcsc($a); =cut *mcsc = \&PDL::mcsc; sub PDL::mcsc { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); $m->_is_complex ? PDL::minv(mexp($i*$m) - mexp(- $i*$m)) * 2*$i : scalar PDL::minv(im(mexp($i*$m))); } =head2 macsc =for ref Return matrix inverse cosecant of a square matrix. =for usage PDL = macsc(PDL(A)) =for example my $a = random(10,10); my $acsc = macsc($a); =cut *macsc = \&PDL::macsc; sub PDL::macsc { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macsc: singular matrix"; return; } return masin($inv,$tol); } =head2 mcosh =for ref Return matrix hyperbolic cosine of a square matrix. =for usage PDL = mcosh(PDL(A)) =for example my $a = random(10,10); my $cos = mcosh($a); =cut *mcosh = \&PDL::mcosh; sub PDL::mcosh { &PDL::LinearAlgebra::_square; my $m = shift; ( $m->mexp + mexp(-$m) )/2; } =head2 macosh =for ref Return matrix hyperbolic inverse cosine of a square matrix. =for usage PDL = macosh(PDL(A)) =for example my $a = random(10,10); my $acos = macosh($a); =cut *macosh = \&PDL::macosh; sub PDL::macosh { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my @dims = $m->dims; my $di = $_[0]->dims_internal; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = msqrt($m x $m - $id); $m = $m->r2C if $ret->getndims > @dims; mlog($m + $ret, $tol); } =head2 msinh =for ref Return matrix hyperbolic sine of a square matrix. =for usage PDL = msinh(PDL(A)) =for example my $a = random(10,10); my $sinh = msinh($a); =cut *msinh = \&PDL::msinh; sub PDL::msinh { &PDL::LinearAlgebra::_square; my $m = shift; ( $m->mexp - mexp(-$m) )/2; } =head2 masinh =for ref Return matrix hyperbolic inverse sine of a square matrix. =for usage PDL = masinh(PDL(A)) =for example my $a = random(10,10); my $asinh = masinh($a); =cut *masinh = \&PDL::masinh; sub PDL::masinh { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my @dims = $m->dims; my $di = $_[0]->dims_internal; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = msqrt($m x $m + $id); $m = $m->r2C if $ret->getndims > @dims; mlog(($m + $ret), $tol); } =head2 mtanh =for ref Return matrix hyperbolic tangent of a square matrix. =for usage PDL = mtanh(PDL(A)) =for example my $a = random(10,10); my $tanh = mtanh($a); =cut *mtanh = \&PDL::mtanh; sub PDL::mtanh { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; return scalar msolvex(mcosh($m), msinh($m),equilibrate=>1) unless $id; my $di = $_[0]->dims_internal; $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; $m = mexp(-2*$m); return scalar msolvex( ($id + $m ),($id - $m), equilibrate=>1); } =head2 matanh =for ref Return matrix hyperbolic inverse tangent of a square matrix. =for usage PDL = matanh(PDL(A)) =for example my $a = random(10,10); my $atanh = matanh($a); =cut *matanh = \&PDL::matanh; sub PDL::matanh { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my @dims = $m->dims; my $di = $_[0]->dims_internal; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; mlog( scalar msolvex( ($id - $m ),($id + $m),equilibrate=>1), $tol ) / 2; } =head2 mcoth =for ref Return matrix hyperbolic cotangent of a square matrix. =for usage PDL = mcoth(PDL(A)) =for example my $a = random(10,10); my $coth = mcoth($a); =cut *mcoth = \&PDL::mcoth; sub PDL::mcoth { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; scalar msolvex(msinh($m), mcosh($m),equilibrate=>1) unless $id; my $di = $_[0]->dims_internal; $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; $m = mexp(-2*$m); return scalar msolvex( ($id - $m ),($id + $m),equilibrate=>1); } =head2 macoth =for ref Return matrix hyperbolic inverse cotangent of a square matrix. =for usage PDL = macoth(PDL(A)) =for example my $a = random(10,10); my $acoth = macoth($a); =cut *macoth = \&PDL::macoth; sub PDL::macoth { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macoth: singular matrix"; return; } return matanh($inv,$tol); } =head2 msech =for ref Return matrix hyperbolic secant of a square matrix. =for usage PDL = msech(PDL(A)) =for example my $a = random(10,10); my $sech = msech($a); =cut *msech = \&PDL::msech; sub PDL::msech { &PDL::LinearAlgebra::_square; my $m = shift; PDL::minv( $m->mexp + mexp(-$m) ) * 2; } =head2 masech =for ref Return matrix hyperbolic inverse secant of a square matrix. =for usage PDL = masech(PDL(A)) =for example my $a = random(10,10); my $asech = masech($a); =cut *masech = \&PDL::masech; sub PDL::masech { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "masech: singular matrix"; return; } return macosh($inv,$tol); } =head2 mcsch =for ref Return matrix hyperbolic cosecant of a square matrix. =for usage PDL = mcsch(PDL(A)) =for example my $a = random(10,10); my $csch = mcsch($a); =cut *mcsch = \&PDL::mcsch; sub PDL::mcsch { &PDL::LinearAlgebra::_square; my $m = shift; PDL::minv( $m->mexp - mexp(-$m) ) * 2; } =head2 macsch =for ref Return matrix hyperbolic inverse cosecant of a square matrix. =for usage PDL = macsch(PDL(A)) =for example my $a = random(10,10); my $acsch = macsch($a); =cut *macsch = \&PDL::macsch; sub PDL::macsch { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macsch: singular matrix"; return; } return masinh($inv,$tol); } =head2 mfun =for ref Return matrix function of second argument of a square matrix. Function will be applied on a complex ndarray. =for usage PDL = mfun(PDL(A),'cos') =for example my $a = random(10,10); my $fun = mfun($a,'cos'); sub sinbycos2{ $_[0]->set_inplace(0); $_[0] .= $_[0]->Csin/$_[0]->Ccos**2; } # Try diagonalization $fun = mfun($a, \&sinbycos2,1); # Now try Schur/Parlett $fun = mfun($a, \&sinbycos2); # Now with function. scalar msolve($a->mcos->mpow(2), $a->msin); =cut *mfun = \&PDL::mfun; sub PDL::mfun { &PDL::LinearAlgebra::_square; my ($m, $method, $diag, $tol) = @_; my @dims = $m->dims; if ($diag){ my ($e, $v) = $m->meigen(0,1); my ($inv, $info) = $v->minv; unless ($info){ $method = 'PDL::Complex::'.$method unless ref($method); eval {$v = ($v * $e->$method) x $v->minv;}; if ($@){ warn "mfun: Error $@\n"; return; } } else{ warn "mfun: Non invertible matrix in computation of $method\n"; return; } return $m->_is_complex ? $v : toreal($v, $tol); } else{ $m = $m->r2C unless $m->_is_complex; my ($t, undef, $z, undef, $info) = $m->mschur(1); if ($info){ warn "mfun: Can't compute Schur form\n"; return; } $method = 'PDL::Complex::'.$method unless ref($method); ($t, $info) = $t->ctrfun(0,$method); if($info){ warn "mfun: Can't compute $method\n"; return; } $m = $z x $t x $z->t(1); return $m->_is_complex ? $m : toreal($m, $tol); } } =head1 TODO Improve error return and check singularity. Improve (msqrt,mlog) / r2C =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut #line 1233 "Trans.pm" # Exit with OK status 1; PDL-LinearAlgebra-0.38/GENERATED/PDL/LinearAlgebra/Complex.pm0000644000175000017500000021443014565105652023066 0ustar osboxesosboxes# # GENERATED WITH PDL::PP! Don't modify! # package PDL::LinearAlgebra::Complex; our @EXPORT_OK = qw(__Ccgtsv __Ncgtsv cgtsv __Ccgesvd __Ncgesvd cgesvd __Ccgesdd __Ncgesdd cgesdd __Ccggsvd __Ncggsvd cggsvd __Ccgeev __Ncgeev cgeev __Ccgeevx __Ncgeevx cgeevx __Ccggev __Ncggev cggev __Ccggevx __Ncggevx cggevx __Ccgees __Ncgees cgees __Ccgeesx __Ncgeesx cgeesx __Ccgges __Ncgges cgges __Ccggesx __Ncggesx cggesx __Ccheev __Ncheev cheev __Ccheevd __Ncheevd cheevd __Ccheevx __Ncheevx cheevx __Ccheevr __Ncheevr cheevr __Cchegv __Nchegv chegv __Cchegvd __Nchegvd chegvd __Cchegvx __Nchegvx chegvx __Ccgesv __Ncgesv cgesv __Ccgesvx __Ncgesvx cgesvx __Ccsysv __Ncsysv csysv __Ccsysvx __Ncsysvx csysvx __Cchesv __Nchesv chesv __Cchesvx __Nchesvx chesvx __Ccposv __Ncposv cposv __Ccposvx __Ncposvx cposvx __Ccgels __Ncgels cgels __Ccgelsy __Ncgelsy cgelsy __Ccgelss __Ncgelss cgelss __Ccgelsd __Ncgelsd cgelsd __Ccgglse __Ncgglse cgglse __Ccggglm __Ncggglm cggglm __Ccgetrf __Ncgetrf cgetrf __Ccgetf2 __Ncgetf2 cgetf2 __Ccsytrf __Ncsytrf csytrf __Ccsytf2 __Ncsytf2 csytf2 __Ccchetrf __Ncchetrf cchetrf __Cchetf2 __Nchetf2 chetf2 __Ccpotrf __Ncpotrf cpotrf __Ccpotf2 __Ncpotf2 cpotf2 __Ccgetri __Ncgetri cgetri __Ccsytri __Ncsytri csytri __Cchetri __Nchetri chetri __Ccpotri __Ncpotri cpotri __Cctrtri __Nctrtri ctrtri __Cctrti2 __Nctrti2 ctrti2 __Ccgetrs __Ncgetrs cgetrs __Ccsytrs __Ncsytrs csytrs __Cchetrs __Nchetrs chetrs __Ccpotrs __Ncpotrs cpotrs __Cctrtrs __Nctrtrs ctrtrs __Cclatrs __Nclatrs clatrs __Ccgecon __Ncgecon cgecon __Ccsycon __Ncsycon csycon __Cchecon __Nchecon checon __Ccpocon __Ncpocon cpocon __Cctrcon __Nctrcon ctrcon __Ccgeqp3 __Ncgeqp3 cgeqp3 __Ccgeqrf __Ncgeqrf cgeqrf __Ccungqr __Ncungqr cungqr __Ccunmqr __Ncunmqr cunmqr __Ccgelqf __Ncgelqf cgelqf __Ccunglq __Ncunglq cunglq __Ccunmlq __Ncunmlq cunmlq __Ccgeqlf __Ncgeqlf cgeqlf __Ccungql __Ncungql cungql __Ccunmql __Ncunmql cunmql __Ccgerqf __Ncgerqf cgerqf __Ccungrq __Ncungrq cungrq __Ccunmrq __Ncunmrq cunmrq __Cctzrzf __Nctzrzf ctzrzf __Ccunmrz __Ncunmrz cunmrz __Ccgehrd __Ncgehrd cgehrd __Ccunghr __Ncunghr cunghr __Cchseqr __Nchseqr chseqr __Cctrevc __Nctrevc ctrevc __Cctgevc __Nctgevc ctgevc __Ccgebal __Ncgebal cgebal __Cclange __Nclange clange __Cclansy __Nclansy clansy __Cclantr __Nclantr clantr __Ccgemm __Ncgemm cgemm __Ccmmult __Ncmmult cmmult __Cccrossprod __Nccrossprod ccrossprod __Ccsyrk __Ncsyrk csyrk __Ccdot __Ncdot cdot __Ccdotc __Ncdotc cdotc __Ccaxpy __Ncaxpy caxpy __Ccnrm2 __Ncnrm2 cnrm2 __Ccasum __Ncasum casum __Ccscal __Ncscal cscal __Ccsscal __Ncsscal csscal __Ccrotg __Ncrotg crotg __Cclacpy __Nclacpy clacpy __Cclaswp __Nclaswp claswp ctricpy cmstack __Cccharpol __Nccharpol ccharpol ); our %EXPORT_TAGS = (Func=>\@EXPORT_OK); use PDL::Core; use PDL::Exporter; use DynaLoader; our $VERSION = '0.14'; our @ISA = ( 'PDL::Exporter','DynaLoader' ); push @PDL::Core::PP, __PACKAGE__; bootstrap PDL::LinearAlgebra::Complex $VERSION; #line 79 "complex.pd" use strict; use PDL::LinearAlgebra::Real; { package # hide from CPAN PDL::Complex; my $warningFlag; BEGIN{ $warningFlag = $^W; $^W = 0; } use overload ( 'x' => sub {UNIVERSAL::isa($_[1],'PDL::Complex') ? PDL::cmmult($_[0], $_[1]) : PDL::cmmult($_[0], PDL::Complex::r2C($_[1])); }, ); BEGIN{ $^W = $warningFlag ; } } =encoding Latin-1 =head1 NAME PDL::LinearAlgebra::Complex - PDL interface to the lapack linear algebra programming library (complex number) =head1 SYNOPSIS use PDL; use PDL::LinearAlgebra::Complex; $a = random(cdouble, 100, 100); $s = zeroes(cdouble, 100); $u = zeroes(cdouble, 100, 100); $v = zeroes(cdouble, 100, 100); $info = 0; $job = 0; cgesdd($a, $job, $info, $s , $u, $v); =head1 DESCRIPTION This module provides an interface to parts of the lapack library (complex numbers). These routines accept either float or double ndarrays. =cut #line 71 "Complex.pm" =head1 FUNCTIONS =cut *__Ccgtsv = \&PDL::__Ccgtsv; *__Ncgtsv = \&PDL::__Ncgtsv; #line 23 "../pp_defc.pl" =head2 cgtsv =for sig Signature: (complex [phys]DL(n);complex [phys]D(n);complex [phys]DU(n);complex [io,phys]B(n,nrhs); int [o,phys]info()) =for ref Solves the equation A * X = B where A is an C by C tridiagonal matrix, by Gaussian elimination with partial pivoting, and B is an C by C matrix. Note that the equation C may be solved by interchanging the order of the arguments DU and DL. B This differs from the LINPACK function C in that C
starts from its first element, while the LINPACK equivalent starts from its second element. Arguments ========= DL: On entry, DL must contain the (n-1) sub-diagonal elements of A. On exit, DL is overwritten by the (n-2) elements of the second super-diagonal of the upper triangular matrix U from the LU factorization of A, in DL(1), ..., DL(n-2). D: On entry, D must contain the diagonal elements of A. On exit, D is overwritten by the n diagonal elements of U. DU: On entry, DU must contain the (n-1) super-diagonal elements of A. On exit, DU is overwritten by the (n-1) elements of the first super-diagonal of the U. B: On entry, the n by nrhs matrix of right hand side matrix B. On exit, if info = 0, the n by nrhs solution matrix X. info: = 0: successful exit < 0: if info = -i, the i-th argument had an illegal value > 0: if info = i, U(i,i) is exactly zero, and the solution has not been computed. The factorization has not been completed unless i = n. =for example $dl = random(float, 9) + random(float, 9) * i; $d = random(float, 10) + random(float, 10) * i; $du = random(float, 9) + random(float, 9) * i; $b = random(10,5) + random(10,5) * i; cgtsv($dl, $d, $du, $b, ($info=null)); print "X is:\n$b" unless $info; =cut sub PDL::cgtsv { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgtsv if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgtsv; } *cgtsv = \&PDL::cgtsv; #line 162 "Complex.pm" *__Ccgesvd = \&PDL::__Ccgesvd; *__Ncgesvd = \&PDL::__Ncgesvd; #line 23 "../pp_defc.pl" =head2 cgesvd =for sig Signature: (complex [io]A(m,n); int jobu(); int jobvt(); [o]s(minmn);complex [o]U(p,p);complex [o]VT(s,s); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L. The SVD is written A = U * SIGMA * ConjugateTranspose(V) =cut sub PDL::cgesvd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgesvd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgesvd; } *cgesvd = \&PDL::cgesvd; #line 201 "Complex.pm" *__Ccgesdd = \&PDL::__Ccgesdd; *__Ncgesdd = \&PDL::__Ncgesdd; #line 23 "../pp_defc.pl" =head2 cgesdd =for sig Signature: (complex [io]A(m,n); int jobz(); [o]s(minmn);complex [o]U(p,p);complex [o]VT(s,s); int [o]info(); int [t]iwork(iworkn)) =for ref Complex version of L. The SVD is written A = U * SIGMA * ConjugateTranspose(V) =cut sub PDL::cgesdd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgesdd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgesdd; } *cgesdd = \&PDL::cgesdd; #line 240 "Complex.pm" *__Ccggsvd = \&PDL::__Ccggsvd; *__Ncggsvd = \&PDL::__Ncggsvd; #line 23 "../pp_defc.pl" =head2 cggsvd =for sig Signature: (complex [io]A(m,n); int jobu(); int jobv(); int jobq();complex [io]B(p,n); int [o]k(); int [o]l();[o]alpha(n);[o]beta(n);complex [o]U(q,q);complex [o]V(r,r);complex [o]Q(s,s); int [o]iwork(n); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cggsvd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccggsvd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncggsvd; } *cggsvd = \&PDL::cggsvd; #line 275 "Complex.pm" *__Ccgeev = \&PDL::__Ccgeev; *__Ncgeev = \&PDL::__Ncgeev; #line 23 "../pp_defc.pl" =head2 cgeev =for sig Signature: (complex A(n,n); int jobvl(); int jobvr();complex [o]w(n);complex [o]vl(m,m);complex [o]vr(p,p); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cgeev { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeev if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeev; } *cgeev = \&PDL::cgeev; #line 310 "Complex.pm" *__Ccgeevx = \&PDL::__Ccgeevx; *__Ncgeevx = \&PDL::__Ncgeevx; #line 23 "../pp_defc.pl" =head2 cgeevx =for sig Signature: (complex [io]A(n,n); int jobvl(); int jobvr(); int balance(); int sense();complex [o]w(n);complex [o]vl(m,m);complex [o]vr(p,p); int [o]ilo(); int [o]ihi(); [o]scale(n); [o]abnrm(); [o]rconde(q); [o]rcondv(r); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cgeevx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeevx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeevx; } *cgeevx = \&PDL::cgeevx; #line 345 "Complex.pm" *__Ccggev = \&PDL::__Ccggev; *__Ncggev = \&PDL::__Ncggev; #line 23 "../pp_defc.pl" =head2 cggev =for sig Signature: (complex A(n,n); int [phys]jobvl();int [phys]jobvr();complex B(n,n);complex [o]alpha(n);complex [o]beta(n);complex [o]VL(m,m);complex [o]VR(p,p);int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cggev { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccggev if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncggev; } *cggev = \&PDL::cggev; #line 380 "Complex.pm" *__Ccggevx = \&PDL::__Ccggevx; *__Ncggevx = \&PDL::__Ncggevx; #line 23 "../pp_defc.pl" =head2 cggevx =for sig Signature: (complex [io,phys]A(n,n);int balanc();int jobvl();int jobvr();int sense();complex [io,phys]B(n,n);complex [o]alpha(n);complex [o]beta(n);complex [o]VL(m,m);complex [o]VR(p,p);int [o]ilo();int [o]ihi();[o]lscale(n);[o]rscale(n);[o]abnrm();[o]bbnrm();[o]rconde(r);[o]rcondv(s);int [o]info(); [t]rwork(rworkn); int [t]bwork(bworkn); int [t]iwork(iworkn)) =for ref Complex version of L =cut sub PDL::cggevx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccggevx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncggevx; } *cggevx = \&PDL::cggevx; #line 415 "Complex.pm" *__Ccgees = \&PDL::__Ccgees; *__Ncgees = \&PDL::__Ncgees; #line 23 "../pp_defc.pl" =head2 cgees =for sig Signature: (complex [io]A(n,n); int jobvs(); int sort();complex [o]w(n);complex [o]vs(p,p); int [o]sdim(); int [o]info(); [t]rwork(n); int [t]bwork(bworkn);SV* select_func) =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An complex eigenvalue w is selected if select_func(PDL::Complex(w)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2. =cut sub PDL::cgees { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgees if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgees; } *cgees = \&PDL::cgees; #line 463 "Complex.pm" *__Ccgeesx = \&PDL::__Ccgeesx; *__Ncgeesx = \&PDL::__Ncgeesx; #line 23 "../pp_defc.pl" =head2 cgeesx =for sig Signature: (complex [io]A(n,n); int jobvs(); int sort(); int sense();complex [o]w(n);complex [o]vs(p,p); int [o]sdim(); [o]rconde();[o]rcondv(); int [o]info(); [t]rwork(n); int [t]bwork(bworkn);SV* select_func) =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An complex eigenvalue w is selected if select_func(PDL::Complex(w)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2. =cut sub PDL::cgeesx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeesx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeesx; } *cgeesx = \&PDL::cgeesx; #line 510 "Complex.pm" *__Ccgges = \&PDL::__Ccgges; *__Ncgges = \&PDL::__Ncgges; #line 23 "../pp_defc.pl" =head2 cgges =for sig Signature: (complex [io]A(n,n); int jobvsl();int jobvsr();int sort();complex [io]B(n,n);complex [o]alpha(n);complex [o]beta(n);complex [o]VSL(m,m);complex [o]VSR(p,p);int [o]sdim();int [o]info(); [t]rwork(rworkn); int [t]bwork(bworkn);SV* select_func) =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An eigenvalue w = w/beta is selected if select_func(PDL::Complex(w), PDL::Complex(beta)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w),PDL::Complex(beta)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+2. =cut sub PDL::cgges { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgges if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgges; } *cgges = \&PDL::cgges; #line 557 "Complex.pm" *__Ccggesx = \&PDL::__Ccggesx; *__Ncggesx = \&PDL::__Ncggesx; #line 23 "../pp_defc.pl" =head2 cggesx =for sig Signature: (complex [io]A(n,n); int jobvsl();int jobvsr();int sort();int sense();complex [io]B(n,n);complex [o]alpha(n);complex [o]beta(n);complex [o]VSL(m,m);complex [o]VSR(p,p);int [o]sdim();[o]rconde(q=2);[o]rcondv(q=2);int [o]info(); [t]rwork(rworkn); int [t]bwork(bworkn); int [t]iwork(iworkn);SV* select_func) =for ref Complex version of L select_func: If sort = 1, select_func is used to select eigenvalues to sort to the top left of the Schur form. If sort = 0, select_func is not referenced. An eigenvalue w = w/beta is selected if select_func(PDL::Complex(w), PDL::Complex(beta)) is true; Note that a selected complex eigenvalue may no longer satisfy select_func(PDL::Complex(w),PDL::Complex(beta)) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned); in this case info is set to N+3. =cut sub PDL::cggesx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccggesx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncggesx; } *cggesx = \&PDL::cggesx; #line 604 "Complex.pm" *__Ccheev = \&PDL::__Ccheev; *__Ncheev = \&PDL::__Ncheev; #line 23 "../pp_defc.pl" =head2 cheev =for sig Signature: (complex [io]A(n,n); int jobz(); int uplo(); [o]w(n); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::cheev { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccheev if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncheev; } *cheev = \&PDL::cheev; #line 639 "Complex.pm" *__Ccheevd = \&PDL::__Ccheevd; *__Ncheevd = \&PDL::__Ncheevd; #line 23 "../pp_defc.pl" =head2 cheevd =for sig Signature: (complex [io,phys]A(n,n); int jobz(); int uplo(); [o,phys]w(n); int [o,phys]info()) =for ref Complex version of L for Hermitian matrix =cut sub PDL::cheevd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccheevd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncheevd; } *cheevd = \&PDL::cheevd; #line 674 "Complex.pm" *__Ccheevx = \&PDL::__Ccheevx; *__Ncheevx = \&PDL::__Ncheevx; #line 23 "../pp_defc.pl" =head2 cheevx =for sig Signature: (complex A(n,n); int jobz(); int range(); int uplo(); vl(); vu(); int il(); int iu(); abstol(); int [o]m(); [o]w(n);complex [o]z(p,p);int [o]ifail(n); int [o]info(); [t]rwork(rworkn); int [t]iwork(iworkn)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::cheevx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccheevx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncheevx; } *cheevx = \&PDL::cheevx; #line 709 "Complex.pm" *__Ccheevr = \&PDL::__Ccheevr; *__Ncheevr = \&PDL::__Ncheevr; #line 23 "../pp_defc.pl" =head2 cheevr =for sig Signature: (complex [phys]A(n,n); int jobz(); int range(); int uplo(); [phys]vl(); [phys]vu(); int [phys]il(); int [phys]iu(); [phys]abstol(); int [o,phys]m(); [o,phys]w(n);complex [o,phys]z(p,q);int [o,phys]isuppz(r); int [o,phys]info()) =for ref Complex version of L for Hermitian matrix =cut sub PDL::cheevr { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccheevr if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncheevr; } *cheevr = \&PDL::cheevr; #line 744 "Complex.pm" *__Cchegv = \&PDL::__Cchegv; *__Nchegv = \&PDL::__Nchegv; #line 23 "../pp_defc.pl" =head2 chegv =for sig Signature: (complex [io]A(n,n);int itype();int jobz(); int uplo();complex [io]B(n,n);[o]w(n); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chegv { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchegv if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchegv; } *chegv = \&PDL::chegv; #line 779 "Complex.pm" *__Cchegvd = \&PDL::__Cchegvd; *__Nchegvd = \&PDL::__Nchegvd; #line 23 "../pp_defc.pl" =head2 chegvd =for sig Signature: (complex [io,phys]A(n,n);int [phys]itype();int jobz(); int uplo();complex [io,phys]B(n,n);[o,phys]w(n); int [o,phys]info()) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chegvd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchegvd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchegvd; } *chegvd = \&PDL::chegvd; #line 814 "Complex.pm" *__Cchegvx = \&PDL::__Cchegvx; *__Nchegvx = \&PDL::__Nchegvx; #line 23 "../pp_defc.pl" =head2 chegvx =for sig Signature: (complex [io]A(n,n);int itype();int jobz();int range(); int uplo();complex [io]B(n,n);vl();vu();int il(); int iu();abstol();int [o]m();[o]w(n);complex [o]Z(p,p);int [o]ifail(n);int [o]info(); [t]rwork(rworkn); int [t]iwork(iworkn); ) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chegvx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchegvx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchegvx; } *chegvx = \&PDL::chegvx; #line 853 "Complex.pm" *__Ccgesv = \&PDL::__Ccgesv; *__Ncgesv = \&PDL::__Ncgesv; #line 23 "../pp_defc.pl" =head2 cgesv =for sig Signature: (complex [io,phys]A(n,n);complex [io,phys]B(n,m); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgesv { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgesv if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgesv; } *cgesv = \&PDL::cgesv; #line 888 "Complex.pm" *__Ccgesvx = \&PDL::__Ccgesvx; *__Ncgesvx = \&PDL::__Ncgesvx; #line 23 "../pp_defc.pl" =head2 cgesvx =for sig Signature: (complex [io]A(n,n); int trans(); int fact();complex [io]B(n,m);complex [io]af(n,n); int [io]ipiv(n); int [io]equed(); [o]r(p); [o]c(q);complex [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m); [o]rpvgrw(); int [o]info(); [t]rwork(rworkn); [t]work(rworkn)) =for ref Complex version of L. trans: Specifies the form of the system of equations: = 0: A * X = B (No transpose) = 1: A' * X = B (Transpose) = 2: A**H * X = B (Conjugate transpose) =cut sub PDL::cgesvx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgesvx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgesvx; } *cgesvx = \&PDL::cgesvx; #line 928 "Complex.pm" *__Ccsysv = \&PDL::__Ccsysv; *__Ncsysv = \&PDL::__Ncsysv; #line 23 "../pp_defc.pl" =head2 csysv =for sig Signature: (complex [io,phys]A(n,n); int uplo();complex [io,phys]B(n,m); int [o]ipiv(n); int [o]info()) =for ref Complex version of L =cut sub PDL::csysv { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsysv if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsysv; } *csysv = \&PDL::csysv; #line 963 "Complex.pm" *__Ccsysvx = \&PDL::__Ccsysvx; *__Ncsysvx = \&PDL::__Ncsysvx; #line 23 "../pp_defc.pl" =head2 csysvx =for sig Signature: (complex [phys]A(n,n); int uplo(); int fact();complex [phys]B(n,m);complex [io,phys]af(n,n); int [io,phys]ipiv(n);complex [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); [t]rwork(n)) =for ref Complex version of L =cut sub PDL::csysvx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsysvx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsysvx; } *csysvx = \&PDL::csysvx; #line 998 "Complex.pm" *__Cchesv = \&PDL::__Cchesv; *__Nchesv = \&PDL::__Nchesv; #line 23 "../pp_defc.pl" =head2 chesv =for sig Signature: (complex [io,phys]A(n,n); int uplo();complex [io,phys]B(n,m); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chesv { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchesv if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchesv; } *chesv = \&PDL::chesv; #line 1033 "Complex.pm" *__Cchesvx = \&PDL::__Cchesvx; *__Nchesvx = \&PDL::__Nchesvx; #line 23 "../pp_defc.pl" =head2 chesvx =for sig Signature: (complex A(n,n); int uplo(); int fact();complex B(n,m);complex [io]af(n,n); int [io]ipiv(n);complex [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); [t]rwork(n)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chesvx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchesvx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchesvx; } *chesvx = \&PDL::chesvx; #line 1068 "Complex.pm" *__Ccposv = \&PDL::__Ccposv; *__Ncposv = \&PDL::__Ncposv; #line 23 "../pp_defc.pl" =head2 cposv =for sig Signature: (complex [io,phys]A(n,n); int uplo();complex [io,phys]B(n,m); int [o,phys]info()) =for ref Complex version of L for Hermitian positive definite matrix =cut sub PDL::cposv { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccposv if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncposv; } *cposv = \&PDL::cposv; #line 1103 "Complex.pm" *__Ccposvx = \&PDL::__Ccposvx; *__Ncposvx = \&PDL::__Ncposvx; #line 23 "../pp_defc.pl" =head2 cposvx =for sig Signature: (complex [io]A(n,n); int uplo(); int fact();complex [io]B(n,m);complex [io]af(n,n); int [io]equed(); [o]s(p);complex [o]X(n,m); [o]rcond(); [o]ferr(m); [o]berr(m); int [o]info(); [t]rwork(rworkn); [t]work(workn)) =for ref Complex version of L for Hermitian positive definite matrix =cut sub PDL::cposvx { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccposvx if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncposvx; } *cposvx = \&PDL::cposvx; #line 1138 "Complex.pm" *__Ccgels = \&PDL::__Ccgels; *__Ncgels = \&PDL::__Ncgels; #line 23 "../pp_defc.pl" =head2 cgels =for sig Signature: (complex [io,phys]A(m,n); int trans();complex [io,phys]B(p,q);int [o,phys]info()) =for ref Solves overdetermined or underdetermined complex linear systems involving an M-by-N matrix A, or its conjugate-transpose. Complex version of L. trans: = 0: the linear system involves A; = 1: the linear system involves A**H. =cut sub PDL::cgels { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgels if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgels; } *cgels = \&PDL::cgels; #line 1178 "Complex.pm" *__Ccgelsy = \&PDL::__Ccgelsy; *__Ncgelsy = \&PDL::__Ncgelsy; #line 23 "../pp_defc.pl" =head2 cgelsy =for sig Signature: (complex [io]A(m,n);complex [io]B(p,q); rcond(); int [io]jpvt(n); int [o]rank();int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cgelsy { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgelsy if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgelsy; } *cgelsy = \&PDL::cgelsy; #line 1213 "Complex.pm" *__Ccgelss = \&PDL::__Ccgelss; *__Ncgelss = \&PDL::__Ncgelss; #line 23 "../pp_defc.pl" =head2 cgelss =for sig Signature: (complex [io]A(m,n);complex [io]B(p,q); rcond(); [o]s(r); int [o]rank();int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cgelss { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgelss if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgelss; } *cgelss = \&PDL::cgelss; #line 1248 "Complex.pm" *__Ccgelsd = \&PDL::__Ccgelsd; *__Ncgelsd = \&PDL::__Ncgelsd; #line 23 "../pp_defc.pl" =head2 cgelsd =for sig Signature: (complex [io]A(m,n);complex [io]B(p,q); rcond(); [o]s(minmn); int [o]rank();int [o]info(); int [t]iwork(iworkn); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cgelsd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgelsd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgelsd; } *cgelsd = \&PDL::cgelsd; #line 1283 "Complex.pm" *__Ccgglse = \&PDL::__Ccgglse; *__Ncgglse = \&PDL::__Ncgglse; #line 23 "../pp_defc.pl" =head2 cgglse =for sig Signature: (complex [phys]A(m,n);complex [phys]B(p,n);complex [io,phys]c(m);complex [phys]d(p);complex [o,phys]x(n);int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgglse { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgglse if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgglse; } *cgglse = \&PDL::cgglse; #line 1318 "Complex.pm" *__Ccggglm = \&PDL::__Ccggglm; *__Ncggglm = \&PDL::__Ncggglm; #line 23 "../pp_defc.pl" =head2 cggglm =for sig Signature: (complex [phys]A(n,m);complex [phys]B(n,p);complex [phys]d(n);complex [o,phys]x(m);complex [o,phys]y(p);int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cggglm { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccggglm if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncggglm; } *cggglm = \&PDL::cggglm; #line 1353 "Complex.pm" *__Ccgetrf = \&PDL::__Ccgetrf; *__Ncgetrf = \&PDL::__Ncgetrf; #line 23 "../pp_defc.pl" =head2 cgetrf =for sig Signature: (complex [io]A(m,n); int [o]ipiv(p); int [o]info()) =for ref Complex version of L =cut sub PDL::cgetrf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgetrf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgetrf; } *cgetrf = \&PDL::cgetrf; #line 1388 "Complex.pm" *__Ccgetf2 = \&PDL::__Ccgetf2; *__Ncgetf2 = \&PDL::__Ncgetf2; #line 23 "../pp_defc.pl" =head2 cgetf2 =for sig Signature: (complex [io]A(m,n); int [o]ipiv(p); int [o]info()) =for ref Complex version of L =cut sub PDL::cgetf2 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgetf2 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgetf2; } *cgetf2 = \&PDL::cgetf2; #line 1423 "Complex.pm" *__Ccsytrf = \&PDL::__Ccsytrf; *__Ncsytrf = \&PDL::__Ncsytrf; #line 23 "../pp_defc.pl" =head2 csytrf =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::csytrf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsytrf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsytrf; } *csytrf = \&PDL::csytrf; #line 1458 "Complex.pm" *__Ccsytf2 = \&PDL::__Ccsytf2; *__Ncsytf2 = \&PDL::__Ncsytf2; #line 23 "../pp_defc.pl" =head2 csytf2 =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int [o,phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::csytf2 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsytf2 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsytf2; } *csytf2 = \&PDL::csytf2; #line 1493 "Complex.pm" *__Ccchetrf = \&PDL::__Ccchetrf; *__Ncchetrf = \&PDL::__Ncchetrf; #line 23 "../pp_defc.pl" =head2 cchetrf =for sig Signature: (complex [io]A(n,n); int uplo(); int [o]ipiv(n); int [o]info(); [t]work(workn)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::cchetrf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccchetrf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncchetrf; } *cchetrf = \&PDL::cchetrf; #line 1528 "Complex.pm" *__Cchetf2 = \&PDL::__Cchetf2; *__Nchetf2 = \&PDL::__Nchetf2; #line 23 "../pp_defc.pl" =head2 chetf2 =for sig Signature: (complex [io]A(n,n); int uplo(); int [o]ipiv(n); int [o]info()) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chetf2 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchetf2 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchetf2; } *chetf2 = \&PDL::chetf2; #line 1563 "Complex.pm" *__Ccpotrf = \&PDL::__Ccpotrf; *__Ncpotrf = \&PDL::__Ncpotrf; #line 23 "../pp_defc.pl" =head2 cpotrf =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int [o,phys]info()) =for ref Complex version of L for Hermitian positive definite matrix =cut sub PDL::cpotrf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccpotrf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncpotrf; } *cpotrf = \&PDL::cpotrf; #line 1598 "Complex.pm" *__Ccpotf2 = \&PDL::__Ccpotf2; *__Ncpotf2 = \&PDL::__Ncpotf2; #line 23 "../pp_defc.pl" =head2 cpotf2 =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int [o,phys]info()) =for ref Complex version of L for Hermitian positive definite matrix =cut sub PDL::cpotf2 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccpotf2 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncpotf2; } *cpotf2 = \&PDL::cpotf2; #line 1633 "Complex.pm" *__Ccgetri = \&PDL::__Ccgetri; *__Ncgetri = \&PDL::__Ncgetri; #line 23 "../pp_defc.pl" =head2 cgetri =for sig Signature: (complex [io,phys]A(n,n); int [phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgetri { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgetri if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgetri; } *cgetri = \&PDL::cgetri; #line 1668 "Complex.pm" *__Ccsytri = \&PDL::__Ccsytri; *__Ncsytri = \&PDL::__Ncsytri; #line 23 "../pp_defc.pl" =head2 csytri =for sig Signature: (complex [io]A(n,n); int uplo(); int ipiv(n); int [o]info(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::csytri { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsytri if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsytri; } *csytri = \&PDL::csytri; #line 1703 "Complex.pm" *__Cchetri = \&PDL::__Cchetri; *__Nchetri = \&PDL::__Nchetri; #line 23 "../pp_defc.pl" =head2 chetri =for sig Signature: (complex [io]A(n,n); int uplo(); int ipiv(n); int [o]info(); [t]work(workn)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chetri { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchetri if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchetri; } *chetri = \&PDL::chetri; #line 1738 "Complex.pm" *__Ccpotri = \&PDL::__Ccpotri; *__Ncpotri = \&PDL::__Ncpotri; #line 23 "../pp_defc.pl" =head2 cpotri =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cpotri { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccpotri if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncpotri; } *cpotri = \&PDL::cpotri; #line 1773 "Complex.pm" *__Cctrtri = \&PDL::__Cctrtri; *__Nctrtri = \&PDL::__Nctrtri; #line 23 "../pp_defc.pl" =head2 ctrtri =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int diag(); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::ctrtri { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrtri if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrtri; } *ctrtri = \&PDL::ctrtri; #line 1808 "Complex.pm" *__Cctrti2 = \&PDL::__Cctrti2; *__Nctrti2 = \&PDL::__Nctrti2; #line 23 "../pp_defc.pl" =head2 ctrti2 =for sig Signature: (complex [io,phys]A(n,n); int uplo(); int diag(); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::ctrti2 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrti2 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrti2; } *ctrti2 = \&PDL::ctrti2; #line 1843 "Complex.pm" *__Ccgetrs = \&PDL::__Ccgetrs; *__Ncgetrs = \&PDL::__Ncgetrs; #line 23 "../pp_defc.pl" =head2 cgetrs =for sig Signature: (complex [phys]A(n,n); int trans();complex [io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L Arguments ========= trans: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; =cut sub PDL::cgetrs { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgetrs if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgetrs; } *cgetrs = \&PDL::cgetrs; #line 1884 "Complex.pm" *__Ccsytrs = \&PDL::__Ccsytrs; *__Ncsytrs = \&PDL::__Ncsytrs; #line 23 "../pp_defc.pl" =head2 csytrs =for sig Signature: (complex [phys]A(n,n); int uplo();complex [io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::csytrs { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsytrs if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsytrs; } *csytrs = \&PDL::csytrs; #line 1919 "Complex.pm" *__Cchetrs = \&PDL::__Cchetrs; *__Nchetrs = \&PDL::__Nchetrs; #line 23 "../pp_defc.pl" =head2 chetrs =for sig Signature: (complex [phys]A(n,n); int uplo();complex [io,phys]B(n,m); int [phys]ipiv(n); int [o,phys]info()) =for ref Complex version of L for Hermitian matrix =cut sub PDL::chetrs { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchetrs if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchetrs; } *chetrs = \&PDL::chetrs; #line 1954 "Complex.pm" *__Ccpotrs = \&PDL::__Ccpotrs; *__Ncpotrs = \&PDL::__Ncpotrs; #line 23 "../pp_defc.pl" =head2 cpotrs =for sig Signature: (complex [phys]A(n,n); int uplo();complex [io,phys]B(n,m); int [o,phys]info()) =for ref Complex version of L for Hermitian positive definite matrix =cut sub PDL::cpotrs { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccpotrs if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncpotrs; } *cpotrs = \&PDL::cpotrs; #line 1989 "Complex.pm" *__Cctrtrs = \&PDL::__Cctrtrs; *__Nctrtrs = \&PDL::__Nctrtrs; #line 23 "../pp_defc.pl" =head2 ctrtrs =for sig Signature: (complex [phys]A(n,n); int uplo(); int trans(); int diag();complex [io,phys]B(n,m); int [o,phys]info()) =for ref Complex version of L Arguments ========= trans: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; =cut sub PDL::ctrtrs { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrtrs if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrtrs; } *ctrtrs = \&PDL::ctrtrs; #line 2030 "Complex.pm" *__Cclatrs = \&PDL::__Cclatrs; *__Nclatrs = \&PDL::__Nclatrs; #line 23 "../pp_defc.pl" =head2 clatrs =for sig Signature: (complex [phys]A(n,n); int uplo(); int trans(); int diag(); int normin();complex [io,phys]x(n); [o,phys]scale();[io,phys]cnorm(n);int [o,phys]info()) =for ref Complex version of L Arguments ========= trans: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; =cut sub PDL::clatrs { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cclatrs if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nclatrs; } *clatrs = \&PDL::clatrs; #line 2071 "Complex.pm" *__Ccgecon = \&PDL::__Ccgecon; *__Ncgecon = \&PDL::__Ncgecon; #line 23 "../pp_defc.pl" =head2 cgecon =for sig Signature: (complex A(n,n); int norm(); anorm(); [o]rcond();int [o]info(); [t]rwork(rworkn); [t]work(workn)) =for ref Complex version of L =cut sub PDL::cgecon { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgecon if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgecon; } *cgecon = \&PDL::cgecon; #line 2106 "Complex.pm" *__Ccsycon = \&PDL::__Ccsycon; *__Ncsycon = \&PDL::__Ncsycon; #line 23 "../pp_defc.pl" =head2 csycon =for sig Signature: (complex A(n,n); int uplo(); int ipiv(n); anorm(); [o]rcond();int [o]info(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::csycon { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsycon if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsycon; } *csycon = \&PDL::csycon; #line 2141 "Complex.pm" *__Cchecon = \&PDL::__Cchecon; *__Nchecon = \&PDL::__Nchecon; #line 23 "../pp_defc.pl" =head2 checon =for sig Signature: (complex A(n,n); int uplo(); int ipiv(n); anorm(); [o]rcond();int [o]info(); [t]work(workn)) =for ref Complex version of L for Hermitian matrix =cut sub PDL::checon { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchecon if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchecon; } *checon = \&PDL::checon; #line 2176 "Complex.pm" *__Ccpocon = \&PDL::__Ccpocon; *__Ncpocon = \&PDL::__Ncpocon; #line 23 "../pp_defc.pl" =head2 cpocon =for sig Signature: (complex A(n,n); int uplo(); anorm(); [o]rcond();int [o]info(); [t]work(workn); [t]rwork(n)) =for ref Complex version of L for Hermitian positive definite matrix =cut sub PDL::cpocon { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccpocon if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncpocon; } *cpocon = \&PDL::cpocon; #line 2211 "Complex.pm" *__Cctrcon = \&PDL::__Cctrcon; *__Nctrcon = \&PDL::__Nctrcon; #line 23 "../pp_defc.pl" =head2 ctrcon =for sig Signature: (complex A(n,n); int norm();int uplo();int diag(); [o]rcond();int [o]info(); [t]work(workn); [t]rwork(n)) =for ref Complex version of L =cut sub PDL::ctrcon { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrcon if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrcon; } *ctrcon = \&PDL::ctrcon; #line 2246 "Complex.pm" *__Ccgeqp3 = \&PDL::__Ccgeqp3; *__Ncgeqp3 = \&PDL::__Ncgeqp3; #line 23 "../pp_defc.pl" =head2 cgeqp3 =for sig Signature: (complex [io]A(m,n); int [io]jpvt(n);complex [o]tau(k); int [o]info(); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::cgeqp3 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeqp3 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeqp3; } *cgeqp3 = \&PDL::cgeqp3; #line 2281 "Complex.pm" *__Ccgeqrf = \&PDL::__Ccgeqrf; *__Ncgeqrf = \&PDL::__Ncgeqrf; #line 23 "../pp_defc.pl" =head2 cgeqrf =for sig Signature: (complex [io,phys]A(m,n);complex [o,phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgeqrf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeqrf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeqrf; } *cgeqrf = \&PDL::cgeqrf; #line 2316 "Complex.pm" *__Ccungqr = \&PDL::__Ccungqr; *__Ncungqr = \&PDL::__Ncungqr; #line 23 "../pp_defc.pl" =head2 cungqr =for sig Signature: (complex [io,phys]A(m,n);complex [phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cungqr { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccungqr if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncungqr; } *cungqr = \&PDL::cungqr; #line 2351 "Complex.pm" *__Ccunmqr = \&PDL::__Ccunmqr; *__Ncunmqr = \&PDL::__Ncunmqr; #line 23 "../pp_defc.pl" =head2 cunmqr =for sig Signature: (complex [phys]A(p,k); int side(); int trans();complex [phys]tau(k);complex [io,phys]C(m,n);int [o,phys]info()) =for ref Complex version of L. Here trans = 1 means conjugate transpose. =cut sub PDL::cunmqr { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunmqr if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunmqr; } *cunmqr = \&PDL::cunmqr; #line 2386 "Complex.pm" *__Ccgelqf = \&PDL::__Ccgelqf; *__Ncgelqf = \&PDL::__Ncgelqf; #line 23 "../pp_defc.pl" =head2 cgelqf =for sig Signature: (complex [io,phys]A(m,n);complex [o,phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgelqf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgelqf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgelqf; } *cgelqf = \&PDL::cgelqf; #line 2421 "Complex.pm" *__Ccunglq = \&PDL::__Ccunglq; *__Ncunglq = \&PDL::__Ncunglq; #line 23 "../pp_defc.pl" =head2 cunglq =for sig Signature: (complex [io,phys]A(m,n);complex [phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cunglq { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunglq if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunglq; } *cunglq = \&PDL::cunglq; #line 2456 "Complex.pm" *__Ccunmlq = \&PDL::__Ccunmlq; *__Ncunmlq = \&PDL::__Ncunmlq; #line 23 "../pp_defc.pl" =head2 cunmlq =for sig Signature: (complex [phys]A(k,p); int side(); int trans();complex [phys]tau(k);complex [io,phys]C(m,n);int [o,phys]info()) =for ref Complex version of L. Here trans = 1 means conjugate transpose. =cut sub PDL::cunmlq { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunmlq if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunmlq; } *cunmlq = \&PDL::cunmlq; #line 2491 "Complex.pm" *__Ccgeqlf = \&PDL::__Ccgeqlf; *__Ncgeqlf = \&PDL::__Ncgeqlf; #line 23 "../pp_defc.pl" =head2 cgeqlf =for sig Signature: (complex [io,phys]A(m,n);complex [o,phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgeqlf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgeqlf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgeqlf; } *cgeqlf = \&PDL::cgeqlf; #line 2526 "Complex.pm" *__Ccungql = \&PDL::__Ccungql; *__Ncungql = \&PDL::__Ncungql; #line 23 "../pp_defc.pl" =head2 cungql =for sig Signature: (complex [io,phys]A(m,n);complex [phys]tau(k); int [o,phys]info()) =for ref Complex version of L. =cut sub PDL::cungql { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccungql if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncungql; } *cungql = \&PDL::cungql; #line 2560 "Complex.pm" *__Ccunmql = \&PDL::__Ccunmql; *__Ncunmql = \&PDL::__Ncunmql; #line 23 "../pp_defc.pl" =head2 cunmql =for sig Signature: (complex [phys]A(p,k); int side(); int trans();complex [phys]tau(k);complex [io,phys]C(m,n);int [o,phys]info()) =for ref Complex version of L. Here trans = 1 means conjugate transpose. =cut sub PDL::cunmql { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunmql if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunmql; } *cunmql = \&PDL::cunmql; #line 2595 "Complex.pm" *__Ccgerqf = \&PDL::__Ccgerqf; *__Ncgerqf = \&PDL::__Ncgerqf; #line 23 "../pp_defc.pl" =head2 cgerqf =for sig Signature: (complex [io,phys]A(m,n);complex [o,phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgerqf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgerqf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgerqf; } *cgerqf = \&PDL::cgerqf; #line 2630 "Complex.pm" *__Ccungrq = \&PDL::__Ccungrq; *__Ncungrq = \&PDL::__Ncungrq; #line 23 "../pp_defc.pl" =head2 cungrq =for sig Signature: (complex [io,phys]A(m,n);complex [phys]tau(k); int [o,phys]info()) =for ref Complex version of L. =cut sub PDL::cungrq { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccungrq if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncungrq; } *cungrq = \&PDL::cungrq; #line 2665 "Complex.pm" *__Ccunmrq = \&PDL::__Ccunmrq; *__Ncunmrq = \&PDL::__Ncunmrq; #line 23 "../pp_defc.pl" =head2 cunmrq =for sig Signature: (complex [phys]A(k,p); int side(); int trans();complex [phys]tau(k);complex [io,phys]C(m,n);int [o,phys]info()) =for ref Complex version of L. Here trans = 1 means conjugate transpose. =cut sub PDL::cunmrq { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunmrq if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunmrq; } *cunmrq = \&PDL::cunmrq; #line 2700 "Complex.pm" *__Cctzrzf = \&PDL::__Cctzrzf; *__Nctzrzf = \&PDL::__Nctzrzf; #line 23 "../pp_defc.pl" =head2 ctzrzf =for sig Signature: (complex [io,phys]A(m,n);complex [o,phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::ctzrzf { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctzrzf if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctzrzf; } *ctzrzf = \&PDL::ctzrzf; #line 2735 "Complex.pm" *__Ccunmrz = \&PDL::__Ccunmrz; *__Ncunmrz = \&PDL::__Ncunmrz; #line 23 "../pp_defc.pl" =head2 cunmrz =for sig Signature: (complex [phys]A(k,p); int side(); int trans();complex [phys]tau(k);complex [io,phys]C(m,n);int [o,phys]info()) =for ref Complex version of L. Here trans = 1 means conjugate transpose. =cut sub PDL::cunmrz { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunmrz if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunmrz; } *cunmrz = \&PDL::cunmrz; #line 2770 "Complex.pm" *__Ccgehrd = \&PDL::__Ccgehrd; *__Ncgehrd = \&PDL::__Ncgehrd; #line 23 "../pp_defc.pl" =head2 cgehrd =for sig Signature: (complex [io,phys]A(n,n); int [phys]ilo();int [phys]ihi();complex [o,phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgehrd { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgehrd if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgehrd; } *cgehrd = \&PDL::cgehrd; #line 2805 "Complex.pm" *__Ccunghr = \&PDL::__Ccunghr; *__Ncunghr = \&PDL::__Ncunghr; #line 23 "../pp_defc.pl" =head2 cunghr =for sig Signature: (complex [io,phys]A(n,n); int [phys]ilo();int [phys]ihi();complex [phys]tau(k); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cunghr { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccunghr if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncunghr; } *cunghr = \&PDL::cunghr; #line 2840 "Complex.pm" *__Cchseqr = \&PDL::__Cchseqr; *__Nchseqr = \&PDL::__Nchseqr; #line 23 "../pp_defc.pl" =head2 chseqr =for sig Signature: (complex [io,phys]H(n,n); int job();int compz();int [phys]ilo();int [phys]ihi();complex [o,phys]w(n);complex [o,phys]Z(m,m); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::chseqr { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cchseqr if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nchseqr; } *chseqr = \&PDL::chseqr; #line 2875 "Complex.pm" *__Cctrevc = \&PDL::__Cctrevc; *__Nctrevc = \&PDL::__Nctrevc; #line 23 "../pp_defc.pl" =head2 ctrevc =for sig Signature: (complex [io]T(n,n); int side();int howmny();int select(q);complex [o]VL(m,m);complex [o]VR(p,p);int [o]m(); int [o]info(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::ctrevc { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctrevc if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctrevc; } *ctrevc = \&PDL::ctrevc; #line 2910 "Complex.pm" *__Cctgevc = \&PDL::__Cctgevc; *__Nctgevc = \&PDL::__Nctgevc; #line 23 "../pp_defc.pl" =head2 ctgevc =for sig Signature: (complex [io]A(n,n); int side();int howmny();complex [io]B(n,n);int select(q);complex [o]VL(m,m);complex [o]VR(p,p);int [o]m(); int [o]info(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::ctgevc { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cctgevc if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nctgevc; } *ctgevc = \&PDL::ctgevc; #line 2945 "Complex.pm" *__Ccgebal = \&PDL::__Ccgebal; *__Ncgebal = \&PDL::__Ncgebal; #line 23 "../pp_defc.pl" =head2 cgebal =for sig Signature: (complex [io,phys]A(n,n); int job(); int [o,phys]ilo();int [o,phys]ihi();[o,phys]scale(n); int [o,phys]info()) =for ref Complex version of L =cut sub PDL::cgebal { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgebal if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgebal; } *cgebal = \&PDL::cgebal; #line 2980 "Complex.pm" *__Cclange = \&PDL::__Cclange; *__Nclange = \&PDL::__Nclange; #line 23 "../pp_defc.pl" =head2 clange =for sig Signature: (complex A(n,m); int norm(); [o]b(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::clange { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cclange if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nclange; } *clange = \&PDL::clange; #line 3015 "Complex.pm" *__Cclansy = \&PDL::__Cclansy; *__Nclansy = \&PDL::__Nclansy; #line 23 "../pp_defc.pl" =head2 clansy =for sig Signature: (complex A(n,n); int uplo(); int norm(); [o]b(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::clansy { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cclansy if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nclansy; } *clansy = \&PDL::clansy; #line 3050 "Complex.pm" *__Cclantr = \&PDL::__Cclantr; *__Nclantr = \&PDL::__Nclantr; #line 23 "../pp_defc.pl" =head2 clantr =for sig Signature: (complex A(m,n); int uplo(); int norm();int diag(); [o]b(); [t]work(workn)) =for ref Complex version of L =cut sub PDL::clantr { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cclantr if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nclantr; } *clantr = \&PDL::clantr; #line 3085 "Complex.pm" *__Ccgemm = \&PDL::__Ccgemm; *__Ncgemm = \&PDL::__Ncgemm; #line 23 "../pp_defc.pl" =head2 cgemm =for sig Signature: (complex [phys]A(m,n); int transa(); int transb();complex [phys]B(p,q);complex [phys]alpha();complex [phys]beta();complex [io,phys]C(r,s)) =for ref Complex version of L. Arguments ========= transa: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; transb: = 0: No transpose; = 1: Transpose; = 2: Conjugate transpose; =cut sub PDL::cgemm { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccgemm if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncgemm; } *cgemm = \&PDL::cgemm; #line 3130 "Complex.pm" *__Ccmmult = \&PDL::__Ccmmult; *__Ncmmult = \&PDL::__Ncmmult; #line 23 "../pp_defc.pl" =head2 cmmult =for sig Signature: (complex [phys]A(m,n);complex [phys]B(p,m);complex [o,phys]C(p,n)) =for ref Complex version of L =cut sub PDL::cmmult { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccmmult if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncmmult; } *cmmult = \&PDL::cmmult; #line 3165 "Complex.pm" *__Cccrossprod = \&PDL::__Cccrossprod; *__Nccrossprod = \&PDL::__Nccrossprod; #line 23 "../pp_defc.pl" =head2 ccrossprod =for sig Signature: (complex [phys]A(n,m);complex [phys]B(p,m);complex [o,phys]C(p,n)) =for ref Complex version of L =cut sub PDL::ccrossprod { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cccrossprod if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nccrossprod; } *ccrossprod = \&PDL::ccrossprod; #line 3200 "Complex.pm" *__Ccsyrk = \&PDL::__Ccsyrk; *__Ncsyrk = \&PDL::__Ncsyrk; #line 23 "../pp_defc.pl" =head2 csyrk =for sig Signature: (complex [phys]A(m,n); int uplo(); int trans();complex [phys]alpha();complex [phys]beta();complex [io,phys]C(p,p)) =for ref Complex version of L =cut sub PDL::csyrk { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsyrk if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsyrk; } *csyrk = \&PDL::csyrk; #line 3235 "Complex.pm" *__Ccdot = \&PDL::__Ccdot; *__Ncdot = \&PDL::__Ncdot; #line 23 "../pp_defc.pl" =head2 cdot =for sig Signature: (complex [phys]a(n);complex [phys]b(n);complex [o]c()) =for ref Complex version of L =cut sub PDL::cdot { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccdot if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncdot; } *cdot = \&PDL::cdot; #line 3270 "Complex.pm" *__Ccdotc = \&PDL::__Ccdotc; *__Ncdotc = \&PDL::__Ncdotc; #line 23 "../pp_defc.pl" =head2 cdotc =for sig Signature: (complex [phys]a(n);complex [phys]b(n);complex [o,phys]c()) =for ref Forms the dot product of two vectors, conjugating the first vector. =cut sub PDL::cdotc { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccdotc if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncdotc; } *cdotc = \&PDL::cdotc; #line 3306 "Complex.pm" *__Ccaxpy = \&PDL::__Ccaxpy; *__Ncaxpy = \&PDL::__Ncaxpy; #line 23 "../pp_defc.pl" =head2 caxpy =for sig Signature: (complex [phys]a(n);complex [phys] alpha();complex [io,phys]b(n)) =for ref Complex version of L =cut sub PDL::caxpy { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccaxpy if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncaxpy; } *caxpy = \&PDL::caxpy; #line 3341 "Complex.pm" *__Ccnrm2 = \&PDL::__Ccnrm2; *__Ncnrm2 = \&PDL::__Ncnrm2; #line 23 "../pp_defc.pl" =head2 cnrm2 =for sig Signature: (complex [phys]a(n);[o]b()) =for ref Complex version of L =cut sub PDL::cnrm2 { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccnrm2 if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncnrm2; } *cnrm2 = \&PDL::cnrm2; #line 3376 "Complex.pm" *__Ccasum = \&PDL::__Ccasum; *__Ncasum = \&PDL::__Ncasum; #line 23 "../pp_defc.pl" =head2 casum =for sig Signature: (complex [phys]a(n);[o]b()) =for ref Complex version of L =cut sub PDL::casum { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccasum if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncasum; } *casum = \&PDL::casum; #line 3411 "Complex.pm" *__Ccscal = \&PDL::__Ccscal; *__Ncscal = \&PDL::__Ncscal; #line 23 "../pp_defc.pl" =head2 cscal =for sig Signature: (complex [io,phys]a(n);complex scale()) =for ref Complex version of L =cut sub PDL::cscal { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccscal if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncscal; } *cscal = \&PDL::cscal; #line 3446 "Complex.pm" *__Ccsscal = \&PDL::__Ccsscal; *__Ncsscal = \&PDL::__Ncsscal; #line 23 "../pp_defc.pl" =head2 csscal =for sig Signature: (complex [io,phys]a(n);scale()) =for ref Scales a complex vector by a real constant. =cut sub PDL::csscal { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccsscal if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncsscal; } *csscal = \&PDL::csscal; #line 3481 "Complex.pm" *__Ccrotg = \&PDL::__Ccrotg; *__Ncrotg = \&PDL::__Ncrotg; #line 23 "../pp_defc.pl" =head2 crotg =for sig Signature: (complex [io,phys]a();complex [phys]b();[o,phys]c();complex [o,phys]s()) =for ref Complex version of L =cut sub PDL::crotg { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Ccrotg if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Ncrotg; } *crotg = \&PDL::crotg; #line 3516 "Complex.pm" *__Cclacpy = \&PDL::__Cclacpy; *__Nclacpy = \&PDL::__Nclacpy; #line 23 "../pp_defc.pl" =head2 clacpy =for sig Signature: (complex [phys]A(m,n); int uplo();complex [o,phys]B(p,n)) =for ref Complex version of L =cut sub PDL::clacpy { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cclacpy if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nclacpy; } *clacpy = \&PDL::clacpy; #line 3551 "Complex.pm" *__Cclaswp = \&PDL::__Cclaswp; *__Nclaswp = \&PDL::__Nclaswp; #line 23 "../pp_defc.pl" =head2 claswp =for sig Signature: (complex [io,phys]A(m,n); int [phys]k1(); int [phys]k2(); int [phys]ipiv(p)) =for ref Complex version of L =cut sub PDL::claswp { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cclaswp if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nclaswp; } *claswp = \&PDL::claswp; #line 3586 "Complex.pm" *ctricpy = \&PDL::ctricpy; =head2 cmstack =for sig Signature: (x(c,n,m);y(c,n,p);[o]out(c,n,q)) =for ref Combine two 3D ndarrays into a single ndarray. This routine does backward and forward dataflow automatically. =for bad cmstack does not process bad values. It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays. =cut *cmstack = \&PDL::cmstack; *__Cccharpol = \&PDL::__Cccharpol; *__Nccharpol = \&PDL::__Nccharpol; #line 23 "../pp_defc.pl" =head2 ccharpol =for sig Signature: (A(c=2,n,n);[o]Y(c=2,n,n);[o]out(c=2,p); [t]rwork(rworkn)) =for ref Complex version of L =cut sub PDL::ccharpol { barf "Cannot mix PDL::Complex and native-complex" if (grep ref($_) eq 'PDL::Complex', @_) and (grep UNIVERSAL::isa($_, 'PDL') && !$_->type->real, @_); goto &PDL::__Cccharpol if grep ref($_) eq 'PDL::Complex', @_; goto &PDL::__Nccharpol; } *ccharpol = \&PDL::ccharpol; #line 5093 "complex.pd" =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut #line 3666 "Complex.pm" # Exit with OK status 1; PDL-LinearAlgebra-0.38/META.yml0000644000175000017500000000153214565105646015765 0ustar osboxesosboxes--- abstract: 'PDL bindings to some BLAS and LAPACK library routines' author: - 'Grégory Vanuxem ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '0.88' configure_requires: Devel::CheckLib: '0' ExtUtils::F77: '1.26' PDL: '2.078' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.44, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: PDL-LinearAlgebra no_index: directory: - t - inc requires: PDL: '2.078' resources: bugtracker: https://github.com/PDLPorters/pdl-linearalgebra/issues homepage: http://pdl.perl.org/ repository: git://github.com/PDLPorters/pdl-linearalgebra.git version: '0.38' x_IRC: irc://irc.perl.org/#pdl x_serialization_backend: 'CPAN::Meta::YAML version 0.018' PDL-LinearAlgebra-0.38/Changes0000644000175000017500000001127514565105373016011 0ustar osboxesosboxes0.38 2024-02-24 - tricpy now supports native-complex types - tricpy now defaults to upper - thanks @jo-37 0.37 2023-04-01 - install pdldoc using PDL::Doc 0.36 2023-03-29 - memory-manage CODE-refs properly to work with PDL 2.083+ 0.35 2022-07-17 - fix `$real x $native_complex` (#18) - thanks @KJ7LNW for report 0.34 2022-07-17 - improve LAPACK detection on Linux - thanks @KJ7LNW 0.33 2022-07-14 - test, fix mtoeplitz (#16) - thanks @jjatria for report 0.32 2022-05-06 - fix to work again with MacOS by stripping unknown libraries 0.31 2022-05-06 - fix to work with Strawberry Perl 5.28's LAPACK (#14) - thanks @aero for report 0.30 2022-05-02 - fix mpow to work with power 0 - https://perlmonks.org/?node_id=1229396 0.29 2022-04-10 - fix mnull reporting different solution on Windows - thanks @aero for CPANTesters report - remove PDL::Complex method aliases now in PDL 2.078 0.28 2022-04-09 - allow alternative values for complex U in mschur (#12) - thanks @sebastic for report - use C macro "FORTRAN()" to hide whether need _ on end of symbols - use [t] Pars instead of malloc for fixed-size workspace 0.27 2022-04-06 - now 64-bit safe - t, issym, tritosym method for complex now defaults to not conjugate - various memory-management bugs fixed - PDL::Complex::tricpy now alias to ctricpy - provide override xerbla_ to not insta-exit on bad input (works with OpenBLAS and reference LAPACK, not ATLAS) - msolve etc now handle native-complex (#10) - thanks @guillepo for report 0.26 2021-11-14 - Reversible now called TwoWay 0.25 2021-10-02 - separate out {Real,Complex,Trans}/selectfunc.c - opt in to upcoming PDL multi-C feature 0.24 2021-10-01 - change $PRIV() to $COMP() 0.23 2021-09-25 - fix mdet acting on complex matrices - thanks @wlmb 0.22 2021-09-15 - switch from $PRIV(__x_size) to $SIZE(x) 0.21 2021-08-12 - fix test bug under at least 5.14.1 that had test compare complex numbers 0.20 2021-05-30 - also export mpinv - fix RedoDimsCode for native-complex - fix matrix-multiplication overload to work with native-complex 0.19 2021-05-24 - change to PDL 2.047 with native complex i() 0.18 2021-05-03 - stop loading PDL::Complex and overriding PDL:: functions 0.17 2021-04-01 - handle native complex data 0.16 2021-03-23 - fix pp_setversion calls now that preserves string 0.15 2021-03-04 - add [c]gtsv functions 0.14 2019-12-09 - updated build-file perms - thanks @manwar - support Lapack >= 3.7.0 - thanks Grégory Vanuxem 0.13 2019-11-10 - updated metadata to point to GitHub 0.12 Mon Jun 8 10:42:52 EDT 2015 * Fix last 'package PDL::Complex' * Add 'clean' option to remove *~ files 0.11 * Hide PDL and PDL::Complex package declarations from PAUSE/CPAN indexer 0.10 * Add -lquadmath to compiler flags for gfortran 0.09 * Use new GENERATE feature to make POD from PP files * Use correct meta-spec for META_MERGE * Require constant 1.03 - older version do not work with hashes. 0.08_03 * Test of KMX patch to Makefile.PL for better docs on metacpan.org and search.cpan.org * Improved library detection for SPP PDL edition 0.08_02 * Test of KMX patch to Makefile.PL 0.08_01 * Add AUTHOR and ABSTRACT info to Makefile.PL * Apply patch from CPAN RT bug #38167 * Fix encoding specs for POD 0.08 Tue Dec 3 06:07:55 EST 2013 * use VERSION_FROM in Makefile.PLs * update license to Artistic 2.0 * bump VERSION to 0.08 for official release 0.07_01 Sat Nov 30 18:17:48 EST 2013 * fixed bug in msyminv() * global conversion from DOS to UNIX line endings * explicitly specifying a Latin-1 encoding in the PODs * removed debianization. This package is already in debian * partial clean up of $VERSION specification 0.07 Wed Nov 27 17:09:40 EST 2013 * Official release with 1st PDL-2.007 support 0.06_02 Wed Nov 27 14:19:17 EST 2013 * fix CPAN dependency info so PDL is used for config 0.06_01 Sun Nov 17 11:21:52 2013 * update build to work with new PDL_Indx data type 0.06 Thu Oct 09 00:00:00 2007 * remove conflicting cplx routine (thanks to P. Dupre) * remove prototype of sec 0.05 Fri Aug 17 00:00:00 2007 * version information fixes 0.04 Thu Aug 16 00:00:00 2007 * mnorm fix (complex) * mfun fix (inplace operations are not supported on upstream PDL::Complex (PDL <= 2.4.3) * remove stringizing routine for PDL::Complex (in upstream now PDL >= 2.4.3) add format variables (forgotten in upstream PDL 2.4.3) * sumover for PDL::Complex fix (dims < 2) * documentation improvements and fixes 0.03 Mon Sep 12 18:05:15 2005 * documentation corrections 0.02 Wed Aug 24 13:39:15 2005 * mnorm threading * new routine mrcond * documentation corrections * add PDL.pm in prerequities (Makefile.PL) 0.01 Mon Aug 15 14:57:24 2005 * Initial release PDL-LinearAlgebra-0.38/lib/0000755000175000017500000000000014565105646015261 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/lib/PDL/0000755000175000017500000000000014565105646015700 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/lib/PDL/LinearAlgebra.pm0000644000175000017500000031016014565105320020714 0ustar osboxesosboxespackage PDL::LinearAlgebra; use PDL::Ops; use PDL::Core; use PDL::Basic qw/sequence/; use PDL::Primitive qw/which which_both/; use PDL::Ufunc qw/sumover/; use PDL::NiceSlice; use PDL::Slices; use PDL::LinearAlgebra::Real; use PDL::LinearAlgebra::Complex; use PDL::LinearAlgebra::Special qw//; use PDL::Exporter; no warnings 'uninitialized'; use constant { NO => 0, WARN => 1, BARF => 2, }; use strict; our $VERSION = '0.38'; $VERSION = eval $VERSION; @PDL::LinearAlgebra::ISA = qw/PDL::Exporter/; @PDL::LinearAlgebra::EXPORT_OK = qw/t diag issym minv mtriinv msyminv mposinv mdet mposdet mrcond positivise mdsvd msvd mgsvd mpinv mlu mhessen mchol mqr mql mlq mrq meigen meigenx mgeigen mgeigenx msymeigen msymeigenx msymgeigen msymgeigenx msolve mtrisolve msymsolve mpossolve msolvex msymsolvex mpossolvex mrank mlls mllsy mllss mglm mlse tritosym mnorm mgschur mgschurx mcrossprod mcond morth mschur mschurx NO WARN BARF setlaerror getlaerorr laerror/; %PDL::LinearAlgebra::EXPORT_TAGS = (Func=>[@PDL::LinearAlgebra::EXPORT_OK]); my $_laerror = BARF; { package # hide from CPAN indexer PDL::Complex; our $floatformat = "%4.4g"; # Default print format for long numbers our $doubleformat = "%6.6g"; our @ISA = @ISA ? @ISA : 'PDL'; # so still operates when no PDL::Complex *tricpy = \&PDL::LinearAlgebra::Complex::ctricpy; } ######################################################################## =encoding utf8 =head1 NAME PDL::LinearAlgebra - Linear Algebra utils for PDL =head1 SYNOPSIS use PDL::LinearAlgebra; $a = random (100,100); ($U, $s, $V) = mdsvd($a); =head1 DESCRIPTION This module provides a convenient interface to L and L. Since Blas and Lapack use a column major ordering scheme some routines here need to transpose matrices before calling fortran routines and transpose back (see the documentation of each routine). If you need optimized code use directly L and L. =cut =head1 FUNCTIONS =head2 setlaerror =for ref Sets action type when an error is encountered, returns previous type. Available values are NO, WARN and BARF (predefined constants). If, for example, in computation of the inverse, singularity is detected, the routine can silently return values from computation (see manuals), warn about singularity or barf. BARF is the default value. =for example # h : x -> g(f(x)) $a = sequence(5,5); $err = setlaerror(NO); ($b, $info)= f($a); setlaerror($err); $info ? barf "can't compute h" : return g($b); =cut sub setlaerror($){ my $err = $_laerror; $_laerror = shift; $err; } =head2 getlaerror =for ref Gets action type when an error is encountered. 0 => NO, 1 => WARN, 2 => BARF =cut sub getlaerror{ $_laerror; } sub laerror{ return unless $_laerror; if ($_laerror < 2){ warn "$_[0]\n"; } else{ barf "$_[0]\n"; } } =head2 t =for usage PDL = t(PDL, SCALAR(conj)) conj : Conjugate Transpose = 1 | Transpose = 0, default = 0; =for ref Convenient function for transposing real or complex 2D array(s). For complex data, if conj is true returns conjugate transposed array(s) and doesn't support dataflow. Supports threading. =cut sub PDL::dims_internal {0} sub PDL::dims_internal_values {()} sub PDL::Complex::dims_internal {1} sub PDL::Complex::dims_internal_values {(2)} sub PDL::_similar { my @di_vals = $_[0]->dims_internal_values; my ($m, @vdims) = @_; ref($m)->new_from_specification($m->type, @di_vals, @vdims); } sub PDL::_similar_null { ref($_[0])->null } sub _complex_null { (defined &PDL::Complex::new_from_specification ? 'PDL::Complex' : 'PDL')->null } sub _ecplx { my ($re, $im) = @_; $re = PDL->topdl($re); return $re if UNIVERSAL::isa($re,'PDL::Complex') or !$re->type->real; Carp::confess("Usage: _ecplx(re,im) or (complex)") if !defined $im; $im = PDL->topdl($im); return $re->czip($im) if !defined &PDL::Complex::new_from_specification; my $ret = PDL::Complex->new_from_specification($re->type, 2, $re->dims); $ret->slice('(0),') .= $re; $ret->slice('(1),') .= $im; return $ret; } sub PDL::_is_complex { !$_[0]->type->real } sub PDL::Complex::_is_complex {1} sub PDL::_norm { my ($m, $real, $trans) = @_; # If trans == true => transpose output matrix # If real == true => rotate (complex as a vector) # such that max abs will be real my $ret = PDL::LinearAlgebra::Complex::cnrm2($m); return ($trans ? $m->t/$ret->dummy(0)->t : $m/$ret->dummy(0))->reshape(-1) if !$real; $m = ($m/$ret->dummy(0))->reshape(-1); my $index = $m->abs->maximum_ind; my $scale = $m->mv(0,-1)->index($index)->mv(-1,0); $scale = $scale->conj/$scale->abs; return $trans ? $m->t*$scale->dummy(2) : $m*$scale->dummy(2)->t; } *t = \&PDL::t; sub PDL::t { my $d = $_[0]->dims_internal; my ($m, $conj) = @_; my $r = ($m->dims > $d+1) ? $m->xchg($d,$d+1) : $m->dummy($d); $conj ? $r->conj : $r; } =head2 issym =for usage PDL = issym(PDL, SCALAR|PDL(tol),SCALAR(hermitian)) tol : tolerance value, default: 1e-8 for double else 1e-5 hermitian : Hermitian = 1 | Symmetric = 0, default = 0; =for ref Checks symmetricity/Hermitianicity of matrix. Supports threading. =cut sub _2d_array { my @dims = $_[0]->dims; my $d = $_[0]->dims_internal; barf("Require 2D array(s)") unless @dims >= 2+$d; } sub _square { &_2d_array; my @dims = $_[0]->dims; my $d = $_[0]->dims_internal; barf("Require square array(s)") unless $dims[$d] == $dims[$d+1]; } sub _square_same { my $d = $_[0]->dims_internal; my @adims = $_[0]->dims; my @bdims = $_[1]->dims; barf("Require square matrices of same order") unless( $adims[$d] == $adims[$d+1] && $bdims[$d] == $bdims[$d+1] && $adims[$d] == $bdims[$d]); } sub _matrices_match { my $d = $_[0]->dims_internal; my @adims = $_[0]->dims; my @bdims = $_[1]->dims; barf("Require right hand side array(s) B with number". " of row equal to number of columns of A") unless @adims >= 2+$d && @bdims >= 2+$d && $bdims[1+$d] == $adims[$d]; } sub _matrices_matchcolumns { my $di = $_[0]->dims_internal; my @adims = $_[0]->dims; my @bdims = $_[1]->dims; barf("Require 2 matrices with equal number of columns") unless( ((@adims >= 2+$di && @bdims >= 2+$di)) && $adims[$di] == $bdims[$di]); } sub _matrices_matchrows { my $d = $_[0]->dims_internal; my @adims = $_[0]->dims; my @bdims = $_[1]->dims; barf("Require a 2D right hand side matrix B with number". " of rows equal to number of rows of A") unless @adims >= 2+$d && @bdims >= 2+$d && $bdims[1+$d] == $adims[1+$d]; } sub _same_dims { my $d = $_[0]->dims_internal; my @adims = $_[0]->dims; my @bdims = $_[1]->dims; barf("Require arrays with equal number of dimensions") if @adims != @bdims; } sub _error { my ($info, $msg) = @_; return unless $info->max > 0 && $_laerror; my @list = (which($info > 0)+1)->list; laerror(sprintf $msg . ": \$info = $info", "@list"); } sub _error_schur { my ($info, $select_func, $N, $func, $algo) = @_; return unless $info->max > 0 && $_laerror; my $index = which((($info > 0)+($info <=$N))==2); if (!$index->isempty) { laerror("$func: The $algo algorithm failed to converge for matrix (PDL(s) @{[$index->list]}): \$info = $info"); print "Returning converged eigenvalues\n"; } return if !$select_func; if (!($index = which($info == $N+1))->isempty) { if ($algo eq 'QR') { laerror("$func: The eigenvalues could not be reordered because some\n". "eigenvalues were too close to separate (the problem". " is very ill-conditioned) for PDL(s) @{[$index->list]}: \$info = $info"); } else { laerror("$func: Error in hgeqz for matrix (PDL(s) @{[$index->list]}): \$info = $info"); } } if (!($index = which($info == $N+2))->isempty) { warn("$func: The Schur form no longer satisfy select_func = 1\n because of roundoff". " or underflow (PDL(s) @{[$index->list]})\n"); } } sub PDL::_wrap_select_func { my ($m, $select_func) = @_; return $select_func if !defined $select_func or $m->_is_complex; sub { &$select_func(_ecplx(@_[0,1]), @_>2 ? PDL->topdl($_[2]) : ()) }; } *issym = \&PDL::issym; sub PDL::issym { &_square; my ($m, $tol, $conj) = @_; $tol //= ($m->type >= double) ? 1e-8 : 1e-5; $m = $m - $m->t($conj); $m = $m->clump(2) if $m->isa('PDL::Complex'); my ($min,$max) = PDL::Ufunc::minmaximum($m); $min = $min->minimum; $max = $max->maximum; return (((abs($max) > $tol) + (abs($min) > $tol)) == 0); } =head2 diag =for ref Returns i-th diagonal if matrix in entry or matrix with i-th diagonal with entry. I-th diagonal returned flows data back&forth. Can be used as lvalue subs if your perl supports it. Supports threading. =for usage PDL = diag(PDL, SCALAR(i), SCALAR(vector))) i : i-th diagonal, default = 0 vector : create diagonal matrices by threading over row vectors, default = 0 =for example my $a = random(5,5); my $diag = diag($a,2); # If your perl support lvaluable subroutines. $a->diag(-2) .= pdl(1,2,3); # Construct a (5,5,5) PDL (5 matrices) with # diagonals from row vectors of $a $a->diag(0,1) =cut *diag = \&PDL::diag; sub PDL::diag { my $di = $_[0]->dims_internal; my @diag_args = ($di, $di+1); my $slice_prefix = ',' x $di; my ($a,$i, $vec) = @_; my $z; my @dims = $a->dims; my $diag = ($i < 0) ? -$i : $i ; if (@dims == $di+1 || $vec){ my $dim = $dims[0]; my $zz = $dim + $diag; my $v = $z = $a->_similar($zz,$zz,@dims[$di+1..$#dims]); $v = ($i < 0) ? $v->slice("$slice_prefix:@{[$dim-1]},$diag:") : $v->slice("$slice_prefix$diag:,:@{[$dim-1]}") if $i; $v->diagonal(@diag_args) .= $a; } elsif($i < 0){ $z = $a->slice("$slice_prefix:-@{[$diag+1]} , $diag:")->diagonal(@diag_args); } elsif($i){ $z = $a->slice("$slice_prefix$diag:, :-@{[$diag+1]}")->diagonal(@diag_args); } else{$z = $a->diagonal(@diag_args);} $a->isa('PDL::Complex') ? $z->complex : $z; } use attributes 'PDL', \&PDL::diag, 'lvalue'; =head2 tritosym =for ref Returns symmetric or Hermitian matrix from lower or upper triangular matrix. Supports inplace and threading. Uses L or L from Lapack. =for usage PDL = tritosym(PDL, SCALAR(uplo), SCALAR(conj)) uplo : UPPER = 0 | LOWER = 1, default = 0 conj : Hermitian = 1 | Symmetric = 0, default = 0; =for example # Assume $a is symmetric triangular my $a = random(10,10); my $b = tritosym($a); =cut *tritosym = \&PDL::tritosym; sub PDL::tritosym { &_square; my ($m, $upper, $conj) = @_; my $b = $m->is_inplace ? $m->t : $m->_similar_null; ($conj ? $m->conj : $m)->tricpy($upper, $b); $m->tricpy($upper, $b->t) unless (!$conj && $m->is_inplace(0)); $b->im->diagonal(0,1) .= 0 if $conj; $b; } =head2 positivise =for ref Returns entry pdl with changed sign by row so that average of positive sign > 0. In other words threads among dimension 1 and row = -row if sum(sign(row)) < 0. Only makes sense for real ndarrays. Works inplace. =for example my $a = random(10,10); $a -= 0.5; $a->xchg(0,1)->inplace->positivise; =cut *positivise = \&PDL::positivise; sub PDL::positivise{ my $m = shift; my $tmp; $m = $m->copy unless $m->is_inplace(0); $tmp = $m->dice('X', which(($m->lt(0,0)->sumover > ($m->dim(0)/2))>0)); $tmp->inplace->mult(-1,0);# .= -$tmp; $m; } =head2 mcrossprod =for ref Computes the cross-product of two matrix: A' x B. If only one matrix is given, takes B to be the same as A. Supports threading. Uses L or L. =for usage PDL = mcrossprod(PDL(A), (PDL(B)) =for example my $a = random(10,10); my $crossproduct = mcrossprod($a); =cut sub PDL::_call_method { my ($m, $method, @args) = @_; $method = [$method, "c$method"] if !ref $method; $method = $method->[!$m->type->real ? 1 : 0]; $m->$method(@args); } sub PDL::Complex::_call_method { my ($m, $method, @args) = @_; $method = [$method, "c$method"] if !ref $method; $method = $method->[1]; $m->$method(@args); } *mcrossprod = \&PDL::mcrossprod; sub PDL::mcrossprod { &_2d_array; my($a, $b) = @_; $b = $a unless defined $b; $a->_call_method('crossprod', $b); } =head2 mrank =for ref Computes the rank of a matrix, using a singular value decomposition, returning a Perl scalar. from Lapack. =for usage SCALAR = mrank(PDL, SCALAR(TOL)) TOL: tolerance value, default : mnorm(dims(PDL),'inf') * mnorm(PDL) * EPS =for example my $a = random(10,10); my $b = mrank($a, 1e-5); =cut *mrank = \&PDL::mrank; sub PDL::mrank { &_2d_array; my $di = $_[0]->dims_internal; my($m, $tol) = @_; my(@dims) = $m->dims; my $err = setlaerror(NO); # Sometimes mdsvd bugs for float (SGEBRD) # ($sv, $info) = $m->msvd(0, 0); my ($sv, $info) = $m->mdsvd(0); setlaerror($err); barf("mrank: SVD algorithm did not converge\n") if $info; unless (defined $tol){ $tol = ($dims[$di+1] > $dims[$di] ? $dims[$di+1] : $dims[$di]) * $sv((0)) * lamch(3); } (which($sv > $tol))->dim(0); } =head2 mnorm =for ref Computes norm of real or complex matrix Supports threading. =for usage PDL(norm) = mnorm(PDL, SCALAR(ord)); ord : 0|'inf' : Infinity norm 1|'one' : One norm 2|'two' : norm 2 (default) 3|'fro' : frobenius norm =for example my $a = random(10,10); my $norm = mnorm($a); =cut my %norms = (inf=>0, one=>1, two=>2, fro=>3); my %norm2arg = (0=>1, 1=>2, 3=>3); *mnorm = \&PDL::mnorm; sub PDL::mnorm { my ($m, $ord) = @_; $ord //= 2; $ord = $norms{$ord} if exists $norms{$ord}; return $m->_call_method('lange', $norm2arg{$ord}) if exists $norm2arg{$ord}; my $err = setlaerror(NO); my ($sv, $info) = $m->msvd(0, 0); setlaerror($err); _error($info, "mnorm: SVD algorithm did not converge for matrix (PDL(s) %s"); $sv->slice('(0)')->reshape(-1)->sever; } =head2 mdet =for ref Computes determinant of a general square matrix using LU factorization. Supports threading. Uses L or L from Lapack. =for usage PDL(determinant) = mdet(PDL); =for example my $a = random(10,10); my $det = mdet($a); =cut *mdet = \&PDL::mdet; sub PDL::mdet { &_square; my $di = $_[0]->dims_internal; my $m_orig = my $m = shift->copy; $m->_call_method('getrf', my $ipiv = null, my $info = null); $m = $m->diagonal($di,$di+1); $m = $m->complex if $m_orig->isa('PDL::Complex'); $m = $m->prodover; $m = $m * ((PDL::Ufunc::sumover(sequence($ipiv->dim(0))->plus(1,0) != $ipiv)%2)*(-2)+1); $info = which($info != 0); $m->flat->index($info) .= 0 if !$info->isempty; $m; } =head2 mposdet =for ref Compute determinant of a symmetric or Hermitian positive definite square matrix using Cholesky factorization. Supports threading. Uses L or L from Lapack. =for usage (PDL, PDL) = mposdet(PDL, SCALAR) SCALAR : UPPER = 0 | LOWER = 1, default = 0 =for example my $a = random(10,10); my $det = mposdet($a); =cut *mposdet = \&PDL::mposdet; sub PDL::mposdet { &_square; my ($m, $upper) = @_; $m = $m->copy; $m->_call_method('potrf', $upper, my $info = null); _error($info, "mposdet: Matrix (PDL(s) %s) is/are not positive definite (after potrf factorization)"); $m = $m->re if $m->_is_complex; $m = $m->diagonal(0,1)->prodover->pow(2); return wantarray ? ($m, $info) : $m; } =head2 mcond =for ref Computes the condition number (two-norm) of a general matrix. The condition number in two-n is defined: norm (a) * norm (inv (a)). Uses a singular value decomposition. Supports threading. =for usage PDL = mcond(PDL) =for example my $a = random(10,10); my $cond = mcond($a); =cut *mcond = \&PDL::mcond; sub PDL::mcond { &_2d_array; my $m = shift; my @dims = $m->dims; my $err = setlaerror(NO); my ($sv, $info) = $m->msvd(0, 0); setlaerror($err); _error($info, "mcond: Algorithm did not converge for matrix (PDL(s) %s)"); my $temp = $sv->slice('(0)'); my $ret = $temp/$sv->((-1)); $info = $ret->flat->index(which($temp == 0)); $info .= inf() unless $info->isempty; return $ret; } =head2 mrcond =for ref Estimates the reciprocal condition number of a general square matrix using LU factorization in either the 1-norm or the infinity-norm. The reciprocal condition number is defined: 1/(norm (a) * norm (inv (a))) Supports threading. Works on transposed array(s) =for usage PDL = mrcond(PDL, SCALAR(ord)) ord : 0 : Infinity norm (default) 1 : One norm =for example my $a = random(10,10); my $rcond = mrcond($a,1); =cut *mrcond = \&PDL::mrcond; sub PDL::mrcond { &_square; my ($m,$anorm) = @_; $anorm = 0 unless defined $anorm; $_ = null for my ($ipiv, $info, $rcond); my $norm = $m->mnorm($anorm); $m = $m->t->copy(); $m->_call_method('getrf', $ipiv, $info); _error($info, "mrcond: Factor(s) U (PDL(s) %s) is/are singular (after getrf factorization)"); $m->_call_method('gecon',$anorm,$norm,$rcond,$info); return wantarray ? ($rcond, $info) : $rcond; } =head2 morth =for ref Returns an orthonormal basis of the range space of matrix A. =for usage PDL = morth(PDL(A), SCALAR(tol)) tol : tolerance for determining rank, default: 1e-8 for double else 1e-5 =for example my $a = sequence(10,10); my $ortho = morth($a, 1e-8); =cut *morth = \&PDL::morth; sub PDL::morth { &_2d_array; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my ($m, $tol) = @_; $tol = (defined $tol) ? $tol : ($m->type == double) ? 1e-8 : 1e-5; (my $u, my $s, undef, my $info) = $m->mdsvd; barf("morth: SVD algorithm did not converge\n") if $info; my $rank = (which($s > $tol))->dim(0) - 1; $rank < 0 ? $m->_similar_null : $u->slice("$slice_prefix:$rank,")->sever; } =head2 mnull =for ref Returns an orthonormal basis of the null space of matrix A. Works on transposed array. =for usage PDL = mnull(PDL(A), SCALAR(tol)) tol : tolerance for determining rank, default: 1e-8 for double else 1e-5 =for example my $a = sequence(10,10); my $null = mnull($a, 1e-8); =cut *mnull = \&PDL::mnull; sub PDL::mnull { &_2d_array; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my ($m, $tol) = @_; my @dims = $m->dims; $tol //= ($m->type == double) ? 1e-8 : 1e-5; (undef, my $s, my $v, my $info) = $m->mdsvd; barf("mnull: SVD algorithm did not converge\n") if $info; #TODO: USE TRANSPOSED A my $rank = (which($s > $tol))->dim(0); $rank < $dims[$di] ? $v->t->slice("$slice_prefix$rank:")->sever : $m->_similar_null; } =head2 minv =for ref Computes inverse of a general square matrix using LU factorization. Supports inplace and threading. Uses L and L or L and L from Lapack and returns C in array context. =for usage PDL(inv) = minv(PDL) =for example my $a = random(10,10); my $inv = minv($a); =cut *minv = \&PDL::minv; sub PDL::minv { &_square; my $m = shift; $m = $m->copy() unless $m->is_inplace(0); $_ = null for my ($ipiv, $info); $m->_call_method('getrf', $ipiv, $info); _error($info, "minv: Factor(s) U (PDL(s) %s) is/are singular (after getrf factorization)"); $m->_call_method('getri', $ipiv, $info); return wantarray ? ($m, $info) : $m; } =head2 mtriinv =for ref Computes inverse of a triangular matrix. Supports inplace and threading. Uses L or L from Lapack. Returns C in array context. =for usage (PDL, PDL(info))) = mtriinv(PDL, SCALAR(uplo), SCALAR|PDL(diag)) uplo : UPPER = 0 | LOWER = 1, default = 0 diag : UNITARY DIAGONAL = 1, default = 0 =for example # Assume $a is upper triangular my $a = random(10,10); my $inv = mtriinv($a); =cut *mtriinv = \&PDL::mtriinv; sub PDL::mtriinv{ &_square; my $m = shift; my $upper = @_ ? (1 - shift) : pdl (long,1); my $diag = shift; $m = $m->copy() unless $m->is_inplace(0); my $info = PDL->null; $m->_call_method('trtri', $upper, $diag, $info); _error($info, "mtriinv: Matrix (PDL(s) %s) is/are singular"); return wantarray ? ($m, $info) : $m; } =head2 msyminv =for ref Computes inverse of a symmetric square matrix using the Bunch-Kaufman diagonal pivoting method. Supports inplace and threading. Uses L and L or L and L from Lapack and returns C in array context. =for usage (PDL, (PDL(info))) = msyminv(PDL, SCALAR|PDL(uplo)) uplo : UPPER = 0 | LOWER = 1, default = 0 =for example # Assume $a is symmetric my $a = random(10,10); my $inv = msyminv($a); =cut *msyminv = \&PDL::msyminv; sub PDL::msyminv { &_square; my $di = $_[0]->dims_internal; my $m = shift; my $upper = @_ ? (1 - shift) : pdl (long,1); $m = $m->copy() unless $m->is_inplace(0); $m->_call_method('sytrf', $upper, my $ipiv=null, my $info=null); _error($info, "msyminv: Block diagonal matrix D (PDL(s) %s) is/are singular (after sytrf factorization)"); $m->_call_method('sytri',$upper,$ipiv,$info); $m = $m->t->tritosym($upper, 0); return wantarray ? ($m, $info) : $m; } =head2 mposinv =for ref Computes inverse of a symmetric positive definite square matrix using Cholesky factorization. Supports inplace and threading. Uses L and L or L and L from Lapack and returns C in array context. =for usage (PDL, (PDL(info))) = mposinv(PDL, SCALAR|PDL(uplo)) uplo : UPPER = 0 | LOWER = 1, default = 0 =for example # Assume $a is symmetric positive definite my $a = random(10,10); $a = $a->crossprod($a); my $inv = mposinv($a); =cut *mposinv = \&PDL::mposinv; sub PDL::mposinv { &_square; my $di = $_[0]->dims_internal; my $m = shift; my $upper = @_ ? (1 - shift) : pdl (long,1); $m = $m->copy() unless $m->is_inplace(0); $m->_call_method('potrf', $upper, my $info=null); _error($info, "mposinv: matrix (PDL(s) %s) is/are not positive definite (after potrf factorization)"); $m->_call_method('potri', $upper, $info); return wantarray ? ($m, $info) : $m; } =head2 mpinv =for ref Computes pseudo-inverse (Moore-Penrose) of a general matrix. Works on transposed array. =for usage PDL(pseudo-inv) = mpinv(PDL, SCALAR(tol)) TOL: tolerance value, default : mnorm(dims(PDL),'inf') * mnorm(PDL) * EPS =for example my $a = random(5,10); my $inv = mpinv($a); =cut *mpinv = \&PDL::mpinv; sub PDL::mpinv{ &_2d_array; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $err = setlaerror(NO); #TODO: don't transpose my ($u, $s, $v, $info) = $m->mdsvd(2); setlaerror($err); _error($info, "mpinv: SVD algorithm did not converge (PDL %s)"); unless (defined $tol){ $tol = ($dims[$di+1] > $dims[$di] ? $dims[$di+1] : $dims[$di]) * $s((0)) * lamch(3); } my ($ind, $cind) = which_both( $s > $tol ); $s->index($cind) .= 0 if defined $cind; $s->index($ind) .= 1/$s->index($ind) ; $ind = ($v->t * ($m->_is_complex ? $s->r2C : $s)) x $u->t; return wantarray ? ($ind, $info) : $ind; } =head2 mlu =for ref Computes LU factorization. Uses L or L from Lapack and returns L, U, pivot and info. Works on transposed array. =for usage (PDL(l), PDL(u), PDL(pivot), PDL(info)) = mlu(PDL) =for example my $a = random(10,10); ($l, $u, $pivot, $info) = mlu($a); =cut *mlu = \&PDL::mlu; sub PDL::mlu { my $di = $_[0]->dims_internal; &_2d_array; my $m = shift; my @dims = $m->dims; $m = $m->copy; $m->t->_call_method('getrf',my $ipiv=null,my $info = null); if($info > 0) { $info--; laerror("mlu: Factor U is singular: U($info,$info) = 0 (after cgetrf factorization)"); return $m, $m, $ipiv, $info; } my $u = $m->mtri; my $l = $m->mtri(1); my $slice_prefix = ',' x $di; my $smallerm1 = ($dims[$di] < $dims[$di+1] ? $dims[$di] : $dims[$di+1]) - 1; my $one = $m->isa('PDL::Complex') ? PDL::Complex::r2C(1) : 1; if ($dims[$di+1] > $dims[$di]) { $u = $u->slice("$slice_prefix,:$smallerm1")->sever; $l->slice("$slice_prefix :$smallerm1, :$smallerm1")->diagonal($di,$di+1) .= $one; } else { $l = $l->slice("$slice_prefix:$smallerm1")->sever if $dims[$di+1] < $dims[$di]; $l->diagonal($di,$di+1) .= $one; } $l, $u, $ipiv, $info; } =head2 mchol =for ref Computes Cholesky decomposition of a symmetric matrix also known as symmetric square root. If inplace flag is set, overwrite the leading upper or lower triangular part of A else returns triangular matrix. Returns C in array context. Supports threading. Uses L or L from Lapack. =for usage PDL(Cholesky) = mchol(PDL, SCALAR) SCALAR : UPPER = 0 | LOWER = 1, default = 0 =for example my $a = random(10,10); $a = crossprod($a, $a); my $u = mchol($a); =cut *mchol = \&PDL::mchol; sub PDL::mchol { &_square; my $di = $_[0]->dims_internal; my($m, $upper) = @_; my(@dims) = $m->dims; $m = $m->mtri($upper) unless $m->is_inplace(0); @dims = @dims[2+$di..$#dims]; my $uplo = 1 - $upper; $m->_call_method('potrf',$uplo,my $info=null); _error($info, "mchol: matrix (PDL(s) %s) is/are not positive definite (after potrf factorization)"); return wantarray ? ($m, $info) : $m; } =head2 mhessen =for ref Reduces a square matrix to Hessenberg form H and orthogonal matrix Q. It reduces a general matrix A to upper Hessenberg form H by an orthogonal similarity transformation: Q' x A x Q = H or A = Q x H x Q' Uses L and L or L and L from Lapack and returns C in scalar context else C and C. Works on transposed array. =for usage (PDL(h), (PDL(q))) = mhessen(PDL) =for example my $a = random(10,10); ($h, $q) = mhessen($a); =cut *mhessen = \&PDL::mhessen; sub PDL::mhessen { &_square; my $di = $_[0]->dims_internal; my @diag_args = ($di, $di+1); my $slice_arg = (',' x $di) . ":-2, 1:"; my $m = shift; my(@dims) = $m->dims; $m = $m->t->copy; $m->_call_method('gehrd',1,$dims[$di], my $tau = $m->_similar($dims[$di]-1),my $info = null); (my $q = $m->copy)->_call_method(['orghr','cunghr'], 1, $dims[$di], $tau, $info) if wantarray; my $h = ($m = $m->t)->mtri; $h->slice($slice_arg)->diagonal(@diag_args) .= $m->slice($slice_arg)->diagonal(@diag_args); wantarray ? return ($h, $q->t->sever) : $h; } =head2 mschur =for ref Computes Schur form, works inplace. A = Z x T x Z' Supports threading for unordered eigenvalues. Uses L or L from Lapack and returns schur(T) in scalar context. Works on transposed array(s). =for usage ( PDL(schur), (PDL(eigenvalues), (PDL(left schur vectors), PDL(right schur vectors), $sdim), $info) ) = mschur(PDL(A), SCALAR(schur vector),SCALAR(left eigenvector), SCALAR(right eigenvector),SCALAR(select_func), SCALAR(backtransform), SCALAR(norm)) schur vector : Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0 left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 select_func : Select_func is used to select eigenvalues to sort to the top left of the Schur form. An eigenvalue is selected if PerlInt select_func(w) is true; (the inputs are converted to complex ndarrays for you) Note that a selected complex eigenvalue may no longer satisfy select_func(w) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned). All eigenvalues/vectors are selected if select_func is undefined. backtransform : Whether or not backtransforms eigenvectors to those of A. Only supported if schur vectors are computed, default = 1. norm : Whether or not computed eigenvectors are normalized to have Euclidean norm equal to 1 and largest component real, default = 1 Returned values : Schur form T (SCALAR CONTEXT), eigenvalues, Schur vectors (Z) if requested, left eigenvectors if requested right eigenvectors if requested sdim: Number of eigenvalues selected if select_func is defined. info: Info output from gees/cgees. =for example my $a = random(10,10); my $schur = mschur($a); sub select{ my $w = shift; # select "discrete time" eigenspace return $w->Cabs < 1 ? 1 : 0; } my ($schur,$eigen,$svectors,$evectors) = mschur($a,1,1,0,\&select); =cut sub _eigen_extract { my ($jobvl, $jobvr, $vl, $vr, @w) = @_; return ($w[0], $vl, $vr) if @w == 1; my $w; ($w, $vl) = cplx_eigen(@w, $vl, 1) if $jobvl; ($w, $vr) = cplx_eigen(@w, $vr, 1) if $jobvr; $w = _ecplx(@w) if !defined $w; ($w, $vl, $vr); } sub _eigen_one { my ($mm, $select_func, $jobv, $jobvl, $jobvr, $mult, $norm, $mdim, $sdim, @w) = @_; my $job = $jobvr && $jobvl ? undef : $jobvl ? 2 : 1; my $is_mult = $jobvl == 1 || $jobvr == 1 || $mult; $_ = $mm->_similar_null for my ($vl, $vr); $mult = ($select_func && !$is_mult) ? 2 : !$jobv ? 0 : $mult; my $sel = ($select_func && !$is_mult) ? zeroes($mdim) : undef; $sel(:($sdim-1)) .= 1 if defined $sel; $mm->_call_method('trevc', $job, $mult, $sel, $vl, $vr, $sdim, my $infos=null); @w = map $is_mult || !$select_func ? $_ : $_(:($sdim-1)), @w if @w == 2; my @ret; for ([$jobvr,$vr], [$jobvl,$vl]) { unshift(@ret, undef), next if !$_->[0]; my $val; if (@w == 2) { (undef,$val) = cplx_eigen(@w,$norm?($_->[1],1):($_->[1]->t,0)); } else { $val = $_->[1]; } unshift(@ret, $norm ? $val->_norm(1,1) : $val), next if !$is_mult or !$select_func; my $di = $val->dims_internal; my $slice_prefix = ',' x $di; $val = $val->slice("$slice_prefix,:@{[$sdim-1]}")->sever if $_->[0] == 2; $val = $val->_norm(1,1) if $norm; unshift @ret, $val; } @ret; } *mschur = \&PDL::mschur; sub PDL::mschur { &_square; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my ($m, $jobv, $jobvl, $jobvr, $select_func, $mult, $norm) = @_; my @dims = $m->dims; barf("mschur: threading not supported for selected vectors") if $select_func && @dims > 2+$di && (grep $_ == 2, $jobv, $jobvl, $jobvr); $mult //= 1; $norm //= 1; $jobv = $jobvl = $jobvr = 0 unless wantarray; my $type = $m->type; my $mm = $m->is_inplace ? $m->t : $m->t->copy; my $v = $m->_similar_null; my @w = map $m->_similar_null, $m->_is_complex ? 1 : 1..2; my $select_f = $m->_wrap_select_func($select_func); $mm->_call_method('gees', $jobv, $select_func ? 1 : 0, @w, $v, my $sdim = null, my $info = null, $select_f ); _error_schur($info, $select_func, $dims[$di], 'mschur', 'QR'); my @ret = !$select_func || $sdim ? () : map _complex_null(), grep $_ == 2, $jobvl, $jobvr; push @ret, $sdim if $select_func; $_ = 0 for grep $select_func && $_ == 2 && !$sdim, $jobvl, $jobvr; my $w = @w == 2 ? _ecplx(@w) : @w[0]; if ($jobvl || $jobvr){ unshift @ret, grep defined, _eigen_one( $mm, $select_func, $jobv, $jobvl, $jobvr, $mult, $norm, $dims[$di+1], $sdim, @w ); } if ($jobv == 2 && $select_func) { unshift @ret, $sdim > 0 ? $v->t->slice("$slice_prefix:@{[$sdim-1]}")->sever : $m->_similar_null; } elsif($jobv){ unshift @ret, $v->t->sever; } $m = $mm->t->sever unless $m->is_inplace(0); return wantarray ? ($m, $w, @ret, $info) : $m; } =head2 mschurx =for ref Computes Schur form, works inplace. Uses L or L from Lapack and returns schur(T) in scalar context. Works on transposed array. =for usage ( PDL(schur) (,PDL(eigenvalues)) (, PDL(schur vectors), HASH(result)) ) = mschurx(PDL, SCALAR(schur vector), SCALAR(left eigenvector), SCALAR(right eigenvector),SCALAR(select_func), SCALAR(sense), SCALAR(backtransform), SCALAR(norm)) schur vector : Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0 left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 select_func : Select_func is used to select eigenvalues to sort to the top left of the Schur form. An eigenvalue is selected if PerlInt select_func(w) is true; (the inputs are converted to complex ndarrays for you) Note that a selected complex eigenvalue may no longer satisfy select_func(w) = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned). All eigenvalues/vectors are selected if select_func is undefined. sense : Determines which reciprocal condition numbers will be computed. 0: None are computed 1: Computed for average of selected eigenvalues only 2: Computed for selected right invariant subspace only 3: Computed for both If select_func is undefined, sense is not used. backtransform : Whether or not backtransforms eigenvectors to those of A. Only supported if schur vector are computed, default = 1 norm : Whether or not computed eigenvectors are normalized to have Euclidean norm equal to 1 and largest component real, default = 1 Returned values : Schur form T (SCALAR CONTEXT), eigenvalues, Schur vectors if requested, HASH{VL}: left eigenvectors if requested HASH{VR}: right eigenvectors if requested HASH{info}: info output from gees/cgees. if select_func is defined: HASH{n}: number of eigenvalues selected, HASH{rconde}: reciprocal condition numbers for the average of the selected eigenvalues if requested, HASH{rcondv}: reciprocal condition numbers for the selected right invariant subspace if requested. =for example my $a = random(10,10); my $schur = mschurx($a); sub select{ my $m = shift; # select "discrete time" eigenspace return $m->Cabs < 1 ? 1 : 0; } my ($schur,$eigen, $vectors,%ret) = mschurx($a,1,0,0,\&select); =cut *mschurx = \&PDL::mschurx; sub PDL::mschurx { &_square; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my($m, $jobv, $jobvl, $jobvr, $select_func, $sense, $mult,$norm) = @_; my(@dims) = $m->dims; $mult //= 1; $norm //= 1; $jobv = $jobvl = $jobvr = 0 unless wantarray; my $type = $m->type; my $select = long($select_func ? 1 : 0); $sense = pdl(long,0) if !$select_func; $_ = null for my ($info, $sdim, $rconde, $rcondv); my $mm = $m->is_inplace ? $m->t : $m->t->copy; my $v = $m->_similar_null; my @w = map $m->_similar_null, $m->_is_complex ? 1 : 1..2; my $select_f = $m->_wrap_select_func($select_func); $mm->_call_method('geesx', $jobv, $select, $sense, @w, $v, $sdim, $rconde, $rcondv,$info, $select_f); _error_schur($info, $select_func, $dims[$di], 'mschurx', 'QR'); my @vl = ('VL', $jobvl); my @vr = ('VR', $jobvr); my %ret; $ret{$_->[0]} = _complex_null(), $_->[1]=0 for grep $select_func && !$sdim && $_->[1] == 2, \@vl, \@vr; $ret{n} = $sdim if $select_func; if ($vl[1] || $vr[1]) { my ($vl, $vr) = _eigen_one( $mm, $select_func, $jobv, $vl[1], $vr[1], $mult, $norm, $dims[$di+1], $sdim, @w ); $ret{$_->[0]} = $_->[1] for grep defined $_->[1], ['VL',$vl], ['VR',$vr]; } my $w = _ecplx(@w); if ($jobv == 2 && $select_func) { $v = $sdim > 0 ? $v->t->slice("$slice_prefix:@{[$sdim-1]},")->sever : $m->_similar_null; } elsif($jobv){ $v = $v->t->sever; } $ret{info} = $info; $ret{rconde} = $rconde if $sense & 1; $ret{rcondv} = $rcondv if $sense & 2; $m = $mm->t->sever unless $m->is_inplace(0); !wantarray ? $m : ($m, $w, ($jobv ? $v : ()), %ret); } # scale by max(abs(real)+abs(imag)) sub magn_norm { my ($m, $trans) = @_; # If trans == true => transpose output matrix my $ret = PDL::cat(map $m->$_, qw(re im))->mv(-1,0)->abs->sumover->maxover->dummy(0); $m = $m->t, $ret = $ret->t if $trans; ($m/$ret)->reshape(-1); } #TODO: inplace ? =head2 mgschur =for ref Computes generalized Schur decomposition of the pair (A,B). A = Q x S x Z' B = Q x T x Z' Uses L or L from Lapack. Works on transposed array. =for usage ( PDL(schur S), PDL(schur T), PDL(alpha), PDL(beta), HASH{result}) = mgschur(PDL(A), PDL(B), SCALAR(left schur vector),SCALAR(right schur vector),SCALAR(left eigenvector), SCALAR(right eigenvector), SCALAR(select_func), SCALAR(backtransform), SCALAR(scale)) left schur vector : Left Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0 right schur vector : Right Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0 left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 select_func : Select_func is used to select eigenvalues to sort. to the top left of the Schur form. An eigenvalue w = wr(j)+sqrt(-1)*wi(j) is selected if PerlInt select_func(alpha,beta) is true; (the inputs are converted to complex ndarrays for you) Note that a selected complex eigenvalue may no longer satisfy select_func = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned). All eigenvalues/vectors are selected if select_func is undefined. backtransform : Whether or not backtransforms eigenvectors to those of (A,B). Only supported if right and/or left schur vector are computed, scale : Whether or not computed eigenvectors are scaled so the largest component will have abs(real part) + abs(imag. part) = 1, default = 1 Returned values : Schur form S, Schur form T, alpha, beta (eigenvalues = alpha/beta), HASH{info}: info output from gges/cgges. HASH{SL}: left Schur vectors if requested HASH{SR}: right Schur vectors if requested HASH{VL}: left eigenvectors if requested HASH{VR}: right eigenvectors if requested HASH{n} : Number of eigenvalues selected if select_func is defined. =for example my $a = random(10,10); my $b = random(10,10); my ($S,$T) = mgschur($a,$b); sub select{ my ($alpha,$beta) = @_; return $alpha->Cabs < abs($beta) ? 1 : 0; } my ($S, $T, $alpha, $beta, %res) = mgschur( $a, $b, 1, 1, 1, 1,\&select); =cut sub _eigen_pair { my ( $mm, $pp, $select_func, $jobvl, $jobvr, $jobvsl, $jobvsr, $vsl, $vsr, $mult, $norm, $mdim, $sdim, @w ) = @_; my $job = !($jobvr && $jobvl) ? $jobvl ? 2 : 1 : undef; $_ = $mm->_similar_null for my ($vl, $vr); $mult = 0 if ($jobvl && !$jobvsl) || ($jobvr && !$jobvsr); if (!$select_func || ($jobvl == 1 || $jobvr == 1 || $mult)) { $vl .= $vsl if $jobvl && $jobvsl; $vr .= $vsr if $jobvr && $jobvsr; } my ($sdim_in, $sel) = $sdim; if ($select_func) { if ($jobvl == 1 || $jobvr == 1 || $mult) { $sdim_in = null; } else { $sel = zeroes($mdim); $sel(:($sdim-1)) .= 1; $mult = 2; @w = map $_(:($sdim-1)), @w; } } $mm->_call_method('tgevc', $job, $mult, $pp, $sel, $vl, $vr, $sdim_in, my $infos=null); if (@w == 2) { (undef,$vl) = cplx_eigen(@w,$vl->t,0) if $jobvl; (undef,$vr) = cplx_eigen(@w,$vr->t,0) if $jobvr; } if ($select_func && ($jobvl == 1 || $jobvr == 1 || $mult)) { $vr = $vr(,:($sdim-1))->sever if $jobvr == 2; $vl = $vl(,:($sdim-1))->sever if $jobvl == 2; } $vl = magn_norm($vl,1) if $jobvl and $norm; $vr = magn_norm($vr,1) if $jobvr and $norm; ($vl, $vr); } *mgschur = \&PDL::mgschur; sub PDL::mgschur{ my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; &_square_same; my($m, $p, $jobvsl, $jobvsr, $jobvl, $jobvr, $select_func, $mult, $norm) = @_; my @mdims = $m->dims; barf("mgschur: threading isn't supported for selected vectors") if ($select_func && ((@mdims > 2+$di) || ($p->ndims > 2+$di)) && ($jobvsl == 2 || $jobvsr == 2 || $jobvl == 2 || $jobvr == 2)); $mult //= 1; $norm //= 1; my $type = $m->type; my $select = $select_func ? pdl(long,1) : pdl(long,0); $_ = null for my ($info, $sdim); my ($mm, $pp) = map $_->is_inplace ? $_->t : $_->t->copy, $m, $p; my $select_f = $m->_wrap_select_func($select_func); my @w = map $m->_similar_null, $m->_is_complex ? 1 : 1..2; $_ = $m->_similar_null for my ($beta, $vsl, $vsr); $mm->_call_method('gges', $jobvsl, $jobvsr, $select, $pp, @w, $beta, $vsl, $vsr, $sdim, $info, $select_f); _error_schur($info, $select_func, $mdims[$di], 'mgschur', 'QZ'); my @vl = ('VL', $jobvl); my @vr = ('VR', $jobvr); my %ret; $ret{$_->[0]} = _complex_null(), $_->[1]=0 for grep $select_func && !$sdim && $_->[1] == 2, \@vl, \@vr; $ret{n} = $sdim if $select_func; if ($vl[1] || $vr[1]) { my ($vl, $vr) = _eigen_pair( $mm, $pp, $select_func, $vl[1], $vr[1], $jobvsl, $jobvsr, $vsl, $vsr, $mult, $norm, $mdims[$di+1], $sdim, @w ); $ret{$_->[0]} = $_->[1] for grep defined $_->[1], ['VL',$vl], ['VR',$vr]; } my $w = @w == 2 ? _ecplx(@w) : @w[0]; if ($jobvsl == 2 && $select_func) { $ret{SL} = $sdim ? $vsl->t->slice("$slice_prefix:@{[$sdim-1]},")->sever : $m->_similar_null; } elsif($jobvsl){ $ret{SL} = $vsl->t->sever; } if ($jobvsr == 2 && $select_func) { $ret{SR} = $sdim ? $vsr->t->slice("$slice_prefix:@{[$sdim-1]},")->sever : $m->_similar_null; } elsif($jobvsr){ $ret{SR} = $vsr->t->sever; } $ret{info} = $info; $m = $mm->t->sever unless $m->is_inplace(0); $p = $pp->t->sever unless $p->is_inplace(0); return ($m, $p, $w, $beta, %ret); } =head2 mgschurx =for ref Computes generalized Schur decomposition of the pair (A,B). A = Q x S x Z' B = Q x T x Z' Uses L or L from Lapack. Works on transposed array. =for usage ( PDL(schur S), PDL(schur T), PDL(alpha), PDL(beta), HASH{result}) = mgschurx(PDL(A), PDL(B), SCALAR(left schur vector),SCALAR(right schur vector),SCALAR(left eigenvector), SCALAR(right eigenvector), SCALAR(select_func), SCALAR(sense), SCALAR(backtransform), SCALAR(scale)) left schur vector : Left Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0 right schur vector : Right Schur vectors returned, none = 0 | all = 1 | selected = 2, default = 0 left eigenvector : Left eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 right eigenvector : Right eigenvectors returned, none = 0 | all = 1 | selected = 2, default = 0 select_func : Select_func is used to select eigenvalues to sort. to the top left of the Schur form. An eigenvalue w = wr(j)+sqrt(-1)*wi(j) is selected if PerlInt select_func(alpha,beta) is true; (the inputs are converted to complex ndarrays for you) Note that a selected complex eigenvalue may no longer satisfy select_func = 1 after ordering, since ordering may change the value of complex eigenvalues (especially if the eigenvalue is ill-conditioned). All eigenvalues/vectors are selected if select_func is undefined. sense : Determines which reciprocal condition numbers will be computed. 0: None are computed 1: Computed for average of selected eigenvalues only 2: Computed for selected deflating subspaces only 3: Computed for both If select_func is undefined, sense is not used. backtransform : Whether or not backtransforms eigenvectors to those of (A,B). Only supported if right and/or left schur vector are computed, default = 1 scale : Whether or not computed eigenvectors are scaled so the largest component will have abs(real part) + abs(imag. part) = 1, default = 1 Returned values : Schur form S, Schur form T, alpha, beta (eigenvalues = alpha/beta), HASH{info}: info output from gges/cgges. HASH{SL}: left Schur vectors if requested HASH{SR}: right Schur vectors if requested HASH{VL}: left eigenvectors if requested HASH{VR}: right eigenvectors if requested HASH{rconde}: reciprocal condition numbers for average of selected eigenvalues if requested HASH{rcondv}: reciprocal condition numbers for selected deflating subspaces if requested HASH{n} : Number of eigenvalues selected if select_func is defined. =for example my $a = random(10,10); my $b = random(10,10); my ($S,$T) = mgschurx($a,$b); sub select{ my ($alpha,$beta) = @_; return $alpha->Cabs < abs($beta) ? 1 : 0; } my ($S, $T, $alpha, $beta, %res) = mgschurx( $a, $b, 1, 1, 1, 1,\&select,3); =cut *mgschurx = \&PDL::mgschurx; sub PDL::mgschurx{ my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; &_square_same; my($m, $p, $jobvsl, $jobvsr, $jobvl, $jobvr, $select_func, $sense, $mult, $norm) = @_; my (@mdims) = $m->dims; $mult //= 1; $norm //= 1; my $type = $m->type; my $select = $select_func ? 1 : 0; $sense = 0 if !$select_func; $_ = null for my ($info, $rconde, $rcondv, $sdim); my ($mm, $pp) = map $_->is_inplace ? $_->t : $_->t->copy, $m, $p; $_ = $m->_similar_null for my ($beta, $vsl, $vsr); my @w = map $m->_similar_null, $m->_is_complex ? 1 : 1..2; my $select_f = $m->_wrap_select_func($select_func); $mm->_call_method('ggesx', $jobvsl, $jobvsr, $select, $sense, $pp, @w, $beta, $vsl, $vsr, $sdim, $rconde, $rcondv,$info, $select_f); _error_schur($info, $select_func, $mdims[$di], 'mgschurx', 'QZ'); my @vl = ('VL', $jobvl); my @vr = ('VR', $jobvr); my %ret; $ret{$_->[0]} = _complex_null(), $_->[1]=0 for grep $select_func && !$sdim && $_->[1] == 2, \@vl, \@vr; $ret{n} = $sdim if $select_func; if ($vl[1] || $vr[1]) { my ($vl, $vr) = _eigen_pair( $mm, $pp, $select_func, $vl[1], $vr[1], $jobvsl, $jobvsr, $vsl, $vsr, $mult, $norm, $mdims[$di+1], $sdim, @w ); $ret{$_->[0]} = $_->[1] for grep defined $_->[1], ['VL',$vl], ['VR',$vr]; } if ($jobvsl == 2 && $select_func) { $ret{SL} = $sdim ? $vsl->t->slice("$slice_prefix:@{[$sdim-1]},")->sever : $m->_similar_null; } elsif($jobvsl){ $ret{SL} = $vsl->t->sever; } if ($jobvsr == 2 && $select_func) { $ret{SR} = $sdim ? $vsr->t->slice("$slice_prefix:@{[$sdim-1]},")->sever : $m->_similar_null; } elsif($jobvsr){ $ret{SR} = $vsr->t->sever; } my $w = @w == 2 ? _ecplx(@w) : @w[0]; $ret{info} = $info; $ret{rconde} = $rconde if $sense & 1; $ret{rcondv} = $rcondv if $sense & 2; $m = $mm->t->sever unless $m->is_inplace(0); $p = $pp->t->sever unless $p->is_inplace(0); return ($m, $p, $w, $beta, %ret); } =head2 mqr =for ref Computes QR decomposition. Handles complex data. Uses L and L or L and L from Lapack and returns C in scalar context. Works on transposed array. =for usage (PDL(Q), PDL(R), PDL(info)) = mqr(PDL, SCALAR) SCALAR : ECONOMIC = 0 | FULL = 1, default = 0 =for example my $a = random(10,10); my ( $q, $r ) = mqr($a); # Can compute full decomposition if nrow > ncol $a = random(5,7); ( $q, $r ) = $a->mqr(1); =cut *mqr = \&PDL::mqr; sub PDL::mqr { &_2d_array; my $di = $_[0]->dims_internal; my @di_vals = $_[0]->dims_internal_values; my($m, $full) = @_; my(@dims) = $m->dims; $m = $m->t->copy; my $min = $dims[$di] < $dims[$di+1] ? $dims[$di] : $dims[$di+1]; my $slice_arg = (',' x $di) . ",:@{[$min-1]}"; my $tau = $m->_similar($min); $m->_call_method('geqrf', $tau, my $info = null); if ($info){ laerror ("mqr: Error $info in geqrf\n"); return ($m->t->sever, $m, $info); } my $q = ($dims[$di] > $dims[$di+1] ? $m->slice($slice_arg) : $m)->copy; $q->reshape(@di_vals, @dims[$di+1,$di+1]) if $full && $dims[$di] < $dims[$di+1]; $q->_call_method(['orgqr','cungqr'], $tau, $info); return $q->t->sever unless wantarray; my $r = (($dims[$di] < $dims[$di+1] && !$full) ? $m->t->slice($slice_arg) : $m->t)->tricpy(0); return ($q->t->sever, $r, $info); } =head2 mrq =for ref Computes RQ decomposition. Handles complex data. Uses L and L or L and L from Lapack and returns C in scalar context. Works on transposed array. =for usage (PDL(R), PDL(Q), PDL(info)) = mrq(PDL, SCALAR) SCALAR : ECONOMIC = 0 | FULL = 1, default = 0 =for example my $a = random(10,10); my ( $r, $q ) = mrq($a); # Can compute full decomposition if nrow < ncol $a = random(5,7); ( $r, $q ) = $a->mrq(1); =cut *mrq = \&PDL::mrq; sub PDL::mrq { &_2d_array; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my @diag_args = ($di, $di+1); my($m, $full) = @_; my(@dims) = $m->dims; my ($q, $r); $m = $m->t->copy; my $min = $dims[$di] < $dims[$di+1] ? $dims[$di] : $dims[$di+1]; my $tau = $m->_similar($min); $m->_call_method('gerqf', $tau, my $info = null); if ($info){ laerror ("mrq: Error $info in gerqf\n"); return ($m, $m->t->sever, $info); } if ($dims[$di] > $dims[$di+1] && $full){ $q = $m->_similar(@dims[$di,$di]); $q->slice("$slice_prefix@{[$dims[$di] - $dims[$di+1]]}:") .= $m; } elsif ($dims[$di] < $dims[$di+1]){ $q = $m->slice("$slice_prefix@{[$dims[$di+1] - $dims[$di]]}:")->copy; } else{ $q = $m->copy; } $q->_call_method(['orgrq','cungrq'], $tau, $info); return $q->t->sever unless wantarray; if ($dims[$di] > $dims[$di+1] && $full){ $r = $m->t->tricpy(0); $r->slice("$slice_prefix:@{[$min-1]},:@{[$min-1]}")->diagonal(@diag_args) .= 0; } elsif ($dims[$di] < $dims[$di+1]){ my $temp = $m->_similar(@dims[$di+1,$di+1]); $temp->slice("$slice_prefix-$min:") .= $m->t; $r = $temp->tricpy(0); $r = $r->slice("$slice_prefix-$min:")->sever; } else{ $r = $m->t->slice("$slice_prefix@{[$dims[$di] - $dims[$di+1]]}:")->tricpy(0); } return ($r, $q->t->sever, $info); } =head2 mql =for ref Computes QL decomposition. Handles complex data. Uses L and L or L and L from Lapack and returns C in scalar context. Works on transposed array. =for usage (PDL(Q), PDL(L), PDL(info)) = mql(PDL, SCALAR) SCALAR : ECONOMIC = 0 | FULL = 1, default = 0 =for example my $a = random(10,10); my ( $q, $l ) = mql($a); # Can compute full decomposition if nrow > ncol $a = random(5,7); ( $q, $l ) = $a->mql(1); =cut *mql = \&PDL::mql; sub PDL::mql { &_2d_array; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my @diag_args = ($di, $di+1); my($m, $full) = @_; my(@dims) = $m->dims; my ($q, $l); $m = $m->t->copy; my $min = $dims[$di] < $dims[$di+1] ? $dims[$di] : $dims[$di+1]; my $tau = $m->_similar($min); $m->_call_method('geqlf', $tau, my $info = null); if ($info){ laerror("mql: Error $info in geqlf\n"); return ($m->t->sever, $m, $info); } if ($dims[$di] < $dims[$di+1] && $full){ $q = $m->_similar(@dims[$di+1,$di+1]); $q->slice("$slice_prefix:,-$dims[$di]:") .= $m; } elsif ($dims[$di] > $dims[$di+1]){ $q = $m->slice("$slice_prefix:,-$min:")->copy; } else{ $q = $m->copy; } $q->_call_method(['orgql','cungql'], $tau, $info); return $q->t->sever unless wantarray; if ($dims[$di] < $dims[$di+1] && $full){ $l = $m->t->tricpy(1); $l->slice("$slice_prefix:@{[$min-1]},:@{[$min-1]}")->diagonal(@diag_args) .= 0; } elsif ($dims[$di] > $dims[$di+1]){ my $temp = $m->_similar(@dims[$di,$di]); $temp->slice("$slice_prefix:,-$dims[$di+1]:") .= $m->t; $l = $temp->tricpy(0); $l = $l->slice("$slice_prefix:,-$dims[$di+1]:"); } else{ $l = $m->t->slice("$slice_prefix:,@{[$dims[$di+1] - $min]}:")->tricpy(1); } return ($q->t->sever, $l, $info); } =head2 mlq =for ref Computes LQ decomposition. Handles complex data. Uses L and L or L and L from Lapack and returns C in scalar context. Works on transposed array. =for usage ( PDL(L), PDL(Q), PDL(info) ) = mlq(PDL, SCALAR) SCALAR : ECONOMIC = 0 | FULL = 1, default = 0 =for example my $a = random(10,10); my ( $l, $q ) = mlq($a); # Can compute full decomposition if nrow < ncol $a = random(5,7); ( $l, $q ) = $a->mlq(1); =cut *mlq = \&PDL::mlq; sub PDL::mlq { &_2d_array; my $di = $_[0]->dims_internal; my($m, $full) = @_; my(@dims) = $m->dims; my ($q); $m = $m->t->copy; my $min = $dims[$di] < $dims[$di+1] ? $dims[$di] : $dims[$di+1]; my $slice_arg = (',' x $di) . ":@{[$min-1]}"; my $tau = $m->_similar($min); $m->_call_method('gelqf', $tau, my $info = null); if ($info){ laerror("mlq: Error $info in gelqf\n"); return ($m, $m->t->sever, $info); } if ($dims[$di] > $dims[$di+1] && $full){ $q = $m->_similar(@dims[$di,$di]); $q->slice($slice_arg) .= $m; } elsif ($dims[$di] < $dims[$di+1]){ $q = $m->slice($slice_arg)->copy; } else{ $q = $m->copy; } $q->_call_method(['orglq','cunglq'], $tau, $info); return $q->t->sever unless wantarray; my $l = (($dims[$di] > $dims[$di+1] && !$full) ? $m->t->slice($slice_arg) : $m->t)->tricpy(1); return ($l, $q->t->sever, $info); } =head2 msolve =for ref Solves linear system of equations using LU decomposition. A * X = B Returns X in scalar context else X, LU, pivot vector and info. B is overwritten by X if its inplace flag is set. Supports threading. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(X), (PDL(LU), PDL(pivot), PDL(info))) = msolve(PDL(A), PDL(B) ) =for example my $a = random(5,5); my $b = random(10,5); my $X = msolve($a, $b); =cut *msolve = \&PDL::msolve; sub PDL::msolve { &_square; &_matrices_match; &_same_dims; my($a, $b) = @_; $a = $a->t->copy; my $c = $b->is_inplace ? $b->t : $b->t->copy; $a->_call_method('gesv', $c, my $ipiv = null, my $info = null); _error($info, "msolve: Can't solve system of linear equations (after getrf factorization): matrix (PDL(s) %s) is/are singular"); $b = $c->t->sever if !$b->is_inplace(0); wantarray ? ($b, $a->t->sever, $ipiv, $info) : $b; } =head2 msolvex =for ref Solves linear system of equations using LU decomposition. A * X = B Can optionally equilibrate the matrix. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL, (HASH(result))) = msolvex(PDL(A), PDL(B), HASH(options)) where options are: transpose: solves A' * X = B 0: false 1: true equilibrate: equilibrates A if necessary. form equilibration is returned in HASH{'equilibration'}: 0: no equilibration 1: row equilibration 2: column equilibration row scale factors are returned in HASH{'row'} column scale factors are returned in HASH{'column'} 0: false 1: true LU: returns lu decomposition in HASH{LU} 0: false 1: true A: returns scaled A if equilibration was done in HASH{A} 0: false 1: true B: returns scaled B if equilibration was done in HASH{B} 0: false 1: true Returned values: X (SCALAR CONTEXT), HASH{'pivot'}: Pivot indice from LU factorization HASH{'rcondition'}: Reciprocal condition of the matrix HASH{'ferror'}: Forward error bound HASH{'berror'}: Componentwise relative backward error HASH{'rpvgrw'}: Reciprocal pivot growth factor HASH{'info'}: Info: output from gesvx =for example my $a = random(10,10); my $b = random(5,10); my %options = ( LU=>1, equilibrate => 1, ); my( $X, %result) = msolvex($a,$b,%options); =cut *msolvex = \&PDL::msolvex; sub PDL::msolvex { &_square; &_matrices_match; my $di = $_[0]->dims_internal; my($a, $b, %opt) = @_; my(@adims) = $a->dims; $a = $a->t->copy; $b = $b->t->copy; my $x = $a->_similar_null; my $af = PDL::zeroes $a; $_ = null for my ($info, $rcond, $rpvgrw, $ferr, $berr); my $equed = pdl(long, 0); my $ipiv = zeroes(long, $adims[$di]); $a->_call_method('gesvx', $opt{transpose}, $opt{equilibrate} ? 2 : 1, $b, $af, $ipiv, $equed, my $r = null, my $c = null, $x, $rcond, $ferr, $berr, $rpvgrw,$info); if( $info < $adims[$di] && $info > 0){ $info--; laerror("msolvex: Can't solve system of linear equations:\nfactor U($info,$info)". " of coefficient matrix is exactly 0"); } elsif ($info != 0 and $_laerror){ warn ("msolvex: The matrix is singular to working precision"); } return $x->t->sever unless wantarray; my %result = (rcondition => $rcond, ferror => $ferr, berror => $berr); if ($opt{equilibrate}){ $result{equilibration} = $equed; $result{row} = $r if $equed & 1; $result{column} = $c if $equed & 2; if ($equed){ $result{A} = $a->t->sever if $opt{A}; $result{B} = $b->t->sever if $opt{B}; } } @result{qw(pivot rpvgrw info)} = ($ipiv, $rpvgrw, $info); $result{LU} = $af->t->sever if $opt{LU}; return ($x->t->sever, %result); } =head2 mtrisolve =for ref Solves linear system of equations with triangular matrix A. A * X = B or A' * X = B B is overwritten by X if its inplace flag is set. Supports threading. Uses L or L from Lapack. Work on transposed array(s). =for usage (PDL(X), (PDL(info)) = mtrisolve(PDL(A), SCALAR(uplo), PDL(B), SCALAR(trans), SCALAR(diag)) uplo : UPPER = 0 | LOWER = 1 trans : NOTRANSPOSE = 0 | TRANSPOSE = 1, default = 0 uplo : UNITARY DIAGONAL = 1, default = 0 =for example # Assume $a is upper triagonal my $a = random(5,5); my $b = random(5,10); my $X = mtrisolve($a, 0, $b); =cut *mtrisolve = \&PDL::mtrisolve; sub PDL::mtrisolve{ &_square; my $uplo = splice @_, 1, 1; &_matrices_match; &_same_dims; my($a, $b, $trans, $diag) = @_; $uplo = 1 - $uplo; $trans = 1 - $trans; my $c = $b->is_inplace ? $b->t : $b->t->copy; $a->_call_method('trtrs', $uplo, $trans, $diag, $c, my $info = null); _error($info, "mtrisolve: Can't solve system of linear equations: matrix (PDL(s) %s) is/are singular"); $b = $c->t->sever if !$b->is_inplace(0); wantarray ? ($b, $info) : $b; } =head2 msymsolve =for ref Solves linear system of equations using diagonal pivoting method with symmetric matrix A. A * X = B Returns X in scalar context else X, block diagonal matrix D (and the multipliers), pivot vector an info. B is overwritten by X if its inplace flag is set. Supports threading. Uses L or L from Lapack. Works on transposed array(s). =for usage (PDL(X), ( PDL(D), PDL(pivot), PDL(info) ) ) = msymsolve(PDL(A), SCALAR(uplo), PDL(B) ) uplo : UPPER = 0 | LOWER = 1, default = 0 =for example # Assume $a is symmetric my $a = random(5,5); my $b = random(5,10); my $X = msymsolve($a, 0, $b); =cut *msymsolve = \&PDL::msymsolve; sub PDL::msymsolve { &_square; my $uplo = splice @_, 1, 1; &_matrices_match; &_same_dims; my($a, $b) = @_; $uplo = 1 - $uplo; $a = $a->copy; my $c = $b->is_inplace ? $b->t : $b->t->copy; $a->_call_method('sysv', $uplo, $c, my $ipiv = null, my $info = null); _error($info, "msymsolve: Can't solve system of linear equations (after sytrf factorization): matrix (PDL(s) %s) is/are singular"); $b = $c->t->sever if !$b->is_inplace(0); wantarray ? ($b, $a, $ipiv, $info) : $b; } =head2 msymsolvex =for ref Solves linear system of equations using diagonal pivoting method with symmetric matrix A. A * X = B Uses L or L from Lapack. Works on transposed array. =for usage (PDL, (HASH(result))) = msymsolvex(PDL(A), SCALAR (uplo), PDL(B), SCALAR(d)) uplo : UPPER = 0 | LOWER = 1, default = 0 d : whether return diagonal matrix d and pivot vector FALSE = 0 | TRUE = 1, default = 0 Returned values: X (SCALAR CONTEXT), HASH{'D'}: Block diagonal matrix D (and the multipliers) (if requested) HASH{'pivot'}: Pivot indice from LU factorization (if requested) HASH{'rcondition'}: Reciprocal condition of the matrix HASH{'ferror'}: Forward error bound HASH{'berror'}: Componentwise relative backward error HASH{'info'}: Info: output from sysvx =for example # Assume $a is symmetric my $a = random(10,10); my $b = random(5,10); my ($X, %result) = msolvex($a, 0, $b); =cut *msymsolvex = \&PDL::msymsolvex; sub PDL::msymsolvex { &_square; my $uplo = splice @_, 1, 1; &_matrices_match; my $di = $_[0]->dims_internal; my($a, $b, $d) = @_; my(@adims) = $a->dims; $uplo = 1 - $uplo; $b = $b->t; my $x = $a->_similar_null; my $af = PDL::zeroes $a; $_ = null for my ($info, $rcond, $ferr, $berr); my $ipiv = zeroes(long, $adims[$di]); $a->_call_method('sysvx', $uplo, 0, $b, $af, $ipiv, $x, $rcond, $ferr, $berr, $info); if( $info < $adims[$di] && $info > 0){ $info--; laerror("msymsolvex: Can't solve system of linear equations:\nfactor D($info,$info)". " of coefficient matrix is exactly 0"); } elsif ($info != 0 and $_laerror){ warn("msymsolvex: The matrix is singular to working precision"); } my %result = (rcondition => $rcond, ferror => $ferr, berror => $berr, info => $info); @result{qw(pivot D)} = ($ipiv, $af) if $d; wantarray ? ($x->t->sever, %result): $x->t->sever; } =head2 mpossolve =for ref Solves linear system of equations using Cholesky decomposition with symmetric positive definite matrix A. A * X = B Returns X in scalar context else X, U or L and info. B is overwritten by X if its inplace flag is set. Supports threading. Uses L or L from Lapack. Works on transposed array(s). =for usage (PDL, (PDL, PDL, PDL)) = mpossolve(PDL(A), SCALAR(uplo), PDL(B) ) uplo : UPPER = 0 | LOWER = 1, default = 0 =for example # asume $a is symmetric positive definite my $a = random(5,5); my $b = random(5,10); my $X = mpossolve($a, 0, $b); =cut *mpossolve = \&PDL::mpossolve; sub PDL::mpossolve { &_square; my $uplo = splice @_, 1, 1; &_matrices_match; &_same_dims; my($a, $b) = @_; $uplo = 1 - $uplo; $a = $a->copy; my $c = $b->is_inplace ? $b->t : $b->t->copy; $a->_call_method('posv', $uplo, $c, my $info=null); _error($info, "mpossolve: Can't solve system of linear equations: matrix (PDL(s) %s) is/are not positive definite"); wantarray ? $b->is_inplace(0) ? ($b, $a,$info) : ($c->t->sever , $a,$info) : $b->is_inplace(0) ? $b : $c->t->sever; } =head2 mpossolvex =for ref Solves linear system of equations using Cholesky decomposition with symmetric positive definite matrix A A * X = B Can optionally equilibrate the matrix. Uses L or L from Lapack. Works on transposed array(s). =for usage (PDL, (HASH(result))) = mpossolvex(PDL(A), SCARA(uplo), PDL(B), HASH(options)) uplo : UPPER = 0 | LOWER = 1, default = 0 where options are: equilibrate: equilibrates A if necessary. form equilibration is returned in HASH{'equilibration'}: 0: no equilibration 1: equilibration scale factors are returned in HASH{'scale'} 0: false 1: true U|L: returns Cholesky factorization in HASH{U} or HASH{L} 0: false 1: true A: returns scaled A if equilibration was done in HASH{A} 0: false 1: true B: returns scaled B if equilibration was done in HASH{B} 0: false 1: true Returned values: X (SCALAR CONTEXT), HASH{'rcondition'}: Reciprocal condition of the matrix HASH{'ferror'}: Forward error bound HASH{'berror'}: Componentwise relative backward error HASH{'info'}: Info: output from gesvx =for example # Assume $a is symmetric positive definite my $a = random(10,10); my $b = random(5,10); my %options = (U=>1, equilibrate => 1, ); my ($X, %result) = msolvex($a, 0, $b,%opt); =cut *mpossolvex = \&PDL::mpossolvex; sub PDL::mpossolvex { &_square; my $uplo = splice(@_, 1, 1) ? 0 : 1; &_matrices_match; my $di = $_[0]->dims_internal; my($a, $b, %opt) = @_; my(@adims) = $a->dims; my(@bdims) = $b->dims; my $equilibrate = $opt{'equilibrate'} ? 2: 1; $a = $a->copy; $b = $b->t->copy; my $x = $a->_similar_null; my $af = PDL::zeroes $a; my $equed = pdl(long, 0); $a->_call_method('posvx', $uplo, $equilibrate, $b, $af, $equed, my $s = null, $x, my $rcond=null, my $ferr=null, my $berr=null, my $info=null); if( $info < $adims[$di] && $info > 0){ $info--; barf("mpossolvex: Can't solve system of linear equations:\n". "the leading minor of order $info of A is". " not positive definite"); return; } elsif ( $info and $_laerror){ warn("mpossolvex: The matrix is singular to working precision"); } my %result = (rcondition=>$rcond, ferror=>$ferr, berror=>$berr); if ($opt{equilibrate}){ $result{equilibration} = $equed; if ($equed){ $result{scale} = $s if $equed; $result{A} = $a if $opt{A}; $result{B} = $b->t->sever if $opt{B}; } } $result{info} = $info; $result{L} = $af if $opt{L}; $result{U} = $af if $opt{U}; wantarray ? ($x->t->sever, %result): $x->t->sever; } =head2 mlls =for ref Solves overdetermined or underdetermined real linear systems using QR or LQ factorization. If M > N in the M-by-N matrix A, returns the residual sum of squares too. Uses L or L from Lapack. Works on transposed arrays. =for usage PDL(X) = mlls(PDL(A), PDL(B), SCALAR(trans)) trans : NOTRANSPOSE = 0 | TRANSPOSE/CONJUGATE = 1, default = 0 =for example $a = random(4,5); $b = random(3,5); ($x, $res) = mlls($a, $b); =cut *mlls = \&PDL::mlls; sub PDL::mlls { my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; &_matrices_matchrows; my($a, $b, $trans) = @_; my(@adims) = $a->dims; my(@bdims) = $b->dims; my $x; $a = $a->copy; my $type = $a->type; if ( $adims[$di+1] < $adims[$di]) { $x = $a->_similar($adims[$di], $bdims[$di]); $x->slice("$slice_prefix:@{[$bdims[$di+1]-1]}, :@{[$bdims[$di]-1]}") .= $b->t; } else { $x = $b->t->copy; } $a->_call_method('gels', $trans ? 0 : 1, $x, my $info = null); $x = $x->t; return $x->sever if $adims[$di+1] <= $adims[$di]; my $sliced = $x->slice("$slice_prefix, :@{[$adims[$di]-1]}")->sever; return $sliced if !wantarray; my $power = $a->_similar(1); $power .= 2; ($sliced, ($x->slice("$slice_prefix, $adims[$di]:")->t ** $power)->sumover); } =head2 mllsy =for ref Computes the minimum-norm solution to a real linear least squares problem using a complete orthogonal factorization. Uses L or L from Lapack. Works on transposed arrays. =for usage ( PDL(X), ( HASH(result) ) ) = mllsy(PDL(A), PDL(B)) Returned values: X (SCALAR CONTEXT), HASH{'A'}: complete orthogonal factorization of A HASH{'jpvt'}: details of columns interchanges HASH{'rank'}: effective rank of A =for example my $a = random(10,10); my $b = random(10,10); $X = mllsy($a, $b); =cut *mllsy = \&PDL::mllsy; sub PDL::mllsy { my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; &_matrices_matchrows; my($a, $b) = @_; my(@adims) = $a->dims; my(@bdims) = $b->dims; my $type = $a->type; my $rcond = lamch(0); $rcond = $rcond->sqrt - ($rcond->sqrt - $rcond) / 2; $a = $a->t->copy; my ($x); if ( $adims[1+$di] < $adims[0+$di]){ $x = $a->_similar($adims[$di], $bdims[$di]); $x->slice("$slice_prefix:@{[$bdims[$di+1]-1]}, :@{[$bdims[$di]-1]}") .= $b->t; } else{ $x = $b->t->copy; } my $info = null; my $rank = null; my $jpvt = zeroes(long, $adims[$di]); $a->_call_method('gelsy', $x, $rcond, $jpvt, $rank, $info); my %ret = !wantarray ? () : ('A'=> $a->t->sever, 'rank' => $rank, 'jpvt'=>$jpvt); return wantarray ? ($x->t->sever, %ret) : $x->t->sever if $adims[$di+1] <= $adims[$di]; $x = $x->t->slice("$slice_prefix, :@{[$adims[$di]-1]}")->sever; wantarray ? ($x, %ret) : $x; } =head2 mllss =for ref Computes the minimum-norm solution to a real linear least squares problem using a singular value decomposition. Uses L or L from Lapack. Works on transposed arrays. =for usage ( PDL(X), ( HASH(result) ) )= mllss(PDL(A), PDL(B), SCALAR(method)) method: specifies which method to use (see Lapack for further details) '(c)gelss' or '(c)gelsd', default = '(c)gelsd' Returned values: X (SCALAR CONTEXT), HASH{'V'}: if method = (c)gelss, the right singular vectors, stored columnwise HASH{'s'}: singular values from SVD HASH{'res'}: if A has full rank the residual sum-of-squares for the solution HASH{'rank'}: effective rank of A HASH{'info'}: info output from method =for example my $a = random(10,10); my $b = random(10,10); $X = mllss($a, $b); =cut *mllss = \&PDL::mllss; sub PDL::mllss { my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; &_matrices_matchrows; my($a, $b, $method) = @_; my @adims = $a->dims; my @bdims = $b->dims; #TODO: Add this in option my $rcond = lamch(0); $rcond = $rcond->sqrt - ($rcond->sqrt - $rcond) / 2; $a = $a->t->copy; my $x; if ($adims[1+$di] < $adims[0+$di]){ $x = $a->_similar($adims[$di], $bdims[$di]); $x->slice("$slice_prefix:@{[$bdims[$di+1]-1]}, :@{[$bdims[$di]-1]}") .= $b->t; } else{ $x = $b->t->copy; } $_ = null for my ($info, $rank, $s); my $min = ($adims[$di] > $adims[$di+1]) ? $adims[$di+1] : $adims[$di]; $method ||= 'gelsd'; $a->_call_method($method, $x, $rcond, $s, $rank, $info); laerror("mllss: The algorithm for computing the SVD failed to converge\n") if $info; $x = $x->t; my %ret = !wantarray ? () : (rank => $rank, s=>$s, info=>$info); $ret{V} = $a if wantarray and $method =~ /gelss/; return wantarray ? ($x->sever, %ret) : $x->sever if $adims[1+$di] <= $adims[0+$di]; if (wantarray and $rank == $min) { my $power = $a->_similar(1); $power .= 2; $ret{res} = ($x->slice("$slice_prefix, $adims[$di]:")->t ** $power)->sumover; } $x = $x->slice("$slice_prefix, :@{[$adims[$di]-1]}")->sever; wantarray ? ($x->sever, %ret) : $x->sever; } =head2 mglm =for ref Solves a general Gauss-Markov Linear Model (GLM) problem. Supports threading. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(x), PDL(y)) = mglm(PDL(a), PDL(b), PDL(d)) where d is the left hand side of the GLM equation =for example my $a = random(8,10); my $b = random(7,10); my $d = random(10); my ($x, $y) = mglm($a, $b, $d); =cut *mglm = \&PDL::mglm; sub PDL::mglm{ my($a, $b, $d) = @_; my $di = $_[0]->dims_internal; my(@adims) = $a->dims; my(@bdims) = $b->dims; my(@ddims) = $d->dims; barf("mglm: Require arrays with equal number of rows") unless( @adims >= 2+$di && @bdims >= 2+$di && $adims[1+$di] == $bdims[1+$di]); barf "mglm: Require that column(A) <= row(A) <= column(A) + column(B)" unless ( ($adims[0+$di] <= $adims[1+$di] ) && ($adims[1+$di] <= ($adims[0+$di] + $bdims[0+$di])) ); barf("mglm: Require vector(s) with size equal to number of rows of A") unless( @ddims >= 1+$di && $adims[1+$di] == $ddims[0+$di]); $a = $a->t->copy; $b = $b->t->copy; $d = $d->copy; my ($x, $y, $info) = $a->_call_method('ggglm', $b, $d); $x, $y; } =head2 mlse =for ref Solves a linear equality-constrained least squares (LSE) problem. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(x), PDL(res2)) = mlse(PDL(a), PDL(b), PDL(c), PDL(d)) where c : The right hand side vector for the least squares part of the LSE problem. d : The right hand side vector for the constrained equation. x : The solution of the LSE problem. res2 : The residual sum of squares for the solution (returned only in array context) =for example my $a = random(5,4); my $b = random(5,3); my $c = random(4); my $d = random(3); my ($x, $res2) = mlse($a, $b, $c, $d); =cut *mlse = \&PDL::mlse; sub PDL::mlse { my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my($a, $b, $c, $d) = @_; my(@adims) = $a->dims; my(@bdims) = $b->dims; my(@cdims) = $c->dims; my(@ddims) = $d->dims; &_matrices_matchcolumns; barf("mlse: Require 1D vector C with size equal to number of A rows") unless( (@cdims == $di+1)&& $adims[$di+2] == $cdims[$di+2]); barf("mlse: Require 1D vector D with size equal to number of B rows") unless( (@ddims == $di+1)&& $bdims[$di+2] == $ddims[$di+2]); barf "mlse: Require that row(B) <= column(A) <= row(A) + row(B)" unless ( ($bdims[$di+1] <= $adims[$di] ) && ($adims[$di] <= ($adims[$di+1]+ $bdims[$di+1])) ); $a = $a->t->copy; $b = $b->t->copy; $c = $c->copy; $d = $d->copy; my ($x, $info) = $a->_call_method('gglse', $b, $c, $d); my $power = $a->_similar(1); $power .= 2; my $sumsq = ($c->slice("$slice_prefix @{[$adims[$di]-$bdims[$di+1]]}:@{[$adims[$di+1]-1]}") ** $power)->sumover; wantarray ? ($x, $sumsq) : $x; } =head2 meigen =for ref Computes eigenvalues and, optionally, the left and/or right eigenvectors of a general square matrix (spectral decomposition). Eigenvectors are normalized (Euclidean norm = 1) and largest component real. The eigenvalues and eigenvectors returned are complex ndarrays. If only eigenvalues are requested, info is returned in array context. Supports threading. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(values), (PDL(LV), (PDL(RV)), (PDL(info)))) = meigen(PDL, SCALAR(left vector), SCALAR(right vector)) left vector : FALSE = 0 | TRUE = 1, default = 0 right vector : FALSE = 0 | TRUE = 1, default = 0 =for example my $a = random(10,10); my ( $eigenvalues, $left_eigenvectors, $right_eigenvectors ) = meigen($a,1,1); =cut *meigen = \&PDL::meigen; sub PDL::meigen { &_square; my ($m,$jobvl,$jobvr) = @_; $_ = null for my ($info, $sdim); my @w = map $m->_similar_null, $m->_is_complex ? 1 : 1..2; $_ = $m->_similar_null for my ($vl, $vr); $m->t->_call_method('geev', $jobvl, $jobvr, @w, $vl, $vr, $info); _error($info, "meigen: The QR algorithm failed to converge for PDL(s) %s"); (my $w, $vl, $vr) = _eigen_extract($jobvl, $jobvr, $vl, $vr, @w); return $w if !wantarray; ($w, ($jobvl?$vl->t->sever:()), ($jobvr?$vr->t->sever:()), $info); } =head2 meigenx =for ref Computes eigenvalues, one-norm and, optionally, the left and/or right eigenvectors of a general square matrix (spectral decomposition). Eigenvectors are normalized (Euclidean norm = 1) and largest component real. The eigenvalues and eigenvectors returned are complex ndarrays. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(value), (PDL(lv), (PDL(rv)), HASH(result)), HASH(result)) = meigenx(PDL, HASH(options)) where options are: vector: eigenvectors to compute 'left': computes left eigenvectors 'right': computes right eigenvectors 'all': computes left and right eigenvectors 0: doesn't compute (default) rcondition: reciprocal condition numbers to compute (returned in HASH{'rconde'} for eigenvalues and HASH{'rcondv'} for eigenvectors) 'value': computes reciprocal condition numbers for eigenvalues 'vector': computes reciprocal condition numbers for eigenvectors 'all': computes reciprocal condition numbers for eigenvalues and eigenvectors 0: doesn't compute (default) error: specifies whether or not it computes the error bounds (returned in HASH{'eerror'} and HASH{'verror'}) error bound = EPS * One-norm / rcond(e|v) (reciprocal condition numbers for eigenvalues or eigenvectors must be computed). 1: returns error bounds 0: not computed scale: specifies whether or not it diagonaly scales the entry matrix (scale details returned in HASH : 'scale') 1: scales 0: Doesn't scale (default) permute: specifies whether or not it permutes row and columns (permute details returned in HASH{'balance'}) 1: permutes 0: Doesn't permute (default) schur: specifies whether or not it returns the Schur form (returned in HASH{'schur'}) 1: returns Schur form 0: not returned Returned values: eigenvalues (SCALAR CONTEXT), left eigenvectors if requested, right eigenvectors if requested, HASH{'norm'}: One-norm of the matrix HASH{'info'}: Info: if > 0, the QR algorithm failed to compute all the eigenvalues (see syevx for further details) =for example my $a = random(10,10); my %options = ( rcondition => 'all', vector => 'all', error => 1, scale => 1, permute=>1, schur => 1 ); my ( $eigenvalues, $left_eigenvectors, $right_eigenvectors, %result) = meigenx($a,%options); print "Error bounds for eigenvalues:\n $eigenvalues\n are:\n". transpose($result{'eerror'}) unless $info; =cut my %rcondition2sense = (value => 1, vector => 2, all => 3); my %vector2jobvl = (left => 1, all => 1); my %vector2jobvr = (right => 1, all => 1); *meigenx = \&PDL::meigenx; sub PDL::meigenx { &_square; my($m, %opt) = @_; my (%result); $m = $m->copy; $_ = null for my ($info, $ilo, $ihi, $abnrm, $scale, $rconde, $rcondv); $_ = $m->_similar_null for my ($vl, $vr); my @w = map $m->_similar_null, $m->_is_complex ? 1 : 1..2; my $balanc = ($opt{'scale'}?2:0) | ($opt{permute}?1:0); my $jobvl = $vector2jobvl{$opt{vector}} || $opt{rcondition} ? 1 : 0; my $jobvr = $vector2jobvr{$opt{vector}} || $opt{rcondition} ? 1 : 0; my $sense = $rcondition2sense{$opt{rcondition}} || 0; $m->t->_call_method('geevx', $jobvl, $jobvr, $balanc, $sense, @w, $vl, $vr, $ilo, $ihi, $scale, $abnrm, $rconde, $rcondv, $info); (my $w, $vl, $vr) = _eigen_extract($jobvl, $jobvr, $vl, $vr, @w); if ($info){ laerror("meigenx: The QR algorithm failed to converge"); print "Returning converged eigenvalues\n" if $_laerror; } $result{'schur'} = $m if $opt{'schur'}; $result{'balance'} = cat $ilo, $ihi if $opt{'permute'}; @result{qw(info norm)} = ($info, $abnrm); $result{'scale'} = $scale if $opt{'scale'}; if ($sense & 2) { $result{'rcondv'} = $rcondv; $result{'verror'} = (lamch(0)* $abnrm /$rcondv ) if $opt{'error'}; } if ($sense & 1) { $result{'rconde'} = $rconde; $result{'eerror'} = (lamch(0)* $abnrm /$rconde ) if $opt{'error'}; } ($w, ($vector2jobvl{$opt{vector}}?$vl->t->sever:()), ($vector2jobvr{$opt{vector}}?$vr->t->sever:()), %result); } =head2 mgeigen =for ref Computes generalized eigenvalues and, optionally, the left and/or right generalized eigenvectors for a pair of N-by-N real nonsymmetric matrices (A,B) . The alpha from ratio alpha/beta is a complex ndarray. Supports threading. Uses L or L from Lapack. Works on transposed arrays. =for usage ( PDL(alpha), PDL(beta), ( PDL(LV), (PDL(RV) ), PDL(info)) = mgeigen(PDL(A),PDL(B) SCALAR(left vector), SCALAR(right vector)) left vector : FALSE = 0 | TRUE = 1, default = 0 right vector : FALSE = 0 | TRUE = 1, default = 0 =for example my $a = random(10,10); my $b = random(10,10); my ( $alpha, $beta, $left_eigenvectors, $right_eigenvectors ) = mgeigen($a, $b,1, 1); =cut *mgeigen = \&PDL::mgeigen; sub PDL::mgeigen { &_square_same; &_same_dims; my ($a,$b,$jobvl,$jobvr) = @_; $_ = null for my ($info, $sdim); my @w = map $a->_similar_null, $a->_is_complex ? 1 : 1..2; $_ = $a->_similar_null for my ($vl, $vr, $beta); $a->t->_call_method('ggev', $jobvl, $jobvr, $b->t, @w, $beta, $vl, $vr, $info); _error($info, "mgeigen: Can't compute eigenvalues/vectors for PDL(s) %s"); (my $w, $vl, $vr) = _eigen_extract($jobvl, $jobvr, $vl, $vr, @w); ($w, $beta, ($jobvl?$vl->t->sever:()), ($jobvr?$vr->t->sever:()), $info); } =head2 mgeigenx =for ref Computes generalized eigenvalues, one-norms and, optionally, the left and/or right generalized eigenvectors for a pair of N-by-N real nonsymmetric matrices (A,B). The alpha from ratio alpha/beta is a complex ndarray. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(alpha), PDL(beta), PDL(lv), PDL(rv), HASH(result) ) = mgeigenx(PDL(a), PDL(b), HASH(options)) where options are: vector: eigenvectors to compute 'left': computes left eigenvectors 'right': computes right eigenvectors 'all': computes left and right eigenvectors 0: doesn't compute (default) rcondition: reciprocal condition numbers to compute (returned in HASH{'rconde'} for eigenvalues and HASH{'rcondv'} for eigenvectors) 'value': computes reciprocal condition numbers for eigenvalues 'vector': computes reciprocal condition numbers for eigenvectors 'all': computes reciprocal condition numbers for eigenvalues and eigenvectors 0: doesn't compute (default) error: specifies whether or not it computes the error bounds (returned in HASH{'eerror'} and HASH{'verror'}) error bound = EPS * sqrt(one-norm(a)**2 + one-norm(b)**2) / rcond(e|v) (reciprocal condition numbers for eigenvalues or eigenvectors must be computed). 1: returns error bounds 0: not computed scale: specifies whether or not it diagonaly scales the entry matrix (scale details returned in HASH : 'lscale' and 'rscale') 1: scales 0: doesn't scale (default) permute: specifies whether or not it permutes row and columns (permute details returned in HASH{'balance'}) 1: permutes 0: Doesn't permute (default) schur: specifies whether or not it returns the Schur forms (returned in HASH{'aschur'} and HASH{'bschur'}) (right or left eigenvectors must be computed). 1: returns Schur forms 0: not returned Returned values: alpha, beta, left eigenvectors if requested, right eigenvectors if requested, HASH{'anorm'}, HASH{'bnorm'}: One-norm of the matrix A and B HASH{'info'}: Info: if > 0, the QR algorithm failed to compute all the eigenvalues (see syevx for further details) =for example $a = random(10,10); $b = random(10,10); %options = (rcondition => 'all', vector => 'all', error => 1, scale => 1, permute=>1, schur => 1 ); ($alpha, $beta, $left_eigenvectors, $right_eigenvectors, %result) = mgeigenx($a, $b,%options); print "Error bounds for eigenvalues:\n $eigenvalues\n are:\n". transpose($result{'eerror'}) unless $info; =cut *mgeigenx = \&PDL::mgeigenx; sub PDL::mgeigenx { &_square_same; my $di = $_[0]->dims_internal; my ($a, $b, %opt) = @_; my @adims = $a->dims; my (%result); $_ = $a->_similar_null for my ($vl, $vr, $beta); $a = $a->copy; $b = $b->t->copy; my @w = map $a->_similar_null, $a->_is_complex ? 1 : 1..2; $_ = null for my ($rconde, $rcondv, $info, $ilo, $ihi, $rscale, $lscale, $abnrm, $bbnrm); my $jobvl = $vector2jobvl{$opt{vector}} || $opt{rcondition} ? 1 : 0; my $jobvr = $vector2jobvr{$opt{vector}} || $opt{rcondition} ? 1 : 0; my $sense = $rcondition2sense{$opt{rcondition}} || 0; my $balanc = ($opt{'scale'}?2:0) | ($opt{permute}?1:0); $a->t->_call_method('ggevx', $balanc, $jobvl, $jobvr, $sense, $b, @w, $beta, $vl, $vr, $ilo, $ihi, $lscale, $rscale, $abnrm, $bbnrm, $rconde, $rcondv, $info); (my $w, $vl, $vr) = _eigen_extract($jobvl, $jobvr, $vl, $vr, @w); if ($info > 0 && $info < $adims[$di+1]) { laerror("mgeigenx: The QZ algorithm failed to converge"); print "Returning converged eigenvalues\n" if $_laerror; } elsif ($info) { laerror("mgeigenx: Error from hgeqz or tgevc"); } $result{'aschur'} = $a if $opt{'schur'}; $result{'bschur'} = $b->t->sever if $opt{'schur'}; $result{'balance'} = cat $ilo, $ihi if $opt{'permute'}; @result{qw(info anorm bnorm)} = ($info, $abnrm, $bbnrm); @result{qw(lscale rscale)} = ($lscale, $rscale) if $opt{'scale'}; # Doesn't use lacpy2 =(sqrt **2 , **2) without unnecessary overflow if ($sense & 2) { $result{'rcondv'} = $rcondv; $result{'verror'} = lamch(0) * sqrt($abnrm->pow(2) + $bbnrm->pow(2)) /$rcondv if $opt{'error'}; } if ($sense & 1) { $result{'rconde'} = $rconde; $result{'eerror'} = lamch(0) * sqrt($abnrm->pow(2) + $bbnrm->pow(2)) /$rconde if $opt{'error'}; } ($w, $beta, ($vector2jobvl{$opt{vector}}?$vl->t->sever:()), ($vector2jobvr{$opt{vector}}?$vr->t->sever:()), %result); } =head2 msymeigen =for ref Computes eigenvalues and, optionally eigenvectors of a real symmetric square or complex Hermitian matrix (spectral decomposition). The eigenvalues are computed from lower or upper triangular matrix. If only eigenvalues are requested, info is returned in array context. Supports threading and works inplace if eigenvectors are requested. From Lapack, uses L or L for real and L or L for complex. Works on transposed array(s). =for usage (PDL(values), (PDL(VECTORS)), PDL(info)) = msymeigen(PDL, SCALAR(uplo), SCALAR(vector), SCALAR(method)) uplo : UPPER = 0 | LOWER = 1, default = 0 vector : FALSE = 0 | TRUE = 1, default = 0 method : 'syev' | 'syevd' | 'cheev' | 'cheevd', default = 'syevd'|'cheevd' =for example # Assume $a is symmetric my $a = random(10,10); my ( $eigenvalues, $eigenvectors ) = msymeigen($a,0,1, 'syev'); =cut *msymeigen = \&PDL::msymeigen; sub PDL::msymeigen { &_square; my($m, $upper, $jobv, $method) = @_; my ($w, $info) = (null, null); $method //= [ 'syevd', 'cheevd' ]; $m = $m->copy unless ($m->is_inplace(0) and $jobv); $m->t->_call_method($method, $jobv, $upper, $w, $info); _error($info, "msymeigen: The algorithm failed to converge for PDL(s) %s"); !wantarray ? $w : ($w, ($jobv?$m:()), $info); } =head2 msymeigenx =for ref Computes eigenvalues and, optionally eigenvectors of a symmetric square matrix (spectral decomposition). The eigenvalues are computed from lower or upper triangular matrix and can be selected by specifying a range. From Lapack, uses L or L for real and L or L for complex. Works on transposed arrays. =for usage (PDL(value), (PDL(vector)), PDL(n), PDL(info), (PDL(support)) ) = msymeigenx(PDL, SCALAR(uplo), SCALAR(vector), HASH(options)) uplo : UPPER = 0 | LOWER = 1, default = 0 vector : FALSE = 0 | TRUE = 1, default = 0 where options are: range_type: method for selecting eigenvalues indice: range of indices interval: range of values 0: find all eigenvalues and optionally all vectors range: PDL(2), lower and upper bounds interval or smallest and largest indices 1<=range<=N for indice abstol: specifies error tolerance for eigenvalues method: specifies which method to use (see Lapack for further details) 'syevx' (default) 'syevr' 'cheevx' (default) 'cheevr' Returned values: eigenvalues (SCALAR CONTEXT), eigenvectors if requested, total number of eigenvalues found (n), info issupz or ifail (support) according to method used and returned info, for (sy|che)evx returns support only if info != 0 =for example # Assume $a is symmetric my $a = random(10,10); my $overflow = lamch(9); my $range = cat pdl(0),$overflow; my $abstol = pdl(1.e-5); my %options = (range_type=>'interval', range => $range, abstol => $abstol, method=>'syevd'); my ( $eigenvalues, $eigenvectors, $n, $isuppz ) = msymeigenx($a,0,1, %options); =cut *msymeigenx = \&PDL::msymeigenx; my %range_type2range = (interval => 1, indice => 2); sub PDL::msymeigenx { &_square; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my($m, $upper, $jobz, %opt) = @_; my(@dims) = $m->dims; my $range = $range_type2range{$opt{range_type}} || 0; if ((ref $opt{range}) ne 'PDL'){ $opt{range} = pdl([0,0]); $range = 0; } elsif ($range == 2){ barf "msymeigenx: Indices must be > 0" unless $opt{range}->(0) > 0; barf "msymeigenx: Indices must be <= $dims[$di+1]" unless $opt{range}->(1) <= $dims[$di+1]; } elsif ($range == 1){ barf "msymeigenx: Interval limits must be different" unless ($opt{range}->(0) != $opt{range}->(1)); } $_ = null for my ($w, $n, $support, $info); my $z = $m->_similar_null; if (!defined $opt{'abstol'}) { my $unfl = lamch(1); $unfl->labad(lamch(9)); $opt{'abstol'} = $unfl + $unfl; } my $method = $opt{'method'} || ['syevx','cheevx']; $upper = $upper ? 0 : 1; $m = $m->copy; $m->_call_method($method, $jobz, $range, $upper, $opt{range}->(0), $opt{range}->(1),$opt{range}->(0),$opt{range}->(1), $opt{'abstol'}, $n, $w, $z , $support, $info); if ($info){ laerror("msymeigenx: The algorithm failed to converge."); print ("See support for details.\n") if $_laerror; } if ($jobz){ return ($w, $z->t->sever, $n, $info, $support) if $info; return (undef,undef,$n,$info,$method =~ qr/evr/?$support:()) if $n == 0; return ($w(:$n-1)->sever, $z->t->slice("$slice_prefix:@{[$n->sclr-1]}")->sever, $n, $info, $method =~ qr/evr/?$support:()); } else{ return $w if !wantarray; if ($info){ ($w, $n, $info, $support); } else{ ($w(:$n-1)->sever, $n, $info, $method =~ qr/evr/?$support:()); } } } =head2 msymgeigen =for ref Computes eigenvalues and, optionally eigenvectors of a real generalized symmetric-definite or Hermitian-definite eigenproblem. The eigenvalues are computed from lower or upper triangular matrix If only eigenvalues are requested, info is returned in array context. Supports threading. From Lapack, uses L or L for real or L or L for complex. Works on transposed array(s). =for usage (PDL(values), (PDL(vectors)), PDL(info)) = msymgeigen(PDL(a), PDL(b),SCALAR(uplo), SCALAR(vector), SCALAR(type), SCALAR(method)) uplo : UPPER = 0 | LOWER = 1, default = 0 vector : FALSE = 0 | TRUE = 1, default = 0 type : 1: A * x = (lambda) * B * x 2: A * B * x = (lambda) * x 3: B * A * x = (lambda) * x default = 1 method : 'sygv' | 'sygvd' for real or ,'chegv' | 'chegvd' for complex, default = 'sygvd' | 'chegvd' =for example # Assume $a is symmetric my $a = random(10,10); my $b = random(10,10); $b = $b->crossprod($b); my ( $eigenvalues, $eigenvectors ) = msymgeigen($a, $b, 0, 1, 1, 'sygv'); =cut *msymgeigen = \&PDL::msymgeigen; sub PDL::msymgeigen { &_square_same; &_same_dims; my($a, $b, $upper, $jobv, $type, $method) = @_; $type ||= 1; $method //= [ 'sygvd', 'chegvd' ]; $upper = 1-$upper; $a = $a->copy; $b = $b->copy; $a->_call_method($method, $type, $jobv, $upper, $b, my $w = null, my $info = null); _error($info, "msymgeigen: Can't compute eigenvalues/vectors: matrix (PDL(s) %s) is/are not positive definite or the algorithm failed to converge"); !wantarray ? $w : ($w, $jobv?$a->t->sever:(), $info); } =head2 msymgeigenx =for ref Computes eigenvalues and, optionally eigenvectors of a real generalized symmetric-definite or Hermitian eigenproblem. The eigenvalues are computed from lower or upper triangular matrix and can be selected by specifying a range. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(value), (PDL(vector)), PDL(info), PDL(n), (PDL(support)) ) = msymeigenx(PDL(a), PDL(b), SCALAR(uplo), SCALAR(vector), HASH(options)) uplo : UPPER = 0 | LOWER = 1, default = 0 vector : FALSE = 0 | TRUE = 1, default = 0 where options are: type : Specifies the problem type to be solved 1: A * x = (lambda) * B * x 2: A * B * x = (lambda) * x 3: B * A * x = (lambda) * x default = 1 range_type: method for selecting eigenvalues indice: range of indices interval: range of values 0: find all eigenvalues and optionally all vectors range: PDL(2), lower and upper bounds interval or smallest and largest indices 1<=range<=N for indice abstol: specifies error tolerance for eigenvalues Returned values: eigenvalues (SCALAR CONTEXT), eigenvectors if requested, total number of eigenvalues found (n), info ifail according to returned info (support). =for example # Assume $a is symmetric my $a = random(10,10); my $b = random(10,10); $b = $b->crossprod($b); my $overflow = lamch(9); my $range = cat pdl(0),$overflow; my $abstol = pdl(1.e-5); my %options = (range_type=>'interval', range => $range, abstol => $abstol, type => 1); my ( $eigenvalues, $eigenvectors, $n, $isuppz ) = msymgeigenx($a, $b, 0,1, %options); =cut *msymgeigenx = \&PDL::msymgeigenx; sub PDL::msymgeigenx { &_square_same; my $di = $_[0]->dims_internal; my($a, $b, $upper, $jobv, %opt) = @_; my(@adims) = $a->dims; my $range = $range_type2range{$opt{range_type}} || 0; if (!UNIVERSAL::isa($opt{range},'PDL')){ $opt{range} = pdl([0,0]); $range = 0; } $opt{type} //= 1; $_ = null for my ($w, $n, $support, $info); if (!defined $opt{'abstol'}){ my $unfl = lamch(1); my $ovfl = lamch(9); $unfl->labad($ovfl); $opt{'abstol'} = $unfl + $unfl; } my $z = $a->_similar_null; $upper = $upper ? 0 : 1; $a = $a->copy; $b = $b->copy; $a->_call_method(['sygvx','chegvx'], $opt{type}, $jobv, $range, $upper, $b, $opt{range}->(0), $opt{range}->(1),$opt{range}->(0),$opt{range}->(1), $opt{'abstol'}, $n, $w, $z ,$support, $info); if ( ($info > 0) && ($info < $adims[$di+1])){ laerror("msymgeigenx: The algorithm failed to converge"); print("see support for details\n") if $_laerror; } elsif($info){ $info = $info - $adims[$di+1] - 1; barf("msymgeigenx: The leading minor of order $info of B is not positive definite\n"); } return $w if !wantarray; ($w, $jobv?$z->t->sever:(), $n, $info, $info?$support:()); } =head2 mdsvd =for ref Computes SVD using Coppen's divide and conquer algorithm. Return singular values in scalar context else left (U), singular values, right (V' (hermitian for complex)) singular vectors and info. Supports threading. If only singulars values are requested, info is only returned in array context. Uses L or L from Lapack. =for usage (PDL(U), (PDL(s), PDL(V)), PDL(info)) = mdsvd(PDL, SCALAR(job)) job : 0 = computes only singular values 1 = computes full SVD (square U and V) 2 = computes SVD (singular values, right and left singular vectors) default = 1 =for example my $a = random(5,10); my ($u, $s, $v) = mdsvd($a); =cut *mdsvd = \&PDL::mdsvd; sub PDL::mdsvd { my $di = $_[0]->dims_internal; my($m, $jobz) = @_; my(@dims) = $m->dims; my $type = $m->type; $jobz = !wantarray ? 0 : $jobz // 1; my $min = $dims[$di] > $dims[1+$di] ? $dims[1+$di]: $dims[$di]; $m = $m->copy; $_ = $m->_similar_null for my ($u, $v); $m->_call_method('gesdd', $jobz, my $s = null, $u, $v, my $info = null); _error($info, "mdsvd: Matrix (PDL(s) %s) is/are singular"); return ($u, $s, $v, $info) if $jobz; wantarray ? ($s, $info) : $s; } =head2 msvd =for ref Computes SVD. Can compute singular values, either U or V or neither. Return singular values in scalar context else left (U), singular values, right (V' (hermitian for complex) singular vector and info. Supports threading. If only singular values are requested, info is returned in array context. Uses L or L from Lapack. =for usage ( (PDL(U)), PDL(s), (PDL(V), PDL(info)) = msvd(PDL, SCALAR(jobu), SCALAR(jobv)) jobu : 0 = Doesn't compute U 1 = computes full SVD (square U) 2 = computes right singular vectors default = 1 jobv : 0 = Doesn't compute V 1 = computes full SVD (square V) 2 = computes left singular vectors default = 1 =for example my $a = random(10,10); my ($u, $s, $v) = msvd($a); =cut *msvd = \&PDL::msvd; sub PDL::msvd { my ($m, $jobu, $jobv) = @_; $jobu = !wantarray ? 0 : $jobu // 1; $jobv = !wantarray ? 0 : $jobv // 1; $m = $m->copy; $_ = $m->_similar_null for my ($u, $v); $m->_call_method('gesvd', $jobv, $jobu,my $s = null, $u, $v, my $info = null); _error($info, "msvd: Matrix (PDL(s) %s) is/are singular"); wantarray ? ($jobu?$u:(), $s, $jobv?$v:(), $info) : $s; } =head2 mgsvd =for ref Computes generalized (or quotient) singular value decomposition. If the effective rank of (A',B')' is 0 return only unitary V, U, Q. Handles complex data. Uses L or L from Lapack. Works on transposed arrays. =for usage (PDL(sa), PDL(sb), %ret) = mgsvd(PDL(a), PDL(b), %HASH(options)) where options are: V: whether or not computes V (boolean, returned in HASH{'V'}) U: whether or not computes U (boolean, returned in HASH{'U'}) Q: whether or not computes Q (boolean, returned in HASH{'Q'}) D1: whether or not computes D1 (boolean, returned in HASH{'D1'}) D2: whether or not computes D2 (boolean, returned in HASH{'D2'}) 0R: whether or not computes 0R (boolean, returned in HASH{'0R'}) R: whether or not computes R (boolean, returned in HASH{'R'}) X: whether or not computes X (boolean, returned in HASH{'X'}) all: whether or not computes all the above. Returned value: sa,sb : singular value pairs of A and B (generalized singular values = sa/sb) $ret{'rank'} : effective numerical rank of (A',B')' $ret{'info'} : info from (c)ggsvd =for example my $a = random(5,5); my $b = random(5,7); my ($c, $s, %ret) = mgsvd($a, $b, X => 1); =cut my @gsvd_opts = qw(V U Q D1 D2 0R R X); *mgsvd = \&PDL::mgsvd; sub PDL::mgsvd { &_matrices_matchcolumns; my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my @diag_args = ($di, $di+1); my($a, $b, %opt) = @_; my(@adims) = $a->dims; my(@bdims) = $b->dims; @opt{@gsvd_opts} = (1) x @gsvd_opts if $opt{all}; my $type = $a->type; my $jobqx = ($opt{Q} || $opt{X}) ? 1 : 0; $a = $a->copy; $b = $b->t->copy; $_ = null for my ($k, $l, $alpha, $beta, $iwork, $info); $_ = $a->_similar_null for my ($U, $V, $Q); $a->t->_call_method('ggsvd', $opt{U}, $opt{V}, $jobqx, $b, $k, $l, $alpha, $beta, $U, $V, $Q, $iwork, $info); laerror("mgsvd: The Jacobi procedure fails to converge") if $info; my %ret = (rank=>$k + $l, info=>$info); warn "mgsvd: Effective rank of 0 in mgsvd" if (!$ret{rank} and $_laerror); if (%opt) { $Q = $Q->t->sever if $jobqx; if (($adims[$di+1] - $k - $l) < 0 && $ret{rank}){ if ( $opt{'0R'} || $opt{R} || $opt{X}){ $a->reshape((map $a->dim($_-1), 1..$di), $adims[$di], ($k + $l)); # Slice $a ??? => always square ?? $a->slice("$slice_prefix@{[$adims[$di] - ($k+$l-$adims[$di+1])]} : , $adims[$di+1]:") .= $b->slice("$slice_prefix@{[$adims[$di+1]-$k]}:@{[$l-1]},@[[$adims[$di]+$adims[$di+1]-$k - $l]}:@{[$adims[$di]-1]}")->t; $ret{'0R'} = $a if $opt{'0R'}; } if ($opt{'D1'}){ my $D1 = zeroes($type, $adims[$di+1], $adims[$di+1]); $D1->diagonal(0,1) .= $alpha(:($adims[$di+1]-1)); $D1 = $D1->t->reshape($adims[$di+1] , ($k+$l))->t->sever; $ret{'D1'} = $D1; } } elsif ($ret{rank}){ if ( $opt{'0R'} || $opt{R} || $opt{X}){ $a->reshape((map $a->dim($_-1), 1..$di), $adims[$di], ($k + $l)); $ret{'0R'} = $a if $opt{'0R'}; } if ($opt{'D1'}){ my $D1 = zeroes($type, ($k + $l), ($k + $l)); $D1->diagonal(0,1) .= $alpha(:($k+$l-1)); $D1->reshape(($k + $l), $adims[$di+1]); $ret{'D1'} = $D1; } } if ($opt{'D2'} && $ret{rank}){ my $work = zeroes($b->type, $l, $l); $work->diagonal(0,1) .= $beta($k:($k+$l-1)); my $D2 = zeroes($b->type, ($k + $l), $bdims[$di+1]); $D2( $k:, :($l-1) ) .= $work; $ret{'D2'} = $D2; } if ( $ret{rank} && ($opt{X} || $opt{R}) ){ my $work = $a->slice("$slice_prefix@{[-($k + $l)]}:"); $ret{R} = $work if $opt{R}; if ($opt{X}){ my $X = $a->_similar(@adims[$di,$di]); $X->diagonal(@diag_args) .= 1 if ($adims[$di] > ($k + $l)); $X->slice("$slice_prefix@{[-($k + $l)]}:, @{[-($k + $l)]}:") .= mtriinv($work); $ret{X} = $Q x $X; } } $ret{U} = $U->t->sever if $opt{U}; $ret{V} = $V->t->sever if $opt{V}; $ret{Q} = $Q if $opt{Q}; } $ret{rank} ? return ($alpha($k:($k+$l-1))->sever, $beta($k:($k+$l-1))->sever, %ret ) : (undef, undef, %ret); } #TODO # Others things # rectangular diag # usage # is_inplace and function which modify entry matrix # threading support # automatically create PDL # inplace operation and memory # PDL type, verify float/double # eig_det qr_det # (g)schur(x): # if conjugate pair # non generalized pb: $seldim ?? (cf: generalized) # return conjugate pair if only selected? # port to PDL::Matrix =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut 1; PDL-LinearAlgebra-0.38/lib/PDL/LinearAlgebra/0000755000175000017500000000000014565105646020370 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/lib/PDL/LinearAlgebra/Special.pm0000644000175000017500000001611614560556542022313 0ustar osboxesosboxespackage PDL::LinearAlgebra::Special; use PDL::Core; use PDL::NiceSlice; use PDL::Slices; use PDL::Basic qw (sequence xvals yvals); use PDL::MatrixOps qw (identity); use PDL::LinearAlgebra qw ( ); use PDL::LinearAlgebra::Real; use PDL::LinearAlgebra::Complex; use PDL::Exporter; no warnings 'uninitialized'; @EXPORT_OK = qw( mhilb mvander mpart mhankel mtoeplitz mtri mpascal mcompanion); %EXPORT_TAGS = (Func=>[@EXPORT_OK]); our $VERSION = '0.14'; $VERSION = eval $VERSION; our @ISA = ( 'PDL::Exporter'); use strict; =encoding utf8 =head1 NAME PDL::LinearAlgebra::Special - Special matrices for PDL =head1 SYNOPSIS use PDL::LinearAlgebra::Special; $a = mhilb(5,5); =head1 DESCRIPTION This module provides some constructors of well known matrices. =head1 FUNCTIONS =head2 mhilb =for ref Construct Hilbert matrix from specifications list or template ndarray =for usage PDL(Hilbert) = mpart(PDL(template) | ARRAY(specification)) =for example my $hilb = mhilb(float,5,5); =cut sub mhilb { if(ref($_[0]) && ref($_[0]) eq 'PDL'){ my $pdl = shift; $pdl->mhilb(@_); } else{ PDL->mhilb(@_); } } sub PDL::mhilb { my $class = shift; my $pdl1 = scalar(@_)? $class->new_from_specification(@_) : $class->copy; my $pdl2 = scalar(@_)? $class->new_from_specification(@_) : $class->copy; 1 / ($pdl1->inplace->axisvals + $pdl2->inplace->axisvals(1) + 1); } =head2 mtri =for ref Return zeroed matrix with upper or lower triangular part from another matrix. Return trapezoid matrix if entry matrix is not square. Supports threading. Uses L or L. =for usage PDL = mtri(PDL, SCALAR) SCALAR : UPPER = 0 | LOWER = 1, default = 0 =for example my $a = random(10,10); my $b = mtri($a, 0); =cut sub mtri{ my $m = shift; $m->mtri(@_); } sub PDL::mtri { &PDL::LinearAlgebra::_2d_array; my ($m, $upper) = @_; $m->tricpy($upper, my $b = $m->_similar_null); $b; } =head2 mvander Return (primal) Vandermonde matrix from vector. =for ref mvander(M,P) is a rectangular version of mvander(P) with M Columns. =cut sub mvander($;$) { my $exp = @_ == 2 ? sequence(shift) : sequence($_[0]->dim(-1)); $_[0]->dummy(-2)**$exp; } =head2 mpart =for ref Return antisymmetric and symmetric part of a real or complex square matrix. =for usage ( PDL(antisymmetric), PDL(symmetric) ) = mpart(PDL, SCALAR(conj)) conj : if true Return AntiHermitian, Hermitian part. =for example my $a = random(10,10); my ( $antisymmetric, $symmetric ) = mpart($a); =cut *mpart = \&PDL::mpart; sub PDL::mpart { &PDL::LinearAlgebra::_square; my ($m, $conj) = @_; # antisymmetric and symmetric part return (0.5* ($m - $m->t($conj))),(0.5* ($m + $m->t($conj))); } =head2 mhankel =for ref Return Hankel matrix also known as persymmetric matrix. Handles complex data. =for usage mhankel(c,r), where c and r are vectors, returns matrix whose first column is c and whose last row is r. The last element of c prevails. mhankel(c) returns matrix with element below skew diagonal (anti-diagonal) equals to zero. If c is a scalar number, make it from sequence beginning at one. =for ref The elements are: H (i,j) = c (i+j), i+j+1 <= m; H (i,j) = r (i+j-m+1), otherwise where m is the size of the vector. If c is a scalar number, it's determinant can be computed by: floor(n/2) n Det(H(n)) = (-1) * n =cut *mhankel = \&PDL::mhankel; sub PDL::mhankel { my $di = $_[0]->dims_internal; my ($m, $n) = @_; $m = xvals($m) + 1 unless ref($m); my @dims = $m->dims; $n = PDL::zeroes($m) unless defined $n; my $index = xvals($dims[$di]); $index = $index->dummy(0) + $index; if (@dims == 2){ $m = mstack($m,$n(,1:)); $n = $m->re->index($index)->r2C; $n((1),).= $m((1),)->index($index); return $n; } else{ $m = augment($m,$n(1:)); return $m->index($index)->sever; } } =head2 mtoeplitz =for ref Return toeplitz matrix. Handles complex data. =for usage mtoeplitz(c,r), where c and r are vectors, returns matrix whose first column is c and whose last row is r. The last element of c prevails. mtoeplitz(c) returns symmetric matrix. =cut *mtoeplitz = \&PDL::mtoeplitz; sub PDL::mtoeplitz { my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my ($m, $n) = @_; $n = $m->copy unless defined $n; my $mdim= $m->dim(-1); my $ndim= $n->dim(-1); my $res = $m->_similar($ndim,$mdim); $ndim--; my $min = $mdim <= $ndim ? $mdim : $ndim; for(1..$min) { $res->slice("$slice_prefix$_:,(@{[$_-1]})") .= $n->slice("${slice_prefix}1:@{[$ndim-$_+1]}"); } $mdim--; $min = $mdim < $ndim ? $mdim : $ndim; for(0..$min){ $res->slice("${slice_prefix}($_),$_:") .= $m->slice("${slice_prefix}:@{[$mdim-$_]}"); } return $res; } =head2 mpascal Return Pascal matrix (from Pascal's triangle) of order N. =for usage mpascal(N,uplo). uplo: 0 => upper triangular (Cholesky factor), 1 => lower triangular (Cholesky factor), 2 => symmetric. =for ref This matrix is obtained by writing Pascal's triangle (whose elements are binomial coefficients from index and/or index sum) as a matrix and truncating appropriately. The symmetric Pascal is positive definite, its inverse has integer entries. Their determinants are all equal to one and: S = L * U where S, L, U are symmetric, lower and upper pascal matrix respectively. =cut *mpascal = \&PDL::mpascal; sub PDL::mpascal { my ($m, $n) = @_; my $mat = eval { require PDL::GSLSF::GAMMA; if ($n > 1){ my $mat = xvals($m); return (PDL::GSLSF::GAMMA::gsl_sf_choose($mat + $mat->dummy(0),$mat))[0]; }else{ my $mat = xvals($m, $m); return (PDL::GSLSF::GAMMA::gsl_sf_choose($mat->tritosym,$mat->xchg(0,1)->tritosym))[0]->mtri($n); } }; return $mat if !$@; warn("mpascal: can't compute binomial coefficients without". " PDL::GSLSF::GAMMA\n"); return; } =head2 mcompanion Return a matrix with characteristic polynomial equal to p if p is monic. If p is not monic the characteristic polynomial of A is equal to p/c where c is the coefficient of largest degree in p (here p is in descending order). =for usage mcompanion(PDL(p),SCALAR(charpol)). charpol: 0 => first row is -P(1:n-1)/P(0), 1 => last column is -P(1:n-1)/P(0), =cut *mcompanion = \&PDL::mcompanion; sub PDL::mcompanion{ my $di = $_[0]->dims_internal; my $slice_prefix = ',' x $di; my ($m, $char) = @_; my( @dims, $dim, $ret); $m = $m->{PDL} if (UNIVERSAL::isa($m, 'HASH') && exists $m->{PDL}); @dims = $m->dims; $dim = $dims[-1] - 1; my $id = identity($dim-1); $id = $id->r2C if $m->_is_complex; if($char){ $ret = (-$m->slice("${slice_prefix}1:$dim")->dummy($di+1)/$m->slice("${slice_prefix}0"))->_call_method('mstack', $id->mstack(zeroes($m->dims_internal_values,$dim-1)->dummy($di))); } else{ $ret = $m->_similar($dim-1)->dummy($di+1)->_call_method('mstack', $id)->mstack(-$m->slice("${slice_prefix}$dim:1")->dummy($di)/$m->slice("${slice_prefix}(0)")); } $ret->sever; } =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2007. This library is free software; you can redistribute it and/or modify it under the terms of the artistic license as specified in the Artistic file. =cut # Exit with OK status 1; PDL-LinearAlgebra-0.38/Trans/0000755000175000017500000000000014565105646015602 5ustar osboxesosboxesPDL-LinearAlgebra-0.38/Trans/trans.pd0000644000175000017500000011654214560470320017254 0ustar osboxesosboxesour $VERSION = '0.14'; pp_setversion($VERSION); $VERSION = eval $VERSION; if ($^O =~ /MSWin/) { pp_addhdr(' #include '); } pp_addhdr(' #include #define CONCAT_(A, B) A ## B #define CONCAT(A, B) CONCAT_(A, B) #define FORTRAN(name) CONCAT(name, F77_USCORE) typedef PDL_Long logical; typedef PDL_Long integer; typedef PDL_Long ftnlen; #ifndef abs #define abs(x) ((x) >= 0 ? (x) : -(x)) #endif #ifndef max #define max(a,b) ((a) >= (b) ? (a) : (b)) #endif '); pp_addpm({At=>'Top'},<<'EOD'); use PDL::Func; use PDL::Core; use PDL::Slices; use PDL::Ops qw//; use PDL::Math qw/floor/; use PDL::MatrixOps qw/identity/; use PDL::LinearAlgebra; use PDL::LinearAlgebra::Real qw //; use PDL::LinearAlgebra::Complex qw //; use strict; =encoding Latin-1 =head1 NAME PDL::LinearAlgebra::Trans - Linear Algebra based transcendental functions for PDL =head1 SYNOPSIS use PDL::LinearAlgebra::Trans; $a = random (100,100); $sqrt = msqrt($a); =head1 DESCRIPTION This module provides some transcendental functions for matrices. Moreover it provides sec, asec, sech, asech, cot, acot, acoth, coth, csc, acsc, csch, acsch. Beware, importing this module will overwrite the hidden PDL routine sec. If you need to call it specify its origin module : PDL::Basic::sec(args) =cut EOD pp_add_exported('', ' mexp mexpts mlog msqrt mpow mcos msin mtan msec mcsc mcot mcosh msinh mtanh msech mcsch mcoth macos masin matan masec macsc macot macosh masinh matanh masech macsch macoth sec asec sech asech cot acot acoth coth mfun csc acsc csch acsch toreal pi'); pp_def('geexp', Pars => '[io,phys]A(n,n);int deg();scale();[io]trace();int [o]ns();int [o]info(); int [t]ipiv(n); [t]wsp(wspn);', RedoDimsCode => ' $SIZE(wspn) = 3 * $SIZE(n) * $SIZE(n); ', GenericTypes => [D], Code => ' /* ----------------------------------------------------------------------| int dgpadm_(integer *ideg, integer *m, double *t, double *h__, integer *ldh, double *wsp, integer *lwsp, integer *ipiv, integer *iexph, integer *ns, integer *iflag) -----Purpose----------------------------------------------------------| Computes exp(t*H), the matrix exponential of a general matrix in full, using the irreducible rational Pade approximation to the exponential function exp(x) = r(x) = (+/-)( I + 2*(q(x)/p(x)) ), combined with scaling-and-squaring. -----Arguments--------------------------------------------------------| ideg|deg : (input) the degre of the diagonal Pade to be used. a value of 6 is generally satisfactory. m : (input) order of H. H|A(ldh,m): (input) argument matrix. t|scale : (input) time-scale (can be < 0). wsp|exp(lwsp) : (workspace/output) lwsp .ge. 4*m*m+ideg+1. ipiv(m) : (workspace) >>>> iexph|index : (output) number such that wsp(iexph) points to exp(tH) i.e., exp(tH) is located at wsp(iexph ... iexph+m*m-1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NOTE: if the routine was called with wsp(iptr), then exp(tH) will start at wsp(iptr+iexph-1). ns : (output) number of scaling-squaring used. iflag|info : (output) exit flag. 0 - no problem > 0 - Singularity in LU factorization when solving Pade approximation ----------------------------------------------------------------------| Roger B. Sidje (rbs@maths.uq.edu.au) EXPOKIT: Software Package for Computing Matrix Exponentials. ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 Gregory Vanuxem (vanuxemg@yahoo.fr) Minor modifications (Fortran to C with help of f2c, memory allocation, PDL adaptation, null entry matrix, error return, exp(tH) in entry matrix, trace normalization). ----------------------------------------------------------------------| */ extern int FORTRAN(dscal)(integer *, double *, double *, integer *); extern int FORTRAN(dgemm)(char *, char *, integer *, integer *, integer *, double *, double *, integer *, double *, integer *, double *, double *, integer *, ftnlen, ftnlen); extern int FORTRAN(dgesv)(integer *, integer *, double *, integer *, integer *, double *, integer *, integer *); extern int FORTRAN(daxpy)(integer *, double *, double *, integer *, double *, integer *); extern double FORTRAN(dlange)(char *norm, integer *m, integer *n, double *a, integer *lda, double *work); integer i__1, i__2, i__, j, k; integer ip, mm, iq, ih2, ifree, iused, iodd, iget, iput; double cp, cq, scale, scale2, hnorm, tracen; double *coef, *wsp = $P(wsp); integer c__1 = 1; integer c__2 = 2; double c_b7 = 0.; double c_b11 = 1.; double c_b19 = -1.; double c_b23 = 2.; double *h__ = $P(A); $info() = 0; ///////////// mm = $SIZE(n) * $SIZE(n); coef = (double *) malloc(($deg() + 1 + mm) * sizeof(double)); ////////// // --- initialise pointers ... ih2 = $deg() + 1; ip = 0; iq = mm; ifree = iq + mm; tracen = 0; if ($trace()) { loop(n0) %{ tracen += h__[n0 + n0 * $SIZE(n)]; %} tracen /= $SIZE(n); if (tracen > 0) { loop(n0) %{ h__[n0 + n0 * $SIZE(n)] -= tracen; %} } } // --- scaling: seek ns such that ||t*H/2^ns|| < 1/2; // and set scale = t/2^ns ... // Compute Infinity norm hnorm = FORTRAN(dlange)("I", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, $P(A), &(integer){$SIZE(n)}, wsp); hnorm = abs($scale() * hnorm); if (hnorm == 0.) { free(coef); coef = $P(A); $ns() = 0; loop(n0,n1) %{ coef[n1 + n0 * $SIZE(n)] = (n0 == n1) ? 1 : 0; %} } else { i__2 = (integer ) (log(hnorm) / log(2.0) + 2); $ns() = max(0, i__2); scale = $scale() / pow(2.0, (double )$ns()); scale2 = scale * scale; // --- compute Pade coefficients ... i__ = $deg() + 1; j = ($deg() << 1) + 1; coef[0] = 1.; i__1 = $deg(); for (k = 1; k <= i__1; ++k) { coef[k] = coef[k - 1] * (double) (i__ - k) / (double) (k * (j - k)); } // --- H2 = scale2*H*H ... FORTRAN(dgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &scale2, h__, &(integer){$SIZE(n)}, h__, &(integer){$SIZE(n)}, &c_b7, &coef[ih2], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); // --- initialize p (numerator) and q (denominator) ... cp = coef[$deg() - 1]; cq = coef[$deg()]; loop(n0) %{ loop(n1) %{ wsp[ip + n0 * $SIZE(n) + n1] = 0.; wsp[iq + n0 * $SIZE(n) + n1] = 0.; %} wsp[ip + n0 * ($SIZE(n) + 1)] = cp; wsp[iq + n0 * ($SIZE(n) + 1)] = cq; %} // --- Apply Horner rule ... iodd = 1; k = $deg() - 2; do{ iused = iodd * iq + (1 - iodd) * ip; FORTRAN(dgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &c_b11, &wsp[iused], &(integer){$SIZE(n)}, &coef[ih2], &(integer){$SIZE(n)}, &c_b7, & wsp[ifree], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); loop(n0) %{ wsp[ifree + n0 * ($SIZE(n) + 1)] += coef[k]; %} ip = (1 - iodd) * ifree + iodd * ip; iq = iodd * ifree + (1 - iodd) * iq; ifree = iused; iodd = 1 - iodd; --k; } while (k >= 0); // --- Obtain (+/-)(I + 2*(p\q)) ... if (iodd == 1) { FORTRAN(dgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &scale, &wsp[iq], &(integer){$SIZE(n)}, h__, &(integer){$SIZE(n)}, & c_b7, &wsp[ifree], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); iq = ifree; } else { FORTRAN(dgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &scale, &wsp[ip], &(integer){$SIZE(n)}, h__, &(integer){$SIZE(n)}, & c_b7, &wsp[ifree], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); ip = ifree; } FORTRAN(daxpy)(&mm, &c_b19, &wsp[ip], &c__1, &wsp[iq], &c__1); FORTRAN(dgesv)(&(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &wsp[iq], &(integer){$SIZE(n)}, $P(ipiv), &wsp[ip], &(integer){$SIZE(n)}, $P(info)); if ($info() != 0) { free(coef); } else { FORTRAN(dscal)(&mm, &c_b23, &wsp[ip], &c__1); loop(n0) %{ wsp[ip + n0 * ($SIZE(n) + 1)] += 1.; %} iput = ip; if ($ns() == 0 && iodd == 1) FORTRAN(dscal)(&mm, &c_b19, &wsp[ip], &c__1); else{ // -- squaring : exp(t*H) = (exp(t*H))^(2^ns) ... iodd = 1; i__1 = $ns(); for (k = 0; k < i__1; k++) { iget = iodd * ip + (1 - iodd) * iq; iput = (1 - iodd) * ip + iodd * iq; FORTRAN(dgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &c_b11, &wsp[iget], &(integer){$SIZE(n)}, &wsp[iget], &(integer){$SIZE(n)}, &c_b7, &wsp[iput], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); iodd = 1 - iodd; } } free(coef); coef = $P(A); i__2 = iput + mm; i__ = 0; $trace() = tracen; if (tracen > 0) { scale = exp(tracen); for (i__1 = iput; i__1 < i__2 ; i__1++) coef[i__++] = scale * wsp[i__1]; } else { for (i__1 = iput; i__1 < i__2 ; i__1++) coef[i__++] = wsp[i__1]; } } } ', Doc => < 0 - Singularity in LU factorization when solving Pade approximation =for example $a = random(5,5); $trace = pdl(1); $a->t->geexp(6,1,$trace, ($ns = null), ($info = null)); =cut EOT ); do '../pp_defc.pl'; die if $@; pp_defc('geexp', Pars => '[io,phys]A(2,n,n);int deg();scale();int trace();int [o]ns();int [o]info(); int [t] ipiv(n)', Doc => ' =for ref Complex version of geexp. The value used for trace normalization is not returned. The algorithm is described in Roger B. Sidje (rbs@maths.uq.edu.au) "EXPOKIT: Software Package for Computing Matrix Exponentials". ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 ', GenericTypes => [D], Code => ' /* ----------------------------------------------------------------------| int dgpadm_(integer *ideg, integer *m, double *t, PDL_CDouble *h__, integer *ldh, PDL_CDouble *wsp, integer *lwsp, integer *ipiv, integer *iexph, integer *ns, integer *iflag) -----Purpose----------------------------------------------------------| Computes exp(t*H), the matrix exponential of a general matrix in full, using the irreducible rational Pade approximation to the exponential function exp(x) = r(x) = (+/-)( I + 2*(q(x)/p(x)) ), combined with scaling-and-squaring. -----Arguments--------------------------------------------------------| ideg|deg : (input) the degre of the diagonal Pade to be used. a value of 6 is generally satisfactory. m : (input) order of H. H|A(ldh,m): (input) argument matrix. t|scale : (input) time-scale (can be < 0). wsp|exp(lwsp) : (workspace/output) lwsp .ge. 4*m*m+ideg+1. ipiv(m) : (workspace) >>>> iexph : (output) number such that wsp(iexph) points to exp(tH) i.e., exp(tH) is located at wsp(iexph ... iexph+m*m-1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NOTE: if the routine was called with wsp(iptr), then exp(tH) will start at wsp(iptr+iexph-1). ns : (output) number of scaling-squaring used. iflag|info : (output) exit flag. 0 - no problem > 0 - Singularity in LU factorization when solving Pade approximation ----------------------------------------------------------------------| Roger B. Sidje (rbs@maths.uq.edu.au) EXPOKIT: Software Package for Computing Matrix Exponentials. ACM - Transactions On Mathematical Software, 24(1):130-156, 1998 Gregory Vanuxem (vanuxemg@yahoo.fr) Minor modifications (Fortran to C with help of f2c, memory allocation, PDL adaptation, null entry matrix, error return, exp(tH) in entry matrix), trace normalization. ----------------------------------------------------------------------| */ static PDL_CDouble c_b1 = 0; static PDL_CDouble c_b2 = 1; static integer c__2 = 2; static integer c__1 = 1; static double c_b19 = 2.; static double c_b21 = -1.; integer i__1, i__2, i__3, i__, j, k; integer ip, mm, iq, ih2, iodd, iget, iput, ifree, iused; double hnorm,d__1, d__2; PDL_CDouble scale, tracen, cp, cq, z__1; PDL_CDouble scale2; PDL_CDouble *wsp, *h__; extern int FORTRAN(zgemm)(char *, char *, integer *, integer *, integer *, PDL_CDouble *, PDL_CDouble *, integer *, PDL_CDouble *, integer *, PDL_CDouble *, PDL_CDouble *, integer *, ftnlen, ftnlen); extern int FORTRAN(zgesv)(integer *, integer *, PDL_CDouble *, integer *, integer *, PDL_CDouble *, integer *, integer *); extern int FORTRAN(zaxpy)(integer *, PDL_CDouble *, PDL_CDouble *, integer *, PDL_CDouble *, integer *), FORTRAN(zdscal)( integer *, double *, PDL_CDouble *, integer *); extern double FORTRAN(zlange)(char *norm, integer *m, integer *n, PDL_CDouble *a, integer *lda, PDL_CDouble *work); h__ = (PDL_CDouble *) $P(A); wsp = malloc (( $deg() + 1 + 4 * $SIZE(n) * $SIZE(n)) * sizeof (PDL_CDouble)); mm = $SIZE(n) * $SIZE(n); $info() = 0; ih2 = $deg() + 1; ip = ih2 + mm; iq = ip + mm; ifree = iq + mm; tracen = 0; if ($trace()) { loop(n0) %{ tracen += h__[n0 + n0 * $SIZE(n)]; %} tracen /= $SIZE(n); if (creal(tracen) < 0){ tracen = cimag(tracen); } loop(n0) %{ h__[n0 + n0 * $SIZE(n)] -= tracen; %} } // --- scaling: seek ns such that ||t*H/2^ns|| < 1/2; // and set scale = t/2^ns ... // Compute Infinity norm hnorm = FORTRAN(zlange)("I", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, h__, &(integer){$SIZE(n)}, wsp); hnorm = abs($scale() * hnorm); if (hnorm == 0.) { $ns() = 0; loop(n0,n1) %{ h__[n1 + n0 * $SIZE(n) ] = (n0 == n1) ? 1 : 0; %} } else { i__2 = (integer) ((log(hnorm) / log(2.)) + 2); $ns() = max(0,i__2); scale = $scale() / pow(2, (double )$ns()); scale2 = scale * scale; // --- compute Pade coefficients ... i__ = $deg() + 1; j = ($deg() << 1) + 1; wsp[0] = 1; for (k = 1; k <= $deg(); ++k) { d__1 = (double) (i__ - k); d__2 = (double) (k * (j - k)); wsp[k] = (d__1 * wsp[k - 1]) / d__2; } // --- H2 = scale2*H*H ... FORTRAN(zgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &scale2, &h__[0], &(integer){$SIZE(n)}, &h__[0], &(integer){$SIZE(n)}, &c_b1, &wsp[ih2], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); // --- initialise p (numerator) and q (denominator) ... cp = wsp[$deg() - 1]; cq = wsp[$deg()]; loop(n0) %{ loop(n1) %{ i__3 = ip + n0 * $SIZE(n) + n1; wsp[i__3] = 0.; i__3 = iq + n0 * $SIZE(n) + n1; wsp[i__3] = 0.; %} i__2 = ip + n0 * ($SIZE(n) + 1); wsp[i__2] = cp; i__2 = iq + n0 * ($SIZE(n) + 1); wsp[i__2] = cq; %} // --- Apply Horner rule ... iodd = 1; k = $deg() - 2; do { iused = iodd * iq + (1 - iodd) * ip; FORTRAN(zgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &c_b2, &wsp[iused], &(integer){$SIZE(n)}, &wsp[ih2], &(integer){$SIZE(n)}, &c_b1, & wsp[ifree], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); loop(n0) %{ i__1 = ifree + n0 * ($SIZE(n) + 1); i__2 = ifree + n0 * ($SIZE(n) + 1); i__3 = k; wsp[i__1] = wsp[i__2] + wsp[i__3]; %} ip = (1 - iodd) * ifree + iodd * ip; iq = iodd * ifree + (1 - iodd) * iq; ifree = iused; iodd = 1 - iodd; --k; } while(k >= 0); // --- Obtain (+/-)(I + 2*(p\q)) ... if (iodd != 0) { FORTRAN(zgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &scale, &wsp[iq], &(integer){$SIZE(n)}, &h__[0], &(integer){$SIZE(n)}, & c_b1, &wsp[ifree], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); iq = ifree; }else { FORTRAN(zgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &scale, &wsp[ip], &(integer){$SIZE(n)}, &h__[0], &(integer){$SIZE(n)}, & c_b1, &wsp[ifree], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); ip = ifree; } z__1 = -1.; FORTRAN(zaxpy)(&mm, &z__1, &wsp[ip], &c__1, &wsp[iq], &c__1); FORTRAN(zgesv)(&(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &wsp[iq], &(integer){$SIZE(n)}, $P(ipiv), &wsp[ip], &(integer){$SIZE(n)}, $P(info)); if ($info() == 0) { FORTRAN(zdscal)(&mm, &c_b19, &wsp[ip], &c__1); loop(n0) %{ i__2 = ip + n0 * ($SIZE(n) + 1); i__3 = ip + n0 * ($SIZE(n) + 1); wsp[i__2] = wsp[i__3] + 1.; %} iput = ip; if ($ns() == 0 && iodd != 0) FORTRAN(zdscal)(&mm, &c_b21, &wsp[ip], &c__1); else { // -- squaring : exp(t*H) = (exp(t*H))^(2^ns) ... iodd = 1; for (k = 0; k < $ns(); k++) { iget = iodd * ip + (1 - iodd) * iq; iput = (1 - iodd) * ip + iodd * iq; FORTRAN(zgemm)("n", "n", &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &(integer){$SIZE(n)}, &c_b2, &wsp[iget], &(integer){$SIZE(n)}, &wsp[iget], &(integer){$SIZE(n)}, &c_b1, &wsp[iput], &(integer){$SIZE(n)}, (ftnlen)1, (ftnlen)1); iodd = 1 - iodd; } } } i__2 = iput + mm; i__ = 0; if ($trace()) { tracen = cexp(tracen); for (i__1 = iput; i__1 < i__2 ; i__1++) { h__[i__++] = tracen * wsp[i__1]; } } else { for (i__1 = iput; i__1 < i__2 ; i__1++) { h__[i__++] = wsp[i__1]; } } } free(wsp); ', ); pp_defc('trsqrt', Pars => '[io,phys]A(2,n,n);int uplo();[phys,o] B(2,n,n);int [o]info()', Doc => ' =for ref Root square of complex triangular matrix. Uses a recurrence of Björck and Hammarling. (See Nicholas J. Higham. A new sqrtm for MATLAB. Numerical Analysis Report No. 336, Manchester Centre for Computational Mathematics, Manchester, England, January 1999. It\'s available at http://www.ma.man.ac.uk/~higham/pap-mf.html) If uplo is true, A is lower triangular. ', GenericTypes => [D], Code => ' PDL_CDouble *cb, *ca; PDL_CDouble s, snum, sdenum; double *b; double tt, dn; integer i, j, k, l, ind, ind1, ind2; ca = (PDL_CDouble *) $P(A); b = (void *)$P(B); cb = (PDL_CDouble *) $P(B); #define subscr(a_1,a_2)\ ($uplo()) ? (a_2) * $SIZE(n) + (a_1) : (a_1) * $SIZE(n) + (a_2) $info() = 0; ind = $SIZE(n) * $SIZE(n) * 2; for (i = 0; i < ind;i++) b[i] = 0; loop(n0) %{ ind = subscr(n0,n0); cb[ind] = csqrt(ca[ind]); %} for (k = 0; k < $SIZE(n)-1; k++) { for (i = 0; i < $SIZE(n)-(k+1); i++) { j = i + k + 1; ind = subscr(i,j); s = 0; for (l = i+1; l < j; l++) { ind1 = subscr(i,l); ind2 = subscr(l,j); s += cb[ind1] * cb[ind2]; } ind1 = subscr(i,i); ind2 = subscr(j,j); sdenum = cb[ind1] + cb[ind2]; snum = ca[ind] - s; if (fabs (creal(sdenum)) > fabs (cimag(sdenum))) { if (creal(sdenum) == 0){ $info() = -1; goto ENDCTRSQRT; } tt = cimag(sdenum) / creal(sdenum); dn = creal(sdenum) + tt * cimag(sdenum); cb[ind] = (snum + tt * (-I * snum)) / dn; } else { if (cimag(sdenum) == 0){ $info() = -1; goto ENDCTRSQRT; } tt = creal(sdenum) / cimag(sdenum); dn = creal(sdenum) * tt + cimag(sdenum); cb[ind] = (snum * tt + (-I * snum)) / dn; } } } ENDCTRSQRT: ; #undef subscr ', ); pp_addhdr(' void dfunc_wrapper(PDL_CDouble *p, integer n, SV* dfunc); '); pp_defc('trfun', Pars => '[io]A(2,n,n);int uplo();[o] B(2,n,n);int [o]info(); complex [t]diag(n);', OtherPars => "SV* func" , Doc => ' =for ref Apply an arbitrary function to a complex triangular matrix. Uses a recurrence of Parlett. If uplo is true, A is lower triangular. ', GenericTypes => [D], Code => ' PDL_CDouble *cb, *ca; PDL_CDouble s, snum, sdenum; double *b; double tt, dn; integer i, j, k, l, p, ind, ind1, ind2, tmp, c__1; extern double FORTRAN(zdotu)(PDL_CDouble *ret, integer *n, PDL_CDouble *dx, integer *incx, PDL_CDouble *dy, integer *incy); ca = (PDL_CDouble *) $P(A); b = (double *)$P(B); cb = (PDL_CDouble *) $P(B); c__1 = 1; #define subscr(a_1,a_2) \ ( $uplo() ) ? (a_2)+ $SIZE(n) * (a_1) : (a_1)+ $SIZE(n) * (a_2) $info() = 0; ind = $SIZE(n) * $SIZE(n) * 2; for (i = 0; i < ind;i++) b[i] = 0; loop (n) %{ $diag() = ca[subscr(n,n)]; %} dfunc_wrapper($P(diag), $SIZE(n), $COMP(func)); loop (n) %{ cb[subscr(n,n)] = $diag(); %} for (p = 1; p < $SIZE(n); p++) { tmp = $SIZE(n) - p; for (i = 0; i < tmp; i++) { j = i + p; //$s = $T(,($j),($i))->Cmul($F(,($j),($j))->Csub($F(,($i),($i)))); ind1 = subscr(i,i); ind2 = subscr(j,j); ind = subscr(j,i); s = snum = ca[ind] * (cb[ind2] - cb[ind1]); if (i < (j-1)) { //$s = $s + $T(,$i+1:$j-1,($i))->cdot(1, $F(,($j), $i+1:$j-1),1)->Csub($F(,$i+1:$j-1,($i))->cdot(1,$T(,($j), $i+1:$j-1),1)); // $T(,$i+1:$j-1,($i))->cdot(1, $F(,($j), $i+1:$j-1),1) l = 0; for(k = i+1; k < j; k++) $diag(n=>l++) = cb[subscr(j,k)]; ind = subscr(i+1,i); // TODO : Humm FORTRAN(zdotu)(&s, &l, &ca[ind], &c__1, $P(diag), &c__1); snum += s; // $F(,$i+1:$j-1,($i))->cdot(1,$T(,($j), $i+1:$j-1),1) l = 0; for(k = i+1; k < j; k++) $diag(n=>l++) = ca[subscr(j,k)]; ind = subscr(i+1,i); // TODO : Humm FORTRAN(zdotu)(&s, &l, &cb[ind], &c__1, $P(diag), &c__1); snum -= s; ind = subscr(j,i); } //$sdenum = $T(,($j),($j))->Csub($T(,($i),($i))); sdenum = ca[ind2] - ca[ind1]; //$s = $s / $sdenum; if (fabs (creal(sdenum)) > fabs (cimag(sdenum))) { if (creal(sdenum) == 0) { $info() = -1; goto ENDCTRFUN; } tt = cimag(sdenum) / creal(sdenum); dn = creal(sdenum) + tt * cimag(sdenum); cb[ind] = (snum + tt * (-I * snum)) / dn; } else { if (cimag(sdenum) == 0) { $info() = -1; goto ENDCTRFUN; } tt = creal(sdenum) / cimag(sdenum); dn = creal(sdenum) * tt + cimag(sdenum); cb[ind] = (snum * tt + (-I * snum)) / dn; } } } ENDCTRFUN: ; #undef subscr ', ); pp_addpm(<<'EOD'); my $pi; BEGIN { $pi = pdl(3.1415926535897932384626433832795029) } sub pi () { $pi->copy }; *sec = \&PDL::sec; sub PDL::sec{1/cos($_[0])} *csc = \&PDL::csc; sub PDL::csc($) {1/sin($_[0])} *cot = \&PDL::cot; sub PDL::cot($) {1/(sin($_[0])/cos($_[0]))} *sech = \&PDL::sech; sub PDL::sech($){1/pdl($_[0])->cosh} *csch = \&PDL::csch; sub PDL::csch($) {1/pdl($_[0])->sinh} *coth = \&PDL::coth; sub PDL::coth($) {1/pdl($_[0])->tanh} *asec = \&PDL::asec; sub PDL::asec($) {my $tmp = 1/pdl($_[0]) ; $tmp->acos} *acsc = \&PDL::acsc; sub PDL::acsc($) {my $tmp = 1/pdl($_[0]) ; $tmp->asin} *acot = \&PDL::acot; sub PDL::acot($) {my $tmp = 1/pdl($_[0]) ; $tmp->atan} *asech = \&PDL::asech; sub PDL::asech($) {my $tmp = 1/pdl($_[0]) ; $tmp->acosh} *acsch = \&PDL::acsch; sub PDL::acsch($) {my $tmp = 1/pdl($_[0]) ; $tmp->asinh} *acoth = \&PDL::acoth; sub PDL::acoth($) {my $tmp = 1/pdl($_[0]) ; $tmp->atanh} my $_tol = 9.99999999999999e-15; sub toreal{ return $_[0] if $_[0]->isempty; $_tol = $_[1] if defined $_[1]; my ($min, $max, $tmp); ($min, $max) = $_[0]->im->minmax; return $_[0]->re->sever unless (abs($min) > $_tol || abs($max) > $_tol); $_[0]; } =head2 mlog =for ref Return matrix logarithm of a square matrix. =for usage PDL = mlog(PDL(A)) =for example my $a = random(10,10); my $log = mlog($a); =cut *mlog = \&PDL::mlog; sub PDL::mlog { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; mfun($m, sub{$_[0].=log $_[0]} , 0, $tol); } =head2 msqrt =for ref Return matrix square root (principal) of a square matrix. =for usage PDL = msqrt(PDL(A)) =for example my $a = random(10,10); my $sqrt = msqrt($a); =cut *msqrt = \&PDL::msqrt; sub PDL::msqrt { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; $m = $m->r2C unless $m->_is_complex; my ($t, undef, $z, undef, $info) = $m->mschur(1); if ($info){ warn "msqrt: Can't compute Schur form\n"; return; } ($t, $info) = $t->ctrsqrt(0); if($info){ warn "msqrt: can't compute square root\n"; return; } $m = $z x $t x $z->t(1); return $m->_is_complex ? $m : toreal($m, $tol); } =head2 mexp =for ref Return matrix exponential of a square matrix. =for usage PDL = mexp(PDL(A)) =for example my $a = random(10,10); my $exp = mexp($a); =cut *mexp = \&PDL::mexp; sub PDL::mexp { &PDL::LinearAlgebra::_square; my ($m, $order, $trace) = @_; $trace = 1 unless defined $trace; $order = 6 unless defined $order; $m = $m->copy; $m->t->_call_method('geexp', $order, 1, $trace, my $ns = PDL->null, my $info = PDL->null); if ($info){ warn "mexp: Error $info"; } else{ return $m; } } *mexpts = \&PDL::mexpts; sub PDL::mexpts { &PDL::LinearAlgebra::_square; my ($m, $order, $tol) = @_; my @dims = $m->dims; my ($em, $trm); $order = 20 unless defined $order; $em = $m->_is_complex ? diag(r2C(ones($dims[1]))) : diag(ones($dims[1])); $trm = $em->copy; for (1..($order - 1)){ $trm = $trm x ($m / $_); $em += $trm; } return $m->_is_complex ? $em : toreal($em, $tol); } =head2 mpow =for ref Return matrix power of a square matrix. =for usage PDL = mpow(PDL(A), SCALAR(exponent)) =for example my $a = random(10,10); my $powered = mpow($a,2.5); =cut *mpow = \&PDL::mpow; sub PDL::mpow { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $power, $tol, $eigen) = @_; my @dims = $m->dims; my $ret; if (UNIVERSAL::isa($power,'PDL') and $power->dims > 1){ my ($e, $v) = $m->meigen(0,1); $ret = $v * ($e**$power) x $v->minv; } elsif( 1/$dims[$di] * 1000 > abs($power) and !$eigen){ $ret = identity($dims[$di]); $ret = $ret->r2C if $m->_is_complex; my $pow = floor($power); $pow++ if ($power < 0 and $power != $pow); # TODO: what a beautiful thing (is it a game ?) for(my $i = 0; $i < abs($pow); $i++){$ret x= $m;} $ret = $ret->minv if $power < 0; if ($power = $power - $pow){ if($power == 0.5){ my $v = $m->msqrt; $ret = ($pow == 0) ? $v : $ret x $v; } else{ my ($e, $v) = $m->meigen(0,1); $ret = ($pow == 0) ? ($v * $e**$power x $v->minv) : $ret->r2C x ($v * $e**$power x $v->minv); } } } else{ my ($e, $v) = $m->meigen(0,1); $ret = $v * $e**$power x $v->minv; } return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 mcos =for ref Return matrix cosine of a square matrix. =for usage PDL = mcos(PDL(A)) =for example my $a = random(10,10); my $cos = mcos($a); =cut sub _i { defined $PDL::Complex::VERSION ? PDL::Complex::i() : i(); } *mcos = \&PDL::mcos; sub PDL::mcos { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); return $m->_is_complex ? (mexp($i*$m) + mexp(- $i*$m)) / 2 : mexp($i*$m)->re->sever; } =head2 macos =for ref Return matrix inverse cosine of a square matrix. =for usage PDL = macos(PDL(A)) =for example my $a = random(10,10); my $acos = macos($a); =cut *macos = \&PDL::macos; sub PDL::macos { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $i = _i(); my $ret = $i * mlog( ($m->r2C - $i * msqrt( ($id - $m x $m), $tol))); return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 msin =for ref Return matrix sine of a square matrix. =for usage PDL = msin(PDL(A)) =for example my $a = random(10,10); my $sin = msin($a); =cut *msin = \&PDL::msin; sub PDL::msin { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); $m->_is_complex ? (mexp($i*$m) - mexp(- $i*$m))/(2*$i) : mexp($i*$m)->im->sever; } =head2 masin =for ref Return matrix inverse sine of a square matrix. =for usage PDL = masin(PDL(A)) =for example my $a = random(10,10); my $asin = masin($a); =cut *masin = \&PDL::masin; sub PDL::masin { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $i = _i(); my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = (-$i) * mlog((($i*$m) + msqrt($id - $m x $m, $tol))); return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 mtan =for ref Return matrix tangent of a square matrix. =for usage PDL = mtan(PDL(A)) =for example my $a = random(10,10); my $tan = mtan($a); =cut *mtan = \&PDL::mtan; sub PDL::mtan { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; return scalar msolvex(mcos($m), msin($m),equilibrate=>1) unless $id; my $i = _i(); if ($m->_is_complex){ my $di = $_[0]->dims_internal; $id = identity($dims[$di])->r2C; $m = mexp(-2*$i*$m); return scalar msolvex( ($id + $m ),( (- $i) * ($id - $m)),equilibrate=>1); } else{ $m = mexp($i * $m); return scalar $m->re->msolvex($m->im,equilibrate=>1); } } =head2 matan =for ref Return matrix inverse tangent of a square matrix. =for usage PDL = matan(PDL(A)) =for example my $a = random(10,10); my $atan = matan($a); =cut *matan = \&PDL::matan; sub PDL::matan { &PDL::LinearAlgebra::_square; my $di = $_[0]->dims_internal; my ($m, $tol) = @_; my @dims = $m->dims; my $i = _i(); my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = -$i/2 * mlog( scalar PDL::msolvex( ($id - $i*$m) ,($id + $i*$m),equilibrate=>1 )); return $m->_is_complex ? $ret : toreal($ret, $tol); } =head2 mcot =for ref Return matrix cotangent of a square matrix. =for usage PDL = mcot(PDL(A)) =for example my $a = random(10,10); my $cot = mcot($a); =cut *mcot = \&PDL::mcot; sub PDL::mcot { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; return scalar msolvex(msin($m),mcos($m),equilibrate=>1) unless $id; my $i = _i(); if ($m->_is_complex){ my $di = $_[0]->dims_internal; $id = identity($dims[$di])->r2C; $m = mexp(-2*$i*$m); return scalar msolvex( ($id - $m), ($i * ($id + $m)), equilibrate=>1); } else{ $m = mexp($i * $m); return scalar $m->im->msolvex($m->re,equilibrate=>1); } } =head2 macot =for ref Return matrix inverse cotangent of a square matrix. =for usage PDL = macot(PDL(A)) =for example my $a = random(10,10); my $acot = macot($a); =cut *macot = \&PDL::macot; sub PDL::macot { &PDL::LinearAlgebra::_square; my ($m, $tol, $id) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macot: singular matrix"; return; } return matan($inv,$tol); } =head2 msec =for ref Return matrix secant of a square matrix. =for usage PDL = msec(PDL(A)) =for example my $a = random(10,10); my $sec = msec($a); =cut *msec = \&PDL::msec; sub PDL::msec { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); return $m->_is_complex ? PDL::minv(mexp($i*$m) + mexp(- $i*$m)) * 2 : scalar PDL::minv(re(mexp($i*$m))); } =head2 masec =for ref Return matrix inverse secant of a square matrix. =for usage PDL = masec(PDL(A)) =for example my $a = random(10,10); my $asec = masec($a); =cut *masec = \&PDL::masec; sub PDL::masec { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "masec: singular matrix"; return; } return macos($inv,$tol); } =head2 mcsc =for ref Return matrix cosecant of a square matrix. =for usage PDL = mcsc(PDL(A)) =for example my $a = random(10,10); my $csc = mcsc($a); =cut *mcsc = \&PDL::mcsc; sub PDL::mcsc { &PDL::LinearAlgebra::_square; my $m = shift; my $i = _i(); $m->_is_complex ? PDL::minv(mexp($i*$m) - mexp(- $i*$m)) * 2*$i : scalar PDL::minv(im(mexp($i*$m))); } =head2 macsc =for ref Return matrix inverse cosecant of a square matrix. =for usage PDL = macsc(PDL(A)) =for example my $a = random(10,10); my $acsc = macsc($a); =cut *macsc = \&PDL::macsc; sub PDL::macsc { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macsc: singular matrix"; return; } return masin($inv,$tol); } =head2 mcosh =for ref Return matrix hyperbolic cosine of a square matrix. =for usage PDL = mcosh(PDL(A)) =for example my $a = random(10,10); my $cos = mcosh($a); =cut *mcosh = \&PDL::mcosh; sub PDL::mcosh { &PDL::LinearAlgebra::_square; my $m = shift; ( $m->mexp + mexp(-$m) )/2; } =head2 macosh =for ref Return matrix hyperbolic inverse cosine of a square matrix. =for usage PDL = macosh(PDL(A)) =for example my $a = random(10,10); my $acos = macosh($a); =cut *macosh = \&PDL::macosh; sub PDL::macosh { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my @dims = $m->dims; my $di = $_[0]->dims_internal; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = msqrt($m x $m - $id); $m = $m->r2C if $ret->getndims > @dims; mlog($m + $ret, $tol); } =head2 msinh =for ref Return matrix hyperbolic sine of a square matrix. =for usage PDL = msinh(PDL(A)) =for example my $a = random(10,10); my $sinh = msinh($a); =cut *msinh = \&PDL::msinh; sub PDL::msinh { &PDL::LinearAlgebra::_square; my $m = shift; ( $m->mexp - mexp(-$m) )/2; } =head2 masinh =for ref Return matrix hyperbolic inverse sine of a square matrix. =for usage PDL = masinh(PDL(A)) =for example my $a = random(10,10); my $asinh = masinh($a); =cut *masinh = \&PDL::masinh; sub PDL::masinh { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my @dims = $m->dims; my $di = $_[0]->dims_internal; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; my $ret = msqrt($m x $m + $id); $m = $m->r2C if $ret->getndims > @dims; mlog(($m + $ret), $tol); } =head2 mtanh =for ref Return matrix hyperbolic tangent of a square matrix. =for usage PDL = mtanh(PDL(A)) =for example my $a = random(10,10); my $tanh = mtanh($a); =cut *mtanh = \&PDL::mtanh; sub PDL::mtanh { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; return scalar msolvex(mcosh($m), msinh($m),equilibrate=>1) unless $id; my $di = $_[0]->dims_internal; $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; $m = mexp(-2*$m); return scalar msolvex( ($id + $m ),($id - $m), equilibrate=>1); } =head2 matanh =for ref Return matrix hyperbolic inverse tangent of a square matrix. =for usage PDL = matanh(PDL(A)) =for example my $a = random(10,10); my $atanh = matanh($a); =cut *matanh = \&PDL::matanh; sub PDL::matanh { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my @dims = $m->dims; my $di = $_[0]->dims_internal; my $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; mlog( scalar msolvex( ($id - $m ),($id + $m),equilibrate=>1), $tol ) / 2; } =head2 mcoth =for ref Return matrix hyperbolic cotangent of a square matrix. =for usage PDL = mcoth(PDL(A)) =for example my $a = random(10,10); my $coth = mcoth($a); =cut *mcoth = \&PDL::mcoth; sub PDL::mcoth { &PDL::LinearAlgebra::_square; my ($m, $id) = @_; my @dims = $m->dims; scalar msolvex(msinh($m), mcosh($m),equilibrate=>1) unless $id; my $di = $_[0]->dims_internal; $id = identity($dims[$di]); $id = $id->r2C if $m->_is_complex; $m = mexp(-2*$m); return scalar msolvex( ($id - $m ),($id + $m),equilibrate=>1); } =head2 macoth =for ref Return matrix hyperbolic inverse cotangent of a square matrix. =for usage PDL = macoth(PDL(A)) =for example my $a = random(10,10); my $acoth = macoth($a); =cut *macoth = \&PDL::macoth; sub PDL::macoth { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macoth: singular matrix"; return; } return matanh($inv,$tol); } =head2 msech =for ref Return matrix hyperbolic secant of a square matrix. =for usage PDL = msech(PDL(A)) =for example my $a = random(10,10); my $sech = msech($a); =cut *msech = \&PDL::msech; sub PDL::msech { &PDL::LinearAlgebra::_square; my $m = shift; PDL::minv( $m->mexp + mexp(-$m) ) * 2; } =head2 masech =for ref Return matrix hyperbolic inverse secant of a square matrix. =for usage PDL = masech(PDL(A)) =for example my $a = random(10,10); my $asech = masech($a); =cut *masech = \&PDL::masech; sub PDL::masech { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "masech: singular matrix"; return; } return macosh($inv,$tol); } =head2 mcsch =for ref Return matrix hyperbolic cosecant of a square matrix. =for usage PDL = mcsch(PDL(A)) =for example my $a = random(10,10); my $csch = mcsch($a); =cut *mcsch = \&PDL::mcsch; sub PDL::mcsch { &PDL::LinearAlgebra::_square; my $m = shift; PDL::minv( $m->mexp - mexp(-$m) ) * 2; } =head2 macsch =for ref Return matrix hyperbolic inverse cosecant of a square matrix. =for usage PDL = macsch(PDL(A)) =for example my $a = random(10,10); my $acsch = macsch($a); =cut *macsch = \&PDL::macsch; sub PDL::macsch { &PDL::LinearAlgebra::_square; my ($m, $tol) = @_; my ($inv, $info) = $m->minv; if ($info){ warn "macsch: singular matrix"; return; } return masinh($inv,$tol); } =head2 mfun =for ref Return matrix function of second argument of a square matrix. Function will be applied on a complex ndarray. =for usage PDL = mfun(PDL(A),'cos') =for example my $a = random(10,10); my $fun = mfun($a,'cos'); sub sinbycos2{ $_[0]->set_inplace(0); $_[0] .= $_[0]->Csin/$_[0]->Ccos**2; } # Try diagonalization $fun = mfun($a, \&sinbycos2,1); # Now try Schur/Parlett $fun = mfun($a, \&sinbycos2); # Now with function. scalar msolve($a->mcos->mpow(2), $a->msin); =cut *mfun = \&PDL::mfun; sub PDL::mfun { &PDL::LinearAlgebra::_square; my ($m, $method, $diag, $tol) = @_; my @dims = $m->dims; if ($diag){ my ($e, $v) = $m->meigen(0,1); my ($inv, $info) = $v->minv; unless ($info){ $method = 'PDL::Complex::'.$method unless ref($method); eval {$v = ($v * $e->$method) x $v->minv;}; if ($@){ warn "mfun: Error $@\n"; return; } } else{ warn "mfun: Non invertible matrix in computation of $method\n"; return; } return $m->_is_complex ? $v : toreal($v, $tol); } else{ $m = $m->r2C unless $m->_is_complex; my ($t, undef, $z, undef, $info) = $m->mschur(1); if ($info){ warn "mfun: Can't compute Schur form\n"; return; } $method = 'PDL::Complex::'.$method unless ref($method); ($t, $info) = $t->ctrfun(0,$method); if($info){ warn "mfun: Can't compute $method\n"; return; } $m = $z x $t x $z->t(1); return $m->_is_complex ? $m : toreal($m, $tol); } } =head1 TODO Improve error return and check singularity. Improve (msqrt,mlog) / r2C =head1 AUTHOR Copyright (C) Grégory Vanuxem 2005-2018. This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. =cut EOD pp_done(); 1; PDL-LinearAlgebra-0.38/Trans/selectfunc.c0000644000175000017500000000246214224215654020076 0ustar osboxesosboxes#include "EXTERN.h" #include "perl.h" #include "pdl.h" #include "pdlcore.h" #define PDL PDL_LinearAlgebra_Trans extern Core *PDL; typedef PDL_Long integer; /* replace BLAS one so don't terminate on bad input */ int xerbla_(char *sub, int *info) { return 0; } void dfunc_wrapper(void *p, integer n, SV* dfunc) { dSP ; PDL_Indx odims[] = {0}; PDL_Indx pc_dims[] = {2,n}; PDL_Indx nat_dims[] = {n}; SV *pcv = perl_get_sv("PDL::Complex::VERSION", 0); char use_native = !pcv || !SvOK(pcv); PDL_Indx *dims = use_native ? nat_dims : pc_dims; PDL_Indx ndims = use_native ? 1 : 2; int type_add = use_native ? PDL_CF - PDL_F : 0; pdl *pdl = PDL->pdlnew(); PDL->setdims(pdl, dims, ndims); pdl->datatype = PDL_D + type_add; pdl->data = p; pdl->state |= PDL_DONTTOUCHDATA | PDL_ALLOCATED; HV *bless_stash = gv_stashpv(use_native ? "PDL" : "PDL::Complex", 0); ENTER ; SAVETMPS ; PUSHMARK(sp) ; SV *pdl1 = sv_newmortal(); PDL->SetSV_PDL(pdl1, pdl); pdl1 = sv_bless(pdl1, bless_stash); XPUSHs(pdl1); PUTBACK ; int count = perl_call_sv(dfunc, G_SCALAR); SPAGAIN; PDL->setdims(pdl, odims, 1); pdl->state &= ~(PDL_ALLOCATED |PDL_DONTTOUCHDATA); pdl->data=NULL; if (count !=1) croak("Error calling perl function\n"); PUTBACK ; FREETMPS ; LEAVE ; } PDL-LinearAlgebra-0.38/Trans/Makefile.PL0000644000175000017500000000067314224144746017556 0ustar osboxesosboxesuse ExtUtils::MakeMaker; use PDL::Core::Dev; our (%ldloadlibs, $libs0, $inc); my $pkg = 'Trans'; my $file = lc($pkg).".pd"; my @pack = ([$file, $pkg, "PDL::LinearAlgebra::$pkg",undef,1]); my %hash = pdlpp_stdargs(@pack); $hash{LIBS}[0] .= $libs0; $hash{OBJECT} .= ' selectfunc$(OBJ_EXT)'; $hash{INC} .= " $inc"; WriteMakefile( %hash, %ldloadlibs, VERSION_FROM => $file, NO_MYMETA => 1, ); sub MY::postamble { pdlpp_postamble(@pack); } PDL-LinearAlgebra-0.38/Config0000644000175000017500000000006313573314157015637 0ustar osboxesosboxes%config = ( CBLAS => 0, WITHOUT_THREAD => 0 ); PDL-LinearAlgebra-0.38/README0000644000175000017500000000167214560467045015400 0ustar osboxesosboxesPDL/LinearAlgebra version 0.08_01 ================================= This module provides a PDL interface to some routines of BLAS and LAPACK library. Moreover it provides some linear algebra based routines (transcendental functions for matrices) and some easy constructors for well known matrices. BLAS and LAPACK libraries can be retrieved for example at www.netlib.org. INSTALLATION To install this module edit Real/Makefile.PL, Complex/Makefile.PL and Trans/Makefile.PL to reflect your local BLAS and LAPACK installation and type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires PDL and working BLAS and LAPACK libraries. COPYRIGHT AND LICENCE Copyright (C) 2005-2007 Grégory Vanuxem Copyright (C) 2013 Chris Marshall This library is free software; you can redistribute it and/or modify it under the terms of the Perl Artistic License as in the file Artistic_2 in this distribution. PDL-LinearAlgebra-0.38/MANIFEST0000644000175000017500000000153314565105656015647 0ustar osboxesosboxesArtistic_2 Changes Complex/complex.pd Complex/Makefile.PL Complex/selectfunc.c Config lib/PDL/LinearAlgebra.pm lib/PDL/LinearAlgebra/Special.pm Makefile.PL MANIFEST This list of files pp_defc.pl README Real/Makefile.PL Real/real.pd Real/selectfunc.c t/1.t t/cgtsv.t t/common.pl t/gtsv.t t/legacy.t Trans/Makefile.PL Trans/selectfunc.c Trans/trans.pd META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) GENERATED/PDL/LinearAlgebra/Complex.pm mod=PDL::LinearAlgebra::Complex pd=Complex/complex.pd (added by pdlpp_mkgen) GENERATED/PDL/LinearAlgebra/Real.pm mod=PDL::LinearAlgebra::Real pd=Real/real.pd (added by pdlpp_mkgen) GENERATED/PDL/LinearAlgebra/Trans.pm mod=PDL::LinearAlgebra::Trans pd=Trans/trans.pd (added by pdlpp_mkgen) PDL-LinearAlgebra-0.38/Makefile.PL0000644000175000017500000000724514560466760016477 0ustar osboxesosboxesuse ExtUtils::MakeMaker; use Config; use Devel::CheckLib qw(check_lib check_lib_or_exit); use ExtUtils::F77; use PDL::Core::Dev; our %ldloadlibs = ($^O =~ /MSWin/ && $Config{cc} eq 'cl') ? (LDLOADLIBS => 'oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib wsock32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib msvcrt.lib ../lapack/libacml.lib "C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\lib\msvcrt.lib" ') : (); my @pkgs = qw(lapack blas); our $libs0 = ( eval {require PkgConfig; join ' ', map PkgConfig->find($_)->get_ldflags, @pkgs} || eval {require ExtUtils::PkgConfig; join ' ', map ExtUtils::PkgConfig->libs($_), @pkgs} || find_libs() || `pkg-config @pkgs --libs` || '-L/usr/lib/atlas -llapack -lblas -latlas' ) . ' ' . ExtUtils::F77->runtime; our $inc = '-DF77_USCORE='. (ExtUtils::F77->trail_ ? '_' : ''); { # work around Devel::CheckLib not doing Text::ParseWords::shellwords use Text::ParseWords qw(shellwords); my @libpath = grep -d, map {my $r=$_;$r=~s/^-L//?$r:()} my @sw = shellwords $libs0; my @lib = grep check_lib(lib=>$_), map {my $r=$_;$r=~s/^-l//?$r:()} @sw; $libs0 = join ' ', (map qq{-L"$_"}, @libpath), (map "-l$_", @lib); my $f77_uscore = (ExtUtils::F77->trail_ ? '_' : ''); check_lib_or_exit( ldflags => $libs0, header => [($^O =~ /MSWin/ ? 'float.h' : ()), qw(stdio.h math.h)], function => < 2) printf("%ld", i); /* try to stop optimiser eliminating */ EOF ); } WriteMakefile( NAME => 'PDL::LinearAlgebra', ABSTRACT => 'PDL bindings to some BLAS and LAPACK library routines', AUTHOR => [ 'Grégory Vanuxem ' ], VERSION_FROM => 'lib/PDL/LinearAlgebra.pm', LICENSE => 'artistic_2', META_MERGE => { "meta-spec" => { version => 2 }, resources => { homepage => 'http://pdl.perl.org/', repository => { url => 'git://github.com/PDLPorters/pdl-linearalgebra.git', type => 'git', web => 'https://github.com/PDLPorters/pdl-linearalgebra', }, bugtracker => {web=>'https://github.com/PDLPorters/pdl-linearalgebra/issues'}, }, x_IRC => 'irc://irc.perl.org/#pdl', }, CONFIGURE_REQUIRES => { "PDL" => '2.078', "Devel::CheckLib" => 0, "ExtUtils::F77" => '1.26', }, PREREQ_PM => { "PDL" => '2.078', # PDL::Complex method aliases }, TEST_REQUIRES => { "Test::More" => '0.88', # done_testing }, dist => { PREOP=>'$(PERL) -MPDL::Core::Dev -e pdlpp_mkgen $(DISTVNAME)' }, # GENERATED subdir in dist tarball clean => { FILES => '*~' }, ); sub find_libs { return if $^O !~ /linux/i; # in performance order based on libraries I've used # for xnec2c in Ubuntu, Debian, SuSE, CentOS, etc. # See comments here for detail: # https://github.com/KJ7LNW/xnec2c/blob/master/src/mathlib.c#L29 my @libs = qw/ openblaso openblas_openmp openblasp openblas_pthreads openblas openblas_serial mkl_rt/; for my $l (@libs) { return "-l$l" if (check_lib(lib => $l)); } return; } sub MY::postamble { my $oneliner = PDL::Core::Dev::_oneliner(qq{exit if \$ENV{DESTDIR}; use PDL::Doc; eval { PDL::Doc::add_module(shift); }}); qq|\ninstall :: pure_install\n\t$oneliner \$(NAME)\n|; }