* speed up hop-to-hop calculations
* better and faster trip clustering: trip tries * add --write-colors to extract line colors from OSM data * refactor config parameter names, update default pfaedle.cfg * add --stats for writing a stats.json file * add --no-fast-hops, --no-a-star, --no-trie for debugging * general refactoring
This commit is contained in:
parent
f1822868c5
commit
4c29892658
126 changed files with 14576 additions and 12196 deletions
|
|
@ -16,7 +16,7 @@ namespace router {
|
|||
using util::editDist;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline double statSimi(const std::string& a, const std::string& b) {
|
||||
inline bool statSimi(const std::string& a, const std::string& b) {
|
||||
if (a == b) return 1;
|
||||
|
||||
if (a.empty() || b.empty()) return 0;
|
||||
|
|
@ -55,7 +55,7 @@ inline double statSimi(const std::string& a, const std::string& b) {
|
|||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline double lineSimi(const std::string& a, const std::string& b) {
|
||||
inline bool lineSimi(const std::string& a, const std::string& b) {
|
||||
if (a == b) return 1;
|
||||
|
||||
if (a.empty() || b.empty()) return 0;
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include "pfaedle/Def.h"
|
||||
#include "util/geo/Geo.h"
|
||||
#include "pfaedle/router/EdgePL.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "util/String.h"
|
||||
|
||||
using pfaedle::router::EdgePL;
|
||||
using pfaedle::router::EdgeCost;
|
||||
using pfaedle::router::EdgeList;
|
||||
using pfaedle::trgraph::Node;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeList* EdgePL::getEdges() { return &_edges; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const EdgeList& EdgePL::getEdges() const { return _edges; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const POINT& EdgePL::frontHop() const {
|
||||
if (!_edges.size()) return *_end->pl().getGeom();
|
||||
return _edges.back()->pl().frontHop();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const POINT& EdgePL::backHop() const {
|
||||
if (!_edges.size()) return *_start->pl().getGeom();
|
||||
return _edges.front()->pl().backHop();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const Node* EdgePL::backNode() const { return _end; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const Node* EdgePL::frontNode() const { return _start; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const LINE* EdgePL::getGeom() const {
|
||||
if (!_edges.size()) return 0;
|
||||
if (!_geom.size()) {
|
||||
const trgraph::Node* l = _start;
|
||||
for (auto i = _edges.rbegin(); i != _edges.rend(); i++) {
|
||||
const auto e = *i;
|
||||
if ((e->getFrom() == l) ^ e->pl().isRev()) {
|
||||
_geom.insert(_geom.end(), e->pl().getGeom()->begin(),
|
||||
e->pl().getGeom()->end());
|
||||
} else {
|
||||
_geom.insert(_geom.end(), e->pl().getGeom()->rbegin(),
|
||||
e->pl().getGeom()->rend());
|
||||
}
|
||||
l = e->getOtherNd(l);
|
||||
}
|
||||
}
|
||||
|
||||
return &_geom;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setStartNode(const trgraph::Node* s) { _start = s; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setEndNode(const trgraph::Node* e) { _end = e; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setStartEdge(const trgraph::Edge* s) { _startE = s; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setEndEdge(const trgraph::Edge* e) { _endE = e; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const EdgeCost& EdgePL::getCost() const { return _cost; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setCost(const router::EdgeCost& c) { _cost = c; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
util::json::Dict EdgePL::getAttrs() const {
|
||||
util::json::Dict obj;
|
||||
obj["cost"] = std::to_string(_cost.getValue());
|
||||
obj["from_edge"] = util::toString(_startE);
|
||||
obj["to_edge"] = util::toString(_endE);
|
||||
obj["dummy"] = _edges.size() ? "no" : "yes";
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_EDGEPL_H_
|
||||
#define PFAEDLE_ROUTER_EDGEPL_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "pfaedle/Def.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "util/geo/Geo.h"
|
||||
#include "util/geo/GeoGraph.h"
|
||||
|
||||
using util::geograph::GeoEdgePL;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class EdgePL {
|
||||
public:
|
||||
EdgePL() : _cost(), _start(0), _end(0), _startE(0), _endE(0) {}
|
||||
const LINE* getGeom() const;
|
||||
util::json::Dict getAttrs() const;
|
||||
router::EdgeList* getEdges();
|
||||
const router::EdgeList& getEdges() const;
|
||||
void setStartNode(const trgraph::Node* s);
|
||||
void setEndNode(const trgraph::Node* s);
|
||||
void setStartEdge(const trgraph::Edge* s);
|
||||
void setEndEdge(const trgraph::Edge* s);
|
||||
const router::EdgeCost& getCost() const;
|
||||
void setCost(const router::EdgeCost& c);
|
||||
const POINT& frontHop() const;
|
||||
const POINT& backHop() const;
|
||||
const trgraph::Node* frontNode() const;
|
||||
const trgraph::Node* backNode() const;
|
||||
|
||||
private:
|
||||
router::EdgeCost _cost;
|
||||
// the edges are in this field in REVERSED ORDER!
|
||||
router::EdgeList _edges;
|
||||
const trgraph::Node* _start;
|
||||
const trgraph::Node* _end;
|
||||
const trgraph::Edge* _startE;
|
||||
const trgraph::Edge* _endE;
|
||||
mutable LINE _geom;
|
||||
};
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_EDGEPL_H_
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_GRAPH_H_
|
||||
#define PFAEDLE_ROUTER_GRAPH_H_
|
||||
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "pfaedle/router/EdgePL.h"
|
||||
#include "pfaedle/router/NodePL.h"
|
||||
#include "util/graph/DirGraph.h"
|
||||
|
||||
using util::geo::Point;
|
||||
using util::geo::Line;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
typedef util::graph::Edge<router::NodePL, router::EdgePL> Edge;
|
||||
typedef util::graph::Node<router::NodePL, router::EdgePL> Node;
|
||||
typedef util::graph::DirGraph<router::NodePL, router::EdgePL> Graph;
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_GRAPH_H_
|
||||
40
src/pfaedle/router/HopCache.cpp
Normal file
40
src/pfaedle/router/HopCache.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2020, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <utility>
|
||||
#include <set>
|
||||
#include "pfaedle/router/HopCache.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/Misc.h"
|
||||
|
||||
using pfaedle::router::HopCache;
|
||||
using pfaedle::trgraph::Edge;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void HopCache::setMin(const Edge* a, const Edge* b, uint32_t val) {
|
||||
_cache.set(a, b, val);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void HopCache::setEx(const Edge* a, const Edge* b, uint32_t val) {
|
||||
int64_t v = val;
|
||||
_cache.set(a, b, -(v + 1));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void HopCache::setMin(const Edge* a, const std::set<Edge*>& b, uint32_t val) {
|
||||
for (auto eb : b) _cache.set(a, eb, val);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void HopCache::setMin(const std::set<Edge*>& a, const Edge* b, uint32_t val) {
|
||||
for (auto ea : a) _cache.set(ea, b, val);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::pair<uint32_t, bool> HopCache::get(const Edge* a, const Edge* b) const {
|
||||
int64_t v = _cache.get(a, b);
|
||||
if (v < 0) return {(-v) - 1, 1};
|
||||
return {v, 0};
|
||||
}
|
||||
39
src/pfaedle/router/HopCache.h
Normal file
39
src/pfaedle/router/HopCache.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2020, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_HOPCACHE_H_
|
||||
#define PFAEDLE_ROUTER_HOPCACHE_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/Misc.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class HopCache {
|
||||
public:
|
||||
void setMin(const trgraph::Edge* a, const trgraph::Edge* b, uint32_t val);
|
||||
|
||||
void setMin(const trgraph::Edge* a, const std::set<trgraph::Edge*>& b,
|
||||
uint32_t val);
|
||||
|
||||
void setMin(const std::set<trgraph::Edge*>& a, const trgraph::Edge* b,
|
||||
uint32_t val);
|
||||
|
||||
void setEx(const trgraph::Edge* a, const trgraph::Edge* b, uint32_t val);
|
||||
|
||||
std::pair<uint32_t, bool> get(const trgraph::Edge* a,
|
||||
const trgraph::Edge* b) const;
|
||||
|
||||
private:
|
||||
util::SparseMatrix<const trgraph::Edge*, int64_t, 0> _cache;
|
||||
};
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_HOPCACHE_H_
|
||||
|
|
@ -21,132 +21,75 @@ using ad::cppgtfs::gtfs::Stop;
|
|||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
struct NodeCand {
|
||||
trgraph::Node* nd;
|
||||
double pen;
|
||||
};
|
||||
extern double time;
|
||||
|
||||
struct EdgeCand {
|
||||
trgraph::Edge* e;
|
||||
double pen;
|
||||
double progr;
|
||||
POINT point;
|
||||
int time;
|
||||
std::vector<size_t> depPrede;
|
||||
};
|
||||
|
||||
struct RoutingOpts {
|
||||
RoutingOpts()
|
||||
: fullTurnPunishFac(2000),
|
||||
: fullTurnPunishFac(1000),
|
||||
fullTurnAngle(45),
|
||||
passThruStationsPunish(100),
|
||||
oneWayPunishFac(1),
|
||||
oneWayEdgePunish(0),
|
||||
lineUnmatchedPunishFact(0.5),
|
||||
noLinesPunishFact(0),
|
||||
lineUnmatchedPunishFact(1),
|
||||
lineNameFromUnmatchedPunishFact(1),
|
||||
lineNameToUnmatchedPunishFact(1),
|
||||
noLinesPunishFact(1),
|
||||
platformUnmatchedPen(0),
|
||||
stationDistPenFactor(0),
|
||||
turnRestrCost(0),
|
||||
popReachEdge(true),
|
||||
noSelfHops(true) {}
|
||||
double fullTurnPunishFac;
|
||||
uint32_t fullTurnPunishFac;
|
||||
double fullTurnAngle;
|
||||
double passThruStationsPunish;
|
||||
double oneWayPunishFac;
|
||||
double oneWayEdgePunish;
|
||||
double lineUnmatchedPunishFact;
|
||||
double lineNameFromUnmatchedPunishFact;
|
||||
double lineNameToUnmatchedPunishFact;
|
||||
double noLinesPunishFact;
|
||||
double platformUnmatchedPen;
|
||||
double stationUnmatchedPen;
|
||||
double stationDistPenFactor;
|
||||
double nonOsmPen;
|
||||
double levelPunish[8];
|
||||
double nonStationPen;
|
||||
uint32_t turnRestrCost;
|
||||
bool popReachEdge;
|
||||
bool noSelfHops;
|
||||
bool useStations;
|
||||
double transitionPen;
|
||||
std::string transPenMethod;
|
||||
};
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline bool operator==(const RoutingOpts& a, const RoutingOpts& b) {
|
||||
return fabs(a.fullTurnPunishFac - b.fullTurnPunishFac) < 0.01 &&
|
||||
return a.fullTurnPunishFac == b.fullTurnPunishFac &&
|
||||
fabs(a.fullTurnAngle - b.fullTurnAngle) < 0.01 &&
|
||||
fabs(a.passThruStationsPunish - b.passThruStationsPunish) < 0.01 &&
|
||||
fabs(a.oneWayPunishFac - b.oneWayPunishFac) < 0.01 &&
|
||||
fabs(a.oneWayEdgePunish - b.oneWayEdgePunish) < 0.01 &&
|
||||
fabs(a.lineUnmatchedPunishFact - b.lineUnmatchedPunishFact) < 0.01 &&
|
||||
fabs(a.lineNameFromUnmatchedPunishFact -
|
||||
b.lineNameFromUnmatchedPunishFact) < 0.01 &&
|
||||
fabs(a.lineNameToUnmatchedPunishFact -
|
||||
b.lineNameToUnmatchedPunishFact) < 0.01 &&
|
||||
fabs(a.noLinesPunishFact - b.noLinesPunishFact) < 0.01 &&
|
||||
fabs(a.platformUnmatchedPen - b.platformUnmatchedPen) < 0.01 &&
|
||||
fabs(a.stationUnmatchedPen - b.stationUnmatchedPen) < 0.01 &&
|
||||
fabs(a.stationDistPenFactor - b.stationDistPenFactor) < 0.01 &&
|
||||
fabs(a.nonOsmPen - b.nonOsmPen) < 0.01 &&
|
||||
fabs(a.levelPunish[0] - b.levelPunish[0]) < 0.01 &&
|
||||
fabs(a.levelPunish[1] - b.levelPunish[1]) < 0.01 &&
|
||||
fabs(a.levelPunish[2] - b.levelPunish[2]) < 0.01 &&
|
||||
fabs(a.levelPunish[3] - b.levelPunish[3]) < 0.01 &&
|
||||
fabs(a.levelPunish[4] - b.levelPunish[4]) < 0.01 &&
|
||||
fabs(a.levelPunish[5] - b.levelPunish[5]) < 0.01 &&
|
||||
fabs(a.levelPunish[6] - b.levelPunish[6]) < 0.01 &&
|
||||
fabs(a.levelPunish[7] - b.levelPunish[7]) < 0.01 &&
|
||||
a.popReachEdge == b.popReachEdge && a.noSelfHops == b.noSelfHops;
|
||||
}
|
||||
|
||||
struct EdgeCost {
|
||||
EdgeCost() : _cost(0) {}
|
||||
explicit EdgeCost(double cost) : _cost(cost) {}
|
||||
EdgeCost(double mDist, double mDistLvl1, double mDistLvl2, double mDistLvl3,
|
||||
double mDistLvl4, double mDistLvl5, double mDistLvl6,
|
||||
double mDistLvl7, uint32_t fullTurns, int32_t passThru,
|
||||
double oneWayMeters, size_t oneWayEdges, double lineUnmatchedMeters,
|
||||
double noLinesMeters, double reachPen, const RoutingOpts* o) {
|
||||
if (!o) {
|
||||
_cost = mDist + reachPen;
|
||||
} else {
|
||||
_cost = mDist * o->levelPunish[0] + mDistLvl1 * o->levelPunish[1] +
|
||||
mDistLvl2 * o->levelPunish[2] + mDistLvl3 * o->levelPunish[3] +
|
||||
mDistLvl4 * o->levelPunish[4] + mDistLvl5 * o->levelPunish[5] +
|
||||
mDistLvl6 * o->levelPunish[6] + mDistLvl7 * o->levelPunish[7] +
|
||||
oneWayMeters * o->oneWayPunishFac +
|
||||
oneWayEdges * o->oneWayEdgePunish +
|
||||
lineUnmatchedMeters * o->lineUnmatchedPunishFact +
|
||||
noLinesMeters * o->noLinesPunishFact +
|
||||
fullTurns * o->fullTurnPunishFac +
|
||||
passThru * o->passThruStationsPunish + reachPen;
|
||||
}
|
||||
}
|
||||
|
||||
float _cost;
|
||||
|
||||
double getValue() const { return _cost; }
|
||||
};
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline EdgeCost operator+(const EdgeCost& a, const EdgeCost& b) {
|
||||
return EdgeCost(a.getValue() + b.getValue());
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline bool operator<=(const EdgeCost& a, const EdgeCost& b) {
|
||||
return a.getValue() <= b.getValue();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline bool operator==(const EdgeCost& a, const EdgeCost& b) {
|
||||
return a.getValue() == b.getValue();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline bool operator>(const EdgeCost& a, const EdgeCost& b) {
|
||||
return a.getValue() > b.getValue();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename F>
|
||||
inline bool angSmaller(const Point<F>& f, const Point<F>& m, const Point<F>& t,
|
||||
double ang) {
|
||||
if (util::geo::innerProd(m, f, t) < ang) return 1;
|
||||
return 0;
|
||||
a.turnRestrCost == b.turnRestrCost &&
|
||||
fabs(a.transitionPen - b.transitionPen) < 0.01 &&
|
||||
fabs(a.nonStationPen - b.nonStationPen) < 0.01 &&
|
||||
a.transPenMethod == b.transPenMethod &&
|
||||
a.useStations == b.useStations && a.popReachEdge == b.popReachEdge &&
|
||||
a.noSelfHops == b.noSelfHops;
|
||||
}
|
||||
|
||||
typedef std::set<trgraph::Node*> NodeSet;
|
||||
typedef std::set<trgraph::Edge*> EdgeSet;
|
||||
typedef std::unordered_map<const Stop*, trgraph::Node*> FeedStops;
|
||||
|
||||
typedef std::vector<NodeCand> NodeCandGroup;
|
||||
typedef std::vector<NodeCandGroup> NodeCandRoute;
|
||||
|
||||
typedef std::vector<EdgeCand> EdgeCandGroup;
|
||||
typedef std::vector<EdgeCandGroup> EdgeCandMap;
|
||||
typedef std::vector<EdgeCandGroup> EdgeCandRoute;
|
||||
|
||||
typedef std::vector<trgraph::Edge*> EdgeList;
|
||||
|
|
@ -154,8 +97,12 @@ typedef std::vector<trgraph::Node*> NodeList;
|
|||
|
||||
struct EdgeListHop {
|
||||
EdgeList edges;
|
||||
const trgraph::Node* start;
|
||||
const trgraph::Node* end;
|
||||
const trgraph::Edge* start;
|
||||
const trgraph::Edge* end;
|
||||
double progrStart;
|
||||
double progrEnd;
|
||||
POINT pointStart;
|
||||
POINT pointEnd;
|
||||
};
|
||||
|
||||
typedef std::vector<EdgeListHop> EdgeListHops;
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_NODEPL_H_
|
||||
#define PFAEDLE_ROUTER_NODEPL_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/geo/GeoGraph.h"
|
||||
#include "util/geo/Geo.h"
|
||||
#include "pfaedle/Def.h"
|
||||
|
||||
using util::geograph::GeoNodePL;
|
||||
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class NodePL {
|
||||
public:
|
||||
NodePL() : _n(0) {}
|
||||
NodePL(const pfaedle::trgraph::Node* n) : _n(n) {} // NOLINT
|
||||
|
||||
const POINT* getGeom() const {
|
||||
return !_n ? 0 : _n->pl().getGeom();
|
||||
}
|
||||
util::json::Dict getAttrs() const {
|
||||
if (_n) return _n->pl().getAttrs();
|
||||
return util::json::Dict();
|
||||
}
|
||||
|
||||
private:
|
||||
const pfaedle::trgraph::Node* _n;
|
||||
};
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_NODEPL_H_
|
||||
|
|
@ -1,646 +0,0 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#else
|
||||
#define omp_get_thread_num() 0
|
||||
#define omp_get_num_procs() 1
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "pfaedle/router/Comp.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "pfaedle/router/RoutingAttrs.h"
|
||||
#include "util/geo/output/GeoGraphJsonOutput.h"
|
||||
#include "util/graph/Dijkstra.h"
|
||||
#include "util/graph/EDijkstra.h"
|
||||
#include "util/log/Log.h"
|
||||
|
||||
using pfaedle::router::Router;
|
||||
using pfaedle::router::EdgeCost;
|
||||
using pfaedle::router::CostFunc;
|
||||
using pfaedle::router::DistHeur;
|
||||
using pfaedle::router::NCostFunc;
|
||||
using pfaedle::router::NDistHeur;
|
||||
using pfaedle::router::CombCostFunc;
|
||||
using pfaedle::router::EdgeListHop;
|
||||
using pfaedle::router::EdgeListHops;
|
||||
using pfaedle::router::RoutingOpts;
|
||||
using pfaedle::router::RoutingAttrs;
|
||||
using pfaedle::router::HopBand;
|
||||
using pfaedle::router::NodeCandRoute;
|
||||
using util::graph::EDijkstra;
|
||||
using util::graph::Dijkstra;
|
||||
using util::geo::webMercMeterDist;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost NCostFunc::operator()(const trgraph::Node* from,
|
||||
const trgraph::Edge* e,
|
||||
const trgraph::Node* to) const {
|
||||
UNUSED(to);
|
||||
if (!from) return EdgeCost();
|
||||
|
||||
int oneway = e->pl().oneWay() == 2;
|
||||
int32_t stationSkip = 0;
|
||||
|
||||
return EdgeCost(e->pl().lvl() == 0 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 1 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 2 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 3 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 4 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 5 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 6 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 7 ? e->pl().getLength() : 0, 0, stationSkip,
|
||||
e->pl().getLength() * oneway, oneway, 0, 0, 0, &_rOpts);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost CostFunc::operator()(const trgraph::Edge* from, const trgraph::Node* n,
|
||||
const trgraph::Edge* to) const {
|
||||
if (!from) return EdgeCost();
|
||||
|
||||
uint32_t fullTurns = 0;
|
||||
int oneway = from->pl().oneWay() == 2;
|
||||
int32_t stationSkip = 0;
|
||||
|
||||
if (n) {
|
||||
if (from->getFrom() == to->getTo() && from->getTo() == to->getFrom()) {
|
||||
// trivial full turn
|
||||
fullTurns = 1;
|
||||
} else if (n->getDeg() > 2) {
|
||||
// otherwise, only intersection angles will be punished
|
||||
fullTurns = router::angSmaller(from->pl().backHop(), *n->pl().getGeom(),
|
||||
to->pl().frontHop(), _rOpts.fullTurnAngle);
|
||||
}
|
||||
|
||||
if (from->pl().isRestricted() && !_res.may(from, to, n)) oneway = 1;
|
||||
|
||||
// for debugging
|
||||
n->pl().setVisited();
|
||||
|
||||
if (_tgGrp && n->pl().getSI() && n->pl().getSI()->getGroup() != _tgGrp)
|
||||
stationSkip = 1;
|
||||
}
|
||||
|
||||
double transitLinePen = transitLineCmp(from->pl());
|
||||
bool noLines = (_rAttrs.shortName.empty() && _rAttrs.toString.empty() &&
|
||||
_rAttrs.fromString.empty() && from->pl().getLines().empty());
|
||||
|
||||
return EdgeCost(from->pl().lvl() == 0 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 1 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 2 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 3 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 4 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 5 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 6 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 7 ? from->pl().getLength() : 0, fullTurns,
|
||||
stationSkip, from->pl().getLength() * oneway, oneway,
|
||||
from->pl().getLength() * transitLinePen,
|
||||
noLines ? from->pl().getLength() : 0, 0, &_rOpts);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double CostFunc::transitLineCmp(const trgraph::EdgePL& e) const {
|
||||
if (_rAttrs.shortName.empty() && _rAttrs.toString.empty() &&
|
||||
_rAttrs.fromString.empty())
|
||||
return 0;
|
||||
double best = 1;
|
||||
for (const auto* l : e.getLines()) {
|
||||
double cur = _rAttrs.simi(l);
|
||||
|
||||
if (cur < 0.0001) return 0;
|
||||
if (cur < best) best = cur;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
NDistHeur::NDistHeur(const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Node*>& tos)
|
||||
: _rOpts(rOpts), _maxCentD(0) {
|
||||
size_t c = 0;
|
||||
double x = 0, y = 0;
|
||||
for (auto to : tos) {
|
||||
x += to->pl().getGeom()->getX();
|
||||
y += to->pl().getGeom()->getY();
|
||||
c++;
|
||||
}
|
||||
|
||||
x /= c;
|
||||
y /= c;
|
||||
_center = POINT(x, y);
|
||||
|
||||
for (auto to : tos) {
|
||||
double cur = webMercMeterDist(*to->pl().getGeom(), _center);
|
||||
if (cur > _maxCentD) _maxCentD = cur;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
DistHeur::DistHeur(uint8_t minLvl, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos)
|
||||
: _rOpts(rOpts), _lvl(minLvl), _maxCentD(0) {
|
||||
size_t c = 0;
|
||||
double x = 0, y = 0;
|
||||
for (auto to : tos) {
|
||||
x += to->getFrom()->pl().getGeom()->getX();
|
||||
y += to->getFrom()->pl().getGeom()->getY();
|
||||
c++;
|
||||
}
|
||||
|
||||
x /= c;
|
||||
y /= c;
|
||||
_center = POINT(x, y);
|
||||
|
||||
for (auto to : tos) {
|
||||
double cur = webMercMeterDist(*to->getFrom()->pl().getGeom(), _center) *
|
||||
_rOpts.levelPunish[_lvl];
|
||||
if (cur > _maxCentD) _maxCentD = cur;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost DistHeur::operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const {
|
||||
UNUSED(b);
|
||||
double cur = webMercMeterDist(*a->getFrom()->pl().getGeom(), _center) *
|
||||
_rOpts.levelPunish[_lvl];
|
||||
|
||||
return EdgeCost(cur - _maxCentD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost NDistHeur::operator()(const trgraph::Node* a,
|
||||
const std::set<trgraph::Node*>& b) const {
|
||||
UNUSED(b);
|
||||
double cur = webMercMeterDist(*a->pl().getGeom(), _center);
|
||||
|
||||
return EdgeCost(cur - _maxCentD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double CombCostFunc::operator()(const router::Edge* from, const router::Node* n,
|
||||
const router::Edge* to) const {
|
||||
UNUSED(n);
|
||||
UNUSED(from);
|
||||
return to->pl().getCost().getValue();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
Router::Router(size_t numThreads, bool caching)
|
||||
: _cache(numThreads), _caching(caching) {
|
||||
for (size_t i = 0; i < numThreads; i++) {
|
||||
_cache[i] = new Cache();
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
Router::~Router() {
|
||||
for (size_t i = 0; i < _cache.size(); i++) {
|
||||
delete _cache[i];
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool Router::compConned(const EdgeCandGroup& a, const EdgeCandGroup& b) const {
|
||||
for (auto n1 : a) {
|
||||
for (auto n2 : b) {
|
||||
if (n1.e->getFrom()->pl().getComp() == n2.e->getFrom()->pl().getComp())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
HopBand Router::getHopBand(const EdgeCandGroup& a, const EdgeCandGroup& b,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
assert(a.size());
|
||||
assert(b.size());
|
||||
|
||||
double pend = 0;
|
||||
for (size_t i = 0; i < a.size(); i++) {
|
||||
for (size_t j = 0; j < b.size(); j++) {
|
||||
double d = webMercMeterDist(*a[i].e->getFrom()->pl().getGeom(),
|
||||
*b[j].e->getFrom()->pl().getGeom());
|
||||
if (d > pend) pend = d;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(VDEBUG) << "Pending max hop distance is " << pend << " meters";
|
||||
|
||||
const trgraph::StatGroup* tgGrpTo = 0;
|
||||
|
||||
if (b.begin()->e->getFrom()->pl().getSI())
|
||||
tgGrpTo = b.begin()->e->getFrom()->pl().getSI()->getGroup();
|
||||
|
||||
CostFunc costF(rAttrs, rOpts, rest, tgGrpTo, pend * 50);
|
||||
|
||||
std::set<trgraph::Edge *> from, to;
|
||||
|
||||
for (auto e : a) from.insert(e.e);
|
||||
for (auto e : b) to.insert(e.e);
|
||||
|
||||
LOG(VDEBUG) << "Doing pilot run between " << from.size() << "->" << to.size()
|
||||
<< " edge candidates";
|
||||
|
||||
EdgeList el;
|
||||
EdgeCost ret = costF.inf();
|
||||
DistHeur distH(0, rOpts, to);
|
||||
|
||||
if (compConned(a, b))
|
||||
ret = EDijkstra::shortestPath(from, to, costF, distH, &el);
|
||||
|
||||
if (el.size() < 2 && costF.inf() <= ret) {
|
||||
LOG(VDEBUG) << "Pilot run: no connection between candidate groups,"
|
||||
<< " setting max distance to 1";
|
||||
return HopBand{0, 1, 0, 0};
|
||||
}
|
||||
|
||||
// cache the found path, will save a few dijkstra iterations
|
||||
nestedCache(&el, from, costF, rAttrs);
|
||||
|
||||
auto na = el.back()->getFrom();
|
||||
auto nb = el.front()->getFrom();
|
||||
|
||||
double maxStrD = 0;
|
||||
|
||||
for (auto e : to) {
|
||||
double d = webMercMeterDist(*el.front()->getFrom()->pl().getGeom(),
|
||||
*e->getTo()->pl().getGeom());
|
||||
if (d > maxStrD) maxStrD = d;
|
||||
}
|
||||
|
||||
// TODO(patrick): derive the punish level here automatically
|
||||
double maxD = std::max(ret.getValue(), pend * rOpts.levelPunish[2]) * 3 +
|
||||
rOpts.fullTurnPunishFac + rOpts.platformUnmatchedPen;
|
||||
double minD = ret.getValue();
|
||||
|
||||
LOG(VDEBUG) << "Pilot run: min distance between two groups is "
|
||||
<< ret.getValue() << " (between nodes " << na << " and " << nb
|
||||
<< "), using a max routing distance of " << maxD << ". The max"
|
||||
<< " straight line distance from the pilot target to any other "
|
||||
"target node was"
|
||||
<< " " << maxStrD << ".";
|
||||
|
||||
return HopBand{minD, maxD, el.front(), maxStrD};
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::routeGreedy(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
if (route.size() < 2) return EdgeListHops();
|
||||
EdgeListHops ret(route.size() - 1);
|
||||
|
||||
for (size_t i = 0; i < route.size() - 1; i++) {
|
||||
const trgraph::StatGroup* tgGrp = 0;
|
||||
std::set<trgraph::Node *> from, to;
|
||||
for (auto c : route[i]) from.insert(c.nd);
|
||||
for (auto c : route[i + 1]) to.insert(c.nd);
|
||||
if (route[i + 1].begin()->nd->pl().getSI())
|
||||
tgGrp = route[i + 1].begin()->nd->pl().getSI()->getGroup();
|
||||
|
||||
NCostFunc cost(rAttrs, rOpts, rest, tgGrp);
|
||||
NDistHeur dist(rOpts, to);
|
||||
|
||||
NodeList nodesRet;
|
||||
EdgeListHop hop;
|
||||
Dijkstra::shortestPath(from, to, cost, dist, &hop.edges, &nodesRet);
|
||||
|
||||
if (nodesRet.size() > 1) {
|
||||
// careful: nodesRet is reversed!
|
||||
hop.start = nodesRet.back();
|
||||
hop.end = nodesRet.front();
|
||||
} else {
|
||||
// just take the first candidate if no route could be found
|
||||
hop.start = *from.begin();
|
||||
hop.end = *to.begin();
|
||||
}
|
||||
|
||||
ret[i] = hop;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::routeGreedy2(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
if (route.size() < 2) return EdgeListHops();
|
||||
EdgeListHops ret(route.size() - 1);
|
||||
|
||||
for (size_t i = 0; i < route.size() - 1; i++) {
|
||||
const trgraph::StatGroup* tgGrp = 0;
|
||||
std::set<trgraph::Node *> from, to;
|
||||
|
||||
if (i == 0)
|
||||
for (auto c : route[i]) from.insert(c.nd);
|
||||
else
|
||||
from.insert(const_cast<trgraph::Node*>(ret[i - 1].end));
|
||||
|
||||
for (auto c : route[i + 1]) to.insert(c.nd);
|
||||
|
||||
if (route[i + 1].begin()->nd->pl().getSI())
|
||||
tgGrp = route[i + 1].begin()->nd->pl().getSI()->getGroup();
|
||||
|
||||
NCostFunc cost(rAttrs, rOpts, rest, tgGrp);
|
||||
NDistHeur dist(rOpts, to);
|
||||
|
||||
NodeList nodesRet;
|
||||
EdgeListHop hop;
|
||||
Dijkstra::shortestPath(from, to, cost, dist, &hop.edges, &nodesRet);
|
||||
if (nodesRet.size() > 1) {
|
||||
// careful: nodesRet is reversed!
|
||||
hop.start = nodesRet.back();
|
||||
hop.end = nodesRet.front();
|
||||
} else {
|
||||
// just take the first candidate if no route could be found
|
||||
hop.start = *from.begin();
|
||||
hop.end = *to.begin();
|
||||
}
|
||||
|
||||
ret[i] = hop;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::route(const EdgeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
router::Graph cg;
|
||||
return Router::route(route, rAttrs, rOpts, rest, &cg);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::route(const EdgeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest,
|
||||
router::Graph* cgraph) const {
|
||||
if (route.size() < 2) return EdgeListHops();
|
||||
EdgeListHops ret(route.size() - 1);
|
||||
|
||||
CombCostFunc ccost(rOpts);
|
||||
router::Node* source = cgraph->addNd();
|
||||
router::Node* sink = cgraph->addNd();
|
||||
CombNodeMap nodes;
|
||||
CombNodeMap nextNodes;
|
||||
|
||||
for (size_t i = 0; i < route[0].size(); i++) {
|
||||
auto e = route[0][i].e;
|
||||
// we can be sure that each edge is exactly assigned to only one
|
||||
// node because the transitgraph is directed
|
||||
nodes[e] = cgraph->addNd(route[0][i].e->getFrom());
|
||||
cgraph->addEdg(source, nodes[e])
|
||||
->pl()
|
||||
.setCost(EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
route[0][i].pen, 0));
|
||||
}
|
||||
|
||||
size_t iters = EDijkstra::ITERS;
|
||||
double itPerSecTot = 0;
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < route.size() - 1; i++) {
|
||||
nextNodes.clear();
|
||||
HopBand hopBand = getHopBand(route[i], route[i + 1], rAttrs, rOpts, rest);
|
||||
|
||||
const trgraph::StatGroup* tgGrp = 0;
|
||||
if (route[i + 1].begin()->e->getFrom()->pl().getSI())
|
||||
tgGrp = route[i + 1].begin()->e->getFrom()->pl().getSI()->getGroup();
|
||||
|
||||
std::set<trgraph::Edge*> froms;
|
||||
for (const auto& fr : route[i]) froms.insert(fr.e);
|
||||
|
||||
for (auto eFr : froms) {
|
||||
router::Node* cNodeFr = nodes.find(eFr)->second;
|
||||
|
||||
EdgeSet tos;
|
||||
std::map<trgraph::Edge*, router::Edge*> edges;
|
||||
std::map<trgraph::Edge*, double> pens;
|
||||
std::unordered_map<trgraph::Edge*, EdgeList*> edgeLists;
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost> costs;
|
||||
|
||||
assert(route[i + 1].size());
|
||||
|
||||
for (const auto& to : route[i + 1]) {
|
||||
auto eTo = to.e;
|
||||
tos.insert(eTo);
|
||||
if (!nextNodes.count(eTo))
|
||||
nextNodes[eTo] = cgraph->addNd(to.e->getFrom());
|
||||
if (i == route.size() - 2) cgraph->addEdg(nextNodes[eTo], sink);
|
||||
|
||||
edges[eTo] = cgraph->addEdg(cNodeFr, nextNodes[eTo]);
|
||||
pens[eTo] = to.pen;
|
||||
|
||||
edgeLists[eTo] = edges[eTo]->pl().getEdges();
|
||||
edges[eTo]->pl().setStartNode(eFr->getFrom());
|
||||
// for debugging
|
||||
edges[eTo]->pl().setStartEdge(eFr);
|
||||
edges[eTo]->pl().setEndNode(to.e->getFrom());
|
||||
// for debugging
|
||||
edges[eTo]->pl().setEndEdge(eTo);
|
||||
}
|
||||
|
||||
size_t iters = EDijkstra::ITERS;
|
||||
auto t1 = TIME();
|
||||
|
||||
assert(tos.size());
|
||||
assert(froms.size());
|
||||
|
||||
hops(eFr, froms, tos, tgGrp, edgeLists, &costs, rAttrs, rOpts, rest,
|
||||
hopBand);
|
||||
double itPerSec =
|
||||
(static_cast<double>(EDijkstra::ITERS - iters)) / TOOK(t1, TIME());
|
||||
n++;
|
||||
itPerSecTot += itPerSec;
|
||||
|
||||
LOG(VDEBUG) << "from " << eFr << ": 1-" << tos.size() << " ("
|
||||
<< route[i + 1].size() << " nodes) hop took "
|
||||
<< EDijkstra::ITERS - iters << " iterations, "
|
||||
<< TOOK(t1, TIME()) << "ms (tput: " << itPerSec << " its/ms)";
|
||||
for (auto& kv : edges) {
|
||||
kv.second->pl().setCost(
|
||||
EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pens[kv.first], 0) +
|
||||
costs[kv.first]);
|
||||
|
||||
if (rOpts.popReachEdge && kv.second->pl().getEdges()->size()) {
|
||||
if (kv.second->pl().getEdges() &&
|
||||
kv.second->pl().getEdges()->size()) {
|
||||
// the reach edge is included, but we dont want it in the geometry
|
||||
kv.second->pl().getEdges()->erase(
|
||||
kv.second->pl().getEdges()->begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(nodes, nextNodes);
|
||||
}
|
||||
|
||||
LOG(VDEBUG) << "Hops took " << EDijkstra::ITERS - iters << " iterations,"
|
||||
<< " average tput was " << (itPerSecTot / n) << " its/ms";
|
||||
|
||||
iters = EDijkstra::ITERS;
|
||||
std::vector<router::Edge*> res;
|
||||
EDijkstra::shortestPath(source, sink, ccost, &res);
|
||||
size_t j = 0;
|
||||
|
||||
LOG(VDEBUG) << "Optim graph solve took " << EDijkstra::ITERS - iters
|
||||
<< " iterations.";
|
||||
|
||||
for (auto i = res.rbegin(); i != res.rend(); i++) {
|
||||
const auto e = *i;
|
||||
if (e->getFrom() != source && e->getTo() != sink) {
|
||||
assert(e->pl().frontNode());
|
||||
assert(e->pl().backNode());
|
||||
|
||||
ret[j] = EdgeListHop{std::move(*e->pl().getEdges()), e->pl().frontNode(),
|
||||
e->pl().backNode()};
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ret.size() == j);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::route(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
router::Graph cg;
|
||||
return Router::route(route, rAttrs, rOpts, rest, &cg);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::route(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest,
|
||||
router::Graph* cgraph) const {
|
||||
EdgeCandRoute r;
|
||||
for (auto& nCands : route) {
|
||||
r.emplace_back();
|
||||
for (auto n : nCands)
|
||||
for (auto* e : n.nd->getAdjListOut())
|
||||
r.back().push_back(EdgeCand{e, n.pen});
|
||||
}
|
||||
|
||||
return Router::route(r, rAttrs, rOpts, rest, cgraph);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Router::hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms,
|
||||
const std::set<trgraph::Edge*> tos,
|
||||
const trgraph::StatGroup* tgGrp,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopBand hopB) const {
|
||||
std::set<trgraph::Edge*> rem;
|
||||
|
||||
CostFunc cost(rAttrs, rOpts, rest, tgGrp, hopB.maxD);
|
||||
|
||||
const auto& cached = getCachedHops(from, tos, edgesRet, rCosts, rAttrs);
|
||||
|
||||
for (auto e : cached) {
|
||||
// shortcut: if the nodes lie in two different connected components,
|
||||
// the distance between them is trivially infinite
|
||||
if ((rOpts.noSelfHops && (e == from || e->getFrom() == from->getFrom())) ||
|
||||
from->getFrom()->pl().getComp() != e->getTo()->pl().getComp() ||
|
||||
e->pl().oneWay() == 2 || from->pl().oneWay() == 2) {
|
||||
(*rCosts)[e] = cost.inf();
|
||||
} else {
|
||||
rem.insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(VDEBUG) << "From cache: " << tos.size() - rem.size()
|
||||
<< ", have to cal: " << rem.size();
|
||||
|
||||
if (rem.size()) {
|
||||
DistHeur dist(from->getFrom()->pl().getComp()->minEdgeLvl, rOpts, rem);
|
||||
const auto& ret = EDijkstra::shortestPath(from, rem, cost, dist, edgesRet);
|
||||
for (const auto& kv : ret) {
|
||||
nestedCache(edgesRet.at(kv.first), froms, cost, rAttrs);
|
||||
|
||||
(*rCosts)[kv.first] = kv.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Router::nestedCache(const EdgeList* el,
|
||||
const std::set<trgraph::Edge*>& froms,
|
||||
const CostFunc& cost,
|
||||
const RoutingAttrs& rAttrs) const {
|
||||
if (!_caching) return;
|
||||
if (el->size() == 0) return;
|
||||
// iterate over result edges backwards
|
||||
EdgeList curEdges;
|
||||
EdgeCost curCost;
|
||||
|
||||
size_t j = 0;
|
||||
|
||||
for (auto i = el->begin(); i < el->end(); i++) {
|
||||
if (curEdges.size()) {
|
||||
curCost = curCost + cost(*i, (*i)->getTo(), curEdges.back());
|
||||
}
|
||||
|
||||
curEdges.push_back(*i);
|
||||
|
||||
if (froms.count(*i)) {
|
||||
EdgeCost startC = cost(0, 0, *i) + curCost;
|
||||
cache(*i, el->front(), startC, &curEdges, rAttrs);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::set<pfaedle::trgraph::Edge*> Router::getCachedHops(
|
||||
trgraph::Edge* from, const std::set<trgraph::Edge*>& tos,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs) const {
|
||||
std::set<trgraph::Edge*> ret;
|
||||
for (auto to : tos) {
|
||||
if (_caching && (*_cache[omp_get_thread_num()])[rAttrs][from].count(to)) {
|
||||
const auto& cv = (*_cache[omp_get_thread_num()])[rAttrs][from][to];
|
||||
(*rCosts)[to] = cv.first;
|
||||
*edgesRet.at(to) = cv.second;
|
||||
} else {
|
||||
ret.insert(to);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Router::cache(trgraph::Edge* from, trgraph::Edge* to, const EdgeCost& c,
|
||||
EdgeList* edges, const RoutingAttrs& rAttrs) const {
|
||||
if (!_caching) return;
|
||||
if (from == to) return;
|
||||
(*_cache[omp_get_thread_num()])[rAttrs][from][to] =
|
||||
std::pair<EdgeCost, EdgeList>(c, *edges);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t Router::getCacheNumber() const { return _cache.size(); }
|
||||
|
|
@ -6,198 +6,97 @@
|
|||
#define PFAEDLE_ROUTER_ROUTER_H_
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "pfaedle/Def.h"
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Graph.h"
|
||||
#include "pfaedle/router/HopCache.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "pfaedle/router/RoutingAttrs.h"
|
||||
#include "pfaedle/router/TripTrie.h"
|
||||
#include "pfaedle/router/Weights.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/Misc.h"
|
||||
#include "util/geo/Geo.h"
|
||||
#include "util/graph/Dijkstra.h"
|
||||
#include "util/graph/EDijkstra.h"
|
||||
|
||||
using util::graph::EDijkstra;
|
||||
using util::graph::Dijkstra;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
typedef std::unordered_map<const trgraph::Edge*, router::Node*> CombNodeMap;
|
||||
constexpr static uint32_t ROUTE_INF = std::numeric_limits<uint32_t>::max();
|
||||
constexpr static double DBL_INF = std::numeric_limits<double>::infinity();
|
||||
constexpr static size_t NO_PREDE = std::numeric_limits<size_t>::max();
|
||||
|
||||
constexpr static int MAX_ROUTE_COST_DOUBLING_STEPS = 3;
|
||||
|
||||
typedef std::pair<size_t, size_t> HId;
|
||||
typedef std::map<
|
||||
RoutingAttrs,
|
||||
std::unordered_map<const trgraph::Edge*,
|
||||
std::unordered_map<const trgraph::Edge*,
|
||||
std::pair<EdgeCost, EdgeList> > > >
|
||||
Cache;
|
||||
typedef std::vector<double> LayerCostsDAG;
|
||||
typedef std::vector<LayerCostsDAG> CostsDAG;
|
||||
typedef std::vector<std::vector<size_t>> PredeDAG;
|
||||
|
||||
struct HopBand {
|
||||
double minD;
|
||||
double maxD;
|
||||
const trgraph::Edge* nearest;
|
||||
double maxInGrpDist;
|
||||
};
|
||||
typedef std::unordered_map<const trgraph::Edge*,
|
||||
std::unordered_map<const trgraph::Edge*, uint32_t>>
|
||||
EdgeCostMatrix;
|
||||
typedef std::unordered_map<const trgraph::Edge*,
|
||||
std::unordered_map<const trgraph::Edge*, double>>
|
||||
EdgeDistMatrix;
|
||||
typedef util::graph::EDijkstra::EList<trgraph::NodePL, trgraph::EdgePL> TrEList;
|
||||
|
||||
struct CostFunc
|
||||
: public EDijkstra::CostFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
CostFunc(const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& res, const trgraph::StatGroup* tgGrp,
|
||||
double max)
|
||||
: _rAttrs(rAttrs),
|
||||
_rOpts(rOpts),
|
||||
_res(res),
|
||||
_tgGrp(tgGrp),
|
||||
_inf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, max, 0) {}
|
||||
typedef std::vector<std::pair<std::pair<size_t, size_t>, uint32_t>> CostMatrix;
|
||||
|
||||
const RoutingAttrs& _rAttrs;
|
||||
const RoutingOpts& _rOpts;
|
||||
const osm::Restrictor& _res;
|
||||
const trgraph::StatGroup* _tgGrp;
|
||||
EdgeCost _inf;
|
||||
|
||||
EdgeCost operator()(const trgraph::Edge* from, const trgraph::Node* n,
|
||||
const trgraph::Edge* to) const;
|
||||
EdgeCost inf() const { return _inf; }
|
||||
|
||||
double transitLineCmp(const trgraph::EdgePL& e) const;
|
||||
};
|
||||
|
||||
struct NCostFunc
|
||||
: public Dijkstra::CostFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
NCostFunc(const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& res, const trgraph::StatGroup* tgGrp)
|
||||
: _rAttrs(rAttrs),
|
||||
_rOpts(rOpts),
|
||||
_res(res),
|
||||
_tgGrp(tgGrp),
|
||||
_inf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
std::numeric_limits<double>::infinity(), 0) {}
|
||||
|
||||
const RoutingAttrs& _rAttrs;
|
||||
const RoutingOpts& _rOpts;
|
||||
const osm::Restrictor& _res;
|
||||
const trgraph::StatGroup* _tgGrp;
|
||||
EdgeCost _inf;
|
||||
|
||||
EdgeCost operator()(const trgraph::Node* from, const trgraph::Edge* e,
|
||||
const trgraph::Node* to) const;
|
||||
EdgeCost inf() const { return _inf; }
|
||||
|
||||
double transitLineCmp(const trgraph::EdgePL& e) const;
|
||||
};
|
||||
|
||||
struct DistHeur
|
||||
: public EDijkstra::HeurFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
DistHeur(uint8_t minLvl, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos);
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
uint8_t _lvl;
|
||||
POINT _center;
|
||||
double _maxCentD;
|
||||
EdgeCost operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const;
|
||||
};
|
||||
|
||||
struct NDistHeur
|
||||
: public Dijkstra::HeurFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
NDistHeur(const RoutingOpts& rOpts, const std::set<trgraph::Node*>& tos);
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
POINT _center;
|
||||
double _maxCentD;
|
||||
EdgeCost operator()(const trgraph::Node* a,
|
||||
const std::set<trgraph::Node*>& b) const;
|
||||
};
|
||||
|
||||
struct CombCostFunc
|
||||
: public EDijkstra::CostFunc<router::NodePL, router::EdgePL, double> {
|
||||
explicit CombCostFunc(const RoutingOpts& rOpts) : _rOpts(rOpts) {}
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
|
||||
double operator()(const router::Edge* from, const router::Node* n,
|
||||
const router::Edge* to) const;
|
||||
double inf() const { return std::numeric_limits<double>::infinity(); }
|
||||
class Router {
|
||||
public:
|
||||
virtual ~Router() = default;
|
||||
virtual std::map<size_t, EdgeListHops> route(const TripTrie* trie,
|
||||
const EdgeCandMap& ecm,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest,
|
||||
HopCache* hopCache,
|
||||
bool noFastHops) const = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Finds the most likely route of schedule-based vehicle between stops in a
|
||||
* physical transportation network
|
||||
*/
|
||||
class Router {
|
||||
template <typename TW>
|
||||
class RouterImpl : public Router {
|
||||
public:
|
||||
// Init this router with caches for numThreads threads
|
||||
explicit Router(size_t numThreads, bool caching);
|
||||
~Router();
|
||||
|
||||
// Find the most likely path through the graph for a node candidate route.
|
||||
EdgeListHops route(const NodeCandRoute& route, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
EdgeListHops route(const NodeCandRoute& route, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts, const osm::Restrictor& rest,
|
||||
router::Graph* cgraph) const;
|
||||
|
||||
// Find the most likely path through the graph for an edge candidate route.
|
||||
EdgeListHops route(const EdgeCandRoute& route, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
EdgeListHops route(const EdgeCandRoute& route, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts, const osm::Restrictor& rest,
|
||||
router::Graph* cgraph) const;
|
||||
|
||||
// Find the most likely path through cgraph for a node candidate route, but
|
||||
// based on a greedy node to node approach
|
||||
EdgeListHops routeGreedy(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
|
||||
// Find the most likely path through cgraph for a node candidate route, but
|
||||
// based on a greedy node to node set approach
|
||||
EdgeListHops routeGreedy2(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
|
||||
// Return the number of thread caches this router was initialized with
|
||||
size_t getCacheNumber() const;
|
||||
// Find the most likely path through the graph for a trip trie.
|
||||
virtual std::map<size_t, EdgeListHops> route(
|
||||
const TripTrie* trie, const EdgeCandMap& ecm, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopCache* hopCache, bool noFastHops) const;
|
||||
|
||||
private:
|
||||
mutable std::vector<Cache*> _cache;
|
||||
bool _caching;
|
||||
HopBand getHopBand(const EdgeCandGroup& a, const EdgeCandGroup& b,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
void hops(const EdgeCandGroup& from, const EdgeCandGroup& to,
|
||||
CostMatrix* rCosts, CostMatrix* dists, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts, const osm::Restrictor& rest,
|
||||
HopCache* hopCache, uint32_t maxCost) const;
|
||||
|
||||
void hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms,
|
||||
const std::set<trgraph::Edge*> to, const trgraph::StatGroup* tgGrp,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopBand hopB) const;
|
||||
void hopsFast(const EdgeCandGroup& from, const EdgeCandGroup& to,
|
||||
const LayerCostsDAG& initCosts, CostMatrix* rCosts,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest,
|
||||
|
||||
std::set<trgraph::Edge*> getCachedHops(
|
||||
trgraph::Edge* from, const std::set<trgraph::Edge*>& to,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs) const;
|
||||
HopCache* hopCache, uint32_t maxCost) const;
|
||||
|
||||
void cache(trgraph::Edge* from, trgraph::Edge* to, const EdgeCost& c,
|
||||
EdgeList* edges, const RoutingAttrs& rAttrs) const;
|
||||
bool connected(const EdgeCand& from, const EdgeCandGroup& tos) const;
|
||||
bool connected(const EdgeCandGroup& froms, const EdgeCand& to) const;
|
||||
|
||||
void nestedCache(const EdgeList* el, const std::set<trgraph::Edge*>& froms,
|
||||
const CostFunc& cost, const RoutingAttrs& rAttrs) const;
|
||||
bool cacheDrop(
|
||||
|
||||
bool compConned(const EdgeCandGroup& a, const EdgeCandGroup& b) const;
|
||||
HopCache* hopCache, const std::set<trgraph::Edge*>& froms,
|
||||
const trgraph::Edge* to, uint32_t maxCost) const;
|
||||
|
||||
uint32_t addNonOverflow(uint32_t a, uint32_t b) const;
|
||||
};
|
||||
|
||||
#include "pfaedle/router/Router.tpp"
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
|
|
|
|||
614
src/pfaedle/router/Router.tpp
Normal file
614
src/pfaedle/router/Router.tpp
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#else
|
||||
#define omp_get_thread_num() 0
|
||||
#define omp_get_num_procs() 1
|
||||
#endif
|
||||
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <set>
|
||||
#include <limits>
|
||||
#include <stack>
|
||||
|
||||
using util::graph::EDijkstra;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
std::map<size_t, EdgeListHops> RouterImpl<TW>::route(
|
||||
const TripTrie* trie, const EdgeCandMap& ecm, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopCache* hopCache, bool noFastHops) const {
|
||||
std::map<size_t, EdgeListHops> ret;
|
||||
|
||||
// the current node costs in our DAG
|
||||
CostsDAG costsDAG(trie->getNds().size());
|
||||
PredeDAG predeDAG(trie->getNds().size());
|
||||
std::vector<double> maxCosts(trie->getNds().size());
|
||||
|
||||
// skip the root node, init all to inf
|
||||
for (size_t nid = 1; nid < trie->getNds().size(); nid++) {
|
||||
costsDAG[nid].resize(ecm.at(nid).size(), DBL_INF);
|
||||
predeDAG[nid].resize(ecm.at(nid).size(), NO_PREDE);
|
||||
maxCosts.resize(ecm.at(nid).size(), 0);
|
||||
}
|
||||
|
||||
std::stack<size_t> st;
|
||||
|
||||
// init cost of all first childs
|
||||
for (size_t cnid : trie->getNd(0).childs) {
|
||||
st.push(cnid);
|
||||
for (size_t frId = 0; frId < ecm.at(cnid).size(); frId++) {
|
||||
costsDAG[cnid][frId] = ecm.at(cnid)[frId].pen;
|
||||
}
|
||||
}
|
||||
|
||||
while (!st.empty()) {
|
||||
size_t frTrNid = st.top();
|
||||
st.pop();
|
||||
const auto& frTrNd = trie->getNd(frTrNid);
|
||||
for (size_t toTrNid : trie->getNd(frTrNid).childs) {
|
||||
CostMatrix costM, dists;
|
||||
const auto& toTrNd = trie->getNd(toTrNid);
|
||||
|
||||
if (frTrNd.arr && !toTrNd.arr) {
|
||||
for (size_t toId = 0; toId < costsDAG[toTrNid].size(); toId++) {
|
||||
auto toCand = ecm.at(toTrNid)[toId];
|
||||
for (size_t frId : toCand.depPrede) {
|
||||
double newC = costsDAG[frTrNid][frId] + ecm.at(toTrNid)[toId].pen;
|
||||
if (newC < costsDAG[toTrNid][toId]) {
|
||||
costsDAG[toTrNid][toId] = newC;
|
||||
predeDAG[toTrNid][toId] = frId;
|
||||
}
|
||||
}
|
||||
}
|
||||
st.push(toTrNid);
|
||||
continue;
|
||||
}
|
||||
|
||||
const double avgDepT = frTrNd.accTime / frTrNd.trips;
|
||||
const double avgArrT = toTrNd.accTime / toTrNd.trips;
|
||||
|
||||
double hopDist = 0;
|
||||
|
||||
if (TW::NEED_DIST)
|
||||
hopDist = util::geo::haversine(frTrNd.lat, frTrNd.lng, toTrNd.lat,
|
||||
toTrNd.lng);
|
||||
|
||||
uint32_t newMaxCost = TW::maxCost(avgArrT - avgDepT, rOpts);
|
||||
uint32_t maxCost = newMaxCost;
|
||||
|
||||
bool found = false;
|
||||
int step = 0;
|
||||
|
||||
while (!found && step <= MAX_ROUTE_COST_DOUBLING_STEPS) {
|
||||
maxCosts[toTrNid] = newMaxCost;
|
||||
maxCost = newMaxCost;
|
||||
|
||||
// calculate n x n hops between layers
|
||||
if (noFastHops || !TW::ALLOWS_FAST_ROUTE) {
|
||||
hops(ecm.at(frTrNid), ecm.at(toTrNid), &costM, &dists, toTrNd.rAttrs,
|
||||
rOpts, rest, hopCache, maxCost);
|
||||
} else {
|
||||
hopsFast(ecm.at(frTrNid), ecm.at(toTrNid), costsDAG[frTrNid], &costM,
|
||||
toTrNd.rAttrs, rOpts, rest, hopCache, maxCost);
|
||||
}
|
||||
|
||||
for (size_t matrixI = 0; matrixI < costM.size(); matrixI++) {
|
||||
const auto& mVal = costM[matrixI];
|
||||
const size_t frId = mVal.first.first;
|
||||
const size_t toId = mVal.first.second;
|
||||
const uint32_t c = mVal.second;
|
||||
|
||||
double mDist = 0;
|
||||
|
||||
// the dists and the costM matrices have entries at exactly the same
|
||||
// loc
|
||||
if (TW::NEED_DIST) mDist = dists[matrixI].second;
|
||||
|
||||
// calculate the transition weights
|
||||
const double depT = ecm.at(frTrNid)[frId].time;
|
||||
const double arrT = ecm.at(toTrNid)[toId].time;
|
||||
const double w = TW::weight(c, mDist, arrT - depT, hopDist, rOpts);
|
||||
|
||||
// update costs to successors in next layer
|
||||
double newC = costsDAG[frTrNid][frId] + ecm.at(toTrNid)[toId].pen + w;
|
||||
if (newC < costsDAG[toTrNid][toId]) {
|
||||
costsDAG[toTrNid][toId] = newC;
|
||||
predeDAG[toTrNid][toId] = frId;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (newMaxCost <= std::numeric_limits<uint32_t>::max() / 2)
|
||||
newMaxCost *= 2;
|
||||
else
|
||||
newMaxCost = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
if (newMaxCost == maxCost) break;
|
||||
step++;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
// write the cost for the NULL candidates as a fallback
|
||||
for (size_t frNid = 0; frNid < ecm.at(frTrNid).size(); frNid++) {
|
||||
double newC = costsDAG[frTrNid][frNid] + maxCost * 100;
|
||||
// in the time expanded case, there might be multiple null cands
|
||||
size_t nullCId = 0;
|
||||
while (nullCId < ecm.at(toTrNid).size() &&
|
||||
!ecm.at(toTrNid)[nullCId].e) {
|
||||
if (newC < costsDAG[toTrNid][nullCId]) {
|
||||
predeDAG[toTrNid][nullCId] = frNid;
|
||||
costsDAG[toTrNid][nullCId] = newC;
|
||||
}
|
||||
nullCId++;
|
||||
}
|
||||
}
|
||||
|
||||
// for the remaining, write dummy edges
|
||||
for (size_t frNid = 0; frNid < ecm.at(frTrNid).size(); frNid++) {
|
||||
// skip NULL candidates
|
||||
size_t toNid = 1;
|
||||
while (toNid < ecm.at(toTrNid).size() && !ecm.at(toTrNid)[toNid].e)
|
||||
toNid++;
|
||||
for (; toNid < ecm.at(toTrNid).size(); toNid++) {
|
||||
double newC = costsDAG[frTrNid][frNid] + ecm.at(toTrNid)[toNid].pen;
|
||||
if (newC < costsDAG[toTrNid][toNid]) {
|
||||
predeDAG[toTrNid][toNid] = frNid;
|
||||
costsDAG[toTrNid][toNid] = newC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st.push(toTrNid);
|
||||
}
|
||||
}
|
||||
|
||||
// update sink costs
|
||||
std::unordered_map<size_t, double> sinkCosts;
|
||||
std::unordered_map<size_t, size_t> frontIds;
|
||||
for (auto leaf : trie->getNdTrips()) {
|
||||
sinkCosts[leaf.first] = DBL_INF;
|
||||
frontIds[leaf.first] = 0;
|
||||
|
||||
for (size_t lastId = 0; lastId < ecm.at(leaf.first).size(); lastId++) {
|
||||
double nCost = costsDAG[leaf.first][lastId];
|
||||
if (nCost < sinkCosts[leaf.first]) {
|
||||
frontIds[leaf.first] = lastId;
|
||||
sinkCosts[leaf.first] = nCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve edges
|
||||
for (auto leaf : trie->getNdTrips()) {
|
||||
const auto leafNid = leaf.first;
|
||||
auto curTrieNid = leafNid;
|
||||
|
||||
while (predeDAG[curTrieNid][frontIds[leafNid]] != NO_PREDE) {
|
||||
const auto curTrieParNid = trie->getNd(curTrieNid).parent;
|
||||
const auto frId = predeDAG[curTrieNid][frontIds[leafNid]];
|
||||
const auto toId = frontIds[leafNid];
|
||||
|
||||
const auto frTrNd = trie->getNd(curTrieParNid);
|
||||
const auto toTrNd = trie->getNd(curTrieNid);
|
||||
|
||||
// skip in-node hops
|
||||
if (frTrNd.arr && !toTrNd.arr) {
|
||||
frontIds[leafNid] = frId;
|
||||
curTrieNid = curTrieParNid;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<trgraph::Edge*> edgs;
|
||||
|
||||
const auto& fr = ecm.at(curTrieParNid)[frId];
|
||||
const auto& to = ecm.at(curTrieNid)[toId];
|
||||
|
||||
// for subtracting and adding progression costs
|
||||
typename TW::CostFunc costPr(toTrNd.rAttrs, rOpts, rest, ROUTE_INF);
|
||||
|
||||
if (fr.e && to.e) {
|
||||
// account for max progression start offset, do this exactly like
|
||||
// in the hops calculation to ensure that we can find the path again
|
||||
double maxProgrStart = 0;
|
||||
for (const auto& fr : ecm.at(curTrieParNid)) {
|
||||
if (!fr.e) continue;
|
||||
double progrStart = 0;
|
||||
if (fr.progr > 0) progrStart = costPr(fr.e, 0, 0) * fr.progr;
|
||||
if (progrStart > maxProgrStart) maxProgrStart = progrStart;
|
||||
}
|
||||
|
||||
const double maxCostRt = maxCosts[curTrieNid] + maxProgrStart;
|
||||
uint32_t maxCostRtInt = maxCostRt;
|
||||
|
||||
// avoid overflow
|
||||
if (maxCostRt >= std::numeric_limits<uint32_t>::max()) {
|
||||
maxCostRtInt = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
typename TW::CostFunc cost(toTrNd.rAttrs, rOpts, rest, maxCostRtInt);
|
||||
typename TW::DistHeur distH(fr.e->getFrom()->pl().getComp().maxSpeed,
|
||||
rOpts, {to.e});
|
||||
|
||||
const double c =
|
||||
EDijkstra::shortestPath(fr.e, to.e, cost, distH, &edgs);
|
||||
// c += costPr(to.e, 0, 0) * to.progr;
|
||||
|
||||
if (c < maxCostRtInt) {
|
||||
// a path was found, use it
|
||||
ret[leafNid].push_back(
|
||||
{edgs, fr.e, to.e, fr.progr, to.progr, {}, {}});
|
||||
} else {
|
||||
// no path was found, which is marked by an empty edge list
|
||||
ret[leafNid].push_back({{}, fr.e, to.e, fr.progr, to.progr, {}, {}});
|
||||
}
|
||||
} else {
|
||||
// fallback to the position given in candidate
|
||||
if (fr.e) {
|
||||
ret[leafNid].push_back({edgs, fr.e, 0, fr.progr, 0, {}, to.point});
|
||||
} else if (to.e) {
|
||||
ret[leafNid].push_back({edgs, 0, to.e, 0, to.progr, fr.point, {}});
|
||||
} else {
|
||||
ret[leafNid].push_back({edgs, 0, 0, 0, 0, fr.point, to.point});
|
||||
}
|
||||
}
|
||||
frontIds[leafNid] = frId;
|
||||
curTrieNid = curTrieParNid;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
void RouterImpl<TW>::hops(const EdgeCandGroup& froms, const EdgeCandGroup& tos,
|
||||
CostMatrix* rCosts, CostMatrix* dists,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopCache* hopCache,
|
||||
uint32_t maxCost) const {
|
||||
// standard 1 -> n approach
|
||||
std::set<trgraph::Edge*> eFrs;
|
||||
for (const auto& from : froms) {
|
||||
if (!from.e) continue;
|
||||
eFrs.insert(from.e);
|
||||
}
|
||||
|
||||
std::set<trgraph::Edge*> eTos;
|
||||
for (const auto& to : tos) {
|
||||
if (!to.e) continue;
|
||||
eTos.insert(to.e);
|
||||
}
|
||||
|
||||
EdgeCostMatrix ecm;
|
||||
EdgeDistMatrix ecmDist;
|
||||
|
||||
// account for max progression start offset
|
||||
double maxProgrStart = 0;
|
||||
typename TW::CostFunc cost(rAttrs, rOpts, rest, ROUTE_INF);
|
||||
for (const auto& fr : froms) {
|
||||
if (!fr.e) continue;
|
||||
double progrStart = 0;
|
||||
if (fr.progr > 0) progrStart = cost(fr.e, 0, 0) * fr.progr;
|
||||
if (progrStart > maxProgrStart) maxProgrStart = progrStart;
|
||||
}
|
||||
|
||||
maxCost = addNonOverflow(maxCost, maxProgrStart);
|
||||
typename TW::CostFunc costF(rAttrs, rOpts, rest, maxCost);
|
||||
|
||||
for (trgraph::Edge* eFrom : eFrs) {
|
||||
std::set<trgraph::Edge*> remTos;
|
||||
for (trgraph::Edge* eTo : eTos) {
|
||||
// init ecmDist
|
||||
ecmDist[eFrom][eTo] = ROUTE_INF;
|
||||
|
||||
std::pair<uint32_t, bool> cached = {0, 0};
|
||||
if (hopCache) cached = hopCache->get(eFrom, eTo);
|
||||
|
||||
// shortcut: if the nodes lie in two different connected components,
|
||||
// the distance between them is trivially infinite
|
||||
if (eFrom->getFrom()->pl().getCompId() !=
|
||||
eTo->getTo()->pl().getCompId()) {
|
||||
ecm[eFrom][eTo] = costF.inf();
|
||||
} else if (cached.second >= costF.inf()) {
|
||||
ecm[eFrom][eTo] = costF.inf();
|
||||
} else if (!TW::NEED_DIST && cached.second) {
|
||||
ecm[eFrom][eTo] = cached.first;
|
||||
} else {
|
||||
remTos.insert(eTo);
|
||||
}
|
||||
}
|
||||
|
||||
if (remTos.size()) {
|
||||
typename TW::DistHeur distH(eFrom->getFrom()->pl().getComp().maxSpeed,
|
||||
rOpts, remTos);
|
||||
|
||||
std::unordered_map<trgraph::Edge*, TrEList> paths;
|
||||
std::unordered_map<trgraph::Edge*, TrEList*> pathPtrs;
|
||||
for (auto to : tos) pathPtrs[to.e] = &paths[to.e];
|
||||
|
||||
const auto& costs =
|
||||
EDijkstra::shortestPath(eFrom, remTos, costF, distH, pathPtrs);
|
||||
|
||||
for (const auto& c : costs) {
|
||||
ecm[eFrom][c.first] = c.second;
|
||||
|
||||
if (paths[c.first].size() == 0) {
|
||||
if (hopCache) hopCache->setMin(eFrom, c.first, maxCost);
|
||||
continue; // no path found
|
||||
}
|
||||
|
||||
if (hopCache) hopCache->setEx(eFrom, c.first, c.second);
|
||||
}
|
||||
|
||||
if (TW::NEED_DIST) {
|
||||
for (const auto& c : costs) {
|
||||
if (!paths[c.first].size()) continue;
|
||||
double d = 0;
|
||||
// don't count last edge
|
||||
for (size_t i = paths[c.first].size() - 1; i > 0; i--) {
|
||||
d += paths[c.first][i]->pl().getLength();
|
||||
}
|
||||
ecmDist[eFrom][c.first] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build return costs
|
||||
for (size_t frId = 0; frId < froms.size(); frId++) {
|
||||
auto fr = froms[frId];
|
||||
if (!fr.e) continue;
|
||||
auto costFr = costF(fr.e, 0, 0);
|
||||
for (size_t toId = 0; toId < tos.size(); toId++) {
|
||||
auto to = tos[toId];
|
||||
if (!to.e) continue;
|
||||
auto costTo = costF(to.e, 0, 0);
|
||||
|
||||
uint32_t c = ecm[fr.e][to.e];
|
||||
|
||||
if (c >= maxCost) continue;
|
||||
|
||||
double dist = 0;
|
||||
if (TW::NEED_DIST) dist = ecmDist[fr.e][to.e];
|
||||
|
||||
if (fr.e == to.e) {
|
||||
if (fr.progr <= to.progr) {
|
||||
const uint32_t progrCFr = costFr * fr.progr;
|
||||
const uint32_t progrCTo = costTo * to.progr;
|
||||
|
||||
// calculate this in one step to avoid uint32_t underflow below
|
||||
c += progrCTo - progrCFr;
|
||||
} else {
|
||||
// trivial case we can ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
// subtract progression cost on first edge
|
||||
if (fr.progr > 0) {
|
||||
const uint32_t progrCFr = costFr * fr.progr;
|
||||
c -= progrCFr;
|
||||
if (TW::NEED_DIST) dist -= fr.e->pl().getLength() * fr.progr;
|
||||
}
|
||||
|
||||
// add progression cost on last edge
|
||||
if (to.progr > 0) {
|
||||
const uint32_t progrCTo = costTo * to.progr;
|
||||
c += progrCTo;
|
||||
if (TW::NEED_DIST) dist += to.e->pl().getLength() * to.progr;
|
||||
}
|
||||
}
|
||||
|
||||
if (c < maxCost) {
|
||||
rCosts->push_back({{frId, toId}, c});
|
||||
if (TW::NEED_DIST) dists->push_back({{frId, toId}, dist});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
void RouterImpl<TW>::hopsFast(const EdgeCandGroup& froms,
|
||||
const EdgeCandGroup& tos,
|
||||
const LayerCostsDAG& rawInitCosts,
|
||||
CostMatrix* rCosts, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& restr, HopCache* hopCache,
|
||||
uint32_t maxCost) const {
|
||||
std::unordered_map<trgraph::Edge*, uint32_t> initCosts;
|
||||
|
||||
std::set<trgraph::Edge*> eFrs, eTos;
|
||||
std::map<trgraph::Edge*, std::vector<size_t>> eFrCands, eToCands;
|
||||
double maxSpeed = 0;
|
||||
for (size_t frId = 0; frId < froms.size(); frId++) {
|
||||
if (rawInitCosts[frId] >= DBL_INF || !connected(froms[frId], tos)) continue;
|
||||
|
||||
eFrs.insert(froms[frId].e);
|
||||
eFrCands[froms[frId].e].push_back(frId);
|
||||
|
||||
if (froms[frId].e->getFrom()->pl().getComp().maxSpeed > maxSpeed)
|
||||
maxSpeed = froms[frId].e->getFrom()->pl().getComp().maxSpeed;
|
||||
}
|
||||
|
||||
for (size_t toId = 0; toId < tos.size(); toId++) {
|
||||
if (!connected(froms, tos[toId]))
|
||||
continue; // skip nodes not conn'ed to any <fr>
|
||||
|
||||
if (hopCache && cacheDrop(hopCache, eFrs, tos[toId].e, maxCost))
|
||||
continue; // skip nodes we have already encountered at higher cost
|
||||
|
||||
eTos.insert(tos[toId].e);
|
||||
eToCands[tos[toId].e].push_back(toId);
|
||||
}
|
||||
|
||||
if (eFrs.size() == 0 || eTos.size() == 0) return;
|
||||
|
||||
// account for max progression start offset
|
||||
double maxProgrStart = 0;
|
||||
typename TW::CostFunc progrCostF(rAttrs, rOpts, restr, ROUTE_INF);
|
||||
for (const auto& fr : froms) {
|
||||
if (!fr.e) continue;
|
||||
double progrStart = 0;
|
||||
if (fr.progr > 0) progrStart = progrCostF(fr.e, 0, 0) * fr.progr;
|
||||
if (progrStart > maxProgrStart) maxProgrStart = progrStart;
|
||||
}
|
||||
|
||||
// initialize init doubles
|
||||
LayerCostsDAG prepInitCosts(froms.size());
|
||||
for (size_t frId = 0; frId < froms.size(); frId++) {
|
||||
if (!froms[frId].e || rawInitCosts[frId] >= DBL_INF) continue;
|
||||
const auto& fr = froms[frId];
|
||||
// offset by progr start
|
||||
double progrStart = progrCostF(fr.e, 0, 0) * fr.progr;
|
||||
prepInitCosts[frId] =
|
||||
TW::invWeight(rawInitCosts[frId], rOpts) + maxProgrStart - progrStart;
|
||||
}
|
||||
|
||||
// all init costs are inf
|
||||
for (const auto& fr : froms) initCosts[fr.e] = ROUTE_INF;
|
||||
|
||||
// now chose the best offset cost
|
||||
for (size_t frId = 0; frId < froms.size(); frId++) {
|
||||
if (!froms[frId].e || rawInitCosts[frId] >= DBL_INF) continue;
|
||||
const auto& fr = froms[frId];
|
||||
if (prepInitCosts[frId] < initCosts[fr.e])
|
||||
initCosts[fr.e] = prepInitCosts[frId];
|
||||
}
|
||||
|
||||
// get max init costs
|
||||
uint32_t maxInit = 0;
|
||||
uint32_t minInit = ROUTE_INF;
|
||||
for (const auto& c : initCosts) {
|
||||
if (!eFrs.count(c.first)) continue;
|
||||
if (c.second != ROUTE_INF && c.second > maxInit) maxInit = c.second;
|
||||
if (c.second < minInit) minInit = c.second;
|
||||
}
|
||||
|
||||
for (auto& c : initCosts) c.second = c.second - minInit;
|
||||
|
||||
// account for start offsets
|
||||
maxCost = addNonOverflow(maxCost, maxProgrStart);
|
||||
|
||||
typename TW::CostFunc costF(rAttrs, rOpts, restr,
|
||||
maxCost + (maxInit - minInit));
|
||||
|
||||
std::unordered_map<trgraph::Edge*, TrEList> paths;
|
||||
std::unordered_map<trgraph::Edge*, TrEList*> pathPtrs;
|
||||
for (const auto& to : tos) pathPtrs[to.e] = &paths[to.e];
|
||||
|
||||
typename TW::DistHeur distH(maxSpeed, rOpts, eTos);
|
||||
|
||||
const auto& costs =
|
||||
EDijkstra::shortestPath(eFrs, eTos, initCosts, maxCost, costF, distH);
|
||||
|
||||
for (const auto& c : costs) {
|
||||
auto toEdg = c.first;
|
||||
if (c.second.second >= costF.inf()) {
|
||||
if (hopCache) hopCache->setMin(eFrs, toEdg, maxCost);
|
||||
continue; // no path found
|
||||
}
|
||||
auto fromEdg = c.second.first;
|
||||
uint32_t cost = c.second.second - initCosts[fromEdg];
|
||||
|
||||
if (cost >= maxCost) continue;
|
||||
|
||||
for (size_t frId : eFrCands.find(fromEdg)->second) {
|
||||
const auto& fr = froms[frId];
|
||||
auto costFr = costF(fr.e, 0, 0);
|
||||
|
||||
for (size_t toId : eToCands.find(toEdg)->second) {
|
||||
const auto& to = tos[toId];
|
||||
uint32_t wrCost = cost;
|
||||
|
||||
if (fr.e == to.e) {
|
||||
if (fr.progr <= to.progr) {
|
||||
const auto costTo = costF(to.e, 0, 0);
|
||||
const uint32_t progrCFr = costFr * fr.progr;
|
||||
const uint32_t progrCTo = costTo * to.progr;
|
||||
|
||||
// calculate this in one step to avoid uint32_t underflow below
|
||||
wrCost += progrCTo - progrCFr;
|
||||
} else {
|
||||
// trivial case we can ignore
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// subtract progression cost on first edge
|
||||
if (fr.progr > 0) {
|
||||
const uint32_t progrCFr = costFr * fr.progr;
|
||||
wrCost -= progrCFr;
|
||||
}
|
||||
|
||||
// add progression cost on last edge
|
||||
if (to.progr > 0) {
|
||||
const auto costTo = costF(to.e, 0, 0);
|
||||
const uint32_t progrCTo = costTo * to.progr;
|
||||
wrCost += progrCTo;
|
||||
}
|
||||
}
|
||||
|
||||
if (wrCost >= maxCost - maxProgrStart) continue;
|
||||
|
||||
rCosts->push_back({{frId, toId}, wrCost});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
bool RouterImpl<TW>::connected(const EdgeCand& fr,
|
||||
const EdgeCandGroup& tos) const {
|
||||
if (!fr.e) return false;
|
||||
for (const auto& to : tos) {
|
||||
if (!to.e) continue;
|
||||
if (fr.e->getFrom()->pl().getCompId() == to.e->getFrom()->pl().getCompId())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
bool RouterImpl<TW>::connected(const EdgeCandGroup& froms,
|
||||
const EdgeCand& to) const {
|
||||
if (!to.e) return false;
|
||||
for (const auto& fr : froms) {
|
||||
if (!fr.e) continue;
|
||||
if (fr.e->getFrom()->pl().getCompId() == to.e->getFrom()->pl().getCompId())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
bool RouterImpl<TW>::cacheDrop(HopCache* hopCache,
|
||||
const std::set<trgraph::Edge*>& froms,
|
||||
const trgraph::Edge* to,
|
||||
uint32_t maxCost) const {
|
||||
for (auto fr : froms)
|
||||
if (hopCache->get(fr, to).first <= maxCost) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
template <typename TW>
|
||||
uint32_t RouterImpl<TW>::addNonOverflow(uint32_t a, uint32_t b) const {
|
||||
if (a == std::numeric_limits<uint32_t>::max() ||
|
||||
b == std::numeric_limits<uint32_t>::max())
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
uint32_t res = a + b;
|
||||
if (res >= a && res >= b) return res;
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
|
@ -5,8 +5,10 @@
|
|||
#ifndef PFAEDLE_ROUTER_ROUTINGATTRS_H_
|
||||
#define PFAEDLE_ROUTER_ROUTINGATTRS_H_
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "pfaedle/statsimi-classifier/StatsimiClassifier.h"
|
||||
#include "pfaedle/trgraph/EdgePL.h"
|
||||
|
||||
using pfaedle::trgraph::TransitEdgeLine;
|
||||
|
|
@ -14,40 +16,74 @@ using pfaedle::trgraph::TransitEdgeLine;
|
|||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
struct LineSimilarity {
|
||||
bool nameSimilar : 1;
|
||||
bool fromSimilar : 1;
|
||||
bool toSimilar : 1;
|
||||
};
|
||||
|
||||
inline bool operator<(const LineSimilarity& a, const LineSimilarity& b) {
|
||||
return (a.nameSimilar + a.fromSimilar + a.toSimilar) <
|
||||
(b.nameSimilar + b.fromSimilar + b.toSimilar);
|
||||
}
|
||||
|
||||
struct RoutingAttrs {
|
||||
RoutingAttrs() : fromString(""), toString(""), shortName(""), _simiCache() {}
|
||||
std::string fromString;
|
||||
std::string toString;
|
||||
RoutingAttrs()
|
||||
: lineFrom(""), lineTo(), shortName(""), classifier(0), _simiCache() {}
|
||||
std::string lineFrom;
|
||||
std::vector<std::string> lineTo;
|
||||
std::string shortName;
|
||||
|
||||
mutable std::map<const TransitEdgeLine*, double> _simiCache;
|
||||
const pfaedle::statsimiclassifier::StatsimiClassifier* classifier;
|
||||
|
||||
mutable std::unordered_map<const TransitEdgeLine*, LineSimilarity> _simiCache;
|
||||
|
||||
LineSimilarity simi(const TransitEdgeLine* line) const {
|
||||
// shortcut, if we don't have a line information, classify as similar
|
||||
if (line->shortName.empty() && line->toStr.empty() && line->fromStr.empty())
|
||||
return {true, true, true};
|
||||
|
||||
// carfull: lower return value = higher similarity
|
||||
double simi(const TransitEdgeLine* line) const {
|
||||
auto i = _simiCache.find(line);
|
||||
if (i != _simiCache.end()) return i->second;
|
||||
|
||||
double cur = 1;
|
||||
LineSimilarity ret{false, false, false};
|
||||
|
||||
if (shortName.empty() || router::lineSimi(line->shortName, shortName) > 0.5)
|
||||
cur -= 0.333333333;
|
||||
ret.nameSimilar = true;
|
||||
|
||||
if (toString.empty() || line->toStr.empty() ||
|
||||
router::statSimi(line->toStr, toString) > 0.5)
|
||||
cur -= 0.333333333;
|
||||
if (lineTo.size() == 0) {
|
||||
ret.toSimilar = true;
|
||||
} else {
|
||||
for (const auto& lTo : lineTo) {
|
||||
if (lTo.empty() || classifier->similar(line->toStr, lTo)) {
|
||||
ret.toSimilar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fromString.empty() || line->fromStr.empty() ||
|
||||
router::statSimi(line->fromStr, fromString) > 0.5)
|
||||
cur -= 0.333333333;
|
||||
if (lineFrom.empty() || classifier->similar(line->fromStr, lineFrom))
|
||||
ret.fromSimilar = true;
|
||||
|
||||
_simiCache[line] = cur;
|
||||
_simiCache[line] = ret;
|
||||
|
||||
return cur;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void merge(const RoutingAttrs& other) {
|
||||
assert(other.lineFrom == lineFrom);
|
||||
assert(other.shortName == shortName);
|
||||
|
||||
for (const auto& l : other.lineTo) {
|
||||
auto i = std::lower_bound(lineTo.begin(), lineTo.end(), l);
|
||||
if (i != lineTo.end() && (*i) == l) continue; // already present
|
||||
lineTo.insert(i, l);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const RoutingAttrs& a, const RoutingAttrs& b) {
|
||||
return a.shortName == b.shortName && a.toString == b.toString &&
|
||||
a.fromString == b.fromString;
|
||||
return a.shortName == b.shortName && a.lineFrom == b.lineFrom;
|
||||
}
|
||||
|
||||
inline bool operator!=(const RoutingAttrs& a, const RoutingAttrs& b) {
|
||||
|
|
@ -55,10 +91,8 @@ inline bool operator!=(const RoutingAttrs& a, const RoutingAttrs& b) {
|
|||
}
|
||||
|
||||
inline bool operator<(const RoutingAttrs& a, const RoutingAttrs& b) {
|
||||
return a.fromString < b.fromString ||
|
||||
(a.fromString == b.fromString && a.toString < b.toString) ||
|
||||
(a.fromString == b.fromString && a.toString == b.toString &&
|
||||
a.shortName < b.shortName);
|
||||
return a.lineFrom < b.lineFrom ||
|
||||
(a.lineFrom == b.lineFrom && a.shortName < b.shortName);
|
||||
}
|
||||
|
||||
} // namespace router
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -9,39 +9,41 @@
|
|||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/Def.h"
|
||||
#include "pfaedle/config/MotConfig.h"
|
||||
#include "pfaedle/config/PfaedleConfig.h"
|
||||
#include "pfaedle/eval/Collector.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/netgraph/Graph.h"
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "pfaedle/router/Stats.h"
|
||||
#include "pfaedle/router/TripTrie.h"
|
||||
#include "pfaedle/statsimi-classifier/StatsimiClassifier.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/geo/Geo.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
using pfaedle::gtfs::Trip;
|
||||
using pfaedle::gtfs::Feed;
|
||||
|
||||
struct Shape {
|
||||
router::EdgeListHops hops;
|
||||
double avgHopDist;
|
||||
};
|
||||
|
||||
typedef std::vector<Trip*> Cluster;
|
||||
typedef std::vector<Cluster> Clusters;
|
||||
typedef std::pair<const Stop*, const Stop*> StopPair;
|
||||
typedef std::unordered_map<const Trip*, router::RoutingAttrs> TripRAttrs;
|
||||
typedef std::unordered_map<const trgraph::Edge*, std::set<const Trip*>>
|
||||
typedef std::vector<TripTrie> TripForest;
|
||||
typedef std::map<router::RoutingAttrs, TripForest> TripForests;
|
||||
typedef std::pair<const ad::cppgtfs::gtfs::Stop*,
|
||||
const ad::cppgtfs::gtfs::Stop*>
|
||||
StopPair;
|
||||
typedef std::unordered_map<const pfaedle::gtfs::Trip*, router::RoutingAttrs>
|
||||
TripRAttrs;
|
||||
typedef std::unordered_map<const trgraph::Edge*,
|
||||
std::vector<const pfaedle::gtfs::Trip*>>
|
||||
TrGraphEdgs;
|
||||
typedef std::map<Route*, std::map<uint32_t, std::vector<gtfs::Trip*>>>
|
||||
RouteRefColors;
|
||||
typedef std::unordered_map<const ad::cppgtfs::gtfs::Stop*, EdgeCandGroup>
|
||||
GrpCache;
|
||||
|
||||
/*
|
||||
* Layer class for the router. Provides an interface for direct usage with
|
||||
|
|
@ -49,76 +51,116 @@ typedef std::unordered_map<const trgraph::Edge*, std::set<const Trip*>>
|
|||
*/
|
||||
class ShapeBuilder {
|
||||
public:
|
||||
ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed, MOTs mots,
|
||||
const config::MotConfig& motCfg, eval::Collector* ecoll,
|
||||
trgraph::Graph* g, router::FeedStops* stops,
|
||||
osm::Restrictor* restr, const config::Config& cfg);
|
||||
ShapeBuilder(
|
||||
pfaedle::gtfs::Feed* feed, MOTs mots, const config::MotConfig& motCfg,
|
||||
trgraph::Graph* g, router::FeedStops* stops, osm::Restrictor* restr,
|
||||
const pfaedle::statsimiclassifier::StatsimiClassifier* classifier,
|
||||
router::Router* router, const config::Config& cfg);
|
||||
|
||||
void shape(pfaedle::netgraph::Graph* ng);
|
||||
Stats shapeify(pfaedle::netgraph::Graph* outNg);
|
||||
|
||||
router::FeedStops* getFeedStops();
|
||||
|
||||
const NodeCandGroup& getNodeCands(const Stop* s) const;
|
||||
// shape single trip
|
||||
std::pair<std::vector<LINE>, Stats> shapeL(pfaedle::gtfs::Trip* trip);
|
||||
|
||||
LINE shapeL(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs);
|
||||
LINE shapeL(Trip* trip);
|
||||
|
||||
pfaedle::router::Shape shape(Trip* trip) const;
|
||||
pfaedle::router::Shape shape(Trip* trip);
|
||||
std::map<size_t, EdgeListHops> shapeify(const TripTrie* trie,
|
||||
HopCache* hopCache) const;
|
||||
EdgeListHops shapeify(pfaedle::gtfs::Trip* trip);
|
||||
|
||||
const trgraph::Graph* getGraph() const;
|
||||
|
||||
static void getGtfsBox(const Feed* feed, const MOTs& mots,
|
||||
static void getGtfsBox(const pfaedle::gtfs::Feed* feed, const MOTs& mots,
|
||||
const std::string& tid, bool dropShapes,
|
||||
osm::BBoxIdx* box);
|
||||
osm::BBoxIdx* box, double maxSpeed);
|
||||
|
||||
private:
|
||||
Feed* _feed;
|
||||
ad::cppgtfs::gtfs::Feed* _evalFeed;
|
||||
pfaedle::gtfs::Feed* _feed;
|
||||
MOTs _mots;
|
||||
config::MotConfig _motCfg;
|
||||
eval::Collector* _ecoll;
|
||||
config::Config _cfg;
|
||||
trgraph::Graph* _g;
|
||||
router::Router _crouter;
|
||||
|
||||
router::FeedStops* _stops;
|
||||
|
||||
NodeCandGroup _emptyNCG;
|
||||
EdgeCandGroup _emptyNCG;
|
||||
|
||||
size_t _curShpCnt, _numThreads;
|
||||
size_t _curShpCnt;
|
||||
|
||||
std::mutex _shpMutex;
|
||||
|
||||
TripRAttrs _rAttrs;
|
||||
|
||||
osm::Restrictor* _restr;
|
||||
const pfaedle::statsimiclassifier::StatsimiClassifier* _classifier;
|
||||
GrpCache _grpCache;
|
||||
|
||||
void buildGraph(router::FeedStops* fStops);
|
||||
router::Router* _router;
|
||||
|
||||
Clusters clusterTrips(Feed* f, MOTs mots);
|
||||
void writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs,
|
||||
const Cluster& cluster) const;
|
||||
void buildTrGraph(TrGraphEdgs* edgs, pfaedle::netgraph::Graph* ng) const;
|
||||
TripForests clusterTrips(pfaedle::gtfs::Feed* f, MOTs mots);
|
||||
void buildNetGraph(TrGraphEdgs* edgs, pfaedle::netgraph::Graph* ng) const;
|
||||
|
||||
std::string getFreeShapeId(Trip* t);
|
||||
std::string getFreeShapeId(pfaedle::gtfs::Trip* t);
|
||||
ad::cppgtfs::gtfs::Shape getGtfsShape(const EdgeListHops& shp,
|
||||
pfaedle::gtfs::Trip* t,
|
||||
const RoutingAttrs& rAttrs,
|
||||
std::vector<float>* hopDists,
|
||||
uint32_t* bestColor);
|
||||
|
||||
ad::cppgtfs::gtfs::Shape getGtfsShape(const Shape& shp, Trip* t,
|
||||
std::vector<double>* hopDists);
|
||||
void setShape(pfaedle::gtfs::Trip* t, const ad::cppgtfs::gtfs::Shape& s,
|
||||
const std::vector<float>& dists);
|
||||
|
||||
void setShape(Trip* t, const ad::cppgtfs::gtfs::Shape& s,
|
||||
const std::vector<double>& dists);
|
||||
EdgeCandGroup getEdgCands(const ad::cppgtfs::gtfs::Stop* s) const;
|
||||
|
||||
router::NodeCandRoute getNCR(Trip* trip) const;
|
||||
double avgHopDist(Trip* trip) const;
|
||||
const router::RoutingAttrs& getRAttrs(const Trip* trip) const;
|
||||
const router::RoutingAttrs& getRAttrs(const Trip* trip);
|
||||
bool routingEqual(Trip* a, Trip* b);
|
||||
bool routingEqual(const Stop* a, const Stop* b);
|
||||
router::EdgeListHops route(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs) const;
|
||||
router::EdgeCandMap getECM(const TripTrie* trie) const;
|
||||
std::vector<double> getTransTimes(pfaedle::gtfs::Trip* trip) const;
|
||||
std::vector<double> getTransDists(pfaedle::gtfs::Trip* trip) const;
|
||||
const router::RoutingAttrs& getRAttrs(const pfaedle::gtfs::Trip* trip) const;
|
||||
const router::RoutingAttrs& getRAttrs(const pfaedle::gtfs::Trip* trip);
|
||||
std::map<size_t, router::EdgeListHops> route(const TripTrie* trie,
|
||||
const EdgeCandMap& ecm,
|
||||
HopCache* hopCache) const;
|
||||
void buildCandCache(const TripForests& clusters);
|
||||
void buildIndex();
|
||||
|
||||
std::vector<LINE> getGeom(const EdgeListHops& shp, const RoutingAttrs& rAttrs,
|
||||
std::map<uint32_t, double>* colors) const;
|
||||
double timePen(int candTime, int schedTime) const;
|
||||
|
||||
LINE getLine(const EdgeListHop& hop, const RoutingAttrs&,
|
||||
std::map<uint32_t, double>* colMap) const;
|
||||
LINE getLine(const trgraph::Edge* edg) const;
|
||||
std::vector<float> getMeasure(const std::vector<LINE>& lines) const;
|
||||
|
||||
trgraph::Edge* deg2reachable(trgraph::Edge* e,
|
||||
std::set<trgraph::Edge*> edgs) const;
|
||||
|
||||
EdgeCandGroup timeExpand(const EdgeCand& ec, int time) const;
|
||||
|
||||
std::set<uint32_t> getColorMatch(const trgraph::Edge* e,
|
||||
const RoutingAttrs& rAttrs) const;
|
||||
|
||||
void updateRouteColors(const RouteRefColors& c);
|
||||
|
||||
uint32_t getTextColor(uint32_t c) const;
|
||||
|
||||
void writeTransitGraph(const router::EdgeListHops& shp, TrGraphEdgs* edgs,
|
||||
const std::vector<pfaedle::gtfs::Trip*>& trips) const;
|
||||
|
||||
void shapeWorker(
|
||||
const std::vector<const TripForest*>* tries, std::atomic<size_t>* at,
|
||||
std::map<std::string, size_t>* shpUsage,
|
||||
std::map<Route*, std::map<uint32_t, std::vector<gtfs::Trip*>>>*,
|
||||
TrGraphEdgs* gtfsGraph);
|
||||
|
||||
void edgCandWorker(std::vector<const Stop*>* stops, GrpCache* cache);
|
||||
void clusterWorker(const std::vector<RoutingAttrs>* rAttrs,
|
||||
const std::map<RoutingAttrs, std::vector<Trip*>>* trips,
|
||||
TripForests* forest);
|
||||
|
||||
pfaedle::trgraph::EdgeGrid _eGrid;
|
||||
pfaedle::trgraph::NodeGrid _nGrid;
|
||||
};
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
|
|
|
|||
33
src/pfaedle/router/Stats.h
Normal file
33
src/pfaedle/router/Stats.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_STATS_H_
|
||||
#define PFAEDLE_ROUTER_STATS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "util/String.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
struct Stats {
|
||||
Stats()
|
||||
: totNumTrips(0),
|
||||
numTries(0),
|
||||
numTrieLeafs(0),
|
||||
solveTime(0),
|
||||
dijkstraIters(0) {}
|
||||
size_t totNumTrips;
|
||||
size_t numTries;
|
||||
size_t numTrieLeafs;
|
||||
double solveTime;
|
||||
size_t dijkstraIters;
|
||||
};
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_STATS_H_
|
||||
219
src/pfaedle/router/TripTrie.cpp
Normal file
219
src/pfaedle/router/TripTrie.cpp
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "TripTrie.h"
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/StopTime.h"
|
||||
#include "pfaedle/router/TripTrie.h"
|
||||
|
||||
using pfaedle::gtfs::Trip;
|
||||
using pfaedle::router::TripTrie;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool TripTrie::addTrip(pfaedle::gtfs::Trip* trip, const RoutingAttrs& rAttrs,
|
||||
bool timeEx, bool degen) {
|
||||
if (!degen) return add(trip, rAttrs, timeEx);
|
||||
|
||||
// check if trip is already fully and uniquely contained, if not, fail
|
||||
size_t existing = get(trip, timeEx);
|
||||
if (existing && _nds[existing].childs.size() == 0) {
|
||||
_tripNds[trip] = existing;
|
||||
_ndTrips[existing].push_back(trip);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool TripTrie::add(pfaedle::gtfs::Trip* trip, const RoutingAttrs& rAttrs,
|
||||
bool timeEx) {
|
||||
if (trip->getStopTimes().size() == 0) return false;
|
||||
|
||||
int startSecs = trip->getStopTimes().front().getDepartureTime().seconds();
|
||||
|
||||
size_t curNdId = 0;
|
||||
for (size_t stId = 0; stId < trip->getStopTimes().size(); stId++) {
|
||||
const auto st = trip->getStopTimes()[stId];
|
||||
|
||||
std::string name = st.getStop()->getName();
|
||||
std::string platform = st.getStop()->getPlatformCode();
|
||||
POINT pos = util::geo::latLngToWebMerc<PFDL_PREC>(st.getStop()->getLat(),
|
||||
st.getStop()->getLng());
|
||||
|
||||
if (stId > 0) {
|
||||
int arrTime = st.getArrivalTime().seconds() - startSecs;
|
||||
|
||||
size_t arrChild =
|
||||
getMatchChild(curNdId, name, platform, pos, arrTime, timeEx);
|
||||
|
||||
if (arrChild) {
|
||||
curNdId = arrChild;
|
||||
|
||||
_nds[arrChild].accTime += arrTime;
|
||||
_nds[arrChild].trips += 1;
|
||||
|
||||
_nds[arrChild].rAttrs.merge(rAttrs);
|
||||
} else {
|
||||
curNdId = insert(st.getStop(), rAttrs, pos, arrTime, true, curNdId);
|
||||
}
|
||||
}
|
||||
|
||||
if (stId < trip->getStopTimes().size() - 1) {
|
||||
int depTime = st.getDepartureTime().seconds() - startSecs;
|
||||
|
||||
size_t depChild =
|
||||
getMatchChild(curNdId, name, platform, pos, depTime, timeEx);
|
||||
|
||||
if (depChild) {
|
||||
curNdId = depChild;
|
||||
|
||||
_nds[depChild].accTime += depTime;
|
||||
_nds[depChild].trips += 1;
|
||||
|
||||
_nds[depChild].rAttrs.merge(rAttrs);
|
||||
} else {
|
||||
if (stId == 0 && _tripNds.size() > 0) return false;
|
||||
curNdId = insert(st.getStop(), rAttrs, pos, depTime, false, curNdId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// curNdId is now the last matching node, insert the trip here
|
||||
_tripNds[trip] = curNdId;
|
||||
_ndTrips[curNdId].push_back(trip);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t TripTrie::get(pfaedle::gtfs::Trip* trip, bool timeEx) {
|
||||
if (trip->getStopTimes().size() == 0) return false;
|
||||
|
||||
int startSecs = trip->getStopTimes().front().getDepartureTime().seconds();
|
||||
|
||||
size_t curNdId = 0;
|
||||
for (size_t stId = 0; stId < trip->getStopTimes().size(); stId++) {
|
||||
const auto st = trip->getStopTimes()[stId];
|
||||
|
||||
std::string name = st.getStop()->getName();
|
||||
std::string platform = st.getStop()->getPlatformCode();
|
||||
POINT pos = util::geo::latLngToWebMerc<PFDL_PREC>(st.getStop()->getLat(),
|
||||
st.getStop()->getLng());
|
||||
|
||||
if (stId > 0) {
|
||||
int arrTime = st.getArrivalTime().seconds() - startSecs;
|
||||
|
||||
size_t arrChild =
|
||||
getMatchChild(curNdId, name, platform, pos, arrTime, timeEx);
|
||||
|
||||
if (arrChild) {
|
||||
curNdId = arrChild;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (stId < trip->getStopTimes().size() - 1) {
|
||||
int depTime = st.getDepartureTime().seconds() - startSecs;
|
||||
|
||||
size_t depChild =
|
||||
getMatchChild(curNdId, name, platform, pos, depTime, timeEx);
|
||||
|
||||
if (depChild) {
|
||||
curNdId = depChild;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return curNdId;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t TripTrie::insert(const ad::cppgtfs::gtfs::Stop* stop,
|
||||
const RoutingAttrs& rAttrs, const POINT& pos, int time,
|
||||
bool arr, size_t parent) {
|
||||
_nds.emplace_back(TripTrieNd{stop,
|
||||
stop->getName(),
|
||||
stop->getPlatformCode(),
|
||||
pos,
|
||||
stop->getLat(),
|
||||
stop->getLng(),
|
||||
time,
|
||||
arr,
|
||||
time,
|
||||
1,
|
||||
parent,
|
||||
{},
|
||||
rAttrs});
|
||||
_nds[parent].childs.push_back(_nds.size() - 1);
|
||||
return _nds.size() - 1;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const std::vector<pfaedle::router::TripTrieNd>& TripTrie::getNds() const {
|
||||
return _nds;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t TripTrie::getMatchChild(size_t parentNid, const std::string& stopName,
|
||||
const std::string& platform, POINT pos, int time,
|
||||
bool timeEx) const {
|
||||
for (size_t child : _nds[parentNid].childs) {
|
||||
// TODO(patrick): use similarity classification here?
|
||||
if (_nds[child].stopName == stopName && _nds[child].platform == platform &&
|
||||
util::geo::dist(_nds[child].pos, pos) < 1 &&
|
||||
(!timeEx || _nds[child].time == time)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void TripTrie::toDot(std::ostream& os, const std::string& rootName,
|
||||
size_t gid) const {
|
||||
os << "digraph triptrie" << gid << " {";
|
||||
|
||||
for (size_t nid = 0; nid < _nds.size(); nid++) {
|
||||
std::string color = "white";
|
||||
if (_ndTrips.count(nid)) color = "red";
|
||||
if (nid == 0) {
|
||||
os << "\"" << gid << ":0\" [label=\"" << rootName << "\"];\n";
|
||||
} else {
|
||||
os << "\"" << gid << ":" << nid
|
||||
<< "\" [shape=\"box\" style=\"filled\" fillcolor=\"" << color
|
||||
<< "\" label=\"#" << nid << ", " << _nds[nid].stopName << "@"
|
||||
<< util::geo::getWKT(_nds[nid].pos) << " t=" << _nds[nid].time
|
||||
<< "\"];\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t nid = 0; nid < _nds.size(); nid++) {
|
||||
for (size_t child : _nds[nid].childs) {
|
||||
os << "\"" << gid << ":" << nid << "\" -> \"" << gid << ":" << child
|
||||
<< "\";\n";
|
||||
}
|
||||
}
|
||||
|
||||
os << "}";
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const std::map<size_t, std::vector<pfaedle::gtfs::Trip*>>&
|
||||
TripTrie::getNdTrips() const {
|
||||
return _ndTrips;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const pfaedle::router::TripTrieNd& TripTrie::getNd(size_t nid) const {
|
||||
return _nds[nid];
|
||||
}
|
||||
65
src/pfaedle/router/TripTrie.h
Normal file
65
src/pfaedle/router/TripTrie.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_TRIPTRIE_H_
|
||||
#define PFAEDLE_ROUTER_TRIPTRIE_H_
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/StopTime.h"
|
||||
#include "pfaedle/router/RoutingAttrs.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
struct TripTrieNd {
|
||||
const ad::cppgtfs::gtfs::Stop* reprStop;
|
||||
std::string stopName; // the stop name at this node
|
||||
std::string platform; // the platform of node
|
||||
POINT pos; // the position of this node
|
||||
double lat, lng;
|
||||
int time;
|
||||
bool arr;
|
||||
int accTime;
|
||||
size_t trips;
|
||||
size_t parent;
|
||||
std::vector<size_t> childs;
|
||||
RoutingAttrs rAttrs;
|
||||
};
|
||||
|
||||
class TripTrie {
|
||||
public:
|
||||
// init node 0, this is the first decision node
|
||||
TripTrie() : _nds(1) {}
|
||||
bool addTrip(pfaedle::gtfs::Trip* trip, const RoutingAttrs& rAttrs,
|
||||
bool timeEx, bool degen);
|
||||
|
||||
const std::vector<TripTrieNd>& getNds() const;
|
||||
const TripTrieNd& getNd(size_t nid) const;
|
||||
|
||||
void toDot(std::ostream& os, const std::string& rootName, size_t gid) const;
|
||||
const std::map<size_t, std::vector<pfaedle::gtfs::Trip*>>& getNdTrips() const;
|
||||
|
||||
private:
|
||||
std::vector<TripTrieNd> _nds;
|
||||
std::map<pfaedle::gtfs::Trip*, size_t> _tripNds;
|
||||
std::map<size_t, std::vector<pfaedle::gtfs::Trip*>> _ndTrips;
|
||||
|
||||
bool add(pfaedle::gtfs::Trip* trip, const RoutingAttrs& rAttrs, bool timeEx);
|
||||
size_t get(pfaedle::gtfs::Trip* trip, bool timeEx);
|
||||
|
||||
size_t getMatchChild(size_t parentNid, const std::string& stopName,
|
||||
const std::string& platform, POINT pos, int time,
|
||||
bool timeEx) const;
|
||||
size_t insert(const ad::cppgtfs::gtfs::Stop* stop, const RoutingAttrs& rAttrs,
|
||||
const POINT& pos, int time, bool arr, size_t parent);
|
||||
};
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_TRIPTRIE_H_
|
||||
261
src/pfaedle/router/Weights.cpp
Normal file
261
src/pfaedle/router/Weights.cpp
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <limits>
|
||||
#include "pfaedle/router/Weights.h"
|
||||
|
||||
using pfaedle::router::DistDiffTransWeight;
|
||||
using pfaedle::router::ExpoTransWeight;
|
||||
using pfaedle::router::LineSimilarity;
|
||||
using pfaedle::router::NormDistrTransWeight;
|
||||
using util::geo::haversine;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
ExpoTransWeight::DistHeur::DistHeur(double maxV, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos)
|
||||
: _rOpts(rOpts), _maxV(maxV), _maxCentD(0), _lastE(0) {
|
||||
size_t c = 0;
|
||||
double x = 0, y = 0;
|
||||
|
||||
for (const auto to : tos) {
|
||||
x += to->getFrom()->pl().getGeom()->getX();
|
||||
y += to->getFrom()->pl().getGeom()->getY();
|
||||
c++;
|
||||
}
|
||||
|
||||
x /= c;
|
||||
y /= c;
|
||||
|
||||
_center = POINT{x, y};
|
||||
|
||||
for (const auto to : tos) {
|
||||
const double cur = haversine(*to->getFrom()->pl().getGeom(), _center);
|
||||
if (cur > _maxCentD) _maxCentD = cur;
|
||||
}
|
||||
|
||||
_maxCentD /= _maxV;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t ExpoTransWeight::DistHeur::operator()(
|
||||
const trgraph::Edge* a, const std::set<trgraph::Edge*>& b) const {
|
||||
UNUSED(b);
|
||||
|
||||
// avoid repeated calculation for the same edge over and over again
|
||||
if (a == _lastE) return _lastC;
|
||||
|
||||
_lastE = a;
|
||||
|
||||
const double d = haversine(*a->getFrom()->pl().getGeom(), _center);
|
||||
const double heur = fmax(0, (d / _maxV - _maxCentD) * 10);
|
||||
|
||||
// avoid overflow
|
||||
if (heur > std::numeric_limits<uint32_t>::max()) {
|
||||
_lastC = std::numeric_limits<uint32_t>::max();
|
||||
;
|
||||
return _lastC;
|
||||
}
|
||||
|
||||
_lastC = heur;
|
||||
return heur;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t ExpoTransWeight::CostFunc::operator()(const trgraph::Edge* from,
|
||||
const trgraph::Node* n,
|
||||
const trgraph::Edge* to) const {
|
||||
if (!from) return 0;
|
||||
|
||||
uint32_t c = from->pl().getCost();
|
||||
|
||||
if (c == std::numeric_limits<uint32_t>::max()) return c;
|
||||
|
||||
if (from == _lastFrom) {
|
||||
// the transit line simi calculation is independent of the "to" edge, so if
|
||||
// the last "from" edge was the same, skip it!
|
||||
c = _lastC;
|
||||
} else if (!_noLineSimiPen) {
|
||||
const auto& simi = transitLineSimi(from);
|
||||
|
||||
if (!simi.nameSimilar) {
|
||||
if (_rOpts.lineUnmatchedPunishFact < 1) {
|
||||
c = std::ceil(static_cast<double>(c) * _rOpts.lineUnmatchedPunishFact);
|
||||
} else if (_rOpts.lineUnmatchedPunishFact > 1) {
|
||||
double a =
|
||||
std::round(static_cast<double>(c) * _rOpts.lineUnmatchedPunishFact);
|
||||
if (a > std::numeric_limits<uint32_t>::max())
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
c = a;
|
||||
}
|
||||
}
|
||||
|
||||
if (!simi.fromSimilar) {
|
||||
if (_rOpts.lineNameFromUnmatchedPunishFact < 1) {
|
||||
c = std::ceil(static_cast<double>(c) *
|
||||
_rOpts.lineNameFromUnmatchedPunishFact);
|
||||
} else if (_rOpts.lineNameFromUnmatchedPunishFact > 1) {
|
||||
double a = std::round(static_cast<double>(c) *
|
||||
_rOpts.lineNameFromUnmatchedPunishFact);
|
||||
if (a > std::numeric_limits<uint32_t>::max())
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
c = a;
|
||||
}
|
||||
}
|
||||
|
||||
if (!simi.toSimilar) {
|
||||
if (_rOpts.lineNameToUnmatchedPunishFact < 1) {
|
||||
c = std::ceil(static_cast<double>(c) *
|
||||
_rOpts.lineNameToUnmatchedPunishFact);
|
||||
} else if (_rOpts.lineNameToUnmatchedPunishFact > 1) {
|
||||
double a = std::round(static_cast<double>(c) *
|
||||
_rOpts.lineNameToUnmatchedPunishFact);
|
||||
if (a > std::numeric_limits<uint32_t>::max())
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
c = a;
|
||||
}
|
||||
}
|
||||
|
||||
_lastC = c;
|
||||
_lastFrom = from;
|
||||
}
|
||||
|
||||
uint32_t overflowCheck = c;
|
||||
|
||||
if (n && !n->pl().isTurnCycle()) {
|
||||
if (_rOpts.fullTurnPunishFac != 0 && from->getFrom() == to->getTo() &&
|
||||
from->getTo() == to->getFrom()) {
|
||||
// trivial full turn
|
||||
c += _rOpts.fullTurnPunishFac;
|
||||
|
||||
if (c <= overflowCheck) return std::numeric_limits<uint32_t>::max();
|
||||
overflowCheck = c;
|
||||
} else if (_rOpts.fullTurnPunishFac != 0 && n->getDeg() > 2) {
|
||||
// otherwise, only intersection angles will be punished
|
||||
|
||||
double ang = util::geo::innerProd(
|
||||
*n->pl().getGeom(), from->pl().backHop(), to->pl().frontHop());
|
||||
|
||||
if (ang < _rOpts.fullTurnAngle) {
|
||||
c += _rOpts.fullTurnPunishFac;
|
||||
if (c <= overflowCheck) return std::numeric_limits<uint32_t>::max();
|
||||
overflowCheck = c;
|
||||
}
|
||||
}
|
||||
|
||||
// turn restriction cost
|
||||
if (_rOpts.turnRestrCost > 0 && from->pl().isRestricted() &&
|
||||
!_res.may(from, to, n)) {
|
||||
c += _rOpts.turnRestrCost;
|
||||
if (c <= overflowCheck) return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
LineSimilarity ExpoTransWeight::CostFunc::transitLineSimi(
|
||||
const trgraph::Edge* e) const {
|
||||
if (_rAttrs.shortName.empty() && _rAttrs.lineFrom.empty() &&
|
||||
_rAttrs.lineTo.empty())
|
||||
return {true, true, true};
|
||||
|
||||
LineSimilarity best = {false, false, false};
|
||||
for (const auto* l : e->pl().getLines()) {
|
||||
auto simi = _rAttrs.simi(l);
|
||||
if (simi.nameSimilar && simi.toSimilar && simi.fromSimilar) return simi;
|
||||
if (best < simi) best = simi;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double ExpoTransWeight::weight(uint32_t c, double d, double t0, double d0,
|
||||
const RoutingOpts& rOpts) {
|
||||
UNUSED(t0);
|
||||
UNUSED(d);
|
||||
UNUSED(d0);
|
||||
return rOpts.transitionPen * static_cast<double>(c) / 10.0;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t ExpoTransWeight::invWeight(double c, const RoutingOpts& rOpts) {
|
||||
return std::round((c / rOpts.transitionPen) * 10);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t ExpoTransWeight::maxCost(double tTime, const RoutingOpts& rOpts) {
|
||||
// abort after 3 times the scheduled time, but assume a min time of
|
||||
// 1 minute!
|
||||
return std::ceil(fmax(tTime, 60) * 3 * rOpts.lineUnmatchedPunishFact *
|
||||
rOpts.lineNameToUnmatchedPunishFact *
|
||||
rOpts.lineNameFromUnmatchedPunishFact * 10);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double NormDistrTransWeight::weight(uint32_t cs, double d, double t0, double d0,
|
||||
const RoutingOpts& rOpts) {
|
||||
UNUSED(d);
|
||||
UNUSED(d0);
|
||||
UNUSED(rOpts);
|
||||
|
||||
double t = static_cast<double>(cs) / 10.0;
|
||||
|
||||
// standard deviation of normal distribution
|
||||
double standarddev = 1;
|
||||
|
||||
// no backwards time travel!
|
||||
if (t0 < 0) return std::numeric_limits<double>::infinity();
|
||||
|
||||
// always assume it takes at least 10 seconds to travel
|
||||
t0 = fmax(10, t0);
|
||||
|
||||
double cNorm = (t / t0 - 1) / standarddev;
|
||||
double normWeight = cNorm * cNorm;
|
||||
|
||||
double expWeight = ExpoTransWeight::weight(cs, d, t0, d0, rOpts);
|
||||
|
||||
return normWeight + expWeight;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t NormDistrTransWeight::invWeight(double c, const RoutingOpts& rOpts) {
|
||||
UNUSED(rOpts);
|
||||
UNUSED(c);
|
||||
|
||||
throw(std::runtime_error("Cannot apply inv weight to DistDiffTransWeight"));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double DistDiffTransWeight::weight(uint32_t c, double d, double t0, double d0,
|
||||
const RoutingOpts& rOpts) {
|
||||
UNUSED(t0);
|
||||
UNUSED(c);
|
||||
// double mean = 250; // expectation value of 250 meters for buses
|
||||
// double lambda = 1.0 / mean;
|
||||
|
||||
double w = fabs(d - d0);
|
||||
|
||||
return rOpts.transitionPen * w;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t DistDiffTransWeight::invWeight(double c, const RoutingOpts& rOpts) {
|
||||
UNUSED(rOpts);
|
||||
UNUSED(c);
|
||||
|
||||
throw(std::runtime_error("Cannot apply inv weight to DistDiffTransWeight"));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
uint32_t DistDiffTransWeight::maxCost(double tTime, const RoutingOpts& rOpts) {
|
||||
UNUSED(tTime);
|
||||
UNUSED(rOpts);
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
161
src/pfaedle/router/Weights.h
Normal file
161
src/pfaedle/router/Weights.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_WEIGHTS_H_
|
||||
#define PFAEDLE_ROUTER_WEIGHTS_H_
|
||||
|
||||
#include <set>
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "pfaedle/router/RoutingAttrs.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/graph/EDijkstra.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
typedef util::graph::EDijkstra::CostFunc<trgraph::NodePL, trgraph::EdgePL,
|
||||
uint32_t>
|
||||
RCostFunc;
|
||||
typedef util::graph::EDijkstra::HeurFunc<trgraph::NodePL, trgraph::EdgePL,
|
||||
uint32_t>
|
||||
RHeurFunc;
|
||||
|
||||
class ExpoTransWeight {
|
||||
public:
|
||||
struct CostFunc : public RCostFunc {
|
||||
CostFunc(const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& res, uint32_t max)
|
||||
: _rAttrs(rAttrs),
|
||||
_rOpts(rOpts),
|
||||
_res(res),
|
||||
_inf(max),
|
||||
_noLineSimiPen(false),
|
||||
_lastFrom(0) {
|
||||
if (_rAttrs.lineFrom.empty() && _rAttrs.lineTo.empty() &&
|
||||
_rAttrs.shortName.empty()) {
|
||||
_noLineSimiPen = true;
|
||||
}
|
||||
if (_rOpts.lineUnmatchedPunishFact == 1) {
|
||||
_noLineSimiPen = true;
|
||||
}
|
||||
}
|
||||
|
||||
const RoutingAttrs& _rAttrs;
|
||||
const RoutingOpts& _rOpts;
|
||||
const osm::Restrictor& _res;
|
||||
uint32_t _inf;
|
||||
bool _noLineSimiPen;
|
||||
mutable const trgraph::Edge* _lastFrom;
|
||||
mutable uint32_t _lastC;
|
||||
|
||||
uint32_t operator()(const trgraph::Edge* from, const trgraph::Node* n,
|
||||
const trgraph::Edge* to) const;
|
||||
uint32_t inf() const { return _inf; }
|
||||
|
||||
LineSimilarity transitLineSimi(const trgraph::Edge* e) const;
|
||||
};
|
||||
|
||||
struct DistHeur : RHeurFunc {
|
||||
DistHeur(double maxV, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos);
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
double _maxV;
|
||||
POINT _center;
|
||||
double _maxCentD;
|
||||
uint32_t operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const;
|
||||
mutable const trgraph::Edge* _lastE;
|
||||
mutable uint32_t _lastC;
|
||||
};
|
||||
|
||||
static uint32_t maxCost(double tTime, const RoutingOpts& rOpts);
|
||||
static double weight(uint32_t c, double d, double t0, double d0,
|
||||
const RoutingOpts& rOpts);
|
||||
static uint32_t invWeight(double cost, const RoutingOpts& rOpts);
|
||||
static const bool ALLOWS_FAST_ROUTE = true;
|
||||
static const bool NEED_DIST = false;
|
||||
};
|
||||
|
||||
class ExpoTransWeightNoHeur : public ExpoTransWeight {
|
||||
public:
|
||||
struct DistHeur : RHeurFunc {
|
||||
DistHeur(double maxV, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos) {
|
||||
UNUSED(maxV);
|
||||
UNUSED(rOpts);
|
||||
UNUSED(tos);
|
||||
}
|
||||
|
||||
uint32_t operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const {
|
||||
UNUSED(a);
|
||||
UNUSED(b);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class NormDistrTransWeight : public ExpoTransWeight {
|
||||
public:
|
||||
static double weight(uint32_t c, double d, double t0, double d0,
|
||||
const RoutingOpts& rOpts);
|
||||
static uint32_t invWeight(double cost, const RoutingOpts& rOpts);
|
||||
static const bool ALLOWS_FAST_ROUTE = false;
|
||||
static const bool NEED_DIST = false;
|
||||
};
|
||||
|
||||
class NormDistrTransWeightNoHeur : public NormDistrTransWeight {
|
||||
public:
|
||||
struct DistHeur : RHeurFunc {
|
||||
DistHeur(double maxV, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos) {
|
||||
UNUSED(maxV);
|
||||
UNUSED(rOpts);
|
||||
UNUSED(tos);
|
||||
}
|
||||
|
||||
uint32_t operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const {
|
||||
UNUSED(a);
|
||||
UNUSED(b);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class DistDiffTransWeight : public ExpoTransWeight {
|
||||
public:
|
||||
static uint32_t maxCost(double tTime, const RoutingOpts& rOpts);
|
||||
static double weight(uint32_t c, double d, double t0, double d0,
|
||||
const RoutingOpts& rOpts);
|
||||
static uint32_t invWeight(double cost, const RoutingOpts& rOpts);
|
||||
static const bool ALLOWS_FAST_ROUTE = false;
|
||||
static const bool NEED_DIST = true;
|
||||
};
|
||||
|
||||
class DistDiffTransWeightNoHeur : public DistDiffTransWeight {
|
||||
public:
|
||||
struct DistHeur : RHeurFunc {
|
||||
DistHeur(double maxV, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos) {
|
||||
UNUSED(maxV);
|
||||
UNUSED(rOpts);
|
||||
UNUSED(tos);
|
||||
}
|
||||
|
||||
uint32_t operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const {
|
||||
UNUSED(a);
|
||||
UNUSED(b);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_WEIGHTS_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue