github.com/LdDl/ch@v1.7.8/bidirectional_ch_n_to_n.go (about) 1 package ch 2 3 import ( 4 "container/heap" 5 ) 6 7 // ShortestPathManyToMany computes and returns shortest paths and theirs's costs (extended Dijkstra's algorithm) between multiple sources and targets 8 // 9 // If there are some errors then function returns '-1.0' as cost and nil as shortest path 10 // 11 // sources - set of user's definied IDs of source vertices 12 // targets - set of user's definied IDs of target vertices 13 func (graph *Graph) ShortestPathManyToMany(sources, targets []int64) ([][]float64, [][][]int64) { 14 endpoints := [directionsCount][]int64{sources, targets} 15 for d, directionEndpoints := range endpoints { 16 for i, endpoint := range directionEndpoints { 17 var ok bool 18 if endpoints[d][i], ok = graph.mapping[endpoint]; !ok { 19 endpoints[d][i] = -1 20 } 21 } 22 } 23 return graph.shortestPathManyToMany(endpoints) 24 } 25 26 func (graph *Graph) initShortestPathManyToMany(endpointCounts [directionsCount]int) (queryDist [directionsCount][]map[int64]float64, processed [directionsCount][]map[int64]bool, queues [directionsCount][]*vertexDistHeap) { 27 for d := forward; d < directionsCount; d++ { 28 queryDist[d] = make([]map[int64]float64, endpointCounts[d]) 29 processed[d] = make([]map[int64]bool, endpointCounts[d]) 30 queues[d] = make([]*vertexDistHeap, endpointCounts[d]) 31 for endpointIdx := 0; endpointIdx < endpointCounts[d]; endpointIdx++ { 32 queryDist[d][endpointIdx] = make(map[int64]float64) 33 processed[d][endpointIdx] = make(map[int64]bool) 34 queues[d][endpointIdx] = &vertexDistHeap{} 35 heap.Init(queues[d][endpointIdx]) 36 } 37 } 38 return 39 } 40 41 func (graph *Graph) shortestPathManyToMany(endpoints [directionsCount][]int64) ([][]float64, [][][]int64) { 42 queryDist, processed, queues := graph.initShortestPathManyToMany([directionsCount]int{len(endpoints[forward]), len(endpoints[backward])}) 43 for d := forward; d < directionsCount; d++ { 44 for endpointIdx, endpoint := range endpoints[d] { 45 processed[d][endpointIdx][endpoint] = true 46 queryDist[d][endpointIdx][endpoint] = 0 47 heapEndpoint := &vertexDist{ 48 id: endpoint, 49 dist: 0, 50 } 51 heap.Push(queues[d][endpointIdx], heapEndpoint) 52 } 53 } 54 return graph.shortestPathManyToManyCore(queryDist, processed, queues) 55 } 56 57 func (graph *Graph) shortestPathManyToManyCore(queryDist [directionsCount][]map[int64]float64, processed [directionsCount][]map[int64]bool, queues [directionsCount][]*vertexDistHeap) ([][]float64, [][][]int64) { 58 var prev [directionsCount][]map[int64]int64 59 for d := forward; d < directionsCount; d++ { 60 prev[d] = make([]map[int64]int64, len(queues[d])) 61 for endpointIdx := range queues[d] { 62 prev[d][endpointIdx] = make(map[int64]int64) 63 } 64 } 65 estimates := make([][]float64, len(queues[forward])) 66 middleIDs := make([][]int64, len(queues[forward])) 67 for sourceEndpointIdx := range queues[forward] { 68 sourceEstimates := make([]float64, len(queues[backward])) 69 sourceMiddleIDs := make([]int64, len(queues[backward])) 70 estimates[sourceEndpointIdx] = sourceEstimates 71 middleIDs[sourceEndpointIdx] = sourceMiddleIDs 72 for targetEndpointIdx := range queues[backward] { 73 sourceEstimates[targetEndpointIdx] = Infinity 74 sourceMiddleIDs[targetEndpointIdx] = int64(-1) 75 } 76 } 77 78 for { 79 queuesProcessed := false 80 for d := forward; d < directionsCount; d++ { 81 reverseDirection := (d + 1) % directionsCount 82 for endpointIdx := range queues[d] { 83 if queues[d][endpointIdx].Len() == 0 { 84 continue 85 } 86 queuesProcessed = true 87 graph.directionalSearchManyToMany(d, endpointIdx, queues[d][endpointIdx], processed[d][endpointIdx], processed[reverseDirection], queryDist[d][endpointIdx], queryDist[reverseDirection], prev[d][endpointIdx], estimates, middleIDs) 88 } 89 } 90 if !queuesProcessed { 91 break 92 } 93 } 94 paths := make([][][]int64, len(estimates)) 95 for sourceEndpointIdx, targetEstimates := range estimates { 96 targetPaths := make([][]int64, len(targetEstimates)) 97 paths[sourceEndpointIdx] = targetPaths 98 for targetEndpointIdx, estimate := range targetEstimates { 99 if estimate == Infinity { 100 targetEstimates[targetEndpointIdx] = -1 101 continue 102 } 103 targetPaths[targetEndpointIdx] = graph.ComputePath(middleIDs[sourceEndpointIdx][targetEndpointIdx], prev[forward][sourceEndpointIdx], prev[backward][targetEndpointIdx]) 104 } 105 } 106 return estimates, paths 107 } 108 109 func (graph *Graph) directionalSearchManyToMany(d direction, endpointIndex int, q *vertexDistHeap, localProcessed map[int64]bool, reverseProcessed []map[int64]bool, localQueryDist map[int64]float64, reverseQueryDist []map[int64]float64, prev map[int64]int64, estimates [][]float64, middleIDs [][]int64) { 110 111 vertex := heap.Pop(q).(*vertexDist) 112 // if vertex.dist <= *estimate { // TODO: move to another place 113 localProcessed[vertex.id] = true 114 // Edge relaxation in a forward propagation 115 var vertexList []incidentEdge 116 if d == forward { 117 vertexList = graph.Vertices[vertex.id].outIncidentEdges 118 } else { 119 vertexList = graph.Vertices[vertex.id].inIncidentEdges 120 } 121 for i := range vertexList { 122 temp := vertexList[i].vertexID 123 cost := vertexList[i].weight 124 if graph.Vertices[vertex.id].orderPos < graph.Vertices[temp].orderPos { 125 localDist, ok := localQueryDist[vertex.id] 126 if !ok { 127 localDist = Infinity 128 } 129 localDistTemp, ok := localQueryDist[temp] 130 if !ok { 131 localDistTemp = Infinity 132 } 133 alt := localDist + cost 134 if localDistTemp > alt { 135 localQueryDist[temp] = alt 136 prev[temp] = vertex.id 137 node := &vertexDist{ 138 id: temp, 139 dist: alt, 140 } 141 heap.Push(q, node) 142 } 143 } 144 } 145 // } 146 for revEndpointIdx, revEndpointProcessed := range reverseProcessed { 147 if revEndpointProcessed[vertex.id] { 148 var sourceEndpoint, targetEndpoint int 149 if d == forward { 150 sourceEndpoint, targetEndpoint = endpointIndex, revEndpointIdx 151 } else { 152 targetEndpoint, sourceEndpoint = endpointIndex, revEndpointIdx 153 } 154 revDist, ok := reverseQueryDist[revEndpointIdx][vertex.id] 155 if !ok { 156 revDist = Infinity 157 } 158 if vertex.dist+revDist < estimates[sourceEndpoint][targetEndpoint] { 159 middleIDs[sourceEndpoint][targetEndpoint] = vertex.id 160 estimates[sourceEndpoint][targetEndpoint] = vertex.dist + revDist 161 } 162 } 163 } 164 } 165 166 // ShortestPathManyToManyWithAlternatives Computes and returns shortest paths and their cost (extended Dijkstra's algorithm), 167 // with multiple alternatives for source and target vertices with additional distances to reach the vertices 168 // (useful if source and target are outside of the graph) 169 // 170 // If there are some errors then function returns '-1.0' as cost and nil as shortest path 171 // 172 // sourcesAlternatives - set of user's definied IDs of source vertices with additional penalty 173 // targetsAlternatives - set of user's definied IDs of target vertices with additional penalty 174 func (graph *Graph) ShortestPathManyToManyWithAlternatives(sourcesAlternatives, targetsAlternatives [][]VertexAlternative) ([][]float64, [][][]int64) { 175 endpoints := [directionsCount][][]VertexAlternative{sourcesAlternatives, targetsAlternatives} 176 var endpointsInternal [directionsCount][][]vertexAlternativeInternal 177 for d, directionEndpoints := range endpoints { 178 endpointsInternal[d] = make([][]vertexAlternativeInternal, 0, len(directionEndpoints)) 179 for _, alternatives := range directionEndpoints { 180 endpointsInternal[d] = append(endpointsInternal[d], graph.vertexAlternativesToInternal(alternatives)) 181 } 182 } 183 return graph.shortestPathManyToManyWithAlternatives(endpointsInternal) 184 } 185 186 func (graph *Graph) shortestPathManyToManyWithAlternatives(endpoints [directionsCount][][]vertexAlternativeInternal) ([][]float64, [][][]int64) { 187 queryDist, processed, queues := graph.initShortestPathManyToMany([directionsCount]int{len(endpoints[0]), len(endpoints[1])}) 188 for d := forward; d < directionsCount; d++ { 189 for endpointIdx, endpointAlternatives := range endpoints[d] { 190 for _, endpointAlternative := range endpointAlternatives { 191 if endpointAlternative.vertexNum == vertexNotFound { 192 continue 193 } 194 processed[d][endpointIdx][endpointAlternative.vertexNum] = true 195 queryDist[d][endpointIdx][endpointAlternative.vertexNum] = endpointAlternative.additionalDistance 196 heapEndpoint := &vertexDist{ 197 id: endpointAlternative.vertexNum, 198 dist: endpointAlternative.additionalDistance, 199 } 200 heap.Push(queues[d][endpointIdx], heapEndpoint) 201 } 202 } 203 } 204 return graph.shortestPathManyToManyCore(queryDist, processed, queues) 205 }