16 #include "libmesh/utility.h" 17 #include "libmesh/simple_range.h" 28 template <
class T,
class Compare>
34 template <
class T,
class Compare = std::less<T>>
49 void addEdge(
const T & a,
const T & b);
91 const std::vector<T> &
dfs();
119 [[nodiscard]]
bool dependsOn(
const T & key,
const T & value);
124 [[nodiscard]]
bool dependsOn(
const std::vector<T> & keys,
const T & value);
154 std::map<T, std::list<T>, Compare>
_adj;
179 template <
class T,
class Compare>
184 bool new_adj_insertion =
false, new_inv_insertion =
false;
186 if (_adj.find(a) == _adj.end())
189 new_adj_insertion =
true;
192 _insertion_order.push_back(a);
195 if (_inv_adj.find(a) == _inv_adj.end())
198 new_inv_insertion =
true;
202 mooseAssert(new_adj_insertion == new_inv_insertion,
203 "We should have symmetric behavior between adjacent and inverse-adjacent " 204 "insertion/non-insertion.");
207 template <
class T,
class Compare>
214 _adj[a].push_back(b);
215 _inv_adj[b].push_back(a);
218 template <
class T,
class Compare>
222 auto remove_item = [](
auto & list,
const auto & item)
224 auto it = std::find(list.begin(), list.end(), item);
225 mooseAssert(it != list.end(),
"We should have this item");
228 remove_item(_adj[a], b);
229 remove_item(_inv_adj[b], a);
232 template <
class T,
class Compare>
236 const auto & inv_adjs = _inv_adj[a];
237 for (
const auto & inv_adj : inv_adjs)
239 auto & adj = _adj[inv_adj];
240 auto it = std::find(adj.begin(), adj.end(), a);
241 mooseAssert(it != adj.end(),
"Should have reciprocity");
248 template <
class T,
class Compare>
254 _insertion_order.clear();
257 template <
class T,
class Compare>
258 const std::vector<T> &
261 _sorted_vector.clear();
265 _circular_node = T{};
267 for (
auto & n : _adj)
269 _visited[n.first] =
false;
270 _rec_stack[n.first] =
false;
273 bool is_cyclic =
false;
276 bool roots_found = _adj.empty();
277 for (
auto & n : _insertion_order)
278 if (_adj[n].size() == 0)
281 is_cyclic = dfsFromNode(n);
292 if (!is_cyclic && _num_visited != _insertion_order.size())
294 for (
const auto & [n, visited] : _visited)
295 if (!visited && (is_cyclic = dfsFromNode(n)))
298 mooseAssert(is_cyclic,
"Should have found a cyclic dependency");
306 for (
auto & n : _insertion_order)
314 mooseAssert(_sorted_vector.size() == _insertion_order.size(),
"Unexpected sorted size");
315 mooseAssert(_num_visited == _insertion_order.size(),
"Did not visit all nodes");
317 return _sorted_vector;
320 template <
class T,
class Compare>
321 const std::vector<std::vector<T>> &
324 _ordered_items.clear();
326 const auto & flat_sorted = dfs();
328 std::vector<T> current_group;
329 for (
const auto &
object : flat_sorted)
331 if (current_group.empty())
333 current_group.push_back(
object);
337 const auto & prev_adj_list = _adj[current_group.back()];
338 const bool depends_on_prev =
339 std::find(prev_adj_list.begin(), prev_adj_list.end(), object) != prev_adj_list.end();
343 _ordered_items.push_back({
object});
344 auto & finalized_group = _ordered_items.back();
347 finalized_group.swap(current_group);
350 current_group.push_back(
object);
353 if (!current_group.empty())
354 _ordered_items.push_back(std::move(current_group));
356 return _ordered_items;
359 template <
class T,
class Compare>
363 if (_adj.find(
value) == _adj.end())
366 for (
auto & n : _adj)
367 _visited[n.first] =
false;
369 return dependsOnFromNode(key,
value);
372 template <
class T,
class Compare>
376 if (_adj.find(
value) == _adj.end())
379 for (
auto & n : _adj)
380 _visited[n.first] =
false;
382 for (
const auto & key : keys)
383 if (dependsOnFromNode(key,
value))
389 template <
class T,
class Compare>
393 std::vector<T> ret_vec;
396 ret_vec.swap(_sorted_vector);
398 for (
auto & n : _adj)
399 _visited[n.first] =
false;
403 ret_vec.swap(_sorted_vector);
404 mooseAssert(ret_vec.back() == key,
"Our key should be the back of the vector");
406 return {ret_vec.begin(), ret_vec.end()};
409 template <
class T,
class Compare>
416 _visited[root] =
true;
418 auto & my_dependencies = _inv_adj[root];
420 for (
auto & i : my_dependencies)
421 if (!_visited.at(i) && dependsOnFromNode(i, item))
427 template <
class T,
class Compare>
432 auto & visited = libmesh_map_find(_visited, root);
438 _rec_stack[root] =
true;
440 for (
auto & i : _inv_adj[root])
442 if (!_visited.at(i) && dfsFromNode(i))
447 else if (_rec_stack.at(i))
450 _sorted_vector.push_back(i);
456 _sorted_vector.push_back(root);
457 _rec_stack[root] =
false;
461 template <
class T,
class Compare = std::less<T>>
467 : runtime_error(error)
469 const auto & sorted = graph._sorted_vector;
470 auto first_occurence = std::find(sorted.begin(), sorted.end(), graph._circular_node);
471 if (first_occurence == sorted.end())
472 mooseError(
"We must have at least one occurence of the circular node");
473 auto second_occurence = std::find(first_occurence + 1, sorted.end(), graph._circular_node);
474 if (second_occurence == sorted.end())
475 mooseError(
"We must have two occurences of the circular node");
476 _cyclic_graph = std::vector<T>(first_occurence, second_occurence + 1);
std::map< T, bool, Compare > _rec_stack
recursive stack
void clear()
Clear Items from the resolver.
std::vector< T > _cyclic_graph
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
std::size_t size() const
Returns the number of unique items stored in the dependency resolver.
const std::vector< T > & getSortedValues()
This function also returns dependency resolved values but with a simpler single vector interface...
void deleteDependency(const T &key, const T &value)
Delete a dependency (only the edge) between items in the resolver.
bool dependsOnFromNode(const T &root, const T &item)
depth first search from a root node, searching for a specific item
bool dfsFromNode(const T &root)
Perform a depth-first-search from the specified root node.
bool dependsOn(const T &key, const T &value)
Return true if key depends on value.
std::vector< std::vector< T > > _ordered_items
The sorted vector of sets.
~DependencyResolver()=default
std::list< T > getAncestors(const T &key)
Returns a list of all values that a given key depends on.
void removeEdgesInvolving(const T &a)
Remove edges drawn from 'a'.
const std::vector< std::vector< T > > & getSortedValuesSets()
Returns a vector of sets that represent dependency resolved values.
void addEdge(const T &a, const T &b)
Add an edge between nodes 'a' and 'b'.
std::vector< T > _insertion_order
Container for keeping track of the insertion order.
void addItem(const T &value)
Add an independent item to the set.
T _circular_node
Data member for storing nodes that appear circularly in the graph.
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
std::map< T, std::list< T >, Compare > _inv_adj
adjacency lists (from roots to leaves)
void deleteDependenciesOfKey(const T &key)
Removes dependencies of the given key.
std::size_t _num_visited
number of visited nodes; used to avoid iterating through _visited
std::map< T, std::list< T >, Compare > _adj
adjacency lists (from leaves to roots)
std::vector< T > _sorted_vector
"sorted" vector of nodes
void addNode(const T &a)
Add a node 'a' to the graph.
const std::vector< T > & getCyclicDependencies() const
std::map< T, bool, Compare > _visited
vector of visited nodes
const std::vector< T > & dfs()
Do depth-first search from root nodes to obtain order in which graph nodes should be "executed"...
void removeEdge(const T &a, const T &b)
Remove an edge between nodes 'a' and 'b'.
Class that represents the dependecy as a graph.
void insertDependency(const T &key, const T &value)
Insert a dependency pair - the first value or the "key" depends on the second value or the "value"...
CyclicDependencyException(const std::string &error, const DependencyResolver< T, Compare > &graph)
DependencyResolver()=default
CyclicDependencyException(const CyclicDependencyException &e)
~CyclicDependencyException()