24 : graph_(graph), source_(source) {
28 [[nodiscard]]
const std::vector<std::uint64_t>&
distances() const noexcept {
return dist_; }
31 if (batch.
empty())
return;
35 for (
const auto& op : batch.
updates) {
36 if (op.src != op.dst && op.add && op.weight >=
kInf) {
37 throw std::invalid_argument(
38 "edge weight exceeds the representable finite-distance domain");
42 const auto canonical = canonicalize(batch);
43 bool requires_recompute =
false;
44 for (
const auto& op : canonical.updates) {
45 const auto old_weight =
edge_weight(graph_, op.src, op.dst);
47 if (old_weight.has_value()) {
48 requires_recompute =
true;
53 if (old_weight && op.weight > *old_weight) {
54 requires_recompute =
true;
61 else relax_from_updates(canonical);
73 static std::uint64_t edge_key(
VertexId u,
VertexId v,
bool directed)
noexcept {
74 if (!directed && v < u) std::swap(u, v);
75 return (
static_cast<std::uint64_t
>(u) << 32U) |
static_cast<std::uint64_t
>(v);
78 WeightedUpdateBatch canonicalize(
const WeightedUpdateBatch& batch)
const {
79 WeightedUpdateBatch out;
80 out.updates.reserve(batch.updates.size());
81 std::unordered_set<std::uint64_t> seen;
82 seen.reserve(batch.updates.size() * 2 + 1);
84 for (
auto it = batch.updates.rbegin(); it != batch.updates.rend(); ++it) {
85 if (it->src == it->dst)
continue;
87 if (!
is_directed(graph_) && op.dst < op.src) std::swap(op.src, op.dst);
88 if (seen.insert(edge_key(op.src, op.dst,
is_directed(graph_))).second) {
89 out.updates.push_back(op);
92 std::reverse(out.updates.begin(), out.updates.end());
96 void relax_from_updates(
const WeightedUpdateBatch& batch) {
99 using Item = std::pair<std::uint64_t, VertexId>;
100 std::priority_queue<Item, std::vector<Item>, std::greater<Item>> queue;
102 for (
const auto& op : batch.updates) {
103 if (!op.add || op.src >= dist_.size() || op.dst >= dist_.size())
continue;
104 const auto final_weight =
edge_weight(graph_, op.src, op.dst);
105 if (!final_weight)
continue;
106 const auto weight = *final_weight;
108 if (dist_[op.src] !=
kInf && weight <=
kInf - dist_[op.src]) {
109 const auto candidate = dist_[op.src] + weight;
110 if (candidate < dist_[op.dst]) {
111 dist_[op.dst] = candidate;
112 queue.push({candidate, op.dst});
116 const auto reverse_candidate = dist_[op.dst] + weight;
117 if (reverse_candidate < dist_[op.src]) {
118 dist_[op.src] = reverse_candidate;
119 queue.push({reverse_candidate, op.src});
133 std::vector<std::uint64_t> dist_;
void propagate_dijkstra(std::vector< std::uint64_t > &dist, std::priority_queue< std::pair< std::uint64_t, VertexId >, std::vector< std::pair< std::uint64_t, VertexId > >, std::greater< std::pair< std::uint64_t, VertexId > > > &queue, NeighborEnumerator &&enumerate)