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