rust/src/fuzzer/rand_util.rs

98 lines
2.4 KiB
Rust
Raw Normal View History

2011-09-23 23:24:43 -07:00
use std;
import std::rand;
import vec;
2011-09-23 23:24:43 -07:00
// random uint less than n
fn under(r : rand::rng, n : uint) -> uint {
assert n != 0u; r.next() as uint % n
}
2011-09-23 23:24:43 -07:00
// random choice from a vec
fn choice<T: copy>(r : rand::rng, v : [T]/~) -> T {
assert vec::len(v) != 0u; v[under(r, vec::len(v))]
}
2011-09-23 23:24:43 -07:00
// 1 in n chance of being true
fn unlikely(r : rand::rng, n : uint) -> bool { under(r, n) == 0u }
// shuffle a vec in place
fn shuffle<T>(r : rand::rng, &v : [mut T]/~) {
2011-09-23 23:24:43 -07:00
let i = vec::len(v);
while i >= 2u {
// Loop invariant: elements with index >= i have been locked in place.
i -= 1u;
vec::swap(v, i, under(r, i + 1u)); // Lock element i in place.
}
}
// create a shuffled copy of a vec
fn shuffled<T: copy>(r : rand::rng, v : [T]/~) -> [T]/~ {
2011-09-23 23:24:43 -07:00
let w = vec::to_mut(v);
shuffle(r, w);
vec::from_mut(w) // Shouldn't this happen automatically?
}
// sample from a population without replacement
//fn sample<T>(r : rand::rng, pop : [T]/~, k : uint) -> [T]/~ { fail }
2011-09-23 23:24:43 -07:00
// Two ways to make a weighted choice.
// * weighted_choice is O(number of choices) time
// * weighted_vec is O(total weight) space
type weighted<T> = { weight: uint, item: T };
fn weighted_choice<T: copy>(r : rand::rng, v : [weighted<T>]/~) -> T {
2011-09-23 23:24:43 -07:00
assert vec::len(v) != 0u;
let total = 0u;
for {weight: weight, item: _} in v {
total += weight;
}
assert total >= 0u;
let chosen = under(r, total);
let so_far = 0u;
for {weight: weight, item: item} in v {
so_far += weight;
if so_far > chosen {
ret item;
}
}
core::unreachable();
2011-09-23 23:24:43 -07:00
}
fn weighted_vec<T: copy>(v : [weighted<T>]/~) -> [T]/~ {
let r = []/~;
2011-09-23 23:24:43 -07:00
for {weight: weight, item: item} in v {
let i = 0u;
while i < weight {
2012-06-15 21:16:42 -04:00
vec::push(r, item);
2011-09-23 23:24:43 -07:00
i += 1u;
}
}
r
}
fn main()
{
let r = rand::mk_rng();
log(error, under(r, 5u));
log(error, choice(r, [10, 20, 30]/~));
log(error, if unlikely(r, 5u) { "unlikely" } else { "likely" });
2011-09-23 23:24:43 -07:00
let a = [mut 1, 2, 3]/~;
2011-09-23 23:24:43 -07:00
shuffle(r, a);
log(error, a);
2011-09-23 23:24:43 -07:00
let i = 0u;
let v = [
{weight:1u, item:"low"},
{weight:8u, item:"middle"},
{weight:1u, item:"high"}
]/~;
2011-09-23 23:24:43 -07:00
let w = weighted_vec(v);
while i < 1000u {
log(error, "Immed: " + weighted_choice(r, v));
2012-01-06 22:06:32 -08:00
log(error, "Fast: " + choice(r, w));
2011-09-23 23:24:43 -07:00
i += 1u;
}
}