OSDN Git Service

new repo
[bytom/vapor.git] / vendor / gonum.org / v1 / gonum / mat / io.go
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.
4
5 package mat
6
7 import (
8         "encoding/binary"
9         "errors"
10         "io"
11         "math"
12 )
13
14 const (
15         // maxLen is the biggest slice/array len one can create on a 32/64b platform.
16         maxLen = int64(int(^uint(0) >> 1))
17 )
18
19 var (
20         sizeInt64   = binary.Size(int64(0))
21         sizeFloat64 = binary.Size(float64(0))
22
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")
27 )
28
29 // MarshalBinary encodes the receiver into a binary form and returns the result.
30 //
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]
37 //           ...
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)
41         if bufLen <= 0 {
42                 // bufLen is too big and has wrapped around.
43                 return nil, errTooBig
44         }
45
46         p := 0
47         buf := make([]byte, bufLen)
48         binary.LittleEndian.PutUint64(buf[p:p+sizeInt64], uint64(m.mat.Rows))
49         p += sizeInt64
50         binary.LittleEndian.PutUint64(buf[p:p+sizeInt64], uint64(m.mat.Cols))
51         p += sizeInt64
52
53         r, c := m.Dims()
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)))
57                         p += sizeFloat64
58                 }
59         }
60
61         return buf, nil
62 }
63
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.
66 //
67 // See MarshalBinary for the on-disk layout.
68 func (m Dense) MarshalBinaryTo(w io.Writer) (int, error) {
69         var n int
70         var buf [8]byte
71         binary.LittleEndian.PutUint64(buf[:], uint64(m.mat.Rows))
72         nn, err := w.Write(buf[:])
73         n += nn
74         if err != nil {
75                 return n, err
76         }
77         binary.LittleEndian.PutUint64(buf[:], uint64(m.mat.Cols))
78         nn, err = w.Write(buf[:])
79         n += nn
80         if err != nil {
81                 return n, err
82         }
83
84         r, c := m.Dims()
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[:])
89                         n += nn
90                         if err != nil {
91                                 return n, err
92                         }
93                 }
94         }
95
96         return n, nil
97 }
98
99 // UnmarshalBinary decodes the binary form into the receiver.
100 // It panics if the receiver is a non-zero Dense matrix.
101 //
102 // See MarshalBinary for the on-disk layout.
103 //
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 {
112         if !m.IsZero() {
113                 panic("mat: unmarshal into non-zero matrix")
114         }
115
116         if len(data) < 2*sizeInt64 {
117                 return errTooSmall
118         }
119
120         p := 0
121         rows := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
122         p += sizeInt64
123         cols := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
124         p += sizeInt64
125         if rows < 0 || cols < 0 {
126                 return errBadSize
127         }
128
129         size := rows * cols
130         if int(size) < 0 || size > maxLen {
131                 return errTooBig
132         }
133
134         if len(data) != int(size)*sizeFloat64+2*sizeInt64 {
135                 return errBadBuffer
136         }
137
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]))
141                 p += sizeFloat64
142         }
143
144         return nil
145 }
146
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.
150 //
151 // See MarshalBinary for the on-disk layout.
152 //
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) {
161         if !m.IsZero() {
162                 panic("mat: unmarshal into non-zero matrix")
163         }
164
165         var (
166                 n   int
167                 buf [8]byte
168         )
169         nn, err := readFull(r, buf[:])
170         n += nn
171         if err != nil {
172                 return n, err
173         }
174         rows := int64(binary.LittleEndian.Uint64(buf[:]))
175
176         nn, err = readFull(r, buf[:])
177         n += nn
178         if err != nil {
179                 return n, err
180         }
181         cols := int64(binary.LittleEndian.Uint64(buf[:]))
182         if rows < 0 || cols < 0 {
183                 return n, errBadSize
184         }
185
186         size := rows * cols
187         if int(size) < 0 || size > maxLen {
188                 return n, errTooBig
189         }
190
191         m.reuseAs(int(rows), int(cols))
192         for i := range m.mat.Data {
193                 nn, err = readFull(r, buf[:])
194                 n += nn
195                 if err != nil {
196                         return n, err
197                 }
198                 m.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(buf[:]))
199         }
200
201         return n, nil
202 }
203
204 // MarshalBinary encodes the receiver into a binary form and returns the result.
205 //
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)
211         if bufLen <= 0 {
212                 // bufLen is too big and has wrapped around.
213                 return nil, errTooBig
214         }
215
216         p := 0
217         buf := make([]byte, bufLen)
218         binary.LittleEndian.PutUint64(buf[p:p+sizeInt64], uint64(v.n))
219         p += sizeInt64
220
221         for i := 0; i < v.n; i++ {
222                 binary.LittleEndian.PutUint64(buf[p:p+sizeFloat64], math.Float64bits(v.at(i)))
223                 p += sizeFloat64
224         }
225
226         return buf, nil
227 }
228
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.
231 //
232 // See MarshalBainry for the on-disk format.
233 func (v VecDense) MarshalBinaryTo(w io.Writer) (int, error) {
234         var (
235                 n   int
236                 buf [8]byte
237         )
238
239         binary.LittleEndian.PutUint64(buf[:], uint64(v.n))
240         nn, err := w.Write(buf[:])
241         n += nn
242         if err != nil {
243                 return n, err
244         }
245
246         for i := 0; i < v.n; i++ {
247                 binary.LittleEndian.PutUint64(buf[:], math.Float64bits(v.at(i)))
248                 nn, err = w.Write(buf[:])
249                 n += nn
250                 if err != nil {
251                         return n, err
252                 }
253         }
254
255         return n, nil
256 }
257
258 // UnmarshalBinary decodes the binary form into the receiver.
259 // It panics if the receiver is a non-zero VecDense.
260 //
261 // See MarshalBinary for the on-disk layout.
262 //
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 {
271         if !v.IsZero() {
272                 panic("mat: unmarshal into non-zero vector")
273         }
274
275         p := 0
276         n := int64(binary.LittleEndian.Uint64(data[p : p+sizeInt64]))
277         p += sizeInt64
278         if n < 0 {
279                 return errBadSize
280         }
281         if n > maxLen {
282                 return errTooBig
283         }
284         if len(data) != int(n)*sizeFloat64+sizeInt64 {
285                 return errBadBuffer
286         }
287
288         v.reuseAs(int(n))
289         for i := range v.mat.Data {
290                 v.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(data[p : p+sizeFloat64]))
291                 p += sizeFloat64
292         }
293
294         return nil
295 }
296
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.
300 //
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) {
304         if !v.IsZero() {
305                 panic("mat: unmarshal into non-zero vector")
306         }
307
308         var (
309                 n   int
310                 buf [8]byte
311         )
312         nn, err := readFull(r, buf[:])
313         n += nn
314         if err != nil {
315                 return n, err
316         }
317         sz := int64(binary.LittleEndian.Uint64(buf[:]))
318         if sz < 0 {
319                 return n, errBadSize
320         }
321         if sz > maxLen {
322                 return n, errTooBig
323         }
324
325         v.reuseAs(int(sz))
326         for i := range v.mat.Data {
327                 nn, err = readFull(r, buf[:])
328                 n += nn
329                 if err != nil {
330                         return n, err
331                 }
332                 v.mat.Data[i] = math.Float64frombits(binary.LittleEndian.Uint64(buf[:]))
333         }
334
335         if n != sizeInt64+int(sz)*sizeFloat64 {
336                 return n, io.ErrUnexpectedEOF
337         }
338
339         return n, nil
340 }
341
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) {
346         var n int
347         var err error
348         for n < len(buf) && err == nil {
349                 var nn int
350                 nn, err = r.Read(buf[n:])
351                 n += nn
352         }
353         if n == len(buf) {
354                 return n, nil
355         }
356         if err == io.EOF {
357                 return n, io.ErrUnexpectedEOF
358         }
359         return n, err
360 }