github.com/gopherd/gonum@v0.0.4/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  	"math/bits"
     9  	"sync"
    10  
    11  	"github.com/gopherd/gonum/blas"
    12  	"github.com/gopherd/gonum/blas/blas64"
    13  	"github.com/gopherd/gonum/blas/cblas128"
    14  )
    15  
    16  // poolFor returns the ceiling of base 2 log of size. It provides an index
    17  // into a pool array to a sync.Pool that will return values able to hold
    18  // size elements.
    19  func poolFor(size uint) int {
    20  	if size == 0 {
    21  		return 0
    22  	}
    23  	return bits.Len(size - 1)
    24  }
    25  
    26  var (
    27  	// poolDense contains size stratified workspace Dense pools.
    28  	// Each poolDense element i returns sized matrices with a data
    29  	// slice capped at 1<<i.
    30  	poolDense [63]sync.Pool
    31  
    32  	// poolSymDense is the SymDense equivalent of poolDense.
    33  	poolSymDense [63]sync.Pool
    34  
    35  	// poolTriDense is the TriDense equivalent of poolDense.
    36  	poolTriDense [63]sync.Pool
    37  
    38  	// poolVecDense is the VecDense equivalent of poolDense.
    39  	poolVecDense [63]sync.Pool
    40  
    41  	// poolCDense is the CDense equivalent of poolDense.
    42  	poolCDense [63]sync.Pool
    43  
    44  	// poolFloat64s is the []float64 equivalent of poolDense.
    45  	poolFloat64s [63]sync.Pool
    46  
    47  	// poolInts is the []int equivalent of poolDense.
    48  	poolInts [63]sync.Pool
    49  )
    50  
    51  func init() {
    52  	for i := range poolDense {
    53  		l := 1 << uint(i)
    54  		// Real matrix pools.
    55  		poolDense[i].New = func() interface{} {
    56  			return &Dense{mat: blas64.General{
    57  				Data: make([]float64, l),
    58  			}}
    59  		}
    60  		poolSymDense[i].New = func() interface{} {
    61  			return &SymDense{mat: blas64.Symmetric{
    62  				Uplo: blas.Upper,
    63  				Data: make([]float64, l),
    64  			}}
    65  		}
    66  		poolTriDense[i].New = func() interface{} {
    67  			return &TriDense{mat: blas64.Triangular{
    68  				Data: make([]float64, l),
    69  			}}
    70  		}
    71  		poolVecDense[i].New = func() interface{} {
    72  			return &VecDense{mat: blas64.Vector{
    73  				Inc:  1,
    74  				Data: make([]float64, l),
    75  			}}
    76  		}
    77  
    78  		// Complex matrix pools.
    79  		poolCDense[i].New = func() interface{} {
    80  			return &CDense{mat: cblas128.General{
    81  				Data: make([]complex128, l),
    82  			}}
    83  		}
    84  
    85  		// Helper pools.
    86  		poolFloat64s[i].New = func() interface{} {
    87  			s := make([]float64, l)
    88  			return &s
    89  		}
    90  		poolInts[i].New = func() interface{} {
    91  			s := make([]int, l)
    92  			return &s
    93  		}
    94  	}
    95  }
    96  
    97  // getDenseWorkspace returns a *Dense of size r×c and a data slice
    98  // with a cap that is less than 2*r*c. If clear is true, the
    99  // data slice visible through the Matrix interface is zeroed.
   100  func getDenseWorkspace(r, c int, clear bool) *Dense {
   101  	l := uint(r * c)
   102  	w := poolDense[poolFor(l)].Get().(*Dense)
   103  	w.mat.Data = w.mat.Data[:l]
   104  	if clear {
   105  		zero(w.mat.Data)
   106  	}
   107  	w.mat.Rows = r
   108  	w.mat.Cols = c
   109  	w.mat.Stride = c
   110  	w.capRows = r
   111  	w.capCols = c
   112  	return w
   113  }
   114  
   115  // putDenseWorkspace replaces a used *Dense into the appropriate size
   116  // workspace pool. putDenseWorkspace must not be called with a matrix
   117  // where references to the underlying data slice have been kept.
   118  func putDenseWorkspace(w *Dense) {
   119  	poolDense[poolFor(uint(cap(w.mat.Data)))].Put(w)
   120  }
   121  
   122  // getSymDenseWorkspace returns a *SymDense of size n and a cap that
   123  // is less than 2*n. If clear is true, the data slice visible
   124  // through the Matrix interface is zeroed.
   125  func getSymDenseWorkspace(n int, clear bool) *SymDense {
   126  	l := uint(n)
   127  	l *= l
   128  	s := poolSymDense[poolFor(l)].Get().(*SymDense)
   129  	s.mat.Data = s.mat.Data[:l]
   130  	if clear {
   131  		zero(s.mat.Data)
   132  	}
   133  	s.mat.N = n
   134  	s.mat.Stride = n
   135  	s.cap = n
   136  	return s
   137  }
   138  
   139  // putSymDenseWorkspace replaces a used *SymDense into the appropriate size
   140  // workspace pool. putSymDenseWorkspace must not be called with a matrix
   141  // where references to the underlying data slice have been kept.
   142  func putSymDenseWorkspace(s *SymDense) {
   143  	poolSymDense[poolFor(uint(cap(s.mat.Data)))].Put(s)
   144  }
   145  
   146  // getTriDenseWorkspace returns a *TriDense of size n and a cap that
   147  // is less than 2*n. If clear is true, the data slice visible
   148  // through the Matrix interface is zeroed.
   149  func getTriDenseWorkspace(n int, kind TriKind, clear bool) *TriDense {
   150  	l := uint(n)
   151  	l *= l
   152  	t := poolTriDense[poolFor(l)].Get().(*TriDense)
   153  	t.mat.Data = t.mat.Data[:l]
   154  	if clear {
   155  		zero(t.mat.Data)
   156  	}
   157  	t.mat.N = n
   158  	t.mat.Stride = n
   159  	if kind == Upper {
   160  		t.mat.Uplo = blas.Upper
   161  	} else if kind == Lower {
   162  		t.mat.Uplo = blas.Lower
   163  	} else {
   164  		panic(ErrTriangle)
   165  	}
   166  	t.mat.Diag = blas.NonUnit
   167  	t.cap = n
   168  	return t
   169  }
   170  
   171  // putTriWorkspace replaces a used *TriDense into the appropriate size
   172  // workspace pool. putTriWorkspace must not be called with a matrix
   173  // where references to the underlying data slice have been kept.
   174  func putTriWorkspace(t *TriDense) {
   175  	poolTriDense[poolFor(uint(cap(t.mat.Data)))].Put(t)
   176  }
   177  
   178  // getVecDenseWorkspace returns a *VecDense of length n and a cap that
   179  // is less than 2*n. If clear is true, the data slice visible
   180  // through the Matrix interface is zeroed.
   181  func getVecDenseWorkspace(n int, clear bool) *VecDense {
   182  	l := uint(n)
   183  	v := poolVecDense[poolFor(l)].Get().(*VecDense)
   184  	v.mat.Data = v.mat.Data[:l]
   185  	if clear {
   186  		zero(v.mat.Data)
   187  	}
   188  	v.mat.N = n
   189  	return v
   190  }
   191  
   192  // putVecDenseWorkspace replaces a used *VecDense into the appropriate size
   193  // workspace pool. putVecDenseWorkspace must not be called with a matrix
   194  // where references to the underlying data slice have been kept.
   195  func putVecDenseWorkspace(v *VecDense) {
   196  	poolVecDense[poolFor(uint(cap(v.mat.Data)))].Put(v)
   197  }
   198  
   199  // getCDenseWorkspace returns a *CDense of size r×c and a data slice
   200  // with a cap that is less than 2*r*c. If clear is true, the
   201  // data slice visible through the CMatrix interface is zeroed.
   202  func getCDenseWorkspace(r, c int, clear bool) *CDense {
   203  	l := uint(r * c)
   204  	w := poolCDense[poolFor(l)].Get().(*CDense)
   205  	w.mat.Data = w.mat.Data[:l]
   206  	if clear {
   207  		zeroC(w.mat.Data)
   208  	}
   209  	w.mat.Rows = r
   210  	w.mat.Cols = c
   211  	w.mat.Stride = c
   212  	w.capRows = r
   213  	w.capCols = c
   214  	return w
   215  }
   216  
   217  // putCDenseWorkspace replaces a used *CDense into the appropriate size
   218  // workspace pool. putWorkspace must not be called with a matrix
   219  // where references to the underlying data slice have been kept.
   220  func putCDenseWorkspace(w *CDense) {
   221  	poolCDense[poolFor(uint(cap(w.mat.Data)))].Put(w)
   222  }
   223  
   224  // getFloat64s returns a []float64 of length l and a cap that is
   225  // less than 2*l. If clear is true, the slice visible is zeroed.
   226  func getFloat64s(l int, clear bool) []float64 {
   227  	w := *poolFloat64s[poolFor(uint(l))].Get().(*[]float64)
   228  	w = w[:l]
   229  	if clear {
   230  		zero(w)
   231  	}
   232  	return w
   233  }
   234  
   235  // putFloat64s replaces a used []float64 into the appropriate size
   236  // workspace pool. putFloat64s must not be called with a slice
   237  // where references to the underlying data have been kept.
   238  func putFloat64s(w []float64) {
   239  	poolFloat64s[poolFor(uint(cap(w)))].Put(&w)
   240  }
   241  
   242  // getInts returns a []int of length l and a cap that is
   243  // less than 2*l. If clear is true, the slice visible is zeroed.
   244  func getInts(l int, clear bool) []int {
   245  	w := *poolInts[poolFor(uint(l))].Get().(*[]int)
   246  	w = w[:l]
   247  	if clear {
   248  		for i := range w {
   249  			w[i] = 0
   250  		}
   251  	}
   252  	return w
   253  }
   254  
   255  // putInts replaces a used []int into the appropriate size
   256  // workspace pool. putInts must not be called with a slice
   257  // where references to the underlying data have been kept.
   258  func putInts(w []int) {
   259  	poolInts[poolFor(uint(cap(w)))].Put(&w)
   260  }