mirror of
https://github.com/gonum/gonum.git
synced 2025-10-25 08:10:28 +08:00
mat: disallow zero dimension results
This commit is contained in:
committed by
Dan Kortschak
parent
91face6738
commit
d1117c6f27
12
mat/dense.go
12
mat/dense.go
@@ -42,6 +42,9 @@ type Dense struct {
|
||||
// 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.
|
||||
func NewDense(r, c int, data []float64) *Dense {
|
||||
if r < 0 || c < 0 {
|
||||
panic("mat: negative dimension")
|
||||
}
|
||||
if data != nil && r*c != len(data) {
|
||||
panic(ErrShape)
|
||||
}
|
||||
@@ -69,6 +72,9 @@ func (m *Dense) reuseAs(r, c int) {
|
||||
// Panic as a string, not a mat.Error.
|
||||
panic("mat: caps not correctly set")
|
||||
}
|
||||
if r == 0 || c == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
if m.IsZero() {
|
||||
m.mat = blas64.General{
|
||||
Rows: r,
|
||||
@@ -95,6 +101,9 @@ func (m *Dense) reuseAsZeroed(r, c int) {
|
||||
// Panic as a string, not a mat.Error.
|
||||
panic("mat: caps not correctly set")
|
||||
}
|
||||
if r == 0 || c == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
if m.IsZero() {
|
||||
m.mat = blas64.General{
|
||||
Rows: r,
|
||||
@@ -129,6 +138,9 @@ func untranspose(a Matrix) (Matrix, bool) {
|
||||
// This should be used when a method receiver is the same pointer as an input argument.
|
||||
func (m *Dense) isolatedWorkspace(a Matrix) (w *Dense, restore func()) {
|
||||
r, c := a.Dims()
|
||||
if r == 0 || c == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
w = getWorkspace(r, c, false)
|
||||
return w, func() {
|
||||
m.Copy(w)
|
||||
|
||||
@@ -118,7 +118,7 @@ var (
|
||||
ErrRowAccess = Error{"matrix: row index out of range"}
|
||||
ErrColAccess = Error{"matrix: column index out of range"}
|
||||
ErrVectorAccess = Error{"matrix: vector index out of range"}
|
||||
ErrZeroLength = Error{"matrix: zero length in matrix definition"}
|
||||
ErrZeroLength = Error{"matrix: zero length in matrix dimension"}
|
||||
ErrRowLength = Error{"matrix: row length mismatch"}
|
||||
ErrColLength = Error{"matrix: col length mismatch"}
|
||||
ErrSquare = Error{"matrix: expect square matrix"}
|
||||
|
||||
12
mat/io.go
12
mat/io.go
@@ -127,6 +127,9 @@ func (m *Dense) UnmarshalBinary(data []byte) error {
|
||||
}
|
||||
|
||||
size := rows * cols
|
||||
if size == 0 {
|
||||
return ErrZeroLength
|
||||
}
|
||||
if int(size) < 0 || size > maxLen {
|
||||
return errTooBig
|
||||
}
|
||||
@@ -184,6 +187,9 @@ func (m *Dense) UnmarshalBinaryFrom(r io.Reader) (int, error) {
|
||||
}
|
||||
|
||||
size := rows * cols
|
||||
if size == 0 {
|
||||
return n, ErrZeroLength
|
||||
}
|
||||
if int(size) < 0 || size > maxLen {
|
||||
return n, errTooBig
|
||||
}
|
||||
@@ -274,6 +280,9 @@ func (v *VecDense) UnmarshalBinary(data []byte) error {
|
||||
|
||||
p := 0
|
||||
n := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
|
||||
if n == 0 {
|
||||
return ErrZeroLength
|
||||
}
|
||||
p += sizeInt64
|
||||
if n < 0 {
|
||||
return errBadSize
|
||||
@@ -315,6 +324,9 @@ func (v *VecDense) UnmarshalBinaryFrom(r io.Reader) (int, error) {
|
||||
return n, err
|
||||
}
|
||||
sz := int64(binary.LittleEndian.Uint64(buf[:]))
|
||||
if sz == 0 {
|
||||
return n, ErrZeroLength
|
||||
}
|
||||
if sz < 0 {
|
||||
return n, errBadSize
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@ var (
|
||||
var denseData = []struct {
|
||||
raw []byte
|
||||
want *Dense
|
||||
err error
|
||||
eq func(got, want Matrix) bool
|
||||
}{
|
||||
{
|
||||
raw: []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||
want: NewDense(0, 0, []float64{}),
|
||||
err: ErrZeroLength,
|
||||
eq: Equal,
|
||||
},
|
||||
{
|
||||
@@ -142,7 +144,9 @@ func TestDenseUnmarshal(t *testing.T) {
|
||||
var v Dense
|
||||
err := v.UnmarshalBinary(test.raw)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
if err != test.err {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !test.eq(&v, test.want) {
|
||||
@@ -161,7 +165,9 @@ func TestDenseUnmarshalFrom(t *testing.T) {
|
||||
buf := bytes.NewReader(test.raw)
|
||||
n, err := v.UnmarshalBinaryFrom(buf)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
if err != test.err {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if n != len(test.raw) {
|
||||
@@ -257,7 +263,10 @@ func TestDenseIORoundTrip(t *testing.T) {
|
||||
var got Dense
|
||||
err = got.UnmarshalBinary(buf)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding test #%d: %v\n", i, err)
|
||||
if err != test.err {
|
||||
t.Errorf("error decoding test #%d: %v\n", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !test.eq(&got, test.want) {
|
||||
@@ -291,11 +300,13 @@ func TestDenseIORoundTrip(t *testing.T) {
|
||||
var vectorData = []struct {
|
||||
raw []byte
|
||||
want *VecDense
|
||||
err error
|
||||
eq func(got, want Matrix) bool
|
||||
}{
|
||||
{
|
||||
raw: []byte("\x00\x00\x00\x00\x00\x00\x00\x00"),
|
||||
want: NewVecDense(0, []float64{}),
|
||||
err: ErrZeroLength,
|
||||
eq: Equal,
|
||||
},
|
||||
{
|
||||
@@ -414,7 +425,9 @@ func TestVecDenseUnmarshal(t *testing.T) {
|
||||
var v VecDense
|
||||
err := v.UnmarshalBinary(test.raw)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
if err != test.err {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !test.eq(&v, test.want) {
|
||||
@@ -433,7 +446,9 @@ func TestVecDenseUnmarshalFrom(t *testing.T) {
|
||||
buf := bytes.NewReader(test.raw)
|
||||
n, err := v.UnmarshalBinaryFrom(buf)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
if err != test.err {
|
||||
t.Errorf("error decoding test-%d: %v\n", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if n != len(test.raw) {
|
||||
@@ -519,7 +534,10 @@ func TestVecDenseIORoundTrip(t *testing.T) {
|
||||
var got VecDense
|
||||
err = got.UnmarshalBinary(buf)
|
||||
if err != nil {
|
||||
t.Errorf("error decoding test #%d: %v\n", i, err)
|
||||
if err != test.err {
|
||||
t.Errorf("error decoding test #%d: %v\n", i, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !test.eq(&got, test.want) {
|
||||
t.Errorf("r/w test #%d failed\n got=%#v\nwant=%#v\n", i, &got, test.want)
|
||||
|
||||
@@ -17,7 +17,6 @@ func TestQR(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
m, n int
|
||||
}{
|
||||
{0, 0}, // Check that there is no panic for zero-sized matrix.
|
||||
{5, 5},
|
||||
{10, 5},
|
||||
} {
|
||||
|
||||
@@ -138,6 +138,9 @@ func (s *SymDense) IsZero() bool {
|
||||
// reuseAs resizes an empty matrix to a n×n matrix,
|
||||
// or checks that a non-empty matrix is n×n.
|
||||
func (s *SymDense) reuseAs(n int) {
|
||||
if n == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
if s.mat.N > s.cap {
|
||||
panic(badSymCap)
|
||||
}
|
||||
@@ -161,6 +164,9 @@ func (s *SymDense) reuseAs(n int) {
|
||||
|
||||
func (s *SymDense) isolatedWorkspace(a Symmetric) (w *SymDense, restore func()) {
|
||||
n := a.Symmetric()
|
||||
if n == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
w = getWorkspaceSym(n, false)
|
||||
return w, func() {
|
||||
s.CopySym(w)
|
||||
|
||||
@@ -235,6 +235,9 @@ func untransposeTri(a Triangular) (Triangular, bool) {
|
||||
// orientation. If the receiver is non-zero, reuseAs checks that the receiver
|
||||
// is the correct size and orientation.
|
||||
func (t *TriDense) reuseAs(n int, kind TriKind) {
|
||||
if n == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
ul := blas.Lower
|
||||
if kind == Upper {
|
||||
ul = blas.Upper
|
||||
@@ -267,7 +270,7 @@ func (t *TriDense) reuseAs(n int, kind TriKind) {
|
||||
func (t *TriDense) isolatedWorkspace(a Triangular) (w *TriDense, restore func()) {
|
||||
n, kind := a.Triangle()
|
||||
if n == 0 {
|
||||
panic("zero size")
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
w = getWorkspaceTri(n, kind, false)
|
||||
return w, func() {
|
||||
|
||||
@@ -87,6 +87,9 @@ type VecDense struct {
|
||||
// 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.
|
||||
func NewVecDense(n int, data []float64) *VecDense {
|
||||
if n < 0 {
|
||||
panic("mat: negative dimension")
|
||||
}
|
||||
if len(data) != n && data != nil {
|
||||
panic(ErrShape)
|
||||
}
|
||||
@@ -633,6 +636,9 @@ func (v *VecDense) MulVec(a Matrix, b Vector) {
|
||||
// reuseAs resizes an empty vector to a r×1 vector,
|
||||
// or checks that a non-empty matrix is r×1.
|
||||
func (v *VecDense) reuseAs(r int) {
|
||||
if r == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
if v.IsZero() {
|
||||
v.mat = blas64.Vector{
|
||||
Inc: 1,
|
||||
@@ -656,6 +662,9 @@ func (v *VecDense) IsZero() bool {
|
||||
|
||||
func (v *VecDense) isolatedWorkspace(a Vector) (n *VecDense, restore func()) {
|
||||
l := a.Len()
|
||||
if l == 0 {
|
||||
panic(ErrZeroLength)
|
||||
}
|
||||
n = getWorkspaceVec(l, false)
|
||||
return n, func() {
|
||||
v.CopyVec(n)
|
||||
|
||||
Reference in New Issue
Block a user