github.com/LdDl/ch@v1.7.8/graph.go (about) 1 package ch 2 3 import ( 4 "container/heap" 5 "fmt" 6 "log" 7 ) 8 9 // Graph Graph object 10 // 11 // mapping Internal map for 1:1 relation of internal IDs to user's IDs 12 // Vertices Slice of vertices of graph 13 // shortcuts Found and stored shortcuts based on contraction hierarchies 14 // 15 type Graph struct { 16 shortcuts map[int64]map[int64]*ShortcutPath 17 restrictions map[int64]map[int64]int64 18 mapping map[int64]int64 19 20 Vertices []Vertex 21 edgesNum int64 22 shortcutsNum int64 23 24 frozen bool 25 verbose bool 26 } 27 28 // NewGraph returns pointer to created Graph and does preallocations for processing purposes 29 func NewGraph() *Graph { 30 return &Graph{ 31 mapping: make(map[int64]int64), 32 Vertices: make([]Vertex, 0), 33 edgesNum: 0, 34 shortcutsNum: 0, 35 shortcuts: make(map[int64]map[int64]*ShortcutPath), 36 restrictions: make(map[int64]map[int64]int64), 37 frozen: false, 38 verbose: false, 39 } 40 } 41 42 // CreateVertex Creates new vertex and assign internal ID to it 43 // 44 // label User's definied ID of vertex 45 // 46 func (graph *Graph) CreateVertex(label int64) error { 47 if graph.frozen { 48 return ErrGraphIsFrozen 49 } 50 v := Vertex{ 51 Label: label, 52 delNeighbors: 0, 53 distance: NewDistance(), 54 contracted: false, 55 } 56 if graph.mapping == nil { 57 graph.mapping = make(map[int64]int64) 58 } 59 if graph.shortcuts == nil { 60 graph.shortcuts = make(map[int64]map[int64]*ShortcutPath) 61 } 62 63 if _, ok := graph.mapping[label]; !ok { 64 v.vertexNum = int64(len(graph.Vertices)) 65 graph.mapping[label] = v.vertexNum 66 graph.Vertices = append(graph.Vertices, v) 67 } 68 return nil 69 } 70 71 // AddEdge Adds new edge between two vertices 72 // 73 // from User's definied ID of first vertex of edge 74 // to User's definied ID of last vertex of edge 75 // weight User's definied weight of edge 76 // 77 func (graph *Graph) AddEdge(from, to int64, weight float64) error { 78 if graph.frozen { 79 return ErrGraphIsFrozen 80 } 81 graph.edgesNum++ 82 from = graph.mapping[from] 83 to = graph.mapping[to] 84 85 graph.addEdge(from, to, weight) 86 return nil 87 } 88 89 func (graph *Graph) addEdge(from, to int64, weight float64) { 90 graph.Vertices[from].outIncidentEdges = append(graph.Vertices[from].outIncidentEdges, incidentEdge{vertexID: to, weight: weight}) 91 graph.Vertices[to].inIncidentEdges = append(graph.Vertices[to].inIncidentEdges, incidentEdge{vertexID: from, weight: weight}) 92 } 93 94 // AddShortcut Adds new shortcut between two vertices 95 // 96 // from - User's definied ID of first vertex of shortcut 97 // to - User's definied ID of last vertex of shortcut 98 // via - User's defined ID of vertex through which the shortcut exists 99 // weight - User's definied weight of shortcut 100 // 101 func (graph *Graph) AddShortcut(from, to, via int64, weight float64) error { 102 if graph.frozen { 103 return ErrGraphIsFrozen 104 } 105 fromInternal := graph.mapping[from] 106 toInternal := graph.mapping[to] 107 viaInternal := graph.mapping[via] 108 if _, ok := graph.shortcuts[fromInternal]; !ok { 109 graph.shortcuts[fromInternal] = make(map[int64]*ShortcutPath) 110 graph.shortcuts[fromInternal][toInternal] = &ShortcutPath{ 111 From: fromInternal, 112 To: toInternal, 113 Via: viaInternal, 114 Cost: weight, 115 } 116 } 117 graph.shortcuts[fromInternal][toInternal] = &ShortcutPath{ 118 From: fromInternal, 119 To: toInternal, 120 Via: viaInternal, 121 Cost: weight, 122 } 123 graph.shortcutsNum++ 124 return nil 125 } 126 127 // PrepareContractionHierarchies Compute contraction hierarchies 128 func (graph *Graph) PrepareContractionHierarchies() { 129 pqImportance := graph.computeImportance() 130 graph.Preprocess(pqImportance) 131 graph.Freeze() 132 } 133 134 // SetVerbose sets verbose parameter for debugging purposes 135 func (graph *Graph) SetVerbose(flag bool) { 136 graph.verbose = flag 137 } 138 139 // computeImportance Returns heap to store computed importance of each vertex 140 func (graph *Graph) computeImportance() *importanceHeap { 141 pqImportance := &importanceHeap{} 142 heap.Init(pqImportance) 143 for i := range graph.Vertices { 144 graph.Vertices[i].computeImportance() 145 heap.Push(pqImportance, &graph.Vertices[i]) 146 } 147 graph.Freeze() 148 return pqImportance 149 } 150 151 // Freeze Freeze graph. Should be called after contraction hierarchies had been prepared. 152 func (graph *Graph) Freeze() { 153 graph.frozen = true 154 } 155 156 // Unfreeze Freeze graph. Should be called if graph modification is needed. 157 func (graph *Graph) Unfreeze() { 158 fmt.Println("Warning: You will need to call PrepareContractionHierarchies() or even refresh graph again if you want to modify graph data") 159 graph.frozen = false 160 } 161 162 // GetVerticesNum Returns number of vertices in graph 163 func (graph *Graph) GetVerticesNum() int64 { 164 return int64(len(graph.Vertices)) 165 } 166 167 // GetShortcutsNum Returns number of shortcuts in graph 168 func (graph *Graph) GetShortcutsNum() int64 { 169 return int64(graph.shortcutsNum) 170 } 171 172 // GetEdgesNum Returns number of edges in graph 173 func (graph *Graph) GetEdgesNum() int64 { 174 return graph.edgesNum 175 } 176 177 // AddTurnRestriction Adds new turn restriction between two vertices via some other vertex 178 // 179 // from User's definied ID of source vertex 180 // via User's definied ID of prohibited vertex (between source and target) 181 // to User's definied ID of target vertex 182 // 183 func (graph *Graph) AddTurnRestriction(from, via, to int64) error { 184 if graph.frozen { 185 return ErrGraphIsFrozen 186 } 187 188 from = graph.mapping[from] 189 via = graph.mapping[via] 190 to = graph.mapping[to] 191 192 if graph.restrictions == nil { 193 graph.restrictions = make(map[int64]map[int64]int64) 194 } 195 196 if _, ok := graph.restrictions[from]; !ok { 197 graph.restrictions[from] = make(map[int64]int64) 198 if _, ok := graph.restrictions[from][via]; ok { 199 log.Printf("Warning: Please notice, library supports only one 'from-via' relation currently. From %d Via %d\n", from, via) 200 } 201 graph.restrictions[from][via] = to 202 } 203 return nil 204 }