Class ConsistentDagIterator
This is the graph-valued companion to the valid-order enumeration. It runs the same Dor-Tarsi sink-peeling DFS (peel a node with no child whose undirected neighbors form a clique, branching over ALL valid sinks), but at each peel it orients every undirected neighbor z--x into the sink as z->x, so a completed peel sequence is a consistent extension.
With distinct (the default) each extension is emitted exactly once. A single
extension is a topological order of many peel sequences; two peel sequences produce the same
DAG iff they differ only by transposing adjacent nodes that are NON-adjacent in the graph
(such a swap flips no edge). The lexicographically-minimal (by rank) sequence of each such
class is characterized by having no adjacent commuting inversion, so we forbid one
incrementally: a sink x is peeled after prev only unless x shares no
edge with prev and outranks it (in which case x could have been peeled before
prev for the same DAG -- a non-canonical duplicate, deferred). This reaches each
distinct DAG exactly once WITHOUT generating the duplicate orders, at O(n) working memory.
With distinct == false the prune is off and every valid order yields a DAG.
Ranks come from initialOrder/forward exactly as in getValidOrder; the
first extension emitted is the one that method's order induces.
Cost note: the prune removes the linear-extension blowup for the common case (e.g. an edgeless or near-edgeless component no longer costs n! -- it costs about the number of rank-increasing prefixes). It is NOT output-polynomial in the worst case, though: a component with many simplicial vertices that are simultaneously valid sinks and pairwise non-adjacent (a large star, say) can still explore up to ~2^k dead-end prefixes to emit k+1 DAGs, because a lower-rank node blocked only transitively (through a shared neighbor) cannot be pruned by the adjacent-pair test. When that bites, enumerate the acyclic moral orientations of the chordal component directly with a clique-tree method (polynomial delay); ask and I'll wire it up.
Assumes a DAG or CPDAG (no bidirected/circle endpoints; the undirected-neighbor clique test is complete only for a completed PDAG). A malformed cyclic input simply yields nothing.
- Author:
- josephramsey
-
Constructor Summary
ConstructorsConstructorDescriptionConsistentDagIterator(Graph graph) Enumerate distinct extensions, preferring the graph's own node order (forward).ConsistentDagIterator(Graph graph, List<Node> initialOrder, boolean forward, boolean distinct) Iterates over DAGs consistent with a given CPDAG. -
Method Summary
Methods inherited from class Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface Iterable
forEach, spliteratorMethods inherited from interface Iterator
forEachRemaining, remove
-
Constructor Details
-
ConsistentDagIterator
Enumerate distinct extensions, preferring the graph's own node order (forward).- Parameters:
graph- a DAG or CPDAG.
-
ConsistentDagIterator
public ConsistentDagIterator(Graph graph, List<Node> initialOrder, boolean forward, boolean distinct) Iterates over DAGs consistent with a given CPDAG.- Parameters:
graph- a DAG or CPDAG.initialOrder- rank source: the first extension emitted is the one induced bygetValidOrder(initialOrder, forward).forward- forward (true) or reverse (false) rank preference.distinct- true to emit each consistent extension exactly once; false to emit one DAG per valid order (i.e. with linear-extension multiplicity).
-
-
Method Details
-
iterator
-
hasNext
-
next
-