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

     1  package ch
     2  
     3  import (
     4  	"container/heap"
     5  	"log"
     6  )
     7  
     8  // VanillaTurnRestrictedShortestPath Computes and returns turns restricted shortest path and it's cost (vanilla Dijkstra's algorithm)
     9  //
    10  // If there are some errors then function returns '-1.0' as cost and nil as shortest path
    11  //
    12  // source User's definied ID of source vertex
    13  // target User's definied ID of target vertex
    14  //
    15  // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
    16  func (graph *Graph) VanillaTurnRestrictedShortestPath(source, target int64) (float64, []int64) {
    17  
    18  	if source == target {
    19  		return 0, []int64{source}
    20  	}
    21  	var ok bool
    22  
    23  	if source, ok = graph.mapping[source]; !ok {
    24  		log.Println("No such source")
    25  		return -1.0, nil
    26  	}
    27  	if target, ok = graph.mapping[target]; !ok {
    28  		log.Println("No such target")
    29  		return -1.0, nil
    30  	}
    31  
    32  	// create vertex set Q
    33  	Q := &minHeap{}
    34  
    35  	// dist[source] ← 0
    36  	distance := make(map[int64]float64, len(graph.Vertices))
    37  	distance[source] = 0
    38  
    39  	// prev[v] ← UNDEFINED
    40  	prev := make(map[int64]int64, len(graph.Vertices))
    41  	// st := time.Now()
    42  	// for each vertex v in Graph:
    43  	for i := range graph.Vertices {
    44  		// if v ≠ source:
    45  		if graph.Vertices[i].vertexNum != source {
    46  			// dist[v] = INFINITY
    47  			distance[graph.Vertices[i].vertexNum] = Infinity
    48  		}
    49  		// prev[v] ← UNDEFINED
    50  		// nothing here
    51  	}
    52  	Q.add_with_priority(graph.Vertices[source].vertexNum, distance[graph.Vertices[source].vertexNum])
    53  	heap.Init(Q)
    54  	prevNodeID := int64(-1)
    55  	// while Q is not empty:
    56  	for Q.Len() != 0 {
    57  		// u ← Q.extract_min()
    58  		u := heap.Pop(Q).(*minHeapVertex)
    59  		destinationRestrictionID := int64(-1)
    60  		if restrictions, ok := graph.restrictions[prevNodeID]; ok {
    61  			// found some restrictions
    62  			destinationRestrictionID = restrictions[u.id]
    63  		}
    64  
    65  		// if u == target:
    66  		if u.id == target {
    67  			// break
    68  			break
    69  		}
    70  
    71  		vertexList := graph.Vertices[u.id].outIncidentEdges
    72  
    73  		// for each neighbor v of u:
    74  		for v := range vertexList {
    75  			neighbor := vertexList[v].vertexID
    76  			if v1, ok1 := graph.shortcuts[u.id]; ok1 {
    77  				if _, ok2 := v1[neighbor]; ok2 {
    78  					// Ignore shortcut
    79  					continue
    80  				}
    81  			}
    82  			if neighbor == destinationRestrictionID {
    83  				// If there is a turn restriction
    84  				distance[u.id] = Infinity
    85  				continue
    86  			}
    87  			cost := vertexList[v].weight
    88  			// alt ← dist[u] + length(u, v)
    89  			alt := distance[u.id] + cost
    90  			// if alt < dist[v]
    91  			if distance[neighbor] > alt {
    92  				// dist[v] ← alt
    93  				distance[neighbor] = alt
    94  				// prev[v] ← u
    95  				prev[neighbor] = u.id
    96  				// Q.decrease_priority(v, alt)
    97  				// Q.decrease_priority(v, alt)
    98  				Q.add_with_priority(neighbor, alt)
    99  			}
   100  		}
   101  
   102  		prevNodeID = u.id
   103  		// heap.Init(Q)
   104  	}
   105  
   106  	// path = []
   107  	var path []int64
   108  	// u = target
   109  	u := target
   110  
   111  	// while prev[u] is defined:
   112  	for {
   113  		if _, ok := prev[u]; !ok {
   114  			break
   115  		}
   116  		// path.push_front(u)
   117  		temp := make([]int64, len(path)+1)
   118  		temp[0] = u
   119  		copy(temp[1:], path)
   120  		path = temp
   121  
   122  		// u = prev[u]
   123  		u = prev[u]
   124  	}
   125  
   126  	temp := make([]int64, len(path)+1)
   127  	temp[0] = source
   128  	copy(temp[1:], path)
   129  	path = temp
   130  
   131  	usersLabelsPath := make([]int64, len(path))
   132  	for e := 0; e < len(usersLabelsPath); e++ {
   133  		usersLabelsPath[e] = graph.Vertices[path[e]].Label
   134  	}
   135  
   136  	return distance[target], usersLabelsPath
   137  }