+++ /dev/null
-// Copyright ©2016 The Gonum Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gonum
-
-import (
- "math"
-
- "gonum.org/v1/gonum/blas"
- "gonum.org/v1/gonum/blas/blas64"
- "gonum.org/v1/gonum/lapack"
-)
-
-// Dsyev computes all eigenvalues and, optionally, the eigenvectors of a real
-// symmetric matrix A.
-//
-// w contains the eigenvalues in ascending order upon return. w must have length
-// at least n, and Dsyev will panic otherwise.
-//
-// On entry, a contains the elements of the symmetric matrix A in the triangular
-// portion specified by uplo. If jobz == lapack.ComputeEV a contains the
-// orthonormal eigenvectors of A on exit, otherwise on exit the specified
-// triangular region is overwritten.
-//
-// work is temporary storage, and lwork specifies the usable memory length. At minimum,
-// lwork >= 3*n-1, and Dsyev will panic otherwise. The amount of blocking is
-// limited by the usable length. If lwork == -1, instead of computing Dsyev the
-// optimal work length is stored into work[0].
-func (impl Implementation) Dsyev(jobz lapack.EVJob, uplo blas.Uplo, n int, a []float64, lda int, w, work []float64, lwork int) (ok bool) {
- checkMatrix(n, n, a, lda)
- upper := uplo == blas.Upper
- wantz := jobz == lapack.ComputeEV
- var opts string
- if upper {
- opts = "U"
- } else {
- opts = "L"
- }
- nb := impl.Ilaenv(1, "DSYTRD", opts, n, -1, -1, -1)
- lworkopt := max(1, (nb+2)*n)
- work[0] = float64(lworkopt)
- if lwork == -1 {
- return
- }
- if len(work) < lwork {
- panic(badWork)
- }
- if lwork < 3*n-1 {
- panic(badWork)
- }
- if n == 0 {
- return true
- }
- if n == 1 {
- w[0] = a[0]
- work[0] = 2
- if wantz {
- a[0] = 1
- }
- return true
- }
- safmin := dlamchS
- eps := dlamchP
- smlnum := safmin / eps
- bignum := 1 / smlnum
- rmin := math.Sqrt(smlnum)
- rmax := math.Sqrt(bignum)
-
- // Scale matrix to allowable range, if necessary.
- anrm := impl.Dlansy(lapack.MaxAbs, uplo, n, a, lda, work)
- scaled := false
- var sigma float64
- if anrm > 0 && anrm < rmin {
- scaled = true
- sigma = rmin / anrm
- } else if anrm > rmax {
- scaled = true
- sigma = rmax / anrm
- }
- if scaled {
- kind := lapack.LowerTri
- if upper {
- kind = lapack.UpperTri
- }
- impl.Dlascl(kind, 0, 0, 1, sigma, n, n, a, lda)
- }
- var inde int
- indtau := inde + n
- indwork := indtau + n
- llwork := lwork - indwork
- impl.Dsytrd(uplo, n, a, lda, w, work[inde:], work[indtau:], work[indwork:], llwork)
-
- // For eigenvalues only, call Dsterf. For eigenvectors, first call Dorgtr
- // to generate the orthogonal matrix, then call Dsteqr.
- if !wantz {
- ok = impl.Dsterf(n, w, work[inde:])
- } else {
- impl.Dorgtr(uplo, n, a, lda, work[indtau:], work[indwork:], llwork)
- ok = impl.Dsteqr(lapack.EVComp(jobz), n, w, work[inde:], a, lda, work[indtau:])
- }
- if !ok {
- return false
- }
-
- // If the matrix was scaled, then rescale eigenvalues appropriately.
- if scaled {
- bi := blas64.Implementation()
- bi.Dscal(n, 1/sigma, w, 1)
- }
- work[0] = float64(lworkopt)
- return true
-}