1 // Copyright ©2015 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"
9 "gonum.org/v1/gonum/lapack"
12 // Dormbr applies a multiplicative update to the matrix C based on a
13 // decomposition computed by Dgebrd.
15 // Dormbr overwrites the m×n matrix C with
16 // Q * C if vect == lapack.ApplyQ, side == blas.Left, and trans == blas.NoTrans
17 // C * Q if vect == lapack.ApplyQ, side == blas.Right, and trans == blas.NoTrans
18 // Q^T * C if vect == lapack.ApplyQ, side == blas.Left, and trans == blas.Trans
19 // C * Q^T if vect == lapack.ApplyQ, side == blas.Right, and trans == blas.Trans
21 // P * C if vect == lapack.ApplyP, side == blas.Left, and trans == blas.NoTrans
22 // C * P if vect == lapack.ApplyP, side == blas.Right, and trans == blas.NoTrans
23 // P^T * C if vect == lapack.ApplyP, side == blas.Left, and trans == blas.Trans
24 // C * P^T if vect == lapack.ApplyP, side == blas.Right, and trans == blas.Trans
25 // where P and Q are the orthogonal matrices determined by Dgebrd when reducing
26 // a matrix A to bidiagonal form: A = Q * B * P^T. See Dgebrd for the
27 // definitions of Q and P.
29 // If vect == lapack.ApplyQ, A is assumed to have been an nq×k matrix, while if
30 // vect == lapack.ApplyP, A is assumed to have been a k×nq matrix. nq = m if
31 // side == blas.Left, while nq = n if side == blas.Right.
33 // tau must have length min(nq,k), and Dormbr will panic otherwise. tau contains
34 // the elementary reflectors to construct Q or P depending on the value of
37 // work must have length at least max(1,lwork), and lwork must be either -1 or
38 // at least max(1,n) if side == blas.Left, and at least max(1,m) if side ==
39 // blas.Right. For optimum performance lwork should be at least n*nb if side ==
40 // blas.Left, and at least m*nb if side == blas.Right, where nb is the optimal
41 // block size. On return, work[0] will contain the optimal value of lwork.
43 // If lwork == -1, the function only calculates the optimal value of lwork and
44 // returns it in work[0].
46 // Dormbr is an internal routine. It is exported for testing purposes.
47 func (impl Implementation) Dormbr(vect lapack.DecompUpdate, side blas.Side, trans blas.Transpose, m, n, k int, a []float64, lda int, tau, c []float64, ldc int, work []float64, lwork int) {
48 if side != blas.Left && side != blas.Right {
51 if trans != blas.NoTrans && trans != blas.Trans {
54 if vect != lapack.ApplyP && vect != lapack.ApplyQ {
55 panic(badDecompUpdate)
59 if side == blas.Left {
63 if vect == lapack.ApplyQ {
64 checkMatrix(nq, min(nq, k), a, lda)
66 checkMatrix(min(nq, k), nq, a, lda)
68 if len(tau) < min(nq, k) {
71 checkMatrix(m, n, c, ldc)
72 if len(work) < lwork {
75 if lwork < max(1, nw) && lwork != -1 {
79 applyQ := vect == lapack.ApplyQ
80 left := side == blas.Left
83 // The current implementation does not use opts, but a future change may
84 // use these options so construct them.
86 if side == blas.Left {
91 if trans == blas.Trans {
98 nb = impl.Ilaenv(1, "DORMQR", opts, m-1, n, m-1, -1)
100 nb = impl.Ilaenv(1, "DORMQR", opts, m, n-1, n-1, -1)
104 nb = impl.Ilaenv(1, "DORMLQ", opts, m-1, n, m-1, -1)
106 nb = impl.Ilaenv(1, "DORMLQ", opts, m, n-1, n-1, -1)
109 lworkopt := max(1, nw) * nb
111 work[0] = float64(lworkopt)
114 // Change the operation to get Q depending on the size of the initial
115 // matrix to Dgebrd. The size matters due to the storage location of
116 // the off-diagonal elements.
118 impl.Dormqr(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork)
130 impl.Dormqr(side, trans, mi, ni, nq-1, a[1*lda:], lda, tau[:nq-1], c[i1*ldc+i2:], ldc, work, lwork)
132 work[0] = float64(lworkopt)
136 if trans == blas.Trans {
137 transt = blas.NoTrans
139 // Change the operation to get P depending on the size of the initial
140 // matrix to Dgebrd. The size matters due to the storage location of
141 // the off-diagonal elements.
143 impl.Dormlq(side, transt, m, n, k, a, lda, tau, c, ldc, work, lwork)
155 impl.Dormlq(side, transt, mi, ni, nq-1, a[1:], lda, tau, c[i1*ldc+i2:], ldc, work, lwork)
157 work[0] = float64(lworkopt)