1 // Copyright ©2013 The Gonum Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
8 "gonum.org/v1/gonum/blas/blas64"
9 "gonum.org/v1/gonum/lapack"
10 "gonum.org/v1/gonum/lapack/lapack64"
13 // SVD is a type for creating and using the Singular Value Decomposition (SVD)
23 // Factorize computes the singular value decomposition (SVD) of the input matrix
24 // A. The singular values of A are computed in all cases, while the singular
25 // vectors are optionally computed depending on the input kind.
27 // The full singular value decomposition (kind == SVDFull) deconstructs A as
29 // where Σ is an m×n diagonal matrix of singular vectors, U is an m×m unitary
30 // matrix of left singular vectors, and V is an n×n matrix of right singular vectors.
32 // It is frequently not necessary to compute the full SVD. Computation time and
33 // storage costs can be reduced using the appropriate kind. Only the singular
34 // values can be computed (kind == SVDNone), or a "thin" representation of the
35 // singular vectors (kind = SVDThin). The thin representation can save a significant
36 // amount of memory if m >> n. See the documentation for the lapack.SVDKind values
37 // for more information.
39 // Factorize returns whether the decomposition succeeded. If the decomposition
40 // failed, routines that require a successful factorization will panic.
41 func (svd *SVD) Factorize(a Matrix, kind SVDKind) (ok bool) {
43 var jobU, jobVT lapack.SVDJob
46 panic("svd: bad input kind")
49 jobVT = lapack.SVDNone
51 // TODO(btracey): This code should be modified to have the smaller
52 // matrix written in-place into aCopy when the lapack/native/dgesvd
53 // implementation is complete.
54 svd.u = blas64.General{
58 Data: use(svd.u.Data, m*m),
60 svd.vt = blas64.General{
64 Data: use(svd.vt.Data, n*n),
69 // TODO(btracey): This code should be modified to have the larger
70 // matrix written in-place into aCopy when the lapack/native/dgesvd
71 // implementation is complete.
72 svd.u = blas64.General{
76 Data: use(svd.u.Data, m*min(m, n)),
78 svd.vt = blas64.General{
82 Data: use(svd.vt.Data, min(m, n)*n),
84 jobU = lapack.SVDInPlace
85 jobVT = lapack.SVDInPlace
88 // A is destroyed on call, so copy the matrix.
89 aCopy := DenseCopyOf(a)
91 svd.s = use(svd.s, min(m, n))
94 lapack64.Gesvd(jobU, jobVT, aCopy.mat, svd.u, svd.vt, svd.s, work, -1)
95 work = getFloats(int(work[0]), false)
96 ok = lapack64.Gesvd(jobU, jobVT, aCopy.mat, svd.u, svd.vt, svd.s, work, len(work))
104 // Kind returns the matrix.SVDKind of the decomposition. If no decomposition has been
105 // computed, Kind returns 0.
106 func (svd *SVD) Kind() SVDKind {
110 // Cond returns the 2-norm condition number for the factorized matrix. Cond will
111 // panic if the receiver does not contain a successful factorization.
112 func (svd *SVD) Cond() float64 {
114 panic("svd: no decomposition computed")
116 return svd.s[0] / svd.s[len(svd.s)-1]
119 // Values returns the singular values of the factorized matrix in decreasing order.
120 // If the input slice is non-nil, the values will be stored in-place into the slice.
121 // In this case, the slice must have length min(m,n), and Values will panic with
122 // matrix.ErrSliceLengthMismatch otherwise. If the input slice is nil,
123 // a new slice of the appropriate length will be allocated and returned.
125 // Values will panic if the receiver does not contain a successful factorization.
126 func (svd *SVD) Values(s []float64) []float64 {
128 panic("svd: no decomposition computed")
131 s = make([]float64, len(svd.s))
133 if len(s) != len(svd.s) {
134 panic(ErrSliceLengthMismatch)
140 // UTo extracts the matrix U from the singular value decomposition, storing
141 // the result in-place into dst. U is size m×m if svd.Kind() == SVDFull,
142 // of size m×min(m,n) if svd.Kind() == SVDThin, and UTo panics otherwise.
143 func (svd *SVD) UTo(dst *Dense) *Dense {
145 if kind != SVDFull && kind != SVDThin {
146 panic("mat: improper SVD kind")
151 dst = NewDense(r, c, nil)
166 // VTo extracts the matrix V from the singular value decomposition, storing
167 // the result in-place into dst. V is size n×n if svd.Kind() == SVDFull,
168 // of size n×min(m,n) if svd.Kind() == SVDThin, and VTo panics otherwise.
169 func (svd *SVD) VTo(dst *Dense) *Dense {
171 if kind != SVDFull && kind != SVDThin {
172 panic("mat: improper SVD kind")
177 dst = NewDense(c, r, nil)