github.com/gopherd/gonum@v0.0.4/graph/simple/directed.go (about)

     1  // Copyright ©2014 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package simple
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/gopherd/gonum/graph"
    11  	"github.com/gopherd/gonum/graph/iterator"
    12  	"github.com/gopherd/gonum/graph/set/uid"
    13  )
    14  
    15  var (
    16  	dg *DirectedGraph
    17  
    18  	_ graph.Graph       = dg
    19  	_ graph.Directed    = dg
    20  	_ graph.NodeAdder   = dg
    21  	_ graph.NodeRemover = dg
    22  	_ graph.EdgeAdder   = dg
    23  	_ graph.EdgeRemover = dg
    24  )
    25  
    26  // DirectedGraph implements a generalized directed graph.
    27  type DirectedGraph struct {
    28  	nodes map[int64]graph.Node
    29  	from  map[int64]map[int64]graph.Edge
    30  	to    map[int64]map[int64]graph.Edge
    31  
    32  	nodeIDs *uid.Set
    33  }
    34  
    35  // NewDirectedGraph returns a DirectedGraph.
    36  func NewDirectedGraph() *DirectedGraph {
    37  	return &DirectedGraph{
    38  		nodes: make(map[int64]graph.Node),
    39  		from:  make(map[int64]map[int64]graph.Edge),
    40  		to:    make(map[int64]map[int64]graph.Edge),
    41  
    42  		nodeIDs: uid.NewSet(),
    43  	}
    44  }
    45  
    46  // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID.
    47  func (g *DirectedGraph) AddNode(n graph.Node) {
    48  	if _, exists := g.nodes[n.ID()]; exists {
    49  		panic(fmt.Sprintf("simple: node ID collision: %d", n.ID()))
    50  	}
    51  	g.nodes[n.ID()] = n
    52  	g.nodeIDs.Use(n.ID())
    53  }
    54  
    55  // Edge returns the edge from u to v if such an edge exists and nil otherwise.
    56  // The node v must be directly reachable from u as defined by the From method.
    57  func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
    58  	edge, ok := g.from[uid][vid]
    59  	if !ok {
    60  		return nil
    61  	}
    62  	return edge
    63  }
    64  
    65  // Edges returns all the edges in the graph.
    66  func (g *DirectedGraph) Edges() graph.Edges {
    67  	var edges []graph.Edge
    68  	for _, u := range g.nodes {
    69  		for _, e := range g.from[u.ID()] {
    70  			edges = append(edges, e)
    71  		}
    72  	}
    73  	if len(edges) == 0 {
    74  		return graph.Empty
    75  	}
    76  	return iterator.NewOrderedEdges(edges)
    77  }
    78  
    79  // From returns all nodes in g that can be reached directly from n.
    80  //
    81  // The returned graph.Nodes is only valid until the next mutation of
    82  // the receiver.
    83  func (g *DirectedGraph) From(id int64) graph.Nodes {
    84  	if len(g.from[id]) == 0 {
    85  		return graph.Empty
    86  	}
    87  	return iterator.NewNodesByEdge(g.nodes, g.from[id])
    88  }
    89  
    90  // HasEdgeBetween returns whether an edge exists between nodes x and y without
    91  // considering direction.
    92  func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
    93  	if _, ok := g.from[xid][yid]; ok {
    94  		return true
    95  	}
    96  	_, ok := g.from[yid][xid]
    97  	return ok
    98  }
    99  
   100  // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
   101  func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
   102  	if _, ok := g.from[uid][vid]; !ok {
   103  		return false
   104  	}
   105  	return true
   106  }
   107  
   108  // NewEdge returns a new Edge from the source to the destination node.
   109  func (g *DirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
   110  	return Edge{F: from, T: to}
   111  }
   112  
   113  // NewNode returns a new unique Node to be added to g. The Node's ID does
   114  // not become valid in g until the Node is added to g.
   115  func (g *DirectedGraph) NewNode() graph.Node {
   116  	if len(g.nodes) == 0 {
   117  		return Node(0)
   118  	}
   119  	if int64(len(g.nodes)) == uid.Max {
   120  		panic("simple: cannot allocate node: no slot")
   121  	}
   122  	return Node(g.nodeIDs.NewID())
   123  }
   124  
   125  // Node returns the node with the given ID if it exists in the graph,
   126  // and nil otherwise.
   127  func (g *DirectedGraph) Node(id int64) graph.Node {
   128  	return g.nodes[id]
   129  }
   130  
   131  // Nodes returns all the nodes in the graph.
   132  //
   133  // The returned graph.Nodes is only valid until the next mutation of
   134  // the receiver.
   135  func (g *DirectedGraph) Nodes() graph.Nodes {
   136  	if len(g.nodes) == 0 {
   137  		return graph.Empty
   138  	}
   139  	return iterator.NewNodes(g.nodes)
   140  }
   141  
   142  // NodeWithID returns a Node with the given ID if possible. If a graph.Node
   143  // is returned that is not already in the graph NodeWithID will return true
   144  // for new and the graph.Node must be added to the graph before use.
   145  func (g *DirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) {
   146  	n, ok := g.nodes[id]
   147  	if ok {
   148  		return n, false
   149  	}
   150  	return Node(id), true
   151  }
   152  
   153  // RemoveEdge removes the edge with the given end point IDs from the graph, leaving the terminal
   154  // nodes. If the edge does not exist it is a no-op.
   155  func (g *DirectedGraph) RemoveEdge(fid, tid int64) {
   156  	if _, ok := g.nodes[fid]; !ok {
   157  		return
   158  	}
   159  	if _, ok := g.nodes[tid]; !ok {
   160  		return
   161  	}
   162  
   163  	delete(g.from[fid], tid)
   164  	delete(g.to[tid], fid)
   165  }
   166  
   167  // RemoveNode removes the node with the given ID from the graph, as well as any edges attached
   168  // to it. If the node is not in the graph it is a no-op.
   169  func (g *DirectedGraph) RemoveNode(id int64) {
   170  	if _, ok := g.nodes[id]; !ok {
   171  		return
   172  	}
   173  	delete(g.nodes, id)
   174  
   175  	for from := range g.from[id] {
   176  		delete(g.to[from], id)
   177  	}
   178  	delete(g.from, id)
   179  
   180  	for to := range g.to[id] {
   181  		delete(g.from[to], id)
   182  	}
   183  	delete(g.to, id)
   184  
   185  	g.nodeIDs.Release(id)
   186  }
   187  
   188  // SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added
   189  // and are set to the nodes of the edge otherwise.
   190  // It will panic if the IDs of the e.From and e.To are equal.
   191  func (g *DirectedGraph) SetEdge(e graph.Edge) {
   192  	var (
   193  		from = e.From()
   194  		fid  = from.ID()
   195  		to   = e.To()
   196  		tid  = to.ID()
   197  	)
   198  
   199  	if fid == tid {
   200  		panic("simple: adding self edge")
   201  	}
   202  
   203  	if _, ok := g.nodes[fid]; !ok {
   204  		g.AddNode(from)
   205  	} else {
   206  		g.nodes[fid] = from
   207  	}
   208  	if _, ok := g.nodes[tid]; !ok {
   209  		g.AddNode(to)
   210  	} else {
   211  		g.nodes[tid] = to
   212  	}
   213  
   214  	if fm, ok := g.from[fid]; ok {
   215  		fm[tid] = e
   216  	} else {
   217  		g.from[fid] = map[int64]graph.Edge{tid: e}
   218  	}
   219  	if tm, ok := g.to[tid]; ok {
   220  		tm[fid] = e
   221  	} else {
   222  		g.to[tid] = map[int64]graph.Edge{fid: e}
   223  	}
   224  }
   225  
   226  // To returns all nodes in g that can reach directly to n.
   227  //
   228  // The returned graph.Nodes is only valid until the next mutation of
   229  // the receiver.
   230  func (g *DirectedGraph) To(id int64) graph.Nodes {
   231  	if len(g.to[id]) == 0 {
   232  		return graph.Empty
   233  	}
   234  	return iterator.NewNodesByEdge(g.nodes, g.to[id])
   235  }