moving RNG helpers from sim to abstutil

This commit is contained in:
Dustin Carlino 2018-11-13 10:45:15 -08:00
parent df5a151f8b
commit b2e3f25393
9 changed files with 59 additions and 50 deletions

View File

@ -6,7 +6,9 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
log = "0.4.5"
multimap = "0.4.0"
rand = { version = "0.5.1", features = ["serde1"] }
serde = "1.0"
serde_cbor = "0.8.2"
serde_derive = "1.0"
serde_json = "1.0"
yansi = "0.4.0"

View File

@ -1,4 +1,5 @@
use std::any::Any;
use WeightedUsizeChoice;
// Trick to make a cloneable Any from
// https://stackoverflow.com/questions/30353462/how-to-clone-a-struct-storing-a-boxed-trait-object/30353928#30353928.
@ -34,3 +35,4 @@ impl Cloneable for usize {}
impl Cloneable for f64 {}
impl Cloneable for String {}
impl Cloneable for (String, Box<Cloneable>) {}
impl Cloneable for WeightedUsizeChoice {}

View File

@ -1,7 +1,10 @@
extern crate log;
extern crate multimap;
extern crate rand;
extern crate serde;
extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate yansi;
@ -11,6 +14,7 @@ mod collections;
mod error;
mod io;
mod logs;
mod random;
mod time;
pub use abst_multimap::MultiMap;
@ -23,6 +27,7 @@ pub use io::{
write_json, FileWithProgress,
};
pub use logs::{format_log_record, LogAdapter};
pub use random::{fork_rng, WeightedUsizeChoice};
pub use time::{elapsed_seconds, Timer};
const PROGRESS_FREQUENCY_SECONDS: f64 = 0.2;

41
abstutil/src/random.rs Normal file
View File

@ -0,0 +1,41 @@
use rand::distributions::{Distribution, Weighted, WeightedChoice};
use rand::{RngCore, SeedableRng, XorShiftRng};
// Need to explain this trick -- basically keeps consistency between two different simulations when
// each one might make slightly different sequences of calls to the RNG.
pub fn fork_rng(base_rng: &mut XorShiftRng) -> XorShiftRng {
XorShiftRng::from_seed([base_rng.next_u32() as u8; 16])
}
// Represents the probability of sampling 0, 1, 2, 3... The sum can be anything.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WeightedUsizeChoice {
pub weights: Vec<u32>,
}
impl WeightedUsizeChoice {
pub fn parse(string: &str) -> Option<WeightedUsizeChoice> {
let parts: Vec<&str> = string.split(",").collect();
if parts.is_empty() {
return None;
}
let mut weights: Vec<u32> = Vec::new();
for x in parts.into_iter() {
let x = x.parse::<u32>().ok()?;
weights.push(x);
}
Some(WeightedUsizeChoice { weights })
}
pub fn sample(&self, rng: &mut XorShiftRng) -> u32 {
let mut items: Vec<Weighted<u32>> = self
.weights
.iter()
.enumerate()
.map(|(idx, pr)| Weighted {
weight: *pr,
item: idx as u32,
}).collect();
WeightedChoice::new(&mut items).sample(rng)
}
}

View File

