14 #include <type_traits>
16 #include <unordered_set>
27 #if defined(__GNUC__) || defined(__clang__)
30 static std::string
demangle (
const char* name)
33 std::unique_ptr<char, void (*)(
void*)> res{abi::__cxa_demangle (name,
nullptr,
nullptr, &status),
35 return status == 0 ? res.get () : name;
38 static std::string
demangle (
const char* name) {
return name; }
62 std::size_t givenSize)
71 "-th dependency is empty (nullptr)");
75 const std::type_info& expectedType,
76 const std::type_info& givenNodeType)
84 std::size_t expectedSize)
86 auto size = deps.size ();
87 if (size != expectedSize)
94 std::size_t expectedMinSize)
96 auto size = deps.size ();
97 if (size < expectedMinSize)
105 for (std::size_t i = 0; i < deps.size (); ++i)
129 n->registerNode (
this);
138 n->registerNode (
this);
147 n->unregisterNode (
this);
155 nodeType = std::regex_replace(nodeType, std::regex(
"bpp::"),
"");
156 nodeType = std::regex_replace(nodeType, std::regex(
"Eigen::"),
"");
157 nodeType = std::regex_replace(nodeType, std::regex(
"std::"),
"");
158 nodeType = std::regex_replace(nodeType, std::regex(
"__cxx..::"),
"");
159 nodeType = std::regex_replace(nodeType, std::regex(
"(char_traits<[^>]*>)"),
"char");
160 nodeType = std::regex_replace(nodeType, std::regex(
"(allocator<[^>]*>)"),
"");
161 nodeType = std::regex_replace(nodeType, std::regex(
"(Matrix<)([^>]*>)"),
"Matrix");
162 nodeType = std::regex_replace(nodeType, std::regex(
"(basic_string<)([^>]*>)"),
"string");
190 std::stack<Node_DF*> nodesToVisit;
191 std::stack<Node_DF*> nodesToRecompute;
192 nodesToVisit.push (
this);
193 while (!nodesToVisit.empty ())
195 auto* n = nodesToVisit.top();
199 nodesToRecompute.push(n);
200 for (
auto& dep : n->dependencies())
203 nodesToVisit.push(dep.get());
207 while (!nodesToRecompute.empty())
209 auto* n = nodesToRecompute.top();
210 nodesToRecompute.pop ();
223 std::stack<Node_DF*> nodesToInvalidate;
224 nodesToInvalidate.push (
this);
225 while (!nodesToInvalidate.empty ())
227 auto* n = nodesToInvalidate.top ();
228 nodesToInvalidate.pop ();
232 for (
auto* dependent : n->dependentNodes_)
234 nodesToInvalidate.push (dependent);
256 std::stack<const Node_DF*> nodesToVisit;
257 nodesToVisit.push (&node);
258 while (!nodesToVisit.empty ())
260 auto* current = nodesToVisit.top ();
262 if (current == &searchedDependency)
264 for (
auto& dep : current->dependencies ())
266 nodesToVisit.push (dep.get ());
273 const std::unordered_map<const Node_DF*, NodeRef>& substitutions)
277 auto it = substitutions.find(node.get());
278 if (it != substitutions.end())
283 else if (node->dependencies().empty())
291 NodeRefVec recreatedDeps(node->nbDependencies ());
292 for (std::size_t i = 0; i < recreatedDeps.size (); ++i)
296 if (recreatedDeps == node->dependencies ())
302 return node->recreate(c, std::move(recreatedDeps));
317 assert (newNode !=
nullptr);
319 auto r =
nodeCache_.emplace(std::move (newNode));
325 assert (newNode !=
nullptr);
354 std::vector<const Node_DF*> ret;
357 ret.push_back(it.ref.get());
368 std::set<NodeRef> sNodes;
369 sNodes.emplace(node);
376 for (
auto n : sNodes)
378 if (n->nbDependentNodes() == 0)
385 for (
auto dep:n->dependencies())
390 dep->unregisterNode (n.get());
414 const auto& lhs = *this->
ref;
415 const auto& rhs = *other.
ref;
416 return typeid (lhs) ==
typeid (rhs) && lhs.dependencies () == rhs.dependencies () &&
417 lhs.compareAdditionalArguments (rhs);
422 const auto& node = *ref.
ref;
423 std::size_t seed =
typeid (node).hash_code ();
424 for (
const auto& dep : node.dependencies ())
428 combineHash (seed, node.hashAdditionalArguments ());
439 using IntType =
typename std::underlying_type<DotOptions>::type;
440 return static_cast<DotOptions>(
static_cast<IntType
>(a) |
static_cast<IntType
>(b));
444 using IntType =
typename std::underlying_type<DotOptions>::type;
445 return static_cast<IntType
>(a) &
static_cast<IntType
>(b);
452 result.reserve (s.size ());
453 static const char toEscape[] =
"<>|{} ";
454 for (
const char c : s)
456 if (std::any_of (std::begin (toEscape), std::end (toEscape),
461 result.push_back (
'\\');
463 result.push_back (c);
487 os <<
",fillcolor=\"" << node.
color() <<
"\"]";
499 os <<
"label=\"" << depIndex <<
"\",";
502 auto fc = from.
color() !=
"white" ? from.
color() :
"black";
511 os <<
"color=\"" << fc <<
"\"";
520 std::stack<const Node_DF*> nodesToVisit;
521 std::unordered_set<const Node_DF*> discoveredNodes;
523 const auto discover = [&nodesToVisit, &discoveredNodes](
const Node_DF* n) {
526 const bool discovered = discoveredNodes.find (n) != discoveredNodes.end ();
529 nodesToVisit.emplace (n);
530 discoveredNodes.emplace (n);
534 for (
const auto* n : entryPoints)
539 while (!nodesToVisit.empty ())
541 const auto* node = nodesToVisit.top ();
548 for (
const auto* dependent : node->dependentNodes ())
550 discover (dependent);
553 for (std::size_t index = 0; index < node->nbDependencies (); ++index)
555 if (node->dependency(index))
558 discover (node->dependency (index).get ());
571 void writeGraphToDot (
const std::string& filename,
const std::vector<const Node_DF*>& nodes,
574 std::ofstream file{filename};
static std::string demangle(const char *name)
r = 0 for each component.
Context for dataflow node construction.
void clear()
Clear the context.
std::unordered_set< CachedNodeRef, CachedNodeRefHash > nodeCache_
NodeRef cached(NodeRef &&newNode)
For a newly created node, return its equivalent from the cache. If not already present in the cache,...
bool erase(const NodeRef &r)
Remove an element from the map, only if it has no dependent nodes, and likewise down the graph.
std::vector< const Node_DF * > getAllNodes() const
Returns the vector of all pointers to all nodes.
Base dataflow Node class.
virtual std::string description() const
Node pretty name (default = type name).
NodeRefVec dependencyNodes_
virtual std::size_t hashAdditionalArguments() const
Return the hash of node-specific configuration.
const NodeRef & dependency(std::size_t i) const noexcept
virtual std::string debugInfo() const
Node debug info (default = ""): user defined detailed info for DF graph debug.
virtual NodeRef derive(Context &c, const Node_DF &node)
Returns a node computing d(this_node_expression)/d(node_expression).
virtual bool hasNumericalProperty(NumericalProperty prop) const
Test if the node has the given numerical property.
virtual NodeRef recreate(Context &c, NodeRefVec &&deps)
Recreate the node with different dependencies.
bool isValid() const noexcept
void registerNode(Node_DF *n)
virtual bool compareAdditionalArguments(const Node_DF &other) const
Compare node-specific configuration to another.
void unregisterNode(const Node_DF *n)
void computeRecursively()
Compute this node value, recomputing dependencies (transitively) as needed.
void invalidateRecursively() noexcept
Invalidate (transitively) dependent nodes from this one.
virtual std::string shape() const
std::vector< Node_DF * > dependentNodes_
virtual std::string color() const
T to(const std::string &s)
Defines the basic types of data flow nodes.
static void writeDotEdge(std::ostream &os, const Node_DF &from, std::size_t depIndex, DotOptions opt)
void checkDependenciesNotNull(const std::type_info &contextNodeType, const NodeRefVec &deps)
Checks that all dependencies are not null, throws if not.
static std::string dotLabelEscape(const std::string &s)
DotOptions operator|(DotOptions a, DotOptions b)
std::string to_string(const NoDimension &)
static std::string dotIdentifier(const Node_DF &node)
void checkNthDependencyNotNull(const std::type_info &contextNodeType, const NodeRefVec &deps, std::size_t index)
static void writeGraphStructure(std::ostream &os, const std::vector< const Node_DF * > &entryPoints, DotOptions opt)
std::vector< NodeRef > NodeRefVec
Alias for a dependency vector (of NodeRef).
std::string prettyTypeName(const std::type_info &ti)
Debug: return a readable name for a C++ type descriptor (from typeid operator).
static void writeDotNode(std::ostream &os, const Node_DF &node, DotOptions opt)
NumericalProperty
Numerical properties for DF Node.
void failureDependencyNumberMismatch(const std::type_info &contextNodeType, std::size_t expectedSize, std::size_t givenSize)
NodeRef recreateWithSubstitution(Context &c, const NodeRef &node, const std::unordered_map< const Node_DF *, NodeRef > &substitutions)
Recreate node by transitively replacing dependencies according to substitutions mapping.
void checkDependencyVectorSize(const std::type_info &contextNodeType, const NodeRefVec &deps, std::size_t expectedSize)
void failureDependencyTypeMismatch(const std::type_info &contextNodeType, std::size_t depIndex, const std::type_info &expectedType, const std::type_info &givenNodeType)
bool isTransitivelyDependentOn(const Node_DF &searchedDependency, const Node_DF &node)
Check if searchedDependency if a transitive dependency of node.
void checkDependencyVectorMinSize(const std::type_info &contextNodeType, const NodeRefVec &deps, std::size_t expectedMinSize)
Checks the minimum size of a dependency vector, throws if mismatch.
void writeGraphToDot(std::ostream &os, const std::vector< const Node_DF * > &nodes, DotOptions opt)
Write dataflow graph starting at nodes to output stream.
void failureNodeConversion(const std::type_info &handleType, const Node_DF &node)
void failureEmptyDependency(const std::type_info &contextNodeType, std::size_t depIndex)
void combineHash(std::size_t &seed, const T &t)
Combine hashable value to a hash, from Boost library.
void failureComputeWasCalled(const std::type_info &nodeType)
std::shared_ptr< Node_DF > NodeRef
bool operator&(DotOptions a, DotOptions b)
std::size_t operator()(const CachedNodeRef &ref) const
NodeRef is hashable and comparable as a pointer. CachedNodeRef is hashable and comparable,...
bool operator==(const CachedNodeRef &other) const
Store a dimension for type T.