# This file is a part of Julia. License is MIT: https://julialang.org/license ## The LAPACK module of interfaces to LAPACK subroutines module LAPACK const liblapack = Base.liblapack_name import ..LinAlg.BLAS.@blasfunc import ..LinAlg: BlasFloat, Char, BlasInt, LAPACKException, DimensionMismatch, SingularException, PosDefException, chkstride1, checksquare using Base: iszero #Generic LAPACK error handlers """ Handle only negative LAPACK error codes *NOTE* use only if the positive error code is useful. """ function chkargsok(ret::BlasInt) if ret < 0 throw(ArgumentError("invalid argument #$(-ret) to LAPACK call")) end end "Handle all nonzero info codes" function chklapackerror(ret::BlasInt) if ret == 0 return elseif ret < 0 throw(ArgumentError("invalid argument #$(-ret) to LAPACK call")) else # ret > 0 throw(LAPACKException(ret)) end end function chknonsingular(ret::BlasInt) if ret > 0 throw(SingularException(ret)) end end function chkposdef(ret::BlasInt) if ret > 0 throw(PosDefException(ret)) end end "Check that upper/lower (for special matrices) is correctly specified" function chkuplo(uplo::Char) if !(uplo == 'U' || uplo == 'L') throw(ArgumentError("uplo argument must be 'U' (upper) or 'L' (lower), got $uplo")) end uplo end "Check that {c}transpose is correctly specified" function chktrans(trans::Char) if !(trans == 'N' || trans == 'C' || trans == 'T') throw(ArgumentError("trans argument must be 'N' (no transpose), 'T' (transpose), or 'C' (conjugate transpose), got $trans")) end trans end "Check that left/right hand side multiply is correctly specified" function chkside(side::Char) if !(side == 'L' || side == 'R') throw(ArgumentError("side argument must be 'L' (left hand multiply) or 'R' (right hand multiply), got $side")) end side end "Check that unit diagonal flag is correctly specified" function chkdiag(diag::Char) if !(diag == 'U' || diag =='N') throw(ArgumentError("diag argument must be 'U' (unit diagonal) or 'N' (non-unit diagonal), got $diag")) end diag end subsetrows(X::AbstractVector, Y::AbstractArray, k) = Y[1:k] subsetrows(X::AbstractMatrix, Y::AbstractArray, k) = Y[1:k, :] function chkfinite(A::StridedMatrix) for a in A if !isfinite(a) throw(ArgumentError("matrix contains Infs or NaNs")) end end return true end # LAPACK version number function laver() major = Ref{BlasInt}(0) minor = Ref{BlasInt}(0) patch = Ref{BlasInt}(0) ccall((@blasfunc(ilaver_), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), major, minor, patch) return major[], minor[], patch[] end # (GB) general banded matrices, LU decomposition and solver for (gbtrf, gbtrs, elty) in ((:dgbtrf_,:dgbtrs_,:Float64), (:sgbtrf_,:sgbtrs_,:Float32), (:zgbtrf_,:zgbtrs_,:Complex128), (:cgbtrf_,:cgbtrs_,:Complex64)) @eval begin # SUBROUTINE DGBTRF( M, N, KL, KU, AB, LDAB, IPIV, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, KL, KU, LDAB, M, N # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION AB( LDAB, * ) function gbtrf!(kl::Integer, ku::Integer, m::Integer, AB::StridedMatrix{$elty}) chkstride1(AB) n = size(AB, 2) mnmn = min(m, n) ipiv = similar(AB, BlasInt, mnmn) info = Ref{BlasInt}() ccall((@blasfunc($gbtrf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &kl, &ku, AB, &max(1,stride(AB,2)), ipiv, info) chklapackerror(info[]) AB, ipiv end # SUBROUTINE DGBTRS( TRANS, N, KL, KU, NRHS, AB, LDAB, IPIV, B, LDB, INFO) # * .. Scalar Arguments .. # CHARACTER TRANS # INTEGER INFO, KL, KU, LDAB, LDB, N, NRHS # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION AB( LDAB, * ), B( LDB, * ) function gbtrs!(trans::Char, kl::Integer, ku::Integer, m::Integer, AB::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(AB, B, ipiv) chktrans(trans) info = Ref{BlasInt}() n = size(AB,2) if m != n || m != size(B,1) throw(DimensionMismatch("matrix AB has dimensions $(size(AB)), but right hand side matrix B has dimensions $(size(B))")) end ccall((@blasfunc($gbtrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &trans, &n, &kl, &ku, &size(B,2), AB, &max(1,stride(AB,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end """ gbtrf!(kl, ku, m, AB) -> (AB, ipiv) Compute the LU factorization of a banded matrix `AB`. `kl` is the first subdiagonal containing a nonzero band, `ku` is the last superdiagonal containing one, and `m` is the first dimension of the matrix `AB`. Returns the LU factorization in-place and `ipiv`, the vector of pivots used. """ gbtrf!(kl::Integer, ku::Integer, m::Integer, AB::StridedMatrix) """ gbtrs!(trans, kl, ku, m, AB, ipiv, B) Solve the equation `AB * X = B`. `trans` determines the orientation of `AB`. It may be `N` (no transpose), `T` (transpose), or `C` (conjugate transpose). `kl` is the first subdiagonal containing a nonzero band, `ku` is the last superdiagonal containing one, and `m` is the first dimension of the matrix `AB`. `ipiv` is the vector of pivots returned from `gbtrf!`. Returns the vector or matrix `X`, overwriting `B` in-place. """ gbtrs!(trans::Char, kl::Integer, ku::Integer, m::Integer, AB::StridedMatrix, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat) ## (GE) general matrices: balancing and back-transforming for (gebal, gebak, elty, relty) in ((:dgebal_, :dgebak_, :Float64, :Float64), (:sgebal_, :sgebak_, :Float32, :Float32), (:zgebal_, :zgebak_, :Complex128, :Float64), (:cgebal_, :cgebak_, :Complex64, :Float32)) @eval begin # SUBROUTINE DGEBAL( JOB, N, A, LDA, ILO, IHI, SCALE, INFO ) #* .. Scalar Arguments .. # CHARACTER JOB # INTEGER IHI, ILP, INFO, LDA, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), SCALE( * ) function gebal!(job::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs ihi = Ref{BlasInt}() ilo = Ref{BlasInt}() scale = similar(A, $relty, n) info = Ref{BlasInt}() ccall((@blasfunc($gebal), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &job, &n, A, &max(1,stride(A,2)), ilo, ihi, scale, info) chklapackerror(info[]) ilo[], ihi[], scale end # SUBROUTINE DGEBAK( JOB, SIDE, N, ILO, IHI, SCALE, M, V, LDV, INFO ) #* .. Scalar Arguments .. # CHARACTER JOB, SIDE # INTEGER IHI, ILP, INFO, LDV, M, N # .. Array Arguments .. # DOUBLE PRECISION SCALE( * ), V( LDV, * ) function gebak!(job::Char, side::Char, ilo::BlasInt, ihi::BlasInt, scale::StridedVector{$relty}, V::StridedMatrix{$elty}) chkstride1(scale, V) chkside(side) chkfinite(V) # balancing routines don't support NaNs and Infs n = checksquare(V) info = Ref{BlasInt}() ccall((@blasfunc($gebak), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &job, &side, &size(V,1), &ilo, &ihi, scale, &n, V, &max(1,stride(V,2)), info) chklapackerror(info[]) V end end end """ gebal!(job, A) -> (ilo, ihi, scale) Balance the matrix `A` before computing its eigensystem or Schur factorization. `job` can be one of `N` (`A` will not be permuted or scaled), `P` (`A` will only be permuted), `S` (`A` will only be scaled), or `B` (`A` will be both permuted and scaled). Modifies `A` in-place and returns `ilo`, `ihi`, and `scale`. If permuting was turned on, `A[i,j] = 0` if `j > i` and `1 < j < ilo` or `j > ihi`. `scale` contains information about the scaling/permutations performed. """ gebal!(job::Char, A::StridedMatrix) """ gebak!(job, side, ilo, ihi, scale, V) Transform the eigenvectors `V` of a matrix balanced using `gebal!` to the unscaled/unpermuted eigenvectors of the original matrix. Modifies `V` in-place. `side` can be `L` (left eigenvectors are transformed) or `R` (right eigenvectors are transformed). """ gebak!(job::Char, side::Char, ilo::BlasInt, ihi::BlasInt, scale::StridedVector, V::StridedMatrix) # (GE) general matrices, direct decompositions # # These mutating functions take as arguments all the values they # return, even if the value of the function does not depend on them # (e.g. the tau argument). This is so that a factorization can be # updated in place. The condensed mutating functions, usually a # function of A only, are defined after this block. for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty) in ((:dgebrd_,:dgelqf_,:dgeqlf_,:dgeqrf_,:dgeqp3_,:dgeqrt_,:dgeqrt3_,:dgerqf_,:dgetrf_,:Float64,:Float64), (:sgebrd_,:sgelqf_,:sgeqlf_,:sgeqrf_,:sgeqp3_,:sgeqrt_,:sgeqrt3_,:sgerqf_,:sgetrf_,:Float32,:Float32), (:zgebrd_,:zgelqf_,:zgeqlf_,:zgeqrf_,:zgeqp3_,:zgeqrt_,:zgeqrt3_,:zgerqf_,:zgetrf_,:Complex128,:Float64), (:cgebrd_,:cgelqf_,:cgeqlf_,:cgeqrf_,:cgeqp3_,:cgeqrt_,:cgeqrt3_,:cgerqf_,:cgetrf_,:Complex64,:Float32)) @eval begin # SUBROUTINE DGEBRD( M, N, A, LDA, D, E, TAUQ, TAUP, WORK, LWORK, # INFO ) # .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAUP( * ), # TAUQ( * ), WORK( * ) function gebrd!(A::StridedMatrix{$elty}) chkstride1(A) m, n = size(A) k = min(m, n) d = similar(A, $relty, k) e = similar(A, $relty, k) tauq = similar(A, $elty, k) taup = similar(A, $elty, k) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gebrd), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &max(1,stride(A,2)), d, e, tauq, taup, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, d, e, tauq, taup end # SUBROUTINE DGELQF( M, N, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function gelqf!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}) chkstride1(A,tau) m = BlasInt(size(A, 1)) n = BlasInt(size(A, 2)) lda = BlasInt(max(1,stride(A, 2))) if length(tau) != min(m,n) throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) end lwork = BlasInt(-1) work = Vector{$elty}(1) info = Ref{BlasInt}() for i = 1:2 # first call returns lwork as work[1] ccall((@blasfunc($gelqf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &lda, tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, tau end # SUBROUTINE DGEQLF( M, N, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function geqlf!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}) chkstride1(A,tau) m = BlasInt(size(A, 1)) n = BlasInt(size(A, 2)) lda = BlasInt(max(1,stride(A, 2))) if length(tau) != min(m,n) throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) end lwork = BlasInt(-1) work = Vector{$elty}(1) info = Ref{BlasInt}() for i = 1:2 # first call returns lwork as work[1] ccall((@blasfunc($geqlf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &lda, tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, tau end # SUBROUTINE DGEQP3( M, N, A, LDA, JPVT, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # * .. Array Arguments .. # INTEGER JPVT( * ) # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function geqp3!(A::StridedMatrix{$elty}, jpvt::StridedVector{BlasInt}, tau::StridedVector{$elty}) chkstride1(A,jpvt,tau) m,n = size(A) if length(tau) != min(m,n) throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) end if length(jpvt) != n throw(DimensionMismatch("jpvt has length $(length(jpvt)), but needs length $n")) end lda = stride(A,2) if lda == 0 return A, tau, jpvt end # Early exit work = Vector{$elty}(1) lwork = BlasInt(-1) cmplx = eltype(A)<:Complex if cmplx rwork = Vector{$relty}(2n) end info = Ref{BlasInt}() for i = 1:2 if cmplx ccall((@blasfunc($geqp3), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &m, &n, A, &lda, jpvt, tau, work, &lwork, rwork, info) else ccall((@blasfunc($geqp3), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &lda, jpvt, tau, work, &lwork, info) end chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end return A, tau, jpvt end function geqrt!(A::StridedMatrix{$elty}, T::StridedMatrix{$elty}) chkstride1(A) m, n = size(A) minmn = min(m, n) nb = size(T, 1) if nb > minmn throw(ArgumentError("block size $nb > $minmn too large")) end lda = max(1, stride(A,2)) work = Vector{$elty}(nb*n) if n > 0 info = Ref{BlasInt}() ccall((@blasfunc($geqrt), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &m, &n, &nb, A, &lda, T, &max(1,stride(T,2)), work, info) chklapackerror(info[]) end A, T end function geqrt3!(A::StridedMatrix{$elty}, T::StridedMatrix{$elty}) chkstride1(A) chkstride1(T) m, n = size(A) p, q = size(T) if m < n throw(DimensionMismatch("input matrix A has dimensions ($m,$n), but should have more rows than columns")) end if p != n || q != n throw(DimensionMismatch("block reflector T has dimensions ($p,$q), but should have dimensions ($n,$n)")) end if n > 0 info = Ref{BlasInt}() ccall((@blasfunc($geqrt3), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &max(1, stride(A, 2)), T, &max(1,stride(T,2)), info) chklapackerror(info[]) end A, T end ## geqrfp! - positive elements on diagonal of R - not defined yet # SUBROUTINE DGEQRFP( M, N, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function geqrf!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}) chkstride1(A,tau) m, n = size(A) if length(tau) != min(m,n) throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 # first call returns lwork as work[1] ccall((@blasfunc($geqrf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &max(1,stride(A,2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, tau end # SUBROUTINE DGERQF( M, N, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function gerqf!(A::StridedMatrix{$elty},tau::StridedVector{$elty}) chkstride1(A,tau) m, n = size(A) if length(tau) != min(m,n) throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) end lwork = BlasInt(-1) work = Vector{$elty}(1) info = Ref{BlasInt}() for i = 1:2 # first call returns lwork as work[1] ccall((@blasfunc($gerqf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &max(1,stride(A,2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, tau end # SUBROUTINE DGETRF( M, N, A, LDA, IPIV, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, M, N # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ) function getrf!(A::StridedMatrix{$elty}) chkstride1(A) m, n = size(A) lda = max(1,stride(A, 2)) ipiv = similar(A, BlasInt, min(m,n)) info = Ref{BlasInt}() ccall((@blasfunc($getrf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &lda, ipiv, info) chkargsok(info[]) A, ipiv, info[] #Error code is stored in LU factorization type end end end """ gebrd!(A) -> (A, d, e, tauq, taup) Reduce `A` in-place to bidiagonal form `A = QBP'`. Returns `A`, containing the bidiagonal matrix `B`; `d`, containing the diagonal elements of `B`; `e`, containing the off-diagonal elements of `B`; `tauq`, containing the elementary reflectors representing `Q`; and `taup`, containing the elementary reflectors representing `P`. """ gebrd!(A::StridedMatrix) """ gelqf!(A, tau) Compute the `LQ` factorization of `A`, `A = LQ`. `tau` contains scalars which parameterize the elementary reflectors of the factorization. `tau` must have length greater than or equal to the smallest dimension of `A`. Returns `A` and `tau` modified in-place. """ gelqf!(A::StridedMatrix, tau::StridedVector) """ geqlf!(A, tau) Compute the `QL` factorization of `A`, `A = QL`. `tau` contains scalars which parameterize the elementary reflectors of the factorization. `tau` must have length greater than or equal to the smallest dimension of `A`. Returns `A` and `tau` modified in-place. """ geqlf!(A::StridedMatrix, tau::StridedVector) """ geqp3!(A, jpvt, tau) Compute the pivoted `QR` factorization of `A`, `AP = QR` using BLAS level 3. `P` is a pivoting matrix, represented by `jpvt`. `tau` stores the elementary reflectors. `jpvt` must have length length greater than or equal to `n` if `A` is an `(m x n)` matrix. `tau` must have length greater than or equal to the smallest dimension of `A`. `A`, `jpvt`, and `tau` are modified in-place. """ geqp3!(A::StridedMatrix, jpvt::StridedVector{BlasInt}, tau::StridedVector) """ geqrt!(A, T) Compute the blocked `QR` factorization of `A`, `A = QR`. `T` contains upper triangular block reflectors which parameterize the elementary reflectors of the factorization. The first dimension of `T` sets the block size and it must be between 1 and `n`. The second dimension of `T` must equal the smallest dimension of `A`. Returns `A` and `T` modified in-place. """ geqrt!(A::StridedMatrix, T::StridedMatrix) """ geqrt3!(A, T) Recursively computes the blocked `QR` factorization of `A`, `A = QR`. `T` contains upper triangular block reflectors which parameterize the elementary reflectors of the factorization. The first dimension of `T` sets the block size and it must be between 1 and `n`. The second dimension of `T` must equal the smallest dimension of `A`. Returns `A` and `T` modified in-place. """ geqrt3!(A::StridedMatrix, T::StridedMatrix) """ geqrf!(A, tau) Compute the `QR` factorization of `A`, `A = QR`. `tau` contains scalars which parameterize the elementary reflectors of the factorization. `tau` must have length greater than or equal to the smallest dimension of `A`. Returns `A` and `tau` modified in-place. """ geqrf!(A::StridedMatrix, tau::StridedVector) """ gerqf!(A, tau) Compute the `RQ` factorization of `A`, `A = RQ`. `tau` contains scalars which parameterize the elementary reflectors of the factorization. `tau` must have length greater than or equal to the smallest dimension of `A`. Returns `A` and `tau` modified in-place. """ gerqf!(A::StridedMatrix, tau::StridedVector) """ getrf!(A) -> (A, ipiv, info) Compute the pivoted `LU` factorization of `A`, `A = LU`. Returns `A`, modified in-place, `ipiv`, the pivoting information, and an `info` code which indicates success (`info = 0`), a singular value in `U` (`info = i`, in which case `U[i,i]` is singular), or an error code (`info < 0`). """ getrf!(A::StridedMatrix, tau::StridedVector) """ gelqf!(A) -> (A, tau) Compute the `LQ` factorization of `A`, `A = LQ`. Returns `A`, modified in-place, and `tau`, which contains scalars which parameterize the elementary reflectors of the factorization. """ gelqf!(A::StridedMatrix{<:BlasFloat}) = ((m,n) = size(A); gelqf!(A, similar(A, min(m, n)))) """ geqlf!(A) -> (A, tau) Compute the `QL` factorization of `A`, `A = QL`. Returns `A`, modified in-place, and `tau`, which contains scalars which parameterize the elementary reflectors of the factorization. """ geqlf!(A::StridedMatrix{<:BlasFloat}) = ((m,n) = size(A); geqlf!(A, similar(A, min(m, n)))) """ geqrt!(A, nb) -> (A, T) Compute the blocked `QR` factorization of `A`, `A = QR`. `nb` sets the block size and it must be between 1 and `n`, the second dimension of `A`. Returns `A`, modified in-place, and `T`, which contains upper triangular block reflectors which parameterize the elementary reflectors of the factorization. """ geqrt!(A::StridedMatrix{<:BlasFloat}, nb::Integer) = geqrt!(A, similar(A, nb, minimum(size(A)))) """ geqrt3!(A) -> (A, T) Recursively computes the blocked `QR` factorization of `A`, `A = QR`. Returns `A`, modified in-place, and `T`, which contains upper triangular block reflectors which parameterize the elementary reflectors of the factorization. """ geqrt3!(A::StridedMatrix{<:BlasFloat}) = (n = size(A, 2); geqrt3!(A, similar(A, n, n))) """ geqrf!(A) -> (A, tau) Compute the `QR` factorization of `A`, `A = QR`. Returns `A`, modified in-place, and `tau`, which contains scalars which parameterize the elementary reflectors of the factorization. """ geqrf!(A::StridedMatrix{<:BlasFloat}) = ((m,n) = size(A); geqrf!(A, similar(A, min(m, n)))) """ gerqf!(A) -> (A, tau) Compute the `RQ` factorization of `A`, `A = RQ`. Returns `A`, modified in-place, and `tau`, which contains scalars which parameterize the elementary reflectors of the factorization. """ gerqf!(A::StridedMatrix{<:BlasFloat}) = ((m,n) = size(A); gerqf!(A, similar(A, min(m, n)))) """ geqp3!(A, jpvt) -> (A, jpvt, tau) Compute the pivoted `QR` factorization of `A`, `AP = QR` using BLAS level 3. `P` is a pivoting matrix, represented by `jpvt`. `jpvt` must have length greater than or equal to `n` if `A` is an `(m x n)` matrix. Returns `A` and `jpvt`, modified in-place, and `tau`, which stores the elementary reflectors. """ function geqp3!(A::StridedMatrix{<:BlasFloat}, jpvt::StridedVector{BlasInt}) m, n = size(A) geqp3!(A, jpvt, similar(A, min(m, n))) end """ geqp3!(A) -> (A, jpvt, tau) Compute the pivoted `QR` factorization of `A`, `AP = QR` using BLAS level 3. Returns `A`, modified in-place, `jpvt`, which represents the pivoting matrix `P`, and `tau`, which stores the elementary reflectors. """ function geqp3!(A::StridedMatrix{<:BlasFloat}) m, n = size(A) geqp3!(A, zeros(BlasInt, n), similar(A, min(m, n))) end ## Complete orthogonaliztion tools for (tzrzf, ormrz, elty) in ((:dtzrzf_,:dormrz_,:Float64), (:stzrzf_,:sormrz_,:Float32), (:ztzrzf_,:zunmrz_,:Complex128), (:ctzrzf_,:cunmrz_,:Complex64)) @eval begin # SUBROUTINE ZTZRZF( M, N, A, LDA, TAU, WORK, LWORK, INFO ) # # .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, M, N # .. # .. Array Arguments .. # COMPLEX*16 A( LDA, * ), TAU( * ), WORK( * ) function tzrzf!(A::StridedMatrix{$elty}) m, n = size(A) if n < m throw(DimensionMismatch("input matrix A has dimensions ($m,$n), but cannot have fewer columns than rows")) end lda = max(1, m) tau = similar(A, $elty, m) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($tzrzf), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, A, &lda, tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, tau end # SUBROUTINE ZUNMRZ( SIDE, TRANS, M, N, K, L, A, LDA, TAU, C, LDC, # WORK, LWORK, INFO ) # # .. Scalar Arguments .. # CHARACTER SIDE, TRANS # INTEGER INFO, K, L, LDA, LDC, LWORK, M, N # .. # .. Array Arguments .. # COMPLEX*16 A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) function ormrz!(side::Char, trans::Char, A::StridedMatrix{$elty}, tau::StridedVector{$elty}, C::StridedMatrix{$elty}) chktrans(trans) chkside(side) chkstride1(tau) m, n = size(C) k = length(tau) l = size(A, 2) - size(A, 1) lda = max(1, stride(A,2)) ldc = max(1, stride(C,2)) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ormrz), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, &l, A, &lda, tau, C, &ldc, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end C end end end """ ormrz!(side, trans, A, tau, C) Multiplies the matrix `C` by `Q` from the transformation supplied by `tzrzf!`. Depending on `side` or `trans` the multiplication can be left-sided (`side = L, Q*C`) or right-sided (`side = R, C*Q`) and `Q` can be unmodified (`trans = N`), transposed (`trans = T`), or conjugate transposed (`trans = C`). Returns matrix `C` which is modified in-place with the result of the multiplication. """ ormrz!(side::Char, trans::Char, A::StridedMatrix, tau::StridedVector, C::StridedMatrix) """ tzrzf!(A) -> (A, tau) Transforms the upper trapezoidal matrix `A` to upper triangular form in-place. Returns `A` and `tau`, the scalar parameters for the elementary reflectors of the transformation. """ tzrzf!(A::StridedMatrix) ## (GE) general matrices, solvers with factorization, solver and inverse for (gels, gesv, getrs, getri, elty) in ((:dgels_,:dgesv_,:dgetrs_,:dgetri_,:Float64), (:sgels_,:sgesv_,:sgetrs_,:sgetri_,:Float32), (:zgels_,:zgesv_,:zgetrs_,:zgetri_,:Complex128), (:cgels_,:cgesv_,:cgetrs_,:cgetri_,:Complex64)) @eval begin # SUBROUTINE DGELS( TRANS, M, N, NRHS, A, LDA, B, LDB, WORK, LWORK,INFO) # * .. Scalar Arguments .. # CHARACTER TRANS # INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS function gels!(trans::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chktrans(trans) chkstride1(A, B) btrn = trans == 'T' m, n = size(A) if size(B,1) != (btrn ? n : m) throw(DimensionMismatch("matrix A has dimensions ($m,$n), transposed: $btrn, but leading dimension of B is $(size(B,1))")) end info = Ref{BlasInt}() work = Vector{$elty}(1) lwork = BlasInt(-1) for i = 1:2 ccall((@blasfunc($gels), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &(btrn?'T':'N'), &m, &n, &size(B,2), A, &max(1,stride(A,2)), B, &max(1,stride(B,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end k = min(m, n) F = m < n ? tril(A[1:k, 1:k]) : triu(A[1:k, 1:k]) ssr = Vector{$elty}(size(B, 2)) for i = 1:size(B,2) x = zero($elty) for j = k+1:size(B,1) x += abs2(B[j,i]) end ssr[i] = x end F, subsetrows(B, B, k), ssr end # SUBROUTINE DGESV( N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LDB, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function gesv!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A, B) n = checksquare(A) if size(B,1) != n throw(DimensionMismatch("B has leading dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) info = Ref{BlasInt}() ccall((@blasfunc($gesv), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B, A, ipiv end # SUBROUTINE DGETRS( TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) #* .. Scalar Arguments .. # CHARACTER TRANS # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function getrs!(trans::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chktrans(trans) chkstride1(A, B, ipiv) n = checksquare(A) if n != size(B, 1) throw(DimensionMismatch("B has leading dimension $(size(B,1)), but needs $n")) end nrhs = size(B, 2) info = Ref{BlasInt}() ccall((@blasfunc($getrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &trans, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end # SUBROUTINE DGETRI( N, A, LDA, IPIV, WORK, LWORK, INFO ) #* .. Scalar Arguments .. # INTEGER INFO, LDA, LWORK, N #* .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function getri!(A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) if n != length(ipiv) throw(DimensionMismatch("ipiv has length $(length(ipiv)), but needs $n")) end lda = max(1,stride(A, 2)) lwork = BlasInt(-1) work = Vector{$elty}(1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($getri), liblapack), Void, (Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, A, &lda, ipiv, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A end end end """ gels!(trans, A, B) -> (F, B, ssr) Solves the linear equation `A * X = B`, `A.' * X =B`, or `A' * X = B` using a QR or LQ factorization. Modifies the matrix/vector `B` in place with the solution. `A` is overwritten with its `QR` or `LQ` factorization. `trans` may be one of `N` (no modification), `T` (transpose), or `C` (conjugate transpose). `gels!` searches for the minimum norm/least squares solution. `A` may be under or over determined. The solution is returned in `B`. """ gels!(trans::Char, A::StridedMatrix, B::StridedVecOrMat) """ gesv!(A, B) -> (B, A, ipiv) Solves the linear equation `A * X = B` where `A` is a square matrix using the `LU` factorization of `A`. `A` is overwritten with its `LU` factorization and `B` is overwritten with the solution `X`. `ipiv` contains the pivoting information for the `LU` factorization of `A`. """ gesv!(A::StridedMatrix, B::StridedVecOrMat) """ getrs!(trans, A, ipiv, B) Solves the linear equation `A * X = B`, `A.' * X =B`, or `A' * X = B` for square `A`. Modifies the matrix/vector `B` in place with the solution. `A` is the `LU` factorization from `getrf!`, with `ipiv` the pivoting information. `trans` may be one of `N` (no modification), `T` (transpose), or `C` (conjugate transpose). """ getrs!(trans::Char, A::StridedMatrix, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat) """ getri!(A, ipiv) Computes the inverse of `A`, using its `LU` factorization found by `getrf!`. `ipiv` is the pivot information output and `A` contains the `LU` factorization of `getrf!`. `A` is overwritten with its inverse. """ getri!(A::StridedMatrix, ipiv::StridedVector{BlasInt}) for (gesvx, elty) in ((:dgesvx_,:Float64), (:sgesvx_,:Float32)) @eval begin # SUBROUTINE DGESVX( FACT, TRANS, N, NRHS, A, LDA, AF, LDAF, IPIV, # EQUED, R, C, B, LDB, X, LDX, RCOND, FERR, BERR, # WORK, IWORK, INFO ) # # .. Scalar Arguments .. # CHARACTER EQUED, FACT, TRANS # INTEGER INFO, LDA, LDAF, LDB, LDX, N, NRHS # DOUBLE PRECISION RCOND # .. # .. Array Arguments .. # INTEGER IPIV( * ), IWORK( * ) # DOUBLE PRECISION A( LDA, * ), AF( LDAF, * ), B( LDB, * ), # $ BERR( * ), C( * ), FERR( * ), R( * ), # $ WORK( * ), X( LDX, * # function gesvx!(fact::Char, trans::Char, A::StridedMatrix{$elty}, AF::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, equed::Char, R::StridedVector{$elty}, C::StridedVector{$elty}, B::StridedVecOrMat{$elty}) chktrans(trans) chkstride1(ipiv, R, C) n = checksquare(A) lda = stride(A,2) n = checksquare(AF) ldaf = stride(AF,2) nrhs = size(B,2) ldb = stride(B,2) rcond = Vector{$elty}(1) ferr = similar(A, $elty, nrhs) berr = similar(A, $elty, nrhs) work = Vector{$elty}(4n) iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() X = similar(A, $elty, n, nrhs) ccall((@blasfunc($gesvx), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{UInt8}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &fact, &trans, &n, &nrhs, A, &lda, AF, &ldaf, ipiv, &equed, R, C, B, &ldb, X, &n, rcond, ferr, berr, work, iwork, info) chklapackerror(info[]) if info[] == n + 1 warn("matrix is singular to working precision") else chknonsingular(info[]) end #WORK(1) contains the reciprocal pivot growth factor norm(A)/norm(U) X, equed, R, C, B, rcond[1], ferr, berr, work[1] end function gesvx!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) n = size(A,1) X, equed, R, C, B, rcond, ferr, berr, rpgf = gesvx!('N', 'N', A, similar(A, $elty, n, n), similar(A, BlasInt, n), 'N', similar(A, $elty, n), similar(A, $elty, n), B) X, rcond, ferr, berr, rpgf end end end for (gesvx, elty, relty) in ((:zgesvx_,:Complex128,:Float64), (:cgesvx_,:Complex64 ,:Float32)) @eval begin # SUBROUTINE ZGESVX( FACT, TRANS, N, NRHS, A, LDA, AF, LDAF, IPIV, # EQUED, R, C, B, LDB, X, LDX, RCOND, FERR, BERR, # WORK, RWORK, INFO ) # # .. Scalar Arguments .. # CHARACTER EQUED, FACT, TRANS # INTEGER INFO, LDA, LDAF, LDB, LDX, N, NRHS # DOUBLE PRECISION RCOND # .. # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION BERR( * ), C( * ), FERR( * ), R( * ), # $ RWORK( * ) # COMPLEX*16 A( LDA, * ), AF( LDAF, * ), B( LDB, * ), # $ WORK( * ), X( LDX, * ) function gesvx!(fact::Char, trans::Char, A::StridedMatrix{$elty}, AF::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, equed::Char, R::StridedVector{$relty}, C::StridedVector{$relty}, B::StridedVecOrMat{$elty}) chktrans(trans) chkstride1(ipiv, R, C) n = checksquare(A) lda = stride(A,2) n = checksquare(AF) ldaf = stride(AF,2) nrhs = size(B,2) ldb = stride(B,2) rcond = Vector{$relty}(1) ferr = similar(A, $relty, nrhs) berr = similar(A, $relty, nrhs) work = Vector{$elty}(2n) rwork = Vector{$relty}(2n) info = Ref{BlasInt}() X = similar(A, $elty, n, nrhs) ccall((@blasfunc($gesvx), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{UInt8}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{$relty}, Ptr{BlasInt}), &fact, &trans, &n, &nrhs, A, &lda, AF, &ldaf, ipiv, &equed, R, C, B, &ldb, X, &n, rcond, ferr, berr, work, rwork, info) chklapackerror(info[]) if info[] == n + 1 warn("matrix is singular to working precision") else chknonsingular(info[]) end #RWORK(1) contains the reciprocal pivot growth factor norm(A)/norm(U) X, equed, R, C, B, rcond[1], ferr, berr, rwork[1] end #Wrapper for the no-equilibration, no-transpose calculation function gesvx!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) n = size(A,1) X, equed, R, C, B, rcond, ferr, berr, rpgf = gesvx!('N', 'N', A, similar(A, $elty, n, n), similar(A, BlasInt, n), 'N', similar(A, $relty, n), similar(A, $relty, n), B) X, rcond, ferr, berr, rpgf end end end """ gesvx!(fact, trans, A, AF, ipiv, equed, R, C, B) -> (X, equed, R, C, B, rcond, ferr, berr, work) Solves the linear equation `A * X = B` (`trans = N`), `A.' * X =B` (`trans = T`), or `A' * X = B` (`trans = C`) using the `LU` factorization of `A`. `fact` may be `E`, in which case `A` will be equilibrated and copied to `AF`; `F`, in which case `AF` and `ipiv` from a previous `LU` factorization are inputs; or `N`, in which case `A` will be copied to `AF` and then factored. If `fact = F`, `equed` may be `N`, meaning `A` has not been equilibrated; `R`, meaning `A` was multiplied by `diagm(R)` from the left; `C`, meaning `A` was multiplied by `diagm(C)` from the right; or `B`, meaning `A` was multiplied by `diagm(R)` from the left and `diagm(C)` from the right. If `fact = F` and `equed = R` or `B` the elements of `R` must all be positive. If `fact = F` and `equed = C` or `B` the elements of `C` must all be positive. Returns the solution `X`; `equed`, which is an output if `fact` is not `N`, and describes the equilibration that was performed; `R`, the row equilibration diagonal; `C`, the column equilibration diagonal; `B`, which may be overwritten with its equilibrated form `diagm(R)*B` (if `trans = N` and `equed = R,B`) or `diagm(C)*B` (if `trans = T,C` and `equed = C,B`); `rcond`, the reciprocal condition number of `A` after equilbrating; `ferr`, the forward error bound for each solution vector in `X`; `berr`, the forward error bound for each solution vector in `X`; and `work`, the reciprocal pivot growth factor. """ gesvx!(fact::Char, trans::Char, A::StridedMatrix, AF::StridedMatrix, ipiv::StridedVector{BlasInt}, equed::Char, R::StridedVector, C::StridedVector, B::StridedVecOrMat) """ gesvx!(A, B) The no-equilibration, no-transpose simplification of `gesvx!`. """ gesvx!(A::StridedMatrix, B::StridedVecOrMat) for (gelsd, gelsy, elty) in ((:dgelsd_,:dgelsy_,:Float64), (:sgelsd_,:sgelsy_,:Float32)) @eval begin # SUBROUTINE DGELSD( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, # $ WORK, LWORK, IWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS, RANK # DOUBLE PRECISION RCOND # * .. # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), S( * ), WORK( * ) function gelsd!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}, rcond::Real=-one($elty)) chkstride1(A, B) m, n = size(A) if size(B, 1) != m throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] s = similar(A, $elty, min(m, n)) rcond = convert($elty, rcond) rnk = Vector{BlasInt}(1) info = Ref{BlasInt}() work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(1) for i = 1:2 ccall((@blasfunc($gelsd), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &size(B,2), A, &max(1,stride(A,2)), newB, &max(1,stride(B,2),n), s, &rcond, rnk, work, &lwork, iwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) iwork = Vector{BlasInt}(iwork[1]) end end subsetrows(B, newB, n), rnk[1] end # SUBROUTINE DGELSY( M, N, NRHS, A, LDA, B, LDB, JPVT, RCOND, RANK, # $ WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS, RANK # DOUBLE PRECISION RCOND # * .. # * .. Array Arguments .. # INTEGER JPVT( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), WORK( * ) function gelsy!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}, rcond::Real=eps($elty)) chkstride1(A, B) m = size(A, 1) n = size(A, 2) nrhs = size(B, 2) if size(B, 1) != m throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] lda = max(1, m) ldb = max(1, m, n) jpvt = zeros(BlasInt, n) rcond = convert($elty, rcond) rnk = Vector{BlasInt}(1) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gelsy), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &nrhs, A, &lda, newB, &ldb, jpvt, &rcond, rnk, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) end end subsetrows(B, newB, n), rnk[1] end end end for (gelsd, gelsy, elty, relty) in ((:zgelsd_,:zgelsy_,:Complex128,:Float64), (:cgelsd_,:cgelsy_,:Complex64,:Float32)) @eval begin # SUBROUTINE ZGELSD( M, N, NRHS, A, LDA, B, LDB, S, RCOND, RANK, # $ WORK, LWORK, RWORK, IWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS, RANK # DOUBLE PRECISION RCOND # * .. # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION RWORK( * ), S( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function gelsd!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}, rcond::Real=-one($relty)) chkstride1(A, B) m, n = size(A) if size(B, 1) != m throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] s = similar(A, $relty, min(m, n)) rcond = convert($relty, rcond) rnk = Vector{BlasInt}(1) info = Ref{BlasInt}() work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(1) iwork = Vector{BlasInt}(1) for i = 1:2 ccall((@blasfunc($gelsd), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &size(B,2), A, &max(1,stride(A,2)), newB, &max(1,stride(B,2),n), s, &rcond, rnk, work, &lwork, rwork, iwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) rwork = Vector{$relty}(BlasInt(rwork[1])) iwork = Vector{BlasInt}(iwork[1]) end end subsetrows(B, newB, n), rnk[1] end # SUBROUTINE ZGELSY( M, N, NRHS, A, LDA, B, LDB, JPVT, RCOND, RANK, # $ WORK, LWORK, RWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS, RANK # DOUBLE PRECISION RCOND # * .. # * .. Array Arguments .. # INTEGER JPVT( * ) # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function gelsy!(A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}, rcond::Real=eps($relty)) chkstride1(A, B) m, n = size(A) nrhs = size(B, 2) if size(B, 1) != m throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] lda = max(1, m) ldb = max(1, m, n) jpvt = zeros(BlasInt, n) rcond = convert($relty, rcond) rnk = Vector{BlasInt}(1) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(2n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gelsy), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &m, &n, &nrhs, A, &lda, newB, &ldb, jpvt, &rcond, rnk, work, &lwork, rwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end subsetrows(B, newB, n), rnk[1] end end end """ gelsd!(A, B, rcond) -> (B, rnk) Computes the least norm solution of `A * X = B` by finding the `SVD` factorization of `A`, then dividing-and-conquering the problem. `B` is overwritten with the solution `X`. Singular values below `rcond` will be treated as zero. Returns the solution in `B` and the effective rank of `A` in `rnk`. """ gelsd!(A::StridedMatrix, B::StridedVecOrMat, rcond::Real) """ gelsy!(A, B, rcond) -> (B, rnk) Computes the least norm solution of `A * X = B` by finding the full `QR` factorization of `A`, then dividing-and-conquering the problem. `B` is overwritten with the solution `X`. Singular values below `rcond` will be treated as zero. Returns the solution in `B` and the effective rank of `A` in `rnk`. """ gelsy!(A::StridedMatrix, B::StridedVecOrMat, rcond::Real) for (gglse, elty) in ((:dgglse_, :Float64), (:sgglse_, :Float32), (:zgglse_, :Complex128), (:cgglse_, :Complex64)) @eval begin # SUBROUTINE DGGLSE( M, N, P, A, LDA, B, LDB, C, D, X, WORK, LWORK, # $ INFO ) # * .. Scalar Arguments .. # INTEGER INFO, LDA, LDB, LWORK, M, N, P # * .. # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), C( * ), D( * ), # $ WORK( * ), X( * ) function gglse!(A::StridedMatrix{$elty}, c::StridedVector{$elty}, B::StridedMatrix{$elty}, d::StridedVector{$elty}) chkstride1(A, B) m, n = size(A) p = size(B, 1) if size(B, 2) != n throw(DimensionMismatch("B has second dimension $(size(B,2)), needs $n")) end if length(c) != m throw(DimensionMismatch("c has length $(length(c)), needs $m")) end if length(d) != p throw(DimensionMismatch("d has length $(length(d)), needs $p")) end X = zeros($elty, n) info = Ref{BlasInt}() work = Vector{$elty}(1) lwork = BlasInt(-1) for i = 1:2 ccall((@blasfunc($gglse), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &p, A, &max(1,stride(A,2)), B, &max(1,stride(B,2)), c, d, X, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end X, dot(view(c, n - p + 1:m), view(c, n - p + 1:m)) end end end """ gglse!(A, c, B, d) -> (X,res) Solves the equation `A * x = c` where `x` is subject to the equality constraint `B * x = d`. Uses the formula `||c - A*x||^2 = 0` to solve. Returns `X` and the residual sum-of-squares. """ gglse!(A::StridedMatrix, c::StridedVector, B::StridedMatrix, d::StridedVector) # (GE) general matrices eigenvalue-eigenvector and singular value decompositions for (geev, gesvd, gesdd, ggsvd, elty, relty) in ((:dgeev_,:dgesvd_,:dgesdd_,:dggsvd_,:Float64,:Float64), (:sgeev_,:sgesvd_,:sgesdd_,:sggsvd_,:Float32,:Float32), (:zgeev_,:zgesvd_,:zgesdd_,:zggsvd_,:Complex128,:Float64), (:cgeev_,:cgesvd_,:cgesdd_,:cggsvd_,:Complex64,:Float32)) @eval begin # SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR, # $ LDVR, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBVL, JOBVR # INTEGER INFO, LDA, LDVL, LDVR, LWORK, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), VL( LDVL, * ), VR( LDVR, * ), # $ WI( * ), WORK( * ), WR( * ) function geev!(jobvl::Char, jobvr::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs lvecs = jobvl == 'V' rvecs = jobvr == 'V' VL = similar(A, $elty, (n, lvecs ? n : 0)) VR = similar(A, $elty, (n, rvecs ? n : 0)) cmplx = eltype(A) <: Complex if cmplx W = similar(A, $elty, n) rwork = similar(A, $relty, 2n) else WR = similar(A, $elty, n) WI = similar(A, $elty, n) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 if cmplx ccall((@blasfunc($geev), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &jobvl, &jobvr, &n, A, &max(1,stride(A,2)), W, VL, &n, VR, &n, work, &lwork, rwork, info) else ccall((@blasfunc($geev), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobvl, &jobvr, &n, A, &max(1,stride(A,2)), WR, WI, VL, &n, VR, &n, work, &lwork, info) end chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end cmplx ? (W, VL, VR) : (WR, WI, VL, VR) end # SUBROUTINE DGESDD( JOBZ, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, # LWORK, IWORK, INFO ) #* .. Scalar Arguments .. # CHARACTER JOBZ # INTEGER INFO, LDA, LDU, LDVT, LWORK, M, N #* .. #* .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), S( * ), U( LDU, * ), # VT( LDVT, * ), WORK( * ) function gesdd!(job::Char, A::StridedMatrix{$elty}) chkstride1(A) m, n = size(A) minmn = min(m, n) if job == 'A' U = similar(A, $elty, (m, m)) VT = similar(A, $elty, (n, n)) elseif job == 'S' U = similar(A, $elty, (m, minmn)) VT = similar(A, $elty, (minmn, n)) elseif job == 'O' U = similar(A, $elty, (m, m >= n ? 0 : m)) VT = similar(A, $elty, (n, m >= n ? n : 0)) else U = similar(A, $elty, (m, 0)) VT = similar(A, $elty, (n, 0)) end work = Vector{$elty}(1) lwork = BlasInt(-1) S = similar(A, $relty, minmn) cmplx = eltype(A)<:Complex if cmplx rwork = Array{$relty}(job == 'N' ? 7*minmn : minmn*max(5*minmn+7, 2*max(m,n)+2*minmn+1)) end iwork = Vector{BlasInt}(8*minmn) info = Ref{BlasInt}() for i = 1:2 if cmplx ccall((@blasfunc($gesdd), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}, Ptr{BlasInt}), &job, &m, &n, A, &max(1,stride(A,2)), S, U, &max(1,stride(U,2)), VT, &max(1,stride(VT,2)), work, &lwork, rwork, iwork, info) else ccall((@blasfunc($gesdd), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &job, &m, &n, A, &max(1,stride(A,2)), S, U, &max(1,stride(U,2)), VT, &max(1,stride(VT,2)), work, &lwork, iwork, info) end chklapackerror(info[]) if i == 1 # Work around issue with truncated Float32 representation of lwork in # sgesdd by using nextfloat. See # http://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=13&t=4587&p=11036&hilit=sgesdd#p11036 # and # https://github.com/scipy/scipy/issues/5401 lwork = round(BlasInt, nextfloat(real(work[1]))) work = Vector{$elty}(lwork) end end if job == 'O' if m >= n return (A, S, VT) else # ()__ # ||::Z__ # ||::|:::Z____ # ||::|:::|====| # ||==|===|====| # ||""|===|====| # || `"""|====| # || `""""` return (U, S, A) end end return (U, S, VT) end # SUBROUTINE DGESVD( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBU, JOBVT # INTEGER INFO, LDA, LDU, LDVT, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), S( * ), U( LDU, * ), # $ VT( LDVT, * ), WORK( * ) function gesvd!(jobu::Char, jobvt::Char, A::StridedMatrix{$elty}) chkstride1(A) m, n = size(A) minmn = min(m, n) S = similar(A, $relty, minmn) U = similar(A, $elty, jobu == 'A'? (m, m):(jobu == 'S'? (m, minmn) : (m, 0))) VT = similar(A, $elty, jobvt == 'A'? (n, n):(jobvt == 'S'? (minmn, n) : (n, 0))) work = Vector{$elty}(1) cmplx = eltype(A) <: Complex if cmplx rwork = Vector{$relty}(5minmn) end lwork = BlasInt(-1) info = Ref{BlasInt}() for i in 1:2 if cmplx ccall((@blasfunc($gesvd), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &jobu, &jobvt, &m, &n, A, &max(1,stride(A,2)), S, U, &max(1,stride(U,2)), VT, &max(1,stride(VT,2)), work, &lwork, rwork, info) else ccall((@blasfunc($gesvd), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobu, &jobvt, &m, &n, A, &max(1,stride(A,2)), S, U, &max(1,stride(U,2)), VT, &max(1,stride(VT,2)), work, &lwork, info) end chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end if jobu == 'O' return (A, S, VT) elseif jobvt == 'O' # =============|===========|() # # # #:::::: # # # #:::::: # # # #:::::: # # # #:::::: # # # # # # # # # # # # # # # # # # # # # return (U, S, A) # # # # # # # else # # # # # # # return (U, S, VT) # # # # # # # end end # SUBROUTINE ZGGSVD( JOBU, JOBV, JOBQ, M, N, P, K, L, A, LDA, B, # $ LDB, ALPHA, BETA, U, LDU, V, LDV, Q, LDQ, WORK, # $ RWORK, IWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBQ, JOBU, JOBV # INTEGER INFO, K, L, LDA, LDB, LDQ, LDU, LDV, M, N, P # * .. # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION ALPHA( * ), BETA( * ), RWORK( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), Q( LDQ, * ), # $ U( LDU, * ), V( LDV, * ), WORK( * ) function ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n throw(DimensionMismatch("B has second dimension $(size(B,2)) but needs $n")) end p = size(B, 1) k = Vector{BlasInt}(1) l = Vector{BlasInt}(1) lda = max(1,stride(A, 2)) ldb = max(1,stride(B, 2)) alpha = similar(A, $relty, n) beta = similar(A, $relty, n) ldu = max(1, m) U = jobu == 'U' ? similar(A, $elty, ldu, m) : similar(A, $elty, 0) ldv = max(1, p) V = jobv == 'V' ? similar(A, $elty, ldv, p) : similar(A, $elty, 0) ldq = max(1, n) Q = jobq == 'Q' ? similar(A, $elty, ldq, n) : similar(A, $elty, 0) work = Vector{$elty}(max(3n, m, p) + n) cmplx = eltype(A) <: Complex if cmplx rwork = Vector{$relty}(2n) end iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() if cmplx ccall((@blasfunc($ggsvd), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$relty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobu, &jobv, &jobq, &m, &n, &p, k, l, A, &lda, B, &ldb, alpha, beta, U, &ldu, V, &ldv, Q, &ldq, work, rwork, iwork, info) else ccall((@blasfunc($ggsvd), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobu, &jobv, &jobq, &m, &n, &p, k, l, A, &lda, B, &ldb, alpha, beta, U, &ldu, V, &ldv, Q, &ldq, work, iwork, info) end chklapackerror(info[]) if m - k[1] - l[1] >= 0 R = triu(A[1:k[1] + l[1],n - k[1] - l[1] + 1:n]) else R = triu([A[1:m, n - k[1] - l[1] + 1:n]; B[m - k[1] + 1:l[1], n - k[1] - l[1] + 1:n]]) end U, V, Q, alpha, beta, k[1], l[1], R end end end """ geev!(jobvl, jobvr, A) -> (W, VL, VR) Finds the eigensystem of `A`. If `jobvl = N`, the left eigenvectors of `A` aren't computed. If `jobvr = N`, the right eigenvectors of `A` aren't computed. If `jobvl = V` or `jobvr = V`, the corresponding eigenvectors are computed. Returns the eigenvalues in `W`, the right eigenvectors in `VR`, and the left eigenvectors in `VL`. """ geev!(jobvl::Char, jobvr::Char, A::StridedMatrix) """ gesdd!(job, A) -> (U, S, VT) Finds the singular value decomposition of `A`, `A = U * S * V'`, using a divide and conquer approach. If `job = A`, all the columns of `U` and the rows of `V'` are computed. If `job = N`, no columns of `U` or rows of `V'` are computed. If `job = O`, `A` is overwritten with the columns of (thin) `U` and the rows of (thin) `V'`. If `job = S`, the columns of (thin) `U` and the rows of (thin) `V'` are computed and returned separately. """ gesdd!(job::Char, A::StridedMatrix) """ gesvd!(jobu, jobvt, A) -> (U, S, VT) Finds the singular value decomposition of `A`, `A = U * S * V'`. If `jobu = A`, all the columns of `U` are computed. If `jobvt = A` all the rows of `V'` are computed. If `jobu = N`, no columns of `U` are computed. If `jobvt = N` no rows of `V'` are computed. If `jobu = O`, `A` is overwritten with the columns of (thin) `U`. If `jobvt = O`, `A` is overwritten with the rows of (thin) `V'`. If `jobu = S`, the columns of (thin) `U` are computed and returned separately. If `jobvt = S` the rows of (thin) `V'` are computed and returned separately. `jobu` and `jobvt` can't both be `O`. Returns `U`, `S`, and `Vt`, where `S` are the singular values of `A`. """ gesvd!(jobu::Char, jobvt::Char, A::StridedMatrix) """ ggsvd!(jobu, jobv, jobq, A, B) -> (U, V, Q, alpha, beta, k, l, R) Finds the generalized singular value decomposition of `A` and `B`, `U'*A*Q = D1*R` and `V'*B*Q = D2*R`. `D1` has `alpha` on its diagonal and `D2` has `beta` on its diagonal. If `jobu = U`, the orthogonal/unitary matrix `U` is computed. If `jobv = V` the orthogonal/unitary matrix `V` is computed. If `jobq = Q`, the orthogonal/unitary matrix `Q` is computed. If `jobu`, `jobv` or `jobq` is `N`, that matrix is not computed. This function is only available in LAPACK versions prior to 3.6.0. """ ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::StridedMatrix, B::StridedMatrix) for (f, elty) in ((:dggsvd3_, :Float64), (:sggsvd3_, :Float32)) @eval begin function ggsvd3!(jobu::Char, jobv::Char, jobq::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n throw(DimensionMismatch("B has second dimension $(size(B,2)) but needs $n")) end p = size(B, 1) k = Ref{BlasInt}() l = Ref{BlasInt}() lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) alpha = similar(A, $elty, n) beta = similar(A, $elty, n) ldu = max(1, m) U = jobu == 'U' ? similar(A, $elty, ldu, m) : similar(A, $elty, 0) ldv = max(1, p) V = jobv == 'V' ? similar(A, $elty, ldv, p) : similar(A, $elty, 0) ldq = max(1, n) Q = jobq == 'Q' ? similar(A, $elty, ldq, n) : similar(A, $elty, 0) work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($f), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ref{BlasInt}, Ref{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ref{BlasInt}), &jobu, &jobv, &jobq, &m, &n, &p, k, l, A, &lda, B, &ldb, alpha, beta, U, &ldu, V, &ldv, Q, &ldq, work, &lwork, iwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) resize!(work, lwork) end end if m - k[] - l[] >= 0 R = triu(A[1:k[] + l[],n - k[] - l[] + 1:n]) else R = triu([A[1:m, n - k[] - l[] + 1:n]; B[m - k[] + 1:l[], n - k[] - l[] + 1:n]]) end return U, V, Q, alpha, beta, k[], l[], R end end end for (f, elty, relty) in ((:zggsvd3_, :Complex128, :Float64), (:cggsvd3_, :Complex64, :Float32)) @eval begin function ggsvd3!(jobu::Char, jobv::Char, jobq::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n throw(DimensionMismatch("B has second dimension $(size(B,2)) but needs $n")) end p = size(B, 1) k = Vector{BlasInt}(1) l = Vector{BlasInt}(1) lda = max(1,stride(A, 2)) ldb = max(1,stride(B, 2)) alpha = similar(A, $relty, n) beta = similar(A, $relty, n) ldu = max(1, m) U = jobu == 'U' ? similar(A, $elty, ldu, m) : similar(A, $elty, 0) ldv = max(1, p) V = jobv == 'V' ? similar(A, $elty, ldv, p) : similar(A, $elty, 0) ldq = max(1, n) Q = jobq == 'Q' ? similar(A, $elty, ldq, n) : similar(A, $elty, 0) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(2n) iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($f), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobu, &jobv, &jobq, &m, &n, &p, k, l, A, &lda, B, &ldb, alpha, beta, U, &ldu, V, &ldv, Q, &ldq, work, &lwork, rwork, iwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) end end if m - k[1] - l[1] >= 0 R = triu(A[1:k[1] + l[1],n - k[1] - l[1] + 1:n]) else R = triu([A[1:m, n - k[1] - l[1] + 1:n]; B[m - k[1] + 1:l[1], n - k[1] - l[1] + 1:n]]) end return U, V, Q, alpha, beta, k[1], l[1], R end end end """ ggsvd3!(jobu, jobv, jobq, A, B) -> (U, V, Q, alpha, beta, k, l, R) Finds the generalized singular value decomposition of `A` and `B`, `U'*A*Q = D1*R` and `V'*B*Q = D2*R`. `D1` has `alpha` on its diagonal and `D2` has `beta` on its diagonal. If `jobu = U`, the orthogonal/unitary matrix `U` is computed. If `jobv = V` the orthogonal/unitary matrix `V` is computed. If `jobq = Q`, the orthogonal/unitary matrix `Q` is computed. If `jobu`, `jobv`, or `jobq` is `N`, that matrix is not computed. This function requires LAPACK 3.6.0. """ ggsvd3! ## Expert driver and generalized eigenvalue problem for (geevx, ggev, elty) in ((:dgeevx_,:dggev_,:Float64), (:sgeevx_,:sggev_,:Float32)) @eval begin # SUBROUTINE DGEEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, WR, WI, # VL, LDVL, VR, LDVR, ILO, IHI, SCALE, ABNRM, # RCONDE, RCONDV, WORK, LWORK, IWORK, INFO ) # # .. Scalar Arguments .. # CHARACTER BALANC, JOBVL, JOBVR, SENSE # INTEGER IHI, ILO, INFO, LDA, LDVL, LDVR, LWORK, N # DOUBLE PRECISION ABNRM # .. # .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), RCONDE( * ), RCONDV( * ), # $ SCALE( * ), VL( LDVL, * ), VR( LDVR, * ), # $ WI( * ), WORK( * ), WR( * ) function geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::StridedMatrix{$elty}) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs lda = max(1,stride(A,2)) wr = similar(A, $elty, n) wi = similar(A, $elty, n) if balanc ∉ ['N', 'P', 'S', 'B'] throw(ArgumentError("balanc must be 'N', 'P', 'S', or 'B', but $balanc was passed")) end ldvl = 0 if jobvl == 'V' ldvl = n elseif jobvl == 'N' ldvl = 0 else throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) end VL = similar(A, $elty, ldvl, n) ldvr = 0 if jobvr == 'V' ldvr = n elseif jobvr == 'N' ldvr = 0 else throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) end VR = similar(A, $elty, ldvr, n) ilo = Ref{BlasInt}() ihi = Ref{BlasInt}() scale = similar(A, $elty, n) abnrm = Ref{$elty}() rconde = similar(A, $elty, n) rcondv = similar(A, $elty, n) work = Vector{$elty}(1) lwork = BlasInt(-1) iworksize = 0 if sense == 'N' || sense == 'E' iworksize = 0 elseif sense == 'V' || sense == 'B' iworksize = 2*n - 2 else throw(ArgumentError("sense must be 'N', 'E', 'V' or 'B', but $sense was passed")) end iwork = Vector{BlasInt}(iworksize) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($geevx), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &balanc, &jobvl, &jobvr, &sense, &n, A, &lda, wr, wi, VL, &max(1,ldvl), VR, &max(1,ldvr), ilo, ihi, scale, abnrm, rconde, rcondv, work, &lwork, iwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) end end A, wr, wi, VL, VR, ilo[], ihi[], scale, abnrm[], rconde, rcondv end # SUBROUTINE DGGEV( JOBVL, JOBVR, N, A, LDA, B, LDB, ALPHAR, ALPHAI, # $ BETA, VL, LDVL, VR, LDVR, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBVL, JOBVR # INTEGER INFO, LDA, LDB, LDVL, LDVR, LWORK, N # * .. # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), ALPHAI( * ), ALPHAR( * ), # $ B( LDB, * ), BETA( * ), VL( LDVL, * ), # $ VR( LDVR, * ), WORK( * ) function ggev!(jobvl::Char, jobvr::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A,B) n, m = checksquare(A,B) if n != m throw(DimensionMismatch("A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) alphar = similar(A, $elty, n) alphai = similar(A, $elty, n) beta = similar(A, $elty, n) ldvl = 0 if jobvl == 'V' ldvl = n elseif jobvl == 'N' ldvl = 1 else throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) end vl = similar(A, $elty, ldvl, n) ldvr = 0 if jobvr == 'V' ldvr = n elseif jobvr == 'N' ldvr = 1 else throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) end vr = similar(A, $elty, ldvr, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ggev), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobvl, &jobvr, &n, A, &lda, B, &ldb, alphar, alphai, beta, vl, &ldvl, vr, &ldvr, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) end end alphar, alphai, beta, vl, vr end end end for (geevx, ggev, elty, relty) in ((:zgeevx_,:zggev_,:Complex128,:Float64), (:cgeevx_,:cggev_,:Complex64,:Float32)) @eval begin # SUBROUTINE ZGEEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, W, VL, # LDVL, VR, LDVR, ILO, IHI, SCALE, ABNRM, RCONDE, # RCONDV, WORK, LWORK, RWORK, INFO ) # # .. Scalar Arguments .. # CHARACTER BALANC, JOBVL, JOBVR, SENSE # INTEGER IHI, ILO, INFO, LDA, LDVL, LDVR, LWORK, N # DOUBLE PRECISION ABNRM # .. # .. Array Arguments .. # DOUBLE PRECISION RCONDE( * ), RCONDV( * ), RWORK( * ), # $ SCALE( * ) # COMPLEX*16 A( LDA, * ), VL( LDVL, * ), VR( LDVR, * ), # $ W( * ), WORK( * ) function geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::StridedMatrix{$elty}) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs lda = max(1,stride(A,2)) w = similar(A, $elty, n) if balanc ∉ ['N', 'P', 'S', 'B'] throw(ArgumentError("balanc must be 'N', 'P', 'S', or 'B', but $balanc was passed")) end ldvl = 0 if jobvl == 'V' ldvl = n elseif jobvl == 'N' ldvl = 0 else throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) end VL = similar(A, $elty, ldvl, n) ldvr = 0 if jobvr == 'V' ldvr = n elseif jobvr == 'N' ldvr = 0 else throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) end if sense ∉ ['N','E','V','B'] throw(ArgumentError("sense must be 'N', 'E', 'V' or 'B', but $sense was passed")) end VR = similar(A, $elty, ldvr, n) ilo = Ref{BlasInt}() ihi = Ref{BlasInt}() scale = similar(A, $relty, n) abnrm = Ref{$relty}() rconde = similar(A, $relty, n) rcondv = similar(A, $relty, n) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(2n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($geevx), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &balanc, &jobvl, &jobvr, &sense, &n, A, &lda, w, VL, &max(1,ldvl), VR, &max(1,ldvr), ilo, ihi, scale, abnrm, rconde, rcondv, work, &lwork, rwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) end end A, w, VL, VR, ilo[], ihi[], scale, abnrm[], rconde, rcondv end # SUBROUTINE ZGGEV( JOBVL, JOBVR, N, A, LDA, B, LDB, ALPHA, BETA, # $ VL, LDVL, VR, LDVR, WORK, LWORK, RWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBVL, JOBVR # INTEGER INFO, LDA, LDB, LDVL, LDVR, LWORK, N # * .. # * .. Array Arguments .. # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), ALPHA( * ), B( LDB, * ), # $ BETA( * ), VL( LDVL, * ), VR( LDVR, * ), # $ WORK( * ) function ggev!(jobvl::Char, jobvr::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m throw(DimensionMismatch("A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) alpha = similar(A, $elty, n) beta = similar(A, $elty, n) ldvl = 0 if jobvl == 'V' ldvl = n elseif jobvl == 'N' ldvl = 1 else throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) end vl = similar(A, $elty, ldvl, n) ldvr = 0 if jobvr == 'V' ldvr = n elseif jobvr == 'N' ldvr = 1 else throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) end vr = similar(A, $elty, ldvr, n) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(8n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ggev), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &jobvl, &jobvr, &n, A, &lda, B, &ldb, alpha, beta, vl, &ldvl, vr, &ldvr, work, &lwork, rwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) end end alpha, beta, vl, vr end end end """ geevx!(balanc, jobvl, jobvr, sense, A) -> (A, w, VL, VR, ilo, ihi, scale, abnrm, rconde, rcondv) Finds the eigensystem of `A` with matrix balancing. If `jobvl = N`, the left eigenvectors of `A` aren't computed. If `jobvr = N`, the right eigenvectors of `A` aren't computed. If `jobvl = V` or `jobvr = V`, the corresponding eigenvectors are computed. If `balanc = N`, no balancing is performed. If `balanc = P`, `A` is permuted but not scaled. If `balanc = S`, `A` is scaled but not permuted. If `balanc = B`, `A` is permuted and scaled. If `sense = N`, no reciprocal condition numbers are computed. If `sense = E`, reciprocal condition numbers are computed for the eigenvalues only. If `sense = V`, reciprocal condition numbers are computed for the right eigenvectors only. If `sense = B`, reciprocal condition numbers are computed for the right eigenvectors and the eigenvectors. If `sense = E,B`, the right and left eigenvectors must be computed. """ geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::StridedMatrix) """ ggev!(jobvl, jobvr, A, B) -> (alpha, beta, vl, vr) Finds the generalized eigendecomposition of `A` and `B`. If `jobvl = N`, the left eigenvectors aren't computed. If `jobvr = N`, the right eigenvectors aren't computed. If `jobvl = V` or `jobvr = V`, the corresponding eigenvectors are computed. """ ggev!(jobvl::Char, jobvr::Char, A::StridedMatrix, B::StridedMatrix) # One step incremental condition estimation of max/min singular values for (laic1, elty) in ((:dlaic1_,:Float64), (:slaic1_,:Float32)) @eval begin # SUBROUTINE DLAIC1( JOB, J, X, SEST, W, GAMMA, SESTPR, S, C ) # # .. Scalar Arguments .. # INTEGER J, JOB # DOUBLE PRECISION C, GAMMA, S, SEST, SESTPR # .. # .. Array Arguments .. # DOUBLE PRECISION W( J ), X( J ) function laic1!(job::Integer, x::StridedVector{$elty}, sest::$elty, w::StridedVector{$elty}, gamma::$elty) j = length(x) if j != length(w) throw(DimensionMismatch("vectors must have same length, but length of x is $j and length of w is $(length(w))")) end sestpr = Vector{$elty}(1) s = Vector{$elty}(1) c = Vector{$elty}(1) ccall((@blasfunc($laic1), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}), &job, &j, x, &sest, w, &gamma, sestpr, s, c) sestpr[1], s[1], c[1] end end end for (laic1, elty, relty) in ((:zlaic1_,:Complex128,:Float64), (:claic1_,:Complex64,:Float32)) @eval begin # SUBROUTINE ZLAIC1( JOB, J, X, SEST, W, GAMMA, SESTPR, S, C ) # # .. Scalar Arguments .. # INTEGER J, JOB # DOUBLE PRECISION SEST, SESTPR # COMPLEX*16 C, GAMMA, S # .. # .. Array Arguments .. # COMPLEX*16 W( J ), X( J ) function laic1!(job::Integer, x::StridedVector{$elty}, sest::$relty, w::StridedVector{$elty}, gamma::$elty) j = length(x) if j != length(w) throw(DimensionMismatch("vectors must have same length, but length of x is $j and length of w is $(length(w))")) end sestpr = Vector{$relty}(1) s = Vector{$elty}(1) c = Vector{$elty}(1) ccall((@blasfunc($laic1), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$relty}, Ptr{$elty}, Ptr{$elty}, Ptr{$relty}, Ptr{$elty}, Ptr{$elty}), &job, &j, x, &sest, w, &gamma, sestpr, s, c) sestpr[1], s[1], c[1] end end end # (GT) General tridiagonal, decomposition, solver and direct solver for (gtsv, gttrf, gttrs, elty) in ((:dgtsv_,:dgttrf_,:dgttrs_,:Float64), (:sgtsv_,:sgttrf_,:sgttrs_,:Float32), (:zgtsv_,:zgttrf_,:zgttrs_,:Complex128), (:cgtsv_,:cgttrf_,:cgttrs_,:Complex64)) @eval begin # SUBROUTINE DGTSV( N, NRHS, DL, D, DU, B, LDB, INFO ) # .. Scalar Arguments .. # INTEGER INFO, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION B( LDB, * ), D( * ), DL( * ), DU( * ) function gtsv!(dl::StridedVector{$elty}, d::StridedVector{$elty}, du::StridedVector{$elty}, B::StridedVecOrMat{$elty}) chkstride1(B, dl, d, du) n = length(d) if !(n >= length(dl) >= n - 1) throw(DimensionMismatch("subdiagonal has length $(length(dl)), but should be $n or $(n - 1)")) end if !(n >= length(du) >= n - 1) throw(DimensionMismatch("superdiagonal has length $(length(du)), but should be $n or $(n - 1)")) end if n != size(B,1) throw(DimensionMismatch("B has leading dimension $(size(B,1)), but should have $n")) end if n == 0 return B # Early exit if possible end info = Ref{BlasInt}() ccall((@blasfunc($gtsv), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, &size(B,2), dl, d, du, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end # SUBROUTINE DGTTRF( N, DL, D, DU, DU2, IPIV, INFO ) # .. Scalar Arguments .. # INTEGER INFO, N # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION D( * ), DL( * ), DU( * ), DU2( * ) function gttrf!(dl::StridedVector{$elty}, d::StridedVector{$elty}, du::StridedVector{$elty}) chkstride1(dl,d,du) n = length(d) if length(dl) != n - 1 throw(DimensionMismatch("subdiagonal has length $(length(dl)), but should be $(n - 1)")) end if length(du) != n - 1 throw(DimensionMismatch("superdiagonal has length $(length(du)), but should be $(n - 1)")) end du2 = similar(d, $elty, n-2) ipiv = similar(d, BlasInt, n) info = Ref{BlasInt}() ccall((@blasfunc($gttrf), liblapack), Void, (Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, dl, d, du, du2, ipiv, info) chklapackerror(info[]) dl, d, du, du2, ipiv end # SUBROUTINE DGTTRS( TRANS, N, NRHS, DL, D, DU, DU2, IPIV, B, LDB, INFO ) # .. Scalar Arguments .. # CHARACTER TRANS # INTEGER INFO, LDB, N, NRHS # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION B( LDB, * ), D( * ), DL( * ), DU( * ), DU2( * ) function gttrs!(trans::Char, dl::StridedVector{$elty}, d::StridedVector{$elty}, du::StridedVector{$elty}, du2::StridedVector{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chktrans(trans) chkstride1(B, ipiv, dl, d, du, du2) n = length(d) if length(dl) != n - 1 throw(DimensionMismatch("subdiagonal has length $(length(dl)), but should be $(n - 1)")) end if length(du) != n - 1 throw(DimensionMismatch("superdiagonal has length $(length(du)), but should be $(n - 1)")) end if n != size(B,1) throw(DimensionMismatch("B has leading dimension $(size(B,1)), but should have $n")) end info = Ref{BlasInt}() ccall((@blasfunc($gttrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &trans, &n, &size(B,2), dl, d, du, du2, ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end """ gtsv!(dl, d, du, B) Solves the equation `A * X = B` where `A` is a tridiagonal matrix with `dl` on the subdiagonal, `d` on the diagonal, and `du` on the superdiagonal. Overwrites `B` with the solution `X` and returns it. """ gtsv!(dl::StridedVector, d::StridedVector, du::StridedVector, B::StridedVecOrMat) """ gttrf!(dl, d, du) -> (dl, d, du, du2, ipiv) Finds the `LU` factorization of a tridiagonal matrix with `dl` on the subdiagonal, `d` on the diagonal, and `du` on the superdiagonal. Modifies `dl`, `d`, and `du` in-place and returns them and the second superdiagonal `du2` and the pivoting vector `ipiv`. """ gttrf!(dl::StridedVector, d::StridedVector, du::StridedVector) """ gttrs!(trans, dl, d, du, du2, ipiv, B) Solves the equation `A * X = B` (`trans = N`), `A.' * X = B` (`trans = T`), or `A' * X = B` (`trans = C`) using the `LU` factorization computed by `gttrf!`. `B` is overwritten with the solution `X`. """ gttrs!(trans::Char, dl::StridedVector, d::StridedVector, du::StridedVector, du2::StridedVector, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat) ## (OR) orthogonal (or UN, unitary) matrices, extractors and multiplication for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in ((:dorglq_,:dorgqr_,:dorgql_,:dorgrq_,:dormlq_,:dormqr_,:dormql_,:dormrq_,:dgemqrt_,:Float64), (:sorglq_,:sorgqr_,:sorgql_,:sorgrq_,:sormlq_,:sormqr_,:sormql_,:sormrq_,:sgemqrt_,:Float32), (:zunglq_,:zungqr_,:zungql_,:zungrq_,:zunmlq_,:zunmqr_,:zunmql_,:zunmrq_,:zgemqrt_,:Complex128), (:cunglq_,:cungqr_,:cungql_,:cungrq_,:cunmlq_,:cunmqr_,:cunmql_,:cunmrq_,:cgemqrt_,:Complex64)) @eval begin # SUBROUTINE DORGLQ( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, K, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function orglq!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}, k::Integer = length(tau)) chkstride1(A,tau) n = size(A, 2) m = min(n, size(A, 1)) if k > m throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($orglq), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &k, A, &max(1,stride(A,2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end if m < size(A,1) A[1:m,:] else A end end # SUBROUTINE DORGQR( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, K, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function orgqr!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}, k::Integer = length(tau)) chkstride1(A,tau) m = size(A, 1) n = min(m, size(A, 2)) if k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($orgqr), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &k, A, &max(1,stride(A,2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end if n < size(A,2) A[:,1:n] else A end end # SUBROUTINE DORGQL( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, K, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function orgql!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}, k::Integer = length(tau)) chkstride1(A,tau) m = size(A, 1) n = min(m, size(A, 2)) if k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($orgql), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &k, A, &max(1,stride(A,2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end if n < size(A,2) A[:,1:n] else A end end # SUBROUTINE DORGRQ( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # INTEGER INFO, K, LDA, LWORK, M, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function orgrq!(A::StridedMatrix{$elty}, tau::StridedVector{$elty}, k::Integer = length(tau)) chkstride1(A,tau) m = size(A, 1) n = min(m, size(A, 2)) if k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($orgrq), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &m, &n, &k, A, &max(1,stride(A,2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end if n < size(A,2) A[:,1:n] else A end end # SUBROUTINE DORMLQ( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, # WORK, LWORK, INFO ) # .. Scalar Arguments .. # CHARACTER SIDE, TRANS # INTEGER INFO, K, LDA, LDC, LWORK, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) function ormlq!(side::Char, trans::Char, A::StridedMatrix{$elty}, tau::StridedVector{$elty}, C::StridedVecOrMat{$elty}) chktrans(trans) chkside(side) chkstride1(A, C, tau) m,n = ndims(C) == 2 ? size(C) : (size(C, 1), 1) mA, nA = size(A) k = length(tau) if side == 'L' && m != nA throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $nA")) end if side == 'R' && n != mA throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $n, must equal the first dimension of A, $mA")) end if side == 'L' && k > m throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ormlq), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, A, &max(1,stride(A,2)), tau, C, &max(1,stride(C,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end C end # SUBROUTINE DORMQR( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, # WORK, INFO ) # .. Scalar Arguments .. # CHARACTER SIDE, TRANS # INTEGER INFO, K, LDA, LDC, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) function ormqr!(side::Char, trans::Char, A::StridedMatrix{$elty}, tau::StridedVector{$elty}, C::StridedVecOrMat{$elty}) chktrans(trans) chkside(side) chkstride1(A, C, tau) m,n = ndims(C) == 2 ? size(C) : (size(C, 1), 1) mA = size(A, 1) k = length(tau) if side == 'L' && m != mA throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'R' && n != mA throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'L' && k > m throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ormqr), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, A, &max(1,stride(A,2)), tau, C, &max(1, stride(C,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end C end # SUBROUTINE DORMQL( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, # WORK, INFO ) # .. Scalar Arguments .. # CHARACTER SIDE, TRANS # INTEGER INFO, K, LDA, LDC, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) function ormql!(side::Char, trans::Char, A::StridedMatrix{$elty}, tau::StridedVector{$elty}, C::StridedVecOrMat{$elty}) chktrans(trans) chkside(side) chkstride1(A, C, tau) m,n = ndims(C) == 2 ? size(C) : (size(C, 1), 1) mA = size(A, 1) k = length(tau) if side == 'L' && m != mA throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'R' && n != mA throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'L' && k > m throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ormql), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, A, &max(1,stride(A,2)), tau, C, &max(1, stride(C,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end C end # SUBROUTINE DORMRQ( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, # WORK, LWORK, INFO ) # .. Scalar Arguments .. # CHARACTER SIDE, TRANS # INTEGER INFO, K, LDA, LDC, LWORK, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) function ormrq!(side::Char, trans::Char, A::StridedMatrix{$elty}, tau::StridedVector{$elty}, C::StridedVecOrMat{$elty}) chktrans(trans) chkside(side) chkstride1(A, C, tau) m,n = ndims(C) == 2 ? size(C) : (size(C, 1), 1) nA = size(A, 2) k = length(tau) if side == 'L' && m != nA throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $nA")) end if side == 'R' && n != nA throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $nA")) end if side == 'L' && k > m throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ormrq), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, A, &max(1,stride(A,2)), tau, C, &max(1,stride(C,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end C end function gemqrt!(side::Char, trans::Char, V::StridedMatrix{$elty}, T::StridedMatrix{$elty}, C::StridedVecOrMat{$elty}) chktrans(trans) chkside(side) chkstride1(V, T, C) m,n = ndims(C) == 2 ? size(C) : (size(C, 1), 1) nb, k = size(T) if k == 0 return C end if side == 'L' if !(0 <= k <= m) throw(DimensionMismatch("wrong value for k = $k: must be between 0 and $m")) end if m != size(V,1) throw(DimensionMismatch("first dimensions of C, $m, and V, $(size(V,1)) must match")) end ldv = stride(V,2) if ldv < max(1, m) throw(DimensionMismatch("Q and C don't fit! The stride of V, $ldv, is too small")) end wss = n*k elseif side == 'R' if !(0 <= k <= n) throw(DimensionMismatch("wrong value for k = $k: must be between 0 and $n")) end if n != size(V,1) throw(DimensionMismatch("second dimension of C, $n, and first dimension of V, $(size(V,1)) must match")) end ldv = stride(V,2) if ldv < max(1, n) throw(DimensionMismatch("Q and C don't fit! The stride of V, $ldv, is too small")) end wss = m*k end if !(1 <= nb <= k) throw(DimensionMismatch("wrong value for nb = $nb, which must be between 1 and $k")) end ldc = stride(C, 2) work = Vector{$elty}(wss) info = Ref{BlasInt}() ccall((@blasfunc($gemqrt), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, &nb, V, &ldv, T, &max(1,stride(T,2)), C, &max(1,ldc), work, info) chklapackerror(info[]) return C end end end """ orglq!(A, tau, k = length(tau)) Explicitly finds the matrix `Q` of a `LQ` factorization after calling `gelqf!` on `A`. Uses the output of `gelqf!`. `A` is overwritten by `Q`. """ orglq!(A::StridedMatrix, tau::StridedVector, k::Integer = length(tau)) """ orgqr!(A, tau, k = length(tau)) Explicitly finds the matrix `Q` of a `QR` factorization after calling `geqrf!` on `A`. Uses the output of `geqrf!`. `A` is overwritten by `Q`. """ orgqr!(A::StridedMatrix, tau::StridedVector, k::Integer = length(tau)) """ orgql!(A, tau, k = length(tau)) Explicitly finds the matrix `Q` of a `QL` factorization after calling `geqlf!` on `A`. Uses the output of `geqlf!`. `A` is overwritten by `Q`. """ orgql!(A::StridedMatrix, tau::StridedVector, k::Integer = length(tau)) """ orgrq!(A, tau, k = length(tau)) Explicitly finds the matrix `Q` of a `RQ` factorization after calling `gerqf!` on `A`. Uses the output of `gerqf!`. `A` is overwritten by `Q`. """ orgrq!(A::StridedMatrix, tau::StridedVector, k::Integer = length(tau)) """ ormlq!(side, trans, A, tau, C) Computes `Q * C` (`trans = N`), `Q.' * C` (`trans = T`), `Q' * C` (`trans = C`) for `side = L` or the equivalent right-sided multiplication for `side = R` using `Q` from a `LQ` factorization of `A` computed using `gelqf!`. `C` is overwritten. """ ormlq!(side::Char, trans::Char, A::StridedMatrix, tau::StridedVector, C::StridedVecOrMat) """ ormqr!(side, trans, A, tau, C) Computes `Q * C` (`trans = N`), `Q.' * C` (`trans = T`), `Q' * C` (`trans = C`) for `side = L` or the equivalent right-sided multiplication for `side = R` using `Q` from a `QR` factorization of `A` computed using `geqrf!`. `C` is overwritten. """ ormqr!(side::Char, trans::Char, A::StridedMatrix, tau::StridedVector, C::StridedVecOrMat) """ ormql!(side, trans, A, tau, C) Computes `Q * C` (`trans = N`), `Q.' * C` (`trans = T`), `Q' * C` (`trans = C`) for `side = L` or the equivalent right-sided multiplication for `side = R` using `Q` from a `QL` factorization of `A` computed using `geqlf!`. `C` is overwritten. """ ormql!(side::Char, trans::Char, A::StridedMatrix, tau::StridedVector, C::StridedVecOrMat) """ ormrq!(side, trans, A, tau, C) Computes `Q * C` (`trans = N`), `Q.' * C` (`trans = T`), `Q' * C` (`trans = C`) for `side = L` or the equivalent right-sided multiplication for `side = R` using `Q` from a `RQ` factorization of `A` computed using `gerqf!`. `C` is overwritten. """ ormrq!(side::Char, trans::Char, A::StridedMatrix, tau::StridedVector, C::StridedVecOrMat) """ gemqrt!(side, trans, V, T, C) Computes `Q * C` (`trans = N`), `Q.' * C` (`trans = T`), `Q' * C` (`trans = C`) for `side = L` or the equivalent right-sided multiplication for `side = R` using `Q` from a `QR` factorization of `A` computed using `geqrt!`. `C` is overwritten. """ gemqrt!(side::Char, trans::Char, V::StridedMatrix, T::StridedMatrix, C::StridedVecOrMat) # (PO) positive-definite symmetric matrices, for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in ((:dposv_,:dpotrf_,:dpotri_,:dpotrs_,:dpstrf_,:Float64,:Float64), (:sposv_,:spotrf_,:spotri_,:spotrs_,:spstrf_,:Float32,:Float32), (:zposv_,:zpotrf_,:zpotri_,:zpotrs_,:zpstrf_,:Complex128,:Float64), (:cposv_,:cpotrf_,:cpotri_,:cpotrs_,:cpstrf_,:Complex64,:Float32)) @eval begin # SUBROUTINE DPOSV( UPLO, N, NRHS, A, LDA, B, LDB, INFO ) #* .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function posv!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A, B) n = checksquare(A) chkuplo(uplo) if size(B,1) != n throw(DimensionMismatch("first dimension of B, $(size(B,1)), and size of A, ($n,$n), must match!")) end info = Ref{BlasInt}() ccall((@blasfunc($posv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), B, &max(1,stride(B,2)), info) chkargsok(info[]) chkposdef(info[]) A, B end # SUBROUTINE DPOTRF( UPLO, N, A, LDA, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ) function potrf!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) checksquare(A) chkuplo(uplo) lda = max(1,stride(A,2)) if lda == 0 return A, 0 end info = Ref{BlasInt}() ccall((@blasfunc($potrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &size(A,1), A, &lda, info) chkargsok(info[]) #info[1]>0 means the leading minor of order info[i] is not positive definite #ordinarily, throw Exception here, but return error code here #this simplifies isposdef! and factorize return A, info[] end # SUBROUTINE DPOTRI( UPLO, N, A, LDA, INFO ) # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ) function potri!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) chkuplo(uplo) info = Ref{BlasInt}() ccall((@blasfunc($potri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &size(A,1), A, &max(1,stride(A,2)), info) chkargsok(info[]) chknonsingular(info[]) A end # SUBROUTINE DPOTRS( UPLO, N, NRHS, A, LDA, B, LDB, INFO ) # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function potrs!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A, B) n = checksquare(A) chkuplo(uplo) nrhs = size(B,2) if size(B,1) != n throw(DimensionMismatch("first dimension of B, $(size(B,1)), and size of A, ($n,$n), must match!")) end lda = max(1,stride(A,2)) if lda == 0 || nrhs == 0 return B end ldb = max(1,stride(B,2)) info = Ref{BlasInt}() ccall((@blasfunc($potrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &nrhs, A, &lda, B, &ldb, info) chklapackerror(info[]) return B end # SUBROUTINE DPSTRF( UPLO, N, A, LDA, PIV, RANK, TOL, WORK, INFO ) # .. Scalar Arguments .. # DOUBLE PRECISION TOL # INTEGER INFO, LDA, N, RANK # CHARACTER UPLO # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), WORK( 2*N ) # INTEGER PIV( N ) function pstrf!(uplo::Char, A::StridedMatrix{$elty}, tol::Real) chkstride1(A) n = checksquare(A) chkuplo(uplo) piv = similar(A, BlasInt, n) rank = Vector{BlasInt}(1) work = Vector{$rtyp}(2n) info = Ref{BlasInt}() ccall((@blasfunc($pstrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$rtyp}, Ptr{$rtyp}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), piv, rank, &tol, work, info) chkargsok(info[]) A, piv, rank[1], info[] #Stored in PivotedCholesky end end end """ posv!(uplo, A, B) -> (A, B) Finds the solution to `A * X = B` where `A` is a symmetric or Hermitian positive definite matrix. If `uplo = U` the upper Cholesky decomposition of `A` is computed. If `uplo = L` the lower Cholesky decomposition of `A` is computed. `A` is overwritten by its Cholesky decomposition. `B` is overwritten with the solution `X`. """ posv!(uplo::Char, A::StridedMatrix, B::StridedVecOrMat) """ potrf!(uplo, A) Computes the Cholesky (upper if `uplo = U`, lower if `uplo = L`) decomposition of positive-definite matrix `A`. `A` is overwritten and returned with an info code. """ potrf!(uplo::Char, A::StridedMatrix) """ potri!(uplo, A) Computes the inverse of positive-definite matrix `A` after calling `potrf!` to find its (upper if `uplo = U`, lower if `uplo = L`) Cholesky decomposition. `A` is overwritten by its inverse and returned. """ potri!(uplo::Char, A::StridedMatrix) """ potrs!(uplo, A, B) Finds the solution to `A * X = B` where `A` is a symmetric or Hermitian positive definite matrix whose Cholesky decomposition was computed by `potrf!`. If `uplo = U` the upper Cholesky decomposition of `A` was computed. If `uplo = L` the lower Cholesky decomposition of `A` was computed. `B` is overwritten with the solution `X`. """ potrs!(uplo::Char, A::StridedMatrix, B::StridedVecOrMat) """ pstrf!(uplo, A, tol) -> (A, piv, rank, info) Computes the (upper if `uplo = U`, lower if `uplo = L`) pivoted Cholesky decomposition of positive-definite matrix `A` with a user-set tolerance `tol`. `A` is overwritten by its Cholesky decomposition. Returns `A`, the pivots `piv`, the rank of `A`, and an `info` code. If `info = 0`, the factorization succeeded. If `info = i > 0 `, then `A` is indefinite or rank-deficient. """ pstrf!(uplo::Char, A::StridedMatrix, tol::Real) # (PT) positive-definite, symmetric, tri-diagonal matrices # Direct solvers for general tridiagonal and symmetric positive-definite tridiagonal for (ptsv, pttrf, elty, relty) in ((:dptsv_,:dpttrf_,:Float64,:Float64), (:sptsv_,:spttrf_,:Float32,:Float32), (:zptsv_,:zpttrf_,:Complex128,:Float64), (:cptsv_,:cpttrf_,:Complex64,:Float32)) @eval begin # SUBROUTINE DPTSV( N, NRHS, D, E, B, LDB, INFO ) # .. Scalar Arguments .. # INTEGER INFO, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION B( LDB, * ), D( * ), E( * ) function ptsv!(D::StridedVector{$relty}, E::StridedVector{$elty}, B::StridedVecOrMat{$elty}) chkstride1(B, D, E) n = length(D) if length(E) != n - 1 throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) end if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($ptsv), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, &size(B,2), D, E, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end # SUBROUTINE DPTTRF( N, D, E, INFO ) # .. Scalar Arguments .. # INTEGER INFO, N # .. Array Arguments .. # DOUBLE PRECISION D( * ), E( * ) function pttrf!(D::StridedVector{$relty}, E::StridedVector{$elty}) chkstride1(D, E) n = length(D) if length(E) != n - 1 throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) end info = Ref{BlasInt}() ccall((@blasfunc($pttrf), liblapack), Void, (Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}), &n, D, E, info) chklapackerror(info[]) D, E end end end """ ptsv!(D, E, B) Solves `A * X = B` for positive-definite tridiagonal `A`. `D` is the diagonal of `A` and `E` is the off-diagonal. `B` is overwritten with the solution `X` and returned. """ ptsv!(D::StridedVector, E::StridedVector, B::StridedVecOrMat) """ pttrf!(D, E) Computes the LDLt factorization of a positive-definite tridiagonal matrix with `D` as diagonal and `E` as off-diagonal. `D` and `E` are overwritten and returned. """ pttrf!(D::StridedVector, E::StridedVector) for (pttrs, elty, relty) in ((:dpttrs_,:Float64,:Float64), (:spttrs_,:Float32,:Float32)) @eval begin # SUBROUTINE DPTTRS( N, NRHS, D, E, B, LDB, INFO ) # .. Scalar Arguments .. # INTEGER INFO, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION B( LDB, * ), D( * ), E( * ) function pttrs!(D::StridedVector{$relty}, E::StridedVector{$elty}, B::StridedVecOrMat{$elty}) chkstride1(B, D, E) n = length(D) if length(E) != n - 1 throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) end if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($pttrs), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, &size(B,2), D, E, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end for (pttrs, elty, relty) in ((:zpttrs_,:Complex128,:Float64), (:cpttrs_,:Complex64,:Float32)) @eval begin # SUBROUTINE ZPTTRS( UPLO, N, NRHS, D, E, B, LDB, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDB, N, NRHS # * .. # * .. Array Arguments .. # DOUBLE PRECISION D( * ) # COMPLEX*16 B( LDB, * ), E( * ) function pttrs!(uplo::Char, D::StridedVector{$relty}, E::StridedVector{$elty}, B::StridedVecOrMat{$elty}) chkstride1(B, D, E) chkuplo(uplo) n = length(D) if length(E) != n - 1 throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) end if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($pttrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), D, E, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end """ pttrs!(D, E, B) Solves `A * X = B` for positive-definite tridiagonal `A` with diagonal `D` and off-diagonal `E` after computing `A`'s LDLt factorization using `pttrf!`. `B` is overwritten with the solution `X`. """ pttrs!(D::StridedVector, E::StridedVector, B::StridedVecOrMat) ## (TR) triangular matrices: solver and inverse for (trtri, trtrs, elty) in ((:dtrtri_,:dtrtrs_,:Float64), (:strtri_,:strtrs_,:Float32), (:ztrtri_,:ztrtrs_,:Complex128), (:ctrtri_,:ctrtrs_,:Complex64)) @eval begin # SUBROUTINE DTRTRI( UPLO, DIAG, N, A, LDA, INFO ) #* .. Scalar Arguments .. # CHARACTER DIAG, UPLO # INTEGER INFO, LDA, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ) function trtri!(uplo::Char, diag::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) chkdiag(diag) lda = max(1,stride(A, 2)) info = Ref{BlasInt}() ccall((@blasfunc($trtri), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &diag, &n, A, &lda, info) chklapackerror(info[]) A end # SUBROUTINE DTRTRS( UPLO, TRANS, DIAG, N, NRHS, A, LDA, B, LDB, INFO ) # * .. Scalar Arguments .. # CHARACTER DIAG, TRANS, UPLO # INTEGER INFO, LDA, LDB, N, NRHS # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function trtrs!(uplo::Char, trans::Char, diag::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chktrans(trans) chkdiag(diag) chkstride1(A) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($trtrs), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &trans, &diag, &n, &size(B,2), A, &max(1,stride(A,2)), B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end """ trtri!(uplo, diag, A) Finds the inverse of (upper if `uplo = U`, lower if `uplo = L`) triangular matrix `A`. If `diag = N`, `A` has non-unit diagonal elements. If `diag = U`, all diagonal elements of `A` are one. `A` is overwritten with its inverse. """ trtri!(uplo::Char, diag::Char, A::StridedMatrix) """ trtrs!(uplo, trans, diag, A, B) Solves `A * X = B` (`trans = N`), `A.' * X = B` (`trans = T`), or `A' * X = B` (`trans = C`) for (upper if `uplo = U`, lower if `uplo = L`) triangular matrix `A`. If `diag = N`, `A` has non-unit diagonal elements. If `diag = U`, all diagonal elements of `A` are one. `B` is overwritten with the solution `X`. """ trtrs!(uplo::Char, trans::Char, diag::Char, A::StridedMatrix, B::StridedVecOrMat) #Eigenvector computation and condition number estimation for (trcon, trevc, trrfs, elty) in ((:dtrcon_,:dtrevc_,:dtrrfs_,:Float64), (:strcon_,:strevc_,:strrfs_,:Float32)) @eval begin # SUBROUTINE DTRCON( NORM, UPLO, DIAG, N, A, LDA, RCOND, WORK, # IWORK, INFO ) # .. Scalar Arguments .. # CHARACTER DIAG, NORM, UPLO # INTEGER INFO, LDA, N # DOUBLE PRECISION RCOND # .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function trcon!(norm::Char, uplo::Char, diag::Char, A::StridedMatrix{$elty}) chkstride1(A) chkdiag(diag) n = checksquare(A) chkuplo(uplo) rcond = Vector{$elty}(1) work = Vector{$elty}(3n) iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() ccall((@blasfunc($trcon), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &norm, &uplo, &diag, &n, A, &max(1,stride(A,2)), rcond, work, iwork, info) chklapackerror(info[]) rcond[1] end # SUBROUTINE DTREVC( SIDE, HOWMNY, SELECT, N, T, LDT, VL, LDVL, VR, # LDVR, MM, M, WORK, INFO ) # # .. Scalar Arguments .. # CHARACTER HOWMNY, SIDE # INTEGER INFO, LDT, LDVL, LDVR, M, MM, N # .. # .. Array Arguments .. # LOGICAL SELECT( * ) # DOUBLE PRECISION T( LDT, * ), VL( LDVL, * ), VR( LDVR, * ), #$ WORK( * ) function trevc!(side::Char, howmny::Char, select::StridedVector{BlasInt}, T::StridedMatrix{$elty}, VL::StridedMatrix{$elty} = similar(T), VR::StridedMatrix{$elty} = similar(T)) # Extract if side ∉ ['L','R','B'] throw(ArgumentError("side argument must be 'L' (left eigenvectors), 'R' (right eigenvectors), or 'B' (both), got $side")) end n, mm = checksquare(T), size(VL, 2) ldt, ldvl, ldvr = stride(T, 2), stride(VL, 2), stride(VR, 2) # Check chkstride1(T, select) # Allocate m = Ref{BlasInt}() work = Vector{$elty}(3n) info = Ref{BlasInt}() ccall((@blasfunc($trevc), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt},Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &side, &howmny, select, &n, T, &ldt, VL, &ldvl, VR, &ldvr, &mm, m, work, info) chklapackerror(info[]) #Decide what exactly to return if howmny == 'S' #compute selected eigenvectors if side == 'L' #left eigenvectors only return select, VL[:,1:m[]] elseif side == 'R' #right eigenvectors only return select, VR[:,1:m[]] else #side == 'B' #both eigenvectors return select, VL[:,1:m[]], VR[:,1:m[]] end else #compute all eigenvectors if side == 'L' #left eigenvectors only return VL[:,1:m[]] elseif side == 'R' #right eigenvectors only return VR[:,1:m[]] else #side == 'B' #both eigenvectors return VL[:,1:m[]], VR[:,1:m[]] end end end # SUBROUTINE DTRRFS( UPLO, TRANS, DIAG, N, NRHS, A, LDA, B, LDB, X, # LDX, FERR, BERR, WORK, IWORK, INFO ) # .. Scalar Arguments .. # CHARACTER DIAG, TRANS, UPLO # INTEGER INFO, LDA, LDB, LDX, N, NRHS # .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), BERR( * ), FERR( * ), #$ WORK( * ), X( LDX, * ) function trrfs!(uplo::Char, trans::Char, diag::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}, X::StridedVecOrMat{$elty}, Ferr::StridedVector{$elty} = similar(B, $elty, size(B,2)), Berr::StridedVector{$elty} = similar(B, $elty, size(B,2))) chktrans(trans) chkuplo(uplo) chkdiag(diag) n = size(A,2) nrhs = size(B,2) if nrhs != size(X,2) throw(DimensionMismatch("second dimensions of B, $nrhs, and X, $(size(X,2)), must match")) end work = Vector{$elty}(3n) iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() ccall((@blasfunc($trrfs), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &trans, &diag, &n, &nrhs, A, &max(1,stride(A,2)), B, &max(1,stride(B,2)), X, &max(1,stride(X,2)), Ferr, Berr, work, iwork, info) chklapackerror(info[]) Ferr, Berr end end end for (trcon, trevc, trrfs, elty, relty) in ((:ztrcon_,:ztrevc_,:ztrrfs_,:Complex128,:Float64), (:ctrcon_,:ctrevc_,:ctrrfs_,:Complex64, :Float32)) @eval begin # SUBROUTINE ZTRCON( NORM, UPLO, DIAG, N, A, LDA, RCOND, WORK, # RWORK, INFO ) # .. Scalar Arguments .. # CHARACTER DIAG, NORM, UPLO # INTEGER INFO, LDA, N # DOUBLE PRECISION RCOND # .. Array Arguments .. # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function trcon!(norm::Char, uplo::Char, diag::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) chkdiag(diag) rcond = Vector{$relty}(1) work = Vector{$elty}(2n) rwork = Vector{$relty}(n) info = Ref{BlasInt}() ccall((@blasfunc($trcon), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{$relty}, Ptr{BlasInt}), &norm, &uplo, &diag, &n, A, &max(1,stride(A,2)), rcond, work, rwork, info) chklapackerror(info[]) rcond[1] end # SUBROUTINE ZTREVC( SIDE, HOWMNY, SELECT, N, T, LDT, VL, LDVL, VR, # LDVR, MM, M, WORK, RWORK, INFO ) # # .. Scalar Arguments .. # CHARACTER HOWMNY, SIDE # INTEGER INFO, LDT, LDVL, LDVR, M, MM, N # .. # .. Array Arguments .. # LOGICAL SELECT( * ) # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 T( LDT, * ), VL( LDVL, * ), VR( LDVR, * ), #$ WORK( * ) function trevc!(side::Char, howmny::Char, select::StridedVector{BlasInt}, T::StridedMatrix{$elty}, VL::StridedMatrix{$elty} = similar(T), VR::StridedMatrix{$elty} = similar(T)) # Extract n, mm = checksquare(T), size(VL, 2) ldt, ldvl, ldvr = stride(T, 2), stride(VL, 2), stride(VR, 2) # Check chkstride1(T, select) if side ∉ ['L','R','B'] throw(ArgumentError("side argument must be 'L' (left eigenvectors), 'R' (right eigenvectors), or 'B' (both), got $side")) end # Allocate m = Ref{BlasInt}() work = Vector{$elty}(2n) rwork = Vector{$relty}(n) info = Ref{BlasInt}() ccall((@blasfunc($trevc), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$relty}, Ptr{BlasInt}), &side, &howmny, select, &n, T, &ldt, VL, &ldvl, VR, &ldvr, &mm, m, work, rwork, info) chklapackerror(info[]) #Decide what exactly to return if howmny == 'S' #compute selected eigenvectors if side == 'L' #left eigenvectors only return select, VL[:,1:m[]] elseif side == 'R' #right eigenvectors only return select, VR[:,1:m[]] else #side=='B' #both eigenvectors return select, VL[:,1:m[]], VR[:,1:m[]] end else #compute all eigenvectors if side == 'L' #left eigenvectors only return VL[:,1:m[]] elseif side == 'R' #right eigenvectors only return VR[:,1:m[]] else #side=='B' #both eigenvectors return VL[:,1:m[]], VR[:,1:m[]] end end end # SUBROUTINE ZTRRFS( UPLO, TRANS, DIAG, N, NRHS, A, LDA, B, LDB, X, # LDX, FERR, BERR, WORK, IWORK, INFO ) # .. Scalar Arguments .. # CHARACTER DIAG, TRANS, UPLO # INTEGER INFO, LDA, LDB, LDX, N, NRHS # .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), BERR( * ), FERR( * ), #$ WORK( * ), X( LDX, * ) function trrfs!(uplo::Char, trans::Char, diag::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}, X::StridedVecOrMat{$elty}, Ferr::StridedVector{$relty} = similar(B, $relty, size(B,2)), Berr::StridedVector{$relty} = similar(B, $relty, size(B,2))) chktrans(trans) chkuplo(uplo) chkdiag(diag) n = size(A,2) nrhs = size(B,2) if nrhs != size(X,2) throw(DimensionMismatch("second dimensions of B, $nrhs, and X, $(size(X,2)), must match")) end work = Vector{$elty}(2n) rwork = Vector{$relty}(n) info = Ref{BlasInt}() ccall((@blasfunc($trrfs), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{$relty}, Ptr{BlasInt}), &uplo, &trans, &diag, &n, &nrhs, A, &max(1,stride(A,2)), B, &max(1,stride(B,2)), X, &max(1,stride(X,2)), Ferr, Berr, work, rwork, info) chklapackerror(info[]) Ferr, Berr end end end """ trcon!(norm, uplo, diag, A) Finds the reciprocal condition number of (upper if `uplo = U`, lower if `uplo = L`) triangular matrix `A`. If `diag = N`, `A` has non-unit diagonal elements. If `diag = U`, all diagonal elements of `A` are one. If `norm = I`, the condition number is found in the infinity norm. If `norm = O` or `1`, the condition number is found in the one norm. """ trcon!(norm::Char, uplo::Char, diag::Char, A::StridedMatrix) """ trevc!(side, howmny, select, T, VL = similar(T), VR = similar(T)) Finds the eigensystem of an upper triangular matrix `T`. If `side = R`, the right eigenvectors are computed. If `side = L`, the left eigenvectors are computed. If `side = B`, both sets are computed. If `howmny = A`, all eigenvectors are found. If `howmny = B`, all eigenvectors are found and backtransformed using `VL` and `VR`. If `howmny = S`, only the eigenvectors corresponding to the values in `select` are computed. """ trevc!(side::Char, howmny::Char, select::StridedVector{BlasInt}, T::StridedMatrix, VL::StridedMatrix = similar(T), VR::StridedMatrix = similar(T)) """ trrfs!(uplo, trans, diag, A, B, X, Ferr, Berr) -> (Ferr, Berr) Estimates the error in the solution to `A * X = B` (`trans = N`), `A.' * X = B` (`trans = T`), `A' * X = B` (`trans = C`) for `side = L`, or the equivalent equations a right-handed `side = R` `X * A` after computing `X` using `trtrs!`. If `uplo = U`, `A` is upper triangular. If `uplo = L`, `A` is lower triangular. If `diag = N`, `A` has non-unit diagonal elements. If `diag = U`, all diagonal elements of `A` are one. `Ferr` and `Berr` are optional inputs. `Ferr` is the forward error and `Berr` is the backward error, each component-wise. """ trrfs!(uplo::Char, trans::Char, diag::Char, A::StridedMatrix, B::StridedVecOrMat, X::StridedVecOrMat, Ferr::StridedVector, Berr::StridedVector) ## (ST) Symmetric tridiagonal - eigendecomposition for (stev, stebz, stegr, stein, elty) in ((:dstev_,:dstebz_,:dstegr_,:dstein_,:Float64), (:sstev_,:sstebz_,:sstegr_,:sstein_,:Float32) # , (:zstev_,:Complex128) Need to rewrite for ZHEEV, rwork, etc. # , (:cstev_,:Complex64) ) @eval begin function stev!(job::Char, dv::StridedVector{$elty}, ev::StridedVector{$elty}) chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than dv's length, $n)")) end Zmat = similar(dv, $elty, (n, job != 'N' ? n : 0)) work = Vector{$elty}(max(1, 2n-2)) info = Ref{BlasInt}() ccall((@blasfunc($stev), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &job, &n, dv, ev, Zmat, &n, work, info) chklapackerror(info[]) dv, Zmat end #* DSTEBZ computes the eigenvalues of a symmetric tridiagonal #* matrix T. The user may ask for all eigenvalues, all eigenvalues #* in the half-open interval (VL, VU], or the IL-th through IU-th #* eigenvalues. function stebz!(range::Char, order::Char, vl::$elty, vu::$elty, il::Integer, iu::Integer, abstol::Real, dv::StridedVector{$elty}, ev::StridedVector{$elty}) chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than dv's length, $n)")) end m = Ref{BlasInt}() nsplit = Vector{BlasInt}(1) w = similar(dv, $elty, n) tmp = 0.0 iblock = similar(dv, BlasInt,n) isplit = similar(dv, BlasInt,n) work = Vector{$elty}(4*n) iwork = Vector{BlasInt}(3*n) info = Ref{BlasInt}() ccall((@blasfunc($stebz), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &range, &order, &n, &vl, &vu, &il, &iu, &abstol, dv, ev, m, nsplit, w, iblock, isplit, work, iwork, info) chklapackerror(info[]) w[1:m[]], iblock[1:m[]], isplit[1:nsplit[1]] end function stegr!(jobz::Char, range::Char, dv::StridedVector{$elty}, ev::StridedVector{$elty}, vl::Real, vu::Real, il::Integer, iu::Integer) chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than dv's length, $n)")) end eev = [ev; zero($elty)] abstol = Vector{$elty}(1) m = Ref{BlasInt}() w = similar(dv, $elty, n) ldz = jobz == 'N' ? 1 : n Z = similar(dv, $elty, ldz, range == 'I' ? iu-il+1 : n) isuppz = similar(dv, BlasInt, 2*size(Z, 2)) work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(1) liwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($stegr), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &jobz, &range, &n, dv, eev, &vl, &vu, &il, &iu, abstol, m, w, Z, &ldz, isuppz, work, &lwork, iwork, &liwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) liwork = iwork[1] iwork = Vector{BlasInt}(liwork) end end m[] == length(w) ? w : w[1:m[]], m[] == size(Z, 2) ? Z : Z[:,1:m[]] end function stein!(dv::StridedVector{$elty}, ev_in::StridedVector{$elty}, w_in::StridedVector{$elty}, iblock_in::StridedVector{BlasInt}, isplit_in::StridedVector{BlasInt}) chkstride1(dv, ev_in, w_in, iblock_in, isplit_in) n = length(dv) if length(ev_in) != n - 1 throw(DimensionMismatch("ev_in has length $(length(ev_in)) but needs one less than dv's length, $n)")) end ev = [ev_in; zeros($elty,1)] ldz = n #Leading dimension #Number of eigenvalues to find if !(1 <= length(w_in) <= n) throw(DimensionMismatch("w_in has length $(length(w_in)), but needs to be between 1 and $n")) end m = length(w_in) #If iblock and isplit are invalid input, assume worst-case block paritioning, # i.e. set the block scheme to be the entire matrix iblock = similar(dv, BlasInt,n) isplit = similar(dv, BlasInt,n) w = similar(dv, $elty,n) if length(iblock_in) < m #Not enough block specifications iblock[1:m] = ones(BlasInt, m) w[1:m] = sort(w_in) else iblock[1:m] = iblock_in w[1:m] = w_in #Assume user has sorted the eigenvalues properly end if length(isplit_in) < 1 #Not enough block specifications isplit[1] = n else isplit[1:length(isplit_in)] = isplit_in end z = similar(dv, $elty,(n,m)) work = Vector{$elty}(5*n) iwork = Vector{BlasInt}(n) ifail = Vector{BlasInt}(m) info = Ref{BlasInt}() ccall((@blasfunc($stein), liblapack), Void, (Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &n, dv, ev, &m, w, iblock, isplit, z, &ldz, work, iwork, ifail, info) chklapackerror(info[]) if any(ifail .!= 0) # TODO: better error message / type error("failed to converge eigenvectors:\n$(nonzeros(ifail))") end z end end end stegr!(jobz::Char, dv::StridedVector, ev::StridedVector) = stegr!(jobz, 'A', dv, ev, 0.0, 0.0, 0, 0) # Allow user to skip specification of iblock and isplit stein!(dv::StridedVector, ev::StridedVector, w_in::StridedVector)=stein!(dv, ev, w_in, zeros(BlasInt,0), zeros(BlasInt,0)) # Allow user to specify just one eigenvector to get in stein! stein!(dv::StridedVector, ev::StridedVector, eval::Real)=stein!(dv, ev, [eval], zeros(BlasInt,0), zeros(BlasInt,0)) """ stev!(job, dv, ev) -> (dv, Zmat) Computes the eigensystem for a symmetric tridiagonal matrix with `dv` as diagonal and `ev` as off-diagonal. If `job = N` only the eigenvalues are found and returned in `dv`. If `job = V` then the eigenvectors are also found and returned in `Zmat`. """ stev!(job::Char, dv::StridedVector, ev::StridedVector) """ stebz!(range, order, vl, vu, il, iu, abstol, dv, ev) -> (dv, iblock, isplit) Computes the eigenvalues for a symmetric tridiagonal matrix with `dv` as diagonal and `ev` as off-diagonal. If `range = A`, all the eigenvalues are found. If `range = V`, the eigenvalues in the half-open interval `(vl, vu]` are found. If `range = I`, the eigenvalues with indices between `il` and `iu` are found. If `order = B`, eigvalues are ordered within a block. If `order = E`, they are ordered across all the blocks. `abstol` can be set as a tolerance for convergence. """ stebz!(range::Char, order::Char, vl, vu, il::Integer, iu::Integer, abstol::Real, dv::StridedVector, ev::StridedVector) """ stegr!(jobz, range, dv, ev, vl, vu, il, iu) -> (w, Z) Computes the eigenvalues (`jobz = N`) or eigenvalues and eigenvectors (`jobz = V`) for a symmetric tridiagonal matrix with `dv` as diagonal and `ev` as off-diagonal. If `range = A`, all the eigenvalues are found. If `range = V`, the eigenvalues in the half-open interval `(vl, vu]` are found. If `range = I`, the eigenvalues with indices between `il` and `iu` are found. The eigenvalues are returned in `w` and the eigenvectors in `Z`. """ stegr!(jobz::Char, range::Char, dv::StridedVector, ev::StridedVector, vl::Real, vu::Real, il::Integer, iu::Integer) """ stein!(dv, ev_in, w_in, iblock_in, isplit_in) Computes the eigenvectors for a symmetric tridiagonal matrix with `dv` as diagonal and `ev_in` as off-diagonal. `w_in` specifies the input eigenvalues for which to find corresponding eigenvectors. `iblock_in` specifies the submatrices corresponding to the eigenvalues in `w_in`. `isplit_in` specifies the splitting points between the submatrix blocks. """ stein!(dv::StridedVector, ev_in::StridedVector, w_in::StridedVector, iblock_in::StridedVector{BlasInt}, isplit_in::StridedVector{BlasInt}) ## (SY) symmetric real matrices - Bunch-Kaufman decomposition, ## solvers (direct and factored) and inverse. for (syconv, sysv, sytrf, sytri, sytrs, elty) in ((:dsyconv_,:dsysv_,:dsytrf_,:dsytri_,:dsytrs_,:Float64), (:ssyconv_,:ssysv_,:ssytrf_,:ssytri_,:ssytrs_,:Float32)) @eval begin # SUBROUTINE DSYCONV( UPLO, WAY, N, A, LDA, IPIV, WORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO, WAY # INTEGER INFO, LDA, N # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function syconv!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($syconv), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &'C', &n, A, &max(1,stride(A,2)), ipiv, work, info) chklapackerror(info[]) A, work end # SUBROUTINE DSYSV( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK, # LWORK, INFO ) # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, LWORK, N, NRHS # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), WORK( * ) function sysv!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sysv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), work, &lwork, info) chkargsok(info[]) chknonsingular(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end B, A, ipiv end # SUBROUTINE DSYTRF( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function sytrf!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) ipiv = similar(A, BlasInt, n) if n == 0 return A, ipiv, zero(BlasInt) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sytrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, A, &stride(A,2), ipiv, work, &lwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end return A, ipiv, info[] end # SUBROUTINE DSYTRI2( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) # function sytri!(uplo::Char, A::StridedMatrix{$elty}, ipiv::Vector{BlasInt}) # chkstride1(A) # n = checksquare(A) # chkuplo(uplo) # work = Vector{$elty}(1) # lwork = BlasInt(-1) # info = Ref{BlasInt}() # for i in 1:2 # ccall((@blasfunc($sytri), liblapack), Void, # (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, # Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), # &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) # @assertargsok # chknonsingular(info[]) # if lwork < 0 # lwork = BlasInt(real(work[1])) # work = Vector{$elty}(lwork) # end # end # A # end # SUBROUTINE DSYTRI( UPLO, N, A, LDA, IPIV, WORK, INFO ) # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function sytri!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($sytri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, info) chkargsok(info[]) chknonsingular(info[]) A end # SUBROUTINE DSYTRS( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function sytrs!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end # Rook-pivoting variants of symmetric-matrix algorithms for (sysv, sytrf, sytri, sytrs, elty) in ((:dsysv_rook_,:dsytrf_rook_,:dsytri_rook_,:dsytrs_rook_,:Float64), (:ssysv_rook_,:ssytrf_rook_,:ssytri_rook_,:ssytrs_rook_,:Float32)) @eval begin # SUBROUTINE DSYSV_ROOK(UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK, # LWORK, INFO ) # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, LWORK, N, NRHS # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), WORK( * ) function sysv_rook!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sysv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), work, &lwork, info) chkargsok(info[]) chknonsingular(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end B, A, ipiv end # SUBROUTINE DSYTRF_ROOK(UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function sytrf_rook!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) ipiv = similar(A, BlasInt, n) if n == 0 return A, ipiv, zero(BlasInt) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sytrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, A, &stride(A,2), ipiv, work, &lwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end return A, ipiv, info[] end # SUBROUTINE DSYTRI_ROOK( UPLO, N, A, LDA, IPIV, WORK, INFO ) # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function sytri_rook!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($sytri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, info) chkargsok(info[]) chknonsingular(info[]) A end # SUBROUTINE DSYTRS_ROOK( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # # .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) function sytrs_rook!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end ## (SY) hermitian matrices - eigendecomposition, Bunch-Kaufman decomposition, ## solvers (direct and factored) and inverse. for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in ((:zsyconv_,:zhesv_,:zhetrf_,:zhetri_,:zhetrs_,:Complex128, :Float64), (:csyconv_,:chesv_,:chetrf_,:chetri_,:chetrs_,:Complex64, :Float32)) @eval begin # SUBROUTINE ZSYCONV( UPLO, WAY, N, A, LDA, IPIV, WORK, INFO ) # # .. Scalar Arguments .. # CHARACTER UPLO, WAY # INTEGER INFO, LDA, N # .. # .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function syconv!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A,ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($syconv), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &'C', &n, A, &max(1,stride(A,2)), ipiv, work, info) chklapackerror(info[]) A, work end # SUBROUTINE ZHESV( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK, # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, LWORK, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function hesv!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($hesv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end B, A, ipiv end # SUBROUTINE ZHETRF( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function hetrf!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i in 1:2 ccall((@blasfunc($hetrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, ipiv, info[] end # SUBROUTINE ZHETRI2( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) # function hetri!(uplo::Char, A::StridedMatrix{$elty}, ipiv::Vector{BlasInt}) # chkstride1(A) # n = checksquare(A) # chkuplo(uplo) # work = Vector{$elty}(1) # lwork = BlasInt(-1) # info = Ref{BlasInt}() # for i in 1:2 # ccall((@blasfunc($hetri), liblapack), Void, # (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, # Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), # &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) # chklapackerror(info[]) # if lwork < 0 # lwork = BlasInt(real(work[1])) # work = Vector{$elty}(lwork) # end # end # A # end # SUBROUTINE ZHETRI( UPLO, N, A, LDA, IPIV, WORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function hetri!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($hetri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, info) chklapackerror(info[]) A end # SUBROUTINE ZHETRS( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) function hetrs!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($hetrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end for (hesv, hetrf, hetri, hetrs, elty, relty) in ((:zhesv_rook_,:zhetrf_rook_,:zhetri_rook_,:zhetrs_rook_,:Complex128, :Float64), (:chesv_rook_,:chetrf_rook_,:chetri_rook_,:chetrs_rook_,:Complex64, :Float32)) @eval begin # SUBROUTINE ZHESV_ROOK( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK, # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, LWORK, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function hesv_rook!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($hesv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end B, A, ipiv end # SUBROUTINE ZHETRF_ROOK( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function hetrf_rook!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i in 1:2 ccall((@blasfunc($hetrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, ipiv, info[] end # SUBROUTINE ZHETRI_ROOK( UPLO, N, A, LDA, IPIV, WORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function hetri_rook!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A,ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($hetri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, info) chklapackerror(info[]) A end # SUBROUTINE ZHETRS_ROOK( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) function hetrs_rook!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($hetrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end for (sysv, sytrf, sytri, sytrs, elty, relty) in ((:zsysv_,:zsytrf_,:zsytri_,:zsytrs_,:Complex128, :Float64), (:csysv_,:csytrf_,:csytri_,:csytrs_,:Complex64, :Float32)) @eval begin # SUBROUTINE ZSYSV( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK, # $ LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, LWORK, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function sysv!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sysv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), work, &lwork, info) chkargsok(info[]) chknonsingular(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end B, A, ipiv end # SUBROUTINE ZSYTRF( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function sytrf!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) ipiv = similar(A, BlasInt, n) if n == 0 return A, ipiv, zero(BlasInt) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sytrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, ipiv, info[] end # SUBROUTINE ZSYTRI2( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) # function sytri!(uplo::Char, A::StridedMatrix{$elty}, ipiv::Vector{BlasInt}) # chkstride1(A) # n = checksquare(A) # chkuplo(uplo) # work = Vector{$elty}(1) # lwork = BlasInt(-1) # info = Ref{BlasInt}() # for i in 1:2 # ccall((@blasfunc($sytri), liblapack), Void, # (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, # Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), # &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) # chklapackerror(info[]) # if lwork < 0 # lwork = BlasInt(real(work[1])) # work = Vector{$elty}(lwork) # end # end # A # end # SUBROUTINE ZSYTRI( UPLO, N, A, LDA, IPIV, WORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function sytri!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($sytri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, info) chklapackerror(info[]) A end # SUBROUTINE ZSYTRS( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) function sytrs!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end for (sysv, sytrf, sytri, sytrs, elty, relty) in ((:zsysv_rook_,:zsytrf_rook_,:zsytri_rook_,:zsytrs_rook_,:Complex128, :Float64), (:csysv_rook_,:csytrf_rook_,:csytri_rook_,:csytrs_rook_,:Complex64, :Float32)) @eval begin # SUBROUTINE ZSYSV_ROOK(UPLO, N, NRHS, A, LDA, IPIV, B, LDB, WORK, # $ LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, LWORK, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function sysv_rook!(uplo::Char, A::StridedMatrix{$elty}, B::StridedVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sysv), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), work, &lwork, info) chkargsok(info[]) chknonsingular(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end B, A, ipiv end # SUBROUTINE ZSYTRF_ROOK( UPLO, N, A, LDA, IPIV, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function sytrf_rook!(uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) ipiv = similar(A, BlasInt, n) if n == 0 return A, ipiv, zero(BlasInt) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sytrf), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, &lwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, ipiv, info[] end # SUBROUTINE ZSYTRI_ROOK( UPLO, N, A, LDA, IPIV, WORK, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, N # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function sytri_rook!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($sytri), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &uplo, &n, A, &max(1,stride(A,2)), ipiv, work, info) chklapackerror(info[]) A end # SUBROUTINE ZSYTRS_ROOK( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) # * .. Scalar Arguments .. # CHARACTER UPLO # INTEGER INFO, LDA, LDB, N, NRHS # * .. # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) function sytrs_rook!(uplo::Char, A::StridedMatrix{$elty}, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) chkuplo(uplo) if n != size(B,1) throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &n, &size(B,2), A, &max(1,stride(A,2)), ipiv, B, &max(1,stride(B,2)), info) chklapackerror(info[]) B end end end """ syconv!(uplo, A, ipiv) -> (A, work) Converts a symmetric matrix `A` (which has been factorized into a triangular matrix) into two matrices `L` and `D`. If `uplo = U`, `A` is upper triangular. If `uplo = L`, it is lower triangular. `ipiv` is the pivot vector from the triangular factorization. `A` is overwritten by `L` and `D`. """ syconv!(uplo::Char, A::StridedMatrix, ipiv::StridedVector{BlasInt}) """ sysv!(uplo, A, B) -> (B, A, ipiv) Finds the solution to `A * X = B` for symmetric matrix `A`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `B` is overwritten by the solution `X`. `A` is overwritten by its Bunch-Kaufman factorization. `ipiv` contains pivoting information about the factorization. """ sysv!(uplo::Char, A::StridedMatrix, B::StridedVecOrMat) """ sytrf!(uplo, A) -> (A, ipiv, info) Computes the Bunch-Kaufman factorization of a symmetric matrix `A`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. Returns `A`, overwritten by the factorization, a pivot vector `ipiv`, and the error code `info` which is a non-negative integer. If `info` is positive the matrix is singular and the diagonal part of the factorization is exactly zero at position `info`. """ sytrf!(uplo::Char, A::StridedMatrix) """ sytri!(uplo, A, ipiv) Computes the inverse of a symmetric matrix `A` using the results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `A` is overwritten by its inverse. """ sytri!(uplo::Char, A::StridedMatrix, ipiv::StridedVector{BlasInt}) """ sytrs!(uplo, A, ipiv, B) Solves the equation `A * X = B` for a symmetric matrix `A` using the results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `B` is overwritten by the solution `X`. """ sytrs!(uplo::Char, A::StridedMatrix, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat) """ hesv!(uplo, A, B) -> (B, A, ipiv) Finds the solution to `A * X = B` for Hermitian matrix `A`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `B` is overwritten by the solution `X`. `A` is overwritten by its Bunch-Kaufman factorization. `ipiv` contains pivoting information about the factorization. """ hesv!(uplo::Char, A::StridedMatrix, B::StridedVecOrMat) """ hetrf!(uplo, A) -> (A, ipiv, info) Computes the Bunch-Kaufman factorization of a Hermitian matrix `A`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. Returns `A`, overwritten by the factorization, a pivot vector `ipiv`, and the error code `info` which is a non-negative integer. If `info` is positive the matrix is singular and the diagonal part of the factorization is exactly zero at position `info`. """ hetrf!(uplo::Char, A::StridedMatrix) """ hetri!(uplo, A, ipiv) Computes the inverse of a Hermitian matrix `A` using the results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `A` is overwritten by its inverse. """ hetri!(uplo::Char, A::StridedMatrix, ipiv::StridedVector{BlasInt}) """ hetrs!(uplo, A, ipiv, B) Solves the equation `A * X = B` for a Hermitian matrix `A` using the results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `B` is overwritten by the solution `X`. """ hetrs!(uplo::Char, A::StridedMatrix, ipiv::StridedVector{BlasInt}, B::StridedVecOrMat) # Symmetric (real) eigensolvers for (syev, syevr, sygvd, elty) in ((:dsyev_,:dsyevr_,:dsygvd_,:Float64), (:ssyev_,:ssyevr_,:ssygvd_,:Float32)) @eval begin # SUBROUTINE DSYEV( JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBZ, UPLO # INTEGER INFO, LDA, LWORK, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ) function syev!(jobz::Char, uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) W = similar(A, $elty, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($syev), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &jobz, &uplo, &n, A, &max(1,stride(A,2)), W, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end jobz == 'V' ? (W, A) : W end # SUBROUTINE DSYEVR( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, IU, # $ ABSTOL, M, W, Z, LDZ, ISUPPZ, WORK, LWORK, # $ IWORK, LIWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBZ, RANGE, UPLO # INTEGER IL, INFO, IU, LDA, LDZ, LIWORK, LWORK, M, N # DOUBLE PRECISION ABSTOL, VL, VU # * .. # * .. Array Arguments .. # INTEGER ISUPPZ( * ), IWORK( * ) # DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * ) function syevr!(jobz::Char, range::Char, uplo::Char, A::StridedMatrix{$elty}, vl::AbstractFloat, vu::AbstractFloat, il::Integer, iu::Integer, abstol::AbstractFloat) chkstride1(A) n = checksquare(A) if range == 'I' && !(1 <= il <= iu <= n) throw(ArgumentError("illegal choice of eigenvalue indices (il = $il, iu = $iu), which must be between 1 and n = $n")) end if range == 'V' && vl >= vu throw(ArgumentError("lower boundary, $vl, must be less than upper boundary, $vu")) end lda = stride(A,2) m = Ref{BlasInt}() w = similar(A, $elty, n) ldz = n if jobz == 'N' Z = similar(A, $elty, ldz, 0) elseif jobz == 'V' Z = similar(A, $elty, ldz, n) end isuppz = similar(A, BlasInt, 2*n) work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(1) liwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($syevr), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &jobz, &range, &uplo, &n, A, &max(1,lda), &vl, &vu, &il, &iu, &abstol, m, w, Z, &max(1,ldz), isuppz, work, &lwork, iwork, &liwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) liwork = iwork[1] iwork = Vector{BlasInt}(liwork) end end w[1:m[]], Z[:,1:(jobz == 'V' ? m[] : 0)] end syevr!(jobz::Char, A::StridedMatrix{$elty}) = syevr!(jobz, 'A', 'U', A, 0.0, 0.0, 0, 0, -1.0) # Generalized eigenproblem # SUBROUTINE DSYGVD( ITYPE, JOBZ, UPLO, N, A, LDA, B, LDB, W, WORK, # $ LWORK, IWORK, LIWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBZ, UPLO # INTEGER INFO, ITYPE, LDA, LDB, LIWORK, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), W( * ), WORK( * ) function sygvd!(itype::Integer, jobz::Char, uplo::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) w = similar(A, $elty, n) work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(1) liwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sygvd), liblapack), Void, (Ptr{BlasInt}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &itype, &jobz, &uplo, &n, A, &lda, B, &ldb, w, work, &lwork, iwork, &liwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(work[1]) work = Vector{$elty}(lwork) liwork = iwork[1] iwork = Vector{BlasInt}(liwork) end end chkposdef(info[]) w, A, B end end end # Hermitian eigensolvers for (syev, syevr, sygvd, elty, relty) in ((:zheev_,:zheevr_,:zhegvd_,:Complex128,:Float64), (:cheev_,:cheevr_,:chegvd_,:Complex64,:Float32)) @eval begin # SUBROUTINE ZHEEV( JOBZ, UPLO, N, A, LDA, W, WORK, LWORK, RWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBZ, UPLO # INTEGER INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # DOUBLE PRECISION RWORK( * ), W( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function syev!(jobz::Char, uplo::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) W = similar(A, $relty, n) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(max(1, 3n-2)) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($syev), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &jobz, &uplo, &n, A, &stride(A,2), W, work, &lwork, rwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end jobz == 'V' ? (W, A) : W end # SUBROUTINE ZHEEVR( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, IU, # $ ABSTOL, M, W, Z, LDZ, ISUPPZ, WORK, LWORK, # $ RWORK, LRWORK, IWORK, LIWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBZ, RANGE, UPLO # INTEGER IL, INFO, IU, LDA, LDZ, LIWORK, LRWORK, LWORK, # $ M, N # DOUBLE PRECISION ABSTOL, VL, VU # * .. # * .. Array Arguments .. # INTEGER ISUPPZ( * ), IWORK( * ) # DOUBLE PRECISION RWORK( * ), W( * ) # COMPLEX*16 A( LDA, * ), WORK( * ), Z( LDZ, * ) function syevr!(jobz::Char, range::Char, uplo::Char, A::StridedMatrix{$elty}, vl::AbstractFloat, vu::AbstractFloat, il::Integer, iu::Integer, abstol::AbstractFloat) chkstride1(A) n = checksquare(A) if range == 'I' && !(1 <= il <= iu <= n) throw(ArgumentError("illegal choice of eigenvalue indices (il = $il, iu=$iu), which must be between 1 and n = $n")) end if range == 'V' && vl >= vu throw(ArgumentError("lower boundary, $vl, must be less than upper boundary, $vu")) end lda = max(1,stride(A,2)) m = Ref{BlasInt}() w = similar(A, $relty, n) if jobz == 'N' ldz = 1 Z = similar(A, $elty, ldz, 0) elseif jobz == 'V' ldz = n Z = similar(A, $elty, ldz, n) end isuppz = similar(A, BlasInt, 2*n) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(1) lrwork = BlasInt(-1) iwork = Vector{BlasInt}(1) liwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($syevr), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &jobz, &range, &uplo, &n, A, &lda, &vl, &vu, &il, &iu, &abstol, m, w, Z, &ldz, isuppz, work, &lwork, rwork, &lrwork, iwork, &liwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) lrwork = BlasInt(rwork[1]) rwork = Vector{$relty}(lrwork) liwork = iwork[1] iwork = Vector{BlasInt}(liwork) end end w[1:m[]], Z[:,1:(jobz == 'V' ? m[] : 0)] end syevr!(jobz::Char, A::StridedMatrix{$elty}) = syevr!(jobz, 'A', 'U', A, 0.0, 0.0, 0, 0, -1.0) # SUBROUTINE ZHEGVD( ITYPE, JOBZ, UPLO, N, A, LDA, B, LDB, W, WORK, # $ LWORK, RWORK, LRWORK, IWORK, LIWORK, INFO ) # * .. Scalar Arguments .. # CHARACTER JOBZ, UPLO # INTEGER INFO, ITYPE, LDA, LDB, LIWORK, LRWORK, LWORK, N # * .. # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION RWORK( * ), W( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) function sygvd!(itype::Integer, jobz::Char, uplo::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) w = similar(A, $relty, n) work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(1) liwork = BlasInt(-1) rwork = Array{$relty,0}() lrwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($sygvd), liblapack), Void, (Ptr{BlasInt}, Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &itype, &jobz, &uplo, &n, A, &lda, B, &ldb, w, work, &lwork, rwork, &lrwork, iwork, &liwork, info) chkargsok(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) liwork = iwork[1] iwork = Vector{BlasInt}(liwork) lrwork = BlasInt(rwork[1]) rwork = Vector{$relty}(lrwork) end end chkposdef(info[]) w, A, B end end end """ syev!(jobz, uplo, A) Finds the eigenvalues (`jobz = N`) or eigenvalues and eigenvectors (`jobz = V`) of a symmetric matrix `A`. If `uplo = U`, the upper triangle of `A` is used. If `uplo = L`, the lower triangle of `A` is used. """ syev!(jobz::Char, uplo::Char, A::StridedMatrix) """ syevr!(jobz, range, uplo, A, vl, vu, il, iu, abstol) -> (W, Z) Finds the eigenvalues (`jobz = N`) or eigenvalues and eigenvectors (`jobz = V`) of a symmetric matrix `A`. If `uplo = U`, the upper triangle of `A` is used. If `uplo = L`, the lower triangle of `A` is used. If `range = A`, all the eigenvalues are found. If `range = V`, the eigenvalues in the half-open interval `(vl, vu]` are found. If `range = I`, the eigenvalues with indices between `il` and `iu` are found. `abstol` can be set as a tolerance for convergence. The eigenvalues are returned in `W` and the eigenvectors in `Z`. """ syevr!(jobz::Char, range::Char, uplo::Char, A::StridedMatrix, vl::AbstractFloat, vu::AbstractFloat, il::Integer, iu::Integer, abstol::AbstractFloat) """ sygvd!(itype, jobz, uplo, A, B) -> (w, A, B) Finds the generalized eigenvalues (`jobz = N`) or eigenvalues and eigenvectors (`jobz = V`) of a symmetric matrix `A` and symmetric positive-definite matrix `B`. If `uplo = U`, the upper triangles of `A` and `B` are used. If `uplo = L`, the lower triangles of `A` and `B` are used. If `itype = 1`, the problem to solve is `A * x = lambda * B * x`. If `itype = 2`, the problem to solve is `A * B * x = lambda * x`. If `itype = 3`, the problem to solve is `B * A * x = lambda * x`. """ sygvd!(itype::Integer, jobz::Char, uplo::Char, A::StridedMatrix, B::StridedMatrix) ## (BD) Bidiagonal matrices - singular value decomposition for (bdsqr, relty, elty) in ((:dbdsqr_,:Float64,:Float64), (:sbdsqr_,:Float32,:Float32), (:zbdsqr_,:Float64,:Complex128), (:cbdsqr_,:Float32,:Complex64)) @eval begin function bdsqr!(uplo::Char, d::StridedVector{$relty}, e_::StridedVector{$relty}, Vt::StridedMatrix{$elty}, U::StridedMatrix{$elty}, C::StridedMatrix{$elty}) chkstride1(d, e_) # Extract number n = length(d) ncvt, nru, ncc = size(Vt, 2), size(U, 1), size(C, 2) ldvt, ldu, ldc = max(1, stride(Vt,2)), max(1, stride(U, 2)), max(1, stride(C,2)) # Do checks chkuplo(uplo) if length(e_) != n - 1 throw(DimensionMismatch("off-diagonal has length $(length(e_)) but should have length $(n - 1)")) end if ncvt > 0 && ldvt < n throw(DimensionMismatch("leading dimension of Vt, $ldvt, must be at least $n")) end if ldu < nru throw(DimensionMismatch("leading dimension of U, $ldu, must be at least $nru")) end if size(U, 2) != n throw(DimensionMismatch("U must have $n columns but has $(size(U, 2))")) end if ncc > 0 && ldc < n throw(DimensionMismatch("leading dimension of C, $ldc, must be at least $n")) end # Allocate work = Vector{$relty}(4n) info = Ref{BlasInt}() ccall((@blasfunc($bdsqr), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &uplo, &n, &ncvt, &nru, &ncc, d, e_, Vt, &ldvt, U, &ldu, C, &ldc, work, info) chklapackerror(info[]) d, Vt, U, C #singular values in descending order, P**T * VT, U * Q, Q**T * C end end end """ bdsqr!(uplo, d, e_, Vt, U, C) -> (d, Vt, U, C) Computes the singular value decomposition of a bidiagonal matrix with `d` on the diagonal and `e_` on the off-diagonal. If `uplo = U`, `e_` is the superdiagonal. If `uplo = L`, `e_` is the subdiagonal. Can optionally also compute the product `Q' * C`. Returns the singular values in `d`, and the matrix `C` overwritten with `Q' * C`. """ bdsqr!(uplo::Char, d::StridedVector, e_::StridedVector, Vt::StridedMatrix, U::StridedMatrix, C::StridedMatrix) #Defined only for real types for (bdsdc, elty) in ((:dbdsdc_,:Float64), (:sbdsdc_,:Float32)) @eval begin #* DBDSDC computes the singular value decomposition (SVD) of a real #* N-by-N (upper or lower) bidiagonal matrix B: B = U * S * VT, #* using a divide and conquer method #* .. Scalar Arguments .. # CHARACTER COMPQ, UPLO # INTEGER INFO, LDU, LDVT, N #* .. #* .. Array Arguments .. # INTEGER IQ( * ), IWORK( * ) # DOUBLE PRECISION D( * ), E( * ), Q( * ), U( LDU, * ), # $ VT( LDVT, * ), WORK( * ) function bdsdc!(uplo::Char, compq::Char, d::StridedVector{$elty}, e_::StridedVector{$elty}) chkstride1(d, e_) n, ldiq, ldq, ldu, ldvt = length(d), 1, 1, 1, 1 chkuplo(uplo) if compq == 'N' lwork = 6*n elseif compq == 'P' warn("COMPQ='P' is not tested") #TODO turn this into an actual LAPACK call #smlsiz=ilaenv(9, $elty==:Float64 ? 'dbdsqr' : 'sbdsqr', string(uplo, compq), n,n,n,n) smlsiz=100 #For now, completely overkill ldq = n*(11+2*smlsiz+8*round(Int,log((n/(smlsiz+1)))/log(2))) ldiq = n*(3+3*round(Int,log(n/(smlsiz+1))/log(2))) lwork = 6*n elseif compq == 'I' ldvt=ldu=max(1, n) lwork=3*n^2 + 4*n else throw(ArgumentError("COMPQ argument must be 'N', 'P' or 'I', got $(repr(compq))")) end u = similar(d, $elty, (ldu, n)) vt = similar(d, $elty, (ldvt, n)) q = similar(d, $elty, ldq) iq = similar(d, BlasInt, ldiq) work = Vector{$elty}(lwork) iwork = Vector{BlasInt}(8n) info = Ref{BlasInt}() ccall((@blasfunc($bdsdc), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &compq, &n, d, e_, u, &ldu, vt, &ldvt, q, iq, work, iwork, info) chklapackerror(info[]) d, e, u, vt, q, iq end end end """ bdsdc!(uplo, compq, d, e_) -> (d, e, u, vt, q, iq) Computes the singular value decomposition of a bidiagonal matrix with `d` on the diagonal and `e_` on the off-diagonal using a divide and conqueq method. If `uplo = U`, `e_` is the superdiagonal. If `uplo = L`, `e_` is the subdiagonal. If `compq = N`, only the singular values are found. If `compq = I`, the singular values and vectors are found. If `compq = P`, the singular values and vectors are found in compact form. Only works for real types. Returns the singular values in `d`, and if `compq = P`, the compact singular vectors in `iq`. """ bdsdc!(uplo::Char, compq::Char, d::StridedVector, e_::StridedVector) for (gecon, elty) in ((:dgecon_,:Float64), (:sgecon_,:Float32)) @eval begin # SUBROUTINE DGECON( NORM, N, A, LDA, ANORM, RCOND, WORK, IWORK, # $ INFO ) # * .. Scalar Arguments .. # CHARACTER NORM # INTEGER INFO, LDA, N # DOUBLE PRECISION ANORM, RCOND # * .. # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) function gecon!(normtype::Char, A::StridedMatrix{$elty}, anorm::$elty) chkstride1(A) n = checksquare(A) lda = max(1, stride(A, 2)) rcond = Vector{$elty}(1) work = Vector{$elty}(4n) iwork = Vector{BlasInt}(n) info = Ref{BlasInt}() ccall((@blasfunc($gecon), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &normtype, &n, A, &lda, &anorm, rcond, work, iwork, info) chklapackerror(info[]) rcond[1] end end end for (gecon, elty, relty) in ((:zgecon_,:Complex128,:Float64), (:cgecon_,:Complex64, :Float32)) @eval begin # SUBROUTINE ZGECON( NORM, N, A, LDA, ANORM, RCOND, WORK, RWORK, # $ INFO ) # * .. Scalar Arguments .. # CHARACTER NORM # INTEGER INFO, LDA, N # DOUBLE PRECISION ANORM, RCOND # * .. # * .. Array Arguments .. # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) function gecon!(normtype::Char, A::StridedMatrix{$elty}, anorm::$relty) chkstride1(A) n = checksquare(A) lda = max(1, stride(A, 2)) rcond = Vector{$relty}(1) work = Vector{$elty}(2n) rwork = Vector{$relty}(2n) info = Ref{BlasInt}() ccall((@blasfunc($gecon), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{$relty}, Ptr{$elty}, Ptr{$relty}, Ptr{BlasInt}), &normtype, &n, A, &lda, &anorm, rcond, work, rwork, info) chklapackerror(info[]) rcond[1] end end end """ gecon!(normtype, A, anorm) Finds the reciprocal condition number of matrix `A`. If `normtype = I`, the condition number is found in the infinity norm. If `normtype = O` or `1`, the condition number is found in the one norm. `A` must be the result of `getrf!` and `anorm` is the norm of `A` in the relevant norm. """ gecon!(normtype::Char, A::StridedMatrix, anorm) for (gehrd, elty) in ((:dgehrd_,:Float64), (:sgehrd_,:Float32), (:zgehrd_,:Complex128), (:cgehrd_,:Complex64)) @eval begin # .. Scalar Arguments .. # INTEGER IHI, ILO, INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function gehrd!(ilo::Integer, ihi::Integer, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs tau = similar(A, $elty, max(0,n - 1)) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gehrd), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, &ilo, &ihi, A, &max(1, stride(A, 2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, tau end end end gehrd!(A::StridedMatrix) = gehrd!(1, size(A, 1), A) """ gehrd!(ilo, ihi, A) -> (A, tau) Converts a matrix `A` to Hessenberg form. If `A` is balanced with `gebal!` then `ilo` and `ihi` are the outputs of `gebal!`. Otherwise they should be `ilo = 1` and `ihi = size(A,2)`. `tau` contains the elementary reflectors of the factorization. """ gehrd!(ilo::Integer, ihi::Integer, A::StridedMatrix) for (orghr, elty) in ((:dorghr_,:Float64), (:sorghr_,:Float32), (:zunghr_,:Complex128), (:cunghr_,:Complex64)) @eval begin # * .. Scalar Arguments .. # INTEGER IHI, ILO, INFO, LDA, LWORK, N # * .. # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) function orghr!(ilo::Integer, ihi::Integer, A::StridedMatrix{$elty}, tau::StridedVector{$elty}) chkstride1(A, tau) n = checksquare(A) if n - length(tau) != 1 throw(DimensionMismatch("tau has length $(length(tau)), needs $(n - 1)")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($orghr), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &n, &ilo, &ihi, A, &max(1, stride(A, 2)), tau, work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A end end end """ orghr!(ilo, ihi, A, tau) Explicitly finds `Q`, the orthogonal/unitary matrix from `gehrd!`. `ilo`, `ihi`, `A`, and `tau` must correspond to the input/output to `gehrd!`. """ orghr!(ilo::Integer, ihi::Integer, A::StridedMatrix, tau::StridedVector) for (ormhr, elty) in ((:dormhr_,:Float64), (:sormhr_,:Float32), (:zunmhr_,:Complex128), (:cunmhr_,:Complex64)) @eval begin # .. Scalar Arguments .. # CHARACTER side, trans # INTEGER ihi, ilo, info, lda, ldc, lwork, m, n # .. # .. Array Arguments .. # DOUBLE PRECISION a( lda, * ), c( ldc, * ), tau( * ), work( * ) function ormhr!(side::Char, trans::Char, ilo::Integer, ihi::Integer, A::StridedMatrix{$elty}, tau::StridedVector{$elty}, C::StridedVecOrMat{$elty}) chkstride1(A, tau) n = checksquare(A) mC, nC = size(C, 1), size(C, 2) if n - length(tau) != 1 throw(DimensionMismatch("tau has length $(length(tau)), needs $(n - 1)")) end if (side == 'L' && mC != n) || (side == 'R' && nC != n) throw(DimensionMismatch("A and C matrices are not conformable")) end work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($ormhr), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &side, &trans, &mC, &nC, &ilo, &ihi, A, &max(1, stride(A, 2)), tau, C, &max(1, stride(C, 2)), work, &lwork, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end C end end end for (gees, gges, elty) in ((:dgees_,:dgges_,:Float64), (:sgees_,:sgges_,:Float32)) @eval begin # .. Scalar Arguments .. # CHARACTER JOBVS, SORT # INTEGER INFO, LDA, LDVS, LWORK, N, SDIM # .. # .. Array Arguments .. # LOGICAL BWORK( * ) # DOUBLE PRECISION A( LDA, * ), VS( LDVS, * ), WI( * ), WORK( * ), # $ WR( * ) function gees!(jobvs::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) sdim = Vector{BlasInt}(1) wr = similar(A, $elty, n) wi = similar(A, $elty, n) vs = similar(A, $elty, jobvs == 'V' ? n : 0, n) ldvs = max(size(vs, 1), 1) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gees), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{Void}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{Void}, Ptr{BlasInt}), &jobvs, &'N', C_NULL, &n, A, &max(1, stride(A, 2)), sdim, wr, wi, vs, &ldvs, work, &lwork, C_NULL, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, vs, iszero(wi) ? wr : complex.(wr, wi) end # * .. Scalar Arguments .. # CHARACTER JOBVSL, JOBVSR, SORT # INTEGER INFO, LDA, LDB, LDVSL, LDVSR, LWORK, N, SDIM # * .. # * .. Array Arguments .. # LOGICAL BWORK( * ) # DOUBLE PRECISION A( LDA, * ), ALPHAI( * ), ALPHAR( * ), # $ B( LDB, * ), BETA( * ), VSL( LDVSL, * ), # $ VSR( LDVSR, * ), WORK( * ) function gges!(jobvsl::Char, jobvsr::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) end sdim = BlasInt(0) alphar = similar(A, $elty, n) alphai = similar(A, $elty, n) beta = similar(A, $elty, n) ldvsl = jobvsl == 'V' ? n : 1 vsl = similar(A, $elty, ldvsl, n) ldvsr = jobvsr == 'V' ? n : 1 vsr = similar(A, $elty, ldvsr, n) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gges), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{Void}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{Void}, Ptr{BlasInt}), &jobvsl, &jobvsr, &'N', C_NULL, &n, A, &max(1,stride(A, 2)), B, &max(1,stride(B, 2)), &sdim, alphar, alphai, beta, vsl, &ldvsl, vsr, &ldvsr, work, &lwork, C_NULL, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, B, complex.(alphar, alphai), beta, vsl[1:(jobvsl == 'V' ? n : 0),:], vsr[1:(jobvsr == 'V' ? n : 0),:] end end end for (gees, gges, elty, relty) in ((:zgees_,:zgges_,:Complex128,:Float64), (:cgees_,:cgges_,:Complex64,:Float32)) @eval begin # * .. Scalar Arguments .. # CHARACTER JOBVS, SORT # INTEGER INFO, LDA, LDVS, LWORK, N, SDIM # * .. # * .. Array Arguments .. # LOGICAL BWORK( * ) # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), VS( LDVS, * ), W( * ), WORK( * ) function gees!(jobvs::Char, A::StridedMatrix{$elty}) chkstride1(A) n = checksquare(A) sort = 'N' sdim = BlasInt(0) w = similar(A, $elty, n) vs = similar(A, $elty, jobvs == 'V' ? n : 1, n) ldvs = max(size(vs, 1), 1) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gees), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{Void}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{Void}, Ptr{BlasInt}), &jobvs, &sort, C_NULL, &n, A, &max(1, stride(A, 2)), &sdim, w, vs, &ldvs, work, &lwork, rwork, C_NULL, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, vs, w end # * .. Scalar Arguments .. # CHARACTER JOBVSL, JOBVSR, SORT # INTEGER INFO, LDA, LDB, LDVSL, LDVSR, LWORK, N, SDIM # * .. # * .. Array Arguments .. # LOGICAL BWORK( * ) # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), ALPHA( * ), B( LDB, * ), # $ BETA( * ), VSL( LDVSL, * ), VSR( LDVSR, * ), # $ WORK( * ) function gges!(jobvsl::Char, jobvsr::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) end sdim = BlasInt(0) alpha = similar(A, $elty, n) beta = similar(A, $elty, n) ldvsl = jobvsl == 'V' ? n : 1 vsl = similar(A, $elty, ldvsl, n) ldvsr = jobvsr == 'V' ? n : 1 vsr = similar(A, $elty, ldvsr, n) work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(8n) info = Ref{BlasInt}() for i = 1:2 ccall((@blasfunc($gges), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{UInt8}, Ptr{Void}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{Void}, Ptr{BlasInt}), &jobvsl, &jobvsr, &'N', C_NULL, &n, A, &max(1, stride(A, 2)), B, &max(1, stride(B, 2)), &sdim, alpha, beta, vsl, &ldvsl, vsr, &ldvsr, work, &lwork, rwork, C_NULL, info) chklapackerror(info[]) if i == 1 lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end A, B, alpha, beta, vsl[1:(jobvsl == 'V' ? n : 0),:], vsr[1:(jobvsr == 'V' ? n : 0),:] end end end """ gees!(jobvs, A) -> (A, vs, w) Computes the eigenvalues (`jobvs = N`) or the eigenvalues and Schur vectors (`jobvs = V`) of matrix `A`. `A` is overwritten by its Schur form. Returns `A`, `vs` containing the Schur vectors, and `w`, containing the eigenvalues. """ gees!(jobvs::Char, A::StridedMatrix) """ gges!(jobvsl, jobvsr, A, B) -> (A, B, alpha, beta, vsl, vsr) Computes the generalized eigenvalues, generalized Schur form, left Schur vectors (`jobsvl = V`), or right Schur vectors (`jobvsr = V`) of `A` and `B`. The generalized eigenvalues are returned in `alpha` and `beta`. The left Schur vectors are returned in `vsl` and the right Schur vectors are returned in `vsr`. """ gges!(jobvsl::Char, jobvsr::Char, A::StridedMatrix, B::StridedMatrix) for (trexc, trsen, tgsen, elty) in ((:dtrexc_, :dtrsen_, :dtgsen_, :Float64), (:strexc_, :strsen_, :stgsen_, :Float32)) @eval begin # * .. Scalar Arguments .. # CHARACTER COMPQ # INTEGER IFST, ILST, INFO, LDQ, LDT, N # * .. # * .. Array Arguments .. # DOUBLE PRECISION Q( LDQ, * ), T( LDT, * ), WORK( * ) function trexc!(compq::Char, ifst::BlasInt, ilst::BlasInt, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) chkstride1(T, Q) n = checksquare(T) ldt = max(1, stride(T, 2)) ldq = max(1, stride(Q, 2)) work = Vector{$elty}(n) info = Ref{BlasInt}() ccall((@blasfunc($trexc), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}), &compq, &n, T, &ldt, Q, &ldq, &ifst, &ilst, work, info) chklapackerror(info[]) T, Q end trexc!(ifst::BlasInt, ilst::BlasInt, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) = trexc!('V', ifst, ilst, T, Q) # * .. Scalar Arguments .. # CHARACTER COMPQ, JOB # INTEGER INFO, LDQ, LDT, LIWORK, LWORK, M, N # DOUBLE PRECISION S, SEP # * .. # * .. Array Arguments .. # LOGICAL SELECT( * ) # INTEGER IWORK( * ) # DOUBLE PRECISION Q( LDQ, * ), T( LDT, * ), WI( * ), WORK( * ), WR( * ) function trsen!(compq::Char, job::Char, select::StridedVector{BlasInt}, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) chkstride1(T, Q, select) n = checksquare(T) ldt = max(1, stride(T, 2)) ldq = max(1, stride(Q, 2)) wr = similar(T, $elty, n) wi = similar(T, $elty, n) m = sum(select) work = Vector{$elty}(1) lwork = BlasInt(-1) iwork = Vector{BlasInt}(1) liwork = BlasInt(-1) info = Ref{BlasInt}() select = convert(Array{BlasInt}, select) for i = 1:2 ccall((@blasfunc($trsen), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{Void}, Ptr{Void}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &compq, &job, select, &n, T, &ldt, Q, &ldq, wr, wi, &m, C_NULL, C_NULL, work, &lwork, iwork, &liwork, info) chklapackerror(info[]) if i == 1 # only estimated optimal lwork, liwork lwork = BlasInt(real(work[1])) liwork = BlasInt(real(iwork[1])) work = Vector{$elty}(lwork) iwork = Vector{BlasInt}(liwork) end end T, Q, iszero(wi) ? wr : complex.(wr, wi) end trsen!(select::StridedVector{BlasInt}, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) = trsen!('N', 'V', select, T, Q) # .. Scalar Arguments .. # LOGICAL WANTQ, WANTZ # INTEGER IJOB, INFO, LDA, LDB, LDQ, LDZ, LIWORK, LWORK, # $ M, N # DOUBLE PRECISION PL, PR # .. # .. Array Arguments .. # LOGICAL SELECT( * ) # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), ALPHAI( * ), ALPHAR( * ), # $ B( LDB, * ), BETA( * ), DIF( * ), Q( LDQ, * ), # $ WORK( * ), Z( LDZ, * ) # .. function tgsen!(select::StridedVector{BlasInt}, S::StridedMatrix{$elty}, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}, Z::StridedMatrix{$elty}) chkstride1(select, S, T, Q, Z) n, nt, nq, nz = checksquare(S, T, Q, Z) if n != nt throw(DimensionMismatch("dimensions of S, ($n,$n), and T, ($nt,$nt), must match")) end if n != nq throw(DimensionMismatch("dimensions of S, ($n,$n), and Q, ($nq,$nq), must match")) end if n != nz throw(DimensionMismatch("dimensions of S, ($n,$n), and Z, ($nz,$nz), must match")) end lds = max(1, stride(S, 2)) ldt = max(1, stride(T, 2)) ldq = max(1, stride(Q, 2)) ldz = max(1, stride(Z, 2)) m = sum(select) alphai = similar(T, $elty, n) alphar = similar(T, $elty, n) beta = similar(T, $elty, n) lwork = BlasInt(-1) work = Vector{$elty}(1) liwork = BlasInt(-1) iwork = Vector{BlasInt}(1) info = Ref{BlasInt}() select = convert(Array{BlasInt}, select) for i = 1:2 ccall((@blasfunc($tgsen), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{Void}, Ptr{Void}, Ptr{Void}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &0, &1, &1, select, &n, S, &lds, T, &ldt, alphar, alphai, beta, Q, &ldq, Z, &ldz, &m, C_NULL, C_NULL, C_NULL, work, &lwork, iwork, &liwork, info) chklapackerror(info[]) if i == 1 # only estimated optimal lwork, liwork lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) liwork = BlasInt(real(iwork[1])) iwork = Vector{BlasInt}(liwork) end end S, T, complex.(alphar, alphai), beta, Q, Z end end end for (trexc, trsen, tgsen, elty) in ((:ztrexc_, :ztrsen_, :ztgsen_, :Complex128), (:ctrexc_, :ctrsen_, :ctgsen_, :Complex64)) @eval begin # .. Scalar Arguments .. # CHARACTER COMPQ # INTEGER IFST, ILST, INFO, LDQ, LDT, N # .. # .. Array Arguments .. # DOUBLE PRECISION Q( LDQ, * ), T( LDT, * ), WORK( * ) function trexc!(compq::Char, ifst::BlasInt, ilst::BlasInt, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) chkstride1(T, Q) n = checksquare(T) ldt = max(1, stride(T, 2)) ldq = max(1, stride(Q, 2)) info = Ref{BlasInt}() ccall((@blasfunc($trexc), liblapack), Void, (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &compq, &n, T, &ldt, Q, &ldq, &ifst, &ilst, info) chklapackerror(info[]) T, Q end trexc!(ifst::BlasInt, ilst::BlasInt, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) = trexc!('V', ifst, ilst, T, Q) # .. Scalar Arguments .. # CHARACTER COMPQ, JOB # INTEGER INFO, LDQ, LDT, LWORK, M, N # DOUBLE PRECISION S, SEP # .. # .. Array Arguments .. # LOGICAL SELECT( * ) # COMPLEX Q( LDQ, * ), T( LDT, * ), W( * ), WORK( * ) function trsen!(compq::Char, job::Char, select::StridedVector{BlasInt}, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) chkstride1(select, T, Q) n = checksquare(T) ldt = max(1, stride(T, 2)) ldq = max(1, stride(Q, 2)) w = similar(T, $elty, n) m = sum(select) work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() select = convert(Array{BlasInt}, select) for i = 1:2 ccall((@blasfunc($trsen), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{Void}, Ptr{Void}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &compq, &job, select, &n, T, &ldt, Q, &ldq, w, &m, C_NULL, C_NULL, work, &lwork, info) chklapackerror(info[]) if i == 1 # only estimated optimal lwork, liwork lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) end end T, Q, w end trsen!(select::StridedVector{BlasInt}, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}) = trsen!('N', 'V', select, T, Q) # .. Scalar Arguments .. # LOGICAL WANTQ, WANTZ # INTEGER IJOB, INFO, LDA, LDB, LDQ, LDZ, LIWORK, LWORK, # $ M, N # DOUBLE PRECISION PL, PR # .. # .. Array Arguments .. # LOGICAL SELECT( * ) # INTEGER IWORK( * ) # DOUBLE PRECISION DIF( * ) # COMPLEX*16 A( LDA, * ), ALPHA( * ), B( LDB, * ), # $ BETA( * ), Q( LDQ, * ), WORK( * ), Z( LDZ, * ) # .. function tgsen!(select::StridedVector{BlasInt}, S::StridedMatrix{$elty}, T::StridedMatrix{$elty}, Q::StridedMatrix{$elty}, Z::StridedMatrix{$elty}) chkstride1(select, S, T, Q, Z) n, nt, nq, nz = checksquare(S, T, Q, Z) if n != nt throw(DimensionMismatch("dimensions of S, ($n,$n), and T, ($nt,$nt), must match")) end if n != nq throw(DimensionMismatch("dimensions of S, ($n,$n), and Q, ($nq,$nq), must match")) end if n != nz throw(DimensionMismatch("dimensions of S, ($n,$n), and Z, ($nz,$nz), must match")) end lds = max(1, stride(S, 2)) ldt = max(1, stride(T, 2)) ldq = max(1, stride(Q, 2)) ldz = max(1, stride(Z, 2)) m = sum(select) alpha = similar(T, $elty, n) beta = similar(T, $elty, n) lwork = BlasInt(-1) work = Vector{$elty}(1) liwork = BlasInt(-1) iwork = Vector{BlasInt}(1) info = Ref{BlasInt}() select = convert(Array{BlasInt}, select) for i = 1:2 ccall((@blasfunc($tgsen), liblapack), Void, (Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{$elty}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{Void}, Ptr{Void}, Ptr{Void}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}), &0, &1, &1, select, &n, S, &lds, T, &ldt, alpha, beta, Q, &ldq, Z, &ldz, &m, C_NULL, C_NULL, C_NULL, work, &lwork, iwork, &liwork, info) chklapackerror(info[]) if i == 1 # only estimated optimal lwork, liwork lwork = BlasInt(real(work[1])) work = Vector{$elty}(lwork) liwork = BlasInt(real(iwork[1])) iwork = Vector{BlasInt}(liwork) end end S, T, alpha, beta, Q, Z end end end """ trexc!(compq, ifst, ilst, T, Q) -> (T, Q) Reorder the Schur factorization of a matrix. If `compq = V`, the Schur vectors `Q` are reordered. If `compq = N` they are not modified. `ifst` and `ilst` specify the reordering of the vectors. """ trexc!(compq::Char, ifst::BlasInt, ilst::BlasInt, T::StridedMatrix, Q::StridedMatrix) """ trsen!(compq, job, select, T, Q) -> (T, Q, w) Reorder the Schur factorization of a matrix and optionally finds reciprocal condition numbers. If `job = N`, no condition numbers are found. If `job = E`, only the condition number for this cluster of eigenvalues is found. If `job = V`, only the condition number for the invariant subspace is found. If `job = B` then the condition numbers for the cluster and subspace are found. If `compq = V` the Schur vectors `Q` are updated. If `compq = N` the Schur vectors are not modified. `select` determines which eigenvalues are in the cluster. Returns `T`, `Q`, and reordered eigenvalues in `w`. """ trsen!(compq::Char, job::Char, select::StridedVector{BlasInt}, T::StridedMatrix, Q::StridedMatrix) """ tgsen!(select, S, T, Q, Z) -> (S, T, alpha, beta, Q, Z) Reorders the vectors of a generalized Schur decomposition. `select` specifices the eigenvalues in each cluster. """ tgsen!(select::StridedVector{BlasInt}, S::StridedMatrix, T::StridedMatrix, Q::StridedMatrix, Z::StridedMatrix) for (fn, elty, relty) in ((:dtrsyl_, :Float64, :Float64), (:strsyl_, :Float32, :Float32), (:ztrsyl_, :Complex128, :Float64), (:ctrsyl_, :Complex64, :Float32)) @eval begin function trsyl!(transa::Char, transb::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}, C::StridedMatrix{$elty}, isgn::Int=1) chkstride1(A, B, C) m, n = checksquare(A, B) lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) m1, n1 = size(C) if m != m1 || n != n1 throw(DimensionMismatch("dimensions of A, ($m,$n), and C, ($m1,$n1), must match")) end ldc = max(1, stride(C, 2)) scale = Vector{$relty}(1) info = Ref{BlasInt}() ccall((@blasfunc($fn), liblapack), Void, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{$relty}, Ptr{BlasInt}), &transa, &transb, &isgn, &m, &n, A, &lda, B, &ldb, C, &ldc, scale, info) chklapackerror(info[]) C, scale[1] end end end """ trsyl!(transa, transb, A, B, C, isgn=1) -> (C, scale) Solves the Sylvester matrix equation `A * X +/- X * B = scale*C` where `A` and `B` are both quasi-upper triangular. If `transa = N`, `A` is not modified. If `transa = T`, `A` is transposed. If `transa = C`, `A` is conjugate transposed. Similarly for `transb` and `B`. If `isgn = 1`, the equation `A * X + X * B = scale * C` is solved. If `isgn = -1`, the equation `A * X - X * B = scale * C` is solved. Returns `X` (overwriting `C`) and `scale`. """ trsyl!(transa::Char, transb::Char, A::StridedMatrix, B::StridedMatrix, C::StridedMatrix, isgn::Int=1) end # module