diff --git a/mat/cholesky.go b/mat/cholesky.go index 3b0c2b02..68454d95 100644 --- a/mat/cholesky.go +++ b/mat/cholesky.go @@ -475,5 +475,5 @@ func (c *Cholesky) isZero() bool { } func (c *Cholesky) valid() bool { - return !c.isZero() && !c.chol.isZero() + return !c.isZero() && !c.chol.IsZero() } diff --git a/mat/dense.go b/mat/dense.go index d78c329c..5b7f6097 100644 --- a/mat/dense.go +++ b/mat/dense.go @@ -69,7 +69,7 @@ func (m *Dense) reuseAs(r, c int) { // Panic as a string, not a mat.Error. panic("mat: caps not correctly set") } - if m.isZero() { + if m.IsZero() { m.mat = blas64.General{ Rows: r, Cols: c, @@ -95,7 +95,7 @@ func (m *Dense) reuseAsZeroed(r, c int) { // Panic as a string, not a mat.Error. panic("mat: caps not correctly set") } - if m.isZero() { + if m.IsZero() { m.mat = blas64.General{ Rows: r, Cols: c, @@ -147,7 +147,9 @@ func (m *Dense) Reset() { m.mat.Data = m.mat.Data[:0] } -func (m *Dense) isZero() bool { +// IsZero returns whether the receiver is zero-sized. Zero-sized matrices can be the +// receiver for size-restricted operations. Dense matrices can be zeroed using Reset. +func (m *Dense) IsZero() bool { // It must be the case that m.Dims() returns // zeros in this case. See comment in Reset(). return m.mat.Stride == 0 diff --git a/mat/dense_arithmetic.go b/mat/dense_arithmetic.go index f3ab5c00..1f49d65f 100644 --- a/mat/dense_arithmetic.go +++ b/mat/dense_arithmetic.go @@ -467,7 +467,7 @@ func (m *Dense) Exp(a Matrix) { } var w *Dense - if m.isZero() { + if m.IsZero() { m.reuseAsZeroed(r, r) w = m } else { @@ -696,7 +696,7 @@ func (m *Dense) Outer(alpha float64, x, y *Vector) { // Panic as a string, not a mat.Error. panic("mat: caps not correctly set") } - if m.isZero() { + if m.IsZero() { m.mat = blas64.General{ Rows: r, Cols: c, diff --git a/mat/doc.go b/mat/doc.go index a27a41bc..5a5cd9c7 100644 --- a/mat/doc.go +++ b/mat/doc.go @@ -36,10 +36,23 @@ // zero.Copy(a) // // Receivers must be the correct size for the matrix operations, otherwise the -// operation will panic. As a special case for convenience, a zero-sized matrix +// operation will panic. As a special case for convenience, a zero-value matrix // will be modified to have the correct size, allocating data if necessary. // var c mat.Dense // construct a new zero-sized matrix -// c.Mul(a, a) // c is automatically adjusted to be 6×6 +// c.Mul(a, a) // c is automatically adjusted to be 6×6 +// +// Zero-value of a matrix +// +// A zero-value matrix is either the Go language definition of a zero-value or +// is a zero-sized matrix with zero-length stride. Matrix implementations may have +// a Reset method to revert the receiver into a zero-valued matrix and an IsZero +// method that returns whether the matrix is zero-valued. +// So the following will all result in a zero-value matrix. +// - var a mat.Dense +// - a := NewDense(0, 0, make([]float64, 0, 100)) +// - a.Reset() +// A zero-value matrix can not be sliced even if it does have an adequately sized +// backing data slice, but can be expanded using its Grow method if it exists. // // The Matrix Interfaces // diff --git a/mat/io.go b/mat/io.go index d1c4c853..bcf32bcb 100644 --- a/mat/io.go +++ b/mat/io.go @@ -109,7 +109,7 @@ func (m Dense) MarshalBinaryTo(w io.Writer) (int, error) { // UnmarshalBinary does not limit the size of the unmarshaled matrix, and so // it should not be used on untrusted data. func (m *Dense) UnmarshalBinary(data []byte) error { - if !m.isZero() { + if !m.IsZero() { panic("mat: unmarshal into non-zero matrix") } @@ -158,7 +158,7 @@ func (m *Dense) UnmarshalBinary(data []byte) error { // UnmarshalBinary does not limit the size of the unmarshaled matrix, and so // it should not be used on untrusted data. func (m *Dense) UnmarshalBinaryFrom(r io.Reader) (int, error) { - if !m.isZero() { + if !m.IsZero() { panic("mat: unmarshal into non-zero matrix") } @@ -268,7 +268,7 @@ func (v Vector) MarshalBinaryTo(w io.Writer) (int, error) { // UnmarshalBinary does not limit the size of the unmarshaled vector, and so // it should not be used on untrusted data. func (v *Vector) UnmarshalBinary(data []byte) error { - if !v.isZero() { + if !v.IsZero() { panic("mat: unmarshal into non-zero vector") } @@ -301,7 +301,7 @@ func (v *Vector) UnmarshalBinary(data []byte) error { // See MarshalBinary for the on-disk layout. // See UnmarshalBinary for the list of sanity checks performed on the input. func (v *Vector) UnmarshalBinaryFrom(r io.Reader) (int, error) { - if !v.isZero() { + if !v.IsZero() { panic("mat: unmarshal into non-zero vector") } diff --git a/mat/product.go b/mat/product.go index dde0bff1..5a0343b7 100644 --- a/mat/product.go +++ b/mat/product.go @@ -71,7 +71,7 @@ func newMultiplier(m *Dense, factors []Matrix) *multiplier { // allocate data for m. r, c := m.Dims() fr, fc := factors[0].Dims() // newMultiplier is only called with len(factors) > 2. - if !m.isZero() { + if !m.IsZero() { if fr != r { panic(ErrShape) } diff --git a/mat/symmetric.go b/mat/symmetric.go index ee99a520..bf1fd571 100644 --- a/mat/symmetric.go +++ b/mat/symmetric.go @@ -126,7 +126,9 @@ func (s *SymDense) Reset() { s.mat.Data = s.mat.Data[:0] } -func (s *SymDense) isZero() bool { +// IsZero returns whether the receiver is zero-sized. Zero-sized matrices can be the +// receiver for size-restricted operations. SymDense matrices can be zeroed using Reset. +func (s *SymDense) IsZero() bool { // It must be the case that m.Dims() returns // zeros in this case. See comment in Reset(). return s.mat.N == 0 @@ -138,7 +140,7 @@ func (s *SymDense) reuseAs(n int) { if s.mat.N > s.cap { panic(badSymCap) } - if s.isZero() { + if s.IsZero() { s.mat = blas64.Symmetric{ N: n, Stride: n, @@ -283,7 +285,7 @@ func (s *SymDense) SymRankK(a Symmetric, alpha float64, x Matrix) { func (s *SymDense) SymOuterK(alpha float64, x Matrix) { n, _ := x.Dims() switch { - case s.isZero(): + case s.IsZero(): s.mat = blas64.Symmetric{ N: n, Stride: n, diff --git a/mat/triangular.go b/mat/triangular.go index c613040e..db5cdc1a 100644 --- a/mat/triangular.go +++ b/mat/triangular.go @@ -135,7 +135,7 @@ func (t *TriDense) Dims() (r, c int) { // Triangle returns the dimension of t and its orientation. The returned // orientation is only valid when n is not zero. func (t *TriDense) Triangle() (n int, kind TriKind) { - return t.mat.N, TriKind(!t.isZero()) && t.triKind() + return t.mat.N, TriKind(!t.IsZero()) && t.triKind() } func (t *TriDense) isUpper() bool { @@ -200,7 +200,9 @@ func (t *TriDense) Reset() { t.mat.Data = t.mat.Data[:0] } -func (t *TriDense) isZero() bool { +// IsZero returns whether the receiver is zero-sized. Zero-sized matrices can be the +// receiver for size-restricted operations. TriDense matrices can be zeroed using Reset. +func (t *TriDense) IsZero() bool { // It must be the case that t.Dims() returns // zeros in this case. See comment in Reset(). return t.mat.Stride == 0 @@ -227,7 +229,7 @@ func (t *TriDense) reuseAs(n int, kind TriKind) { if t.mat.N > t.cap { panic(badTriCap) } - if t.isZero() { + if t.IsZero() { t.mat = blas64.Triangular{ N: n, Stride: n, diff --git a/mat/vector.go b/mat/vector.go index d63071b9..c405738e 100644 --- a/mat/vector.go +++ b/mat/vector.go @@ -67,7 +67,7 @@ func (v *Vector) SliceVec(i, k int) *Vector { // Dims returns the number of rows and columns in the matrix. Columns is always 1 // for a non-Reset vector. func (v *Vector) Dims() (r, c int) { - if v.isZero() { + if v.IsZero() { return 0, 0 } return v.n, 1 @@ -76,7 +76,7 @@ func (v *Vector) Dims() (r, c int) { // Caps returns the number of rows and columns in the backing matrix. Columns is always 1 // for a non-Reset vector. func (v *Vector) Caps() (r, c int) { - if v.isZero() { + if v.IsZero() { return 0, 0 } return v.Cap(), 1 @@ -89,7 +89,7 @@ func (v *Vector) Len() int { // Cap returns the capacity of the vector. func (v *Vector) Cap() int { - if v.isZero() { + if v.IsZero() { return 0 } return (cap(v.mat.Data)-1)/v.mat.Inc + 1 @@ -426,7 +426,7 @@ func (v *Vector) 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 *Vector) reuseAs(r int) { - if v.isZero() { + if v.IsZero() { v.mat = blas64.Vector{ Inc: 1, Data: use(v.mat.Data, r), @@ -439,7 +439,9 @@ func (v *Vector) reuseAs(r int) { } } -func (v *Vector) isZero() bool { +// IsZero returns whether the receiver is zero-sized. Zero-sized vectors can be the +// receiver for size-restricted operations. Vectors can be zeroed using Reset. +func (v *Vector) IsZero() bool { // It must be the case that v.Dims() returns // zeros in this case. See comment in Reset(). return v.mat.Inc == 0