1 // Copyright ©2015 The Gonum Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 // maxLen is the biggest slice/array len one can create on a 32/64b platform.
16 maxLen = int64(int(^uint(0) >> 1))
20 sizeInt64 = binary.Size(int64(0))
21 sizeFloat64 = binary.Size(float64(0))
23 errTooBig = errors.New("mat: resulting data slice too big")
24 errTooSmall = errors.New("mat: input slice too small")
25 errBadBuffer = errors.New("mat: data buffer size mismatch")
26 errBadSize = errors.New("mat: invalid dimension")
29 // MarshalBinary encodes the receiver into a binary form and returns the result.
31 // Dense is little-endian encoded as follows:
32 // 0 - 7 number of rows (int64)
33 // 8 - 15 number of columns (int64)
34 // 16 - .. matrix data elements (float64)
35 // [0,0] [0,1] ... [0,ncols-1]
36 // [1,0] [1,1] ... [1,ncols-1]
38 // [nrows-1,0] ... [nrows-1,ncols-1]
39 func (m Dense) MarshalBinary() ([]byte, error) {
40 bufLen := int64(m.mat.Rows)*int64(m.mat.Cols)*int64(sizeFloat64) + 2*int64(sizeInt64)
42 // bufLen is too big and has wrapped around.
47 buf := make([]byte, bufLen)
48 binary.LittleEndian.PutUint64(buf[p:p+sizeInt64], uint64(m.mat.Rows))
50 binary.LittleEndian.PutUint64(buf[p:p+sizeInt64], uint64(m.mat.Cols))
54 for i := 0; i < r; i++ {
55 for j := 0; j < c; j++ {
56 binary.LittleEndian.PutUint64(buf[p:p+sizeFloat64], math.Float64bits(m.at(i, j)))
64 // MarshalBinaryTo encodes the receiver into a binary form and writes it into w.
65 // MarshalBinaryTo returns the number of bytes written into w and an error, if any.
67 // See MarshalBinary for the on-disk layout.
68 func (m Dense) MarshalBinaryTo(w io.Writer) (int, error) {
71 binary.LittleEndian.PutUint64(buf[:], uint64(m.mat.Rows))
72 nn, err := w.Write(buf[:])
77 binary.LittleEndian.PutUint64(buf[:], uint64(m.mat.Cols))
78 nn, err = w.Write(buf[:])
85 for i := 0; i < r; i++ {
86 for j := 0; j < c; j++ {
87 binary.LittleEndian.PutUint64(buf[:], math.Float64bits(m.at(i, j)))
88 nn, err = w.Write(buf[:])
99 // UnmarshalBinary decodes the binary form into the receiver.
100 // It panics if the receiver is a non-zero Dense matrix.
102 // See MarshalBinary for the on-disk layout.
104 // Limited checks on the validity of the binary input are performed:
105 // - matrix.ErrShape is returned if the number of rows or columns is negative,
106 // - an error is returned if the resulting Dense matrix is too
107 // big for the current architecture (e.g. a 16GB matrix written by a
108 // 64b application and read back from a 32b application.)
109 // UnmarshalBinary does not limit the size of the unmarshaled matrix, and so
110 // it should not be used on untrusted data.
111 func (m *Dense) UnmarshalBinary(data []byte) error {
113 panic("mat: unmarshal into non-zero matrix")
116 if len(data) < 2*sizeInt64 {
121 rows := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
123 cols := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
125 if rows < 0 || cols < 0 {
130 if int(size) < 0 || size > maxLen {
134 if len(data) != int(size)*sizeFloat64+2*sizeInt64 {
138 m.reuseAs(int(rows), int(cols))
139 for i := range m.mat.Data {
140 m.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[p : p+sizeFloat64]))
147 // UnmarshalBinaryFrom decodes the binary form into the receiver and returns
148 // the number of bytes read and an error if any.
149 // It panics if the receiver is a non-zero Dense matrix.
151 // See MarshalBinary for the on-disk layout.
153 // Limited checks on the validity of the binary input are performed:
154 // - matrix.ErrShape is returned if the number of rows or columns is negative,
155 // - an error is returned if the resulting Dense matrix is too
156 // big for the current architecture (e.g. a 16GB matrix written by a
157 // 64b application and read back from a 32b application.)
158 // UnmarshalBinary does not limit the size of the unmarshaled matrix, and so
159 // it should not be used on untrusted data.
160 func (m *Dense) UnmarshalBinaryFrom(r io.Reader) (int, error) {
162 panic("mat: unmarshal into non-zero matrix")
169 nn, err := readFull(r, buf[:])
174 rows := int64(binary.LittleEndian.Uint64(buf[:]))
176 nn, err = readFull(r, buf[:])
181 cols := int64(binary.LittleEndian.Uint64(buf[:]))
182 if rows < 0 || cols < 0 {
187 if int(size) < 0 || size > maxLen {
191 m.reuseAs(int(rows), int(cols))
192 for i := range m.mat.Data {
193 nn, err = readFull(r, buf[:])
198 m.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(buf[:]))
204 // MarshalBinary encodes the receiver into a binary form and returns the result.
206 // VecDense is little-endian encoded as follows:
207 // 0 - 7 number of elements (int64)
208 // 8 - .. vector's data elements (float64)
209 func (v VecDense) MarshalBinary() ([]byte, error) {
210 bufLen := int64(sizeInt64) + int64(v.n)*int64(sizeFloat64)
212 // bufLen is too big and has wrapped around.
213 return nil, errTooBig
217 buf := make([]byte, bufLen)
218 binary.LittleEndian.PutUint64(buf[p:p+sizeInt64], uint64(v.n))
221 for i := 0; i < v.n; i++ {
222 binary.LittleEndian.PutUint64(buf[p:p+sizeFloat64], math.Float64bits(v.at(i)))
229 // MarshalBinaryTo encodes the receiver into a binary form, writes it to w and
230 // returns the number of bytes written and an error if any.
232 // See MarshalBainry for the on-disk format.
233 func (v VecDense) MarshalBinaryTo(w io.Writer) (int, error) {
239 binary.LittleEndian.PutUint64(buf[:], uint64(v.n))
240 nn, err := w.Write(buf[:])
246 for i := 0; i < v.n; i++ {
247 binary.LittleEndian.PutUint64(buf[:], math.Float64bits(v.at(i)))
248 nn, err = w.Write(buf[:])
258 // UnmarshalBinary decodes the binary form into the receiver.
259 // It panics if the receiver is a non-zero VecDense.
261 // See MarshalBinary for the on-disk layout.
263 // Limited checks on the validity of the binary input are performed:
264 // - matrix.ErrShape is returned if the number of rows is negative,
265 // - an error is returned if the resulting VecDense is too
266 // big for the current architecture (e.g. a 16GB vector written by a
267 // 64b application and read back from a 32b application.)
268 // UnmarshalBinary does not limit the size of the unmarshaled vector, and so
269 // it should not be used on untrusted data.
270 func (v *VecDense) UnmarshalBinary(data []byte) error {
272 panic("mat: unmarshal into non-zero vector")
276 n := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
284 if len(data) != int(n)*sizeFloat64+sizeInt64 {
289 for i := range v.mat.Data {
290 v.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[p : p+sizeFloat64]))
297 // UnmarshalBinaryFrom decodes the binary form into the receiver, from the
298 // io.Reader and returns the number of bytes read and an error if any.
299 // It panics if the receiver is a non-zero VecDense.
301 // See MarshalBinary for the on-disk layout.
302 // See UnmarshalBinary for the list of sanity checks performed on the input.
303 func (v *VecDense) UnmarshalBinaryFrom(r io.Reader) (int, error) {
305 panic("mat: unmarshal into non-zero vector")
312 nn, err := readFull(r, buf[:])
317 sz := int64(binary.LittleEndian.Uint64(buf[:]))
326 for i := range v.mat.Data {
327 nn, err = readFull(r, buf[:])
332 v.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(buf[:]))
335 if n != sizeInt64+int(sz)*sizeFloat64 {
336 return n, io.ErrUnexpectedEOF
342 // readFull reads from r into buf until it has read len(buf).
343 // It returns the number of bytes copied and an error if fewer bytes were read.
344 // If an EOF happens after reading fewer than len(buf) bytes, io.ErrUnexpectedEOF is returned.
345 func readFull(r io.Reader, buf []byte) (int, error) {
348 for n < len(buf) && err == nil {
350 nn, err = r.Read(buf[n:])
357 return n, io.ErrUnexpectedEOF