Fishnet 2.0.1
Framework for Graph-Based Analysis of GIS Vector Data
Loading...
Searching...
No Matches
Contraction.hpp
Go to the documentation of this file.
1#pragma once
2#include "BFSAlgorithm.hpp"
3#include <future>
4#include <mutex>
5#include <numeric>
6#include <type_traits>
7#include <chrono>
8#include <unordered_set>
11
12namespace fishnet::graph::__impl {
13
14template<typename N>
16
17template<typename N>
18using QueuePtr = std::shared_ptr<QueueType<N>>;
19
29template<typename N,typename R>
30static std::vector<std::pair<int,R>> mergeWorker(QueuePtr<N> queue, util::ReduceFunction<std::vector<N>,R> auto const& reduceFunction){
31 std::vector<std::pair<int,R>> mergeResult;
32 fishnet::Option<std::pair<int,std::vector<N>>> current = std::nullopt;
33 do{
34 current = queue->take();
35 if(not current) {
36 queue->putPoisonPill();
37 break;
38 }
39 const auto & [componentId, nodes] = current.value();
40 mergeResult.emplace_back(componentId, reduceFunction(std::move(nodes)));
41 }while(current);
42 return mergeResult;
43}
44
53template<typename N>
54static std::vector<std::pair<int,N>> mergeWorker(QueuePtr<N> queue, util::ReduceFunction<std::vector<N>> auto const& reduceFunction){
55 return mergeWorker(queue, reduceFunction,util::Identity());
56}
57
58template<typename N,typename E>
59struct ContractionResult {
60 std::vector<N> nodes;
61 std::unordered_set<E> edges;
62};
63
79template<Graph SourceGraphType, Graph TargetGraphType>
80auto contractImpl(const SourceGraphType & source,
81 util::BiPredicate<typename SourceGraphType::node_type> auto const & contractBiPredicate,
82 util::ReduceFunction<std::vector<typename SourceGraphType::node_type>,typename TargetGraphType::node_type> auto const & reduceFunction,
83 util::UnaryFunction<typename SourceGraphType::node_type,typename TargetGraphType::node_type> auto const & mapper,
84 TargetGraphType & output,
85 u_int8_t workers = 1)
86{
87 using N = SourceGraphType::node_type;
88 using R = TargetGraphType::node_type;
89 if(workers == 0)
90 workers = 1;
91 auto queue = std::make_shared<__impl::QueueType<N>>();
92 std::vector<std::future<std::vector<std::pair<int,R>>>> futures;
93 futures.reserve(workers);
94 for(int i = 0; i < workers; i++){
95 futures.emplace_back(std::async(std::launch::async,[queue,&reduceFunction](){return __impl::mergeWorker<N,R>(queue,reduceFunction);}));
96 }
97 auto componentsMap = BFS::connectedComponents(source,queue,contractBiPredicate).nodeMap();
98 std::unordered_map<int,R> result;
99 queue->putPoisonPill();
100 result.reserve(componentsMap.size());
101 for(auto & f: futures){
102 for(auto & merged: f.get() ){
103 result.try_emplace(merged.first,merged.second);
104 }
105 }
106 std::vector<R> nodes;
107 for(const auto & node: source.getNodes()){
108 if(util::size(source.getNeighbours(node))==0 && util::size(source.getReachableFrom(node))==0){
109 nodes.emplace_back(mapper(node));
110 }
111 }
112 nodes.insert(nodes.end(), std::views::values(result).begin(), std::views::values(result).end());
113
114 std::unordered_set<typename TargetGraphType::edge_type> edges;
115 for(const auto & edge: source.getEdges()){
116 if(componentsMap.at(edge.getFrom()) != componentsMap.at(edge.getTo())){
117 edges.insert(
118 output.makeEdge(result.at(componentsMap.at(edge.getFrom())), result.at(componentsMap.at(edge.getTo())))
119 );
120 }
121 }
122 return ContractionResult<R,typename TargetGraphType::edge_type>{std::move(nodes), std::move(edges)};
123}
124
125
126template<Graph SourceGraphType, Graph TargetGraphType>
127void contract(const SourceGraphType & source,
128 util::BiPredicate<typename SourceGraphType::node_type> auto const & contractBiPredicate,
129 util::ReduceFunction<std::vector<typename SourceGraphType::node_type>,typename TargetGraphType::node_type> auto const & reduceFunction,
130 util::UnaryFunction<typename SourceGraphType::node_type,typename TargetGraphType::node_type> auto const & mapper,
131 TargetGraphType & output,
132 u_int8_t workers = 1)
133{
134 auto [nodes, edges] = contractImpl(source,contractBiPredicate,reduceFunction,mapper,output,workers);
135 output.addNodes(nodes);
136 output.addEdges(edges);
137}
138
139
140template<Graph SourceGraphType, Graph TargetGraphType>
141void contractInPlace(SourceGraphType & source,
142 util::BiPredicate<typename SourceGraphType::node_type> auto const & contractBiPredicate,
143 util::ReduceFunction<std::vector<typename SourceGraphType::node_type>,typename TargetGraphType::node_type> auto const & reduceFunction,
144 util::UnaryFunction<typename SourceGraphType::node_type,typename TargetGraphType::node_type> auto const & mapper,
145 TargetGraphType & output,
146 u_int8_t workers = 1)
147{
148 auto [nodes, edges] = contractImpl(source,contractBiPredicate,reduceFunction,mapper,output,workers);
149 source.clear();
150 output.addNodes(nodes);
151 output.addEdges(edges);
152}
153
154
155}
156
157namespace fishnet::graph{
158
174template<Graph SourceGraphType, Graph TargetGraphType>
176 util::UnaryFunction<typename SourceGraphType::node_type,typename TargetGraphType::node_type> auto const & mapper, TargetGraphType & output, u_int8_t workers = 1)
177{
178 using R = typename TargetGraphType::node_type;
179 using N = typename SourceGraphType::node_type;
180 auto reduceFunction = [&mapper,&mergeFunction](const std::vector<N> & nodes){
181 R merged = mapper(nodes.front());
182 for(size_t i = 1; i < nodes.size(); i++){
183 merged = mergeFunction(merged,mapper(nodes[i]));
184 }
185 return merged;
186 };
187 __impl::contract(source,contractBiPredicate,reduceFunction,mapper,output,workers);
188}
189
204template<Graph SourceGraphType, Graph TargetGraphType>
205void contract( const SourceGraphType & source, util::BiPredicate<typename SourceGraphType::node_type> auto const & contractBiPredicate,
206 util::ReduceFunction<std::vector<typename SourceGraphType::node_type>,typename TargetGraphType::node_type> auto const & reduceFunction, TargetGraphType & output, u_int8_t workers = 1)
207{
208 using N = SourceGraphType::node_type;
209 auto mapper = [&reduceFunction](const N & node){return reduceFunction(std::vector<N>({node}));};
210 __impl::contract(source,contractBiPredicate,reduceFunction,mapper,output,workers);
211}
212
213
228template<Graph SourceGraphType, Graph TargetGraphType>
229void contractInPlace( SourceGraphType & source, util::BiPredicate<typename SourceGraphType::node_type> auto const & contractBiPredicate,
230 util::ReduceFunction<std::vector<typename SourceGraphType::node_type>,typename TargetGraphType::node_type> auto const & reduceFunction, TargetGraphType & output, u_int8_t workers = 1)
231{
232 using N = SourceGraphType::node_type;
233 auto mapper = [&reduceFunction](const N & node){return reduceFunction(std::vector<N>({node}));};
234 __impl::contractInPlace(source,contractBiPredicate,reduceFunction,mapper,output,workers);
235}
236
250template<Graph SourceGraphType>
251void contractInPlace( SourceGraphType & graph, util::BiPredicate<typename SourceGraphType::node_type> auto const & contractBiPredicate,
252 util::ReduceFunction<std::vector<typename SourceGraphType::node_type>,typename SourceGraphType::node_type> auto const & reduceFunction, u_int8_t workers = 1)
253{
254 using N = SourceGraphType::node_type;
255 auto mapper = [&reduceFunction](const N & node){return reduceFunction(std::vector<N>({node}));};
256 __impl::contractInPlace(graph,contractBiPredicate,reduceFunction,mapper,graph,workers);
257}
258
269template<Graph G> requires std::is_constructible_v<G>
270G contract(const G & source, fishnet::util::BiPredicate<typename G::node_type> auto const& contractBiPredicate, fishnet::util::BiOperator<typename G::node_type> auto const& mergeFunction, u_int8_t workers = 1){
271 G result;
272 contract(source,contractBiPredicate,mergeFunction,util::Identity(),result,workers);
273 return result;
274}
275
286template<Graph G> requires std::is_constructible_v<G>
287G contract(const G & source, fishnet::util::BiPredicate<typename G::node_type> auto const& contractBiPredicate, fishnet::util::ReduceFunction<std::vector<typename G::node_type>> auto const& reduceFunction, u_int8_t workers = 1){
288 G result;
289 contract(source,contractBiPredicate,reduceFunction,result,workers);
290 return result;
291}
292}
Definition Option.hpp:13
Blocking queue implementation. Blocks when no elements are present and take() is called until further...
Definition BlockingQueue.hpp:14
Definition FunctionalConcepts.hpp:15
Definition FunctionalConcepts.hpp:27
Definition FunctionalConcepts.hpp:42
Definition FunctionalConcepts.hpp:66
Definition FunctionalConcepts.hpp:9
auto connectedComponents(const G &graph, fishnet::util::BiPredicate< typename G::node_type > auto const &inRelation)
Compute connected components of the graph.
Definition BFSAlgorithm.hpp:95
Definition AdjacencyContainer.hpp:4
void contractInPlace(SourceGraphType &source, util::BiPredicate< typename SourceGraphType::node_type > auto const &contractBiPredicate, util::ReduceFunction< std::vector< typename SourceGraphType::node_type >, typename TargetGraphType::node_type > auto const &reduceFunction, TargetGraphType &output, u_int8_t workers=1)
Performs edge contraction algorithm. Edges between nodes fulfilling the contractBiPredicate get contr...
Definition Contraction.hpp:229
void contract(const SourceGraphType &source, util::BiPredicate< typename SourceGraphType::node_type > auto const &contractBiPredicate, util::BiFunction< typename SourceGraphType::node_type, typename SourceGraphType::node_type, typename TargetGraphType::node_type > auto const &mergeFunction, util::UnaryFunction< typename SourceGraphType::node_type, typename TargetGraphType::node_type > auto const &mapper, TargetGraphType &output, u_int8_t workers=1)
Performs edge contraction algorithm. Edges between nodes fulfilling the contractBiPredicate get contr...
Definition Contraction.hpp:175
constexpr size_t size(std::ranges::range auto &&range) noexcept
Definition CollectionConcepts.hpp:50
Definition FunctionalConcepts.hpp:95