mtzikara
6 years ago
committed by
GitHub
14 changed files with 1105 additions and 0 deletions
@ -0,0 +1,37 @@ |
|||||
|
SHELL := /bin/bash |
||||
|
|
||||
|
# ============================================
|
||||
|
# COMMANDS
|
||||
|
|
||||
|
CC = gcc -std=gnu99 |
||||
|
RM = rm -f |
||||
|
CFLAGS_DEBUG=-O0 -ggdb3 -Wall -I. |
||||
|
CFLAGS=-O3 -Wall -I. |
||||
|
OBJ=serial_gs_pagerank.o serial_gs_pagerank_functions.o csr_sparse_matrix.o lil_sparse_matrix.o |
||||
|
DEPS=serial_gs_pagerank_functions.h csr_sparse_matrix.h lil_sparse_matrix.h |
||||
|
|
||||
|
# ==========================================
|
||||
|
# TARGETS
|
||||
|
|
||||
|
EXECUTABLES = pagerank.out |
||||
|
|
||||
|
.PHONY: all clean |
||||
|
|
||||
|
all: $(EXECUTABLES) |
||||
|
|
||||
|
# ==========================================
|
||||
|
# DEPENDENCIES (HEADERS)
|
||||
|
|
||||
|
%.o: %.c $(DEPS) |
||||
|
$(CC) -c -o $@ $< $(CFLAGS) |
||||
|
|
||||
|
.PRECIOUS: $(EXECUTABLES) $(OBJ) |
||||
|
|
||||
|
# ==========================================
|
||||
|
# EXECUTABLE (MAIN)
|
||||
|
|
||||
|
$(EXECUTABLES): $(OBJ) |
||||
|
$(CC) -o $@ $^ $(CFLAGS) |
||||
|
|
||||
|
clean: |
||||
|
$(RM) *.o *~ $(EXECUTABLES) |
@ -0,0 +1,263 @@ |
|||||
|
#include "csr_sparse_matrix.h" |
||||
|
|
||||
|
|
||||
|
CsrSparseMatrix initCsrSparseMatrix() { |
||||
|
CsrSparseMatrix sparseMatrix; |
||||
|
sparseMatrix.size = 0; |
||||
|
sparseMatrix.nnz = 0; |
||||
|
sparseMatrix.values = NULL; |
||||
|
sparseMatrix.columnIndexes = NULL; |
||||
|
sparseMatrix.rowaccInd = NULL; |
||||
|
return sparseMatrix; |
||||
|
} |
||||
|
|
||||
|
void allocMemoryForElements (CsrSparseMatrix *sparseMatrix, int edges) { |
||||
|
sparseMatrix->values = (double *) malloc( |
||||
|
edges * sizeof(double)); |
||||
|
sparseMatrix->columnIndexes = (int *) malloc( |
||||
|
edges * sizeof(int)); |
||||
|
sparseMatrix->rowaccInd = (int *) malloc( |
||||
|
edges * sizeof(int)); |
||||
|
} |
||||
|
|
||||
|
void addElement(CsrSparseMatrix *sparseMatrix, double value, int row, int column) { |
||||
|
|
||||
|
for(int i=row+1; i<sparseMatrix->size; ++i){ |
||||
|
++sparseMatrix->rowaccInd[i]; |
||||
|
} |
||||
|
sparseMatrix->nnz = sparseMatrix->nnz+1; |
||||
|
sparseMatrix->values[sparseMatrix->rowaccInd[row-1]+1] = value; |
||||
|
sparseMatrix->columnIndexes[sparseMatrix->rowaccInd[row-1]+1] = column; |
||||
|
// Creates the new element
|
||||
|
/*CsrSparseMatrixElement *newElement = (CsrSparseMatrixElement *) malloc(
|
||||
|
sizeof(CsrSparseMatrixElement)); |
||||
|
|
||||
|
newElement->value = value; |
||||
|
newElement->rowIndex = row; |
||||
|
newElement->columnIndex = column; |
||||
|
|
||||
|
sparseMatrix->elements[sparseMatrix->size] = newElement; |
||||
|
sparseMatrix->size = sparseMatrix->size + 1; */ |
||||
|
} |
||||
|
|
||||
|
void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row) { |
||||
|
int noofnnzinrow; |
||||
|
if(row==0){ |
||||
|
noofnnzinrow = sparseMatrix->rowaccInd[row]; |
||||
|
} |
||||
|
else{ |
||||
|
noofnnzinrow = sparseMatrix->rowaccInd[row]-sparseMatrix->rowaccInd[row-1]; |
||||
|
} |
||||
|
int startdeleteInd = sparseMatrix->rowaccInd[row-1]+1; |
||||
|
|
||||
|
//delete the values and columnindexes of these rows by moving up the rest
|
||||
|
for(int i=0; i<noofnnzinrow; ++i){ |
||||
|
sparseMatrix->values[i+startdeleteInd] = sparseMatrix->values[sparseMatrix->nnz-noofnnzinrow+i]; |
||||
|
sparseMatrix->values[sparseMatrix->nnz-noofnnzinrow+i] = 0; |
||||
|
sparseMatrix->columnIndexes[i+startdeleteInd] = sparseMatrix->columnIndexes[sparseMatrix->nnz-noofnnzinrow+i]; |
||||
|
sparseMatrix->columnIndexes[sparseMatrix->nnz-noofnnzinrow+i] = 0; |
||||
|
} |
||||
|
sparseMatrix->nnz = sparseMatrix->nnz - noofnnzinrow; |
||||
|
|
||||
|
//substract from accumulative no. of row nnz elements
|
||||
|
for(int i=row; i<sparseMatrix->size ; ++i){ |
||||
|
sparseMatrix->rowaccInd[i] -= noofnnzinrow; |
||||
|
} |
||||
|
|
||||
|
/*for (int i=0; i<sparseMatrix->size; ++i) {
|
||||
|
CooSparseMatrixElement *element = sparseMatrix->elements[i]; |
||||
|
if (element->rowIndex == row) { |
||||
|
element->value = 0; |
||||
|
} |
||||
|
}*/ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column) { |
||||
|
|
||||
|
/*for (int i=0; i<sparseMatrix->size; ++i) {
|
||||
|
CooSparseMatrixElement *element = sparseMatrix->elements[i]; |
||||
|
if (element->columnIndex == column) { |
||||
|
element->value = 0; |
||||
|
} |
||||
|
} |
||||
|
*/ |
||||
|
for (int i=0; i<sparseMatrix->nnz; ++i){ |
||||
|
if(sparseMatrix->columnIndexes[i] == column){ |
||||
|
//delete columns by moving up the rest
|
||||
|
for(int j=i; j<sparseMatrix->nnz-1; ++j){ |
||||
|
sparseMatrix->columnIndexes[j] = sparseMatrix->columnIndexes[j+1]; |
||||
|
sparseMatrix->values[j] = sparseMatrix->values[j+1]; |
||||
|
} |
||||
|
int flag = 0; |
||||
|
//adjust rowaccInd
|
||||
|
for(int j=0; j<sparseMatrix->size; ++j){ |
||||
|
if(sparseMatrix->rowaccInd[j] > i){ |
||||
|
flag = 1; //must be substracted since column belonged to this row
|
||||
|
} |
||||
|
if(flag){ |
||||
|
--sparseMatrix->rowaccInd[j]; //substract till end of rows
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
int *getRowIndexes(CsrSparseMatrix sparseMatrix, int row, int *rowSize) { |
||||
|
*rowSize = 0; |
||||
|
/*for (int i=0; i<sparseMatrix.size; ++i) {
|
||||
|
if (sparseMatrix.elements[i]->rowIndex == row) { |
||||
|
++(*rowSize); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!(*rowSize)) { |
||||
|
return NULL; |
||||
|
}*/ |
||||
|
if((row-1)>0 && (sparseMatrix.rowaccInd[row]-sparseMatrix.rowaccInd[row-1])>0){ |
||||
|
(*rowSize) = sparseMatrix.rowaccInd[row]-sparseMatrix.rowaccInd[row-1]; |
||||
|
} |
||||
|
else if((sparseMatrix.rowaccInd[row]-sparseMatrix.rowaccInd[row-1])>0){ //if row = 0
|
||||
|
(*rowSize) = sparseMatrix.rowaccInd[row]; |
||||
|
} |
||||
|
else{ |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
int *indexes = (int *) malloc((*rowSize) * sizeof(int)); |
||||
|
for (int i=1; i<=(*rowSize); ++i) { |
||||
|
|
||||
|
indexes[i-1] = sparseMatrix.rowaccInd[row-1]+i; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return indexes; |
||||
|
} |
||||
|
|
||||
|
void transposeSparseMatrix(CsrSparseMatrix *sparseMatrix) { |
||||
|
/*for (int i=0; i<sparseMatrix->size; ++i) {
|
||||
|
CooSparseMatrixElement *element = sparseMatrix->elements[i]; |
||||
|
int tempRow = element->rowIndex; |
||||
|
element->rowIndex = element->columnIndex; |
||||
|
element->columnIndex = tempRow; |
||||
|
}*/ |
||||
|
double* values_t = (double *) malloc( |
||||
|
sparseMatrix->size * sizeof(double)); |
||||
|
int* rowIndexes = (int *) malloc( |
||||
|
sparseMatrix->size * sizeof(int)); |
||||
|
int* colaccInd = (int *) malloc( |
||||
|
sparseMatrix->size * sizeof(int)); |
||||
|
|
||||
|
|
||||
|
|
||||
|
int columncount, nnznew = 0; |
||||
|
//for all columns
|
||||
|
for(columncount = 0; columncount<sparseMatrix->size; ++columncount){ |
||||
|
//index for searching in columnIndexes matrix
|
||||
|
for(int i = 0; i<sparseMatrix->nnz;++i){ |
||||
|
if(sparseMatrix->columnIndexes[i] == columncount){ |
||||
|
//Find which row it belongs to
|
||||
|
for(int j=0; j<sparseMatrix->size; ++j){ |
||||
|
if(sparseMatrix->rowaccInd[j] == i){ |
||||
|
rowIndexes[nnznew] = j-1; |
||||
|
values_t[nnznew] = sparseMatrix->values[i]; |
||||
|
for(int k=i; k<sparseMatrix->size; ++k){ |
||||
|
++colaccInd[k]; |
||||
|
} |
||||
|
++nnznew; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
memcpy(sparseMatrix->values, values_t, sparseMatrix->size*sizeof(double)); |
||||
|
memcpy(sparseMatrix->columnIndexes, rowIndexes, sparseMatrix->size*sizeof(int)); |
||||
|
memcpy(sparseMatrix->rowaccInd, colaccInd, sparseMatrix->size*sizeof(int) ); |
||||
|
sparseMatrix->nnz = nnznew; |
||||
|
} |
||||
|
|
||||
|
void csrSparseMatrixVectorMultiplication(CsrSparseMatrix sparseMatrix, |
||||
|
double *vector, double **product, int vectorSize) { |
||||
|
// Initializes the elements of the product vector to zero
|
||||
|
for (int i=0; i<vectorSize; ++i) { |
||||
|
(*product)[i] = 0; |
||||
|
} |
||||
|
|
||||
|
/*CooSparseMatrixElement *element;
|
||||
|
for (int i=0; i<sparseMatrix.size; ++i) { |
||||
|
element = sparseMatrix.elements[i]; |
||||
|
int row = element->rowIndex, column = element->columnIndex; |
||||
|
|
||||
|
if (row >= vectorSize) { |
||||
|
printf("Error at sparseMatrixVectorMultiplication. Matrix has more rows than vector!\n"); |
||||
|
printf("row = %d\n", row); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
(*product)[row] = (*product)[row] + element->value * vector[column]; |
||||
|
}*/ |
||||
|
int t; |
||||
|
//for every row
|
||||
|
for (int i=0; i<sparseMatrix.size; ++i) { |
||||
|
if(i==0){ |
||||
|
t = sparseMatrix.rowaccInd[0]; |
||||
|
} |
||||
|
else{ |
||||
|
t = sparseMatrix.rowaccInd[i]-sparseMatrix.rowaccInd[i-1]; |
||||
|
} |
||||
|
for(int j=0; j<t; ++j){ |
||||
|
for(int k=0; k<vectorSize; ++k){ |
||||
|
if(sparseMatrix.columnIndexes[sparseMatrix.rowaccInd[i]+t]==k){ |
||||
|
(*product)[k] += sparseMatrix.values[sparseMatrix.rowaccInd[i]+t]*vector[k]; |
||||
|
} |
||||
|
else if(sparseMatrix.columnIndexes[sparseMatrix.rowaccInd[i]+t]>k){ |
||||
|
printf("Error at sparseMatrixVectorMultiplication. Matrix has more columns than vector rows!\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
void destroyCsrSparseMatrix(CsrSparseMatrix *sparseMatrix) { |
||||
|
/*for (int i=0; i<sparseMatrix->size; ++i) {
|
||||
|
free(sparseMatrix->elements[i]); |
||||
|
}*/ |
||||
|
free(sparseMatrix->values); |
||||
|
free(sparseMatrix->rowaccInd); |
||||
|
free(sparseMatrix->columnIndexes); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void printCsrSparseMatrix(CsrSparseMatrix sparseMatrix) { |
||||
|
if (sparseMatrix.size == 0) { |
||||
|
return; |
||||
|
} |
||||
|
/*
|
||||
|
CooSparseMatrixElement *element; |
||||
|
for (int i=0; i<sparseMatrix.size; ++i) { |
||||
|
element = sparseMatrix.elements[i]; |
||||
|
printf("[%d,%d] = %f\n", element->rowIndex, element->columnIndex, |
||||
|
element->value); |
||||
|
}*/ |
||||
|
int t; |
||||
|
for (int i=0; i<sparseMatrix.size; ++i){ |
||||
|
if(i==0){ |
||||
|
t = sparseMatrix.rowaccInd[i]; |
||||
|
} |
||||
|
else{ |
||||
|
t = sparseMatrix.rowaccInd[i]-sparseMatrix.rowaccInd[i-1]; |
||||
|
} |
||||
|
for(int j=0; j<t ; ++j){ |
||||
|
printf("Row [%d] has [%d] nz elements: \n at column[%d] is value = %f \n", |
||||
|
i, t, sparseMatrix.columnIndexes[sparseMatrix.rowaccInd[i]+j], sparseMatrix.values[sparseMatrix.rowaccInd[i]+j]); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
#ifndef CSR_SPARSE_MATRIX_H /* Include guard */ |
||||
|
#define CSR_SPARSE_MATRIX_H |
||||
|
|
||||
|
#include <stdbool.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
typedef struct csrSparseMatrix { |
||||
|
double* values; |
||||
|
int* rowaccInd; //without the first cell, always 0
|
||||
|
int* columnIndexes; |
||||
|
int size; //no. of rows
|
||||
|
int nnz; //no. of non zero elements
|
||||
|
|
||||
|
} CsrSparseMatrix; |
||||
|
|
||||
|
CsrSparseMatrix initCsrSparseMatrix(); |
||||
|
void allocMemoryForElements (CsrSparseMatrix *sparseMatrix, int edges); |
||||
|
void addElement(CsrSparseMatrix *sparseMatrix, double value, int row, int column); |
||||
|
void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row); |
||||
|
void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column); |
||||
|
int *getRowIndexes(CsrSparseMatrix sparseMatrix, int row, int *rowSize); |
||||
|
void transposeSparseMatrix(CsrSparseMatrix *sparseMatrix); |
||||
|
void csrSparseMatrixVectorMultiplication(CsrSparseMatrix sparseMatrix, double *vector, |
||||
|
double **product, int vectorSize); |
||||
|
void destroyCsrSparseMatrix(CsrSparseMatrix *sparseMatrix); |
||||
|
void printCsrSparseMatrix(CsrSparseMatrix sparseMatrix); |
||||
|
|
||||
|
#endif // CSR_SPARSE_MATRIX_H
|
Binary file not shown.
@ -0,0 +1,76 @@ |
|||||
|
#include "lil_sparse_matrix.h" |
||||
|
|
||||
|
LilSparseMatrix createLilSparseMatrix() { |
||||
|
LilSparseMatrix sparseMatrix; |
||||
|
sparseMatrix.elements = 0; |
||||
|
sparseMatrix.firstElement = NULL; |
||||
|
sparseMatrix.lastElement = NULL; |
||||
|
return sparseMatrix; |
||||
|
} |
||||
|
|
||||
|
void apendElement(LilSparseMatrix *sparseMatrix, double value, int row, int column) { |
||||
|
// Creates the new element
|
||||
|
LilSparseMatrixElement *newElement = (LilSparseMatrixElement *) malloc(sizeof(LilSparseMatrixElement)); |
||||
|
newElement->value = value; |
||||
|
newElement->rowIndex = row; |
||||
|
newElement->columnIndex = column; |
||||
|
newElement->nextElement = NULL; |
||||
|
|
||||
|
if (sparseMatrix->firstElement == NULL) { |
||||
|
// Sparse matrix is empty, this is the first element
|
||||
|
sparseMatrix->firstElement = newElement; |
||||
|
sparseMatrix->lastElement = newElement; |
||||
|
} else { |
||||
|
//Gets last element of the matrix
|
||||
|
LilSparseMatrixElement *lastElement = sparseMatrix->lastElement; |
||||
|
|
||||
|
lastElement->nextElement = newElement; |
||||
|
sparseMatrix->lastElement = newElement; |
||||
|
} |
||||
|
|
||||
|
sparseMatrix->elements = sparseMatrix->elements + 1; |
||||
|
} |
||||
|
|
||||
|
void lilSparseMatrixVectorMultiplication(LilSparseMatrix sparseMatrix, |
||||
|
double *vector, double **product, int vectorSize) { |
||||
|
// Initializes the elements of the product vector to zero
|
||||
|
for (int i=0; i<vectorSize; ++i) { |
||||
|
(*product)[i] = 0; |
||||
|
} |
||||
|
|
||||
|
LilSparseMatrixElement *element = sparseMatrix.firstElement; |
||||
|
for (int i=0; i<sparseMatrix.elements; ++i) { |
||||
|
int row = element->rowIndex, column = element->columnIndex; |
||||
|
|
||||
|
if (row >= vectorSize) { |
||||
|
printf("Error at sparseMatrixVectorMultiplication. Matrix has more rows than vector!\n"); |
||||
|
printf("row = %d\n", row); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
(*product)[row] = (*product)[row] + element->value * vector[column]; |
||||
|
element = element->nextElement; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void destroyLilSparseMatrix(LilSparseMatrix *sparseMatrix) { |
||||
|
LilSparseMatrixElement *currentElement = sparseMatrix->firstElement; |
||||
|
while (currentElement != NULL) { |
||||
|
LilSparseMatrixElement *toDelete = currentElement; |
||||
|
currentElement = currentElement->nextElement; |
||||
|
free(toDelete); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void printLilSparseMatrix(LilSparseMatrix sparseMatrix) { |
||||
|
if (sparseMatrix.elements == 0) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
LilSparseMatrixElement *currentElement = sparseMatrix.firstElement; |
||||
|
for (int i=0; i<sparseMatrix.elements; ++i) { |
||||
|
printf("[%d,%d] = %f\n", currentElement->rowIndex, |
||||
|
currentElement->columnIndex, currentElement->value); |
||||
|
currentElement = currentElement->nextElement; |
||||
|
} |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
#ifndef LIL_SPARSE_MATRIX_H /* Include guard */ |
||||
|
#define LIL_SPARSE_MATRIX_H |
||||
|
|
||||
|
#include <stdbool.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
typedef struct lilSparseMatrixElement { |
||||
|
double value; |
||||
|
int rowIndex, columnIndex; |
||||
|
struct lilSparseMatrixElement *nextElement; |
||||
|
} LilSparseMatrixElement; |
||||
|
|
||||
|
typedef struct lilSparseMatrix { |
||||
|
int elements; |
||||
|
LilSparseMatrixElement *firstElement; |
||||
|
LilSparseMatrixElement *lastElement; |
||||
|
} LilSparseMatrix; |
||||
|
|
||||
|
LilSparseMatrix createLilSparseMatrix(); |
||||
|
void apendElement(LilSparseMatrix *sparseMatrix, double value, int row, |
||||
|
int column); |
||||
|
void lilSparseMatrixVectorMultiplication(LilSparseMatrix sparseMatrix, |
||||
|
double *vector, double **product, int vectorSize); |
||||
|
void destroyLilSparseMatrix(LilSparseMatrix *sparseMatrix); |
||||
|
void printLilSparseMatrix(LilSparseMatrix sparseMatrix); |
||||
|
|
||||
|
#endif // LIL_SPARSE_MATRIX_H
|
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -0,0 +1,44 @@ |
|||||
|
#include <sys/time.h> |
||||
|
|
||||
|
#include "serial_gs_pagerank_functions.h" |
||||
|
//#include "coo_sparse_matrix.h"
|
||||
|
|
||||
|
struct timeval startwtime, endwtime; |
||||
|
double seq_time; |
||||
|
|
||||
|
int main(int argc, char **argv) { |
||||
|
CsrSparseMatrix transitionMatrix = initCsrSparseMatrix(); |
||||
|
double *pagerankVector; |
||||
|
bool convergenceStatus; |
||||
|
Parameters parameters; |
||||
|
|
||||
|
parseArguments(argc, argv, ¶meters); |
||||
|
|
||||
|
initialize(&transitionMatrix, &pagerankVector, ¶meters); |
||||
|
|
||||
|
// Starts wall-clock timer
|
||||
|
gettimeofday (&startwtime, NULL); |
||||
|
|
||||
|
int iterations = pagerank(&transitionMatrix, &pagerankVector, |
||||
|
&convergenceStatus, parameters); |
||||
|
if (parameters.verbose) { |
||||
|
printf(ANSI_COLOR_YELLOW "\n----- RESULTS -----\n" ANSI_COLOR_RESET); |
||||
|
if (convergenceStatus) { |
||||
|
printf(ANSI_COLOR_GREEN "Pagerank converged after %d iterations!\n" \ |
||||
|
ANSI_COLOR_RESET, iterations); |
||||
|
} else { |
||||
|
printf(ANSI_COLOR_RED "Pagerank did not converge after max number of" \ |
||||
|
" iterations (%d) was reached!\n" ANSI_COLOR_RESET, iterations); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Stops wall-clock timer
|
||||
|
gettimeofday (&endwtime, NULL); |
||||
|
double seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 + |
||||
|
endwtime.tv_sec - startwtime.tv_sec); |
||||
|
printf("%s wall clock time = %f\n","Pagerank (Gauss-Seidel method), serial implementation", |
||||
|
seq_time); |
||||
|
|
||||
|
free(pagerankVector); |
||||
|
destroyCsrSparseMatrix(&transitionMatrix); |
||||
|
} |
Binary file not shown.
@ -0,0 +1,525 @@ |
|||||
|
/* ===== INCLUDES ===== */ |
||||
|
|
||||
|
#include "serial_gs_pagerank_functions.h" |
||||
|
|
||||
|
/* ===== CONSTANTS ===== */ |
||||
|
|
||||
|
const char *ARGUMENT_CONVERGENCE_TOLERANCE = "-c"; |
||||
|
const char *ARGUMENT_MAX_ITERATIONS = "-m"; |
||||
|
const char *ARGUMENT_DAMPING_FACTOR = "-a"; |
||||
|
const char *ARGUMENT_VERBAL_OUTPUT = "-v"; |
||||
|
const char *ARGUMENT_OUTPUT_HISTORY = "-h"; |
||||
|
const char *ARGUMENT_OUTPUT_FILENAME = "-o"; |
||||
|
|
||||
|
const int NUMERICAL_BASE = 10; |
||||
|
char *DEFAULT_OUTPUT_FILENAME = "pagerank_output"; |
||||
|
const int FILE_READ_BUFFER_SIZE = 4096; |
||||
|
|
||||
|
const int CONVERGENCE_CHECK_ITERATION_PERIOD = 3; |
||||
|
const int SPARSITY_INCREASE_ITERATION_PERIOD = 9; |
||||
|
|
||||
|
/* ===== FUNCTIONS ===== */ |
||||
|
|
||||
|
int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector, |
||||
|
bool *convergenceStatus, Parameters parameters) { |
||||
|
// Variables declaration
|
||||
|
int iterations = 0, numberOfPages = parameters.numberOfPages; |
||||
|
double delta, *pagerankDifference, *previousPagerankVector, |
||||
|
*convergedPagerankVector, *linksFromConvergedPagesPagerankVector; |
||||
|
LilSparseMatrix linksFromConvergedPages = createLilSparseMatrix(); |
||||
|
bool *convergenceMatrix; |
||||
|
|
||||
|
// Space allocation
|
||||
|
{ |
||||
|
size_t sizeofDouble = sizeof(double); |
||||
|
// pagerankDifference used to calculate delta
|
||||
|
pagerankDifference = (double *) malloc(numberOfPages * sizeofDouble); |
||||
|
// previousPagerankVector holds last iteration's pagerank vector
|
||||
|
previousPagerankVector = (double *) malloc(numberOfPages * sizeofDouble); |
||||
|
// convergedPagerankVector is the pagerank vector of converged pages only
|
||||
|
convergedPagerankVector = (double *) malloc(numberOfPages * sizeofDouble); |
||||
|
// linksFromConvergedPagesPagerankVector holds the partial sum of the
|
||||
|
// pagerank vector, that describes effect of the links from converged
|
||||
|
// pages to non converged pages
|
||||
|
linksFromConvergedPagesPagerankVector = (double *) malloc(numberOfPages * sizeofDouble); |
||||
|
// convergenceMatrix indicates which pages have converged
|
||||
|
convergenceMatrix = (bool *) malloc(numberOfPages * sizeof(bool)); |
||||
|
*convergenceStatus = false; |
||||
|
|
||||
|
// Initialization
|
||||
|
for (int i=0; i<numberOfPages; ++i) { |
||||
|
convergedPagerankVector[i] = 0; |
||||
|
convergenceMatrix[i] = false; |
||||
|
linksFromConvergedPagesPagerankVector[i] = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (parameters.verbose) { |
||||
|
printf(ANSI_COLOR_YELLOW "\n----- Starting iterations -----\n" ANSI_COLOR_RESET); |
||||
|
} |
||||
|
|
||||
|
do { |
||||
|
// Stores previous pagerank vector
|
||||
|
memcpy(previousPagerankVector, *pagerankVector, numberOfPages * sizeof(double)); |
||||
|
|
||||
|
// Calculates new pagerank vector
|
||||
|
calculateNextPagerank(transitionMatrix, previousPagerankVector, |
||||
|
pagerankVector, linksFromConvergedPagesPagerankVector, |
||||
|
convergedPagerankVector, numberOfPages, |
||||
|
parameters.dampingFactor); |
||||
|
|
||||
|
if (parameters.history) { |
||||
|
// Outputs pagerank vector to file
|
||||
|
savePagerankToFile(parameters.outputFilename, iterations != 0, |
||||
|
*pagerankVector, numberOfPages); |
||||
|
} |
||||
|
|
||||
|
// Periodically checks for convergence
|
||||
|
if (!(iterations % CONVERGENCE_CHECK_ITERATION_PERIOD)) { |
||||
|
// Builds pagerank vectors difference
|
||||
|
for (int i=0; i<numberOfPages; ++i) { |
||||
|
pagerankDifference[i] = (*pagerankVector)[i] - previousPagerankVector[i]; |
||||
|
} |
||||
|
// Calculates convergence
|
||||
|
delta = vectorNorm(pagerankDifference, numberOfPages); |
||||
|
|
||||
|
if (delta < parameters.convergenceCriterion) { |
||||
|
// Converged
|
||||
|
*convergenceStatus = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Periodically increases sparsity
|
||||
|
if (iterations && !(iterations % SPARSITY_INCREASE_ITERATION_PERIOD)) { |
||||
|
bool *newlyConvergedPages = (bool *) malloc(numberOfPages * sizeof(bool)); |
||||
|
// Checks each individual page for convergence
|
||||
|
for (int i=0; i<numberOfPages; ++i) { |
||||
|
double difference = fabs((*pagerankVector)[i] - |
||||
|
previousPagerankVector[i]) / fabs(previousPagerankVector[i]); |
||||
|
|
||||
|
newlyConvergedPages[i] = false; |
||||
|
if (!convergenceMatrix[i] && difference < parameters.convergenceCriterion){ |
||||
|
// Page converged
|
||||
|
newlyConvergedPages[i] = true; |
||||
|
convergenceMatrix[i] = true; |
||||
|
convergedPagerankVector[i] = (*pagerankVector)[i]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (int i=0; i<numberOfPages; ++i) { |
||||
|
if (newlyConvergedPages[i] == true) { |
||||
|
int rowSize; |
||||
|
int *rowIndexes = getRowIndexes(*transitionMatrix, i, &rowSize); |
||||
|
for (int j=0; j<rowSize; ++j){ |
||||
|
/*CooSparseMatrixElement *element = transitionMatrix->elements[rowIndexes[j]];
|
||||
|
// Checks for links from converged pages to non converged
|
||||
|
int pageLinksTo = element->columnIndex; |
||||
|
if (convergenceMatrix[pageLinksTo] == false){ |
||||
|
// Link exists, adds element to the vector
|
||||
|
apendElement(&linksFromConvergedPages, |
||||
|
element->value, i, pageLinksTo); |
||||
|
}*/ |
||||
|
int pageLinksTo = transitionMatrix->columnIndexes[rowIndexes[j]]; |
||||
|
if (convergenceMatrix[pageLinksTo] == false){ |
||||
|
// Link exists, adds element to the vector
|
||||
|
apendElement(&linksFromConvergedPages, |
||||
|
transitionMatrix->values[rowIndexes[j]], i, pageLinksTo); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Increases sparsity of the transition matrix by
|
||||
|
// deleting elements that correspond to converged pages
|
||||
|
zeroOutRow(transitionMatrix, i); |
||||
|
zeroOutColumn(transitionMatrix, i); |
||||
|
|
||||
|
// Builds the new linksFromConvergedPagesPagerankVector
|
||||
|
lilSparseMatrixVectorMultiplication(linksFromConvergedPages, |
||||
|
*pagerankVector, &linksFromConvergedPagesPagerankVector, |
||||
|
numberOfPages); |
||||
|
} |
||||
|
} |
||||
|
free(newlyConvergedPages); |
||||
|
} |
||||
|
|
||||
|
++iterations; |
||||
|
// Outputs information about this iteration
|
||||
|
if (iterations%2) { |
||||
|
printf(ANSI_COLOR_BLUE "Iteration %d: delta = %f\n" ANSI_COLOR_RESET, iterations, delta); |
||||
|
} else { |
||||
|
printf(ANSI_COLOR_CYAN "Iteration %d: delta = %f\n" ANSI_COLOR_RESET, iterations, delta); |
||||
|
} |
||||
|
} while (!*convergenceStatus && (parameters.maxIterations == 0 || |
||||
|
iterations < parameters.maxIterations)); |
||||
|
|
||||
|
if (!parameters.history) { |
||||
|
// Outputs last pagerank vector to file
|
||||
|
savePagerankToFile(parameters.outputFilename, false, *pagerankVector, numberOfPages); |
||||
|
} |
||||
|
|
||||
|
// Frees memory
|
||||
|
free(pagerankDifference); |
||||
|
free(previousPagerankVector); |
||||
|
free(convergedPagerankVector); |
||||
|
free(linksFromConvergedPagesPagerankVector); |
||||
|
free(convergenceMatrix); |
||||
|
destroyLilSparseMatrix(&linksFromConvergedPages); |
||||
|
|
||||
|
return iterations; |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* 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(CsrSparseMatrix *transitionMatrix, |
||||
|
double **pagerankVector, Parameters *parameters) { |
||||
|
|
||||
|
// Reads web graph from file
|
||||
|
if ((*parameters).verbose) { |
||||
|
printf(ANSI_COLOR_YELLOW "----- Reading graph from file -----\n" ANSI_COLOR_RESET); |
||||
|
} |
||||
|
generateNormalizedTransitionMatrixFromFile(transitionMatrix, parameters); |
||||
|
|
||||
|
// Outputs the algorithm parameters to the console
|
||||
|
if ((*parameters).verbose) { |
||||
|
printf(ANSI_COLOR_YELLOW "\n----- Running with parameters -----\n" ANSI_COLOR_RESET\ |
||||
|
"Number 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; |
||||
|
} |
||||
|
|
||||
|
// Transposes the transition matrix (P^T).
|
||||
|
transposeSparseMatrix(transitionMatrix); |
||||
|
} |
||||
|
|
||||
|
// ==================== MATH UTILS ====================
|
||||
|
|
||||
|
/*
|
||||
|
* calculateNextPagerank calculates the product of the multiplication |
||||
|
* between a matrix and the a vector in a cheap way. |
||||
|
*/ |
||||
|
void calculateNextPagerank(CsrSparseMatrix *transitionMatrix, |
||||
|
double *previousPagerankVector, double **pagerankVector, |
||||
|
double *linksFromConvergedPagesPagerankVector, |
||||
|
double *convergedPagerankVector, int vectorSize, double dampingFactor) { |
||||
|
// Calculates the web uniform probability once.
|
||||
|
double webUniformProbability = 1. / vectorSize; |
||||
|
|
||||
|
csrSparseMatrixVectorMultiplication(*transitionMatrix, previousPagerankVector, |
||||
|
pagerankVector, vectorSize); |
||||
|
|
||||
|
for (int i=0; i<vectorSize; ++i) { |
||||
|
(*pagerankVector)[i] = dampingFactor * (*pagerankVector)[i]; |
||||
|
} |
||||
|
|
||||
|
double normDifference = vectorNorm(previousPagerankVector, vectorSize) - |
||||
|
vectorNorm(*pagerankVector, vectorSize); |
||||
|
|
||||
|
for (int i=0; i<vectorSize; ++i) { |
||||
|
(*pagerankVector)[i] += normDifference * webUniformProbability + |
||||
|
linksFromConvergedPagesPagerankVector[i] + convergedPagerankVector[i]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* 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; |
||||
|
} |
||||
|
|
||||
|
// ==================== PROGRAM INPUT AND OUTPUT UTILS ====================
|
||||
|
|
||||
|
/*
|
||||
|
* parseArguments parses the command line arguments given by the user. |
||||
|
*/ |
||||
|
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) { |
||||
|
if (argumentCount < 2 || argumentCount > 10) { |
||||
|
validUsage(argumentVector[0]); |
||||
|
} |
||||
|
|
||||
|
(*parameters).numberOfPages = 0; |
||||
|
(*parameters).maxIterations = 0; |
||||
|
(*parameters).convergenceCriterion = 1; |
||||
|
(*parameters).dampingFactor = 0.85; |
||||
|
(*parameters).verbose = false; |
||||
|
(*parameters).history = false; |
||||
|
(*parameters).outputFilename = DEFAULT_OUTPUT_FILENAME; |
||||
|
|
||||
|
char *endPointer; |
||||
|
int argumentIndex = 1; |
||||
|
|
||||
|
while (argumentIndex < argumentCount) { |
||||
|
if (!strcmp(argumentVector[argumentIndex], ARGUMENT_CONVERGENCE_TOLERANCE)) { |
||||
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
||||
|
|
||||
|
double convergenceInput = strtod(argumentVector[argumentIndex], &endPointer); |
||||
|
if (convergenceInput == 0) { |
||||
|
printf("Invalid convergence argument\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
(*parameters).convergenceCriterion = convergenceInput; |
||||
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_MAX_ITERATIONS)) { |
||||
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
||||
|
|
||||
|
size_t iterationsInput = strtol(argumentVector[argumentIndex], &endPointer, NUMERICAL_BASE); |
||||
|
if (iterationsInput == 0 && endPointer) { |
||||
|
printf("Invalid iterations argument\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
(*parameters).maxIterations = iterationsInput; |
||||
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_DAMPING_FACTOR)) { |
||||
|
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]); |
||||
|
|
||||
|
double alphaInput = strtod(argumentVector[argumentIndex], &endPointer); |
||||
|
if ((alphaInput == 0 || alphaInput > 1) && endPointer) { |
||||
|
printf("Invalid alpha argument\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
(*parameters).dampingFactor = alphaInput; |
||||
|
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_VERBAL_OUTPUT)) { |
||||
|
(*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) { |
||||
|
(*parameters).graphFilename = argumentVector[argumentIndex]; |
||||
|
} else { |
||||
|
validUsage(argumentVector[0]); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
++argumentIndex; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* readGraphFromFile loads the file supplied in the command line arguments to an |
||||
|
* array (directedWebGraph) that represents the graph. |
||||
|
*/ |
||||
|
void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatrix, |
||||
|
Parameters *parameters){ |
||||
|
FILE *graphFile; |
||||
|
|
||||
|
// Opens the file for reading
|
||||
|
graphFile = fopen((*parameters).graphFilename, "r+"); |
||||
|
if (!graphFile) { |
||||
|
printf("Error opening file \n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
char buffer[FILE_READ_BUFFER_SIZE]; |
||||
|
char *readResult; |
||||
|
// Skips the first two lines
|
||||
|
readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile); |
||||
|
readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile); |
||||
|
if (readResult == NULL) { |
||||
|
printf("Error while reading from the file. Does the file have the correct format?\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
// Third line contains the numbers of nodes and edges
|
||||
|
int numberOfNodes = 0, numberOfEdges = 0; |
||||
|
|
||||
|
readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile); |
||||
|
if (readResult == NULL) { |
||||
|
printf("Error while reading from the file. Does the file have the correct format?\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
// Parses the number of nodes and number of edges
|
||||
|
{ |
||||
|
// Splits string to whitespace
|
||||
|
char *token = strtok(buffer, " "); |
||||
|
bool nextIsNodes = false, nextIsEdges = false; |
||||
|
|
||||
|
while (token != NULL) { |
||||
|
if (strcmp(token, "Nodes:") == 0) { |
||||
|
nextIsNodes = true; |
||||
|
} else if (nextIsNodes) { |
||||
|
numberOfNodes = atoi(token); |
||||
|
nextIsNodes = false; |
||||
|
} else if (strcmp(token, "Edges:") == 0) { |
||||
|
nextIsEdges = true; |
||||
|
} else if (nextIsEdges) { |
||||
|
numberOfEdges = atoi(token); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// Gets next string token
|
||||
|
token = strtok (NULL, " ,.-"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if ((*parameters).verbose) { |
||||
|
printf("File claims number of pages is: %d\nThe number of edges is: %d\n", |
||||
|
numberOfNodes, numberOfEdges); |
||||
|
} |
||||
|
|
||||
|
// Skips the fourth line
|
||||
|
readResult = fgets(buffer, 512, graphFile); |
||||
|
if (readResult == NULL) { |
||||
|
printf("Error while reading from the file. Does the file have the correct format?\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
int tenPercentIncrements = (int) numberOfEdges/10; |
||||
|
int maxPageIndex = 0; |
||||
|
allocMemoryForElements(transitionMatrix, numberOfEdges); |
||||
|
|
||||
|
for (int i=0; i<numberOfEdges; i++) { |
||||
|
if (((*parameters).verbose) && (tenPercentIncrements != 0) && ((i % tenPercentIncrements) == 0)) { |
||||
|
int percentage = (i/tenPercentIncrements)*10; |
||||
|
printf("%d%% • ", percentage); |
||||
|
} |
||||
|
|
||||
|
int fileFrom = 0, fileTo = 0; |
||||
|
if (!fscanf(graphFile, "%d %d", &fileFrom, &fileTo)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (fileFrom > maxPageIndex) { |
||||
|
maxPageIndex = fileFrom; |
||||
|
} |
||||
|
if (fileTo > maxPageIndex) { |
||||
|
maxPageIndex = fileTo; |
||||
|
} |
||||
|
addElement(transitionMatrix, 1, fileFrom, fileTo); |
||||
|
|
||||
|
} |
||||
|
printf("\n"); |
||||
|
|
||||
|
if ((*parameters).verbose) { |
||||
|
printf("Max page index found is: %d\n", maxPageIndex); |
||||
|
} |
||||
|
(*parameters).numberOfPages = maxPageIndex + 1; |
||||
|
|
||||
|
// Calculates the outdegree of each page and assigns the uniform probability
|
||||
|
// of transition to the elements of the corresponding row
|
||||
|
|
||||
|
//int currentRow = transitionMatrix->elements[0]->rowIndex;
|
||||
|
int pageOutdegree = 1; |
||||
|
/*for (int i=1; i<transitionMatrix->size; ++i) {
|
||||
|
CooSparseMatrixElement *currentElement = transitionMatrix->elements[i]; |
||||
|
if (currentElement->rowIndex == currentRow) { |
||||
|
++pageOutdegree; |
||||
|
} else { |
||||
|
double pageUniformProbability = 1. / pageOutdegree; |
||||
|
for (int j=i-pageOutdegree; j<i; ++j) { //gia ola ta rows mexri to twrino apo to twrino-pageOutdegree
|
||||
|
transitionMatrix->elements[j]->value = pageUniformProbability; |
||||
|
} |
||||
|
|
||||
|
currentRow = currentElement->rowIndex; |
||||
|
pageOutdegree = 1; |
||||
|
} |
||||
|
}*/ |
||||
|
for(int i=0; i<transitionMatrix->size; ++i){ |
||||
|
if((i==0) && (transitionMatrix->rowaccInd[i]>0)){ |
||||
|
pageOutdegree+=transitionMatrix->rowaccInd[i]; |
||||
|
} |
||||
|
else if((i!=0)&&(transitionMatrix->rowaccInd[i]-transitionMatrix->rowaccInd[i-1]>0)){ |
||||
|
pageOutdegree+=transitionMatrix->rowaccInd[i]-transitionMatrix->rowaccInd[i-1] |
||||
|
} |
||||
|
else{ |
||||
|
//no connections from that row
|
||||
|
double pageUniformProbability = 1. / pageOutdegree; |
||||
|
for (int j = i-pageOutdegree; j<i ; ++j){ //gia auta ta rows
|
||||
|
transitionMatrix->values[transitionMatrix->rowaccInd[j-1]+1] = pageUniformProbability; ///???
|
||||
|
} |
||||
|
pageOutdegree = 1; |
||||
|
} |
||||
|
} |
||||
|
// Does the last row
|
||||
|
/*double pageUniformProbability = 1. / pageOutdegree;
|
||||
|
for (int j=transitionMatrix->size-pageOutdegree; j<transitionMatrix->size; ++j) { |
||||
|
transitionMatrix->elements[j]->value = pageUniformProbability; |
||||
|
}*/ |
||||
|
|
||||
|
double pageUniformProbability = 1. / pageOutdegree; |
||||
|
for (int j=transitionMatrix->size-pageOutdegree; j<transitionMatrix->size; ++j) { |
||||
|
transitionMatrix->values[transitionMatrix->rowaccInd[j-1]+1] = pageUniformProbability; |
||||
|
} |
||||
|
|
||||
|
fclose(graphFile); |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* validUsage outputs a message to the console that informs the user of the |
||||
|
* correct (valid) way to use the program. |
||||
|
*/ |
||||
|
void validUsage(char *programName) { |
||||
|
printf("%s [-c convergence_criterion] [-m max_iterations] [-a alpha] [-v] [-h] [-o output_filename] <graph_file>" \ |
||||
|
"\n-c convergence_criterion" \ |
||||
|
"\n\tthe convergence tolerance criterion" \ |
||||
|
"\n-m max_iterations" \ |
||||
|
"\n\tmaximum number of iterations to perform" \ |
||||
|
"\n-a alpha" \ |
||||
|
"\n\tthe damping factor" \ |
||||
|
"\n-v enable verbal output" \ |
||||
|
"\n-h enable history output to file" \ |
||||
|
"\n-o output_filename" \ |
||||
|
"\n\tfilename and path for the output" \ |
||||
|
"\n", programName); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
/*
|
||||
|
* checkIncrement is a helper function for parseArguments function. |
||||
|
*/ |
||||
|
int checkIncrement(int previousIndex, int maxIndex, char *programName) { |
||||
|
if (previousIndex == maxIndex) { |
||||
|
validUsage(programName); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
return ++previousIndex; |
||||
|
} |
||||
|
|
||||
|
void savePagerankToFile(char *filename, bool append, double *pagerankVector, int vectorSize) { |
||||
|
FILE *outputFile; |
||||
|
|
||||
|
if (append) { |
||||
|
outputFile = fopen(filename, "a"); |
||||
|
} else { |
||||
|
outputFile = fopen(filename, "w"); |
||||
|
} |
||||
|
|
||||
|
if (outputFile == NULL) { |
||||
|
printf("Error while opening the output file.\n"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
for (int i=0; i<vectorSize; ++i) { |
||||
|
fprintf(outputFile, "%f ", pagerankVector[i]); |
||||
|
} |
||||
|
fprintf(outputFile, "\n"); |
||||
|
|
||||
|
fclose(outputFile); |
||||
|
} |
@ -0,0 +1,99 @@ |
|||||
|
#ifndef SERIAL_GS_PAGERANK_FUNCTIONS_H /* Include guard */ |
||||
|
#define SERIAL_GS_PAGERANK_FUNCTIONS_H |
||||
|
|
||||
|
/* ===== INCLUDES ===== */ |
||||
|
|
||||
|
#include <stdbool.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include <math.h> |
||||
|
|
||||
|
#include "csr_sparse_matrix.h" |
||||
|
#include "lil_sparse_matrix.h" |
||||
|
|
||||
|
/* ===== DEFINITIONS ===== */ |
||||
|
|
||||
|
//Colors used for better console output formating.
|
||||
|
#define ANSI_COLOR_RED "\x1B[31m" |
||||
|
#define ANSI_COLOR_GREEN "\x1B[32m" |
||||
|
#define ANSI_COLOR_YELLOW "\x1B[33m" |
||||
|
#define ANSI_COLOR_BLUE "\x1B[34m" |
||||
|
#define ANSI_COLOR_CYAN "\x1B[36m" |
||||
|
#define ANSI_COLOR_RESET "\x1B[0m" |
||||
|
|
||||
|
/* ===== CONSTANTS DEFINITION ===== */ |
||||
|
|
||||
|
// Constant strings that store the command line options available.
|
||||
|
extern const char *ARGUMENT_CONVERGENCE_TOLERANCE; |
||||
|
extern const char *ARGUMENT_MAX_ITERATIONS; |
||||
|
extern const char *ARGUMENT_DAMPING_FACTOR; |
||||
|
extern const char *ARGUMENT_VERBAL_OUTPUT; |
||||
|
extern const char *ARGUMENT_OUTPUT_HISTORY; |
||||
|
extern const char *ARGUMENT_OUTPUT_FILENAME; |
||||
|
// The numerical base used when parsing numerical command line arguments.
|
||||
|
extern const int NUMERICAL_BASE; |
||||
|
// Default filename used for the output.
|
||||
|
extern char *DEFAULT_OUTPUT_FILENAME; |
||||
|
// The size of the buffer used for reading the graph input file.
|
||||
|
extern const int FILE_READ_BUFFER_SIZE; |
||||
|
|
||||
|
/* ===== STRUCTURES ===== */ |
||||
|
|
||||
|
// A data structure to conveniently hold the algorithm's parameters.
|
||||
|
typedef struct parameters { |
||||
|
int numberOfPages, maxIterations; |
||||
|
double convergenceCriterion, dampingFactor; |
||||
|
bool verbose, history; |
||||
|
char *outputFilename, *graphFilename; |
||||
|
} Parameters; |
||||
|
|
||||
|
/* ===== FUNCTION DEFINITIONS ===== */ |
||||
|
|
||||
|
// Function validUsage outputs the correct way to use the program with command
|
||||
|
// line arguments.
|
||||
|
void validUsage(char *programName); |
||||
|
|
||||
|
// Function checkIncrement is a helper function used in parseArguments (see
|
||||
|
// bellow).
|
||||
|
int checkIncrement(int previousIndex, int maxIndex, char *programName); |
||||
|
|
||||
|
// Function parseArguments parses command line arguments.
|
||||
|
void parseArguments(int argumentCount, char **argumentVector, |
||||
|
Parameters *parameters); |
||||
|
|
||||
|
// Function generateNormalizedTransitionMatrixFromFile reads through the entries
|
||||
|
// of the file specified in the arguments (parameters->graphFilename), using
|
||||
|
// them to populate the sparse array (transitionMatrix). The entries of the file
|
||||
|
// represent the edges of the web transition graph. The entries are then
|
||||
|
// modified to become the rows of the transition matrix.
|
||||
|
void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatrix, |
||||
|
Parameters *parameters); |
||||
|
|
||||
|
// Function savePagerankToFile appends or overwrites the pagerank vector
|
||||
|
// "pagerankVector" to the file with the filename supplied in the arguments.
|
||||
|
void savePagerankToFile(char *filename, bool append, double *pagerankVector, |
||||
|
int vectorSize); |
||||
|
|
||||
|
// Function initialize allocates memory for the pagerank vector, reads the
|
||||
|
// dataset from the file and creates the transition probability distribution
|
||||
|
// matrix.
|
||||
|
void initialize(CsrSparseMatrix *transitionMatrix, double **pagerankVector, |
||||
|
Parameters *parameters); |
||||
|
|
||||
|
// Function vectorNorm calculates the first norm of a vector.
|
||||
|
double vectorNorm(double *vector, int vectorSize); |
||||
|
|
||||
|
// Function calculateNextPagerank calculates the next pagerank vector.
|
||||
|
void calculateNextPagerank(CsrSparseMatrix *transitionMatrix, |
||||
|
double *previousPagerankVector, double **pagerankVector, |
||||
|
double *linksFromConvergedPagesPagerankVector, |
||||
|
double *convergedPagerankVector, int vectorSize, double dampingFactor); |
||||
|
|
||||
|
// Function pagerank iteratively calculates the pagerank of each page until
|
||||
|
// either the convergence criterion is met or the maximum number of iterations
|
||||
|
// is reached.
|
||||
|
int pagerank(CsrSparseMatrix *transitionMatrix, double **pagerankVector, |
||||
|
bool *convergenceStatus, Parameters parameters); |
||||
|
|
||||
|
#endif // SERIAL_GS_PAGERANK_FUNCTIONS_H
|
Binary file not shown.
Loading…
Reference in new issue