85 lines
1.7 KiB
C#
85 lines
1.7 KiB
C#
using System;
|
|
|
|
namespace FrostFS.SDK.ClientV2;
|
|
|
|
internal sealed class Sampler
|
|
{
|
|
private readonly object _lock = new();
|
|
|
|
private Random random = new();
|
|
|
|
internal double[] Probabilities { get; set; }
|
|
internal int[] Alias { get; set; }
|
|
|
|
internal Sampler(double[] probabilities)
|
|
{
|
|
var small = new WorkList();
|
|
var large = new WorkList();
|
|
|
|
var n = probabilities.Length;
|
|
|
|
// sampler.randomGenerator = rand.New(source)
|
|
Probabilities = new double[n];
|
|
Alias = new int[n];
|
|
|
|
// Compute scaled probabilities.
|
|
var p = new double[n];
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
p[i] = probabilities[i] * n;
|
|
if (p[i] < 1)
|
|
small.Add(i);
|
|
else
|
|
large.Add(i);
|
|
}
|
|
|
|
while (small.Length > 0 && large.Length > 0)
|
|
{
|
|
var l = small.Remove();
|
|
var g = large.Remove();
|
|
|
|
Probabilities[l] = p[l];
|
|
Alias[l] = g;
|
|
|
|
p[g] = p[g] + p[l] - 1;
|
|
|
|
if (p[g] < 1)
|
|
small.Add(g);
|
|
else
|
|
large.Add(g);
|
|
}
|
|
|
|
while (large.Length > 0)
|
|
{
|
|
var g = large.Remove();
|
|
Probabilities[g] = 1;
|
|
}
|
|
|
|
while (small.Length > 0)
|
|
{
|
|
var l = small.Remove();
|
|
probabilities[l] = 1;
|
|
}
|
|
}
|
|
|
|
internal int Next()
|
|
{
|
|
var n = Alias.Length;
|
|
|
|
int i;
|
|
double f;
|
|
lock (_lock)
|
|
{
|
|
i = random.Next(0, n - 1);
|
|
f = random.NextDouble();
|
|
}
|
|
|
|
if (f < Probabilities[i])
|
|
{
|
|
return i;
|
|
}
|
|
|
|
return Alias[i];
|
|
}
|
|
}
|