github.com/vertgenlab/gonomics@v1.0.0/genomeGraph/sort.go (about) 1 package genomeGraph 2 3 // SortGraph will reorder nodes in a graph such that the order and Ids of the output graph are topologically sorted. 4 func SortGraph(g *GenomeGraph) *GenomeGraph { 5 answer := &GenomeGraph{} 6 answer.Nodes = make([]Node, len(g.Nodes)) 7 order := GetSortOrder(g) 8 for sortedIdx, originalIdx := range order { 9 answer.Nodes[sortedIdx] = g.Nodes[originalIdx] 10 answer.Nodes[sortedIdx].Id = uint32(sortedIdx) 11 } 12 return answer 13 } 14 15 // GetSortOrder will perform a breadth first search (BFS) on a graph and return an output slice where output[sortedIdx] = originalIdx. 16 func GetSortOrder(g *GenomeGraph) []uint32 { 17 return breadthFirstSearch(g.Nodes) 18 } 19 20 // TODO: design function to get start positions only 21 // breadthFirstSearch performs a breadth first search on a graph and returns a slice correlating the sort order to the original order. 22 func breadthFirstSearch(nodes []Node) []uint32 { 23 answer := make([]uint32, 0) 24 var inDegree int 25 var nodeId uint32 26 inDegreeTable := make(map[uint32]int) 27 28 // Updated nodes is going to keep track of each node 29 // which has had a change to it's inDegree 30 // We will use this to loop through the graph 31 // visiting each group of connected nodes in order 32 // and by searching within each group with a 33 // breadth-first approach 34 updatedNodes := make([]*Node, 0) 35 36 subGraphs := BreakNonContiguousGraph(nodes) 37 38 // loop through each contiguous subGraph 39 for _, nodeSet := range subGraphs { 40 updatedNodes = nil 41 inDegreeTable = make(map[uint32]int) 42 for i := 0; i < len(nodeSet); i++ { 43 inDegreeTable[nodeSet[i].Id] = len(nodeSet[i].Prev) 44 } 45 46 // Find all nodes that start with inDegree zero and add to updatedNodes 47 for nodeId, inDegree = range inDegreeTable { 48 if inDegree == 0 { 49 updatedNodes = append(updatedNodes, &nodes[nodeId]) 50 } 51 } 52 53 for k := 0; k < len(updatedNodes); k++ { 54 answer = append(answer, updatedNodes[k].Id) 55 delete(inDegreeTable, updatedNodes[k].Id) 56 updateTable(inDegreeTable, updatedNodes[k], &updatedNodes) 57 } 58 } 59 return answer 60 } 61 62 // updateTable updates the table of node in degrees. 63 func updateTable(inDegreeTable map[uint32]int, node *Node, updatedNodes *[]*Node) { 64 for i := 0; i < len(node.Next); i++ { 65 inDegreeTable[node.Next[i].Dest.Id]-- 66 if inDegreeTable[node.Next[i].Dest.Id] == 0 { 67 *updatedNodes = append(*updatedNodes, node.Next[i].Dest) 68 } 69 } 70 } 71 72 // TODO: possible to order nodes while breaking discontiguous graphs??? 73 // BreakNonContiguousGraph will return a slice of graphs ([]*Node) such that each graph in the slice is contiguous. 74 func BreakNonContiguousGraph(g []Node) [][]*Node { 75 answer := make([][]*Node, 0) 76 var contiguousGraph []*Node 77 inDegreeTable := make(map[uint32]int) 78 visited := make([]bool, len(g)) 79 var inDegree int 80 var nodeId uint32 81 82 for i := 0; i < len(g); i++ { 83 inDegreeTable[g[i].Id] = len(g[i].Prev) 84 } 85 86 for nodeId, inDegree = range inDegreeTable { 87 if inDegree == 0 && !visited[nodeId] { 88 contiguousGraph = make([]*Node, 1) 89 contiguousGraph[0] = &g[nodeId] 90 visited[nodeId] = true 91 traceGraph(&g[nodeId], visited, &contiguousGraph) 92 answer = append(answer, contiguousGraph) 93 } 94 } 95 96 return answer 97 } 98 99 // traceGraph is a helper function that traverses graph and keeps track of which nodes have been visited. 100 func traceGraph(startNode *Node, visited []bool, answer *[]*Node) { 101 var i int = 0 102 103 for i = 0; i < len(startNode.Next); i++ { 104 if !visited[startNode.Next[i].Dest.Id] { 105 *answer = append(*answer, startNode.Next[i].Dest) 106 visited[startNode.Next[i].Dest.Id] = true 107 traceGraph(startNode.Next[i].Dest, visited, answer) 108 } 109 } 110 111 for i = 0; i < len(startNode.Prev); i++ { 112 if !visited[startNode.Prev[i].Dest.Id] { 113 *answer = append(*answer, startNode.Prev[i].Dest) 114 visited[startNode.Prev[i].Dest.Id] = true 115 traceGraph(startNode.Prev[i].Dest, visited, answer) 116 } 117 } 118 }