gonum.org/v1/gonum@v0.14.0/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 }