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  }