暂无描述

graph_test.go 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package graph
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. func edgeDebugString(edge *Edge) string {
  7. debug := ""
  8. debug += fmt.Sprintf("\t\tSrc: %p\n", edge.Src)
  9. debug += fmt.Sprintf("\t\tDest: %p\n", edge.Dest)
  10. debug += fmt.Sprintf("\t\tWeight: %d\n", edge.Weight)
  11. debug += fmt.Sprintf("\t\tResidual: %t\n", edge.Residual)
  12. debug += fmt.Sprintf("\t\tInline: %t\n", edge.Inline)
  13. return debug
  14. }
  15. func edgeMapsDebugString(in, out EdgeMap) string {
  16. debug := ""
  17. debug += "In Edges:\n"
  18. for parent, edge := range in {
  19. debug += fmt.Sprintf("\tParent: %p\n", parent)
  20. debug += edgeDebugString(edge)
  21. }
  22. debug += "Out Edges:\n"
  23. for child, edge := range out {
  24. debug += fmt.Sprintf("\tChild: %p\n", child)
  25. debug += edgeDebugString(edge)
  26. }
  27. return debug
  28. }
  29. func graphDebugString(graph *Graph) string {
  30. debug := ""
  31. for i, node := range graph.Nodes {
  32. debug += fmt.Sprintf("Node %d: %p\n", i, node)
  33. }
  34. for i, node := range graph.Nodes {
  35. debug += "\n"
  36. debug += fmt.Sprintf("=== Node %d: %p ===\n", i, node)
  37. debug += edgeMapsDebugString(node.In, node.Out)
  38. }
  39. return debug
  40. }
  41. func expectedNodesDebugString(expected []expectedNode) string {
  42. debug := ""
  43. for i, node := range expected {
  44. debug += fmt.Sprintf("Node %d: %p\n", i, node.node)
  45. }
  46. for i, node := range expected {
  47. debug += "\n"
  48. debug += fmt.Sprintf("=== Node %d: %p ===\n", i, node.node)
  49. debug += edgeMapsDebugString(node.in, node.out)
  50. }
  51. return debug
  52. }
  53. // edgeMapsEqual checks if all the edges in this equal all the edges in that.
  54. func edgeMapsEqual(this, that EdgeMap) bool {
  55. if len(this) != len(that) {
  56. return false
  57. }
  58. for node, thisEdge := range this {
  59. if *thisEdge != *that[node] {
  60. return false
  61. }
  62. }
  63. return true
  64. }
  65. // nodesEqual checks if node is equal to expected.
  66. func nodesEqual(node *Node, expected expectedNode) bool {
  67. return node == expected.node && edgeMapsEqual(node.In, expected.in) &&
  68. edgeMapsEqual(node.Out, expected.out)
  69. }
  70. // graphsEqual checks if graph is equivalent to the graph templated by expected.
  71. func graphsEqual(graph *Graph, expected []expectedNode) bool {
  72. if len(graph.Nodes) != len(expected) {
  73. return false
  74. }
  75. expectedSet := make(map[*Node]expectedNode)
  76. for i := range expected {
  77. expectedSet[expected[i].node] = expected[i]
  78. }
  79. for _, node := range graph.Nodes {
  80. expectedNode, found := expectedSet[node]
  81. if !found || !nodesEqual(node, expectedNode) {
  82. return false
  83. }
  84. }
  85. return true
  86. }
  87. type expectedNode struct {
  88. node *Node
  89. in, out EdgeMap
  90. }
  91. type trimTreeTestcase struct {
  92. initial *Graph
  93. expected []expectedNode
  94. keep NodePtrSet
  95. }
  96. // makeExpectedEdgeResidual makes the edge from parent to child residual.
  97. func makeExpectedEdgeResidual(parent, child expectedNode) {
  98. parent.out[child.node].Residual = true
  99. child.in[parent.node].Residual = true
  100. }
  101. func makeEdgeInline(edgeMap EdgeMap, node *Node) {
  102. edgeMap[node].Inline = true
  103. }
  104. func setEdgeWeight(edgeMap EdgeMap, node *Node, weight int64) {
  105. edgeMap[node].Weight = weight
  106. }
  107. // createEdges creates directed edges from the parent to each of the children.
  108. func createEdges(parent *Node, children ...*Node) {
  109. for _, child := range children {
  110. edge := &Edge{
  111. Src: parent,
  112. Dest: child,
  113. }
  114. parent.Out[child] = edge
  115. child.In[parent] = edge
  116. }
  117. }
  118. // createEmptyNode creates a node without any edges.
  119. func createEmptyNode() *Node {
  120. return &Node{
  121. In: make(EdgeMap),
  122. Out: make(EdgeMap),
  123. }
  124. }
  125. // createExpectedNodes creates a slice of expectedNodes from nodes.
  126. func createExpectedNodes(nodes ...*Node) ([]expectedNode, NodePtrSet) {
  127. expected := make([]expectedNode, len(nodes))
  128. keep := make(NodePtrSet, len(nodes))
  129. for i, node := range nodes {
  130. expected[i] = expectedNode{
  131. node: node,
  132. in: make(EdgeMap),
  133. out: make(EdgeMap),
  134. }
  135. keep[node] = true
  136. }
  137. return expected, keep
  138. }
  139. // createExpectedEdges creates directed edges from the parent to each of the
  140. // children.
  141. func createExpectedEdges(parent expectedNode, children ...expectedNode) {
  142. for _, child := range children {
  143. edge := &Edge{
  144. Src: parent.node,
  145. Dest: child.node,
  146. }
  147. parent.out[child.node] = edge
  148. child.in[parent.node] = edge
  149. }
  150. }
  151. // createTestCase1 creates a test case that initially looks like:
  152. // 0
  153. // |(5)
  154. // 1
  155. // (3)/ \(4)
  156. // 2 3.
  157. //
  158. // After keeping 0, 2, and 3, it expects the graph:
  159. // 0
  160. // (3)/ \(4)
  161. // 2 3.
  162. func createTestCase1() trimTreeTestcase {
  163. // Create initial graph
  164. graph := &Graph{make(Nodes, 4)}
  165. nodes := graph.Nodes
  166. for i := range nodes {
  167. nodes[i] = createEmptyNode()
  168. }
  169. createEdges(nodes[0], nodes[1])
  170. createEdges(nodes[1], nodes[2], nodes[3])
  171. makeEdgeInline(nodes[0].Out, nodes[1])
  172. makeEdgeInline(nodes[1].Out, nodes[2])
  173. setEdgeWeight(nodes[0].Out, nodes[1], 5)
  174. setEdgeWeight(nodes[1].Out, nodes[2], 3)
  175. setEdgeWeight(nodes[1].Out, nodes[3], 4)
  176. // Create expected graph
  177. expected, keep := createExpectedNodes(nodes[0], nodes[2], nodes[3])
  178. createExpectedEdges(expected[0], expected[1], expected[2])
  179. makeEdgeInline(expected[0].out, expected[1].node)
  180. makeExpectedEdgeResidual(expected[0], expected[1])
  181. makeExpectedEdgeResidual(expected[0], expected[2])
  182. setEdgeWeight(expected[0].out, expected[1].node, 3)
  183. setEdgeWeight(expected[0].out, expected[2].node, 4)
  184. return trimTreeTestcase{
  185. initial: graph,
  186. expected: expected,
  187. keep: keep,
  188. }
  189. }
  190. // createTestCase2 creates a test case that initially looks like:
  191. // 3
  192. // | (12)
  193. // 1
  194. // | (8)
  195. // 2
  196. // | (15)
  197. // 0
  198. // | (10)
  199. // 4.
  200. //
  201. // After keeping 3 and 4, it expects the graph:
  202. // 3
  203. // | (10)
  204. // 4.
  205. func createTestCase2() trimTreeTestcase {
  206. // Create initial graph
  207. graph := &Graph{make(Nodes, 5)}
  208. nodes := graph.Nodes
  209. for i := range nodes {
  210. nodes[i] = createEmptyNode()
  211. }
  212. createEdges(nodes[3], nodes[1])
  213. createEdges(nodes[1], nodes[2])
  214. createEdges(nodes[2], nodes[0])
  215. createEdges(nodes[0], nodes[4])
  216. setEdgeWeight(nodes[3].Out, nodes[1], 12)
  217. setEdgeWeight(nodes[1].Out, nodes[2], 8)
  218. setEdgeWeight(nodes[2].Out, nodes[0], 15)
  219. setEdgeWeight(nodes[0].Out, nodes[4], 10)
  220. // Create expected graph
  221. expected, keep := createExpectedNodes(nodes[3], nodes[4])
  222. createExpectedEdges(expected[0], expected[1])
  223. makeExpectedEdgeResidual(expected[0], expected[1])
  224. setEdgeWeight(expected[0].out, expected[1].node, 10)
  225. return trimTreeTestcase{
  226. initial: graph,
  227. expected: expected,
  228. keep: keep,
  229. }
  230. }
  231. // createTestCase3 creates an initially empty graph and expects an empty graph
  232. // after trimming.
  233. func createTestCase3() trimTreeTestcase {
  234. graph := &Graph{make(Nodes, 0)}
  235. expected, keep := createExpectedNodes()
  236. return trimTreeTestcase{
  237. initial: graph,
  238. expected: expected,
  239. keep: keep,
  240. }
  241. }
  242. // createTestCase4 creates a test case that initially looks like:
  243. // 0.
  244. //
  245. // After keeping 0, it expects the graph:
  246. // 0.
  247. func createTestCase4() trimTreeTestcase {
  248. graph := &Graph{make(Nodes, 1)}
  249. nodes := graph.Nodes
  250. for i := range nodes {
  251. nodes[i] = createEmptyNode()
  252. }
  253. expected, keep := createExpectedNodes(nodes[0])
  254. return trimTreeTestcase{
  255. initial: graph,
  256. expected: expected,
  257. keep: keep,
  258. }
  259. }
  260. func createTrimTreeTestCases() []trimTreeTestcase {
  261. caseGenerators := []func() trimTreeTestcase{
  262. createTestCase1,
  263. createTestCase2,
  264. createTestCase3,
  265. createTestCase4,
  266. }
  267. cases := make([]trimTreeTestcase, len(caseGenerators))
  268. for i, gen := range caseGenerators {
  269. cases[i] = gen()
  270. }
  271. return cases
  272. }
  273. func TestTrimTree(t *testing.T) {
  274. tests := createTrimTreeTestCases()
  275. for _, test := range tests {
  276. graph := test.initial
  277. graph.TrimTree(test.keep)
  278. if !graphsEqual(graph, test.expected) {
  279. t.Fatalf("Graphs do not match.\nExpected: %s\nFound: %s\n",
  280. expectedNodesDebugString(test.expected),
  281. graphDebugString(graph))
  282. }
  283. }
  284. }