A fresh attempt at finding the root causes of gridlock map-wide

This commit is contained in:
Dustin Carlino 2020-12-01 10:50:05 -08:00
parent b5ea263fc1
commit 2ebaf99e0d
4 changed files with 83 additions and 8 deletions

View File

@ -97,7 +97,7 @@ impl<T: Ord + PartialEq + Clone> Counter<T> {
self.map.get(&val).cloned().unwrap_or(0)
}
// Values with the same count are grouped together
/// Values with the same count are grouped together
pub fn sorted_asc(&self) -> Vec<Vec<T>> {
let mut list = self.map.iter().collect::<Vec<_>>();
list.sort_by_key(|(_, cnt)| *cnt);
@ -108,6 +108,18 @@ impl<T: Ord + PartialEq + Clone> Counter<T> {
.collect()
}
pub fn highest_n(&self, n: usize) -> Vec<(T, usize)> {
let mut list: Vec<(T, usize)> = self
.map
.iter()
.map(|(key, cnt)| (key.clone(), *cnt))
.collect();
list.sort_by_key(|(_, cnt)| *cnt);
list.reverse();
list.truncate(n);
list
}
pub fn max(&self) -> usize {
self.map.values().max().cloned().unwrap_or(0)
}

View File

@ -71,10 +71,10 @@ example:
"people": [
{
"origin": {
"Position": {
"Position": {
"longitude": -122.303723,
"latitude": 47.6372834
}
}
},
"trips": [
{

View File

@ -1,6 +1,7 @@
use std::collections::{BTreeMap, HashSet};
use geom::{ArrowCap, Distance, Duration, PolyLine, Polygon, Pt2D};
use abstutil::Counter;
use geom::{ArrowCap, Circle, Distance, Duration, PolyLine, Polygon, Pt2D};
use map_gui::Cached;
use sim::{AgentID, DelayCause};
use widgetry::{
@ -34,15 +35,17 @@ impl Viewer {
.map(|a| (a.id, a.pos))
.collect(),
arrows: Drawable::empty(ctx),
panel: Panel::new(
panel: Panel::new(Widget::col(vec![
Widget::row(vec![
Line("What agents are blocked by others?")
.small_heading()
.draw(ctx),
Btn::close(ctx),
]),
// TODO info about cycles
)
Text::from(Line("Root causes"))
.draw(ctx)
.named("root causes"),
]))
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx),
@ -55,6 +58,10 @@ impl Viewer {
arrows.push(color.alpha(0.5), arrow);
}
}
let (batch, txt) = viewer.find_worst_problems(app);
arrows.append(batch);
viewer.panel.replace(ctx, "root causes", txt.draw(ctx));
viewer.arrows = ctx.upload(arrows);
Box::new(viewer)
}
@ -112,6 +119,62 @@ impl Viewer {
}
(batch, reason)
}
/// Trace the root cause for everyone, find the most common sources, highlight them, and
/// describe them.
fn find_worst_problems(&self, app: &App) -> (GeomBatch, Text) {
let mut problems: Counter<DelayCause> = Counter::new();
for start in self.graph.keys() {
problems.inc(self.simple_root_cause(*start));
}
let mut batch = GeomBatch::new();
let mut txt = Text::from(Line("Root causes"));
for (cause, cnt) in problems.highest_n(3) {
txt.add(Line(format!("{:?} is blocking {} agents", cause, cnt)));
let pt = match cause {
DelayCause::Agent(a) => {
if let Some(pt) = self.agent_positions.get(&a) {
*pt
} else {
continue;
}
}
DelayCause::Intersection(i) => app.primary.map.get_i(i).polygon.center(),
};
batch.push(
Color::YELLOW,
Circle::new(pt, Distance::meters(5.0))
.to_outline(Distance::meters(1.0))
.unwrap(),
);
}
(batch, txt)
}
fn simple_root_cause(&self, start: AgentID) -> DelayCause {
let mut seen: HashSet<AgentID> = HashSet::new();
let mut current = start;
loop {
if seen.contains(&current) {
return DelayCause::Agent(current);
}
seen.insert(current);
match self.graph.get(&current) {
Some((_, DelayCause::Agent(a))) => {
current = *a;
}
Some((_, DelayCause::Intersection(i))) => {
return DelayCause::Intersection(*i);
}
None => {
return DelayCause::Agent(current);
}
}
}
}
}
impl State<App> for Viewer {

View File

@ -478,7 +478,7 @@ pub struct AgentProperties {
/// Why is an agent delayed? If there are multiple reasons, arbitrarily pick one -- ie, somebody
/// could be blocked by two conflicting turns.
#[derive(Serialize)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize)]
pub enum DelayCause {
/// Queued behind someone, or someone's doing a conflicting turn, or someone's eating up space
/// in a target queue