/**
 * Represents a set of nodes that can be processed in parallel as defined by
 * their relationship to each other in the graph.
 */
type ParallelCollection<T> = Set<T | SerialCollection<T>>;
/**
 * Represents a list of nodes that must be processed sequentially as defined by
 * their relationship to each other in the graph.
 */
type SerialCollection<T> = (T | Set<T>)[];
/**
 * A Directed Acyclic Graph structure with online cycle detection and topological ordering.
 */
declare class DAG<T> {
    #private;
    /**
     * Creates a new DAG with optional initial nodes.
     *
     * @param initialNodes - An optional iterable of initial nodes to populate the graph with.
     */
    constructor(initialNodes?: Iterable<T>);
    /**
     * Returns a list of all nodes in the graph in a topological order.
     *
     * **Note:** for every `U -> V` directed edge, `U` will appear
     * before `V` in a topological order.
     *
     * @return An array of all graph nodes in a topological order.
     */
    get order(): T[];
    /**
     * Returns the number of nodes in the graph.
     *
     * @return Number of nodes in the graph
     */
    get size(): number;
    /**
     * Iterates over all nodes in the graph in a topological order.
     *
     * @alias keys
     * @return An iterator over all nodes in the graph.
     */
    [Symbol.iterator](): IterableIterator<T>;
    /**
     * Iterates over all nodes in the graph in a topological order.
     *
     * @return An iterator over all nodes in the graph.
     */
    keys(): IterableIterator<T>;
    /**
     * Creates a new, independent copy of this DAG.
     *
     * @return Clone of this DAG.
     */
    copy(): DAG<T>;
    /**
     * Removes all nodes (and their edges) from the graph.
     *
     * @return This DAG.
     */
    clear(): this;
    /**
     * Adds a node to the graph.
     * If the node already exists, this is a no-op.
     *
     * @param node - The node to add.
     * @return This DAG.
     */
    add(node: T): this;
    /**
     * Checks if a specific node exists in the graph.
     *
     * @param node - The node to check.
     * @return `true` if the node exists, `false` otherwise.
     */
    has(node: T): boolean;
    /**
     * Removes a specified node from the graph.
     * If such node doesn't exist, this is a no-op.
     *
     * **Note:** This also removes all edges from or to the specified node.
     *
     * @param node - The node to remove.
     * @return This DAG.
     */
    delete(node: T): this;
    /**
     * Tries to add a directed edge to the graph.
     *
     * If any of the nodes doesn't already exist, it will be added.
     *
     * If inserting the given edge would introduce a cycle no changes
     * are made to the graph and CycleError is thrown.
     *
     * Adding an edge from a node to that same node (i.e. `from` and `to` are
     * the same) is considered a cycle and such edge cannot be added.
     *
     * @param from - The "source" node.
     * @param to - The "target" node.
     * @return This DAG.
     */
    addEdge(from: T, to: T): this;
    /**
     * Tries to add a directed edge to the graph.
     *
     * If any of the nodes doesn't already exist, it will be added.
     *
     * If inserting the given edge would introduce a cycle no changes
     * are made to the graph and `false` is returned.
     *
     * Adding an edge from a node to that same node (i.e. `from` and `to` are
     * the same) is considered a cycle and such edge cannot be added.
     *
     * @param from - The "source" node.
     * @param to - The "target" node.
     * @return `true` if the edge was added, `false` otherwise.
     */
    tryAddEdge(from: T, to: T): boolean;
    /**
     * Checks if a specific (directed) edge exists in the graph.
     *
     * @param from - The "source" node.
     * @param to - The "target" node.
     * @return `true` if the edge exists, `false` otherwise.
     */
    hasEdge(from: T, to: T): boolean;
    /**
     * Removes a specified edge from the graph.
     * If such edge doesn't exist, this is a no-op.
     *
     * **Note:** this removes a directed edge. If an edge A -> B exists,
     * it will not be removed with a removeEdge(B, A) call.
     *
     * @param from - The "source" node.
     * @param to - The "target" node.
     * @return This DAG.
     */
    deleteEdge(from: T, to: T): this;
    /**
     * Removes all outgoing edges from a given node.
     * If such node doesn't exist, this is a no-op.
     *
     * @param node - The node to remove outgoing edges from.
     * @return This DAG.
     */
    deleteOutgoingEdgesOf(node: T): this;
    /**
     * Removes all incoming edges to a given node.
     * If such node doesn't exist, this is a no-op.
     *
     * @param node - The node to remove incoming edges to.
     * @return This DAG.
     */
    deleteIncomingEdgesOf(node: T): this;
    /**
     * Returns the given nodes in a topological order.
     *
     * In a case that a node does not exist in the graph, it is pushed to the end of the array.
     *
     * @param nodes - The nodes to sort.
     * @return An array of the given nodes in a topological order.
     */
    getNodeOrder(...nodes: T[]): T[];
    /**
     * Sorts the given array of nodes, in place by their topological order.
     *
     * In a case that a node does not exist in the graph, it is pushed to the end of the array.
     *
     * @param nodes - The nodes to sort.
     * @return The input array of nodes, sorted in a topological order.
     */
    sortNodes(nodes: T[]): T[];
    /**
     * Returns (an unordered) set of all immediate predecessors of the given nodes.
     *
     * @param nodes - The nodes to get immediate predecessors of.
     * @return An unordered set of all immediate predecessors of the given nodes.
     */
    getImmediatePredecessorsOf(...nodes: T[]): Set<T>;
    /**
     * Returns an iterable of all immediate predecessors of the given nodes which
     * iterates over them in a topological order.
     *
     * @param nodes - The nodes to get immediate predecessors of.
     * @return A topologically ordered iterable of all immediate predecessors of the given nodes.
     */
    getOrderedImmediatePredecessorsOf(...nodes: T[]): Iterable<T>;
    /**
     * Returns (an unordered) set of all predecessors of the given nodes.
     *
     * @param nodes - The nodes to get predecessors of.
     * @return An unordered set of all predecessors of the given nodes.
     */
    getPredecessorsOf(...nodes: T[]): Set<T>;
    /**
     * Returns an iterable of all predecessors of the given nodes which
     * iterates over them in a topological order.
     *
     * @param nodes - The nodes to get predecessors of.
     * @return A topologically ordered iterable of all predecessors of the given nodes.
     */
    getOrderedPredecessorsOf(...nodes: T[]): Iterable<T>;
    /**
     * Returns (an unordered) set of all immediate successors of the given nodes.
     *
     * @param nodes - The nodes to get immediate successors of.
     * @return An unordered set of all immediate successors of the given nodes.
     */
    getImmediateSuccessorsOf(...nodes: T[]): Set<T>;
    /**
     * Returns an iterable of all immediate successors of the given nodes which
     * iterates over them in a topological order.
     *
     * @param nodes - The nodes to get immediate successors of.
     * @return A topologically ordered iterable of all immediate successors of the given nodes.
     */
    getOrderedImmediateSuccessorsOf(...nodes: T[]): Iterable<T>;
    /**
     * Returns (an unordered) set of all successors of the given nodes.
     *
     * @param nodes - The nodes to get successors of.
     * @return An unordered set of all successors of the given nodes.
     */
    getSuccessorsOf(...nodes: T[]): Set<T>;
    /**
     * Returns an iterable of all successors of the given nodes which
     * iterates over them in a topological order.
     *
     * @param nodes - The nodes to get successors of.
     * @return A topologically ordered iterable of all successors of the given nodes.
     */
    getOrderedSuccessorsOf(...nodes: T[]): Iterable<T>;
    /**
     * Checks whether a directed path between two nodes exists in the graph.
     *
     * If A is directly connected to B, `hasPath(A, B)` is exactly the same as `hasEdge(A, B)`.
     * On the other hand, if only the edges `A -> B` and `A -> C` exists in the
     * graph, a `hasPath(A, C)` returns `true`, while `hasEdge(A, C)` returns `false`.
     *
     *
     * @param from - The "source" node.
     * @param to - The "target" node.
     * @return `true` if a directed path exists, `false` otherwise.
     */
    hasPath(from: T, to: T): boolean;
    /**
     * Merges two nodes if such action would not introduce a cycle.
     *
     * "Merging" of A and B is performed by making:
     *   - all immediate predecessors of B be immediate predecessors of A, and
     *   - all immediate successors of B be immediate successors of A.
     *
     * After that remapping, node B gets removed from the graph.
     *
     * **Note:** This method is a no-op if either A or B is absent in the graph.
     *
     * If there is a path between A and B (in either direction), a CycleError
     * gets thrown, and the graph is not changed.
     *
     * @param a - The first node to merge.
     * @param b - The second node to merge.
     * @return This DAG.
     */
    mergeNodes(a: T, b: T): this;
    /**
     * Tries to merge two nodes if such action would not introduce a cycle.
     *
     * "Merging" of A and B is performed by making:
     *   - all immediate predecessors of B be immediate predecessors of A, and
     *   - all immediate successors of B be immediate successors of A.
     *
     * After that remapping, node B gets removed from the graph.
     *
     * **Note:** This method is a no-op if either A or B is absent in the graph.
     *
     * If there is a path between A and B (in either direction), the merging would
     * introduce a cycle so this function returns `false`, and the graph is not changed.
     *
     * @param a - The first node to merge.
     * @param b - The second node to merge.
     * @return True if the nodes were successfully merged, or if
     * at least one of the given nodes is not present in the graph.
     */
    tryMergeNodes(a: T, b: T): boolean;
    /**
     * Returns an array of node arrays, where each inner array represents a subgraph.
     *
     * The nodes in each subgraph are topologically ordered.
     *
     * @return An array of independent subgraphs.
     */
    subGraphs(): T[][];
    /**
     * Returns a set of all subgraphs in the graph.
     *
     * Each subgraph is represented either as a single node, or as an array which
     * is meant to be processed sequentially and its items are either a single node
     * or a Set of nodes that can be processed in parallel.
     *
     * @example
     * ```typescript
     * const dag = new DAG<string>(['Z']);
     * dag.addEdge('A', 'B');
     * dag.addEdge('A', 'C');
     * dag.addEdge('B', 'D');
     * dag.addEdge('C', 'D');
     * dag.addEdge('X', 'Y');
     *
     * console.log(dag.parallelize());
     * // Set(3) { [ 'A', Set(2) { 'B', 'C' }, 'D' ], [ 'X', 'Y' ], 'Z' }
     *```
     *
     * @return A set of all subgraphs in the graph, parallelized.
     */
    parallelize(): ParallelCollection<T>;
}

/**
 * Error thrown when a cycle would be introduced in a DAG.
 */
declare class CycleError extends Error {
    constructor();
}

export { CycleError, DAG, type ParallelCollection, type SerialCollection };
