mat: disallow New calls with zero length

This commit is contained in:
Dan Kortschak
2018-11-20 17:35:34 +10:30
committed by Dan Kortschak
parent d41320af1e
commit 3b99883391
11 changed files with 60 additions and 17 deletions

View File

@@ -107,6 +107,7 @@ func (t TransposeBand) UntransposeBand() Banded {
// BandDense will be reflected in data. If neither of these is true, NewBandDense // BandDense will be reflected in data. If neither of these is true, NewBandDense
// will panic. kl must be at least zero and less r, and ku must be at least zero and // will panic. kl must be at least zero and less r, and ku must be at least zero and
// less than c, otherwise NewBandDense will panic. // less than c, otherwise NewBandDense will panic.
// NewBandDense will panic if either r or c is zero.
// //
// The data must be arranged in row-major order constructed by removing the zeros // The data must be arranged in row-major order constructed by removing the zeros
// from the rows outside the band and aligning the diagonals. For example, the matrix // from the rows outside the band and aligning the diagonals. For example, the matrix
@@ -126,7 +127,10 @@ func (t TransposeBand) UntransposeBand() Banded {
// which is passed to NewBandDense as []float64{*, 1, 2, 3, 4, ...} with kl=1 and ku=2. // which is passed to NewBandDense as []float64{*, 1, 2, 3, 4, ...} with kl=1 and ku=2.
// Only the values in the band portion of the matrix are used. // Only the values in the band portion of the matrix are used.
func NewBandDense(r, c, kl, ku int, data []float64) *BandDense { func NewBandDense(r, c, kl, ku int, data []float64) *BandDense {
if r < 0 || c < 0 || kl < 0 || ku < 0 { if r <= 0 || c <= 0 || kl < 0 || ku < 0 {
if r == 0 || c == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if kl+1 > r || ku+1 > c { if kl+1 > r || ku+1 > c {

View File

@@ -38,11 +38,15 @@ type Dense struct {
// a new slice is allocated for the backing slice. If len(data) == r*c, data is // a new slice is allocated for the backing slice. If len(data) == r*c, data is
// used as the backing slice, and changes to the elements of the returned Dense // used as the backing slice, and changes to the elements of the returned Dense
// will be reflected in data. If neither of these is true, NewDense will panic. // will be reflected in data. If neither of these is true, NewDense will panic.
// NewDense will panic if either r or c is zero.
// //
// The data must be arranged in row-major order, i.e. the (i*c + j)-th // The data must be arranged in row-major order, i.e. the (i*c + j)-th
// element in the data slice is the {i, j}-th element in the matrix. // element in the data slice is the {i, j}-th element in the matrix.
func NewDense(r, c int, data []float64) *Dense { func NewDense(r, c int, data []float64) *Dense {
if r < 0 || c < 0 { if r <= 0 || c <= 0 {
if r == 0 || c == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if data != nil && r*c != len(data) { if data != nil && r*c != len(data) {

View File

@@ -42,9 +42,12 @@ type DiagDense struct {
// NewDiagonal creates a new Diagonal matrix with n rows and n columns. // NewDiagonal creates a new Diagonal matrix with n rows and n columns.
// The length of data must be n or data must be nil, otherwise NewDiagonal // The length of data must be n or data must be nil, otherwise NewDiagonal
// will panic. // will panic. NewDiagonal will panic if n is zero.
func NewDiagonal(n int, data []float64) *DiagDense { func NewDiagonal(n int, data []float64) *DiagDense {
if n < 0 { if n <= 0 {
if n == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if data == nil { if data == nil {

View File

@@ -30,7 +30,7 @@ var denseData = []struct {
}{ }{
{ {
raw: []byte("\x01\x00\x00\x00GFA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), raw: []byte("\x01\x00\x00\x00GFA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
want: NewDense(0, 0, []float64{}), want: &Dense{},
err: ErrZeroLength, err: ErrZeroLength,
eq: Equal, eq: Equal,
}, },
@@ -305,7 +305,7 @@ var vectorData = []struct {
}{ }{
{ {
raw: []byte("\x01\x00\x00\x00GFA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), raw: []byte("\x01\x00\x00\x00GFA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
want: NewVecDense(0, []float64{}), want: &VecDense{},
err: ErrZeroLength, err: ErrZeroLength,
eq: Equal, eq: Equal,
}, },

View File

@@ -315,7 +315,10 @@ func makeRandOf(a Matrix, m, n int) Matrix {
case Untransposer: case Untransposer:
rMatrix = retranspose(a, makeRandOf(t.Untranspose(), n, m)) rMatrix = retranspose(a, makeRandOf(t.Untranspose(), n, m))
case *Dense, *basicMatrix: case *Dense, *basicMatrix:
mat := NewDense(m, n, nil) var mat = &Dense{}
if m != 0 && n != 0 {
mat = NewDense(m, n, nil)
}
for i := 0; i < m; i++ { for i := 0; i < m; i++ {
for j := 0; j < n; j++ { for j := 0; j < n; j++ {
mat.Set(i, j, rand.NormFloat64()) mat.Set(i, j, rand.NormFloat64())
@@ -363,7 +366,10 @@ func makeRandOf(a Matrix, m, n int) Matrix {
if m != n { if m != n {
panic("bad size") panic("bad size")
} }
mat := NewSymDense(n, nil) mat := &SymDense{}
if n != 0 {
mat = NewSymDense(n, nil)
}
for i := 0; i < m; i++ { for i := 0; i < m; i++ {
for j := i; j < n; j++ { for j := i; j < n; j++ {
mat.SetSym(i, j, rand.NormFloat64()) mat.SetSym(i, j, rand.NormFloat64())
@@ -386,6 +392,14 @@ func makeRandOf(a Matrix, m, n int) Matrix {
triKind = (*TriDense)(t).triKind() triKind = (*TriDense)(t).triKind()
} }
if n == 0 {
uplo := blas.Upper
if triKind == Lower {
uplo = blas.Lower
}
return returnAs(&TriDense{mat: blas64.Triangular{Uplo: uplo}}, t)
}
mat := NewTriDense(n, triKind, nil) mat := NewTriDense(n, triKind, nil)
if triKind == Upper { if triKind == Upper {
for i := 0; i < m; i++ { for i := 0; i < m; i++ {
@@ -604,7 +618,7 @@ var testMatrices = []Matrix{
&SymDense{}, &SymDense{},
NewTriDense(3, true, nil), NewTriDense(3, true, nil),
NewTriDense(3, false, nil), NewTriDense(3, false, nil),
NewVecDense(0, nil), &VecDense{mat: blas64.Vector{Inc: 1}},
&DiagDense{}, &DiagDense{},
&basicVector{}, &basicVector{},
&VecDense{mat: blas64.Vector{Inc: 10}}, &VecDense{mat: blas64.Vector{Inc: 10}},
@@ -618,7 +632,7 @@ var testMatrices = []Matrix{
TransposeTri{NewTriDense(3, true, nil)}, TransposeTri{NewTriDense(3, true, nil)},
Transpose{NewTriDense(3, false, nil)}, Transpose{NewTriDense(3, false, nil)},
TransposeTri{NewTriDense(3, false, nil)}, TransposeTri{NewTriDense(3, false, nil)},
Transpose{NewVecDense(0, nil)}, Transpose{&VecDense{mat: blas64.Vector{Inc: 1}}},
Transpose{&VecDense{mat: blas64.Vector{Inc: 10}}}, Transpose{&VecDense{mat: blas64.Vector{Inc: 10}}},
Transpose{&DiagDense{}}, Transpose{&DiagDense{}},
TransposeTri{&DiagDense{}}, TransposeTri{&DiagDense{}},

View File

@@ -97,7 +97,7 @@ func TestMulTypes(t *testing.T) {
// Check that it panics if it is supposed to // Check that it panics if it is supposed to
if test.Panics { if test.Panics {
c := NewDense(0, 0, nil) c := &Dense{}
fn := func() { fn := func() {
c.Mul(a, b) c.Mul(a, b)
} }
@@ -125,7 +125,7 @@ func TestMulTypes(t *testing.T) {
ccomp := matComp{r: ar, c: bc, data: cvecCopy} ccomp := matComp{r: ar, c: bc, data: cvecCopy}
// Do normal multiply with empty dense // Do normal multiply with empty dense
d := NewDense(0, 0, nil) d := &Dense{}
testMul(t, a, b, d, acomp, bcomp, ccomp, false, "zero receiver") testMul(t, a, b, d, acomp, bcomp, ccomp, false, "zero receiver")

View File

@@ -126,7 +126,10 @@ func TestProduct(t *testing.T) {
} }
} }
got := NewDense(test.product.r, test.product.c, nil) got := &Dense{}
if test.product.r != 0 && test.product.c != 0 {
got = NewDense(test.product.r, test.product.c, nil)
}
panicked, message := panics(func() { panicked, message := panics(func() {
got.Product(factors...) got.Product(factors...)
}) })

View File

@@ -67,7 +67,10 @@ type RawSymBander interface {
// which is passed to NewBandDense as []float64{1, 2, 3, 4, ...} with k=2. // which is passed to NewBandDense as []float64{1, 2, 3, 4, ...} with k=2.
// Only the values in the band portion of the matrix are used. // Only the values in the band portion of the matrix are used.
func NewSymBandDense(n, k int, data []float64) *SymBandDense { func NewSymBandDense(n, k int, data []float64) *SymBandDense {
if n < 0 || k < 0 { if n <= 0 || k < 0 {
if n == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if k+1 > n { if k+1 > n {

View File

@@ -55,12 +55,16 @@ type MutableSymmetric interface {
// a new slice is allocated for the backing slice. If len(data) == n*n, data is // a new slice is allocated for the backing slice. If len(data) == n*n, data is
// used as the backing slice, and changes to the elements of the returned SymDense // used as the backing slice, and changes to the elements of the returned SymDense
// will be reflected in data. If neither of these is true, NewSymDense will panic. // will be reflected in data. If neither of these is true, NewSymDense will panic.
// NewSymDense will panic if n is zero.
// //
// The data must be arranged in row-major order, i.e. the (i*c + j)-th // The data must be arranged in row-major order, i.e. the (i*c + j)-th
// element in the data slice is the {i, j}-th element in the matrix. // element in the data slice is the {i, j}-th element in the matrix.
// Only the values in the upper triangular portion of the matrix are used. // Only the values in the upper triangular portion of the matrix are used.
func NewSymDense(n int, data []float64) *SymDense { func NewSymDense(n int, data []float64) *SymDense {
if n < 0 { if n <= 0 {
if n == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if data != nil && n*n != len(data) { if data != nil && n*n != len(data) {

View File

@@ -111,12 +111,16 @@ func (t TransposeTri) UntransposeTri() Triangular {
// a new slice is allocated for the backing slice. If len(data) == n*n, data is // a new slice is allocated for the backing slice. If len(data) == n*n, data is
// used as the backing slice, and changes to the elements of the returned TriDense // used as the backing slice, and changes to the elements of the returned TriDense
// will be reflected in data. If neither of these is true, NewTriDense will panic. // will be reflected in data. If neither of these is true, NewTriDense will panic.
// NewTriDense will panic if n is zero.
// //
// The data must be arranged in row-major order, i.e. the (i*c + j)-th // The data must be arranged in row-major order, i.e. the (i*c + j)-th
// element in the data slice is the {i, j}-th element in the matrix. // element in the data slice is the {i, j}-th element in the matrix.
// Only the values in the triangular portion corresponding to kind are used. // Only the values in the triangular portion corresponding to kind are used.
func NewTriDense(n int, kind TriKind, data []float64) *TriDense { func NewTriDense(n int, kind TriKind, data []float64) *TriDense {
if n < 0 { if n <= 0 {
if n == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if data != nil && len(data) != n*n { if data != nil && len(data) != n*n {

View File

@@ -86,8 +86,12 @@ type VecDense struct {
// a new slice is allocated for the backing slice. If len(data) == n, data is // a new slice is allocated for the backing slice. If len(data) == n, data is
// used as the backing slice, and changes to the elements of the returned VecDense // used as the backing slice, and changes to the elements of the returned VecDense
// will be reflected in data. If neither of these is true, NewVecDense will panic. // will be reflected in data. If neither of these is true, NewVecDense will panic.
// NewVecDense will panic if n is zero.
func NewVecDense(n int, data []float64) *VecDense { func NewVecDense(n int, data []float64) *VecDense {
if n < 0 { if n <= 0 {
if n == 0 {
panic(ErrZeroLength)
}
panic("mat: negative dimension") panic("mat: negative dimension")
} }
if len(data) != n && data != nil { if len(data) != n && data != nil {