github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/undirect.go (about)

     1  // Copyright ©2015 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 graph
     6  
     7  // Undirect converts a directed graph to an undirected graph.
     8  type Undirect struct {
     9  	G Directed
    10  }
    11  
    12  var _ Undirected = Undirect{}
    13  
    14  // Node returns the node with the given ID if it exists in the graph,
    15  // and nil otherwise.
    16  func (g Undirect) Node(id int64) Node { return g.G.Node(id) }
    17  
    18  // Nodes returns all the nodes in the graph.
    19  func (g Undirect) Nodes() Nodes { return g.G.Nodes() }
    20  
    21  // From returns all nodes in g that can be reached directly from u.
    22  func (g Undirect) From(uid int64) Nodes {
    23  	if g.G.Node(uid) == nil {
    24  		return Empty
    25  	}
    26  	return newNodeIteratorPair(g.G.From(uid), g.G.To(uid))
    27  }
    28  
    29  // HasEdgeBetween returns whether an edge exists between nodes x and y.
    30  func (g Undirect) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
    31  
    32  // Edge returns the edge from u to v if such an edge exists and nil otherwise.
    33  // The node v must be directly reachable from u as defined by the From method.
    34  // If an edge exists, the Edge returned is an EdgePair. The weight of
    35  // the edge is determined by applying the Merge func to the weights of the
    36  // edges between u and v.
    37  func (g Undirect) Edge(uid, vid int64) Edge { return g.EdgeBetween(uid, vid) }
    38  
    39  // EdgeBetween returns the edge between nodes x and y. If an edge exists, the
    40  // Edge returned is an EdgePair. The weight of the edge is determined by
    41  // applying the Merge func to the weights of edges between x and y.
    42  func (g Undirect) EdgeBetween(xid, yid int64) Edge {
    43  	fe := g.G.Edge(xid, yid)
    44  	re := g.G.Edge(yid, xid)
    45  	if fe == nil && re == nil {
    46  		return nil
    47  	}
    48  
    49  	return EdgePair{fe, re}
    50  }
    51  
    52  // UndirectWeighted converts a directed weighted graph to an undirected weighted graph,
    53  // resolving edge weight conflicts.
    54  type UndirectWeighted struct {
    55  	G WeightedDirected
    56  
    57  	// Absent is the value used to
    58  	// represent absent edge weights
    59  	// passed to Merge if the reverse
    60  	// edge is present.
    61  	Absent float64
    62  
    63  	// Merge defines how discordant edge
    64  	// weights in G are resolved. A merge
    65  	// is performed if at least one edge
    66  	// exists between the nodes being
    67  	// considered. The edges corresponding
    68  	// to the two weights are also passed,
    69  	// in the same order.
    70  	// The order of weight parameters
    71  	// passed to Merge is not defined, so
    72  	// the function should be commutative.
    73  	// If Merge is nil, the arithmetic
    74  	// mean is used to merge weights.
    75  	Merge func(x, y float64, xe, ye Edge) float64
    76  }
    77  
    78  var (
    79  	_ Undirected         = UndirectWeighted{}
    80  	_ WeightedUndirected = UndirectWeighted{}
    81  )
    82  
    83  // Node returns the node with the given ID if it exists in the graph,
    84  // and nil otherwise.
    85  func (g UndirectWeighted) Node(id int64) Node { return g.G.Node(id) }
    86  
    87  // Nodes returns all the nodes in the graph.
    88  func (g UndirectWeighted) Nodes() Nodes { return g.G.Nodes() }
    89  
    90  // From returns all nodes in g that can be reached directly from u.
    91  func (g UndirectWeighted) From(uid int64) Nodes {
    92  	if g.G.Node(uid) == nil {
    93  		return Empty
    94  	}
    95  	return newNodeIteratorPair(g.G.From(uid), g.G.To(uid))
    96  }
    97  
    98  // HasEdgeBetween returns whether an edge exists between nodes x and y.
    99  func (g UndirectWeighted) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
   100  
   101  // Edge returns the edge from u to v if such an edge exists and nil otherwise.
   102  // The node v must be directly reachable from u as defined by the From method.
   103  // If an edge exists, the Edge returned is an EdgePair. The weight of
   104  // the edge is determined by applying the Merge func to the weights of the
   105  // edges between u and v.
   106  func (g UndirectWeighted) Edge(uid, vid int64) Edge { return g.WeightedEdgeBetween(uid, vid) }
   107  
   108  // WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
   109  // The node v must be directly reachable from u as defined by the From method.
   110  // If an edge exists, the Edge returned is an EdgePair. The weight of
   111  // the edge is determined by applying the Merge func to the weights of the
   112  // edges between u and v.
   113  func (g UndirectWeighted) WeightedEdge(uid, vid int64) WeightedEdge {
   114  	return g.WeightedEdgeBetween(uid, vid)
   115  }
   116  
   117  // EdgeBetween returns the edge between nodes x and y. If an edge exists, the
   118  // Edge returned is an EdgePair. The weight of the edge is determined by
   119  // applying the Merge func to the weights of edges between x and y.
   120  func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge {
   121  	return g.WeightedEdgeBetween(xid, yid)
   122  }
   123  
   124  // WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the
   125  // Edge returned is an EdgePair. The weight of the edge is determined by
   126  // applying the Merge func to the weights of edges between x and y.
   127  func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge {
   128  	fe := g.G.Edge(xid, yid)
   129  	re := g.G.Edge(yid, xid)
   130  	if fe == nil && re == nil {
   131  		return nil
   132  	}
   133  
   134  	f, ok := g.G.Weight(xid, yid)
   135  	if !ok {
   136  		f = g.Absent
   137  	}
   138  	r, ok := g.G.Weight(yid, xid)
   139  	if !ok {
   140  		r = g.Absent
   141  	}
   142  
   143  	var w float64
   144  	if g.Merge == nil {
   145  		w = (f + r) / 2
   146  	} else {
   147  		w = g.Merge(f, r, fe, re)
   148  	}
   149  	return WeightedEdgePair{EdgePair: [2]Edge{fe, re}, W: w}
   150  }
   151  
   152  // Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
   153  // If x and y are the same node the internal node weight is returned. If there is no joining
   154  // edge between the two nodes the weight value returned is zero. Weight returns true if an edge
   155  // exists between x and y or if x and y have the same ID, false otherwise.
   156  func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) {
   157  	fe := g.G.Edge(xid, yid)
   158  	re := g.G.Edge(yid, xid)
   159  
   160  	f, fOk := g.G.Weight(xid, yid)
   161  	if !fOk {
   162  		f = g.Absent
   163  	}
   164  	r, rOK := g.G.Weight(yid, xid)
   165  	if !rOK {
   166  		r = g.Absent
   167  	}
   168  	ok = fOk || rOK
   169  
   170  	if g.Merge == nil {
   171  		return (f + r) / 2, ok
   172  	}
   173  	return g.Merge(f, r, fe, re), ok
   174  }
   175  
   176  // EdgePair is an opposed pair of directed edges.
   177  type EdgePair [2]Edge
   178  
   179  // From returns the from node of the first non-nil edge, or nil.
   180  func (e EdgePair) From() Node {
   181  	if e[0] != nil {
   182  		return e[0].From()
   183  	} else if e[1] != nil {
   184  		return e[1].From()
   185  	}
   186  	return nil
   187  }
   188  
   189  // To returns the to node of the first non-nil edge, or nil.
   190  func (e EdgePair) To() Node {
   191  	if e[0] != nil {
   192  		return e[0].To()
   193  	} else if e[1] != nil {
   194  		return e[1].To()
   195  	}
   196  	return nil
   197  }
   198  
   199  // ReversedEdge returns a new Edge with the end point of the
   200  // edges in the pair swapped.
   201  func (e EdgePair) ReversedEdge() Edge {
   202  	if e[0] != nil {
   203  		e[0] = e[0].ReversedEdge()
   204  	}
   205  	if e[1] != nil {
   206  		e[1] = e[1].ReversedEdge()
   207  	}
   208  	return e
   209  }
   210  
   211  // WeightedEdgePair is an opposed pair of directed edges.
   212  type WeightedEdgePair struct {
   213  	EdgePair
   214  	W float64
   215  }
   216  
   217  // ReversedEdge returns a new Edge with the end point of the
   218  // edges in the pair swapped.
   219  func (e WeightedEdgePair) ReversedEdge() Edge {
   220  	e.EdgePair = e.EdgePair.ReversedEdge().(EdgePair)
   221  	return e
   222  }
   223  
   224  // Weight returns the merged edge weights of the two edges.
   225  func (e WeightedEdgePair) Weight() float64 { return e.W }
   226  
   227  // nodeIteratorPair combines two Nodes to produce a single stream of
   228  // unique nodes.
   229  type nodeIteratorPair struct {
   230  	a, b Nodes
   231  
   232  	curr Node
   233  
   234  	idx, cnt int
   235  
   236  	// unique indicates the node in b with the key ID is unique.
   237  	unique map[int64]bool
   238  }
   239  
   240  func newNodeIteratorPair(a, b Nodes) *nodeIteratorPair {
   241  	n := nodeIteratorPair{a: a, b: b, unique: make(map[int64]bool)}
   242  	for n.b.Next() {
   243  		n.unique[n.b.Node().ID()] = true
   244  		n.cnt++
   245  	}
   246  	n.b.Reset()
   247  	for n.a.Next() {
   248  		if _, ok := n.unique[n.a.Node().ID()]; !ok {
   249  			n.cnt++
   250  		}
   251  		n.unique[n.a.Node().ID()] = false
   252  	}
   253  	n.a.Reset()
   254  	return &n
   255  }
   256  
   257  func (n *nodeIteratorPair) Len() int {
   258  	return n.cnt - n.idx
   259  }
   260  
   261  func (n *nodeIteratorPair) Next() bool {
   262  	if n.a.Next() {
   263  		n.idx++
   264  		n.curr = n.a.Node()
   265  		return true
   266  	}
   267  	for n.b.Next() {
   268  		if n.unique[n.b.Node().ID()] {
   269  			n.idx++
   270  			n.curr = n.b.Node()
   271  			return true
   272  		}
   273  	}
   274  	n.curr = nil
   275  	return false
   276  }
   277  
   278  func (n *nodeIteratorPair) Node() Node {
   279  	return n.curr
   280  }
   281  
   282  func (n *nodeIteratorPair) Reset() {
   283  	n.idx = 0
   284  	n.curr = nil
   285  	n.a.Reset()
   286  	n.b.Reset()
   287  }