Files
gonum/mat64/svd_test.go
kortschak b10f3a00f3 Change NewDense signature and behaviour
This is an API breaking change.

NewDense now panics if len(mat) != r*c, unless mat == nil. When mat is
nil a new, correctly sized slice is allocated.
2014-01-08 09:56:39 +10:30

141 lines
3.2 KiB
Go

// Copyright ©2013 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mat64
import (
check "launchpad.net/gocheck"
"math"
)
func (s *S) TestSVD(c *check.C) {
for _, t := range []struct {
a *Dense
epsilon float64
small float64
wantu bool
u *Dense
sigma []float64
wantv bool
v *Dense
}{
{
a: NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0}),
epsilon: math.Pow(2, -52.0),
small: math.Pow(2, -966.0),
wantu: true,
u: NewDense(4, 2, []float64{
0.8174155604703632, -0.5760484367663209,
0.5760484367663209, 0.8174155604703633,
0, 0,
0, 0,
}),
sigma: []float64{5.464985704219041, 0.365966190626258},
wantv: true,
v: NewDense(2, 2, []float64{
0.4045535848337571, -0.9145142956773044,
0.9145142956773044, 0.4045535848337571,
}),
},
{
a: NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0}),
epsilon: math.Pow(2, -52.0),
small: math.Pow(2, -966.0),
wantu: true,
u: NewDense(4, 2, []float64{
0.8174155604703632, -0.5760484367663209,
0.5760484367663209, 0.8174155604703633,
0, 0,
0, 0,
}),
sigma: []float64{5.464985704219041, 0.365966190626258},
wantv: false,
},
{
a: NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0}),
epsilon: math.Pow(2, -52.0),
small: math.Pow(2, -966.0),
wantu: false,
sigma: []float64{5.464985704219041, 0.365966190626258},
wantv: true,
v: NewDense(2, 2, []float64{
0.4045535848337571, -0.9145142956773044,
0.9145142956773044, 0.4045535848337571,
}),
},
{
a: NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0}),
epsilon: math.Pow(2, -52.0),
small: math.Pow(2, -966.0),
sigma: []float64{5.464985704219041, 0.365966190626258},
},
{
// FIXME(kortschak)
// This test will fail if t.sigma is set to the real expected values
// or if u and v are requested, due to a bug in the original Jama code
// forcing a to be a tall or square matrix.
//
// This is a failing case to use to fix that bug.
a: NewDense(3, 11, []float64{
1, 1, 0, 1, 0, 0, 0, 0, 0, 11, 1,
1, 0, 0, 0, 0, 0, 1, 0, 0, 12, 2,
1, 1, 0, 0, 0, 0, 0, 0, 1, 13, 3,
}),
epsilon: math.Pow(2, -52.0),
small: math.Pow(2, -966.0),
// FIXME(kortschak) sigma is one element longer than it should be.
sigma: []float64{21.25950088109745, 1.5415021616856577, 1.2873979074613637, 0},
},
} {
svd := SVD(DenseCopyOf(t.a), t.epsilon, t.small, t.wantu, t.wantv)
if t.sigma != nil {
c.Check(svd.Sigma, check.DeepEquals, t.sigma)
}
s := svd.S()
if svd.U != nil {
c.Check(svd.U.Equals(t.u), check.Equals, true)
} else {
c.Check(t.wantu, check.Equals, false)
c.Check(t.u, check.IsNil)
}
if svd.V != nil {
c.Check(svd.V.Equals(t.v), check.Equals, true)
} else {
c.Check(t.wantv, check.Equals, false)
c.Check(t.v, check.IsNil)
}
if t.wantu && t.wantv {
c.Assert(svd.U, check.NotNil)
c.Assert(svd.V, check.NotNil)
vt := &Dense{}
vt.TCopy(svd.V)
svd.U.Mul(svd.U, s)
svd.U.Mul(svd.U, vt)
c.Check(svd.U.EqualsApprox(t.a, 1e-12), check.Equals, true)
}
}
}