-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpageRank.c
More file actions
348 lines (297 loc) · 9.86 KB
/
Copy pathpageRank.c
File metadata and controls
348 lines (297 loc) · 9.86 KB
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
// Written by Robert Parton
// 17 November 2022
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Graph.h"
#include "List.h"
#define MAX_STRLEN 100
List readCollectionFile();
Graph createGraph(List l);
static void insertEdges(Graph g, List l, FILE *fp, char *url, Node curr);
static int getUrlIndex(List l, char *url);
List calculatePageRank(List l, Graph g, double d, double diffPR,
int maxIterations);
static double getPageWeight(List l, Graph g, Graph gWin, Graph gWout, Node pi);
static void initialiseRankAndDegree(List l, Graph g, double N);
static double calculateDiff(List l);
static Graph setGraphWin(List l, Graph g);
static Graph setGraphWout(List l, Graph g);
static double calculateWin(List l, Graph g, Node pj, Node pi);
static double incomingDegree(Graph g, int urlA);
static double calculateWout(List l, Graph g, Node pj, Node pi);
static double outgoingDegree(Graph g, int urlA);
static bool isAdjacent(Graph g, int v, int w);
static Node getNode(List l, int index);
int main(int argc, char *argv[]) {
if (argc != 4) {
fprintf(stderr, "Usage: %s dampingFactor diffPR maxIterations\n",
argv[0]);
return EXIT_FAILURE;
}
// Convert inputs from strings to integers
double d = atof(argv[1]);
double diffPR = atof(argv[2]);
int maxIterations = atoi(argv[3]);
// Read URLs and store in a Linked List
List urlList = readCollectionFile();
// Create Graph Matrix for urlList
Graph urlGraph = createGraph(urlList);
// Calculate the page ranks for each url
urlList = calculatePageRank(urlList, urlGraph, d, diffPR, maxIterations);
ListSort(urlList);
ListPrint(urlList);
ListFree(urlList);
GraphFree(urlGraph);
return 0;
}
//
// Helper Functions
//
// Reads the collection.txt file and creates a Linked List containing the URLs
List readCollectionFile() {
List urlList = ListNew();
FILE *fp = fopen("collection.txt", "r");
if (fp == NULL) {
fprintf(stderr, "fopen\n");
exit(EXIT_FAILURE);
}
// Create the linked list to store the urls
char *url = malloc(MAX_STRLEN * sizeof(char) + 1);
if (url == NULL) {
fprintf(stderr, "error: out of memory\n");
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%s", url) != EOF) {
ListAppend(urlList, url);
}
free(url);
fclose(fp);
if (urlList->head == NULL) {
ListFree(urlList);
return NULL;
}
return urlList;
}
Graph createGraph(List l) {
Graph g = GraphNew(l->size);
// Allocate memory the url filename string
char *filename = malloc((MAX_STRLEN + strlen(".txt") + 1) * sizeof(char));
if (filename == NULL) {
fprintf(stderr, "error: out of memory\n");
exit(EXIT_FAILURE);
}
char *url = malloc(MAX_STRLEN * sizeof(char) + 1);
if (url == NULL) {
fprintf(stderr, "error: out of memory\n");
exit(EXIT_FAILURE);
}
for (Node curr = l->head; curr != NULL; curr = curr->next) {
// Create a url node for each filename
strcpy(filename, curr->url);
strcat(filename, ".txt");
// Open the url's file
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "fopen");
exit(EXIT_FAILURE);
}
// Insert all the edges
insertEdges(g, l, fp, url, curr);
}
free(filename);
free(url);
return g;
}
// Reads a url.txt file and inserts all edges the url is adjacent to
static void insertEdges(Graph g, List l, FILE *fp, char *url, Node curr) {
// Move fp to be after the first line
char buffer[MAX_STRLEN];
fgets(buffer, MAX_STRLEN, fp);
int file_offset = strlen(buffer);
fseek(fp, file_offset, SEEK_SET);
// Read strings until we read #end
while (fscanf(fp, "%s", url) != EOF) {
if (strcmp(url, "#end") == 0) break;
int outlinkIndex = getUrlIndex(l, url);
if (outlinkIndex >= 0 && outlinkIndex != curr->index) {
Edge e = {curr->index, outlinkIndex, 1};
GraphInsertEdge(g, e);
}
}
}
// Returns the index for url string
static int getUrlIndex(List l, char *url) {
for (Node n = l->head; n != NULL; n = n->next) {
if (strcmp(url, n->url) == 0) {
return n->index;
}
}
return -1;
}
// Calculates page ranks for each url using the given formula
List calculatePageRank(List l, Graph g, double d, double diffPR,
int maxIterations) {
double N = g->nV;
// calculate iteration 0 rank, incoming and outgoing degree
initialiseRankAndDegree(l, g, N);
// Create graphs containing the Win and Wout values for each edge
Graph gWin = setGraphWin(l, g);
Graph gWout = setGraphWout(l, g);
double diff = diffPR;
for (int i = 1; i < maxIterations && diff >= diffPR; i++) {
// store the previous rank
for (Node pi = l->head; pi != NULL; pi = pi->next) {
pi->prevRank = pi->rank;
}
// Update the rank
for (Node pi = l->head; pi != NULL; pi = pi->next) {
double weights = getPageWeight(l, g, gWin, gWout, pi);
pi->rank = (1 - d) / N + d * weights;
}
diff = calculateDiff(l);
}
GraphFree(gWin);
GraphFree(gWout);
return l;
}
// Initialises rank to 1/N and sets out/in degree for each url
static void initialiseRankAndDegree(List l, Graph g, double N) {
for (Node pi = l->head; pi != NULL; pi = pi->next) {
pi->rank = 1 / N;
pi->outDegree = outgoingDegree(g, pi->index);
pi->inDegree = incomingDegree(g, pi->index);
}
}
// Takes a url index and returns the corresponding url node
static Node getNode(List l, int index) {
assert(index >= 0 && index < l->size);
for (Node n = l->head; n != NULL; n = n->next) {
if (n->index == index) return n;
}
return NULL;
}
// Sets the Win for each edge in the graph
static Graph setGraphWin(List l, Graph g) {
Graph gWin = GraphNew(g->nV);
for (int pj = 0; pj < g->nV; pj++) {
for (int pi = 0; pi < g->nV; pi++) {
// don't include self loops
if (isAdjacent(g, pj, pi) && pj != pi) {
Node pjNode = getNode(l, pj);
Node piNode = getNode(l, pi);
double Win = calculateWin(l, g, pjNode, piNode);
Edge e = {pj, pi, Win};
GraphInsertEdge(gWin, e);
}
}
}
return gWin;
}
// Sets the Wout for each edge in the graph
static Graph setGraphWout(List l, Graph g) {
Graph gWout = GraphNew(g->nV);
for (int pj = 0; pj < g->nV; pj++) {
for (int pi = 0; pi < g->nV; pi++) {
if (isAdjacent(g, pj, pi) && pj != pi) {
Node pjNode = getNode(l, pj);
Node piNode = getNode(l, pi);
double Wout = calculateWout(l, g, pjNode, piNode);
Edge e = {pj, pi, Wout};
GraphInsertEdge(gWout, e);
}
}
}
return gWout;
}
// Calculates the Win for each edge
static double calculateWin(List l, Graph g, Node pj, Node pi) {
// Store all the incoming links
double pjTotalIncomingLinks = 0;
int pjRow = pj->index;
for (int pjCol = 0; pjCol < g->nV; pjCol++) {
if (isAdjacent(g, pjRow, pjCol)) {
Node refPage = getNode(l, pjCol);
pjTotalIncomingLinks += refPage->inDegree;
}
}
return pi->inDegree / pjTotalIncomingLinks;
}
// Returns true if edges[v][w] == 1, else false.
static bool isAdjacent(Graph g, int v, int w) {
if (g->edges[v][w] != 0) return true;
return false;
}
// Returns the number of incoming links for a url
static double incomingDegree(Graph g, int urlA) {
int degree = 0;
for (int urlB = 0; urlB < g->nV; urlB++) {
// for each urlB check if it is an incoming link in urlA (i.e. urlB -> urlA)
if (isAdjacent(g, urlB, urlA)) {
degree++;
}
}
return degree;
}
// Returns the number of outgoing links for a url
static double outgoingDegree(Graph g, int urlA) {
double degree = 0;
for (int urlB = 0; urlB < g->nV; urlB++) {
if (isAdjacent(g, urlA, urlB)) {
degree++;
}
}
return degree;
}
// Calculates the Wout for an edge
static double calculateWout(List l, Graph g, Node pj, Node pi) {
// Set to 0.5 if pi == 0 per spec
double piOutgoingLinks = pi->outDegree;
if (piOutgoingLinks == 0) {
piOutgoingLinks = 0.5;
}
double pjTotalOutgoingLinks = 0;
int pjRow = pj->index;
for (int pjCol = 0; pjCol < g->nV; pjCol++) {
if (isAdjacent(g, pjRow, pjCol)) {
Node refPage = getNode(l, pjCol);
if (refPage->outDegree == 0) {
pjTotalOutgoingLinks += 0.5;
} else {
pjTotalOutgoingLinks += refPage->outDegree;
}
}
}
// Set to 0.5 per spec if == 0
if (pjTotalOutgoingLinks == 0) {
pjTotalOutgoingLinks = 0.5;
}
return piOutgoingLinks / pjTotalOutgoingLinks;
}
// Calculates the page weight
static double getPageWeight(List l, Graph g, Graph gWin, Graph gWout, Node pi) {
int piIndex = pi->index;
double totalWeight = 0;
for (int pjIndex = 0; pjIndex < g->nV; pjIndex++) {
if (isAdjacent(g, pjIndex, piIndex)) {
Node pj = getNode(l, pjIndex);
double Wout = gWout->edges[pjIndex][piIndex];
double Win = gWin->edges[pjIndex][piIndex];
double weight = pj->prevRank * Wout * Win;
totalWeight += weight;
}
}
return totalWeight;
}
// Calculates the diff for each iteration cycle
static double calculateDiff(List l) {
double diff = 0;
for (Node pi = l->head; pi != NULL; pi = pi->next) {
diff += fabs(pi->rank - pi->prevRank);
}
return diff;
}