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  }