matrix/mat64: reverse API signatures for matrix extraction

This commit is contained in:
kortschak
2017-05-27 08:01:22 +09:30
committed by Dan Kortschak
parent c1725b9fe9
commit 15641d34f4
14 changed files with 119 additions and 118 deletions

View File

@@ -203,9 +203,9 @@ func (gsvd *GSVD) ValuesB(s []float64) []float64 {
return s return s
} }
// ZeroRFromGSVD extracts the matrix [ 0 R ] from the singular value decomposition, storing // ZeroRTo extracts the matrix [ 0 R ] from the singular value decomposition, storing
// the result in-place into the receiver. [ 0 R ] is size (k+l)×c. // the result in-place into dst. [ 0 R ] is size (k+l)×c.
func (m *Dense) ZeroRFromGSVD(gsvd *GSVD) { func (gsvd *GSVD) ZeroRTo(dst *Dense) {
if gsvd.kind == 0 { if gsvd.kind == 0 {
panic("gsvd: no decomposition computed") panic("gsvd: no decomposition computed")
} }
@@ -214,13 +214,13 @@ func (m *Dense) ZeroRFromGSVD(gsvd *GSVD) {
k := gsvd.k k := gsvd.k
l := gsvd.l l := gsvd.l
h := min(k+l, r) h := min(k+l, r)
m.reuseAsZeroed(k+l, c) dst.reuseAsZeroed(k+l, c)
a := Dense{ a := Dense{
mat: gsvd.a, mat: gsvd.a,
capRows: r, capRows: r,
capCols: c, capCols: c,
} }
m.Slice(0, h, c-k-l, c).(*Dense). dst.Slice(0, h, c-k-l, c).(*Dense).
Copy(a.Slice(0, h, c-k-l, c)) Copy(a.Slice(0, h, c-k-l, c))
if r < k+l { if r < k+l {
b := Dense{ b := Dense{
@@ -228,32 +228,32 @@ func (m *Dense) ZeroRFromGSVD(gsvd *GSVD) {
capRows: gsvd.p, capRows: gsvd.p,
capCols: c, capCols: c,
} }
m.Slice(r, k+l, c+r-k-l, c).(*Dense). dst.Slice(r, k+l, c+r-k-l, c).(*Dense).
Copy(b.Slice(r-k, l, c+r-k-l, c)) Copy(b.Slice(r-k, l, c+r-k-l, c))
} }
} }
// SigmaAFromGSVD extracts the matrix Σ₁ from the singular value decomposition, storing // SigmaATo extracts the matrix Σ₁ from the singular value decomposition, storing
// the result in-place into the receiver. Σ₁ is size r×(k+l). // the result in-place into dst. Σ₁ is size r×(k+l).
func (m *Dense) SigmaAFromGSVD(gsvd *GSVD) { func (gsvd *GSVD) SigmaATo(dst *Dense) {
if gsvd.kind == 0 { if gsvd.kind == 0 {
panic("gsvd: no decomposition computed") panic("gsvd: no decomposition computed")
} }
r := gsvd.r r := gsvd.r
k := gsvd.k k := gsvd.k
l := gsvd.l l := gsvd.l
m.reuseAsZeroed(r, k+l) dst.reuseAsZeroed(r, k+l)
for i := 0; i < k; i++ { for i := 0; i < k; i++ {
m.set(i, i, 1) dst.set(i, i, 1)
} }
for i := k; i < min(r, k+l); i++ { for i := k; i < min(r, k+l); i++ {
m.set(i, i, gsvd.s1[i]) dst.set(i, i, gsvd.s1[i])
} }
} }
// SigmaBFromGSVD extracts the matrix Σ₂ from the singular value decomposition, storing // SigmaBTo extracts the matrix Σ₂ from the singular value decomposition, storing
// the result in-place into the receiver. Σ₂ is size p×(k+l). // the result in-place into dst. Σ₂ is size p×(k+l).
func (m *Dense) SigmaBFromGSVD(gsvd *GSVD) { func (gsvd *GSVD) SigmaBTo(dst *Dense) {
if gsvd.kind == 0 { if gsvd.kind == 0 {
panic("gsvd: no decomposition computed") panic("gsvd: no decomposition computed")
} }
@@ -261,65 +261,65 @@ func (m *Dense) SigmaBFromGSVD(gsvd *GSVD) {
p := gsvd.p p := gsvd.p
k := gsvd.k k := gsvd.k
l := gsvd.l l := gsvd.l
m.reuseAsZeroed(p, k+l) dst.reuseAsZeroed(p, k+l)
for i := 0; i < min(l, r-k); i++ { for i := 0; i < min(l, r-k); i++ {
m.set(i, i+k, gsvd.s2[k+i]) dst.set(i, i+k, gsvd.s2[k+i])
} }
for i := r - k; i < l; i++ { for i := r - k; i < l; i++ {
m.set(i, i+k, 1) dst.set(i, i+k, 1)
} }
} }
// UFromGSVD extracts the matrix U from the singular value decomposition, storing // UTo extracts the matrix U from the singular value decomposition, storing
// the result in-place into the receiver. U is size r×r. // the result in-place into dst. U is size r×r.
func (m *Dense) UFromGSVD(gsvd *GSVD) { func (gsvd *GSVD) UTo(dst *Dense) {
if gsvd.kind&matrix.GSVDU == 0 { if gsvd.kind&matrix.GSVDU == 0 {
panic("mat64: improper GSVD kind") panic("mat64: improper GSVD kind")
} }
r := gsvd.u.Rows r := gsvd.u.Rows
c := gsvd.u.Cols c := gsvd.u.Cols
m.reuseAs(r, c) dst.reuseAs(r, c)
tmp := &Dense{ tmp := &Dense{
mat: gsvd.u, mat: gsvd.u,
capRows: r, capRows: r,
capCols: c, capCols: c,
} }
m.Copy(tmp) dst.Copy(tmp)
} }
// VFromGSVD extracts the matrix V from the singular value decomposition, storing // VTo extracts the matrix V from the singular value decomposition, storing
// the result in-place into the receiver. V is size p×p. // the result in-place into dst. V is size p×p.
func (m *Dense) VFromGSVD(gsvd *GSVD) { func (gsvd *GSVD) VTo(dst *Dense) {
if gsvd.kind&matrix.GSVDV == 0 { if gsvd.kind&matrix.GSVDV == 0 {
panic("mat64: improper GSVD kind") panic("mat64: improper GSVD kind")
} }
r := gsvd.v.Rows r := gsvd.v.Rows
c := gsvd.v.Cols c := gsvd.v.Cols
m.reuseAs(r, c) dst.reuseAs(r, c)
tmp := &Dense{ tmp := &Dense{
mat: gsvd.v, mat: gsvd.v,
capRows: r, capRows: r,
capCols: c, capCols: c,
} }
m.Copy(tmp) dst.Copy(tmp)
} }
// QFromGSVD extracts the matrix Q from the singular value decomposition, storing // QTo extracts the matrix Q from the singular value decomposition, storing
// the result in-place into the receiver. Q is size c×c. // the result in-place into dst. Q is size c×c.
func (m *Dense) QFromGSVD(gsvd *GSVD) { func (gsvd *GSVD) QTo(dst *Dense) {
if gsvd.kind&matrix.GSVDQ == 0 { if gsvd.kind&matrix.GSVDQ == 0 {
panic("mat64: improper GSVD kind") panic("mat64: improper GSVD kind")
} }
r := gsvd.q.Rows r := gsvd.q.Rows
c := gsvd.q.Cols c := gsvd.q.Cols
m.reuseAs(r, c) dst.reuseAs(r, c)
tmp := &Dense{ tmp := &Dense{
mat: gsvd.q, mat: gsvd.q,
capRows: r, capRows: r,
capCols: c, capCols: c,
} }
m.Copy(tmp) dst.Copy(tmp)
} }

View File

@@ -26,8 +26,8 @@ func ExampleGSVD() {
} }
var u, v mat64.Dense var u, v mat64.Dense
u.UFromGSVD(&gsvd) gsvd.UTo(&u)
v.VFromGSVD(&gsvd) gsvd.VTo(&v)
s1 := gsvd.ValuesA(nil) s1 := gsvd.ValuesA(nil)
s2 := gsvd.ValuesB(nil) s2 := gsvd.ValuesB(nil)
@@ -38,8 +38,8 @@ func ExampleGSVD() {
s2, mat64.Formatted(&v, mat64.Prefix("\t "), mat64.Excerpt(2))) s2, mat64.Formatted(&v, mat64.Prefix("\t "), mat64.Excerpt(2)))
var zeroR, q mat64.Dense var zeroR, q mat64.Dense
zeroR.ZeroRFromGSVD(&gsvd) gsvd.ZeroRTo(&zeroR)
q.QFromGSVD(&gsvd) gsvd.QTo(&q)
q.Mul(&zeroR, &q) q.Mul(&zeroR, &q)
fmt.Printf("\nCommon basis vectors\n\n\tQ^T = %.4f\n", fmt.Printf("\nCommon basis vectors\n\n\tQ^T = %.4f\n",
mat64.Formatted(q.T(), mat64.Prefix("\t "))) mat64.Formatted(q.T(), mat64.Prefix("\t ")))

View File

@@ -107,12 +107,12 @@ func TestGSVD(t *testing.T) {
func extractGSVD(gsvd *GSVD) (c, s []float64, s1, s2, zR, u, v, q *Dense) { func extractGSVD(gsvd *GSVD) (c, s []float64, s1, s2, zR, u, v, q *Dense) {
var s1m, s2m, zeroR, um, vm, qm Dense var s1m, s2m, zeroR, um, vm, qm Dense
s1m.SigmaAFromGSVD(gsvd) gsvd.SigmaATo(&s1m)
s2m.SigmaBFromGSVD(gsvd) gsvd.SigmaBTo(&s2m)
zeroR.ZeroRFromGSVD(gsvd) gsvd.ZeroRTo(&zeroR)
um.UFromGSVD(gsvd) gsvd.UTo(&um)
vm.VFromGSVD(gsvd) gsvd.VTo(&vm)
qm.QFromGSVD(gsvd) gsvd.QTo(&qm)
c = gsvd.ValuesA(nil) c = gsvd.ValuesA(nil)
s = gsvd.ValuesB(nil) s = gsvd.ValuesB(nil)
return c, s, &s1m, &s2m, &zeroR, &um, &vm, &qm return c, s, &s1m, &s2m, &zeroR, &um, &vm, &qm

View File

@@ -141,11 +141,11 @@ func (gsvd *HOGSVD) Len() int {
return gsvd.n return gsvd.n
} }
// UFromHOGSVD extracts the matrix U_n from the singular value decomposition, storing // UTo extracts the matrix U_n from the singular value decomposition, storing
// the result in-place into the receiver. U_n is size r×c. // the result in-place into dst. U_n is size r×c.
// //
// UFromHOGSVD will panic if the receiver does not contain a successful factorization. // UTo will panic if the receiver does not contain a successful factorization.
func (m *Dense) UFromHOGSVD(gsvd *HOGSVD, n int) { func (gsvd *HOGSVD) UTo(dst *Dense, n int) {
if gsvd.n == 0 { if gsvd.n == 0 {
panic("hogsvd: unsuccessful factorization") panic("hogsvd: unsuccessful factorization")
} }
@@ -153,10 +153,10 @@ func (m *Dense) UFromHOGSVD(gsvd *HOGSVD, n int) {
panic("hogsvd: invalid index") panic("hogsvd: invalid index")
} }
m.reuseAs(gsvd.b[n].Dims()) dst.reuseAs(gsvd.b[n].Dims())
m.Copy(&gsvd.b[n]) dst.Copy(&gsvd.b[n])
for j, f := range gsvd.Values(nil, n) { for j, f := range gsvd.Values(nil, n) {
v := m.ColView(j) v := dst.ColView(j)
v.ScaleVec(1/f, v) v.ScaleVec(1/f, v)
} }
} }
@@ -188,13 +188,14 @@ func (gsvd *HOGSVD) Values(s []float64, n int) []float64 {
return s return s
} }
// VFromHOGSVD extracts the matrix V from the singular value decomposition, storing // VTo extracts the matrix V from the singular value decomposition, storing
// the result in-place into the receiver. V is size c×c. // the result in-place into dst. V is size c×c.
// //
// VFromHOGSVD will panic if the receiver does not contain a successful factorization. // VTo will panic if the receiver does not contain a successful factorization.
func (m *Dense) VFromHOGSVD(gsvd *HOGSVD) { func (gsvd *HOGSVD) VTo(dst *Dense) {
if gsvd.n == 0 { if gsvd.n == 0 {
panic("hogsvd: unsuccessful factorization") panic("hogsvd: unsuccessful factorization")
} }
*m = *DenseCopyOf(gsvd.v) dst.reuseAs(gsvd.v.Dims())
dst.Copy(gsvd.v)
} }

View File

@@ -25,14 +25,14 @@ func ExampleHOGSVD() {
for i, n := range []string{"Africa", "Asia", "Latin America/Caribbean", "Oceania"} { for i, n := range []string{"Africa", "Asia", "Latin America/Caribbean", "Oceania"} {
var u mat64.Dense var u mat64.Dense
u.UFromHOGSVD(&gsvd, i) gsvd.UTo(&u, i)
s := gsvd.Values(nil, i) s := gsvd.Values(nil, i)
fmt.Printf("%s\n\ts_%d = %.4f\n\n\tU_%[2]d = %.4[4]f\n", fmt.Printf("%s\n\ts_%d = %.4f\n\n\tU_%[2]d = %.4[4]f\n",
n, i, s, mat64.Formatted(&u, mat64.Prefix("\t "))) n, i, s, mat64.Formatted(&u, mat64.Prefix("\t ")))
} }
var v mat64.Dense var v mat64.Dense
v.VFromHOGSVD(&gsvd) gsvd.VTo(&v)
fmt.Printf("\nCommon basis vectors\n\n\tV^T = %.4f", fmt.Printf("\nCommon basis vectors\n\n\tV^T = %.4f",
mat64.Formatted(v.T(), mat64.Prefix("\t "))) mat64.Formatted(v.T(), mat64.Prefix("\t ")))

View File

@@ -80,10 +80,10 @@ func extractHOGSVD(gsvd *HOGSVD) (u []*Dense, s [][]float64, v *Dense) {
s = make([][]float64, gsvd.Len()) s = make([][]float64, gsvd.Len())
for i := 0; i < gsvd.Len(); i++ { for i := 0; i < gsvd.Len(); i++ {
u[i] = &Dense{} u[i] = &Dense{}
u[i].UFromHOGSVD(gsvd, i) gsvd.UTo(u[i], i)
s[i] = gsvd.Values(nil, i) s[i] = gsvd.Values(nil, i)
} }
v = &Dense{} v = &Dense{}
v.VFromHOGSVD(gsvd) gsvd.VTo(v)
return u, s, v return u, s, v
} }

View File

@@ -36,7 +36,7 @@ func (lq *LQ) updateCond() {
// //
// The LQ decomposition is a factorization of the matrix A such that A = L * Q. // The LQ decomposition is a factorization of the matrix A such that A = L * Q.
// The matrix Q is an orthonormal n×n matrix, and L is an m×n upper triangular matrix. // The matrix Q is an orthonormal n×n matrix, and L is an m×n upper triangular matrix.
// L and Q can be extracted from the LFromLQ and QFromLQ methods on Dense. // L and Q can be extracted from the LTo and QTo methods.
func (lq *LQ) Factorize(a Matrix) { func (lq *LQ) Factorize(a Matrix) {
m, n := a.Dims() m, n := a.Dims()
if m > n { if m > n {
@@ -58,10 +58,10 @@ func (lq *LQ) Factorize(a Matrix) {
// TODO(btracey): Add in the "Reduced" forms for extracting the m×m orthogonal // TODO(btracey): Add in the "Reduced" forms for extracting the m×m orthogonal
// and upper triangular matrices. // and upper triangular matrices.
// LFromLQ extracts the m×n lower trapezoidal matrix from a LQ decomposition. // LTo extracts the m×n lower trapezoidal matrix from a LQ decomposition.
func (m *Dense) LFromLQ(lq *LQ) { func (lq *LQ) LTo(dst *Dense) {
r, c := lq.lq.Dims() r, c := lq.lq.Dims()
m.reuseAs(r, c) dst.reuseAs(r, c)
// Disguise the LQ as a lower triangular // Disguise the LQ as a lower triangular
t := &TriDense{ t := &TriDense{
@@ -74,25 +74,25 @@ func (m *Dense) LFromLQ(lq *LQ) {
}, },
cap: lq.lq.capCols, cap: lq.lq.capCols,
} }
m.Copy(t) dst.Copy(t)
if r == c { if r == c {
return return
} }
// Zero right of the triangular. // Zero right of the triangular.
for i := 0; i < r; i++ { for i := 0; i < r; i++ {
zero(m.mat.Data[i*m.mat.Stride+r : i*m.mat.Stride+c]) zero(dst.mat.Data[i*dst.mat.Stride+r : i*dst.mat.Stride+c])
} }
} }
// QFromLQ extracts the n×n orthonormal matrix Q from an LQ decomposition. // QTo extracts the n×n orthonormal matrix Q from an LQ decomposition.
func (m *Dense) QFromLQ(lq *LQ) { func (lq *LQ) QTo(dst *Dense) {
r, c := lq.lq.Dims() r, c := lq.lq.Dims()
m.reuseAs(c, c) dst.reuseAs(c, c)
// Set Q = I. // Set Q = I.
for i := 0; i < c; i++ { for i := 0; i < c; i++ {
v := m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c] v := dst.mat.Data[i*dst.mat.Stride : i*dst.mat.Stride+c]
zero(v) zero(v)
v[i] = 1 v[i] = 1
} }
@@ -127,10 +127,10 @@ func (m *Dense) QFromLQ(lq *LQ) {
// Compute the multiplication matrix. // Compute the multiplication matrix.
blas64.Ger(-lq.tau[i], v, v, h) blas64.Ger(-lq.tau[i], v, v, h)
qCopy.Copy(m) qCopy.Copy(dst)
blas64.Gemm(blas.NoTrans, blas.NoTrans, blas64.Gemm(blas.NoTrans, blas.NoTrans,
1, h, qCopy.mat, 1, h, qCopy.mat,
0, m.mat) 0, dst.mat)
} }
} }

View File

@@ -27,16 +27,16 @@ func TestLQ(t *testing.T) {
var want Dense var want Dense
want.Clone(a) want.Clone(a)
lq := &LQ{} var lq LQ
lq.Factorize(a) lq.Factorize(a)
var l, q Dense var l, q Dense
q.QFromLQ(lq) lq.QTo(&q)
if !isOrthonormal(&q, 1e-10) { if !isOrthonormal(&q, 1e-10) {
t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n) t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n)
} }
l.LFromLQ(lq) lq.LTo(&l)
var got Dense var got Dense
got.Mul(&l, &q) got.Mul(&l, &q)

View File

@@ -51,7 +51,7 @@ func (lu *LU) updateCond(norm float64) {
// The LU factorization is computed with pivoting, and so really the decomposition // The LU factorization is computed with pivoting, and so really the decomposition
// is a PLU decomposition where P is a permutation matrix. The individual matrix // is a PLU decomposition where P is a permutation matrix. The individual matrix
// factors can be extracted from the factorization using the Permutation method // factors can be extracted from the factorization using the Permutation method
// on Dense, and the LFrom and UFrom methods on TriDense. // on Dense, and the LU LTo and UTo methods.
func (lu *LU) Factorize(a Matrix) { func (lu *LU) Factorize(a Matrix) {
r, c := a.Dims() r, c := a.Dims()
if r != c { if r != c {
@@ -204,30 +204,30 @@ func (lu *LU) RankOne(orig *LU, alpha float64, x, y *Vector) {
lu.updateCond(-1) lu.updateCond(-1)
} }
// LFromLU extracts the lower triangular matrix from an LU factorization. // LTo extracts the lower triangular matrix from an LU factorization.
func (t *TriDense) LFromLU(lu *LU) { func (lu *LU) LTo(dst *TriDense) {
_, n := lu.lu.Dims() _, n := lu.lu.Dims()
t.reuseAs(n, false) dst.reuseAs(n, false)
// Extract the lower triangular elements. // Extract the lower triangular elements.
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
for j := 0; j < i; j++ { for j := 0; j < i; j++ {
t.mat.Data[i*t.mat.Stride+j] = lu.lu.mat.Data[i*lu.lu.mat.Stride+j] dst.mat.Data[i*dst.mat.Stride+j] = lu.lu.mat.Data[i*lu.lu.mat.Stride+j]
} }
} }
// Set ones on the diagonal. // Set ones on the diagonal.
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
t.mat.Data[i*t.mat.Stride+i] = 1 dst.mat.Data[i*dst.mat.Stride+i] = 1
} }
} }
// UFromLU extracts the upper triangular matrix from an LU factorization. // UTo extracts the upper triangular matrix from an LU factorization.
func (t *TriDense) UFromLU(lu *LU) { func (lu *LU) UTo(dst *TriDense) {
_, n := lu.lu.Dims() _, n := lu.lu.Dims()
t.reuseAs(n, true) dst.reuseAs(n, true)
// Extract the upper triangular elements. // Extract the upper triangular elements.
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
for j := i; j < n; j++ { for j := i; j < n; j++ {
t.mat.Data[i*t.mat.Stride+j] = lu.lu.mat.Data[i*lu.lu.mat.Stride+j] dst.mat.Data[i*dst.mat.Stride+j] = lu.lu.mat.Data[i*lu.lu.mat.Stride+j]
} }
} }
} }

View File

@@ -20,12 +20,12 @@ func TestLUD(t *testing.T) {
var want Dense var want Dense
want.Clone(a) want.Clone(a)
lu := &LU{} var lu LU
lu.Factorize(a) lu.Factorize(a)
var l, u TriDense var l, u TriDense
l.LFromLU(lu) lu.LTo(&l)
u.UFromLU(lu) lu.UTo(&u)
var p Dense var p Dense
pivot := lu.Pivot(nil) pivot := lu.Pivot(nil)
p.Permutation(n, pivot) p.Permutation(n, pivot)
@@ -93,8 +93,8 @@ func TestLURankOne(t *testing.T) {
// luReconstruct reconstructs the original A matrix from an LU decomposition. // luReconstruct reconstructs the original A matrix from an LU decomposition.
func luReconstruct(lu *LU) *Dense { func luReconstruct(lu *LU) *Dense {
var L, U TriDense var L, U TriDense
L.LFromLU(lu) lu.LTo(&L)
U.UFromLU(lu) lu.UTo(&U)
var P Dense var P Dense
pivot := lu.Pivot(nil) pivot := lu.Pivot(nil)
P.Permutation(len(pivot), pivot) P.Permutation(len(pivot), pivot)

View File

@@ -37,7 +37,7 @@ func (qr *QR) updateCond() {
// //
// The QR decomposition is a factorization of the matrix A such that A = Q * R. // The QR decomposition is a factorization of the matrix A such that A = Q * R.
// The matrix Q is an orthonormal m×m matrix, and R is an m×n upper triangular matrix. // The matrix Q is an orthonormal m×m matrix, and R is an m×n upper triangular matrix.
// Q and R can be extracted from the QFromQR and RFromQR methods on Dense. // Q and R can be extracted using the QTo and RTo methods.
func (qr *QR) Factorize(a Matrix) { func (qr *QR) Factorize(a Matrix) {
m, n := a.Dims() m, n := a.Dims()
if m < n { if m < n {
@@ -60,10 +60,10 @@ func (qr *QR) Factorize(a Matrix) {
// TODO(btracey): Add in the "Reduced" forms for extracting the n×n orthogonal // TODO(btracey): Add in the "Reduced" forms for extracting the n×n orthogonal
// and upper triangular matrices. // and upper triangular matrices.
// RFromQR extracts the m×n upper trapezoidal matrix from a QR decomposition. // RTo extracts the m×n upper trapezoidal matrix from a QR decomposition.
func (m *Dense) RFromQR(qr *QR) { func (qr *QR) RTo(dst *Dense) {
r, c := qr.qr.Dims() r, c := qr.qr.Dims()
m.reuseAs(r, c) dst.reuseAs(r, c)
// Disguise the QR as an upper triangular // Disguise the QR as an upper triangular
t := &TriDense{ t := &TriDense{
@@ -76,29 +76,29 @@ func (m *Dense) RFromQR(qr *QR) {
}, },
cap: qr.qr.capCols, cap: qr.qr.capCols,
} }
m.Copy(t) dst.Copy(t)
// Zero below the triangular. // Zero below the triangular.
for i := r; i < c; i++ { for i := r; i < c; i++ {
zero(m.mat.Data[i*m.mat.Stride : i*m.mat.Stride+c]) zero(dst.mat.Data[i*dst.mat.Stride : i*dst.mat.Stride+c])
} }
} }
// QFromQR extracts the m×m orthonormal matrix Q from a QR decomposition. // QTo extracts the m×m orthonormal matrix Q from a QR decomposition.
func (m *Dense) QFromQR(qr *QR) { func (qr *QR) QTo(dst *Dense) {
r, _ := qr.qr.Dims() r, _ := qr.qr.Dims()
m.reuseAsZeroed(r, r) dst.reuseAsZeroed(r, r)
// Set Q = I. // Set Q = I.
for i := 0; i < r*r; i += r + 1 { for i := 0; i < r*r; i += r + 1 {
m.mat.Data[i] = 1 dst.mat.Data[i] = 1
} }
// Construct Q from the elementary reflectors. // Construct Q from the elementary reflectors.
work := make([]float64, 1) work := make([]float64, 1)
lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, m.mat, work, -1) lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, dst.mat, work, -1)
work = make([]float64, int(work[0])) work = make([]float64, int(work[0]))
lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, m.mat, work, len(work)) lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, dst.mat, work, len(work))
} }
// SolveQR finds a minimum-norm solution to a system of linear equations defined // SolveQR finds a minimum-norm solution to a system of linear equations defined

View File

@@ -30,16 +30,16 @@ func TestQR(t *testing.T) {
var want Dense var want Dense
want.Clone(a) want.Clone(a)
qr := &QR{} var qr QR
qr.Factorize(a) qr.Factorize(a)
var q, r Dense var q, r Dense
q.QFromQR(qr) qr.QTo(&q)
if !isOrthonormal(&q, 1e-10) { if !isOrthonormal(&q, 1e-10) {
t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n) t.Errorf("Q is not orthonormal: m = %v, n = %v", m, n)
} }
r.RFromQR(qr) qr.RTo(&r)
var got Dense var got Dense
got.Mul(&q, &r) got.Mul(&q, &r)

View File

@@ -138,42 +138,42 @@ func (svd *SVD) Values(s []float64) []float64 {
return s return s
} }
// UFromSVD extracts the matrix U from the singular value decomposition, storing // UTo extracts the matrix U from the singular value decomposition, storing
// the result in-place into the receiver. U is size m×m if svd.Kind() == SVDFull, // the result in-place into dst. U is size m×m if svd.Kind() == SVDFull,
// of size m×min(m,n) if svd.Kind() == SVDThin, and UFromSVD panics otherwise. // of size m×min(m,n) if svd.Kind() == SVDThin, and UTo panics otherwise.
func (m *Dense) UFromSVD(svd *SVD) { func (svd *SVD) UTo(dst *Dense) {
kind := svd.kind kind := svd.kind
if kind != matrix.SVDFull && kind != matrix.SVDThin { if kind != matrix.SVDFull && kind != matrix.SVDThin {
panic("mat64: improper SVD kind") panic("mat64: improper SVD kind")
} }
r := svd.u.Rows r := svd.u.Rows
c := svd.u.Cols c := svd.u.Cols
m.reuseAs(r, c) dst.reuseAs(r, c)
tmp := &Dense{ tmp := &Dense{
mat: svd.u, mat: svd.u,
capRows: r, capRows: r,
capCols: c, capCols: c,
} }
m.Copy(tmp) dst.Copy(tmp)
} }
// VFromSVD extracts the matrix V from the singular value decomposition, storing // VTo extracts the matrix V from the singular value decomposition, storing
// the result in-place into the receiver. V is size n×n if svd.Kind() == SVDFull, // the result in-place into dst. V is size n×n if svd.Kind() == SVDFull,
// of size n×min(m,n) if svd.Kind() == SVDThin, and VFromSVD panics otherwise. // of size n×min(m,n) if svd.Kind() == SVDThin, and VTo panics otherwise.
func (m *Dense) VFromSVD(svd *SVD) { func (svd *SVD) VTo(dst *Dense) {
kind := svd.kind kind := svd.kind
if kind != matrix.SVDFull && kind != matrix.SVDThin { if kind != matrix.SVDFull && kind != matrix.SVDThin {
panic("mat64: improper SVD kind") panic("mat64: improper SVD kind")
} }
r := svd.vt.Rows r := svd.vt.Rows
c := svd.vt.Cols c := svd.vt.Cols
m.reuseAs(c, r) dst.reuseAs(c, r)
tmp := &Dense{ tmp := &Dense{
mat: svd.vt, mat: svd.vt,
capRows: r, capRows: r,
capCols: c, capCols: c,
} }
m.Copy(tmp.T()) dst.Copy(tmp.T())
} }

View File

@@ -170,8 +170,8 @@ func TestSVD(t *testing.T) {
func extractSVD(svd *SVD) (s []float64, u, v *Dense) { func extractSVD(svd *SVD) (s []float64, u, v *Dense) {
var um, vm Dense var um, vm Dense
um.UFromSVD(svd) svd.UTo(&um)
vm.VFromSVD(svd) svd.VTo(&vm)
s = svd.Values(nil) s = svd.Values(nil)
return s, &um, &vm return s, &um, &vm
} }