OSDN Git Service

new repo
[bytom/vapor.git] / vendor / gonum.org / v1 / gonum / mat / format.go
1 // Copyright ©2013 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         "fmt"
9         "strconv"
10 )
11
12 // Formatted returns a fmt.Formatter for the matrix m using the given options.
13 func Formatted(m Matrix, options ...FormatOption) fmt.Formatter {
14         f := formatter{
15                 matrix: m,
16                 dot:    '.',
17         }
18         for _, o := range options {
19                 o(&f)
20         }
21         return f
22 }
23
24 type formatter struct {
25         matrix  Matrix
26         prefix  string
27         margin  int
28         dot     byte
29         squeeze bool
30 }
31
32 // FormatOption is a functional option for matrix formatting.
33 type FormatOption func(*formatter)
34
35 // Prefix sets the formatted prefix to the string p. Prefix is a string that is prepended to
36 // each line of output.
37 func Prefix(p string) FormatOption {
38         return func(f *formatter) { f.prefix = p }
39 }
40
41 // Excerpt sets the maximum number of rows and columns to print at the margins of the matrix
42 // to m. If m is zero or less all elements are printed.
43 func Excerpt(m int) FormatOption {
44         return func(f *formatter) { f.margin = m }
45 }
46
47 // DotByte sets the dot character to b. The dot character is used to replace zero elements
48 // if the result is printed with the fmt ' ' verb flag. Without a DotByte option, the default
49 // dot character is '.'.
50 func DotByte(b byte) FormatOption {
51         return func(f *formatter) { f.dot = b }
52 }
53
54 // Squeeze sets the printing behaviour to minimise column width for each individual column.
55 func Squeeze() FormatOption {
56         return func(f *formatter) { f.squeeze = true }
57 }
58
59 // Format satisfies the fmt.Formatter interface.
60 func (f formatter) Format(fs fmt.State, c rune) {
61         if c == 'v' && fs.Flag('#') {
62                 fmt.Fprintf(fs, "%#v", f.matrix)
63                 return
64         }
65         format(f.matrix, f.prefix, f.margin, f.dot, f.squeeze, fs, c)
66 }
67
68 // format prints a pretty representation of m to the fs io.Writer. The format character c
69 // specifies the numerical representation of of elements; valid values are those for float64
70 // specified in the fmt package, with their associated flags. In addition to this, a space
71 // preceding a verb indicates that zero values should be represented by the dot character.
72 // The printed range of the matrix can be limited by specifying a positive value for margin;
73 // If margin is greater than zero, only the first and last margin rows/columns of the matrix
74 // are output. If squeeze is true, column widths are determined on a per-column basis.
75 //
76 // format will not provide Go syntax output.
77 func format(m Matrix, prefix string, margin int, dot byte, squeeze bool, fs fmt.State, c rune) {
78         rows, cols := m.Dims()
79
80         var printed int
81         if margin <= 0 {
82                 printed = rows
83                 if cols > printed {
84                         printed = cols
85                 }
86         } else {
87                 printed = margin
88         }
89
90         prec, pOk := fs.Precision()
91         if !pOk {
92                 prec = -1
93         }
94
95         var (
96                 maxWidth int
97                 widths   widther
98                 buf, pad []byte
99         )
100         if squeeze {
101                 widths = make(columnWidth, cols)
102         } else {
103                 widths = new(uniformWidth)
104         }
105         switch c {
106         case 'v', 'e', 'E', 'f', 'F', 'g', 'G':
107                 if c == 'v' {
108                         buf, maxWidth = maxCellWidth(m, 'g', printed, prec, widths)
109                 } else {
110                         buf, maxWidth = maxCellWidth(m, c, printed, prec, widths)
111                 }
112         default:
113                 fmt.Fprintf(fs, "%%!%c(%T=Dims(%d, %d))", c, m, rows, cols)
114                 return
115         }
116         width, _ := fs.Width()
117         width = max(width, maxWidth)
118         pad = make([]byte, max(width, 2))
119         for i := range pad {
120                 pad[i] = ' '
121         }
122
123         first := true
124         if rows > 2*printed || cols > 2*printed {
125                 first = false
126                 fmt.Fprintf(fs, "Dims(%d, %d)\n", rows, cols)
127         }
128
129         skipZero := fs.Flag(' ')
130         for i := 0; i < rows; i++ {
131                 if !first {
132                         fmt.Fprint(fs, prefix)
133                 }
134                 first = false
135                 var el string
136                 switch {
137                 case rows == 1:
138                         fmt.Fprint(fs, "[")
139                         el = "]"
140                 case i == 0:
141                         fmt.Fprint(fs, "⎡")
142                         el = "⎤\n"
143                 case i < rows-1:
144                         fmt.Fprint(fs, "⎢")
145                         el = "⎥\n"
146                 default:
147                         fmt.Fprint(fs, "⎣")
148                         el = "⎦"
149                 }
150
151                 for j := 0; j < cols; j++ {
152                         if j >= printed && j < cols-printed {
153                                 j = cols - printed - 1
154                                 if i == 0 || i == rows-1 {
155                                         fmt.Fprint(fs, "...  ...  ")
156                                 } else {
157                                         fmt.Fprint(fs, "          ")
158                                 }
159                                 continue
160                         }
161
162                         v := m.At(i, j)
163                         if v == 0 && skipZero {
164                                 buf = buf[:1]
165                                 buf[0] = dot
166                         } else {
167                                 if c == 'v' {
168                                         buf = strconv.AppendFloat(buf[:0], v, 'g', prec, 64)
169                                 } else {
170                                         buf = strconv.AppendFloat(buf[:0], v, byte(c), prec, 64)
171                                 }
172                         }
173                         if fs.Flag('-') {
174                                 fs.Write(buf)
175                                 fs.Write(pad[:widths.width(j)-len(buf)])
176                         } else {
177                                 fs.Write(pad[:widths.width(j)-len(buf)])
178                                 fs.Write(buf)
179                         }
180
181                         if j < cols-1 {
182                                 fs.Write(pad[:2])
183                         }
184                 }
185
186                 fmt.Fprint(fs, el)
187
188                 if i >= printed-1 && i < rows-printed && 2*printed < rows {
189                         i = rows - printed - 1
190                         fmt.Fprintf(fs, "%s .\n%[1]s .\n%[1]s .\n", prefix)
191                         continue
192                 }
193         }
194 }
195
196 func maxCellWidth(m Matrix, c rune, printed, prec int, w widther) ([]byte, int) {
197         var (
198                 buf        = make([]byte, 0, 64)
199                 rows, cols = m.Dims()
200                 max        int
201         )
202         for i := 0; i < rows; i++ {
203                 if i >= printed-1 && i < rows-printed && 2*printed < rows {
204                         i = rows - printed - 1
205                         continue
206                 }
207                 for j := 0; j < cols; j++ {
208                         if j >= printed && j < cols-printed {
209                                 continue
210                         }
211
212                         buf = strconv.AppendFloat(buf, m.At(i, j), byte(c), prec, 64)
213                         if len(buf) > max {
214                                 max = len(buf)
215                         }
216                         if len(buf) > w.width(j) {
217                                 w.setWidth(j, len(buf))
218                         }
219                         buf = buf[:0]
220                 }
221         }
222         return buf, max
223 }
224
225 type widther interface {
226         width(i int) int
227         setWidth(i, w int)
228 }
229
230 type uniformWidth int
231
232 func (u *uniformWidth) width(_ int) int   { return int(*u) }
233 func (u *uniformWidth) setWidth(_, w int) { *u = uniformWidth(w) }
234
235 type columnWidth []int
236
237 func (c columnWidth) width(i int) int   { return c[i] }
238 func (c columnWidth) setWidth(i, w int) { c[i] = w }