| 62 | } |
| 63 | |
| 64 | Status ValidateGraphHasNoCycle(const Graph& graph) { |
| 65 | // A node is ready when all of its inputs have been visited. |
| 66 | std::vector<const Node*> ready; |
| 67 | std::vector<int> pending_count(graph.num_node_ids(), 0); |
| 68 | |
| 69 | for (int i = 0; i < graph.num_node_ids(); ++i) { |
| 70 | const Node* n = graph.FindNodeId(i); |
| 71 | if (n == nullptr) continue; |
| 72 | pending_count[i] = n->in_edges().size(); |
| 73 | if (n->IsMerge()) { |
| 74 | // While-loop cycles are legal cycles so we manually adjust the |
| 75 | // pending_count to make sure that the loop is visited. |
| 76 | for (const Edge* e : n->in_edges()) { |
| 77 | if (!e->IsControlEdge() && e->src()->IsNextIteration()) { |
| 78 | pending_count[i]--; |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | if (pending_count[i] == 0) { |
| 83 | ready.push_back(n); |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | int processed = 0; |
| 88 | while (!ready.empty()) { |
| 89 | const Node* node = ready.back(); |
| 90 | ready.pop_back(); |
| 91 | ++processed; |
| 92 | |
| 93 | for (const Edge* out : node->out_edges()) { |
| 94 | const int output_id = out->dst()->id(); |
| 95 | pending_count[output_id]--; |
| 96 | if (pending_count[output_id] == 0) { |
| 97 | ready.push_back(out->dst()); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | if (processed < graph.num_nodes()) { |
| 103 | std::vector<string> nodes_in_cycle; |
| 104 | for (int i = 0; i < pending_count.size() && nodes_in_cycle.size() < 3; |
| 105 | ++i) { |
| 106 | if (pending_count[i] != 0) { |
| 107 | nodes_in_cycle.push_back(graph.FindNodeId(i)->name()); |
| 108 | } |
| 109 | } |
| 110 | return errors::InvalidArgument( |
| 111 | "Graph is invalid, contains a cycle with ", |
| 112 | graph.num_nodes() - processed, |
| 113 | " nodes, including: ", absl::StrJoin(nodes_in_cycle, ", ")); |
| 114 | } |
| 115 | return Status::OK(); |
| 116 | } |
| 117 | |
| 118 | Status VerifyNoDuplicateNodeNames(const GraphDef& graph) { |
| 119 | absl::flat_hash_set<absl::string_view> nodes; |
no test coverage detected