|
@ -1,32 +1,210 @@ |
|
|
#include "serial_gs_pagerank_functions.h" |
|
|
#include "serial_gs_pagerank_functions.h" |
|
|
|
|
|
|
|
|
const char *CONVERGENCE_ARGUMENT = "-c"; |
|
|
const char *ARGUMENT_CONVERGENCE_TOLERANCE = "-c"; |
|
|
const char *MAX_ITERATIONS_ARGUMENT = "-m"; |
|
|
const char *ARGUMENT_MAX_ITERATIONS = "-m"; |
|
|
const char *DAMPING_FACTOR_ARGUMENT = "-a"; |
|
|
const char *ARGUMENT_DAMPING_FACTOR = "-a"; |
|
|
const char *VERBAL_OUTPUT_ARGUMENT = "-v"; |
|
|
const char *ARGUMENT_VERBAL_OUTPUT = "-v"; |
|
|
|
|
|
const char *ARGUMENT_OUTPUT_HISTORY = "-h"; |
|
|
|
|
|
const char *ARGUMENT_OUTPUT_FILENAME = "-o"; |
|
|
|
|
|
|
|
|
const int NUMERICAL_BASE = 10; |
|
|
const int NUMERICAL_BASE = 10; |
|
|
|
|
|
char *DEFAULT_OUTPUT_FILENAME = "pagerank_output"; |
|
|
|
|
|
|
|
|
void validUsage(char *programName) { |
|
|
// ==================== PAGERANK ====================
|
|
|
printf("%s [-c convergence] [-m max_iterations] [-a alpha] [-v] <graph_file>\
|
|
|
|
|
|
\n-c convergence\ |
|
|
int pagerank(double ***transitionMatrix, double **pagerankVector, Parameters parameters) { |
|
|
\n\tthe convergence criterion\ |
|
|
int iterations = 0; |
|
|
\n-m max_iterations\ |
|
|
double delta, |
|
|
\n\tmaximum number of iterations to perform\ |
|
|
*vectorDifference = (double *) malloc(parameters.numberOfPages * sizeof(double)), |
|
|
\n-a alpha\ |
|
|
*previousPagerankVector = (double *) malloc(parameters.numberOfPages * sizeof(double)); |
|
|
\n\tthe damping factor\ |
|
|
|
|
|
\n-v enable verbal output\ |
|
|
if (parameters.verbose) { |
|
|
\n", programName); |
|
|
printf("\n----- Starting iterations -----\n"); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
memcpy(previousPagerankVector, *pagerankVector, parameters.numberOfPages * sizeof(double)); |
|
|
|
|
|
|
|
|
|
|
|
matrixVectorMultiplication(transitionMatrix, previousPagerankVector, |
|
|
|
|
|
pagerankVector, parameters.numberOfPages, parameters.dampingFactor); |
|
|
|
|
|
|
|
|
|
|
|
if (parameters.history) { |
|
|
|
|
|
savePagerankToFile(parameters.outputFilename, iterations != 0, |
|
|
|
|
|
*pagerankVector, parameters.numberOfPages); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
|
|
|
vectorDifference[i] = (*pagerankVector)[i] - previousPagerankVector[i]; |
|
|
|
|
|
} |
|
|
|
|
|
delta = vectorNorm(vectorDifference, parameters.numberOfPages); |
|
|
|
|
|
|
|
|
|
|
|
++iterations; |
|
|
|
|
|
printf("Iteration %d: delta = %f\n", iterations, delta); |
|
|
|
|
|
} while (delta > parameters.convergenceCriterion && |
|
|
|
|
|
(parameters.maxIterations == 0 || iterations < parameters.maxIterations)); |
|
|
|
|
|
|
|
|
|
|
|
if (!parameters.history) { |
|
|
|
|
|
savePagerankToFile(parameters.outputFilename, false, *pagerankVector, |
|
|
|
|
|
parameters.numberOfPages); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return iterations; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int checkIncrement(int previousIndex, int maxIndex, char *programName) { |
|
|
// ==================== INITIALIZATION ====================
|
|
|
if (previousIndex == maxIndex) { |
|
|
|
|
|
validUsage(programName); |
|
|
/*
|
|
|
exit(EXIT_FAILURE); |
|
|
* initialize allocates required memory for arrays, reads the web graph from the |
|
|
|
|
|
* from the file and creates the initial transition probability distribution |
|
|
|
|
|
* matrix. |
|
|
|
|
|
*/ |
|
|
|
|
|
void initialize(int ***directedWebGraph, double ***transitionMatrix, |
|
|
|
|
|
double **pagerankVector, Parameters *parameters) { |
|
|
|
|
|
|
|
|
|
|
|
// Reads web graph from file
|
|
|
|
|
|
if ((*parameters).verbose) { |
|
|
|
|
|
printf("----- Reading graph from file -----\n"); |
|
|
} |
|
|
} |
|
|
return ++previousIndex; |
|
|
readGraphFromFile(directedWebGraph, parameters); |
|
|
|
|
|
|
|
|
|
|
|
// Outputs the algorithm parameters to the console
|
|
|
|
|
|
if ((*parameters).verbose) { |
|
|
|
|
|
printf("\n----- Running with parameters -----\
|
|
|
|
|
|
\nNumber of pages: %d", (*parameters).numberOfPages); |
|
|
|
|
|
if (!(*parameters).maxIterations) { |
|
|
|
|
|
printf("\nMaximum number of iterations: inf"); |
|
|
|
|
|
} else { |
|
|
|
|
|
printf("\nMaximum number of iterations: %d", (*parameters).maxIterations); |
|
|
|
|
|
} |
|
|
|
|
|
printf("\nConvergence criterion: %f\
|
|
|
|
|
|
\nDamping factor: %f\ |
|
|
|
|
|
\nGraph filename: %s\n", (*parameters).convergenceCriterion, |
|
|
|
|
|
(*parameters).dampingFactor, (*parameters).graphFilename); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Allocates memory for the pagerank vector
|
|
|
|
|
|
(*pagerankVector) = (double *) malloc((*parameters).numberOfPages * sizeof(double)); |
|
|
|
|
|
double webUniformProbability = 1. / (*parameters).numberOfPages; |
|
|
|
|
|
for (int i=0; i<(*parameters).numberOfPages; ++i) { |
|
|
|
|
|
(*pagerankVector)[i] = webUniformProbability; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Generates the initial transition matrix (matrix P).
|
|
|
|
|
|
generateNormalizedTransitionMatrix(transitionMatrix, *directedWebGraph, *parameters); |
|
|
|
|
|
// Transposes the transition matrix (P^T).
|
|
|
|
|
|
transposeMatrix(transitionMatrix, (*parameters).numberOfPages, (*parameters).numberOfPages); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* generateNormalizedTransitionMatrix generates the normalized transition matrix |
|
|
|
|
|
* from the graph data (matrix P'). |
|
|
|
|
|
*/ |
|
|
|
|
|
void generateNormalizedTransitionMatrix(double ***transitionMatrix, |
|
|
|
|
|
int **directedWebGraph, Parameters parameters) { |
|
|
|
|
|
// Allocates memory for the transitionMatrix rows
|
|
|
|
|
|
(*transitionMatrix) = (double **) malloc(parameters.numberOfPages * sizeof(double *)); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
|
|
|
// Allocates memory for this row's columns
|
|
|
|
|
|
(*transitionMatrix)[i] = (double *) malloc(parameters.numberOfPages * sizeof(double)); |
|
|
|
|
|
|
|
|
|
|
|
// Calculates the outdegree of this page
|
|
|
|
|
|
int pageOutdegree = 0; |
|
|
|
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
|
|
|
pageOutdegree += directedWebGraph[i][j]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Populates this row of the transition matrix
|
|
|
|
|
|
if (pageOutdegree != 0) { |
|
|
|
|
|
// Calculates the uniform probability once.
|
|
|
|
|
|
double pageUniformProbability = 1. / pageOutdegree; |
|
|
|
|
|
|
|
|
|
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
|
|
|
if (directedWebGraph[i][j] == 1){ |
|
|
|
|
|
(*transitionMatrix)[i][j] = pageUniformProbability; |
|
|
|
|
|
} else { |
|
|
|
|
|
(*transitionMatrix)[i][j] = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
|
|
|
(*transitionMatrix)[i][j] = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ==================== MATH UTILS ====================
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* matrixVectorMultiplication calculates the product of the multiplication |
|
|
|
|
|
* between a matrix and the a vector in a cheap way. |
|
|
|
|
|
*/ |
|
|
|
|
|
void matrixVectorMultiplication(double ***matrix, double *vector, |
|
|
|
|
|
double **product, int vectorSize, double dampingFactor) { |
|
|
|
|
|
double webUniformProbability = 1. / vectorSize; |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<vectorSize; ++i) { |
|
|
|
|
|
double sum = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int j=0; j<vectorSize; ++j) { |
|
|
|
|
|
sum += (*matrix)[i][j] * vector[j]; |
|
|
|
|
|
} |
|
|
|
|
|
(*product)[i] = dampingFactor * sum; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double normDifference = vectorNorm(vector, vectorSize) - |
|
|
|
|
|
vectorNorm((*product), vectorSize); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<vectorSize; ++i) { |
|
|
|
|
|
(*product)[i] += normDifference * webUniformProbability; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* vectorNorm calculates the first norm of a vector. |
|
|
|
|
|
*/ |
|
|
|
|
|
double vectorNorm(double *vector, int vectorSize) { |
|
|
|
|
|
double norm = 0.; |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<vectorSize; ++i) { |
|
|
|
|
|
norm += fabs(vector[i]); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return norm; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* transposeMatrix transposes the matrix passed (by reference) in the arguments. |
|
|
|
|
|
*/ |
|
|
|
|
|
void transposeMatrix(double ***matrix, int rows, int columns) { |
|
|
|
|
|
// Transposes the matrix
|
|
|
|
|
|
// Rows become columns and vice versa
|
|
|
|
|
|
|
|
|
|
|
|
double **tempArray = (double **) malloc(columns * sizeof(double *)); |
|
|
|
|
|
for (int i=0; i<columns; ++i) { |
|
|
|
|
|
tempArray[i] = malloc(rows * sizeof(double)); |
|
|
|
|
|
|
|
|
|
|
|
for (int j=0; j<rows; ++j) { |
|
|
|
|
|
tempArray[i][j] = (*matrix)[j][i]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO free memory
|
|
|
|
|
|
|
|
|
|
|
|
//double **pointerToFreeMemoryLater = *matrix;
|
|
|
|
|
|
*matrix = tempArray; |
|
|
|
|
|
/*for (int i=0; i<rows; ++i) {
|
|
|
|
|
|
free(pointerToFreeMemoryLater[i]); |
|
|
|
|
|
} |
|
|
|
|
|
free(pointerToFreeMemoryLater);*/ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ==================== PROGRAM INPUT AND OUTPUT UTILS ====================
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* parseArguments parses the command line arguments given by the user. |
|
|
|
|
|
*/ |
|
|
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) { |
|
|
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) { |
|
|
if (argumentCount < 2 || argumentCount > 10) { |
|
|
if (argumentCount < 2 || argumentCount > 10) { |
|
|
validUsage(argumentVector[0]); |
|
|
validUsage(argumentVector[0]); |
|
@ -37,12 +215,14 @@ void parseArguments(int argumentCount, char **argumentVector, Parameters *parame |
|
|
(*parameters).convergenceCriterion = 1; |
|
|
(*parameters).convergenceCriterion = 1; |
|
|
(*parameters).dampingFactor = 0.85; |
|
|
(*parameters).dampingFactor = 0.85; |
|
|
(*parameters).verbose = false; |
|
|
(*parameters).verbose = false; |
|
|
|
|
|
(*parameters).history = false; |
|
|
|
|
|
(*parameters).outputFilename = DEFAULT_OUTPUT_FILENAME; |
|
|
|
|
|
|
|
|
char *endPointer; |
|
|
char *endPointer; |
|
|
int argumentIndex = 1; |
|
|
int argumentIndex = 1; |
|
|
|
|
|
|
|
|
while (argumentIndex < argumentCount) { |
|
|
while (argumentIndex < argumentCount) { |
|
|
if (!strcmp(argumentVector[argumentIndex], CONVERGENCE_ARGUMENT)) { |
|
|
if (!strcmp(argumentVector[argumentIndex], ARGUMENT_CONVERGENCE_TOLERANCE)) { |
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
|
|
|
|
|
|
double convergenceInput = strtod(argumentVector[argumentIndex], &endPointer); |
|
|
double convergenceInput = strtod(argumentVector[argumentIndex], &endPointer); |
|
@ -51,7 +231,7 @@ void parseArguments(int argumentCount, char **argumentVector, Parameters *parame |
|
|
exit(EXIT_FAILURE); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
|
} |
|
|
(*parameters).convergenceCriterion = convergenceInput; |
|
|
(*parameters).convergenceCriterion = convergenceInput; |
|
|
} else if (!strcmp(argumentVector[argumentIndex], MAX_ITERATIONS_ARGUMENT)) { |
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_MAX_ITERATIONS)) { |
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
|
|
|
|
|
|
size_t iterationsInput = strtol(argumentVector[argumentIndex], &endPointer, NUMERICAL_BASE); |
|
|
size_t iterationsInput = strtol(argumentVector[argumentIndex], &endPointer, NUMERICAL_BASE); |
|
@ -60,7 +240,7 @@ void parseArguments(int argumentCount, char **argumentVector, Parameters *parame |
|
|
exit(EXIT_FAILURE); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
|
} |
|
|
(*parameters).maxIterations = iterationsInput; |
|
|
(*parameters).maxIterations = iterationsInput; |
|
|
} else if (!strcmp(argumentVector[argumentIndex], DAMPING_FACTOR_ARGUMENT)) { |
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_DAMPING_FACTOR)) { |
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
|
|
|
|
|
|
double alphaInput = strtod(argumentVector[argumentIndex], &endPointer); |
|
|
double alphaInput = strtod(argumentVector[argumentIndex], &endPointer); |
|
@ -69,8 +249,18 @@ void parseArguments(int argumentCount, char **argumentVector, Parameters *parame |
|
|
exit(EXIT_FAILURE); |
|
|
exit(EXIT_FAILURE); |
|
|
} |
|
|
} |
|
|
(*parameters).dampingFactor = alphaInput; |
|
|
(*parameters).dampingFactor = alphaInput; |
|
|
} else if (!strcmp(argumentVector[argumentIndex], VERBAL_OUTPUT_ARGUMENT)) { |
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_VERBAL_OUTPUT)) { |
|
|
(*parameters).verbose = true; |
|
|
(*parameters).verbose = true; |
|
|
|
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_OUTPUT_HISTORY)) { |
|
|
|
|
|
(*parameters).history = true; |
|
|
|
|
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_OUTPUT_FILENAME)) { |
|
|
|
|
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
|
|
|
|
|
|
|
|
|
|
|
if (fopen(argumentVector[argumentIndex], "w") == NULL) { |
|
|
|
|
|
printf("Invalid output filename. Reverting to default.\n"); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
(*parameters).outputFilename = argumentVector[argumentIndex]; |
|
|
} else if (argumentIndex == argumentCount - 1) { |
|
|
} else if (argumentIndex == argumentCount - 1) { |
|
|
(*parameters).graphFilename = argumentVector[argumentIndex]; |
|
|
(*parameters).graphFilename = argumentVector[argumentIndex]; |
|
|
} else { |
|
|
} else { |
|
@ -81,6 +271,10 @@ void parseArguments(int argumentCount, char **argumentVector, Parameters *parame |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* readGraphFromFile loads the file supplied in the command line arguments to an |
|
|
|
|
|
* array (directedWebGraph) that represents the graph. |
|
|
|
|
|
*/ |
|
|
void readGraphFromFile(int ***directedWebGraph, Parameters *parameters) { |
|
|
void readGraphFromFile(int ***directedWebGraph, Parameters *parameters) { |
|
|
FILE *graphFile; |
|
|
FILE *graphFile; |
|
|
|
|
|
|
|
@ -103,11 +297,11 @@ void readGraphFromFile(int ***directedWebGraph, Parameters *parameters) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if ((*parameters).verbose) { |
|
|
if ((*parameters).verbose) { |
|
|
printf("Line count of file is %d \n", numberOfLines); |
|
|
printf("Line count of file is %d \n", numberOfLines + 1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Each line of the file represents one page of the graph
|
|
|
// Each line of the file represents one page of the graph
|
|
|
(*parameters).numberOfPages = numberOfLines; |
|
|
(*parameters).numberOfPages = numberOfLines + 1; |
|
|
rewind(graphFile); |
|
|
rewind(graphFile); |
|
|
|
|
|
|
|
|
// Allocates memory and loads values into directedWebGraph (matrix A)
|
|
|
// Allocates memory and loads values into directedWebGraph (matrix A)
|
|
@ -122,165 +316,62 @@ void readGraphFromFile(int ***directedWebGraph, Parameters *parameters) { |
|
|
if (!fscanf(graphFile, "%d ", &(*directedWebGraph)[i][j])) { |
|
|
if (!fscanf(graphFile, "%d ", &(*directedWebGraph)[i][j])) { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
//printf("directedWebGraph[%d][%d] = %d", i , j, (*directedWebGraph)[i][j]);
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fclose(graphFile); |
|
|
fclose(graphFile); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void generateNormalizedTransitionMatrix(double ***transitionMatrix, |
|
|
/*
|
|
|
int **directedWebGraph, Parameters parameters) { |
|
|
* validUsage outputs a message to the console that informs the user of the |
|
|
// Allocates memory for the transitionMatrix rows
|
|
|
* correct (valid) way to use the program. |
|
|
(*transitionMatrix) = (double **) malloc(parameters.numberOfPages * sizeof(double *)); |
|
|
*/ |
|
|
|
|
|
void validUsage(char *programName) { |
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
printf("%s [-c convergence_criterion] [-m max_iterations] [-a alpha] [-v] [-h] [-o output_filename] <graph_file>\
|
|
|
// Allocates memory for this row's columns
|
|
|
\n-c convergence_criterion\ |
|
|
(*transitionMatrix)[i] = (double *) malloc(parameters.numberOfPages * sizeof(double)); |
|
|
\n\tthe convergence tolerance criterion\ |
|
|
|
|
|
\n-m max_iterations\ |
|
|
int pageOutdegree = 0; |
|
|
\n\tmaximum number of iterations to perform\ |
|
|
//Calculates the outdegree of this page
|
|
|
\n-a alpha\ |
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
\n\tthe damping factor\ |
|
|
pageOutdegree += directedWebGraph[i][j]; |
|
|
\n-v enable verbal output\ |
|
|
} |
|
|
\n-h enable history output to file\ |
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
\n-o output_filename\ |
|
|
if (pageOutdegree == 0) { |
|
|
\n\tfilename and path for the output\ |
|
|
// Introduces random jumps from dangling nodes (P' = P + D)
|
|
|
\n", programName); |
|
|
// This makes sure that there are no pages with zero outdegree.
|
|
|
exit(EXIT_FAILURE); |
|
|
(*transitionMatrix)[i][j] = 1. / parameters.numberOfPages; |
|
|
|
|
|
} else { |
|
|
|
|
|
(*transitionMatrix)[i][j] = 1. / pageOutdegree; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void makeIrreducible(double ***transitionMatrix, Parameters parameters) { |
|
|
|
|
|
// Manipulates the values of transitionMatrix to make it irreducible. A
|
|
|
|
|
|
// uniform probability (1/number_of_pages) and no personalization are used
|
|
|
|
|
|
// here.
|
|
|
|
|
|
|
|
|
|
|
|
// Introduces teleportation (P'' = cP' + (1 - c)E)
|
|
|
|
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
|
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
|
|
|
(*transitionMatrix)[i][j] = |
|
|
|
|
|
parameters.dampingFactor *(*transitionMatrix)[i][j] + |
|
|
|
|
|
(1 - parameters.dampingFactor) / parameters.numberOfPages; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void transposeMatrix(double ***matrix, int rows, int columns) { |
|
|
/*
|
|
|
// Transposes the matrix
|
|
|
* checkIncrement is a helper function for parseArguments function. |
|
|
// Rows become columns and vice versa
|
|
|
*/ |
|
|
|
|
|
int checkIncrement(int previousIndex, int maxIndex, char *programName) { |
|
|
double **tempArray = (double **) malloc(rows * sizeof(double *)); |
|
|
if (previousIndex == maxIndex) { |
|
|
for (int i=0; i<rows; ++i) { |
|
|
validUsage(programName); |
|
|
tempArray[i] = malloc(columns * sizeof(double)); |
|
|
exit(EXIT_FAILURE); |
|
|
|
|
|
|
|
|
for (int j=0; j<columns; ++j) { |
|
|
|
|
|
tempArray[i][j] = (*matrix)[j][i]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//double **pointerToFreeMemoryLater = *matrix;
|
|
|
|
|
|
matrix = &tempArray; |
|
|
|
|
|
/*for (int i=0; i<rows; ++i) {
|
|
|
|
|
|
free(pointerToFreeMemoryLater[i]); |
|
|
|
|
|
} |
|
|
} |
|
|
free(pointerToFreeMemoryLater);*/ |
|
|
return ++previousIndex; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void initialize(int ***directedWebGraph, double ***transitionMatrix, |
|
|
void savePagerankToFile(char *filename, bool append, double *pagerankVector, |
|
|
double **pagerankVector, Parameters *parameters) { |
|
|
int vectorSize) { |
|
|
|
|
|
FILE *outputFile; |
|
|
|
|
|
|
|
|
if ((*parameters).verbose) { |
|
|
if (append) { |
|
|
printf("----- Reading graph from file -----\n"); |
|
|
outputFile = fopen(filename, "a"); |
|
|
} |
|
|
|
|
|
readGraphFromFile(directedWebGraph, parameters); |
|
|
|
|
|
|
|
|
|
|
|
if ((*parameters).verbose) { |
|
|
|
|
|
printf("\n----- Running with parameters -----\
|
|
|
|
|
|
\nNumber of pages: %d", (*parameters).numberOfPages); |
|
|
|
|
|
if (!(*parameters).maxIterations) { |
|
|
|
|
|
printf("\nMaximum number of iterations: inf"); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
printf("\nMaximum number of iterations: %d", (*parameters).maxIterations); |
|
|
outputFile = fopen(filename, "w"); |
|
|
} |
|
|
|
|
|
printf("\nConvergence criterion: %f\
|
|
|
|
|
|
\nDamping factor: %f\ |
|
|
|
|
|
\nGraph filename: %s\n", (*parameters).convergenceCriterion, |
|
|
|
|
|
(*parameters).dampingFactor, (*parameters).graphFilename); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Allocates memory for the pagerank vector
|
|
|
if (outputFile == NULL) { |
|
|
(*pagerankVector) = (double *) malloc((*parameters).numberOfPages * sizeof(double)); |
|
|
printf("Error while opening the output file.\n"); |
|
|
for (int i=0; i<(*parameters).numberOfPages; ++i) { |
|
|
return; |
|
|
(*pagerankVector)[i] = 1. / (*parameters).numberOfPages; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
generateNormalizedTransitionMatrix(transitionMatrix, *directedWebGraph, *parameters); |
|
|
|
|
|
makeIrreducible(transitionMatrix, *parameters); |
|
|
|
|
|
transposeMatrix(transitionMatrix, (*parameters).numberOfPages, (*parameters).numberOfPages); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double vectorFirstNorm(double *vector, int vectorSize) { |
|
|
|
|
|
double norm = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<vectorSize; ++i) { |
|
|
for (int i=0; i<vectorSize; ++i) { |
|
|
norm += vector[i]; |
|
|
fprintf(outputFile, "%f ", pagerankVector[i]); |
|
|
} |
|
|
} |
|
|
|
|
|
fprintf(outputFile, "\n"); |
|
|
|
|
|
|
|
|
return norm; |
|
|
fclose(outputFile); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void nextProbabilityDistribution(double ***transitionMatrix, double *previousPagerankVector, |
|
|
|
|
|
double **newPagerankVector, Parameters parameters) { |
|
|
|
|
|
|
|
|
|
|
|
transposeMatrix(transitionMatrix, parameters.numberOfPages, parameters.numberOfPages); |
|
|
|
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
|
|
|
double sum = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (int j=0; j<parameters.numberOfPages; ++j) { |
|
|
|
|
|
sum += (*transitionMatrix)[i][j] * previousPagerankVector[j]; |
|
|
|
|
|
} |
|
|
|
|
|
(*newPagerankVector)[i] = parameters.dampingFactor * sum; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
double normDifference = vectorFirstNorm(previousPagerankVector, parameters.numberOfPages) - |
|
|
|
|
|
vectorFirstNorm((*newPagerankVector), parameters.numberOfPages); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
|
|
|
(*newPagerankVector)[i] += normDifference / parameters.numberOfPages; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
transposeMatrix(transitionMatrix, parameters.numberOfPages, parameters.numberOfPages); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int pagerank(double ***transitionMatrix, double **pagerankVector, Parameters parameters) { |
|
|
|
|
|
int iterations = 0; |
|
|
|
|
|
double delta, |
|
|
|
|
|
*vectorDifference = (double *) malloc(parameters.numberOfPages * sizeof(double)), |
|
|
|
|
|
*previousPagerankVector = (double *) malloc(parameters.numberOfPages * sizeof(double)); |
|
|
|
|
|
|
|
|
|
|
|
if (parameters.verbose) { |
|
|
|
|
|
printf("\n----- Starting iterations -----\n"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
memcpy(previousPagerankVector, *pagerankVector, parameters.numberOfPages * sizeof(double)); |
|
|
|
|
|
|
|
|
|
|
|
nextProbabilityDistribution(transitionMatrix, previousPagerankVector, pagerankVector, parameters); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<parameters.numberOfPages; ++i) { |
|
|
|
|
|
vectorDifference[i] = (*pagerankVector)[i] - previousPagerankVector[i]; |
|
|
|
|
|
} |
|
|
|
|
|
delta = vectorFirstNorm(vectorDifference, parameters.numberOfPages); |
|
|
|
|
|
|
|
|
|
|
|
++iterations; |
|
|
|
|
|
printf("Iteration %d: delta = %f\n", iterations, delta); |
|
|
|
|
|
} while (delta > parameters.convergenceCriterion && |
|
|
|
|
|
(parameters.maxIterations != 0 || iterations < parameters.maxIterations)); |
|
|
|
|
|
|
|
|
|
|
|
return iterations; |
|
|
|
|
|
} |
|
|
} |