public void Sample() { Contracts.Check(!_locked, "Cannot continue to sample after Lock() has been called"); _numSampled++; // If the number of samples seen so far is less than the total reservoir size, cache the new sample. if (_numSampled <= _cache.Length) { _getter(ref _cache[_numSampled - 1]); // If the cache is full, sample from it with replacement into the reservoir. if (_numSampled == _cache.Length) { for (int i = 0; i < _cache.Length; i++) { _reservoir[i] = _rnd.Next(_cache.Length); _counts[_reservoir[i]]++; } } } else { // Choose how many times to insert the current instance into the reservoir. int k = Stats.SampleFromBinomial(_rnd, _cache.Length, 1.0 / _numSampled); if (k > 0) { int ind = _rnd.Next(_reservoir.Length); // If the item referenced at this index appears more than once in the reservoir, we cannot overwrite it, // we need to find an available place in the cache. if (_counts[_reservoir[ind]] > 1) { Contracts.Assert(_counts.Contains(0)); var tmp = _counts.Select((count, i) => new KeyValuePair <int, int>(count, i)).First(kvp => kvp.Key == 0); _counts[_reservoir[ind]]--; _reservoir[ind] = tmp.Value; _counts[tmp.Value] = 1; } else if (_counts[_reservoir[ind]] == 0) { _counts[_reservoir[ind]]++; } _getter(ref _cache[_reservoir[ind]]); for (int j = 1; j < k;) { var next = _rnd.Next(_reservoir.Length); if (_reservoir[next] == _reservoir[ind]) { continue; } _counts[_reservoir[next]]--; _reservoir[next] = _reservoir[ind]; _counts[_reservoir[next]]++; j++; } } } }
/// <summary> /// Defines a sample stream for a biniomian distribution /// </summary> /// <param name="random">The random source</param> /// <param name="n">The number of trials</param> /// <param name="p">The probability of success of a given trial</param> public static IEnumerable <int> SampleBinomial(this IPolyrand random, int n, double p) { var sysrand = SysRand.Derive(random); while (true) { yield return(MlStats.SampleFromBinomial(sysrand, n, p)); } }
/// <summary> /// Defines a sample stream for a biniomian distribution /// </summary> /// <param name="random">The random source</param> /// <param name="n">The number of trials</param> /// <param name="p">The probability of success of a given trial</param> public static IEnumerable <T> SampleBinomial <T>(this IPolyrand random, T n, double p) where T : struct { var sysrand = SysRand.Derive(random); while (true) { yield return(convert <T>(MlStats.SampleFromBinomial(sysrand, convert <T, int>(n), p))); } }