/* sort the nodes in topological order. */ void topological_sort(SEXP fitted, int *poset, int nnodes) { int i = 0; SEXP roots, node_depth; PROTECT(roots = root_nodes(fitted, FALSESEXP)); PROTECT(node_depth = topological_ordering(fitted, roots, FALSESEXP, FALSESEXP)); for (i = 0; i < nnodes; i++) poset[i] = i; R_qsort_int_I(INTEGER(node_depth), poset, 1, nnodes); UNPROTECT(2); }/*TOPOLOGICAL_SORT*/
void update_sd_tree(sd_node_ref node, sd_tree& tree, bool include_root) { // Build graph of all dependents of 'node' // auto dep_graph = build_dependency_graph(tree, node); std::set< sd_node_ref, sd_node_ref_compare > processed; if(!include_root) { processed.insert(node); } auto defn_deps = build_defn_dependency_graph(tree[tree.get_root()].defn, tree[node.nd].defn); auto dep_order = defn_deps.topological_ordering(); while(true) { // TODO: What about nodes that have a dependency via another node that has been removed, being // cut off from the set of nodes to be updated... // auto defn_deps = build_defn_dependency_graph(tree[tree.get_root()].defn, tree[node.nd].defn); // auto dep_order = defn_deps.topological_ordering(); #if __DEBUG_OUTPUT print_dependency_graph(defn_deps, [](std::string str) { std::cout << str << std::endl; }); #endif auto id_map = construct_dep_id_map(tree, node, defn_deps); auto next = sd_node_ref{}; // Look for first node in the list that is not already processed for(auto const& rf : dep_order) { auto defn = defn_deps[rf].nd; auto id = defn.get_id(); if(id_map.find(id) == id_map.end()) { // No node with this id continue; } auto& matching = id_map.at(id); for(auto const& nref : matching) { if(processed.find(nref) == std::end(processed)) { // Not yet processed, do this one next next = nref; break; } } if(next) { break; } } // TODO: maybe deal here with any null defn nodes? // ie. empty condition contents, should ideally be updated to ensure both schema and data // are set to null. currently since no id, they won't be deal with. // alternative could be to just set schema and data for them when setting the defn to null, // but this is kind of inconsistent with general approach... if(!next) { // No more to process, finished break; } auto& sd_node = tree[next.nd]; // Reinstantiate the schema at this node only sd_node.schema = instantiate_locally(next, tree); // if(sd_node.schema) { // Adjust the data (if necessary) to conform to the reinstantiated schema adjust_to_schema(next, tree); } // Mark this node as done processed.insert(next); } }