github.com/LdDl/ch@v1.7.8/dijkstra_bidirectional.go (about)

     1  package ch
     2  
     3  import (
     4  	"container/heap"
     5  	"container/list"
     6  )
     7  
     8  type direction int
     9  
    10  const (
    11  	forward direction = iota
    12  	backward
    13  	directionsCount
    14  )
    15  
    16  // ShortestPath Computes and returns shortest path and it's cost (extended Dijkstra's algorithm)
    17  //
    18  // If there are some errors then function returns '-1.0' as cost and nil as shortest path
    19  //
    20  // source - user's definied ID of source vertex
    21  // target - user's definied ID of target vertex
    22  func (graph *Graph) ShortestPath(source, target int64) (float64, []int64) {
    23  	if source == target {
    24  		return 0, []int64{source}
    25  	}
    26  	endpoints := [directionsCount]int64{source, target}
    27  	for d, endpoint := range endpoints {
    28  		var ok bool
    29  		if endpoints[d], ok = graph.mapping[endpoint]; !ok {
    30  			return -1.0, nil
    31  		}
    32  	}
    33  	return graph.shortestPath(endpoints)
    34  }
    35  
    36  func (graph *Graph) initShortestPath() (queryDist [directionsCount][]float64, processed [directionsCount][]bool, queues [directionsCount]*vertexDistHeap) {
    37  	for d := forward; d < directionsCount; d++ {
    38  		queryDist[d] = make([]float64, len(graph.Vertices))
    39  		for i := range queryDist[d] {
    40  			queryDist[d][i] = Infinity
    41  		}
    42  		processed[d] = make([]bool, len(graph.Vertices))
    43  		queues[d] = &vertexDistHeap{}
    44  		heap.Init(queues[d])
    45  	}
    46  	return
    47  }
    48  
    49  func (graph *Graph) shortestPath(endpoints [directionsCount]int64) (float64, []int64) {
    50  	queryDist, processed, queues := graph.initShortestPath()
    51  	for d := forward; d < directionsCount; d++ {
    52  		processed[d][endpoints[d]] = true
    53  		queryDist[d][endpoints[d]] = 0
    54  		heapEndpoint := &vertexDist{
    55  			id:   endpoints[d],
    56  			dist: 0,
    57  		}
    58  		heap.Push(queues[d], heapEndpoint)
    59  	}
    60  	return graph.shortestPathCore(queryDist, processed, queues)
    61  }
    62  
    63  func (graph *Graph) shortestPathCore(queryDist [directionsCount][]float64, processed [directionsCount][]bool, queues [directionsCount]*vertexDistHeap) (float64, []int64) {
    64  	var prev [directionsCount]map[int64]int64
    65  	for d := forward; d < directionsCount; d++ {
    66  		prev[d] = make(map[int64]int64)
    67  	}
    68  	estimate := Infinity
    69  	middleID := int64(-1)
    70  	for {
    71  		queuesProcessed := false
    72  		for d := forward; d < directionsCount; d++ {
    73  			if queues[d].Len() == 0 {
    74  				continue
    75  			}
    76  			queuesProcessed = true
    77  			reverseDirection := (d + 1) % directionsCount
    78  			graph.directionalSearch(d, queues[d], processed[d], processed[reverseDirection], queryDist[d], queryDist[reverseDirection], prev[d], &estimate, &middleID)
    79  		}
    80  		if !queuesProcessed {
    81  			break
    82  		}
    83  	}
    84  	if estimate == Infinity {
    85  		return -1.0, nil
    86  	}
    87  	return estimate, graph.ComputePath(middleID, prev[forward], prev[backward])
    88  }
    89  
    90  func (graph *Graph) directionalSearch(d direction, q *vertexDistHeap, localProcessed, reverseProcessed []bool, localQueryDist, reverseQueryDist []float64, prev map[int64]int64, estimate *float64, middleID *int64) {
    91  	vertex := heap.Pop(q).(*vertexDist)
    92  	if vertex.dist <= *estimate {
    93  		localProcessed[vertex.id] = true
    94  		// Edge relaxation in a forward propagation
    95  		var vertexList []incidentEdge
    96  		if d == forward {
    97  			vertexList = graph.Vertices[vertex.id].outIncidentEdges
    98  		} else {
    99  			vertexList = graph.Vertices[vertex.id].inIncidentEdges
   100  		}
   101  		for i := range vertexList {
   102  			temp := vertexList[i].vertexID
   103  			cost := vertexList[i].weight
   104  			if graph.Vertices[vertex.id].orderPos < graph.Vertices[temp].orderPos {
   105  				alt := localQueryDist[vertex.id] + cost
   106  				if localQueryDist[temp] > alt {
   107  					localQueryDist[temp] = alt
   108  					prev[temp] = vertex.id
   109  					node := &vertexDist{
   110  						id:   temp,
   111  						dist: alt,
   112  					}
   113  					heap.Push(q, node)
   114  				}
   115  			}
   116  		}
   117  	}
   118  	if reverseProcessed[vertex.id] {
   119  		if vertex.dist+reverseQueryDist[vertex.id] < *estimate {
   120  			*middleID = vertex.id
   121  			*estimate = vertex.dist + reverseQueryDist[vertex.id]
   122  		}
   123  	}
   124  }
   125  
   126  // ShortestPathWithAlternatives Computes and returns shortest path and it's cost (extended Dijkstra's algorithm),
   127  // with multiple alternatives for source and target vertices with additional distances to reach the vertices
   128  // (useful if source and target are outside of the graph)
   129  //
   130  // If there are some errors then function returns '-1.0' as cost and nil as shortest path
   131  //
   132  // sources - user's definied ID of source vertex with additional penalty
   133  // targets - user's definied ID of target vertex with additional penalty
   134  func (graph *Graph) ShortestPathWithAlternatives(sources, targets []VertexAlternative) (float64, []int64) {
   135  	endpoints := [directionsCount][]VertexAlternative{sources, targets}
   136  	var endpointsInternal [directionsCount][]vertexAlternativeInternal
   137  	for d, alternatives := range endpoints {
   138  		endpointsInternal[d] = graph.vertexAlternativesToInternal(alternatives)
   139  	}
   140  	return graph.shortestPathWithAlternatives(endpointsInternal)
   141  }
   142  
   143  func (graph *Graph) shortestPathWithAlternatives(endpoints [directionsCount][]vertexAlternativeInternal) (float64, []int64) {
   144  	queryDist, processed, queues := graph.initShortestPath()
   145  	for d := forward; d < directionsCount; d++ {
   146  		for _, endpoint := range endpoints[d] {
   147  			if endpoint.vertexNum == vertexNotFound {
   148  				continue
   149  			}
   150  			processed[d][endpoint.vertexNum] = true
   151  			queryDist[d][endpoint.vertexNum] = endpoint.additionalDistance
   152  			heapEndpoint := &vertexDist{
   153  				id:   endpoint.vertexNum,
   154  				dist: endpoint.additionalDistance,
   155  			}
   156  			heap.Push(queues[d], heapEndpoint)
   157  		}
   158  	}
   159  	return graph.shortestPathCore(queryDist, processed, queues)
   160  }
   161  
   162  // ComputePath Returns slice of IDs (user defined) of computed path
   163  func (graph *Graph) ComputePath(middleID int64, forwardPrev, backwardPrev map[int64]int64) []int64 {
   164  	l := list.New()
   165  	l.PushBack(middleID)
   166  	u := middleID
   167  	var ok bool
   168  	for {
   169  		if u, ok = forwardPrev[u]; ok {
   170  			l.PushFront(u)
   171  		} else {
   172  			break
   173  		}
   174  	}
   175  	u = middleID
   176  	for {
   177  		if u, ok = backwardPrev[u]; ok {
   178  			l.PushBack(u)
   179  		} else {
   180  			break
   181  		}
   182  	}
   183  	ok = true
   184  	for ok {
   185  		ok = false
   186  		for e := l.Front(); e.Next() != nil; e = e.Next() {
   187  			if contractedNode, ok2 := graph.shortcuts[e.Value.(int64)][e.Next().Value.(int64)]; ok2 {
   188  				ok = true
   189  				l.InsertAfter(contractedNode.Via, e)
   190  			}
   191  		}
   192  	}
   193  
   194  	var path = make([]int64, 0, l.Len())
   195  	for e := l.Front(); e != nil; e = e.Next() {
   196  		path = append(path, graph.Vertices[e.Value.(int64)].Label)
   197  	}
   198  
   199  	return path
   200  }