gonum.org/v1/gonum@v0.14.0/graph/simple/weighted_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  	"gonum.org/v1/gonum/graph"
    11  	"gonum.org/v1/gonum/graph/iterator"
    12  	"gonum.org/v1/gonum/graph/set/uid"
    13  )
    14  
    15  var (
    16  	wdg *WeightedDirectedGraph
    17  
    18  	_ graph.Graph             = wdg
    19  	_ graph.Weighted          = wdg
    20  	_ graph.Directed          = wdg
    21  	_ graph.WeightedDirected  = wdg
    22  	_ graph.NodeAdder         = wdg
    23  	_ graph.NodeRemover       = wdg
    24  	_ graph.WeightedEdgeAdder = wdg
    25  	_ graph.EdgeRemover       = wdg
    26  )
    27  
    28  // WeightedDirectedGraph implements a generalized weighted directed graph.
    29  type WeightedDirectedGraph struct {
    30  	nodes map[int64]graph.Node
    31  	from  map[int64]map[int64]graph.WeightedEdge
    32  	to    map[int64]map[int64]graph.WeightedEdge
    33  
    34  	self, absent float64
    35  
    36  	nodeIDs *uid.Set
    37  }
    38  
    39  // NewWeightedDirectedGraph returns a WeightedDirectedGraph with the specified self and absent
    40  // edge weight values.
    41  func NewWeightedDirectedGraph(self, absent float64) *WeightedDirectedGraph {
    42  	return &WeightedDirectedGraph{
    43  		nodes: make(map[int64]graph.Node),
    44  		from:  make(map[int64]map[int64]graph.WeightedEdge),
    45  		to:    make(map[int64]map[int64]graph.WeightedEdge),
    46  
    47  		self:   self,
    48  		absent: absent,
    49  
    50  		nodeIDs: uid.NewSet(),
    51  	}
    52  }
    53  
    54  // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID.
    55  func (g *WeightedDirectedGraph) AddNode(n graph.Node) {
    56  	if _, exists := g.nodes[n.ID()]; exists {
    57  		panic(fmt.Sprintf("simple: node ID collision: %d", n.ID()))
    58  	}
    59  	g.nodes[n.ID()] = n
    60  	g.nodeIDs.Use(n.ID())
    61  }
    62  
    63  // Edge returns the edge from u to v if such an edge exists and nil otherwise.
    64  // The node v must be directly reachable from u as defined by the From method.
    65  func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
    66  	return g.WeightedEdge(uid, vid)
    67  }
    68  
    69  // Edges returns all the edges in the graph.
    70  func (g *WeightedDirectedGraph) Edges() graph.Edges {
    71  	var edges []graph.Edge
    72  	for _, u := range g.nodes {
    73  		for _, e := range g.from[u.ID()] {
    74  			edges = append(edges, e)
    75  		}
    76  	}
    77  	if len(edges) == 0 {
    78  		return graph.Empty
    79  	}
    80  	return iterator.NewOrderedEdges(edges)
    81  }
    82  
    83  // From returns all nodes in g that can be reached directly from n.
    84  //
    85  // The returned graph.Nodes is only valid until the next mutation of
    86  // the receiver.
    87  func (g *WeightedDirectedGraph) From(id int64) graph.Nodes {
    88  	if len(g.from[id]) == 0 {
    89  		return graph.Empty
    90  	}
    91  	return iterator.NewNodesByWeightedEdge(g.nodes, g.from[id])
    92  }
    93  
    94  // HasEdgeBetween returns whether an edge exists between nodes x and y without
    95  // considering direction.
    96  func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
    97  	if _, ok := g.from[xid][yid]; ok {
    98  		return true
    99  	}
   100  	_, ok := g.from[yid][xid]
   101  	return ok
   102  }
   103  
   104  // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
   105  func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
   106  	if _, ok := g.from[uid][vid]; !ok {
   107  		return false
   108  	}
   109  	return true
   110  }
   111  
   112  // NewNode returns a new unique Node to be added to g. The Node's ID does
   113  // not become valid in g until the Node is added to g.
   114  func (g *WeightedDirectedGraph) NewNode() graph.Node {
   115  	if len(g.nodes) == 0 {
   116  		return Node(0)
   117  	}
   118  	if int64(len(g.nodes)) == uid.Max {
   119  		panic("simple: cannot allocate node: no slot")
   120  	}
   121  	return Node(g.nodeIDs.NewID())
   122  }
   123  
   124  // NewWeightedEdge returns a new weighted edge from the source to the destination node.
   125  func (g *WeightedDirectedGraph) NewWeightedEdge(from, to graph.Node, weight float64) graph.WeightedEdge {
   126  	return WeightedEdge{F: from, T: to, W: weight}
   127  }
   128  
   129  // Node returns the node with the given ID if it exists in the graph,
   130  // and nil otherwise.
   131  func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
   132  	return g.nodes[id]
   133  }
   134  
   135  // Nodes returns all the nodes in the graph.
   136  //
   137  // The returned graph.Nodes is only valid until the next mutation of
   138  // the receiver.
   139  func (g *WeightedDirectedGraph) Nodes() graph.Nodes {
   140  	if len(g.nodes) == 0 {
   141  		return graph.Empty
   142  	}
   143  	return iterator.NewNodes(g.nodes)
   144  }
   145  
   146  // NodeWithID returns a Node with the given ID if possible. If a graph.Node
   147  // is returned that is not already in the graph NodeWithID will return true
   148  // for new and the graph.Node must be added to the graph before use.
   149  func (g *WeightedDirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) {
   150  	n, ok := g.nodes[id]
   151  	if ok {
   152  		return n, false
   153  	}
   154  	return Node(id), true
   155  }
   156  
   157  // RemoveEdge removes the edge with the given end point IDs from the graph, leaving the terminal
   158  // nodes. If the edge does not exist it is a no-op.
   159  func (g *WeightedDirectedGraph) RemoveEdge(fid, tid int64) {
   160  	if _, ok := g.nodes[fid]; !ok {
   161  		return
   162  	}
   163  	if _, ok := g.nodes[tid]; !ok {
   164  		return
   165  	}
   166  
   167  	delete(g.from[fid], tid)
   168  	delete(g.to[tid], fid)
   169  }
   170  
   171  // RemoveNode removes the node with the given ID from the graph, as well as any edges attached
   172  // to it. If the node is not in the graph it is a no-op.
   173  func (g *WeightedDirectedGraph) RemoveNode(id int64) {
   174  	if _, ok := g.nodes[id]; !ok {
   175  		return
   176  	}
   177  	delete(g.nodes, id)
   178  
   179  	for from := range g.from[id] {
   180  		delete(g.to[from], id)
   181  	}
   182  	delete(g.from, id)
   183  
   184  	for to := range g.to[id] {
   185  		delete(g.from[to], id)
   186  	}
   187  	delete(g.to, id)
   188  
   189  	g.nodeIDs.Release(id)
   190  }
   191  
   192  // SetWeightedEdge adds a weighted edge from one node to another. If the nodes do not exist, they are added
   193  // and are set to the nodes of the edge otherwise.
   194  // It will panic if the IDs of the e.From and e.To are equal.
   195  func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
   196  	var (
   197  		from = e.From()
   198  		fid  = from.ID()
   199  		to   = e.To()
   200  		tid  = to.ID()
   201  	)
   202  
   203  	if fid == tid {
   204  		panic("simple: adding self edge")
   205  	}
   206  
   207  	if _, ok := g.nodes[fid]; !ok {
   208  		g.AddNode(from)
   209  	} else {
   210  		g.nodes[fid] = from
   211  	}
   212  	if _, ok := g.nodes[tid]; !ok {
   213  		g.AddNode(to)
   214  	} else {
   215  		g.nodes[tid] = to
   216  	}
   217  
   218  	if fm, ok := g.from[fid]; ok {
   219  		fm[tid] = e
   220  	} else {
   221  		g.from[fid] = map[int64]graph.WeightedEdge{tid: e}
   222  	}
   223  	if tm, ok := g.to[tid]; ok {
   224  		tm[fid] = e
   225  	} else {
   226  		g.to[tid] = map[int64]graph.WeightedEdge{fid: e}
   227  	}
   228  }
   229  
   230  // To returns all nodes in g that can reach directly to n.
   231  //
   232  // The returned graph.Nodes is only valid until the next mutation of
   233  // the receiver.
   234  func (g *WeightedDirectedGraph) To(id int64) graph.Nodes {
   235  	if len(g.to[id]) == 0 {
   236  		return graph.Empty
   237  	}
   238  	return iterator.NewNodesByWeightedEdge(g.nodes, g.to[id])
   239  }
   240  
   241  // Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
   242  // If x and y are the same node or there is no joining edge between the two nodes the weight
   243  // value returned is either the graph's absent or self value. Weight returns true if an edge
   244  // exists between x and y or if x and y have the same ID, false otherwise.
   245  func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
   246  	if xid == yid {
   247  		return g.self, true
   248  	}
   249  	if to, ok := g.from[xid]; ok {
   250  		if e, ok := to[yid]; ok {
   251  			return e.Weight(), true
   252  		}
   253  	}
   254  	return g.absent, false
   255  }
   256  
   257  // WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
   258  // The node v must be directly reachable from u as defined by the From method.
   259  func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
   260  	edge, ok := g.from[uid][vid]
   261  	if !ok {
   262  		return nil
   263  	}
   264  	return edge
   265  }
   266  
   267  // WeightedEdges returns all the weighted edges in the graph.
   268  func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges {
   269  	var edges []graph.WeightedEdge
   270  	for _, u := range g.nodes {
   271  		for _, e := range g.from[u.ID()] {
   272  			edges = append(edges, e)
   273  		}
   274  	}
   275  	if len(edges) == 0 {
   276  		return graph.Empty
   277  	}
   278  	return iterator.NewOrderedWeightedEdges(edges)
   279  }