I've written a few functions that generate random numbers from an arbitrary discrete distribution in O(log N) time, where N is the number of possible values, using SortedRange.lowerBound(). It's similar to dice() except that in exchange for O(N) auxiliary space and upfront initialization cost you get O(log N) generation. I've attached the code, which is fairly simple. Should this go in std.random, or is needing this O(log N) performance on dice() niche enough that this belongs in my dstats lib instead?
import std.range, std.array, std.traits, std.exception, std.random;

/**
Returns a delegate that generates random numbers similarly to $(D dice()) but
in $(BIGOH log N) time per number generated, where $(D N) is the number of
possible values.  In exchange, it requires $(BIGOH N) auxiliary space and
$(BIGOH N) upfront initialization time.
*/
size_t delegate() fastDice(R)(R range)
if(isInputRange!R && isNumeric!(ElementType!R)) {
    auto sorted = makeSortedSums(range);

    size_t generate() {
        return generateFastDice(rndGen, sorted);
    }

    return &generate;
}

/// Ditto
size_t delegate() fastDice(R, Random)(R range, Random gen)
if(isInputRange!R && isNumeric!(ElementType!R)) {
    auto sorted = makeSortedSums(range);

    size_t generate() {
        return generateFastDice(gen, sorted);
    }

    return &generate;
}

private size_t generateFastDice(Random, R)(ref Random gen, R range) {
    immutable point = uniform(0.0, cast(double) range.back, gen);
    return range.lowerBound(point).length;
}

// Helper function to make the range of sums.
private auto makeSortedSums(R)(R range) {
    auto sums = array(range);
    foreach(i, ref elem; sums) {
        enforce(elem >= 0, "Can't have negative probabilities for fastDice.");
        elem += sums[i - 1];
    }

    return assumeSorted(sums);
}

unittest {
    auto i = fastDice([0.0, 100.0])();
    assert(i == 1);
    i = fastDice([100.0, 0.0])();
    assert(i == 0);
}
_______________________________________________
phobos mailing list
[email protected]
http://lists.puremagic.com/mailman/listinfo/phobos

Reply via email to