/**
 * A {@link Sugiyama} for computing a layered layout of a dag
 *
 * @packageDocumentation
 */
import type { Graph } from "../graph";
import { type LayoutResult, type NodeSize } from "../layout";
import type { Tweak } from "../tweaks";
import { type U } from "../utils";
import type { Coord } from "./coord";
import { type DefaultCoordSimplex } from "./coord/simplex";
import type { Decross } from "./decross";
import { type DefaultDecrossTwoLayer } from "./decross/two-layer";
import { type Layering } from "./layering";
import { type DefaultLayeringSimplex } from "./layering/simplex";
/** sugiyama operators */
export interface SugiyamaOps<in N = never, in L = never> {
    /** layering operator */
    layering: Layering<N, L>;
    /** decross operator */
    decross: Decross<N, L>;
    /** coord operator */
    coord: Coord<N, L>;
    /** node size operator */
    nodeSize: NodeSize<N, L>;
    /** tweaks */
    tweaks: readonly Tweak<N, L>[];
}
/**
 * the operator used to layout a {@link Graph} using the sugiyama layered method
 *
 * The algorithm is roughly comprised of three steps:
 * 1. {@link Layering} - in this step, every node is assigned a non-negative
 *    integer later such that children are guaranteed to have higher layers
 *    than their parents. (modified with {@link layering})
 * 2. {@link Decross} - in the step, nodes in each layer are reordered to
 *     minimize the number of crossings. (modified with {@link decross})
 * 3. {@link Coord} - in the step, the nodes are assigned x and y coordinates
 *    that respect their layer, layer ordering, and size. (modified with
 *    {@link coord} and {@link nodeSize})
 *
 * The algorithm is based off ideas presented in K. Sugiyama et al. [1979], but
 * described by {@link http://www.it.usyd.edu.au/~shhong/fab.pdf | S. Hong}.
 * The sugiyama layout can be configured with different algorithms for each
 * stage of the layout. For each stage there should be adecuate choices for
 * methods that balance speed and quality for your desired layout. In the
 * absence of those, any function that meets the interface for that stage is
 * valid.
 *
 * Create with {@link sugiyama}.
 *
 * @remarks
 *
 * If one wants even more control over the algorithm, each step is broken down
 * in the source code and can be achieved by calling an exported utility
 * function. If one wants to call certain pieces incrementally, or adjust how
 * things are called, it's recommended to look at the source and call each
 * component function successively.
 */
