MCPcopy Create free account
hub / github.com/NVIDIAGameWorks/Falcor / AliasTable

Method AliasTable

Source/Falcor/Utils/Sampling/AliasTable.cpp:48–139  ·  view source on GitHub ↗

This builds an alias table via the O(N) algorithm from Vose 1991, "A linear algorithm for generating random numbers with a given distribution," IEEE Transactions on Software Engineering 17(9), 972-975. Basic idea: creating each alias table entry combines one overweighted sample and one underweighted sample into one alias table entry plus a residual sample (the overweighted sample minus some of i

Source from the content-addressed store, hash-verified

46// have 2 valid entries to combine. By definition, in these corner cases, all remaining unhandled samples
47// actually have the average weight (within numerical precision limits)
48AliasTable::AliasTable(ref<Device> pDevice, std::vector<float> weights, std::mt19937& rng) : mCount((uint32_t)weights.size())
49{
50 // Use >= since we reserve 0xFFFFFFFFu as an invalid flag marker during construction.
51 if (weights.size() >= std::numeric_limits<uint32_t>::max())
52 FALCOR_THROW("Too many entries for alias table.");
53
54 std::uniform_int_distribution<uint32_t> rngDist;
55
56 mpWeights =
57 pDevice->createStructuredBuffer(sizeof(float), mCount, ResourceBindFlags::ShaderResource, MemoryType::DeviceLocal, weights.data());
58
59 // Our working set / intermediate buffers (underweight & overweight); initialize to "invalid"
60 std::vector<uint32_t> lowIdx(mCount, 0xFFFFFFFFu);
61 std::vector<uint32_t> highIdx(mCount, 0xFFFFFFFFu);
62
63 // Sum element weights, use double to minimize precision issues
64 mWeightSum = 0.0;
65 for (float f : weights)
66 mWeightSum += f;
67
68 // Find the average weight
69 float avgWeight = float(mWeightSum / double(mCount));
70
71 // Initialize working set. Inset inputs into our lists of above-average or below-average weight elements.
72 int lowCount = 0;
73 int highCount = 0;
74 for (uint32_t i = 0; i < mCount; ++i)
75 {
76 if (weights[i] < avgWeight)
77 lowIdx[lowCount++] = i;
78 else
79 highIdx[highCount++] = i;
80 }
81
82 // Create alias table entries by merging above- and below-average samples
83 std::vector<AliasTable::Item> items(mCount);
84 for (uint32_t i = 0; i < mCount; ++i)
85 {
86 // Usual case: We have an above-average and below-average sample we can combine into one alias table entry
87 if ((lowIdx[i] != 0xFFFFFFFFu) && (highIdx[i] != 0xFFFFFFFFu))
88 {
89 // Create an alias table tuple:
90 items[i] = {weights[lowIdx[i]] / avgWeight, highIdx[i], lowIdx[i], 0};
91
92 // We've removed some weight from element highIdx[i]; update it's weight, then re-enter it
93 // on the end of either the above-average or below-average lists.
94 float updatedWeight = (weights[lowIdx[i]] + weights[highIdx[i]]) - avgWeight;
95 weights[highIdx[i]] = updatedWeight;
96 if (updatedWeight < avgWeight)
97 lowIdx[lowCount++] = highIdx[i];
98 else
99 highIdx[highCount++] = highIdx[i];
100 }
101
102 // The next two cases can only occur towards the end of table creation, because either:
103 // (a) all the remaining possible alias table entries have weight *exactly* equal to avgWeight,
104 // which means these alias table entries only have one input item that is selected
105 // with 100% probability

Callers

nothing calls this directly

Calls 4

maxFunction · 0.50
sizeMethod · 0.45
dataMethod · 0.45

Tested by

no test coverage detected