@ -28,14 +28,12 @@ pub mod turn_cycler;
pub mod warp;
use abstutil;
use abstutil::WeightedUsizeChoice;
use downcast::Any;
use ezgui::{Color, GfxCtx, WrappedWizard};
use map_model::{IntersectionID, Map};
use objects::{Ctx, ID};
use sim::{
ABTest, Neighborhood, NeighborhoodBuilder, OriginDestination, Scenario, Tick,
WeightedUsizeChoice,
};
use sim::{ABTest, Neighborhood, NeighborhoodBuilder, OriginDestination, Scenario, Tick};
use ui::PluginCtx;
pub trait Plugin: Any {

View File

@ -1,3 +1,4 @@
use abstutil::WeightedUsizeChoice;
use control::ControlMap;
use driving::DrivingGoal;
use map_model::{BuildingID, BusRoute, BusStopID, LaneID, Map, RoadID};
@ -5,7 +6,7 @@ use std::collections::{BTreeSet, VecDeque};
use walking::SidewalkSpot;
use {
BorderSpawnOverTime, CarID, Event, OriginDestination, PedestrianID, RouteID, Scenario,
SeedParkedCars, Sim, SpawnOverTime, Tick, WeightedUsizeChoice,
SeedParkedCars, Sim, SpawnOverTime, Tick,
};
// Helpers to run the sim

View File

@ -58,7 +58,6 @@ pub use make::{
OriginDestination, Scenario, SeedParkedCars, SimFlags, SpawnOverTime,
};
use map_model::{BuildingID, LaneID, Trace, TurnID};
use rand::{RngCore, SeedableRng, XorShiftRng};
pub use sim::{Benchmark, Sim, Summary};
pub use stats::SimStats;
use std::fmt;
@ -335,42 +334,3 @@ impl Cloneable for Scenario {}
impl Cloneable for Tick {}
impl Cloneable for MapEdits {}
impl Cloneable for ABTest {}
impl Cloneable for WeightedUsizeChoice {}
fn fork_rng(base_rng: &mut XorShiftRng) -> XorShiftRng {
XorShiftRng::from_seed([base_rng.next_u32() as u8; 16])
}
// Represents the probability of sampling 0, 1, 2, 3... The sum can be anything.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WeightedUsizeChoice {
weights: Vec<u32>,
}
impl WeightedUsizeChoice {
pub fn parse(string: &str) -> Option<WeightedUsizeChoice> {
let parts: Vec<&str> = string.split(",").collect();
if parts.is_empty() {
return None;
}
let mut weights: Vec<u32> = Vec::new();
for x in parts.into_iter() {
let x = x.parse::<u32>().ok()?;
weights.push(x);
}
Some(WeightedUsizeChoice { weights })
}
}
fn weighted_sample(choices: &WeightedUsizeChoice, rng: &mut XorShiftRng) -> u32 {
use rand::distributions::{Distribution, Weighted, WeightedChoice};
let mut items: Vec<Weighted<u32>> = choices
.weights
.iter()
.enumerate()
.map(|(idx, pr)| Weighted {
weight: *pr,
item: idx as u32,
}).collect();
WeightedChoice::new(&mut items).sample(rng)
}

View File

@ -1,11 +1,12 @@
use abstutil;
use abstutil::WeightedUsizeChoice;
use driving::DrivingGoal;
use map_model::{BuildingID, IntersectionID, LaneType, Map, RoadID};
use rand::Rng;
use rand::XorShiftRng;
use std::collections::{BTreeSet, HashMap, HashSet};
use walking::SidewalkSpot;
use {CarID, Neighborhood, Sim, Tick, WeightedUsizeChoice};
use {CarID, Neighborhood, Sim, Tick};
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Scenario {

View File

@ -1,4 +1,4 @@
use abstutil::elapsed_seconds;
use abstutil::{elapsed_seconds, fork_rng, WeightedUsizeChoice};
use dimensioned::si;
use driving::{CreateCar, DrivingGoal, DrivingSimState};
use kinematics::Vehicle;
@ -12,8 +12,7 @@ use transit::TransitSimState;
use trips::{TripLeg, TripManager};
use walking::{SidewalkSpot, WalkingSimState};
use {
fork_rng, weighted_sample, AgentID, CarID, Distance, Event, ParkedCar, ParkingSpot,
PedestrianID, RouteID, Tick, TripID, WeightedUsizeChoice,
AgentID, CarID, Distance, Event, ParkedCar, ParkingSpot, PedestrianID, RouteID, Tick, TripID,
};
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
@ -329,7 +328,7 @@ impl Spawner {
let mut new_cars = 0;
for b in owner_buildings {
for _ in 0..weighted_sample(&cars_per_building, base_rng) {
for _ in 0..cars_per_building.sample(base_rng) {
if let Some(spot) =
find_spot_near_building(*b, &mut open_spots_per_road, neighborhoods_roads, map)
{