Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nigiri Praktikum #60

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .pkg.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
6084367865481574367
cista 05ba0e6c74195bb7921e178e9f7d850407172772
12671130249166382240
cista 04f84b0490e0e91ead20ae6eabed5add8f243ba0
res 7d97784ba785ce8a2677ea77164040fde484fb04
date 26d109612ddb8ba331edba7619a6452667f842bb
fmt c68ab4be8f3cb0e5c6eb181b3f419622e15e02bd
Expand All @@ -12,5 +12,5 @@ miniz 1edbdece9d71dc65c6ff405572ee37cbdcef7af4
protobuf 297171ade5e9bd01d823ffe8b203a5443ec03f15
unordered_dense 77e91016354e6d8cba24a86c5abb807de2534c02
Catch2 47d56f28a9801911c048d011b375e5631dbb658f
utl 71144d441da35f934e14904ac1e9492925017058
utl b81cfdccda166cef3c20dd41b4c9697b4137cea4
wyhash 1e012b57fc2227a9e583a57e2eacb3da99816d99
6 changes: 6 additions & 0 deletions include/nigiri/loader/loader_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ namespace nigiri::loader {

struct loader_config {
unsigned link_stop_distance_;
bool use_stationfilter_;
bool time_consistency_;
bool weighted_filter_;
double percent_for_filter_;
bool percentage_filter_;
bool line_filter_;
std::string_view default_tz_;
};

Expand Down
8 changes: 6 additions & 2 deletions include/nigiri/routing/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ struct search {

if (is_pretrip()) {
utl::erase_if(state_.results_, [&](journey const& j) {
return !search_interval_.contains(j.start_time_) ||
bool consistency = search_interval_.from_ - 1_minutes == j.start_time_
|| search_interval_.to_ == j.start_time_;
return (!search_interval_.contains(j.start_time_) && !consistency) ||
j.travel_time() >= fastest_direct_ ||
j.travel_time() > kMaxTravelTime;
});
Expand Down Expand Up @@ -321,8 +323,10 @@ struct search {
state_.results_);

for (auto& j : state_.results_) {
bool consistency = search_interval_.from_ - 1_minutes == j.start_time_
|| search_interval_.to_ == j.start_time_;
if (j.legs_.empty() &&
(is_ontrip() || search_interval_.contains(j.start_time_)) &&
(is_ontrip() || search_interval_.contains(j.start_time_) || consistency) &&
j.travel_time() < fastest_direct_) {
algo_.reconstruct(q_, j);
}
Expand Down
163 changes: 163 additions & 0 deletions include/nigiri/routing/station_filter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#pragma once

#include <cstring>

#include "nigiri/timetable.h"
#include "nigiri/types.h"
#include "utl/erase_if.h"

namespace nigiri::routing {
struct station_filter {

struct weight_info {
location_idx_t l_;
int weight_;
};

static void percentage_filter(std::vector<start>& starts, double percent, bool fwd) {
auto const min = [&](start const& a, start const& b) {
return a.time_at_stop_ < b.time_at_stop_;
};
auto const cmp = [&](start const& a, start const& b) {
return fwd ? b < a : a < b;
};
std::sort(starts.begin(), starts.end(), min);
size_t percent_to_dismiss = static_cast<size_t>(starts.size() * percent);
size_t new_size = starts.size() - percent_to_dismiss;
if(starts.at(starts.size()-1).time_at_stop_ == starts.at(0).time_at_stop_ || percent_to_dismiss == 0) {
return;
}
starts.resize(new_size);
//starts.shrink_to_fit();
std::sort(starts.begin(), starts.end(), cmp);
}

static void weighted_filter(std::vector<start>& starts, timetable const& tt, bool linefilter, bool fwd) {
double threshold = 20.0;
if(starts.size() > 80 && starts.size() < 400) {
threshold = 18.0;
}
if(starts.size() > 1000) {
threshold = 15.0;
}
if(starts.size() > 2000) {
threshold = 10.0;
}
vector<weight_info> v_weights;
int most = 1;
auto const weighted = [&](start const& a) {
location_idx_t l = a.stop_;
for(auto const w : v_weights) {
if(l == w.l_) {
double percent = w.weight_ * 100.0 / most;
return percent > threshold ? false : true;
}
}
return true;
};
// Example:
// dep_count = 3, local_count=2 *2=4, slow_count=1 *3=3, o=5 +4
// -> weight = 14
// dep_count = 2, slow_count=1 *3=3, fast_count=1 *4=4, o=10 +2
// -> weight = 11
// Offset Weights:
// 0-3min = 6; 3-5min = 5; 5-7min = 4; 7-10min = 3
// 10-15min = 2; 15-20min = 1; >20min = 0
for (auto const& s : starts) {
auto const l = s.stop_;
auto const o = fwd ? s.time_at_stop_ - s.time_at_start_ :
s.time_at_start_ - s.time_at_stop_;
auto dep_count = 0;
bool not_found = true;
for(auto dc : tt.depature_count_) {
if(dc.first == l) {
not_found = false;
dep_count = dc.second;
break;
}
}
if(not_found) {
continue;
}
int local_count = tt.get_groupclass_count(l, group::klocal) * 2;
int slow_count = tt.get_groupclass_count(l, group::kslow) * 3;
int fast_count = tt.get_groupclass_count(l, group::kfast) * 4;
int weight = local_count + slow_count + fast_count + dep_count;
if(o.count() >= 15 && o.count() < 20) weight += 1;
if(o.count() >= 10 && o.count() < 15) weight += 2;
if(o.count() >= 7 && o.count() < 10) weight += 3;
if(o.count() >= 5 && o.count() < 7) weight += 4;
if(o.count() >= 3 && o.count() < 5) weight += 5;
if(o.count() >= 0 && o.count() < 3) weight += 6;
int extra_weight = 0;
if(linefilter) {
extra_weight = line_filter(starts, tt, s, fwd);
}
weight += extra_weight;
weight_info wi = {l, weight};
v_weights.emplace_back(wi);
most = weight > most ? weight : most;
}
if(most == 1) {
return;
}
utl::erase_if(starts, weighted);
}

static vector<location_idx_t> find_lines(route_idx_t find, timetable const& tt) {
vector<location_idx_t> found_at;
for(auto lidx = location_idx_t{0}; lidx < tt.location_routes_.size(); lidx++) {
for(route_idx_t rix : tt.location_routes_.at(lidx)) {
if(find == rix) {
found_at.emplace_back(lidx);
}
}
}
return found_at;
}

static start find_start_from_locidx(std::vector<start>& starts, location_idx_t locidx) {
for(start s : starts) {
if(s.stop_ == locidx) return s;
}
return start();
}

static int line_filter(std::vector<start>& starts, timetable const& tt, start this_start, bool fwd) {
duration_t o = fwd ? this_start.time_at_stop_ - this_start.time_at_start_ :
this_start.time_at_start_ - this_start.time_at_stop_;
location_idx_t l = this_start.stop_;
int weight_count = 0;
duration_t dur_off;
unixtime_t null{};
auto const this_start_lines = tt.location_routes_.at(l);
vector<location_idx_t> v_li;
for(route_idx_t line : this_start_lines) {
v_li = find_lines(line, tt);
for (auto const a : v_li) {
start s = find_start_from_locidx(starts, a);
if (s.time_at_stop_ == null && s.time_at_start_ == null &&
s.stop_ == 0) {
continue;
}
dur_off = fwd ? s.time_at_stop_ - s.time_at_start_ :
s.time_at_start_ - s.time_at_stop_;
if (o < dur_off || this_start.time_at_stop_ < s.time_at_stop_) {
weight_count++;
}
}
}
return weight_count;
}

static void filter_stations(std::vector<start>& starts, timetable const& tt, bool fwd) {
if(tt.percentage_filter_) {
percentage_filter(starts, tt.percent_for_filter_, fwd);
}
if(tt.weighted_filter_) {
weighted_filter(starts, tt, tt.line_filter_, fwd);
}
}

};
} // namespace nigiri::routing
27 changes: 27 additions & 0 deletions include/nigiri/timetable.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,39 @@ struct timetable {
trip_debug_[trip_idx].front().line_number_to_};
}

// --- Filter Data ---
// how many departures are at l with classgroup x
int get_groupclass_count(location_idx_t const ix, group classgroup) const {
for(const auto& col : classgroups_on_loc_) {
if(col.first == ix) {
switch (classgroup) {
case group::klocal: return col.second.at(0);
case group::kslow: return col.second.at(1);
case group::kfast: return col.second.at(2);
case group::kaway: return col.second.at(3);
default: return 0;
}
}
}
return 0;
}

friend std::ostream& operator<<(std::ostream&, timetable const&);

void write(cista::memory_holder&) const;
void write(std::filesystem::path const&) const;
static cista::wrapped<timetable> read(cista::memory_holder&&);

// Filter
bool use_station_filter_;
bool time_consistency_;
bool weighted_filter_;
double percent_for_filter_;
bool percentage_filter_;
bool line_filter_;
vector<pair<location_idx_t, size_t>> depature_count_;
vector<pair<location_idx_t, vector<int>>> classgroups_on_loc_;

// Schedule range.
interval<date::sys_days> date_range_;

Expand Down
12 changes: 12 additions & 0 deletions include/nigiri/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,18 @@ enum class clasz : std::uint8_t {
kNumClasses
};

// Group of clasz for filter, to add weight
// local: kMetro, kSubway, kTram, kBus
// slow: kLongDistance, kRegional, kNight
// fast: kHighSpeed, kRegionalFast
// away: kAir, kCoach, kShip, kOther
enum class group : std::uint8_t {
klocal = 0,
kslow = 1,
kfast = 2,
kaway = 3
};

constexpr auto const kNumClasses =
static_cast<std::underlying_type_t<clasz>>(clasz::kNumClasses);

Expand Down
37 changes: 36 additions & 1 deletion src/loader/gtfs/load_timetable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ void load_timetable(loader_config const& config,
timetable& tt) {
nigiri::scoped_timer const global_timer{"gtfs parser"};

tt.use_station_filter_ = config.use_stationfilter_;
tt.time_consistency_ = config.time_consistency_;
tt.weighted_filter_ = config.weighted_filter_;
tt.percent_for_filter_ = config.percent_for_filter_;
tt.line_filter_ = config.line_filter_;
tt.percentage_filter_ = config.percentage_filter_;

auto const load = [&](std::string_view file_name) -> file {
return d.exists(file_name) ? d.get_file(file_name) : file{};
};
Expand Down Expand Up @@ -335,16 +342,44 @@ void load_timetable(loader_config const& config,
progress_tracker->increment();
}

// Build location_routes map
// Build location_routes map and filter data for station filter
for (auto l = tt.location_routes_.size(); l != tt.n_locations(); ++l) {
tt.location_routes_.emplace_back(location_routes[location_idx_t{l}]);
assert(tt.location_routes_.size() == l + 1U);
if(tt.use_station_filter_) {
pair<location_idx_t, size_t> temp =
{location_idx_t{l}, location_routes[location_idx_t{l}].size()};
tt.depature_count_.emplace_back(temp);
int local = 0;
int slow = 0;
int fast = 0;
int away = 0;
for(auto const r : location_routes[location_idx_t{l}]) {
clasz klasse = tt.route_section_clasz_.at(route_idx_t{r}).at(0);
if(klasse == clasz::kMetro || klasse == clasz::kBus || klasse == clasz::kTram || klasse == clasz::kSubway) {
local++;
}
else if(klasse == clasz::kLongDistance || klasse == clasz::kRegional || klasse == clasz::kNight) {
slow++;
}
else if(klasse == clasz::kHighSpeed || klasse == clasz::kRegionalFast) {
fast++;
}
else if(klasse == clasz::kAir || klasse == clasz::kCoach || klasse == clasz::kShip || klasse == clasz::kOther) {
away++;
}
}
vector<int> groups = {local, slow, fast, away};
pair<location_idx_t, vector<int>> classcount = {location_idx_t{l}, groups};
tt.classgroups_on_loc_.emplace_back(classcount);
}
}

// Build transport ranges.
for (auto const& t : trip_data.data_) {
tt.trip_transport_ranges_.emplace_back(t.transport_ranges_);
}

}
}

Expand Down
9 changes: 8 additions & 1 deletion src/loader/hrd/loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ bool hrd_loader::applicable(dir const& d) const {
return nigiri::loader::hrd::applicable(config_, d);
}

void hrd_loader::load(loader_config const&,
void hrd_loader::load(loader_config const& config,
source_idx_t const src,
dir const& d,
timetable& tt) const {
tt.use_station_filter_ = config.use_stationfilter_;
tt.time_consistency_ = config.time_consistency_;
tt.weighted_filter_ = config.weighted_filter_;
tt.percent_for_filter_ = config.percent_for_filter_;
tt.line_filter_ = config.line_filter_;
tt.percentage_filter_ = config.percentage_filter_;
return nigiri::loader::hrd::load_timetable(src, config_, d, tt);
}


cista::hash_t hrd_loader::hash(dir const& d) const {
return nigiri::loader::hrd::hash(config_, d);
}
Expand Down
27 changes: 27 additions & 0 deletions src/loader/hrd/service/service_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,33 @@ void service_builder::write_location_routes() {
for (auto l = tt_.location_routes_.size(); l != tt_.n_locations(); ++l) {
tt_.location_routes_.emplace_back(location_routes_[location_idx_t{l}]);
assert(tt_.location_routes_.size() == l + 1U);
if(tt_.use_station_filter_) {
pair<location_idx_t, size_t> temp =
{location_idx_t{l}, location_routes_[location_idx_t{l}].size()};
tt_.depature_count_.emplace_back(temp);
int local = 0;
int slow = 0;
int fast = 0;
int away = 0;
for(auto const r : location_routes_[location_idx_t{l}]) {
clasz klasse = tt_.route_section_clasz_.at(route_idx_t{r}).at(0);
if(klasse == clasz::kMetro || klasse == clasz::kBus || klasse == clasz::kTram || klasse == clasz::kSubway) {
local++;
}
else if(klasse == clasz::kLongDistance || klasse == clasz::kRegional || klasse == clasz::kNight) {
slow++;
}
else if(klasse == clasz::kHighSpeed || klasse == clasz::kRegionalFast) {
fast++;
}
else if(klasse == clasz::kAir || klasse == clasz::kCoach || klasse == clasz::kShip || klasse == clasz::kOther) {
away++;
}
}
vector<int> groups = {local, slow, fast, away};
pair<location_idx_t, vector<int>> classcount = {location_idx_t{l}, groups};
tt_.classgroups_on_loc_.emplace_back(classcount);
}
}
}

Expand Down
Loading