Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
GraphBaseT.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* GraphBaseT.h (C) 2000-2024 */
9/* */
10/* Common base of graph implementation */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_GRAPHBASET_H_
13#define ARCANE_GRAPHBASET_H_
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include <map>
18#include <set>
19#include <list>
20#include <functional>
21#include <algorithm>
22#include <utility>
23#include <vector>
24#include <numeric>
25
27#include "arcane/utils/SharedArray.h"
28#include "arcane/utils/FatalErrorException.h"
29#include "arcane/utils/ITraceMng.h"
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
44
45// TODO EdgeType = void (default)
46// TODO add a template argument Comparator = std::less
47template <class VertexType, class EdgeType>
49{
50 protected:
51
54 : m_trace_mng(trace_mng)
55 {}
56
58 virtual ~GraphBaseT() {}
59
60 public:
61
62 template <class ContainerT>
63 class IterableEnsembleT
64 {
65 public:
66
67 IterableEnsembleT(ContainerT& elements)
68 : m_empty_container(nullptr)
69 , m_elements(elements)
70 {}
71
72 IterableEnsembleT()
73 : m_empty_container(new ContainerT())
74 , m_elements(*m_empty_container)
75 {}
76
77 virtual ~IterableEnsembleT()
78 {
79 if (m_empty_container)
80 delete m_empty_container;
81 }
82
83 typedef typename ContainerT::iterator iterator;
84 typedef typename ContainerT::const_iterator const_iterator;
85
86 iterator begin() { return m_elements.begin(); }
87 const_iterator begin() const { return m_elements.begin(); }
88
89 iterator end() { return m_elements.end(); }
90 const_iterator end() const { return m_elements.end(); }
91
92 Integer size() { return m_elements.size(); }
93
94 Integer size() const { return m_elements.size(); }
95
96 private:
97
98 ContainerT* m_empty_container;
99 ContainerT& m_elements;
100 };
101
102 public:
103
104 typedef std::reference_wrapper<VertexType> VertexTypeRef;
105 typedef std::reference_wrapper<const VertexType> VertexTypeConstRef;
106 typedef std::reference_wrapper<EdgeType> EdgeTypeRef;
107 typedef std::reference_wrapper<const EdgeType> EdgeTypeConstRef;
108 typedef std::list<VertexType> VertexList;
109 typedef std::list<EdgeType> EdgeList;
110 typedef SharedArray<VertexTypeRef> VertexTypeRefArray;
111 typedef SharedArray<VertexTypeConstRef> VertexTypeConstRefArray;
112 typedef SharedArray<EdgeTypeRef> EdgeTypeRefArray;
113 typedef SharedArray<EdgeTypeConstRef> EdgeTypeConstRefArray;
114 typedef std::map<VertexTypeConstRef, std::pair<VertexTypeRefArray, EdgeTypeRefArray>> AdjacencyListType;
115 typedef std::pair<VertexTypeRef, VertexTypeRef> VertexPair;
116 typedef std::map<EdgeTypeConstRef, VertexPair> EdgeToVertexMap;
117
118 typedef IterableEnsembleT<VertexList> VertexSet;
119 typedef IterableEnsembleT<EdgeList> EdgeSet;
120 typedef IterableEnsembleT<EdgeTypeRefArray> ConnectedEdgeSet;
121
122 private:
123
124 bool isNull(EdgeType const& edge)
125 {
126 if (std::is_pointer_v<EdgeType> && edge == nullptr)
127 return true;
128 else
129 return false;
130 }
131
132 public:
133
134 typedef VertexType VertexRef;
135 typedef EdgeType EdgeRef;
136
137 // TODO Array of reference_wrapper does not work ... because it does T()... see std::vector...
138
140 void addEdge(const VertexType& source_vertex, const VertexType& target_vertex, const EdgeType& source_to_target_edge)
141 {
142 _addEdge(source_vertex, target_vertex, source_to_target_edge);
143 }
144
145 void addEdge(VertexType&& source_vertex, VertexType&& target_vertex, EdgeType&& source_to_target_edge)
146 {
147 _addEdge(source_vertex, target_vertex, source_to_target_edge);
148 }
149
150 template <class Vertex, class Edge>
151 void _addEdge(Vertex source_vertex, Vertex target_vertex, Edge source_to_target_edge)
152 {
153 bool has_edge = (_getEdgeIndex(source_vertex, target_vertex).first != -1 ||
154 m_edge_to_vertex_map.find(source_to_target_edge) != m_edge_to_vertex_map.end() && !isNull(source_to_target_edge));
155 if (has_edge)
156 throw FatalErrorException("Cannot insert existing edge."); // TODO print edge and vertices values if possible (enable_if)
157 m_edges.push_back(source_to_target_edge);
158 EdgeType& inserted_edge = m_edges.back(); // Get a reference to the inserted objects (since objects are only stored in list, other structures handle references)
159 VertexType& inserted_source_vertex = _addVertex(source_vertex);
160 VertexType& inserted_target_vertex = _addVertex(target_vertex);
161 // Fill adjacency map [source_vertex] = pair<TargetVertexArray,EdgeArray>
162 auto adjacency_entry = m_adjacency_list[inserted_source_vertex];
163 adjacency_entry.first.push_back(inserted_target_vertex);
164 adjacency_entry.second.push_back(inserted_edge);
165 // Fill transposed adjacency map [target_vertex] = pair<SourceVertexArray,EdgeArray>
166 auto transposed_adjacency_entry = m_adjacency_list_transposed[inserted_target_vertex];
167 transposed_adjacency_entry.first.push_back(inserted_source_vertex);
168 transposed_adjacency_entry.second.push_back(inserted_edge);
169 // Fill edge map [edge] = pair <Vertex,Vertex>
170 m_edge_to_vertex_map.insert(std::make_pair(std::ref(inserted_edge), std::make_pair(std::ref(inserted_source_vertex), std::ref(inserted_target_vertex))));
171 // It's ugly but we cannot use [] on the map with reference_wrapper (not default constructible) nor use emplace (not supported in gcc 4.7.2
172 // m_edge_to_vertex_map.emplace(std::cref(inserted_edge),std::make_pair(inserted_source_vertex,inserted_target_vertex)); // No Gcc 4,7,2
173 }
174
176 EdgeType* getEdge(const VertexType& source_vertex, const VertexType& target_vertex)
177 {
178 return _getEdge(source_vertex, target_vertex);
179 }
180
182 const EdgeType* getEdge(const VertexType& source_vertex, const VertexType& target_vertex) const
183 {
184 return _getEdge(source_vertex, target_vertex);
185 }
186
187 EdgeType* _getEdge(const VertexType& source_vertex, const VertexType& target_vertex)
188 {
189 Integer edge_index;
190 EdgeTypeRefArray edge_array;
191 std::tie(edge_index, edge_array) = _getEdgeIndex(source_vertex, target_vertex);
192 if (edge_index == -1)
193 return nullptr;
194 else
195 return &edge_array[edge_index].get();
196 }
197
198 // Implement in_edges(vertex) and out_edges(vertex) with an iterator... then edges() and vertices()
199
200 VertexType* getSourceVertex(const EdgeType& edge)
201 {
202 typename EdgeToVertexMap::iterator edge_entry = m_edge_to_vertex_map.find(edge);
203 if (edge_entry != m_edge_to_vertex_map.end())
204 return &(edge_entry->second.first.get());
205 else
206 return nullptr;
207 }
208
209 const VertexType* getSourceVertex(const EdgeType& edge) const
210 {
211 auto edge_entry = m_edge_to_vertex_map.find(edge);
212 if (edge_entry != m_edge_to_vertex_map.end())
213 return &edge_entry->second.first.get();
214 else
215 return nullptr;
216 }
217
218 VertexType* getTargetVertex(const EdgeType& edge)
219 {
220 auto edge_entry = m_edge_to_vertex_map.find(edge);
221 if (edge_entry != m_edge_to_vertex_map.end())
222 return &edge_entry->second.second.get();
223 else
224 return nullptr;
225 }
226
227 const VertexType* getTargetVertex(const EdgeType& edge) const
228 {
229 auto edge_entry = m_edge_to_vertex_map.find(edge);
230 if (edge_entry != m_edge_to_vertex_map.end())
231 return &edge_entry->second.second.get();
232 else
233 return nullptr;
234 }
235
236 VertexSet vertices() { return VertexSet(m_vertices); }
237 EdgeSet edges() { return EdgeSet(m_edges); }
238
239 ConnectedEdgeSet inEdges(const VertexType& vertex)
240 {
241 auto found_vertex = m_adjacency_list_transposed.find(vertex);
242 if (found_vertex == m_adjacency_list_transposed.end()) {
243 return ConnectedEdgeSet();
244 }
245 else
246 return ConnectedEdgeSet(found_vertex->second.second); // map <vertex, pair <VertexArray, EdgeArray> >
247 }
248
249 ConnectedEdgeSet outEdges(const VertexType& vertex)
250 {
251 auto found_vertex = m_adjacency_list.find(vertex);
252 if (found_vertex == m_adjacency_list.end()) {
253 return ConnectedEdgeSet();
254 }
255 else
256 return ConnectedEdgeSet(found_vertex->second.second); // map <vertex, pair <VertexArray, EdgeArray> >
257 }
258
259 protected:
260
261 ITraceMng* m_trace_mng;
262 VertexList m_vertices;
263 EdgeList m_edges;
264 AdjacencyListType m_adjacency_list;
265 AdjacencyListType m_adjacency_list_transposed;
266 EdgeToVertexMap m_edge_to_vertex_map;
267
268 private:
269
270 template <class Vertex>
271 VertexType& _addVertex(Vertex vertex) // to handle _add(VertexType&) and _add(VertexType&&)
272 {
273 // Look up if vertex does exist
274 auto found_vertex = std::find_if(m_vertices.begin(), m_vertices.end(), [&vertex](const VertexType& u) { return (!(u < vertex) && !(vertex < u)); }); // Unary predicate used to avoid contraining VertexObject to be Equality Comparable objects
275 if (found_vertex == m_vertices.end()) // Vertex does not exist
276 {
277 m_vertices.push_back(vertex);
278 return m_vertices.back();
279 }
280 else
281 return *found_vertex;
282 }
283
284 template <class Vertex> // to handle Vertex&& and Vertex& = another way to do so ?
285 std::pair<Integer, EdgeTypeRefArray> _getEdgeIndex(Vertex source_vertex, Vertex target_vertex)
286 {
287 typename AdjacencyListType::iterator found_source_vertex = m_adjacency_list.find(source_vertex);
288 if (found_source_vertex == m_adjacency_list.end())
289 return std::make_pair(-1, EdgeTypeRefArray());
290 Integer target_vertex_index = _getTargetVertexIndex(found_source_vertex, target_vertex);
291 return std::make_pair(target_vertex_index, found_source_vertex->second.second); // pair < u, pair <[u], [u_v] > >...Use get<T> with pair when available to improve readability
292 }
293
294 template <class Vertex> // it's contagious...
295 Integer _getTargetVertexIndex(typename AdjacencyListType::iterator source_vertex_map_entry, Vertex target_vertex)
296 {
297 if (source_vertex_map_entry == m_adjacency_list.end())
298 return -1;
299 return _getConnectedVertexIndex(source_vertex_map_entry, target_vertex);
300 }
301
302 template <class Vertex> // it's contagious...
303 Integer _getConnectedVertexIndex(typename AdjacencyListType::iterator vertex_map_entry, Vertex connected_vertex)
304 {
305 VertexTypeRefArray& vertex_array = vertex_map_entry->second.first;
306 Int32UniqueArray indexes(vertex_array.size());
307 std::iota(indexes.begin(), indexes.end(), 0);
308 auto connected_vertex_index = std::find_if(indexes.begin(), indexes.end(),
309 [&](const Integer index) { return (!(vertex_array[index] < connected_vertex) && !(connected_vertex < vertex_array[index])); });
310 if (connected_vertex_index == indexes.end())
311 return -1;
312 else
313 return *connected_vertex_index;
314 }
315};
316
317/*---------------------------------------------------------------------------*/
318/*---------------------------------------------------------------------------*/
319
320} // namespace Arcane
321
322/*---------------------------------------------------------------------------*/
323/*---------------------------------------------------------------------------*/
324
325#endif
Arcane configuration file.
void addEdge(const VertexType &source_vertex, const VertexType &target_vertex, const EdgeType &source_to_target_edge)
Multiple edges (consisting of the same source and target nodes) are not allowed (throws FatalErrorExc...
Definition GraphBaseT.h:140
virtual ~GraphBaseT()
Definition GraphBaseT.h:58
AdjacencyListType m_adjacency_list_transposed
source_vertex -> target_vertices
Definition GraphBaseT.h:265
GraphBaseT(ITraceMng *trace_mng)
Definition GraphBaseT.h:53
EdgeToVertexMap m_edge_to_vertex_map
target_vertex -> source_vertices
Definition GraphBaseT.h:266
EdgeType * getEdge(const VertexType &source_vertex, const VertexType &target_vertex)
Returns a pointer to the EdgeType instance stored in the graph or nullptr if not found.
Definition GraphBaseT.h:176
const EdgeType * getEdge(const VertexType &source_vertex, const VertexType &target_vertex) const
Returns a pointer to the EdgeType instance stored in the graph or nullptr if not found.
Definition GraphBaseT.h:182
1D vector of data with reference semantics.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
UniqueArray< Int32 > Int32UniqueArray
Dynamic 1D array of 32-bit integers.
Definition UtilsTypes.h:341