Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
DirectedAcyclicGraphT.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 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/* DirectedAcyclicGraphT.h (C) 2000-2022 */
9/* */
10/* Implementation of a directed acyclic graph */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_DIRECTEDACYCLICGRAPHT_H_
13#define ARCANE_DIRECTEDACYCLICGRAPHT_H_
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include <iterator>
18
20#include "arcane/utils/GraphBaseT.h"
21#include "arcane/utils/ITraceMng.h"
22#include "arcane/utils/Math.h"
23
24/*---------------------------------------------------------------------------*/
25/*---------------------------------------------------------------------------*/
26
27namespace Arcane
28{
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32/*! Template class for DirectedAcyclicGraph.
33 * VertexType must implement a less comparison operator.
34 *
35 */
36
37template <class VertexType, class EdgeType>
39: public GraphBaseT<VertexType,EdgeType>
40{
41 typedef VertexType& VertexRef;
42 typedef EdgeType& EdgeRef;
43public:
44
45 /** Constructeur de la classe */
47 : GraphBaseT<VertexType,EdgeType>(trace_mng)
48 , m_compute_vertex_levels(true){}
49
50 /** Destructeur de la classe */
52
53public:
54
55 template <class ContainerT>
57 {
58 public:
59 template <class T>
61 {
62 public:
63 ReverseOrderSet(const T& elements) : m_elements(elements){}
64
65 virtual ~ReverseOrderSet() {}
66
67 typedef typename std::reverse_iterator<typename T::iterator> iterator;
68 typedef typename std::reverse_iterator<typename T::const_iterator> const_iterator;
69
70 iterator begin() {return iterator(m_elements.end()); }
71 const_iterator begin() const {return iterator(m_elements.end()); ;}
72
73 iterator end() {return iterator(m_elements.begin());}
74 const_iterator end() const {return iterator(m_elements.begin());}
75
76 Integer size() {return m_elements.size();}
77
78 private:
79 T m_elements;
80
81 };
82 public:
83 SortedElementSet(const ContainerT& elements) : m_elements(elements) {}
84
85 SortedElementSet(ContainerT&& elements) : m_elements(elements) {}
86
87 SortedElementSet() {}
88
89 virtual ~SortedElementSet(){}
90
91 typedef typename ContainerT::iterator iterator;
92 typedef typename ContainerT::const_iterator const_iterator;
93
94 iterator begin() {return m_elements.begin();}
95 const_iterator begin() const {return m_elements.begin();}
96
97 iterator end() {return m_elements.end();}
98 const_iterator end() const {return m_elements.end();}
99
100 Integer size() {return m_elements.size();}
101
102 ReverseOrderSet<ContainerT> reverseOrder() {return ReverseOrderSet<ContainerT>(m_elements);}
103
104 private:
105 ContainerT m_elements;
106 };
107
108 typedef GraphBaseT<VertexType,EdgeType> Base;
109 typedef SortedElementSet<typename Base::EdgeTypeRefArray> SortedEdgeSet;
110 typedef SortedElementSet<typename Base::VertexTypeRefArray> SortedVertexSet;
111 typedef std::map<typename Base::VertexTypeConstRef,Integer> VertexLevelMap;
112 typedef std::map<typename Base::EdgeTypeConstRef,Integer> EdgeLevelMap;
113 typedef std::set<std::pair<VertexType,Integer>, std::function<bool (std::pair<VertexType,Integer>,std::pair<VertexType,Integer>)>> VertexLevelSet;
114
115 void addEdge(const VertexType& source_vertex, const VertexType& target_vertex, const EdgeType& source_to_target_edge)
116 {
117 Base::addEdge(source_vertex,target_vertex,source_to_target_edge);
118 m_compute_vertex_levels = true;
119 }
120
121 void addEdge(VertexType&& source_vertex, VertexType&& target_vertex, EdgeType&& source_to_target_edge)
122 {
123 Base::addEdge(source_vertex,target_vertex,source_to_target_edge);
124 m_compute_vertex_levels = true;
125 }
126
127 SortedVertexSet topologicalSort()
128 {
129 if (m_compute_vertex_levels) _computeVertexLevels();
130 typename Base::VertexTypeRefArray sorted_vertices;
131 for (auto& vertex : this->m_vertices) {sorted_vertices.add(std::ref(vertex));}
132 std::sort(sorted_vertices.begin(),sorted_vertices.end(),[&](const VertexType& a, const VertexType& b){
133 return m_vertex_level_map[a] < m_vertex_level_map[b];});
134 return SortedVertexSet(std::move(sorted_vertices));
135 }
136
137 SortedEdgeSet spanningTree()
138 {
139 if (m_compute_vertex_levels) _computeVertexLevels();
140 typename Base::EdgeTypeRefArray spaning_tree_edges;
141 for (auto& edge : this->m_edges)
142 {
143 Integer level = _computeEdgeLevel(edge);
144 m_edge_level_map[edge] = level;
145 if (level < 0) continue; // edge must not be accounted for in spanning tree
146 spaning_tree_edges.add(std::ref(edge));
147 }
148 std::sort(spaning_tree_edges.begin(),spaning_tree_edges.end(), [&](const EdgeType& a, const EdgeType& b){
149 return m_edge_level_map[a] < m_edge_level_map[b];});
150 return SortedEdgeSet(spaning_tree_edges);
151 }
152
153 void print()
154 {
155 if (m_compute_vertex_levels) _computeVertexLevels();
156 this->m_trace_mng->info() << "--- Directed Graph ---";
157 for (const auto& vertex_entry: this->m_adjacency_list)
158 _printGraphEntry(vertex_entry);
159
160 std::ostringstream oss;
161 this->m_trace_mng->info() << oss.str();
162
163 for (const auto& vertex_level_set_entry : m_vertex_level_map)
164 this->m_trace_mng->info() << "-- Graph has vertex " << vertex_level_set_entry.first << " with level " << vertex_level_set_entry.second;
165 }
166
167 /*! La detection de cycle se fait avec un pattern lazy qui n'est lancé que lors de l'appel à topologicalSort() et print().
168 * Cette méthode permet de savoir si le graphe contient un cycle (ce qui produirait l'échec de topologicalSort())
169 */
170 bool hasCycle()
171 {
172 bool has_cycle = false;
173 try {
174 _computeVertexLevels();
175 } catch (const FatalErrorException& e) {
176 has_cycle = true;
177 }
178 return has_cycle;
179 }
180
181private:
182 std::set<typename Base::VertexTypeConstRef> m_colored_vertices;
183 VertexLevelMap m_vertex_level_map;
184 EdgeLevelMap m_edge_level_map;
185 bool m_compute_vertex_levels;
186
187private:
188
189 void _computeVertexLevels()
190 {
191 // Current algo cannot update vertex level ; need to clear the map.
192 m_vertex_level_map.clear();
193 // compute vertex level
194 for (const auto& vertex_entry : this->m_adjacency_list)
195 _computeVertexLevel(vertex_entry.first,0);
196 m_compute_vertex_levels = false;
197 }
198
199 void _computeVertexLevel(const VertexType& vertex, Integer level)
200 {
201 // Check for cycles
202 if (! m_colored_vertices.insert(std::cref(vertex)).second) throw FatalErrorException("Cycle in graph. Exiting");
203
204 // Try to insert vertex at the given level
205 bool update_children = true;
206 auto vertex_level_set_entry = m_vertex_level_map.insert(std::make_pair(std::cref(vertex),level)); // use emplace when available (gcc >= 4.8.0)
207 if (!vertex_level_set_entry.second) // vertex already present
208 {
209 if (vertex_level_set_entry.first->second < level) vertex_level_set_entry.first->second = level;
210 else update_children = false;
211 }
212 if (update_children)
213 {
214 auto vertex_adjacency_list = Base::m_adjacency_list.find(vertex);
215 if (vertex_adjacency_list != Base::m_adjacency_list.end())
216 {
217 ++level;
218 for (const auto& child_vertex : vertex_adjacency_list->second.first)
219 _computeVertexLevel(child_vertex,level);
220 }
221 }
222 // Remove vertex from cycle detection
223 m_colored_vertices.erase(vertex);
224 }
225
226 Integer _computeEdgeLevel(const EdgeType& edge)
227 {
228 auto edge_vertices_iterator = this->m_edge_to_vertex_map.find(edge);
229 if (edge_vertices_iterator == this->m_edge_to_vertex_map.end()) throw FatalErrorException("Not existing edge.");
230 typename Base::VertexPair edge_vertices = edge_vertices_iterator->second;
231 // edge level is set to source vertex level
232 Integer edge_level = m_vertex_level_map[std::cref(edge_vertices.first)];
233 // if the edge crosses graph levels (ie vertices level difference > 1), we put edge_level =-1, since we don't want to keep it in the spanning tree
234 if (math::abs(edge_level - m_vertex_level_map[std::cref(edge_vertices.second)]) >1) edge_level = -1;
235 return edge_level;
236 }
237
238 void _printGraphEntry(const typename Base::AdjacencyListType::value_type& vertex_entry)
239 {
240 this->m_trace_mng->info() << "-- Vertex " << vertex_entry.first << " depends on ";
241 for (const auto& connected_vertex : vertex_entry.second.first )
242 this->m_trace_mng->info() << " - " << connected_vertex;
243 }
244
245};
246
247/*---------------------------------------------------------------------------*/
248/*---------------------------------------------------------------------------*/
249
250} // End namespace Arcane
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
255#endif /* DIRECTEDACYCLICGRAPHT_H_ */
Fichier de configuration d'Arcane.
DirectedAcyclicGraphT(ITraceMng *trace_mng)
EdgeToVertexMap m_edge_to_vertex_map
target_vertex -> source_vertices
Definition GraphBaseT.h:229
Exception lorsqu'une erreur fatale est survenue.
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 Integer
Type représentant un entier.