-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathGR4.swift
105 lines (95 loc) · 3.59 KB
/
GR4.swift
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
//
// GR4.swift
// AlgorithmsSwift
//
// Created by Michael Ho on 10/29/20.
//
class GR4 {
/**
PageRank (PR) is an algorithm used by Google to rank their search engine results. PR works by counting the number and quality of
links to a page to estimate how important the website is. For example, page A has 3 incoming links, page B has 2 outgoing links,
page C has 1 outgoing link, and page D has 3 outgoing links. In such case, the PageRank of A can be calculated by
Page(A) = Page(B) / 2 + Page(C) / 1 + Page(D) / 3. Besides, the below function applies damping factor = 0.85 (generally used).
- Parameter webGraph: The web graph used to calculate PageRank.
- Returns: A set of web pages.
*/
func performPageRank(_ webGraph: WebGraph) -> [Int] {
guard let webAdjacencyLists = webGraph.adjacencyLists as? [Webpage : Set<Edge>] else {
print("No valid adjacency list is found in web graph.")
return []
}
// Set initial values
let webCount = Double(webAdjacencyLists.keys.count)
for webpage in webAdjacencyLists.keys {
webpage.rank = 1/webCount
}
// Calculate PageRank
let damping = 0.85
for _ in 0..<100 {
for webpage in webAdjacencyLists.keys {
var inbound: Double = 0
for otherWebpage in webAdjacencyLists.keys {
let edgeCount = Double(webAdjacencyLists[otherWebpage]!.count)
for edge in webAdjacencyLists[otherWebpage]! {
if(edge.dest == webpage){
inbound += otherWebpage.rank / edgeCount
}
}
}
webpage.rank = (1 - damping) / webCount + damping * inbound
}
}
return webAdjacencyLists.keys.sorted { $0.rank > $1.rank }.map { (webpage) -> Int in
return webpage.val
}
}
}
class Webpage: Vertex {
var rank: Double = 0
static func == (lhs: Webpage, rhs: Webpage) -> Bool {
return lhs.val == rhs.val && lhs.rank == rhs.rank
}
}
class WebGraph: Graph {
// The adjacencyList used to override the adjacencyLists in Graph class.
private var _adjacencyLists: [Webpage : Set<Edge>]
override var adjacencyLists: [Vertex : Set<Edge>] {
get {
return _adjacencyLists
}
set {
guard let newLists = newValue as? [Webpage : Set<Edge>] else {
fatalError("Adjacency list has to be in type of [Webpage : Set<Edge>].")
}
_adjacencyLists = newLists
}
}
/**
Initializer. Only directed graph is allowed in web graph.
*/
public convenience init() {
self.init(isDirected: true)
}
private override init(isDirected: Bool = true) {
_adjacencyLists = [Webpage : Set<Edge>]()
super.init(isDirected: isDirected)
}
/**
Add edge to the graph.
- Parameter from: The source/start of the edge.
- Parameter to: The destination/end of the edge.
- Parameter weight: The weight of the edge.
*/
override func addEdge(from: Int, to: Int, weight: Int = 0) {
let web1 = Webpage(from)
let web2 = Webpage(to)
let edge = Edge(web1, web2, weight)
if _adjacencyLists[web1] == nil {
_adjacencyLists[web1] = Set<Edge>()
}
_adjacencyLists[web1]!.insert(edge)
if _adjacencyLists[web2] == nil {
_adjacencyLists[web2] = Set<Edge>()
}
}
}