mirror of
https://github.com/luxfi/container.git
synced 2026-09-24 00:24:34 +00:00
70 lines
1.6 KiB
Go
70 lines
1.6 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package sampler
|
|
|
|
type defaultMap map[uint64]uint64
|
|
|
|
func (m defaultMap) get(key uint64, defaultVal uint64) uint64 {
|
|
if val, ok := m[key]; ok {
|
|
return val
|
|
}
|
|
return defaultVal
|
|
}
|
|
|
|
// uniformReplacer allows for sampling over a uniform distribution without
|
|
// replacement.
|
|
//
|
|
// Sampling is performed by lazily performing an array shuffle of the array
|
|
// [0, 1, ..., length - 1]. By performing the first count swaps of this shuffle,
|
|
// we can create an array of length count with elements sampled with uniform
|
|
// probability.
|
|
//
|
|
// Initialization takes O(1) time.
|
|
//
|
|
// Sampling is performed in O(count) time and O(count) space.
|
|
type uniformReplacer struct {
|
|
rng *rng
|
|
length uint64
|
|
drawn defaultMap
|
|
drawsCount uint64
|
|
}
|
|
|
|
func (s *uniformReplacer) Initialize(length uint64) {
|
|
s.length = length
|
|
s.drawn = make(defaultMap)
|
|
s.drawsCount = 0
|
|
}
|
|
|
|
func (s *uniformReplacer) Sample(count int) ([]uint64, bool) {
|
|
s.Reset()
|
|
|
|
results := make([]uint64, count)
|
|
for i := 0; i < count; i++ {
|
|
ret, hasNext := s.Next()
|
|
if !hasNext {
|
|
return nil, false
|
|
}
|
|
results[i] = ret
|
|
}
|
|
return results, true
|
|
}
|
|
|
|
func (s *uniformReplacer) Reset() {
|
|
clear(s.drawn)
|
|
s.drawsCount = 0
|
|
}
|
|
|
|
func (s *uniformReplacer) Next() (uint64, bool) {
|
|
if s.drawsCount >= s.length {
|
|
return 0, false
|
|
}
|
|
|
|
draw := s.rng.Uint64Inclusive(s.length-1-s.drawsCount) + s.drawsCount
|
|
ret := s.drawn.get(draw, draw)
|
|
s.drawn[draw] = s.drawn.get(s.drawsCount, s.drawsCount)
|
|
s.drawsCount++
|
|
|
|
return ret, true
|
|
}
|