export interface Sugiyama<Ops extends SugiyamaOps = SugiyamaOps> {
    /**
     * layout the graph using the sugiyama layout
     *
     * @param graph - the graph to layout
     * @returns dimension - the width and height of resulting layout
     */
    (graph: Ops extends SugiyamaOps<infer N, infer L> ? Graph<N, L> : never): LayoutResult;
    /**
     * set the {@link Layering} operator
     *
     * The layering operator takes the graph, and assigns each node layer that
     * respects
     *
     * There are three built-in layering operators:
     * - {@link layeringSimplex} - This minimizes the overall length of edges,
     *   and is reasonably fast for most graphs. Minimizing edges also tends to
     *   make the next steps faster.
     * - {@link layeringLongestPath} - This minimizes the height of the overall
     *   graph.
     * - {@link layeringTopological} - This creates a topological ordering, which
     *   inherently minimizes the width of the graph, but will only produce good
     *   layouts with other topological operators.
     *
     * You can also supply any function that satisfies the {@link Layering}
     * interface. See that documentation for more information about implementing
     * your own layering operator.
     *
     * (default: {@link layeringSimplex})
     *
     * @example
     *
     * ```ts
     * const layout = sugiyama().layering(layeringLongestPath());
     * ```
     */
    layering<NewLayering extends Layering>(layer: NewLayering): Sugiyama<U<Ops, "layering", NewLayering>>;
    /**
     * get the current {@link Layering}.
     */
    layering(): Ops["layering"];
    /**
     * set the {@link Decross} operator
     *
     * The decross operator takes a layered graph with extra nodes for long
     * paths, and reorders nodes along a layer to minimize the number of edge
     * crossings (or other desired properties).
     *
     * There are three built-in decrossing operators:
     * - {@link decrossOpt} - This optimally minimizes edge crossings, but due to
     *   the complex nature of the task, only works for reasonably small graphs.
     * - {@link decrossTwoLayer} - This is a heuristic method for decrossing
     *   minimization that tries to strike a balance between a small number of
     *   edge crossings, and reasonable running time.
     * - {@link decrossDfs} - This is a very cheap decrossing operator that
     *   orders nodes via a depth first search. It's mostly used for
     *   {@link DecrossTwoLayer#inits} of the two-layer operator.
     *
     * You can also supply any function that satisfies the {@link Decross}
     * interface. See that documentation for more information about implementing
     * your own decrossing operator.
     *
     * (default: {@link decrossTwoLayer})
     *
     * @example
     *
     * ```ts
     * const layout = sugiyama().decross(decrossOpt());
     * ```
     */
    decross<NewDecross extends Decross>(dec: NewDecross): Sugiyama<U<Ops, "decross", NewDecross>>;
    /**
     * get the current {@link Decross}.
     */
    decross(): Ops["decross"];
    /**
     * set the {@link Coord} operator
     *
     * The final stage is coordinate assignment, which takes a layered graph with
     * nodes in the correct order, and assigns them x coordinates.
     *
     * There are four built-in coordinate assignment operators:
     * - {@link coordSimplex} - This assigns x coordinates based on a simplex
     *   minimization that tries to produce long vertical edges. It usually
     *   produces attractive layouts in a reasonable amount of time.
     * - {@link coordQuad} - This uses a quadratic optimization that tries to
     *   minimize the curvature of lines, but usually produces worse layouts
     *   than the simplex variant.
     * - {@link coordGreedy} - If either of the above methods take too long, this
     *   uses a heuristic to assign x coordinates meaning it will run more
     *   quickly, but usually produce slightly worse layouts.
     * - {@link coordTopological} - This is a coordinate assignment tailored for
     * a {@link layeringTopological | topological layout}. It can use a
     *   simplex or quadratic optimization to create a topological layout.
     *
     * You can also supply any function that satisfies the {@link Coord}
     * interface. See that documentation for more information about implementing
     * your own coordinate assignment operator.
     *
     * (default: {@link coordSimplex})
     *
     * @example
     *
     * ```ts
     * const layout = sugiyama().coord(coordQuad());
     * ```
     */
    coord<NewCoord extends Coord>(crd: NewCoord): Sugiyama<U<Ops, "coord", NewCoord>>;
    /**
     * get the current {@link Coord}.
     */
    coord(): Ops["coord"];
    /**
     * set the {@link Tweak}s to apply after layout
     */
    tweaks<const NewTweaks extends readonly Tweak[]>(val: NewTweaks): Sugiyama<U<Ops, "tweaks", NewTweaks>>;
    /**
     * get the current {@link Tweak}s.
     */
    tweaks(): Ops["tweaks"];
    /**
     * sets the {@link NodeSize}
     *
     * (default: `[1, 1]`)
     */
    nodeSize<NewNodeSize extends NodeSize>(acc: NewNodeSize): Sugiyama<U<Ops, "nodeSize", NewNodeSize>>;
    /** get the current node size */
    nodeSize(): Ops["nodeSize"];
    /**
     * get the gap size between nodes
     *
     * (default: `[1, 1]`)
     */
    gap(val: readonly [number, number]): Sugiyama<Ops>;
    /** get the current gap size */
    gap(): readonly [number, number];
}
/** default sugiyama operator */
export type DefaultSugiyama = Sugiyama<{
    /** default layering */
    layering: DefaultLayeringSimplex;
    /** default decross */
    decross: DefaultDecrossTwoLayer;
    /** default coord */
    coord: DefaultCoordSimplex;
    /** default node size */
    nodeSize: readonly [1, 1];
    /** default tweaks */
    tweaks: readonly [];
}>;
/**
 * construct a new {@link Sugiyama} with the default settings
 *
 * The sugiyama layout takes a three step layering approach. First it calls
 * {@link Sugiyama#layering} to assign a layer to each node. Then it calls
 * {@link Sugiyama#decross} to arrange nodes in each layer to minimize edge
 * crossings. Finally it calls {@link Sugiyama#coord} to assign actual
 * coordinates given the ordering.
 *
 * Finally, you can also tweak the standard settings of
 * {@link Sugiyama#nodeSize}, {@link Sugiyama#gap}, and
 * {@link Sugiyama#tweaks}. Note that {@link Rank} can be set in some {@link
 * Layering} operators.
 *
 * <img alt="Sugiyama example" src="../../resources/sugi-simplex-twolayer-simplex.png" width="400">
 *
 * @example
 *
 * To use the default layout:
 *
 * ```ts
 * const grf: Graph = ...
 * const layout = sugiyama();
 * layout(dag);
 * for (const node of dag.nodes()) {
 *   console.log(node.x, node.y);
 * }
 * ```
 *
 * @example
 *
 * To use optimal decrossing, which will only work for small graphs:
 *
 * ```ts
 * const grf: Graph = ...
 * const layout = sugiyama().decross(decrossOpt());
 * layout(dag);
 * for (const node of dag.nodes()) {
 *   console.log(node.x, node.y);
 * }
 * ```
 */
export declare function sugiyama(...args: never[]): DefaultSugiyama;
