committed by
							
								 GitHub
								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