use fixedbitset::FixedBitSet;
use crate::RangeJourney;
use crate::RaptorCache;
use crate::Timetable;
use crate::algorithm::boarding::extract_target_journeys;
use crate::algorithm::per_call::earliest_accessible_trip;
use crate::algorithm::per_call::run_raptor_rounds;
use crate::endpoints::Endpoints;
use crate::ids::RouteIdx;
use crate::label::ArrivalTime;
use crate::label::Label;
use crate::time::SecondOfDay;
pub(crate) fn filter_range_pareto_front<L: Label>(
mut all: Vec<RangeJourney<L>>,
) -> Vec<RangeJourney<L>> {
all.sort_by(|a, b| {
b.depart
.cmp(&a.depart)
.then(a.journey.plan.len().cmp(&b.journey.plan.len()))
.then(a.journey.arrival().cmp(&b.journey.arrival()))
});
let mut front: Vec<RangeJourney<L>> = Vec::with_capacity(all.len());
'outer: for r in all {
for f in &front {
if f.depart >= r.depart
&& f.journey.plan.len() <= r.journey.plan.len()
&& f.journey.label.dominates(&r.journey.label)
{
continue 'outer;
}
}
front.retain(|f| {
!(r.depart >= f.depart
&& r.journey.plan.len() <= f.journey.plan.len()
&& r.journey.label.dominates(&f.journey.label))
});
front.push(r);
}
front
}
pub(crate) fn newly_active_stops_into<T: Timetable + ?Sized>(
tt: &T,
lo: SecondOfDay,
hi: SecondOfDay,
marked: &mut FixedBitSet,
require_wheelchair_accessible: bool,
) {
if lo >= hi {
return;
}
let n_routes = tt.n_routes() as u32;
for r in 0..n_routes {
let route = RouteIdx::new(r);
let stops = tt.get_stops_after(route, 0);
for (pos_offset, &stop) in stops.iter().enumerate() {
let pos = pos_offset as u32;
if let Some(trip) =
earliest_accessible_trip(tt, route, lo, pos, require_wheelchair_accessible)
&& tt.get_departure_time(trip, pos) < hi
{
marked.insert(stop.idx());
}
}
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn raptor_range_rrap_arrival<T: Timetable + ?Sized>(
tt: &T,
cache: &mut RaptorCache<ArrivalTime>,
transfers: usize,
departures: &[SecondOfDay],
origins: Endpoints,
targets: Endpoints,
require_wheelchair_accessible: bool,
) -> Vec<RangeJourney<ArrivalTime>> {
let origins = origins.as_slice();
let targets = targets.as_slice();
cache.reset_for_query(transfers, tt.n_stops() as u32, tt.n_routes() as u32);
let RaptorCache {
labels,
best_arrival,
board_detail,
marked_stops,
q_entry,
q_routes,
walked_buf,
origin_set,
relax_heap,
ever_reached,
..
} = cache;
origin_set.clear();
for &(source, _) in origins {
origin_set.insert(source.idx());
}
let mut output: Vec<RangeJourney<ArrivalTime>> = Vec::new();
let mut prev_tau: Option<SecondOfDay> = None;
for &tau in departures {
marked_stops.clear();
for &(source, walk) in origins {
let seed = ArrivalTime(tau + walk);
if labels[0][source.idx()].insert(seed) {
best_arrival[source.idx()].insert(seed);
marked_stops.insert(source.idx());
ever_reached.insert(source.idx());
}
}
if let Some(prev) = prev_tau {
newly_active_stops_into(tt, tau, prev, marked_stops, require_wheelchair_accessible);
}
run_raptor_rounds(
tt,
labels,
best_arrival,
board_detail,
marked_stops,
q_entry,
q_routes,
walked_buf,
relax_heap,
ever_reached,
transfers,
require_wheelchair_accessible,
targets,
);
let snapshot =
extract_target_journeys(labels, board_detail, origin_set, targets, transfers);
for journey in snapshot {
output.push(RangeJourney {
depart: tau,
journey,
});
}
prev_tau = Some(tau);
}
filter_range_pareto_front(output)
}