31#include "neml2/models/DependencyDefinition.h"
32#include "neml2/misc/string_utils.h"
44template <
typename Node,
typename ItemType>
54 Item(Node *
const node, ItemType item)
56 value(std::move(item))
54 Item(Node *
const node, ItemType item) {
…}
100 const std::vector<Node *> &
resolution()
const {
return _resolution; }
106 const std::map<Item, std::set<Item>> &
item_providers()
const {
return _item_provider_graph; }
112 const std::map<Item, std::set<Item>> &
item_consumers()
const {
return _item_consumer_graph; }
118 const std::map<Node *, std::set<Node *>> &
node_providers()
const {
return _node_provider_graph; }
124 const std::map<Node *, std::set<Node *>> &
node_consumers()
const {
return _node_consumer_graph; }
127 const std::set<Node *> &
end_nodes()
const {
return _end_nodes; }
133 const std::set<Node *> &
start_nodes()
const {
return _start_nodes; }
152 bool _unique_item_provider =
true;
155 bool _unique_item_consumer =
false;
158 std::set<Node *> _nodes;
161 std::set<Item> _consumed_items;
164 std::set<Item> _provided_items;
168 std::map<Item, std::set<Item>> _item_provider_graph;
172 std::map<Item, std::set<Item>> _item_consumer_graph;
176 std::map<Node *, std::set<Node *>> _node_provider_graph;
180 std::map<Node *, std::set<Node *>> _node_consumer_graph;
183 std::set<Node *> _end_nodes;
186 std::set<Node *> _start_nodes;
189 std::set<Item> _out_items;
192 std::set<Item> _in_items;
195 std::vector<Node *> _resolution;
198 std::map<Node *, int> _status;
201 std::map<Node *, size_t> _priority;
204template <
typename Node,
typename ItemType>
208 auto node =
dynamic_cast<Node *
>(def);
209 _nodes.emplace(node);
211 for (
const auto & item : node->consumed_items())
212 _consumed_items.emplace(node, item);
214 for (
const auto & item : node->provided_items())
215 _provided_items.emplace(node, item);
218template <
typename Node,
typename ItemType>
222 _consumed_items.emplace(
nullptr, item);
225template <
typename Node,
typename ItemType>
230 auto node =
dynamic_cast<Node *
>(def);
231 _priority[node] = priority;
234template <
typename Node,
typename ItemType>
236DependencyResolver<Node, ItemType>::build_graph()
239 _item_provider_graph.clear();
240 _item_consumer_graph.clear();
241 _node_provider_graph.clear();
242 _node_consumer_graph.clear();
243 _start_nodes.clear();
249 for (
const auto & itemi : _consumed_items)
251 std::vector<Item> providers;
253 for (
const auto & itemj : _provided_items)
256 if (itemi.value != itemj.value)
260 if (itemi.parent == itemj.parent)
264 if (_priority[itemi.parent] > _priority[itemj.parent])
267 providers.push_back(itemj);
272 if (!providers.empty())
274 if (_unique_item_provider)
275 if (providers.size() != 1)
276 throw NEMLException(
"Multiple providers have been found for item " +
278 _item_provider_graph[itemi].insert(providers[0]);
280 _node_provider_graph[itemi.parent].insert(providers[0].parent);
285 for (
const auto & itemi : _provided_items)
287 std::vector<Item> consumers;
289 for (
const auto & itemj : _consumed_items)
296 if (itemi.value != itemj.value)
300 if (itemi.parent == itemj.parent)
304 if (_priority[itemi.parent] < _priority[itemj.parent])
307 consumers.push_back(itemj);
312 if (!consumers.empty())
314 if (_unique_item_consumer)
315 if (consumers.size() != 1)
316 throw NEMLException(
"Multiple consumers have been found for item " +
318 _item_consumer_graph[itemi].insert(consumers[0]);
319 _node_consumer_graph[itemi.parent].insert(consumers[0].parent);
324 for (
const auto & node : _nodes)
325 if (_node_provider_graph.count(node) == 0)
326 _start_nodes.insert(node);
329 for (
const auto & node : _nodes)
330 if (_node_consumer_graph.count(node) == 0)
331 _end_nodes.insert(node);
334 for (
const auto & item : _consumed_items)
335 if (_item_provider_graph.count(item) == 0)
336 _in_items.insert(item);
339 for (
const auto & item : _provided_items)
340 if (_item_consumer_graph.count(item) == 0)
341 _out_items.insert(item);
344 for (
const auto & item : _consumed_items)
347 if (!_item_provider_graph.count(item))
348 throw NEMLException(
"Unable to find provider of the additional outbound item " +
350 for (
const auto & provider : _item_provider_graph[item])
352 _out_items.insert(provider);
353 _end_nodes.insert(provider.parent);
358template <
typename Node,
typename ItemType>
366 for (
const auto & node : _end_nodes)
371 for (
const auto & node : _nodes)
373 auto count = std::count(_resolution.begin(), _resolution.end(), node);
376 "Each node must appear in the dependency resolution. Node " + node->name() +
377 " is missing. This is an internal error -- consider filing a bug report.");
380 "Each node must appear in the dependency resolution once and only once. Node " +
381 node->name() +
" appeared " + std::to_string(count) +
382 " times. This indicates cyclic dependency.");
386template <
typename Node,
typename ItemType>
395 if (_node_provider_graph.count(node))
396 for (
const auto & dep : _node_provider_graph[node])
400 if (_status[dep] == 1)
402 "While resolving dependency, two nodes '" + node->name() +
"' and '" + dep->name() +
403 "' have (possibly indirect) cyclic dependency. The cyclic dependency can be "
404 "resolved by explicitly setting the node priorities.");
412 _resolution.push_back(node);
Definition DependencyDefinition.h:40
const std::map< Node *, std::set< Node * > > & node_consumers() const
Definition DependencyResolver.h:124
const std::map< Node *, std::set< Node * > > & node_providers() const
Definition DependencyResolver.h:118
const std::set< Item > & inbound_items() const
The items consumed by the overall dependency graph, i.e., the items that are not provided by any node...
Definition DependencyResolver.h:136
const std::map< Item, std::set< Item > > & item_consumers() const
Definition DependencyResolver.h:112
DependencyResolver()=default
void add_additional_outbound_item(const ItemType &item)
Add an additional outbound item that the dependency graph provides
Definition DependencyResolver.h:220
void set_priority(DependencyDefinition< ItemType > *, size_t)
Set a node's priority, useful for resolving cyclic dependency.
Definition DependencyResolver.h:227
bool & unique_item_provider()
Definition DependencyResolver.h:139
void resolve()
Resolve nodal dependency and find an evaluation order.
Definition DependencyResolver.h:360
const std::set< Node * > & end_nodes() const
End nodes which are not consumed by anyone else.
Definition DependencyResolver.h:127
const std::vector< Node * > & resolution() const
The resolved (nodal) evaluation order following which all consumed items of the current node.
Definition DependencyResolver.h:100
const std::set< Item > & outbound_items() const
The items provided by the overall dependency graph, i.e., the items that are not consumed by any node...
Definition DependencyResolver.h:130
void add_node(DependencyDefinition< ItemType > *)
Add a node (defining consumed/provided items) in the dependency graph.
Definition DependencyResolver.h:206
const std::set< Node * > & start_nodes() const
Start nodes which do not consume anyone else.
Definition DependencyResolver.h:133
const std::map< Item, std::set< Item > > & item_providers() const
Definition DependencyResolver.h:106
bool & unique_item_consumer()
Definition DependencyResolver.h:142
std::string stringify(const T &t)
Definition string_utils.h:73
Definition DiagnosticsInterface.cxx:30
Node *const parent
Node which defines this item.
Definition DependencyResolver.h:61
bool operator<(const Item &other) const
An arbitrary comparator so that items can be sorted (for consistency)
Definition DependencyResolver.h:79
bool operator==(const Item &other) const
Test for equality between two items.
Definition DependencyResolver.h:67
bool operator!=(const Item &other) const
Test for inequality between two items.
Definition DependencyResolver.h:73
const ItemType value
The consumed/provided item.
Definition DependencyResolver.h:64
Item(Node *const node, ItemType item)
Definition DependencyResolver.h:54