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