This repository has been archived by the owner on Feb 23, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
247 lines (204 loc) · 5.24 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package main
import (
"container/heap"
"encoding/csv"
"fmt"
"io"
"log"
"math"
"os"
"strconv"
"strings"
"time"
)
type Edge struct {
in int
out int
weight float64
}
type Node struct {
edges []*Edge
value NodeValue
}
func (n *Node) addEdge(from_idx int, to_idx int, weight float64) {
n.edges = append(n.edges, &Edge{from_idx, to_idx, weight})
}
type NodeValue struct {
x float64
y float64
}
type Graph struct {
nodes []*Node
}
func (g *Graph) addNode(node *Node) int {
g.nodes = append(g.nodes, node)
return len(g.nodes) - 1
}
func (g *Graph) addEdgeBidirectional(from_idx int, to_idx int, weight float64) {
g.addEdge(from_idx, to_idx, weight)
g.addEdge(to_idx, from_idx, weight)
}
func (g *Graph) addEdge(from_idx int, to_idx int, weight float64) {
node := g.nodes[from_idx]
node.addEdge(from_idx, to_idx, weight)
}
func (g *Graph) print() {
fmt.Println("Nodes: ", len(g.nodes))
for i, n := range g.nodes {
fmt.Println(i, ": ", n.value)
for _, e := range n.edges {
fmt.Println(e.in, " -> ", e.out, " ", e.weight)
}
}
}
func euclidean(a NodeValue, b NodeValue) float64 {
return math.Sqrt(math.Pow(a.x-b.x, 2) + math.Pow(a.y-b.y, 2))
}
type AStarPQElement struct {
curr_index int
prev_index int
cost_to_come float64
cost_to_go float64
Index int
}
type AStarVisitedElement struct {
prev_idx int
cost_to_come float64
}
type AStarResult struct {
path []int
path_len float64
visited_count int
}
type PriorityQueue []*AStarPQElement
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].cost_to_come+pq[i].cost_to_go < pq[j].cost_to_come+pq[j].cost_to_go
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
item.Index = -1
*pq = old[0 : n-1]
return item
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*AStarPQElement)
item.Index = n
*pq = append(*pq, item)
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].Index = i
pq[j].Index = j
}
func reverse(a []int) []int {
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
return a
}
func (g *Graph) extractAStarSolution(start_idx int, goal_idx int, visited map[int]AStarVisitedElement, num_visited int) AStarResult {
path := []int{goal_idx}
prev, _ := visited[goal_idx]
pathlen := prev.cost_to_come
// this is poorly written lol
for prev.prev_idx != start_idx {
curr := prev
path = append(path, curr.prev_idx)
prev, _ = visited[curr.prev_idx]
}
path = append(path, start_idx)
return AStarResult{reverse(path), pathlen, num_visited}
}
func (g *Graph) AStarSearch(start_idx int, goal_idx int, h func(NodeValue, NodeValue) float64) AStarResult {
start := g.nodes[start_idx].value
goal := g.nodes[goal_idx].value
// Create priority queue
pq := PriorityQueue{}
heap.Init(&pq)
// Create visited map
visited := make(map[int]AStarVisitedElement)
numVisited := 0
heap.Push(&pq, &AStarPQElement{start_idx, -1, 0.0, h(start, goal), 0})
for pq.Len() > 0 {
best := heap.Pop(&pq).(*AStarPQElement)
numVisited++
seen, found := visited[best.curr_index]
better := false
if found && best.cost_to_come < seen.cost_to_come {
better = true
}
if !found || better {
visited[best.curr_index] = AStarVisitedElement{best.prev_index, best.cost_to_come}
if best.curr_index == goal_idx {
break
}
parent := g.nodes[best.curr_index]
for _, edge := range parent.edges {
childCostToCome := best.cost_to_come + edge.weight
child, childFound := visited[edge.out]
childBetter := false
if childFound && childCostToCome < child.cost_to_come {
childBetter = true
}
if !childFound || childBetter {
heap.Push(&pq, &AStarPQElement{edge.out, best.curr_index, childCostToCome, h(g.nodes[edge.out].value, goal), 0})
}
}
}
}
return g.extractAStarSolution(start_idx, goal_idx, visited, numVisited)
}
func main() {
g := Graph{}
node_file, err := os.Open("./data/cal.cnode")
if err != nil {
log.Fatalln("Couldn't open the node file", err)
}
r := csv.NewReader(node_file)
for {
// seems like a bad pattern
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
// also seems bad lol
record = strings.Split(record[0], " ")
long, _ := strconv.ParseFloat(record[1], 64)
lat, _ := strconv.ParseFloat(record[2], 64)
g.addNode(&Node{[]*Edge{}, NodeValue{lat, long}})
}
edge_file, err := os.Open("./data/cal.cedge")
if err != nil {
log.Fatalln("Couldn't open the edge file", err)
}
r = csv.NewReader(edge_file)
for {
// seems like a bad pattern
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
// also seems bad lol
record = strings.Split(record[0], " ")
idx_one, _ := strconv.ParseInt(record[1], 10, 32)
idx_two, _ := strconv.ParseInt(record[2], 10, 32)
weight, _ := strconv.ParseFloat(record[3], 64)
g.addEdgeBidirectional(int(idx_one), int(idx_two), weight)
}
start := time.Now()
res := g.AStarSearch(7261, 20286, euclidean)
fmt.Println("Finished search in : ", time.Now().Sub(start))
fmt.Println("Nodes visited: ", res.visited_count)
fmt.Println("Path len: ", res.path_len)
fmt.Println("Path: ", res.path)
}