gsvd.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. // Copyright ©2017 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.
  4. package mat
  5. import (
  6. "gonum.org/v1/gonum/blas/blas64"
  7. "gonum.org/v1/gonum/floats"
  8. "gonum.org/v1/gonum/lapack"
  9. "gonum.org/v1/gonum/lapack/lapack64"
  10. )
  11. // GSVDKind specifies the treatment of singular vectors during a GSVD
  12. // factorization.
  13. type GSVDKind int
  14. const (
  15. // GSVDNone specifies that no singular vectors should be computed during
  16. // the decomposition.
  17. GSVDNone GSVDKind = 0
  18. // GSVDU specifies that the U singular vectors should be computed during
  19. // the decomposition.
  20. GSVDU GSVDKind = 1 << iota
  21. // GSVDV specifies that the V singular vectors should be computed during
  22. // the decomposition.
  23. GSVDV
  24. // GSVDQ specifies that the Q singular vectors should be computed during
  25. // the decomposition.
  26. GSVDQ
  27. // GSVDAll is a convenience value for computing all of the singular vectors.
  28. GSVDAll = GSVDU | GSVDV | GSVDQ
  29. )
  30. // GSVD is a type for creating and using the Generalized Singular Value Decomposition
  31. // (GSVD) of a matrix.
  32. //
  33. // The factorization is a linear transformation of the data sets from the given
  34. // variable×sample spaces to reduced and diagonalized "eigenvariable"×"eigensample"
  35. // spaces.
  36. type GSVD struct {
  37. kind GSVDKind
  38. r, p, c, k, l int
  39. s1, s2 []float64
  40. a, b, u, v, q blas64.General
  41. work []float64
  42. iwork []int
  43. }
  44. // succFact returns whether the receiver contains a successful factorization.
  45. func (gsvd *GSVD) succFact() bool {
  46. return gsvd.r != 0
  47. }
  48. // Factorize computes the generalized singular value decomposition (GSVD) of the input
  49. // the r×c matrix A and the p×c matrix B. The singular values of A and B are computed
  50. // in all cases, while the singular vectors are optionally computed depending on the
  51. // input kind.
  52. //
  53. // The full singular value decomposition (kind == GSVDAll) deconstructs A and B as
  54. // A = U * Σ₁ * [ 0 R ] * Qᵀ
  55. //
  56. // B = V * Σ₂ * [ 0 R ] * Qᵀ
  57. // where Σ₁ and Σ₂ are r×(k+l) and p×(k+l) diagonal matrices of singular values, and
  58. // U, V and Q are r×r, p×p and c×c orthogonal matrices of singular vectors. k+l is the
  59. // effective numerical rank of the matrix [ Aᵀ Bᵀ ]ᵀ.
  60. //
  61. // It is frequently not necessary to compute the full GSVD. Computation time and
  62. // storage costs can be reduced using the appropriate kind. Either only the singular
  63. // values can be computed (kind == SVDNone), or in conjunction with specific singular
  64. // vectors (kind bit set according to matrix.GSVDU, matrix.GSVDV and matrix.GSVDQ).
  65. //
  66. // Factorize returns whether the decomposition succeeded. If the decomposition
  67. // failed, routines that require a successful factorization will panic.
  68. func (gsvd *GSVD) Factorize(a, b Matrix, kind GSVDKind) (ok bool) {
  69. // kill the previous decomposition
  70. gsvd.r = 0
  71. gsvd.kind = 0
  72. r, c := a.Dims()
  73. gsvd.r, gsvd.c = r, c
  74. p, c := b.Dims()
  75. gsvd.p = p
  76. if gsvd.c != c {
  77. panic(ErrShape)
  78. }
  79. var jobU, jobV, jobQ lapack.GSVDJob
  80. switch {
  81. default:
  82. panic("gsvd: bad input kind")
  83. case kind == GSVDNone:
  84. jobU = lapack.GSVDNone
  85. jobV = lapack.GSVDNone
  86. jobQ = lapack.GSVDNone
  87. case GSVDAll&kind != 0:
  88. if GSVDU&kind != 0 {
  89. jobU = lapack.GSVDU
  90. gsvd.u = blas64.General{
  91. Rows: r,
  92. Cols: r,
  93. Stride: r,
  94. Data: use(gsvd.u.Data, r*r),
  95. }
  96. }
  97. if GSVDV&kind != 0 {
  98. jobV = lapack.GSVDV
  99. gsvd.v = blas64.General{
  100. Rows: p,
  101. Cols: p,
  102. Stride: p,
  103. Data: use(gsvd.v.Data, p*p),
  104. }
  105. }
  106. if GSVDQ&kind != 0 {
  107. jobQ = lapack.GSVDQ
  108. gsvd.q = blas64.General{
  109. Rows: c,
  110. Cols: c,
  111. Stride: c,
  112. Data: use(gsvd.q.Data, c*c),
  113. }
  114. }
  115. }
  116. // A and B are destroyed on call, so copy the matrices.
  117. aCopy := DenseCopyOf(a)
  118. bCopy := DenseCopyOf(b)
  119. gsvd.s1 = use(gsvd.s1, c)
  120. gsvd.s2 = use(gsvd.s2, c)
  121. gsvd.iwork = useInt(gsvd.iwork, c)
  122. gsvd.work = use(gsvd.work, 1)
  123. lapack64.Ggsvd3(jobU, jobV, jobQ, aCopy.mat, bCopy.mat, gsvd.s1, gsvd.s2, gsvd.u, gsvd.v, gsvd.q, gsvd.work, -1, gsvd.iwork)
  124. gsvd.work = use(gsvd.work, int(gsvd.work[0]))
  125. gsvd.k, gsvd.l, ok = lapack64.Ggsvd3(jobU, jobV, jobQ, aCopy.mat, bCopy.mat, gsvd.s1, gsvd.s2, gsvd.u, gsvd.v, gsvd.q, gsvd.work, len(gsvd.work), gsvd.iwork)
  126. if ok {
  127. gsvd.a = aCopy.mat
  128. gsvd.b = bCopy.mat
  129. gsvd.kind = kind
  130. }
  131. return ok
  132. }
  133. // Kind returns the GSVDKind of the decomposition. If no decomposition has been
  134. // computed, Kind returns -1.
  135. func (gsvd *GSVD) Kind() GSVDKind {
  136. if !gsvd.succFact() {
  137. return -1
  138. }
  139. return gsvd.kind
  140. }
  141. // Rank returns the k and l terms of the rank of [ Aᵀ Bᵀ ]ᵀ.
  142. func (gsvd *GSVD) Rank() (k, l int) {
  143. return gsvd.k, gsvd.l
  144. }
  145. // GeneralizedValues returns the generalized singular values of the factorized matrices.
  146. // If the input slice is non-nil, the values will be stored in-place into the slice.
  147. // In this case, the slice must have length min(r,c)-k, and GeneralizedValues will
  148. // panic with matrix.ErrSliceLengthMismatch otherwise. If the input slice is nil,
  149. // a new slice of the appropriate length will be allocated and returned.
  150. //
  151. // GeneralizedValues will panic if the receiver does not contain a successful factorization.
  152. func (gsvd *GSVD) GeneralizedValues(v []float64) []float64 {
  153. if !gsvd.succFact() {
  154. panic(badFact)
  155. }
  156. r := gsvd.r
  157. c := gsvd.c
  158. k := gsvd.k
  159. d := min(r, c)
  160. if v == nil {
  161. v = make([]float64, d-k)
  162. }
  163. if len(v) != d-k {
  164. panic(ErrSliceLengthMismatch)
  165. }
  166. floats.DivTo(v, gsvd.s1[k:d], gsvd.s2[k:d])
  167. return v
  168. }
  169. // ValuesA returns the singular values of the factorized A matrix.
  170. // If the input slice is non-nil, the values will be stored in-place into the slice.
  171. // In this case, the slice must have length min(r,c)-k, and ValuesA will panic with
  172. // matrix.ErrSliceLengthMismatch otherwise. If the input slice is nil,
  173. // a new slice of the appropriate length will be allocated and returned.
  174. //
  175. // ValuesA will panic if the receiver does not contain a successful factorization.
  176. func (gsvd *GSVD) ValuesA(s []float64) []float64 {
  177. if !gsvd.succFact() {
  178. panic(badFact)
  179. }
  180. r := gsvd.r
  181. c := gsvd.c
  182. k := gsvd.k
  183. d := min(r, c)
  184. if s == nil {
  185. s = make([]float64, d-k)
  186. }
  187. if len(s) != d-k {
  188. panic(ErrSliceLengthMismatch)
  189. }
  190. copy(s, gsvd.s1[k:min(r, c)])
  191. return s
  192. }
  193. // ValuesB returns the singular values of the factorized B matrix.
  194. // If the input slice is non-nil, the values will be stored in-place into the slice.
  195. // In this case, the slice must have length min(r,c)-k, and ValuesB will panic with
  196. // matrix.ErrSliceLengthMismatch otherwise. If the input slice is nil,
  197. // a new slice of the appropriate length will be allocated and returned.
  198. //
  199. // ValuesB will panic if the receiver does not contain a successful factorization.
  200. func (gsvd *GSVD) ValuesB(s []float64) []float64 {
  201. if !gsvd.succFact() {
  202. panic(badFact)
  203. }
  204. r := gsvd.r
  205. c := gsvd.c
  206. k := gsvd.k
  207. d := min(r, c)
  208. if s == nil {
  209. s = make([]float64, d-k)
  210. }
  211. if len(s) != d-k {
  212. panic(ErrSliceLengthMismatch)
  213. }
  214. copy(s, gsvd.s2[k:d])
  215. return s
  216. }
  217. // ZeroRTo extracts the matrix [ 0 R ] from the singular value decomposition,
  218. // storing the result into dst. [ 0 R ] is of size (k+l)×c.
  219. //
  220. // If dst is empty, ZeroRTo will resize dst to be (k+l)×c. When dst is
  221. // non-empty, ZeroRTo will panic if dst is not (k+l)×c. ZeroRTo will also panic
  222. // if the receiver does not contain a successful factorization.
  223. func (gsvd *GSVD) ZeroRTo(dst *Dense) {
  224. if !gsvd.succFact() {
  225. panic(badFact)
  226. }
  227. r := gsvd.r
  228. c := gsvd.c
  229. k := gsvd.k
  230. l := gsvd.l
  231. h := min(k+l, r)
  232. if dst.IsEmpty() {
  233. dst.ReuseAs(k+l, c)
  234. } else {
  235. r2, c2 := dst.Dims()
  236. if r2 != k+l || c != c2 {
  237. panic(ErrShape)
  238. }
  239. dst.Zero()
  240. }
  241. a := Dense{
  242. mat: gsvd.a,
  243. capRows: r,
  244. capCols: c,
  245. }
  246. dst.slice(0, h, c-k-l, c).Copy(a.Slice(0, h, c-k-l, c))
  247. if r < k+l {
  248. b := Dense{
  249. mat: gsvd.b,
  250. capRows: gsvd.p,
  251. capCols: c,
  252. }
  253. dst.slice(r, k+l, c+r-k-l, c).Copy(b.Slice(r-k, l, c+r-k-l, c))
  254. }
  255. }
  256. // SigmaATo extracts the matrix Σ₁ from the singular value decomposition, storing
  257. // the result into dst. Σ₁ is size r×(k+l).
  258. //
  259. // If dst is empty, SigmaATo will resize dst to be r×(k+l). When dst is
  260. // non-empty, SigmATo will panic if dst is not r×(k+l). SigmaATo will also
  261. // panic if the receiver does not contain a successful factorization.
  262. func (gsvd *GSVD) SigmaATo(dst *Dense) {
  263. if !gsvd.succFact() {
  264. panic(badFact)
  265. }
  266. r := gsvd.r
  267. k := gsvd.k
  268. l := gsvd.l
  269. if dst.IsEmpty() {
  270. dst.ReuseAs(r, k+l)
  271. } else {
  272. r2, c := dst.Dims()
  273. if r2 != r || c != k+l {
  274. panic(ErrShape)
  275. }
  276. dst.Zero()
  277. }
  278. for i := 0; i < k; i++ {
  279. dst.set(i, i, 1)
  280. }
  281. for i := k; i < min(r, k+l); i++ {
  282. dst.set(i, i, gsvd.s1[i])
  283. }
  284. }
  285. // SigmaBTo extracts the matrix Σ₂ from the singular value decomposition, storing
  286. // the result into dst. Σ₂ is size p×(k+l).
  287. //
  288. // If dst is empty, SigmaBTo will resize dst to be p×(k+l). When dst is
  289. // non-empty, SigmBTo will panic if dst is not p×(k+l). SigmaBTo will also
  290. // panic if the receiver does not contain a successful factorization.
  291. func (gsvd *GSVD) SigmaBTo(dst *Dense) {
  292. if !gsvd.succFact() {
  293. panic(badFact)
  294. }
  295. r := gsvd.r
  296. p := gsvd.p
  297. k := gsvd.k
  298. l := gsvd.l
  299. if dst.IsEmpty() {
  300. dst.ReuseAs(p, k+l)
  301. } else {
  302. r, c := dst.Dims()
  303. if r != p || c != k+l {
  304. panic(ErrShape)
  305. }
  306. dst.Zero()
  307. }
  308. for i := 0; i < min(l, r-k); i++ {
  309. dst.set(i, i+k, gsvd.s2[k+i])
  310. }
  311. for i := r - k; i < l; i++ {
  312. dst.set(i, i+k, 1)
  313. }
  314. }
  315. // UTo extracts the matrix U from the singular value decomposition, storing
  316. // the result into dst. U is size r×r.
  317. //
  318. // If dst is empty, UTo will resize dst to be r×r. When dst is
  319. // non-empty, UTo will panic if dst is not r×r. UTo will also
  320. // panic if the receiver does not contain a successful factorization.
  321. func (gsvd *GSVD) UTo(dst *Dense) {
  322. if !gsvd.succFact() {
  323. panic(badFact)
  324. }
  325. if gsvd.kind&GSVDU == 0 {
  326. panic("mat: improper GSVD kind")
  327. }
  328. r := gsvd.u.Rows
  329. c := gsvd.u.Cols
  330. if dst.IsEmpty() {
  331. dst.ReuseAs(r, c)
  332. } else {
  333. r2, c2 := dst.Dims()
  334. if r != r2 || c != c2 {
  335. panic(ErrShape)
  336. }
  337. }
  338. tmp := &Dense{
  339. mat: gsvd.u,
  340. capRows: r,
  341. capCols: c,
  342. }
  343. dst.Copy(tmp)
  344. }
  345. // VTo extracts the matrix V from the singular value decomposition, storing
  346. // the result into dst. V is size p×p.
  347. //
  348. // If dst is empty, VTo will resize dst to be p×p. When dst is
  349. // non-empty, VTo will panic if dst is not p×p. VTo will also
  350. // panic if the receiver does not contain a successful factorization.
  351. func (gsvd *GSVD) VTo(dst *Dense) {
  352. if !gsvd.succFact() {
  353. panic(badFact)
  354. }
  355. if gsvd.kind&GSVDV == 0 {
  356. panic("mat: improper GSVD kind")
  357. }
  358. r := gsvd.v.Rows
  359. c := gsvd.v.Cols
  360. if dst.IsEmpty() {
  361. dst.ReuseAs(r, c)
  362. } else {
  363. r2, c2 := dst.Dims()
  364. if r != r2 || c != c2 {
  365. panic(ErrShape)
  366. }
  367. }
  368. tmp := &Dense{
  369. mat: gsvd.v,
  370. capRows: r,
  371. capCols: c,
  372. }
  373. dst.Copy(tmp)
  374. }
  375. // QTo extracts the matrix Q from the singular value decomposition, storing
  376. // the result into dst. Q is size c×c.
  377. //
  378. // If dst is empty, QTo will resize dst to be c×c. When dst is
  379. // non-empty, QTo will panic if dst is not c×c. QTo will also
  380. // panic if the receiver does not contain a successful factorization.
  381. func (gsvd *GSVD) QTo(dst *Dense) {
  382. if !gsvd.succFact() {
  383. panic(badFact)
  384. }
  385. if gsvd.kind&GSVDQ == 0 {
  386. panic("mat: improper GSVD kind")
  387. }
  388. r := gsvd.q.Rows
  389. c := gsvd.q.Cols
  390. if dst.IsEmpty() {
  391. dst.ReuseAs(r, c)
  392. } else {
  393. r2, c2 := dst.Dims()
  394. if r != r2 || c != c2 {
  395. panic(ErrShape)
  396. }
  397. }
  398. tmp := &Dense{
  399. mat: gsvd.q,
  400. capRows: r,
  401. capCols: c,
  402. }
  403. dst.Copy(tmp)
  404. }