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.
This commit is contained in:
kortschak
2014-01-08 09:56:39 +10:30
parent fadcd6dd7f
commit b10f3a00f3
13 changed files with 87 additions and 112 deletions

View File

@@ -21,7 +21,7 @@ func Cholesky(a *Dense) CholeskyFactor {
// Initialize.
m, n := a.Dims()
spd := m == n
l, _ := NewDense(n, n, make([]float64, n*n))
l := NewDense(n, n, nil)
// Main loop.
lRowj := make([]float64, n)
@@ -59,7 +59,7 @@ func CholeskyR(a *Dense) (r *Dense, spd bool) {
// Initialize.
m, n := a.Dims()
spd = m == n
r, _ = NewDense(n, n, make([]float64, n*n))
r = NewDense(n, n, nil)
// Main loop.
for j := 0; j < n; j++ {

View File

@@ -14,11 +14,11 @@ func (s *S) TestCholesky(c *check.C) {
spd bool
}{
{
a: mustDense(NewDense(3, 3, []float64{
a: NewDense(3, 3, []float64{
4, 1, 1,
1, 2, 3,
1, 3, 6,
})),
}),
spd: true,
},

View File

@@ -62,9 +62,12 @@ type Dense struct {
mat BlasMatrix
}
func NewDense(r, c int, mat []float64) (*Dense, error) {
if r*c != len(mat) {
return nil, ErrShape
func NewDense(r, c int, mat []float64) *Dense {
if mat != nil && r*c != len(mat) {
panic(ErrShape)
}
if mat == nil {
mat = make([]float64, r*c)
}
return &Dense{BlasMatrix{
Order: BlasOrder,
@@ -72,7 +75,7 @@ func NewDense(r, c int, mat []float64) (*Dense, error) {
Cols: c,
Stride: c,
Data: mat,
}}, nil
}}
}
// DenseCopyOf returns a newly allocated copy of the elements of a.

View File

@@ -359,7 +359,7 @@ func orthes(a *Dense) (hess, v *Dense) {
}
// Accumulate transformations (Algol's ortran).
v, _ = NewDense(n, n, make([]float64, n*n))
v = NewDense(n, n, nil)
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if i == j {
@@ -811,7 +811,7 @@ func (f EigenFactors) D() *Dense {
if n = len(d); n != len(e) {
panic(ErrSquare)
}
dm, _ := NewDense(n, n, make([]float64, n*n))
dm := NewDense(n, n, nil)
for i := 0; i < n; i++ {
dm.Set(i, i, d[i])
if e[i] > 0 {

View File

@@ -19,66 +19,66 @@ func (s *S) TestEigen(c *check.C) {
v *Dense
}{
{
a: mustDense(NewDense(3, 3, []float64{
a: NewDense(3, 3, []float64{
1, 2, 1,
6, -1, 0,
-1, -2, -1,
})),
}),
epsilon: math.Pow(2, -52.0),
d: []float64{3.0000000000000044, -4.000000000000003, -1.0980273383714707e-16},
e: []float64{0, 0, 0},
v: mustDense(NewDense(3, 3, []float64{
v: NewDense(3, 3, []float64{
-0.48507125007266627, 0.41649656391752204, 0.11785113019775795,
-0.7276068751089995, -0.8329931278350428, 0.7071067811865481,
0.48507125007266627, -0.4164965639175216, -1.5320646925708532,
})),
}),
},
{
a: mustDense(NewDense(3, 3, []float64{
a: NewDense(3, 3, []float64{
1, 6, -1,
6, -1, -2,
-1, -2, -1,
})),
}),
epsilon: math.Pow(2, -52.0),
d: []float64{-6.240753470718579, -1.3995889142010132, 6.640342384919599},
e: []float64{0, 0, 0},
v: mustDense(NewDense(3, 3, []float64{
v: NewDense(3, 3, []float64{
-0.6134279348516111, -0.31411097261113, -0.7245967607083111,
0.7697297716508223, -0.03251534945303795, -0.6375412384185983,
0.17669818159240022, -0.9488293044247931, 0.2617263908869383,
})),
}),
},
{ // Jama pvals
a: mustDense(NewDense(3, 3, []float64{
a: NewDense(3, 3, []float64{
4, 1, 1,
1, 2, 3,
1, 3, 6,
})),
}),
epsilon: math.Pow(2, -52.0),
},
{ // Jama evals
a: mustDense(NewDense(4, 4, []float64{
a: NewDense(4, 4, []float64{
0, 1, 0, 0,
1, 0, 2e-7, 0,
0, -2e-7, 0, 1,
0, 0, 1, 0,
})),
}),
epsilon: math.Pow(2, -52.0),
},
{ // Jama badeigs
a: mustDense(NewDense(5, 5, []float64{
a: NewDense(5, 5, []float64{
0, 0, 0, 0, 0,
0, 0, 0, 0, 1,
0, 0, 0, 1, 0,
1, 1, 0, 0, 1,
1, 0, 1, 0, 1,
})),
}),
epsilon: math.Pow(2, -52.0),
},

View File

@@ -173,7 +173,7 @@ func (f LUFactors) IsSingular() bool {
func (f LUFactors) L() *Dense {
lu := f.LU
m, n := lu.Dims()
l, _ := NewDense(m, n, make([]float64, m*n))
l := NewDense(m, n, nil)
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if i > j {
@@ -190,7 +190,7 @@ func (f LUFactors) L() *Dense {
func (f LUFactors) U() *Dense {
lu := f.LU
m, n := lu.Dims()
u, _ := NewDense(m, n, make([]float64, m*n))
u := NewDense(m, n, nil)
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if i <= j {

View File

@@ -19,22 +19,22 @@ func (s *S) TestLUD(c *check.C) {
sign int
}{
{ // This is a hard coded equivalent of the approach used in the Jama LU test.
a: mustDense(NewDense(3, 3, []float64{
a: NewDense(3, 3, []float64{
0, 2, 3,
4, 5, 6,
7, 8, 9,
})),
}),
l: mustDense(NewDense(3, 3, []float64{
l: NewDense(3, 3, []float64{
1, 0, 0,
0, 1, 0,
0.5714285714285714, 0.2142857142857144, 1,
})),
u: mustDense(NewDense(3, 3, []float64{
}),
u: NewDense(3, 3, []float64{
7, 8, 9,
0, 2, 3,
0, 0, 0.2142857142857144,
})),
}),
pivot: []int{
2, // 0 0 1
0, // 1 0 0
@@ -78,22 +78,22 @@ func (s *S) TestLUDGaussian(c *check.C) {
sign int
}{
{ // This is a hard coded equivalent of the approach used in the Jama LU test.
a: mustDense(NewDense(3, 3, []float64{
a: NewDense(3, 3, []float64{
0, 2, 3,
4, 5, 6,
7, 8, 9,
})),
}),
l: mustDense(NewDense(3, 3, []float64{
l: NewDense(3, 3, []float64{
1, 0, 0,
0, 1, 0,
0.5714285714285714, 0.2142857142857144, 1,
})),
u: mustDense(NewDense(3, 3, []float64{
}),
u: NewDense(3, 3, []float64{
7, 8, 9,
0, 2, 3,
0, 0, 0.2142857142857144,
})),
}),
pivot: []int{
2, // 0 0 1
0, // 1 0 0

View File

@@ -289,7 +289,7 @@ func Inverse(a Matrix) *Dense {
for i := 0; i < m*m; i += m + 1 {
d[i] = 1
}
eye, _ := NewDense(m, m, d)
eye := NewDense(m, m, d)
return Solve(a, eye)
}

View File

@@ -46,19 +46,12 @@ func unflatten(r, c int, d []float64) [][]float64 {
return m
}
func mustDense(m *Dense, err error) *Dense {
if err != nil {
panic(err)
}
return m
}
func eye() *Dense {
return mustDense(NewDense(3, 3, []float64{
return NewDense(3, 3, []float64{
1, 0, 0,
0, 1, 0,
0, 0, 1,
}))
})
}
func (s *S) TestMaybe(c *check.C) {
@@ -185,8 +178,7 @@ func (s *S) TestNewDense(c *check.C) {
}},
},
} {
m, err := NewDense(test.rows, test.cols, test.a)
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
m := NewDense(test.rows, test.cols, test.a)
rows, cols := m.Dims()
c.Check(rows, check.Equals, test.rows, check.Commentf("Test %d", i))
c.Check(cols, check.Equals, test.cols, check.Commentf("Test %d", i))
@@ -204,8 +196,7 @@ func (s *S) TestRowCol(c *check.C) {
{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}},
{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
} {
a, err := NewDense(flatten(af))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(af))
for ri, row := range af {
c.Check(a.Row(nil, ri), check.DeepEquals, row, check.Commentf("Test %d", i))
}
@@ -220,14 +211,13 @@ func (s *S) TestRowCol(c *check.C) {
}
func (s *S) TestSetRowColumn(c *check.C) {
for i, as := range [][][]float64{
for _, as := range [][][]float64{
{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}},
{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}},
{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
} {
for ri, row := range as {
a, err := NewDense(flatten(as))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(as))
t := &Dense{}
t.Clone(a)
a.SetRow(ri, make([]float64, a.mat.Cols))
@@ -236,8 +226,7 @@ func (s *S) TestSetRowColumn(c *check.C) {
}
for ci := range as[0] {
a, err := NewDense(flatten(as))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(as))
t := &Dense{}
t.Clone(a)
a.SetCol(ci, make([]float64, a.mat.Rows))
@@ -281,12 +270,9 @@ func (s *S) TestAdd(c *check.C) {
[][]float64{{2, 4, 6}, {8, 10, 12}},
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
b, err := NewDense(flatten(test.b))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
r, err := NewDense(flatten(test.r))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
b := NewDense(flatten(test.b))
r := NewDense(flatten(test.r))
temp := &Dense{}
temp.Add(a, b)
@@ -338,12 +324,9 @@ func (s *S) TestSub(c *check.C) {
[][]float64{{0, 0, 0}, {0, 0, 0}},
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
b, err := NewDense(flatten(test.b))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
r, err := NewDense(flatten(test.r))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
b := NewDense(flatten(test.b))
r := NewDense(flatten(test.r))
temp := &Dense{}
temp.Sub(a, b)
@@ -395,12 +378,9 @@ func (s *S) TestMulElem(c *check.C) {
[][]float64{{1, 4, 9}, {16, 25, 36}},
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
b, err := NewDense(flatten(test.b))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
r, err := NewDense(flatten(test.r))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
b := NewDense(flatten(test.b))
r := NewDense(flatten(test.r))
temp := &Dense{}
temp.MulElem(a, b)
@@ -457,12 +437,9 @@ func (s *S) TestMul(c *check.C) {
[][]float64{{0, 2, 2}, {0, 2, 2}, {0, 2, 2}},
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
b, err := NewDense(flatten(test.b))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
r, err := NewDense(flatten(test.r))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
b := NewDense(flatten(test.b))
r := NewDense(flatten(test.r))
temp := &Dense{}
temp.Mul(a, b)
@@ -587,10 +564,8 @@ func (s *S) TestTranspose(c *check.C) {
[][]float64{{1, 4}, {2, 5}, {3, 6}},
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
t, err := NewDense(flatten(test.t))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
t := NewDense(flatten(test.t))
var r, rr Dense
@@ -652,8 +627,7 @@ func (s *S) TestNorm(c *check.C) {
norm: 6,
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
c.Check(a.Norm(test.ord), check.Equals, test.norm, check.Commentf("Test %d: %v norm = %f", i, test.a, test.norm))
}
}
@@ -716,10 +690,8 @@ func (s *S) TestApply(c *check.C) {
},
},
} {
a, err := NewDense(flatten(test.a))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
t, err := NewDense(flatten(test.t))
c.Assert(err, check.Equals, nil, check.Commentf("Test %d", i))
a := NewDense(flatten(test.a))
t := NewDense(flatten(test.t))
var r Dense

View File

@@ -80,7 +80,7 @@ func (f QRFactor) IsFullRank() bool {
func (f QRFactor) H() *Dense {
qr := f.QR
m, n := qr.Dims()
h, _ := NewDense(m, n, make([]float64, m*n))
h := NewDense(m, n, nil)
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if i >= j {
@@ -95,7 +95,7 @@ func (f QRFactor) H() *Dense {
func (f QRFactor) R() *Dense {
qr, rDiag := f.QR, f.rDiag
_, n := qr.Dims()
r, _ := NewDense(n, n, make([]float64, n*n))
r := NewDense(n, n, nil)
for i, v := range rDiag[:n] {
for j := 0; j < n; j++ {
if i < j {
@@ -112,7 +112,7 @@ func (f QRFactor) R() *Dense {
func (f QRFactor) Q() *Dense {
qr := f.QR
m, n := qr.Dims()
q, _ := NewDense(m, n, make([]float64, m*n))
q := NewDense(m, n, nil)
for k := n - 1; k >= 0; k-- {
// for i := 0; i < m; i++ {

View File

@@ -13,7 +13,7 @@ func (s *S) TestQRD(c *check.C) {
a *Dense
}{
{
a: mustDense(NewDense(4, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})),
a: NewDense(4, 3, []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}),
},
} {
qf := QR(DenseCopyOf(t.a))

View File

@@ -40,10 +40,10 @@ func SVD(a *Dense, epsilon, small float64, wantu, wantv bool) SVDFactors {
nu := min(m, n)
var u, v *Dense
if wantu {
u, _ = NewDense(m, nu, make([]float64, m*nu))
u = NewDense(m, nu, nil)
}
if wantv {
v, _ = NewDense(n, n, make([]float64, n*n))
v = NewDense(n, n, nil)
}
var (
@@ -431,7 +431,7 @@ func SVD(a *Dense, epsilon, small float64, wantu, wantv bool) SVDFactors {
// S returns a newly allocated S matrix from the sigma values held by the
// factorisation.
func (f SVDFactors) S() *Dense {
s, _ := NewDense(len(f.Sigma), len(f.Sigma), make([]float64, len(f.Sigma)*len(f.Sigma)))
s := NewDense(len(f.Sigma), len(f.Sigma), nil)
for i, v := range f.Sigma {
s.Set(i, i, v)
}

View File

@@ -25,47 +25,47 @@ func (s *S) TestSVD(c *check.C) {
v *Dense
}{
{
a: mustDense(NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0})),
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: mustDense(NewDense(4, 2, []float64{
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: mustDense(NewDense(2, 2, []float64{
v: NewDense(2, 2, []float64{
0.4045535848337571, -0.9145142956773044,
0.9145142956773044, 0.4045535848337571,
})),
}),
},
{
a: mustDense(NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0})),
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: mustDense(NewDense(4, 2, []float64{
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: mustDense(NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0})),
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),
@@ -75,13 +75,13 @@ func (s *S) TestSVD(c *check.C) {
sigma: []float64{5.464985704219041, 0.365966190626258},
wantv: true,
v: mustDense(NewDense(2, 2, []float64{
v: NewDense(2, 2, []float64{
0.4045535848337571, -0.9145142956773044,
0.9145142956773044, 0.4045535848337571,
})),
}),
},
{
a: mustDense(NewDense(4, 2, []float64{2, 4, 1, 3, 0, 0, 0, 0})),
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),
@@ -95,11 +95,11 @@ func (s *S) TestSVD(c *check.C) {
// forcing a to be a tall or square matrix.
//
// This is a failing case to use to fix that bug.
a: mustDense(NewDense(3, 11, []float64{
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),