From 71c2a7b1a60e6aaaf4488d031659ebc75cc512ba Mon Sep 17 00:00:00 2001 From: Philipp Schlehuber-Caissier Date: Sun, 15 May 2022 23:56:19 +0200 Subject: [PATCH] Add a new function to sort edges sort_edge_srcfirst_ will sort the edge with respect to the src state, then sort each sub list with respect to the given predicate, possibly in parallel. * spot/graph/graph.hh: Here --- spot/graph/graph.hh | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/spot/graph/graph.hh b/spot/graph/graph.hh index fa276131d..dc7ffc6ae 100644 --- a/spot/graph/graph.hh +++ b/spot/graph/graph.hh @@ -28,6 +28,7 @@ #include #include #include +#include namespace spot { @@ -1226,6 +1227,75 @@ namespace spot std::stable_sort(edges_.begin() + 1, edges_.end(), p); } + /// \brief Sort all edges by src first, then, within edges of the same + /// source use the predicate + /// + /// This will invalidate all iterators, and also destroy edge + /// chains. Call chain_edges_() immediately afterwards unless you + /// know what you are doing. + /// \note: for performance this will work in parallel (if enabled) + /// and make a temporary copy of the edges (needs more ram) + /// \pre This needs the edge_vector to be in a coherent state when called + template> + void sort_edges_srcfirst_(Predicate p = Predicate()) + { + //std::cerr << "\nbefore\n"; + //dump_storage(std::cerr); + const auto N = num_states(); + // Read threads once + const unsigned nthreads = get_nthreads(); + + auto idx_list = std::vector(N+1); + auto new_edges = edge_vector_t(); + new_edges.reserve(edges_.size()); + if (SPOT_UNLIKELY(edges_.empty())) + throw std::runtime_error("Empty edge vector!"); + new_edges.resize(1); + // This causes edge 0 to be considered as dead. + new_edges[0].next_succ = 0; + // Copy the edges such that they are sorted by src + for (auto s = 0u; s < N; ++s) + { + idx_list[s] = new_edges.size(); + for (const auto& e : out(s)) + new_edges.push_back(e); + } + idx_list[N] = new_edges.size(); + // New edge sorted by source + // If we have few edge or only one threads + // Benchmark few? + auto bne = new_edges.begin(); + if (nthreads == 1 || edges_.size() < 1000) + { + for (auto s = 0u; s < N; ++s) + std::stable_sort(bne + idx_list[s], + bne + idx_list[s+1], + p); + } + else + { + static auto tv = std::vector(); + SPOT_ASSERT(tv.empty()); + tv.resize(nthreads); + for (unsigned id = 0; id < nthreads; ++id) + tv[id] = std::thread( + [bne, id, N, &idx_list, p, nthreads]() + { + for (auto s = id; s < N; s+=nthreads) + std::stable_sort(bne + idx_list[s], + bne + idx_list[s+1], + p); + return; + }); + for (auto& t : tv) + t.join(); + tv.clear(); + } + // Done + std::swap(edges_, new_edges); + // Like after normal sort_edges, they need to be chained before usage + } + /// \brief Sort edges of the given states /// /// \tparam Predicate : Comparison type