undirect.go 7.7 KB

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