UNPKG

graph-data-structure

Version:
268 lines (247 loc) 9.73 kB
declare class Graph<Node = string, LinkProps = never> { /** * Contains all the nodes added to the graph. */ nodes: Set<Node>; /** * The adjacency list of the graph. */ edges: Map<Node, Set<Node>>; /** * The weights of edges. * * Map<SourceNode, Map<TargetNode, EdgeWeight>> */ edgeWeights: Map<Node, Map<Node, EdgeWeight>>; /** * Arbitrary properties of edges. * Map<SourceNode, Map<TargetNode, EdgeProperties>> */ edgeProperties: Map<Node, Map<Node, LinkProps>>; /** * Adds a node to the graph. * If node was already added, this function does nothing. * If node was not already added, this function sets up an empty adjacency list. */ addNode(node: Node): this; /** * Removes a node from the graph. * Also removes incoming and outgoing edges. */ removeNode(node: Node): this; /** * Gets the adjacent nodes set for the given node. */ adjacent(node: Node): Set<Node> | undefined; /** * Sets the weight of the given edge. */ setEdgeWeight(source: Node, target: Node, weight: EdgeWeight): this; /** * Gets the weight of the given edge or `1` if not set. */ getEdgeWeight(source: Node, target: Node): number; /** * Set the properties of the given edge. */ setEdgeProperties(source: Node, target: Node, props: LinkProps): this; /** * Get the properties of the given edge or undefined if the edge doesn't exist . */ getEdgeProperties(source: Node, target: Node): LinkProps | undefined; /** * Adds an edge from the `source` node to `target` node. * This method will create the nodes if they were not already added. */ addEdge(source: Node, target: Node, ...args: AddEdgeArgs<LinkProps>): this; /** * Removes the edge from the `source` node to `target` node. * Does not remove the nodes themselves. * Does nothing if the edge does not exist. */ removeEdge(source: Node, target: Node): this; /** * Returns true if there is an edge from the `source` node to `target` node.. */ hasEdge(source: Node, target: Node): boolean; } type AddEdgeArgs<LinkProps> = [LinkProps] extends [never] ? [weight?: EdgeWeight] | [opts?: { weight?: EdgeWeight; }] : [opts: { weight?: EdgeWeight; props: LinkProps; }]; type EdgeWeight = number; type Edge<NodeIdentity = unknown, Props = unknown> = { source: NodeIdentity; target: NodeIdentity; weight?: EdgeWeight; props: Props; }; type Serialized<Node = unknown, LinkProps = unknown, NodeIdentity = Node> = { nodes: Node[]; links: Edge<NodeIdentity, LinkProps>[]; }; type SerializedInput<Node = unknown, LinkProps = unknown> = { nodes: ReadonlyArray<Node>; links: ReadonlyArray<Edge<Node, LinkProps>>; }; type NoInfer<T> = [T][T extends any ? 0 : never]; type NextWeightFnParams<Node = unknown, LinkProps = unknown> = { edgeWeight: EdgeWeight; currentPathWeight: EdgeWeight | undefined; hop: number; graph: Graph<Node, LinkProps>; path: readonly [NoInfer<Node>, NoInfer<Node>, ...NoInfer<Node>[]]; previousNode: NoInfer<Node> | undefined; currentNode: NoInfer<Node>; props: LinkProps; }; declare class CycleError extends Error { constructor(message: string); } type DepthFirstSearchOptions<Node, LinkProps> = { /** * Use those nodes as source nodes. * @default all the nodes in the graph are used as source nodes. */ sourceNodes?: Node[]; /** * Include or exclude the source nodes from the result. * @default true */ includeSourceNodes?: boolean; /** * Throw an error when a cycle is detected. * @default false */ errorOnCycle?: boolean; /** * A function that is executed to determine if the branch should be visited or not. * @param source the current node * @param target the next node to explore * @param graph the graph instance being explored * @returns boolean */ shouldFollow?: (args: { source: Node; target: Node; props: LinkProps; graph: Graph<Node, LinkProps>; }) => boolean; }; /** * Depth First Search algorithm, inspired by * Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 604 */ declare function depthFirstSearch<Node, LinkProps>(graph: Graph<Node, LinkProps>, opts?: DepthFirstSearchOptions<NoInfer<Node>, NoInfer<LinkProps>>): Node[]; /** * Dijkstra's Shortest Path Algorithm. * Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 658 * Variable and function names correspond to names in the book. */ declare function shortestPath<Node, LinkProps>(graph: Graph<Node, LinkProps>, source: NoInfer<Node>, destination: NoInfer<Node>, nextWeightFn?: (params: NextWeightFnParams) => number): { nodes: [Node, Node, ...Node[]]; weight: number | undefined; }; declare function shortestPaths<Node, LinkProps>(graph: Graph<Node, LinkProps>, source: NoInfer<Node>, destination: NoInfer<Node>): { nodes: [Node, Node, ...Node[]]; weight: number | undefined; }[]; /** * The topological sort algorithm yields a list of visited nodes * such that for each visited edge (u, v), u comes before v in the list. * Amazingly, this comes from just reversing the result from depth first search. * Cormen et al. "Introduction to Algorithms" 3rd Ed. p. 613 */ type TopologicalSortOptions<Node, LinkProps> = { /** * Run the first on those nodes. * @default all the nodes of the graph. */ sourceNodes?: Node[]; /** * Include the source nodes from the result. * @default true */ includeSourceNodes?: boolean; /** * A function that is executed to determine if the branch should be visited or not. * @param source the current node * @param target the next node to explore * @param graph the graph instance being explored * @returns boolean */ shouldFollow?: (args: { source: Node; target: Node; props: LinkProps; graph: Graph<Node, LinkProps>; }) => boolean; }; declare function topologicalSort<Node, LinkProps>(graph: Graph<Node, LinkProps>, opts?: TopologicalSortOptions<NoInfer<Node>, NoInfer<LinkProps>>): Node[]; /** * Return an array containing the lowest common ancestors. * * Inspired by https://github.com/relaxedws/lca/blob/master/src/LowestCommonAncestor.php code * but uses depth search instead of breadth. Also uses some optimizations. */ declare function lowestCommonAncestors<Node, LinkProps>(graph: Graph<Node, LinkProps>, node1: NoInfer<Node>, node2: NoInfer<Node>): Node[]; /** * Computes the indegree for the given node. * Not very efficient, costs O(E) where E = number of edges. */ declare function indegree<Node>(graph: Graph<Node>, node: NoInfer<Node>): number; declare function outdegree<Node>(graph: Graph<Node>, node: NoInfer<Node>): number; /** * Clone the graph data structures. * Nodes references are preserves. */ declare function cloneGraph<Node, LinkProps>(graph: Graph<Node, LinkProps>): Graph<Node, LinkProps>; /** * Perform a depth first search to detect an eventual cycle. * * You can provide a `shouldFollow` function to constrain the traversing and * provide `sourceNodes` to explore a particular sub-graphs. */ declare function hasCycle<Node, LinkProps>(graph: Graph<Node, LinkProps>, opts?: Pick<DepthFirstSearchOptions<Node, LinkProps>, 'shouldFollow' | 'sourceNodes'>): boolean; /** * Serializes the graph. */ type SerializeGraphOptions<IncludeDefaultWeight extends boolean = false> = { /** * If no weight is set on an edge, the default weight is `1`. * When `includeDefaultWeight: true`, the serialization will include the edge's weight even when none is set or * the value has been set to `1`. * * @default false */ includeDefaultWeight?: IncludeDefaultWeight; }; /** * Serialize the graph data set : nodes, edges, edges weight & properties. * * Optionally, you can pass a function that returns a unique value for a given node. * When provided, the function will be used to avoid data duplication in the serialized object. */ declare function serializeGraph<Node, LinkProps, IncludeDefaultWeight extends boolean, NodeIdentity = Node>(graph: Graph<Node, LinkProps>, ...args: [ identityFn: (node: NoInfer<Node>) => NodeIdentity, SerializeGraphOptions<IncludeDefaultWeight>? ] | [SerializeGraphOptions<IncludeDefaultWeight>?]): Serialized<Node, LinkProps, NodeIdentity>; declare function deserializeGraph<Node, LinkProps, NodeIdentity>(...args: Node extends object ? [ data: SerializedInput<Node, LinkProps>, identityFn: (node: NoInfer<Node>) => NodeIdentity ] : [data: SerializedInput<Node, LinkProps>]): Graph<Node, LinkProps>; /** * Returns all the nodes matching your function. */ declare function findNodes<Node>(graph: Graph<Node, any>, fn: (node: NoInfer<Node>) => boolean): Node[]; /** * Return the node matching your function. Throws if none is found or if more than one node if found. */ declare function getNode<Node>(graph: Graph<Node, any>, fn: (node: NoInfer<Node>) => boolean): Node; /** * Return the first node matching your function and throws if none is found. */ declare function getFirstNode<Node>(graph: Graph<Node, any>, fn: (node: NoInfer<Node>) => boolean): Node; export { CycleError, type Edge, type EdgeWeight, Graph, type NextWeightFnParams, type Serialized, type SerializedInput, cloneGraph, depthFirstSearch, deserializeGraph, findNodes, getFirstNode, getNode, hasCycle, indegree, lowestCommonAncestors, outdegree, serializeGraph, shortestPath, shortestPaths, topologicalSort };