mirror of
https://github.com/gonum/gonum.git
synced 2025-10-31 02:26:59 +08:00
matrix/mat64: provide sugar for easy matrix extraction
This commit is contained in:
@@ -205,7 +205,8 @@ func (gsvd *GSVD) ValuesB(s []float64) []float64 {
|
|||||||
|
|
||||||
// ZeroRTo 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 dst. [ 0 R ] is size (k+l)×c.
|
// the result in-place into dst. [ 0 R ] is size (k+l)×c.
|
||||||
func (gsvd *GSVD) ZeroRTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting ZeroR matrix is returned.
|
||||||
|
func (gsvd *GSVD) ZeroRTo(dst *Dense) *Dense {
|
||||||
if gsvd.kind == 0 {
|
if gsvd.kind == 0 {
|
||||||
panic("gsvd: no decomposition computed")
|
panic("gsvd: no decomposition computed")
|
||||||
}
|
}
|
||||||
@@ -214,7 +215,11 @@ func (gsvd *GSVD) ZeroRTo(dst *Dense) {
|
|||||||
k := gsvd.k
|
k := gsvd.k
|
||||||
l := gsvd.l
|
l := gsvd.l
|
||||||
h := min(k+l, r)
|
h := min(k+l, r)
|
||||||
dst.reuseAsZeroed(k+l, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(k+l, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAsZeroed(k+l, c)
|
||||||
|
}
|
||||||
a := Dense{
|
a := Dense{
|
||||||
mat: gsvd.a,
|
mat: gsvd.a,
|
||||||
capRows: r,
|
capRows: r,
|
||||||
@@ -231,29 +236,37 @@ func (gsvd *GSVD) ZeroRTo(dst *Dense) {
|
|||||||
dst.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))
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// SigmaATo extracts the matrix Σ₁ from the singular value decomposition, storing
|
// SigmaATo extracts the matrix Σ₁ from the singular value decomposition, storing
|
||||||
// the result in-place into dst. Σ₁ is size r×(k+l).
|
// the result in-place into dst. Σ₁ is size r×(k+l).
|
||||||
func (gsvd *GSVD) SigmaATo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting SigmaA matrix is returned.
|
||||||
|
func (gsvd *GSVD) SigmaATo(dst *Dense) *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
|
||||||
dst.reuseAsZeroed(r, k+l)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, k+l, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAsZeroed(r, k+l)
|
||||||
|
}
|
||||||
for i := 0; i < k; i++ {
|
for i := 0; i < k; i++ {
|
||||||
dst.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++ {
|
||||||
dst.set(i, i, gsvd.s1[i])
|
dst.set(i, i, gsvd.s1[i])
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// SigmaBTo extracts the matrix Σ₂ from the singular value decomposition, storing
|
// SigmaBTo extracts the matrix Σ₂ from the singular value decomposition, storing
|
||||||
// the result in-place into dst. Σ₂ is size p×(k+l).
|
// the result in-place into dst. Σ₂ is size p×(k+l).
|
||||||
func (gsvd *GSVD) SigmaBTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting SigmaB matrix is returned.
|
||||||
|
func (gsvd *GSVD) SigmaBTo(dst *Dense) *Dense {
|
||||||
if gsvd.kind == 0 {
|
if gsvd.kind == 0 {
|
||||||
panic("gsvd: no decomposition computed")
|
panic("gsvd: no decomposition computed")
|
||||||
}
|
}
|
||||||
@@ -261,24 +274,34 @@ func (gsvd *GSVD) SigmaBTo(dst *Dense) {
|
|||||||
p := gsvd.p
|
p := gsvd.p
|
||||||
k := gsvd.k
|
k := gsvd.k
|
||||||
l := gsvd.l
|
l := gsvd.l
|
||||||
dst.reuseAsZeroed(p, k+l)
|
if dst == nil {
|
||||||
|
dst = NewDense(p, k+l, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAsZeroed(p, k+l)
|
||||||
|
}
|
||||||
for i := 0; i < min(l, r-k); i++ {
|
for i := 0; i < min(l, r-k); i++ {
|
||||||
dst.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++ {
|
||||||
dst.set(i, i+k, 1)
|
dst.set(i, i+k, 1)
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTo 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 dst. U is size r×r.
|
// the result in-place into dst. U is size r×r.
|
||||||
func (gsvd *GSVD) UTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting U matrix is returned.
|
||||||
|
func (gsvd *GSVD) UTo(dst *Dense) *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
|
||||||
dst.reuseAs(r, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
tmp := &Dense{
|
tmp := &Dense{
|
||||||
mat: gsvd.u,
|
mat: gsvd.u,
|
||||||
@@ -286,17 +309,23 @@ func (gsvd *GSVD) UTo(dst *Dense) {
|
|||||||
capCols: c,
|
capCols: c,
|
||||||
}
|
}
|
||||||
dst.Copy(tmp)
|
dst.Copy(tmp)
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// VTo 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 dst. V is size p×p.
|
// the result in-place into dst. V is size p×p.
|
||||||
func (gsvd *GSVD) VTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting V matrix is returned.
|
||||||
|
func (gsvd *GSVD) VTo(dst *Dense) *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
|
||||||
dst.reuseAs(r, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
tmp := &Dense{
|
tmp := &Dense{
|
||||||
mat: gsvd.v,
|
mat: gsvd.v,
|
||||||
@@ -304,17 +333,23 @@ func (gsvd *GSVD) VTo(dst *Dense) {
|
|||||||
capCols: c,
|
capCols: c,
|
||||||
}
|
}
|
||||||
dst.Copy(tmp)
|
dst.Copy(tmp)
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// QTo 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 dst. Q is size c×c.
|
// the result in-place into dst. Q is size c×c.
|
||||||
func (gsvd *GSVD) QTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting Q matrix is returned.
|
||||||
|
func (gsvd *GSVD) QTo(dst *Dense) *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
|
||||||
dst.reuseAs(r, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
tmp := &Dense{
|
tmp := &Dense{
|
||||||
mat: gsvd.q,
|
mat: gsvd.q,
|
||||||
@@ -322,4 +357,5 @@ func (gsvd *GSVD) QTo(dst *Dense) {
|
|||||||
capCols: c,
|
capCols: c,
|
||||||
}
|
}
|
||||||
dst.Copy(tmp)
|
dst.Copy(tmp)
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,22 +25,19 @@ func ExampleGSVD() {
|
|||||||
log.Fatal("GSVD factorization failed")
|
log.Fatal("GSVD factorization failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
var u, v mat64.Dense
|
u := gsvd.UTo(nil)
|
||||||
gsvd.UTo(&u)
|
v := gsvd.VTo(nil)
|
||||||
gsvd.VTo(&v)
|
|
||||||
|
|
||||||
s1 := gsvd.ValuesA(nil)
|
s1 := gsvd.ValuesA(nil)
|
||||||
s2 := gsvd.ValuesB(nil)
|
s2 := gsvd.ValuesB(nil)
|
||||||
|
|
||||||
fmt.Printf("Africa\n\ts1 = %.4f\n\n\tU = %.4f\n\n",
|
fmt.Printf("Africa\n\ts1 = %.4f\n\n\tU = %.4f\n\n",
|
||||||
s1, mat64.Formatted(&u, mat64.Prefix("\t "), mat64.Excerpt(2)))
|
s1, mat64.Formatted(u, mat64.Prefix("\t "), mat64.Excerpt(2)))
|
||||||
fmt.Printf("Latin America/Caribbean\n\ts2 = %.4f\n\n\tV = %.4f\n",
|
fmt.Printf("Latin America/Caribbean\n\ts2 = %.4f\n\n\tV = %.4f\n",
|
||||||
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 q mat64.Dense
|
||||||
gsvd.ZeroRTo(&zeroR)
|
q.Mul(gsvd.ZeroRTo(nil), gsvd.QTo(nil))
|
||||||
gsvd.QTo(&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 ")))
|
||||||
|
|
||||||
|
|||||||
@@ -106,14 +106,13 @@ 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
|
s1 = gsvd.SigmaATo(nil)
|
||||||
gsvd.SigmaATo(&s1m)
|
s2 = gsvd.SigmaBTo(nil)
|
||||||
gsvd.SigmaBTo(&s2m)
|
zR = gsvd.ZeroRTo(nil)
|
||||||
gsvd.ZeroRTo(&zeroR)
|
u = gsvd.UTo(nil)
|
||||||
gsvd.UTo(&um)
|
v = gsvd.VTo(nil)
|
||||||
gsvd.VTo(&vm)
|
q = gsvd.QTo(nil)
|
||||||
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, s1, s2, zR, u, v, q
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,9 +143,10 @@ func (gsvd *HOGSVD) Len() int {
|
|||||||
|
|
||||||
// UTo 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 dst. U_n is size r×c.
|
// the result in-place into dst. U_n is size r×c.
|
||||||
|
// If dst is nil, a new matrix is allocated. The resulting U matrix is returned.
|
||||||
//
|
//
|
||||||
// UTo will panic if the receiver does not contain a successful factorization.
|
// UTo will panic if the receiver does not contain a successful factorization.
|
||||||
func (gsvd *HOGSVD) UTo(dst *Dense, n int) {
|
func (gsvd *HOGSVD) UTo(dst *Dense, n int) *Dense {
|
||||||
if gsvd.n == 0 {
|
if gsvd.n == 0 {
|
||||||
panic("hogsvd: unsuccessful factorization")
|
panic("hogsvd: unsuccessful factorization")
|
||||||
}
|
}
|
||||||
@@ -153,12 +154,18 @@ func (gsvd *HOGSVD) UTo(dst *Dense, n int) {
|
|||||||
panic("hogsvd: invalid index")
|
panic("hogsvd: invalid index")
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.reuseAs(gsvd.b[n].Dims())
|
if dst == nil {
|
||||||
|
r, c := gsvd.b[n].Dims()
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(gsvd.b[n].Dims())
|
||||||
|
}
|
||||||
dst.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 := dst.ColView(j)
|
v := dst.ColView(j)
|
||||||
v.ScaleVec(1/f, v)
|
v.ScaleVec(1/f, v)
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values returns the nth set of singular values of the factorized system.
|
// Values returns the nth set of singular values of the factorized system.
|
||||||
@@ -190,12 +197,19 @@ func (gsvd *HOGSVD) Values(s []float64, n int) []float64 {
|
|||||||
|
|
||||||
// VTo 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 dst. V is size c×c.
|
// the result in-place into dst. V is size c×c.
|
||||||
|
// If dst is nil, a new matrix is allocated. The resulting V matrix is returned.
|
||||||
//
|
//
|
||||||
// VTo will panic if the receiver does not contain a successful factorization.
|
// VTo will panic if the receiver does not contain a successful factorization.
|
||||||
func (gsvd *HOGSVD) VTo(dst *Dense) {
|
func (gsvd *HOGSVD) VTo(dst *Dense) *Dense {
|
||||||
if gsvd.n == 0 {
|
if gsvd.n == 0 {
|
||||||
panic("hogsvd: unsuccessful factorization")
|
panic("hogsvd: unsuccessful factorization")
|
||||||
}
|
}
|
||||||
dst.reuseAs(gsvd.v.Dims())
|
if dst == nil {
|
||||||
|
r, c := gsvd.v.Dims()
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(gsvd.v.Dims())
|
||||||
|
}
|
||||||
dst.Copy(gsvd.v)
|
dst.Copy(gsvd.v)
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,15 +24,13 @@ 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
|
u := gsvd.UTo(nil, 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
|
v := gsvd.VTo(nil)
|
||||||
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 ")))
|
||||||
|
|
||||||
|
|||||||
@@ -79,11 +79,9 @@ func extractHOGSVD(gsvd *HOGSVD) (u []*Dense, s [][]float64, v *Dense) {
|
|||||||
u = make([]*Dense, gsvd.Len())
|
u = make([]*Dense, gsvd.Len())
|
||||||
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] = gsvd.UTo(nil, i)
|
||||||
gsvd.UTo(u[i], i)
|
|
||||||
s[i] = gsvd.Values(nil, i)
|
s[i] = gsvd.Values(nil, i)
|
||||||
}
|
}
|
||||||
v = &Dense{}
|
v = gsvd.VTo(nil)
|
||||||
gsvd.VTo(v)
|
|
||||||
return u, s, v
|
return u, s, v
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,16 @@ func (lq *LQ) Factorize(a Matrix) {
|
|||||||
// and upper triangular matrices.
|
// and upper triangular matrices.
|
||||||
|
|
||||||
// LTo extracts the m×n lower trapezoidal matrix from a LQ decomposition.
|
// LTo extracts the m×n lower trapezoidal matrix from a LQ decomposition.
|
||||||
func (lq *LQ) LTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting L matrix is returned.
|
||||||
|
func (lq *LQ) LTo(dst *Dense) *Dense {
|
||||||
r, c := lq.lq.Dims()
|
r, c := lq.lq.Dims()
|
||||||
dst.reuseAs(r, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
// Disguise the LQ as a lower triangular
|
// Disguise the LQ as a lower triangular.
|
||||||
t := &TriDense{
|
t := &TriDense{
|
||||||
mat: blas64.Triangular{
|
mat: blas64.Triangular{
|
||||||
N: r,
|
N: r,
|
||||||
@@ -77,18 +82,25 @@ func (lq *LQ) LTo(dst *Dense) {
|
|||||||
dst.Copy(t)
|
dst.Copy(t)
|
||||||
|
|
||||||
if r == c {
|
if r == c {
|
||||||
return
|
return dst
|
||||||
}
|
}
|
||||||
// Zero right of the triangular.
|
// Zero right of the triangular.
|
||||||
for i := 0; i < r; i++ {
|
for i := 0; i < r; i++ {
|
||||||
zero(dst.mat.Data[i*dst.mat.Stride+r : i*dst.mat.Stride+c])
|
zero(dst.mat.Data[i*dst.mat.Stride+r : i*dst.mat.Stride+c])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// QTo extracts the n×n orthonormal matrix Q from an LQ decomposition.
|
// QTo extracts the n×n orthonormal matrix Q from an LQ decomposition.
|
||||||
func (lq *LQ) QTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting Q matrix is returned.
|
||||||
|
func (lq *LQ) QTo(dst *Dense) *Dense {
|
||||||
r, c := lq.lq.Dims()
|
r, c := lq.lq.Dims()
|
||||||
dst.reuseAs(c, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(c, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(c, c)
|
||||||
|
}
|
||||||
|
|
||||||
// Set Q = I.
|
// Set Q = I.
|
||||||
for i := 0; i < c; i++ {
|
for i := 0; i < c; i++ {
|
||||||
@@ -132,6 +144,8 @@ func (lq *LQ) QTo(dst *Dense) {
|
|||||||
1, h, qCopy.mat,
|
1, h, qCopy.mat,
|
||||||
0, dst.mat)
|
0, dst.mat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// SolveLQ finds a minimum-norm solution to a system of linear equations defined
|
// SolveLQ finds a minimum-norm solution to a system of linear equations defined
|
||||||
|
|||||||
@@ -29,17 +29,16 @@ func TestLQ(t *testing.T) {
|
|||||||
|
|
||||||
var lq LQ
|
var lq LQ
|
||||||
lq.Factorize(a)
|
lq.Factorize(a)
|
||||||
var l, q Dense
|
q := lq.QTo(nil)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
lq.LTo(&l)
|
l := lq.LTo(nil)
|
||||||
|
|
||||||
var got Dense
|
var got Dense
|
||||||
got.Mul(&l, &q)
|
got.Mul(l, q)
|
||||||
if !EqualApprox(&got, &want, 1e-12) {
|
if !EqualApprox(&got, &want, 1e-12) {
|
||||||
t.Errorf("LQ does not equal original matrix. \nWant: %v\nGot: %v", want, got)
|
t.Errorf("LQ does not equal original matrix. \nWant: %v\nGot: %v", want, got)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,9 +205,14 @@ func (lu *LU) RankOne(orig *LU, alpha float64, x, y *Vector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LTo extracts the lower triangular matrix from an LU factorization.
|
// LTo extracts the lower triangular matrix from an LU factorization.
|
||||||
func (lu *LU) LTo(dst *TriDense) {
|
// If dst is nil, a new matrix is allocated. The resulting L matrix is returned.
|
||||||
|
func (lu *LU) LTo(dst *TriDense) *TriDense {
|
||||||
_, n := lu.lu.Dims()
|
_, n := lu.lu.Dims()
|
||||||
dst.reuseAs(n, false)
|
if dst == nil {
|
||||||
|
dst = NewTriDense(n, matrix.Lower, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(n, matrix.Lower)
|
||||||
|
}
|
||||||
// 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++ {
|
||||||
@@ -218,18 +223,25 @@ func (lu *LU) LTo(dst *TriDense) {
|
|||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
dst.mat.Data[i*dst.mat.Stride+i] = 1
|
dst.mat.Data[i*dst.mat.Stride+i] = 1
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTo extracts the upper triangular matrix from an LU factorization.
|
// UTo extracts the upper triangular matrix from an LU factorization.
|
||||||
func (lu *LU) UTo(dst *TriDense) {
|
// If dst is nil, a new matrix is allocated. The resulting U matrix is returned.
|
||||||
|
func (lu *LU) UTo(dst *TriDense) *TriDense {
|
||||||
_, n := lu.lu.Dims()
|
_, n := lu.lu.Dims()
|
||||||
dst.reuseAs(n, true)
|
if dst == nil {
|
||||||
|
dst = NewTriDense(n, matrix.Upper, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(n, matrix.Upper)
|
||||||
|
}
|
||||||
// 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++ {
|
||||||
dst.mat.Data[i*dst.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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permutation constructs an r×r permutation matrix with the given row swaps.
|
// Permutation constructs an r×r permutation matrix with the given row swaps.
|
||||||
|
|||||||
@@ -23,15 +23,13 @@ func TestLUD(t *testing.T) {
|
|||||||
var lu LU
|
var lu LU
|
||||||
lu.Factorize(a)
|
lu.Factorize(a)
|
||||||
|
|
||||||
var l, u TriDense
|
l := lu.LTo(nil)
|
||||||
lu.LTo(&l)
|
u := lu.UTo(nil)
|
||||||
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)
|
||||||
var got Dense
|
var got Dense
|
||||||
got.Mul(&p, &l)
|
got.Product(&p, l, u)
|
||||||
got.Mul(&got, &u)
|
|
||||||
if !EqualApprox(&got, &want, 1e-12) {
|
if !EqualApprox(&got, &want, 1e-12) {
|
||||||
t.Errorf("PLU does not equal original matrix.\nWant: %v\n Got: %v", want, got)
|
t.Errorf("PLU does not equal original matrix.\nWant: %v\n Got: %v", want, got)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,14 @@ func (qr *QR) Factorize(a Matrix) {
|
|||||||
// and upper triangular matrices.
|
// and upper triangular matrices.
|
||||||
|
|
||||||
// RTo extracts the m×n upper trapezoidal matrix from a QR decomposition.
|
// RTo extracts the m×n upper trapezoidal matrix from a QR decomposition.
|
||||||
func (qr *QR) RTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting dst matrix is returned.
|
||||||
|
func (qr *QR) RTo(dst *Dense) *Dense {
|
||||||
r, c := qr.qr.Dims()
|
r, c := qr.qr.Dims()
|
||||||
dst.reuseAs(r, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
// Disguise the QR as an upper triangular
|
// Disguise the QR as an upper triangular
|
||||||
t := &TriDense{
|
t := &TriDense{
|
||||||
@@ -82,12 +87,19 @@ func (qr *QR) RTo(dst *Dense) {
|
|||||||
for i := r; i < c; i++ {
|
for i := r; i < c; i++ {
|
||||||
zero(dst.mat.Data[i*dst.mat.Stride : i*dst.mat.Stride+c])
|
zero(dst.mat.Data[i*dst.mat.Stride : i*dst.mat.Stride+c])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// QTo extracts the m×m orthonormal matrix Q from a QR decomposition.
|
// QTo extracts the m×m orthonormal matrix Q from a QR decomposition.
|
||||||
func (qr *QR) QTo(dst *Dense) {
|
// If dst is nil, a new matrix is allocated. The resulting Q matrix is returned.
|
||||||
|
func (qr *QR) QTo(dst *Dense) *Dense {
|
||||||
r, _ := qr.qr.Dims()
|
r, _ := qr.qr.Dims()
|
||||||
dst.reuseAsZeroed(r, r)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, r, nil)
|
||||||
|
} else {
|
||||||
|
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 {
|
||||||
@@ -99,6 +111,8 @@ func (qr *QR) QTo(dst *Dense) {
|
|||||||
lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, dst.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, dst.mat, work, len(work))
|
lapack64.Ormqr(blas.Left, blas.NoTrans, qr.qr.mat, qr.tau, dst.mat, work, len(work))
|
||||||
|
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -32,17 +32,16 @@ func TestQR(t *testing.T) {
|
|||||||
|
|
||||||
var qr QR
|
var qr QR
|
||||||
qr.Factorize(a)
|
qr.Factorize(a)
|
||||||
var q, r Dense
|
q := qr.QTo(nil)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
qr.RTo(&r)
|
r := qr.RTo(nil)
|
||||||
|
|
||||||
var got Dense
|
var got Dense
|
||||||
got.Mul(&q, &r)
|
got.Mul(q, r)
|
||||||
if !EqualApprox(&got, &want, 1e-12) {
|
if !EqualApprox(&got, &want, 1e-12) {
|
||||||
t.Errorf("QR does not equal original matrix. \nWant: %v\nGot: %v", want, got)
|
t.Errorf("QR does not equal original matrix. \nWant: %v\nGot: %v", want, got)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,14 +141,18 @@ func (svd *SVD) Values(s []float64) []float64 {
|
|||||||
// UTo 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 dst. 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 UTo panics otherwise.
|
// of size m×min(m,n) if svd.Kind() == SVDThin, and UTo panics otherwise.
|
||||||
func (svd *SVD) UTo(dst *Dense) {
|
func (svd *SVD) UTo(dst *Dense) *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
|
||||||
dst.reuseAs(r, c)
|
if dst == nil {
|
||||||
|
dst = NewDense(r, c, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(r, c)
|
||||||
|
}
|
||||||
|
|
||||||
tmp := &Dense{
|
tmp := &Dense{
|
||||||
mat: svd.u,
|
mat: svd.u,
|
||||||
@@ -156,19 +160,25 @@ func (svd *SVD) UTo(dst *Dense) {
|
|||||||
capCols: c,
|
capCols: c,
|
||||||
}
|
}
|
||||||
dst.Copy(tmp)
|
dst.Copy(tmp)
|
||||||
|
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
// VTo 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 dst. 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 VTo panics otherwise.
|
// of size n×min(m,n) if svd.Kind() == SVDThin, and VTo panics otherwise.
|
||||||
func (svd *SVD) VTo(dst *Dense) {
|
func (svd *SVD) VTo(dst *Dense) *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
|
||||||
dst.reuseAs(c, r)
|
if dst == nil {
|
||||||
|
dst = NewDense(c, r, nil)
|
||||||
|
} else {
|
||||||
|
dst.reuseAs(c, r)
|
||||||
|
}
|
||||||
|
|
||||||
tmp := &Dense{
|
tmp := &Dense{
|
||||||
mat: svd.vt,
|
mat: svd.vt,
|
||||||
@@ -176,4 +186,6 @@ func (svd *SVD) VTo(dst *Dense) {
|
|||||||
capCols: c,
|
capCols: c,
|
||||||
}
|
}
|
||||||
dst.Copy(tmp.T())
|
dst.Copy(tmp.T())
|
||||||
|
|
||||||
|
return dst
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,9 +169,5 @@ 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
|
return svd.Values(nil), svd.UTo(nil), svd.VTo(nil)
|
||||||
svd.UTo(&um)
|
|
||||||
svd.VTo(&vm)
|
|
||||||
s = svd.Values(nil)
|
|
||||||
return s, &um, &vm
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user