| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- """
- Dominance algorithms.
- """
- from functools import reduce
- import networkx as nx
- from networkx.utils import not_implemented_for
- __all__ = ["immediate_dominators", "dominance_frontiers"]
- @not_implemented_for("undirected")
- @nx._dispatchable
- def immediate_dominators(G, start):
- """Returns the immediate dominators of all nodes of a directed graph.
- Parameters
- ----------
- G : a DiGraph or MultiDiGraph
- The graph where dominance is to be computed.
- start : node
- The start node of dominance computation.
- Returns
- -------
- idom : dict keyed by nodes
- A dict containing the immediate dominators of each node reachable from
- `start`, except for `start` itself.
- Raises
- ------
- NetworkXNotImplemented
- If `G` is undirected.
- NetworkXError
- If `start` is not in `G`.
- Notes
- -----
- The immediate dominators are the parents of their corresponding nodes in
- the dominator tree. Every node reachable from `start` has an immediate
- dominator, except for `start` itself.
- Examples
- --------
- >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)])
- >>> sorted(nx.immediate_dominators(G, 1).items())
- [(2, 1), (3, 1), (4, 3), (5, 1)]
- References
- ----------
- .. [1] Cooper, Keith D., Harvey, Timothy J. and Kennedy, Ken.
- "A simple, fast dominance algorithm." (2006).
- https://hdl.handle.net/1911/96345
- .. [2] Lengauer, Thomas; Tarjan, Robert Endre (July 1979).
- "A fast algorithm for finding dominators in a flowgraph".
- ACM Transactions on Programming Languages and Systems. 1 (1): 121--141.
- https://dl.acm.org/doi/10.1145/357062.357071
- """
- if start not in G:
- raise nx.NetworkXError("start is not in G")
- idom = {start: None}
- order = list(nx.dfs_postorder_nodes(G, start))
- dfn = {u: i for i, u in enumerate(order)}
- order.pop()
- order.reverse()
- def intersect(u, v):
- while u != v:
- while dfn[u] < dfn[v]:
- u = idom[u]
- while dfn[u] > dfn[v]:
- v = idom[v]
- return u
- changed = True
- while changed:
- changed = False
- for u in order:
- new_idom = reduce(intersect, (v for v in G.pred[u] if v in idom))
- if u not in idom or idom[u] != new_idom:
- idom[u] = new_idom
- changed = True
- del idom[start]
- return idom
- @not_implemented_for("undirected")
- @nx._dispatchable
- def dominance_frontiers(G, start):
- """Returns the dominance frontiers of all nodes of a directed graph.
- Parameters
- ----------
- G : a DiGraph or MultiDiGraph
- The graph where dominance is to be computed.
- start : node
- The start node of dominance computation.
- Returns
- -------
- df : dict keyed by nodes
- A dict containing the dominance frontiers of each node reachable from
- `start` as lists.
- Raises
- ------
- NetworkXNotImplemented
- If `G` is undirected.
- NetworkXError
- If `start` is not in `G`.
- Examples
- --------
- >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)])
- >>> sorted((u, sorted(df)) for u, df in nx.dominance_frontiers(G, 1).items())
- [(1, []), (2, [5]), (3, [5]), (4, [5]), (5, [])]
- References
- ----------
- .. [1] Cooper, Keith D., Harvey, Timothy J. and Kennedy, Ken.
- "A simple, fast dominance algorithm." (2006).
- https://hdl.handle.net/1911/96345
- """
- idom = nx.immediate_dominators(G, start) | {start: None}
- df = {u: set() for u in idom}
- for u in idom:
- if u == start or len(G.pred[u]) >= 2:
- for v in G.pred[u]:
- if v in idom:
- while v != idom[u]:
- df[v].add(u)
- v = idom[v]
- return df
|