-
Notifications
You must be signed in to change notification settings - Fork 0
/
Dijkstra.fs
80 lines (69 loc) · 2.41 KB
/
Dijkstra.fs
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
module Dijkstra
type Distance = int
type NodeInfo<'T when 'T : comparison> = {
NodeID: 'T
Cost: Distance
}
let nodeInfo id cost = {
NodeID = id
Cost = cost
}
type EdgeInfo<'T when 'T : comparison> = Map<'T, ('T * Distance) list>
type private UnvisitedNode<'T when 'T : comparison> = {
Node: NodeInfo<'T>
CurrentDistance: Distance
}
type VisitedNode<'T when 'T : comparison> = {
NodeID: 'T
Distance: Distance
}
let private visitedNode id distance = {
NodeID = id
Distance = distance
}
let private cons x y = x :: y
let private addDist dist node =
{Node = node; CurrentDistance = dist}
let rec private fillAcc (neighbourInfo: EdgeInfo<'T>) visited unvisited =
match unvisited with
| [] -> visited
| _ ->
let {Node = {NodeID = nextNodeID; Cost = nextCost}; CurrentDistance = nextDist} =
List.minBy (fun {CurrentDistance = dist} -> dist) unvisited
let nextNeighbours =
neighbourInfo
|> Map.find nextNodeID
|> List.filter (fun (curr, _) -> List.forall (fun fin -> fin.NodeID <> curr) visited)
let nextAndNeighbourIDs =
nextNeighbours
|> List.map (fun (id, _) -> id)
|> cons nextNodeID
let unvisitedWithoutNextAndNeighbours =
unvisited
|> List.filter
(fun {Node = {NodeID = itemNodeID}} ->
nextAndNeighbourIDs
|> List.contains itemNodeID
|> not
)
let neighbourEntries =
nextNeighbours
|> List.map (fun (id, cost) ->
{NodeID = id; Cost = cost}
|> addDist (nextDist + nextCost)
)
let minCostNeighbourAppearances =
nextNeighbours
|> List.map (fun (id, _) ->
(unvisited @ neighbourEntries)
|> List.filter (fun {Node = {NodeID = y}} -> y = id)
|> List.minBy (fun {CurrentDistance = dist} -> dist))
fillAcc neighbourInfo ((visitedNode nextNodeID nextDist) :: visited) (unvisitedWithoutNextAndNeighbours @ minCostNeighbourAppearances)
let fill (nodes: NodeInfo<'T> list) edges destinations =
nodes
|> List.choose (fun nodeInfo ->
match (List.contains nodeInfo.NodeID destinations) with
| true -> Some (addDist 0 nodeInfo)
| false -> None
)
|> fillAcc edges []