// Copyright ©2014 The gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package graph // All a node needs to do is identify itself. This allows the user to pass in nodes more // interesting than an int, but also allow us to reap the benefits of having a map-storable, // ==able type. type Node interface { ID() int } // Allows edges to do something more interesting that just be a group of nodes. While the methods // are called Head and Tail, they are not considered directed unless the given interface specifies // otherwise. type Edge interface { Head() Node Tail() Node } // A Graph implements the behavior of an undirected graph. // // All methods in Graph are implicitly undirected. Graph algorithms that care about directionality // will intelligently choose the DirectedGraph behavior if that interface is also implemented, // even if the function itself only takes in a Graph (or a super-interface of graph). type Graph interface { // NodeExists returns true when node is currently in the graph. NodeExists(Node) bool // NodeList returns a list of all nodes in no particular order, useful for // determining things like if a graph is fully connected. The caller is // free to modify this list. Implementations should construct a new list // and not return internal representation. NodeList() []Node // Neighbors returns all nodes connected by any edge to this node. Neighbors(Node) []Node // EdgeBetween returns an edge between node and neighbor such that // Head is one argument and Tail is the other. If no // such edge exists, this function returns nil. EdgeBetween(node, neighbor Node) Edge } // Directed graphs are characterized by having seperable Heads and Tails in their edges. // That is, if node1 goes to node2, that does not necessarily imply that node2 goes to node1. // // While it's possible for a directed graph to have fully reciprocal edges (i.e. the graph is // symmetric) -- it is not required to be. The graph is also required to implement Graph // because in many cases it can be useful to know all neighbors regardless of direction. type DirectedGraph interface { Graph // Successors gives the nodes connected by OUTBOUND edges. // If the graph is an undirected graph, this set is equal to Predecessors. Successors(Node) []Node // EdgeTo returns an edge between node and successor such that // Head returns node and Tail returns successor, if no // such edge exists, this function returns nil. EdgeTo(node, successor Node) Edge // Predecessors gives the nodes connected by INBOUND edges. // If the graph is an undirected graph, this set is equal to Successors. Predecessors(Node) []Node } // Returns all undirected edges in the graph type EdgeLister interface { EdgeList() []Edge } type EdgeListGraph interface { Graph EdgeLister } // Returns all directed edges in the graph. type DirectedEdgeLister interface { DirectedEdgeList() []Edge } type DirectedEdgeListGraph interface { Graph DirectedEdgeLister } // A crunch graph forces a sparse graph to become a dense graph. That is, if the node IDs are // [1,4,9,7] it would "crunch" the ids into the contiguous block [0,1,2,3]. Order is not // required to be preserved between the non-cruched and crunched instances (that means in // the example above 0 may correspond to 4 or 7 or 9, not necessarily 1). // // All dense graphs must have the first ID as 0. type CrunchGraph interface { Graph Crunch() } // A Graph that implements Coster has an actual cost between adjacent nodes, also known as a // weighted graph. If a graph implements coster and a function needs to read cost (e.g. A*), // this function will take precedence over the Uniform Cost function (all weights are 1) if "nil" // is passed in for the function argument. // // If the argument is nil, or the edge is invalid for some reason, this should return math.Inf(1) type Coster interface { Cost(edge Edge) float64 } type CostGraph interface { Coster Graph } type CostDirectedGraph interface { Coster DirectedGraph } // A graph that implements HeuristicCoster implements a heuristic between any two given nodes. // Like Coster, if a graph implements this and a function needs a heuristic cost (e.g. A*), this // function will take precedence over the Null Heuristic (always returns 0) if "nil" is passed in // for the function argument. If HeuristicCost is not intended to be used, it can be implemented as // the null heuristic (always returns 0.) type HeuristicCoster interface { // HeuristicCost returns a heuristic cost between any two nodes. HeuristicCost(node1, node2 Node) float64 } // A Mutable is a graph that can have arbitrary nodes and edges added or removed. // // Anything implementing Mutable is required to store the actual argument. So if AddNode(myNode) is // called and later a user calls on the graph graph.NodeList(), the node added by AddNode must be // an the exact node, not a new node with the same ID. // // In any case where conflict is possible (e.g. adding two nodes with the same ID), the later // call always supercedes the earlier one. // // Functions will generally expect one of MutableGraph or MutableDirectedGraph and not Mutable // itself. That said, any function that takes Mutable[x], the destination mutable should // always be a different graph than the source. type Mutable interface { // NewNode adds a node with an arbitrary ID and returns the new, unique ID // used. NewNode() Node // Adds a node to the graph. If this is called multiple times for the same ID, the newer node // overwrites the old one. AddNode(Node) // EmptyGraph clears the graph of all nodes and edges. EmptyGraph() // RemoveNode removes a node from the graph, as well as any edges // attached to it. If no such node exists, this is a no-op, not an error. RemoveNode(Node) } // MutableGraph is an interface ensuring the implementation of the ability to construct // an arbitrary undirected graph. It is very important to note that any implementation // of MutableGraph absolutely cannot safely implement the DirectedGraph interface. // // A MutableGraph is required to store any Edge argument in the same way Mutable must // store a Node argument -- any retrieval call is required to return the exact supplied edge. // This is what makes it incompatible with DirectedGraph. // // A call to AddEdgeBetween(Edge{head,tail}) make is so there is simply no way to safely // return EdgeTo(tail, head) since the edge returned will, by this contract, need to be // Head() == head and Tail() == tail when the reverse must be true to fulfill the // functionality guaranteed of EdgeTo. type MutableGraph interface { CostGraph Mutable // Like EdgeBetween in Graph, AddEdgeBetween adds an edge between two nodes. // If one or both nodes do not exist, the Graph is expected to add them. AddEdgeBetween(e Edge, cost float64) // RemoveEdge clears the stored edge between two nodes. Calling this will never // remove a node. If the edge does not exist this is a no-op, not an error. RemoveEdgeBetween(e Edge) } // MutableDirectedGraph is an interface that ensures one can construct an arbitrary directed // graph. Naturally, a MutableDirectedGraph works for both undirected and directed cases, // but simply using a MutableGraph may be cleaner. As the documentation for MutableGraph // notes, however, a graph cannot safely implement MutableGraph and MutableDirectedGraph // at the same time, because of the functionality of a EdgeTo in DirectedGraph. type MutableDirectedGraph interface { CostDirectedGraph Mutable // Adds an edge FROM e.Head TO e.Tail. Newer calls overwrite older ones. // If the nodes Head or Tail do not exist in the graph, this must add them. AddEdgeTo(e Edge, cost float64) // Removes an edge FROM e.Head TO e.Tail. If no such edge exists, this is a no-op, // not an error. RemoveEdgeTo(e Edge) } // A function that returns the cost of following an edge type CostFunc func(Edge) float64 // Estimates the cost of travelling between two nodes type HeuristicCostFunc func(Node, Node) float64 // Determines if a MutableGraph implements DirectedGraph and panics if it does. // This is a utility function to detect unsafe implementations. It's mostly for internal use, // but is exported since it may be useful to people who use the package for their own tests. func VetMutableGraph(g MutableGraph) { if _, ok := g.(DirectedGraph); ok { panic("A MutableGraph implements DirectedGraph; this is unsafe!") } }