OSDN Git Service

new repo
[bytom/vapor.git] / vendor / gonum.org / v1 / gonum / mat / pool.go
1 // Copyright ©2014 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         "sync"
9
10         "gonum.org/v1/gonum/blas"
11         "gonum.org/v1/gonum/blas/blas64"
12 )
13
14 var tab64 = [64]byte{
15         0x3f, 0x00, 0x3a, 0x01, 0x3b, 0x2f, 0x35, 0x02,
16         0x3c, 0x27, 0x30, 0x1b, 0x36, 0x21, 0x2a, 0x03,
17         0x3d, 0x33, 0x25, 0x28, 0x31, 0x12, 0x1c, 0x14,
18         0x37, 0x1e, 0x22, 0x0b, 0x2b, 0x0e, 0x16, 0x04,
19         0x3e, 0x39, 0x2e, 0x34, 0x26, 0x1a, 0x20, 0x29,
20         0x32, 0x24, 0x11, 0x13, 0x1d, 0x0a, 0x0d, 0x15,
21         0x38, 0x2d, 0x19, 0x1f, 0x23, 0x10, 0x09, 0x0c,
22         0x2c, 0x18, 0x0f, 0x08, 0x17, 0x07, 0x06, 0x05,
23 }
24
25 // bits returns the ceiling of base 2 log of v.
26 // Approach based on http://stackoverflow.com/a/11398748.
27 func bits(v uint64) byte {
28         if v == 0 {
29                 return 0
30         }
31         v <<= 2
32         v--
33         v |= v >> 1
34         v |= v >> 2
35         v |= v >> 4
36         v |= v >> 8
37         v |= v >> 16
38         v |= v >> 32
39         return tab64[((v-(v>>1))*0x07EDD5E59A4E28C2)>>58] - 1
40 }
41
42 var (
43         // pool contains size stratified workspace Dense pools.
44         // Each pool element i returns sized matrices with a data
45         // slice capped at 1<<i.
46         pool [63]sync.Pool
47
48         // poolSym is the SymDense equivalent of pool.
49         poolSym [63]sync.Pool
50
51         // poolTri is the TriDense equivalent of pool.
52         poolTri [63]sync.Pool
53
54         // poolVec is the VecDense equivalent of pool.
55         poolVec [63]sync.Pool
56
57         // poolFloats is the []float64 equivalent of pool.
58         poolFloats [63]sync.Pool
59
60         // poolInts is the []int equivalent of pool.
61         poolInts [63]sync.Pool
62 )
63
64 func init() {
65         for i := range pool {
66                 l := 1 << uint(i)
67                 pool[i].New = func() interface{} {
68                         return &Dense{mat: blas64.General{
69                                 Data: make([]float64, l),
70                         }}
71                 }
72                 poolSym[i].New = func() interface{} {
73                         return &SymDense{mat: blas64.Symmetric{
74                                 Uplo: blas.Upper,
75                                 Data: make([]float64, l),
76                         }}
77                 }
78                 poolTri[i].New = func() interface{} {
79                         return &TriDense{mat: blas64.Triangular{
80                                 Data: make([]float64, l),
81                         }}
82                 }
83                 poolVec[i].New = func() interface{} {
84                         return &VecDense{mat: blas64.Vector{
85                                 Inc:  1,
86                                 Data: make([]float64, l),
87                         }}
88                 }
89                 poolFloats[i].New = func() interface{} {
90                         return make([]float64, l)
91                 }
92                 poolInts[i].New = func() interface{} {
93                         return make([]int, l)
94                 }
95         }
96 }
97
98 // getWorkspace returns a *Dense of size r×c and a data slice
99 // with a cap that is less than 2*r*c. If clear is true, the
100 // data slice visible through the Matrix interface is zeroed.
101 func getWorkspace(r, c int, clear bool) *Dense {
102         l := uint64(r * c)
103         w := pool[bits(l)].Get().(*Dense)
104         w.mat.Data = w.mat.Data[:l]
105         if clear {
106                 zero(w.mat.Data)
107         }
108         w.mat.Rows = r
109         w.mat.Cols = c
110         w.mat.Stride = c
111         w.capRows = r
112         w.capCols = c
113         return w
114 }
115
116 // putWorkspace replaces a used *Dense into the appropriate size
117 // workspace pool. putWorkspace must not be called with a matrix
118 // where references to the underlying data slice have been kept.
119 func putWorkspace(w *Dense) {
120         pool[bits(uint64(cap(w.mat.Data)))].Put(w)
121 }
122
123 // getWorkspaceSym returns a *SymDense of size n and a cap that
124 // is less than 2*n. If clear is true, the data slice visible
125 // through the Matrix interface is zeroed.
126 func getWorkspaceSym(n int, clear bool) *SymDense {
127         l := uint64(n)
128         l *= l
129         s := poolSym[bits(l)].Get().(*SymDense)
130         s.mat.Data = s.mat.Data[:l]
131         if clear {
132                 zero(s.mat.Data)
133         }
134         s.mat.N = n
135         s.mat.Stride = n
136         s.cap = n
137         return s
138 }
139
140 // putWorkspaceSym replaces a used *SymDense into the appropriate size
141 // workspace pool. putWorkspaceSym must not be called with a matrix
142 // where references to the underlying data slice have been kept.
143 func putWorkspaceSym(s *SymDense) {
144         poolSym[bits(uint64(cap(s.mat.Data)))].Put(s)
145 }
146
147 // getWorkspaceTri returns a *TriDense of size n and a cap that
148 // is less than 2*n. If clear is true, the data slice visible
149 // through the Matrix interface is zeroed.
150 func getWorkspaceTri(n int, kind TriKind, clear bool) *TriDense {
151         l := uint64(n)
152         l *= l
153         t := poolTri[bits(l)].Get().(*TriDense)
154         t.mat.Data = t.mat.Data[:l]
155         if clear {
156                 zero(t.mat.Data)
157         }
158         t.mat.N = n
159         t.mat.Stride = n
160         if kind == Upper {
161                 t.mat.Uplo = blas.Upper
162         } else if kind == Lower {
163                 t.mat.Uplo = blas.Lower
164         } else {
165                 panic(ErrTriangle)
166         }
167         t.mat.Diag = blas.NonUnit
168         t.cap = n
169         return t
170 }
171
172 // putWorkspaceTri replaces a used *TriDense into the appropriate size
173 // workspace pool. putWorkspaceTri must not be called with a matrix
174 // where references to the underlying data slice have been kept.
175 func putWorkspaceTri(t *TriDense) {
176         poolTri[bits(uint64(cap(t.mat.Data)))].Put(t)
177 }
178
179 // getWorkspaceVec returns a *VecDense of length n and a cap that
180 // is less than 2*n. If clear is true, the data slice visible
181 // through the Matrix interface is zeroed.
182 func getWorkspaceVec(n int, clear bool) *VecDense {
183         l := uint64(n)
184         v := poolVec[bits(l)].Get().(*VecDense)
185         v.mat.Data = v.mat.Data[:l]
186         if clear {
187                 zero(v.mat.Data)
188         }
189         v.n = n
190         return v
191 }
192
193 // putWorkspaceVec replaces a used *VecDense into the appropriate size
194 // workspace pool. putWorkspaceVec must not be called with a matrix
195 // where references to the underlying data slice have been kept.
196 func putWorkspaceVec(v *VecDense) {
197         poolVec[bits(uint64(cap(v.mat.Data)))].Put(v)
198 }
199
200 // getFloats returns a []float64 of length l and a cap that is
201 // less than 2*l. If clear is true, the slice visible is zeroed.
202 func getFloats(l int, clear bool) []float64 {
203         w := poolFloats[bits(uint64(l))].Get().([]float64)
204         w = w[:l]
205         if clear {
206                 zero(w)
207         }
208         return w
209 }
210
211 // putFloats replaces a used []float64 into the appropriate size
212 // workspace pool. putFloats must not be called with a slice
213 // where references to the underlying data have been kept.
214 func putFloats(w []float64) {
215         poolFloats[bits(uint64(cap(w)))].Put(w)
216 }
217
218 // getInts returns a []ints of length l and a cap that is
219 // less than 2*l. If clear is true, the slice visible is zeroed.
220 func getInts(l int, clear bool) []int {
221         w := poolInts[bits(uint64(l))].Get().([]int)
222         w = w[:l]
223         if clear {
224                 for i := range w {
225                         w[i] = 0
226                 }
227         }
228         return w
229 }
230
231 // putInts replaces a used []int into the appropriate size
232 // workspace pool. putInts must not be called with a slice
233 // where references to the underlying data have been kept.
234 func putInts(w []int) {
235         poolInts[bits(uint64(cap(w)))].Put(w)
236 }