Browse Source

Finalization

master
Apostolos Fanakis 6 years ago
parent
commit
90f19ba482
No known key found for this signature in database GPG Key ID: 56CE2DEDE9F1FB78
  1. 8
      datasets/Stanford Large Network Dataset Collection/README.md
  2. BIN
      datasets/Stanford Large Network Dataset Collection/web-Google.tar.xz
  3. BIN
      datasets/Stanford Large Network Dataset Collection/wiki-Talk.tar.xz
  4. 3
      datasets/barabasi-90000.txt
  5. 50102
      datasets/erdos-100000.txt
  6. 428981
      datasets/java.txt
  7. 162
      filterMARP.c
  8. BIN
      matlab/package/cs-stanford.mat
  9. 893
      matlab/package/pagerank.m
  10. 109
      matlab/package/pagerank_gs_mult.c
  11. BIN
      matlab/package/pagerank_gs_mult.mexa64
  12. BIN
      matlab/package/pagerank_gs_mult.mexglx
  13. 128
      matlab/package/pagerank_mult.c
  14. BIN
      matlab/package/pagerank_mult.mexa64
  15. BIN
      matlab/package/pagerank_mult.mexglx
  16. 78
      matlab/package/spmatvec_mult.c
  17. BIN
      matlab/package/spmatvec_mult.mexa64
  18. BIN
      matlab/package/spmatvec_mult.mexglx
  19. 82
      matlab/package/spmatvec_transmult.c
  20. BIN
      matlab/package/spmatvec_transmult.mexa64
  21. BIN
      matlab/package/spmatvec_transmult.mexglx
  22. 17
      openmp/openmp_gs_pagerank_functions.c
  23. 37
      pthread/Makefile
  24. 132
      pthread/coo_sparse_matrix.c
  25. 60
      pthread/coo_sparse_matrix.h
  26. 92
      pthread/csr_sparse_matrix.c
  27. 47
      pthread/csr_sparse_matrix.h
  28. BIN
      pthread/pagerank.out
  29. 42
      pthread/serial_gs_pagerank.c
  30. 610
      pthread/serial_gs_pagerank_functions.c
  31. 100
      pthread/serial_gs_pagerank_functions.h
  32. 4
      serial/Makefile
  33. 17
      serial/serial_gs_pagerank_functions.c

8
datasets/Stanford Large Network Dataset Collection/README.md

@ -1,8 +0,0 @@
The datasets on this folder where downloaded from the website of the Stanford Network Analysis Project (SNAP), found [here](https://snap.stanford.edu/data/).
More details about the datasets can be found in the table bellow.
| Dataset directory | Description | Nodes | Edges | URL link |
| ----------- | ----------- | ----------- | ----------- | ----------- |
| web-Google | "web-Google" | 875,713 | 5,105,039 | [link](https://snap.stanford.edu/data/web-Google.html) |
| wiki-Talk | "wiki-Talk" | 2,394,385 | 5,021,410 | [link](https://snap.stanford.edu/data/wiki-Talk.html) |

BIN
datasets/Stanford Large Network Dataset Collection/web-Google.tar.xz

Binary file not shown.

BIN
datasets/Stanford Large Network Dataset Collection/wiki-Talk.tar.xz

Binary file not shown.

3
datasets/barabasi-90000.txt

@ -1,7 +1,4 @@
# Directed graph (each unordered pair of nodes is saved once): web-Google.txt
# Webgraph from the Google programming contest, 2002
# Nodes: 90000 Edges: 89999 # Nodes: 90000 Edges: 89999
# FromNodeId ToNodeId
1 0 1 0
2 0 2 0
3 1 3 1

50102
datasets/erdos-100000.txt

File diff suppressed because it is too large

428981
datasets/java.txt

File diff suppressed because it is too large

162
filterMARP.c

@ -1,162 +0,0 @@
//ALGORITHM 6
//p_1 is period 1, p_2 is period 2 in no. of iterations
float** filterMARP(int** A, float* x, float e, int max_iterations, float a, int p_1, int p_2, int size){
float* x_new, x_c, y;
int count = 0;
float norm = 1.0;
int* N, C, N_new, C_new;
int** Ann, Acn;
int i;
/*********** ...malloc... *************/
x_new = malloc(size*sizeof(float));
x_c = malloc(size*sizeof(float));
y = malloc(size*sizeof(float));
N = malloc(size*sizeof(int));
C = malloc(size*sizeof(int));
N_new = malloc(size*sizeof(int));
C_new = malloc(size*sizeof(int));
Ann = malloc(size*sizeof(int *));
for(i=0; i<size; i++){
Ann[i] = malloc(size*sizeof(int));
}
Acn = malloc(size*sizeof(int *));
for(i=0; i<size; i++){
Acn[i] = malloc(size*sizeof(int));
}
/******************* start iterations ********************/
while(count<max_iterations && norm<e){
if(count == 0){
gauss_Seidel(x, x_new, A, NULL, NULL, a, size);
}
else{
gauss_Seidel(x, x_new, Ann, Acn, x_c, a, size);
}
count++;
if(count%p_1==0){
N = N_new; //might not be needed
C = C_new;
detect_Converged(N_new, C_new, x_new, x, e, size); //sinthiki stin prwti selida toy prwtou kefalaiou
filterA(A, Ann, Acn, C_new, N_new, size); //
y = compy(Acn, x, size);//Acn*x ;
x_c = filterx(x_new, C, size);
}
if(count%p_2==0){
norm = comp_norm(x_new, A); //||A*x - x||
}
x = x_new;
}
return x_new;
}
void detect_Converged(int* N_new, int* C_new, float* x_new, float* x, float e, int size){
int i;
for( i=0; i<size; i++){
if((norm(x_new[i] - x[i])/norm(x[i]))<e){ // 10 ^ -3
//converged
N_new[i] = 0;
C_new[i] = 1;
}
else{
N_new[i] = 1;
C_new[i] = 0;
}
}
return;
}
float* compy(int** Acn, float* x, int size){ //Acn*x pollaplasiasmos
float* y;
y = malloc(size*sizeof(float));
int i,j;
for(i=0; i<size; i++){
for(j=0; j<size; j++){
y[i] += Acn[i][j]*x[j];
}
}
return y;
}
void filterA(int** A, int** Ann, int** Acn, int* C_new, int* N_new, int size){
int i,j;
for(i=0; i<size; i++){
if(C_new[i] == 1){
for(j = 0; j<size;j++){
Ann[i][j] = 0; //sxesi 10 sto pdf
}
}
else{
for(j = 0; j<size;j++){
Ann[i][j] = A[i][j]; //sxesi 10 sto pdf
}
}
}
//Acn part: pages that have converged to pages that haven't
// assuming A is column - based transition matrix (since it was transposed)
for(i=0; i<size; i++){
for(j=0; j<size ; j++){
if(C_new[j] == 1 && N_new[i] == 1){
Acn[i][j] = A[i][j];
}
else{
Acn[i][j] = 0;
}
}
}
}
float* filterx(float* xnew, int* C_new, int size){
int i,j;
float *x_c;
x_c = malloc(size*sizeof(float));
for(i=0; i<size; i++){
if(C_new[i] == 1){
x_c[i] = x[i];
}
else{
x_c[i] = 0;
}
}
return x_c;
}
void gauss_Seidel(float* x, float* x_new, int** Ann, int** Acn, float* x_c, float* y, float a, int size){
int i, j;
float sum1 = 0;
float sum2 = 0;
x_new = x; //giati ston algorithmo leei most updated values na xrisimopoiountai gia to sum1
if(Acn == NULL && x_c == NULL){
for(i=0; i<size; i++){
for(j=0;j<i;j++){
sum1 += Ann[i][j]*x_new[j]; //einai o pinakas A afou einai i prwti epanalipsi
}
for(j=i;j<size;j++){
sum2 += Ann[i][j]*x[j];
}
x_new[i] = (1-a)+a*sum1+a*sum2;
}
}
else{
for(i=0; i<size; i++){
for(j=0;j<i;j++){
sum1 += Ann[i][j]*x_new[j];
}
for(j=i;j<size;j++){
sum2 += Ann[i][j]*x[j];
}
x_new[i] = (1-a)+a*sum1+a*sum2+y[i]+x_c[i];
}
}
}

BIN
matlab/package/cs-stanford.mat

Binary file not shown.

893
matlab/package/pagerank.m

@ -1,893 +0,0 @@
function [x flag hist dt] = pagerank(A,optionsu)
% PAGERANK Compute the PageRank for a directed graph.
%
% [p flag hist dt] = pagerank(A)
%
% Compute the pagerank vector p for the directed graph A, with
% teleportation probability (1-c).
%
% flag is 1 if the method converged; hist returns the convergence history
% and dt is the total time spent solving the system
%
% The matrix A should have the outlinks represented in the rows.
%
% This driver can compute PageRank using 4 different algorithms,
% the default algorithm is the Arnoldi iteration for PageRank due to
% Grief and Golub. Other algorithms include gauss-seidel iterations,
% power iterations, a linear system formulation, or an approximate
% PageRank formulation.
%
% The output p satisfies p = c A'*D^{+} p + c d'*p v + (1-c) v and
% norm(p,1) = 1.
%
% The power method solves the eigensystem x = P''^T x.
% The linear system solves the system (I-cP^T)x = (1-c)v.
% The dense method uses "\" on I-cP^T which the LU factorization.
%
% To specify a different solver for the linear system, use an anonymous
% function wrapper around one of Matlab's solver calls. To use GMRES,
% call pagerank(..., struct('linsolver', ...
% @(f,v,tol,its) gmres(f,v,[],tol, its)))
%
% Note 1: the 'approx' algorithm is the PageRank approximate personalized
% PageRank algorithm due to Gleich and Polito. It creates a set of
% active pages and runs until either norm(p(boundary),1) < options.bp or
% norm(p(boundary),inf) < options.bp, where the boundary is defined as
% the set of pages that have a non-zero personalized PageRank but are not
% in the set of active pages. As options.bp -> 0, both of these
% approximations compute the actual personalized PageRank vector.
%
% Note 2: the 'eval' algorithm evaluates five algorithms to compute the
% PageRank vector and summarizes the results in a report. The return
% from the algorithm are a set of cell arrays where
% p = cell(5,1), flag = cell(5,1), hist = cell(5,1), dt = cell(5,1)
% and each cell contains the result from one algorithm.
% p{1} is the vector computed from the 'power' algorithm
% p{2} is the vector computed from the 'gs' algorithm
% p{3} is the vector computed from the 'arnoldi' algorithm
% p{4} is the vector computed from the 'linsys' algorithm with bicgstab
% p{5} is the vector comptued from the 'linsys' algorithm with gmres
% the other outputs all match these indices.
%
% pagerank(A,options) specifies optional parameters
% options.c: the teleportation coefficient [double | {0.85}]
% options.tol: the stopping tolerance [double | {1e-7}]
% options.v: the personalization vector [vector | {uniform: 1/n}]
% options.maxiter maximum number of iterations [integer | {500}]
% options.verbose: extra output information [{0} | 1]
% options.x0: the initial vector [vector | {options.v}]
% options.alg: force the algorithm type
% ['gs' | 'power' | 'linsys' | 'dense' | {'arnoldi'} | ...
% 'approx' | 'eval']
%
% options.linsys_solver: a function handle for the linear solver used
% with the linsys option [fh | {@(f,v,tol,its) bicgstab(f,v,tol,its)}]
% options.arnoldi_k: use a k dimensional arnoldi basis [intger | {8}]
% options.approx_bp: boundary probability to expand [float | 1e-3]
% options.approx_boundary: when to expand on the boundary [1 | {inf}]
% options.approx_subiter: number of subiterations of power iterations
% [integer | {5}]
%
% Example:
% load cs-stanford;
% p = pagerank(A);
% p = pagerank(A,struct('alg','linsys',...
% 'linsys_solver',@(f,v,tol,its) gmres(f,v,[],tol, its)));
% pagerank(A,struct('alg','eval'));
%
% pagerank.m
% David Gleich
%
%
% 21 February 2006
% -- added approximate PageRank
%
% Revision 1.10
% 28 January 2006
% -- added different computational modes and timing information
%
% Revision 1.00
% 19 Octoboer 2005
%
%
% The driver does mainly parameter checking, then sends things off to one
% of the computational routines.
%
[m n] = size(A);
if (m ~= n)
error('pagerank:invalidParameter', 'the matrix A must be square');
end;
options = struct('tol', 1e-7, 'maxiter', 500, 'v', ones(n,1)./n, ...
'c', 0.85, 'verbose', 0, 'alg', 'arnoldi', ...
'linsys_solver', @(f,v,tol,its) bicgstab(f,v,tol,its), ...
'arnoldi_k', 8, 'approx_bp', 1e-3, 'approx_boundary', inf,...
'approx_subiter', 5);
if (nargin > 1)
options = merge_structs(optionsu, options);
end;
if (size(options.v) ~= size(A,1))
error('pagerank:invalidParameter', ...
'the vector v must have the same size as A');
end;
if (~issparse(A))
A = sparse(A);
end;
% normalize the matrix
P = normout(A);
switch (options.alg)
case 'dense'
[x flag hist dt] = pagerank_dense(P, options);
case 'linsys'
[x flag hist dt] = pagerank_linsys(P, options);
case 'gs'
[x flag hist dt] = pagerank_gs(P, options);
case 'power'
[x flag hist dt] = pagerank_power(P, options);
case 'arnoldi'
[x flag hist dt] = pagerank_arnoldi(P, options);
case 'approx'
[x flag hist dt] = pagerank_approx(P, options);
case 'eval'
[x flag hist dt] = pagerank_eval(P, options);
otherwise
error('pagerank:invalidParameter', ...
'invalid computation mode specified.');
end;
% ===================================
% pagerank_linsys
% ===================================
function [x flag hist dt] = pagerank_linsys(P, options)
if (options.verbose > 0)
fprintf('linear system computation...\n');
end;
tol = options.tol;
v = options.v;
maxiter = options.maxiter;
c = options.c;
solver = options.linsys_solver;
% transpose P (see pagerank_linsys_mult docs)
P = P';
f = @(x,varargin) pagerank_linsys_mult(x,P,c,length(varargin));
tic;
[x flag ignore1 ignore2 hist] = solver(f,v,tol,maxiter);
dt = toc;
% renormalize the vector to have norm 1
x = x./norm(x,1);
function y = pagerank_linsys_mult(x,P,c,tflag)
% compute the matrix vector product for the linear system. This function
% includes the transpose flag (tflag > 0) to indicate a transpose multiply.
% Because many of the algorithms just use A*x (and not A'*x) the matrix P
% should have already been transposed.
if (tflag > 0)
%y = x - c*P'*x;
y = x - c*spmatvec_transmult(P,x);
else
%y = x - c*P*x;
y = x - c*spmatvec_mult(P,x);
end;
% ===================================
% pagerank_dense
% ===================================
function [x flag hist dt] = pagerank_dense(P, options)
% solve as a dense linear system
if (options.verbose > 0)
fprintf('dense computation...\n');
end;
v = options.v;
c = options.c;
n = size(P,1);
P = eye(n) - c*full(P)';
tic;
x = P \ v;
dt = toc;
hist = norm(P*x - v,1);
flag = 0;
% renormalize the vector to have norm 1
x = x./norm(x,1);
% ===================================
% pagerank_gs
% ===================================
function [x flag hist dt] = pagerank_gs(P, options)
% use gauss-seidel computation
if (options.verbose > 0)
fprintf('gauss-seidel computation...\n');
end;
tol = options.tol;
v = options.v;
maxiter = options.maxiter;
c = options.c;
x = v;
if (isfield(options, 'x0'))
x = options.x0;
else
% this is dumb, but we need to make sure
% we actually get x it's own memory...
% right now, Matlab just has a ``shadow copy''
x(1) = x(1)-1.0;
x(1) = x(1)+1.0;
end;
delta = 1;
iter = 0;
P = -c*P;
hist = zeros(maxiter,1);
dt = 0;
while (delta > tol && iter < maxiter)
tic;
xold = pagerank_gs_mult(P,x,(1-c)*v);
dt = dt + toc;
delta = norm(x - xold,1);
hist(iter+1) = delta;
if (options.verbose > 0)
fprintf('iter=%d; delta=%f\n', iter, delta);
end;
iter = iter + 1;
end;
% resize hist
hist = hist(1:iter);
% renormalize the vector to have norm 1
x = x./norm(x,1);
% default is convergence
flag = 0;
if (delta > tol && iter == maxiter)
warning('pagerank:didNotConverge', ...
'The PageRank algorithm did not converge after %i iterations', ...
maxiter);
flag = 1;
end;
% ===================================
% pagerank_power
% ===================================
function [x flag hist dt] = pagerank_power(P, options)
% use the power iteration algorithm
if (options.verbose > 0)
fprintf('power iteration computation...\n');
end;
tol = options.tol;
v = options.v;
maxiter = options.maxiter;
c = options.c;
x = v;
if (isfield(options, 'x0'))
x = options.x0;
end;
hist = zeros(maxiter,1);
delta = 1;
iter = 0;
dt = 0;
while (delta > tol && iter < maxiter)
tic;
y =c* spmatvec_transmult(P,x);
w = 1 - norm(y,1);
y = y + w*v;
dt = dt + toc;
delta = norm(x - y,1);
hist(iter+1) = delta;
tic;
x = y;
dt = dt + toc;
if (options.verbose > 0)
fprintf('iter=%d; delta=%f\n', iter, delta);
end;
iter = iter + 1;
end;
% resize hist
hist = hist(1:iter);
flag = 0;
if (delta > tol && iter == maxiter)
warning('pagerank:didNotConverge', ...
'The PageRank algorithm did not converge after %i iterations', ...
maxiter);
flag = 1;
end;
% ===================================
% pagerank_arnoldi
% ===================================
function [x flag hist dt] = pagerank_arnoldi(P, options)
% use the power iteration algorithm
if (options.verbose > 0)
fprintf('arnoldi method computation...\n');
end;
tol = options.tol;
v = options.v;
maxiter = options.maxiter;
c = options.c;
k = options.arnoldi_k;
x = v;
if (isfield(options, 'x0'))
x = options.x0;
end;
hist = zeros(maxiter,1);
d = dangling(P);
d = double(d);
P = P';
%f = @(x) pagerank_arnoldi_mult(x,P,c,d,v);
f = @(x) pagerank_mult(x,P,c,d,v);
iter = 0;
dt = 0;
delta = 1;
while (delta > tol && iter < maxiter)
tic;
[Q H] = pagerank_arnoldi_fact(f,x,k);
[u,s,v]=svd(H-[speye(k);zeros(1,k)]);
x=Q(:,1:k)*v(:,k);
dt = dt + toc;
% for statistics purposes only
delta=norm(f(x)-x,1)/norm(x,1);
hist(iter+1) = delta;
if (options.verbose > 0)
fprintf('iter=%d; delta=%f\n', iter, delta);
end;
iter = iter + 1;
end;
% ensure correct normalization
x = sign(sum(x))*x;
x = x/norm(x,1);
% resize hist
hist = hist(1:iter);
flag = 0;
if (delta > tol && iter == maxiter)
warning('pagerank:didNotConverge', ...
'The PageRank algorithm did not converge after %i iterations', ...
maxiter);
flag = 1;
end;
function [V,H] = pagerank_arnoldi_fact(A,V,k)
% [Q,H] = ARNOLDI7(A,Q0,K,c,d,e,v)
%
% ARNOLDI: Reduce an n x n matrix A to upper Hessenberg form.
% [Q,H] = ARNOLDI(A,Q0,K) computes (k+1) x k upper
% Hessenberg matrix H and n x k matrix Q with orthonormal
% columns and Q(:,1) = Q0/NORM(Q0), such that
% Q(:,1:k+1)'*A*Q(:,1:k) = H.
%
% A can also be a function_handle to return A*x
%
%
% Written by Chen Grief
% modified by David Gleich
%
V(:,1) = V(:,1)/norm(V(:,1));
if (~isa(A,'function_handle'))
f = @(x) A*x;
A = f;
end;
w = A(V(:,1));
alpha=V(:,1)'*w;
H(1,1)=alpha;
f(:,1)=w-V(:,1)*alpha;
for j=1:k-1
beta=norm(f(:,j));
V(:,j+1)=f(:,j)/beta;
ejt=[zeros(1,j-1) beta];
Hhat=[H; ejt];
w=A(V(:,j+1));
h=V(:,1:j+1)'*w;
f(:,j+1)=w-V(:,1:j+1)*h;
H=[Hhat h];
end
% Extend Arnoldi factorization
beta=norm(f(:,k));
V(:,k+1) = f(:,k)/beta;
ejt=[zeros(1,k-1) beta];
H=[H ;ejt];
% ===================================
% pagerank_approx
% ===================================
function [x flag hist dt] = pagerank_approx(A, options)
% use the power iteration algorithm
if (options.verbose > 0)
fprintf('approximate computation...\n');
end;
tol = options.tol;
v = options.v;
maxiter = options.maxiter;
c = options.c;
bp = options.approx_bp;
subiter = options.approx_subiter;
boundary = options.approx_boundary;
n = size(A,1);
%x = v;
%if (isfield(options, 'x0'))
% x = options.x0;
%end;
if (length(find(v)) ~= n)
global_pr = 0;
else
global_pr = 1;
error('pagerank:invalidParameter',...
'approximation computations are not implemented for global pagerank yet');
end;
hist = zeros(maxiter,1);
delta = 1;
iter = 0;
dt = 0;
% set the initial set of seed pages
if (global_pr)
if (isfield(options, 'x0'))
% the seed pages come from the x0 vector if provided
p = find(options.x0);
x = x0(p);
else
% the seed pages come from the x0 vector (otherwise, choose random)
p = unique(ceil(rand(250,1)*size(P,1)));
x = ones(length(p),1)./length(p);
end;
else
% the seed pages come from the x0 vector
p = find(v);
x = ones(length(p),1)./length(p);
v = v(p);
end;
local = [];
active = p;
frontier = p;
tic;
while (iter <= maxiter && delta > tol)
% expand all pages
if (boundary == 1)
% if we are running the boundary algorithm...
[ignore sp] = sort(-x);
cs = cumsum(x(sp));
spactive = active(sp);
allexpand_ind = cs < (1-bp);
% actually, we need to add the first 0 after the last 1 in
% allexpand_ind because we need cumsum to be larger than 1-bp
allexpand_ind(min(find(allexpand_ind == 0))) = ~0;
allexpand = spactive(allexpand_ind);
toexpand = setdiff(allexpand,local);
else
%
% otherwise, just expand all pages with a sufficient tolerance
%
allexpand = active(x > bp);
toexpand = setdiff(allexpand,local);
end;
if (length(toexpand) > 0)
xp = zeros(n,1);
xp([local frontier]) = x;
local = [local toexpand];
frontier = setdiff(find(sum(A(local,:),1)), local);
active = [local frontier];
x = xp(local);
else
xp = zeros(n,1);
xp([local frontier]) = x;
x = xp(local);
end;
Lp = A(local,active);
outdegree = full(sum(Lp,2));
outdegree = [outdegree; zeros(length(frontier),1)];
siter = 0;
L = [Lp; sparse(length(frontier),length(active))];
x2 = [x; xp(frontier)];
while (siter < subiter)
y = full(c*L'*(invzero(outdegree).*x2));
omega = 1 - norm(y,1);
% the ordering of local is preseved, so these are always the
% correct vertices
y(1:length(p)) = y(1:length(p)) + omega*v;
x2 = y;
siter = siter+1;
end;
x2 = [x; xp(frontier)];
delta = norm(y-x2,1);
hist(iter+1) = delta;
if (options.verbose > 0)
fprintf('iter=%02i; delta=%0.03e expand=%i\n', iter, delta, length(toexpand));
end
x = y;
iter = iter + 1;
end;
dt = toc;
% resize hist
hist = hist(1:iter);
xpartial = x;
x = zeros(n,1);
x([local frontier]) = xpartial;
flag = 0;
if (delta > tol && iter == maxiter)
warning('pagerank:didNotConverge', ...
'The PageRank algorithm did not converge after %i iterations', ...
maxiter);
flag = 1;
end;
no% ===================================
% pagerank_eval
% ===================================
function [x flag hist dt] = pagerank_eval(P,options)
algs = {'power', 'gs', 'arnoldi', 'linsys', 'linsys'};
extra_opts = {struct(''), struct(''), struct(''), struct(''), ...
struct('linsys_solver',@(f,v,tol,its) gmres(f,v,8,tol, its))};
names = {'power', 'gs', 'arnoldi8', 'bicgstab', 'gmres8'};
v = options.v;
c = options.c;
x = cell(5,1);
flag = cell(5,1);
hist = cell(5,1);
dt = cell(5,1);
web('text://<html><body>Generating PageRank report...</body></html>','-noaddressbox');
htmlend = '</body></html>';
s = {};
s{1} = '<html><head><title>PageRank runtime report</title></head><body><h1>PageRank Report</h1>';
stemp = s;
stemp{end+1} = '<p>Generating graph statistics...</p>';
stemp{end+1} = htmlend;
A = spones(P);
d = dangling(P);
npages = size(P,1);
nedges = nnz(P);
ndangling = sum(d);
maxindeg = full(max(sum(A,1)));
maxoutdeg = full(max(sum(A,2)));
ncomp = components(A);
s{end+1} = '<h2>Graph statistics</h2>';
s{end+1} = '<table border="0" cellspacing="4">';
s{end+1} = sprintf('<tr><td style="font-weight: bold">%s:</td><td>%i</td></tr>', ...
'Number of pages', npages);
s{end+1} = sprintf('<tr><td style="font-weight: bold">%s:</td><td>%i</td></tr>', ...
'Number of edges', nedges);
s{end+1} = sprintf('<tr><td style="font-weight: bold">%s:</td><td>%i</td></tr>', ...
'Number of dangling nodes', ndangling);
s{end+1} = sprintf('<tr><td style="font-weight: bold">%s:</td><td>%i</td></tr>', ...
'Max in-degree', maxindeg);
s{end+1} = sprintf('<tr><td style="font-weight: bold">%s:</td><td>%i</td></tr>', ...
'Max out-degree', maxoutdeg);
s{end+1} = sprintf('<tr><td style="font-weight: bold">%s:</td><td>%i</td></tr>', ...
'Number of strong components:', ncomp);
s{end+1} = '</table>';
sOut = [stemp{:}];
web(['text://' sOut],'-noaddressbox');
s{end+1} = '<h2>Algorithm performance</h2>';
s{end+1} = '<table border="0">';
s{end+1} = sprintf('<tr><td style="text-align: right">%s</td><td>%0.3f</td></tr>', ...
'c = ', c);
s{end+1} = sprintf('<tr><td style="text-align: right">%s</td><td>%2.2e</td></tr>', ...
'tol = ', options.tol);
s{end+1} = sprintf('<tr><td style="text-align: right">%s</td><td>%i</td></tr>', ...
'maxiter = ', options.maxiter);
s{end+1} = '</table>';
s{end+1} = '<table border="0">';
s{end+1} = ['<tr style="text-align: left">' ...
'<th style="border-bottom:solid 1px">Algorithm</th>' ...
'<th style="border-bottom:solid 1px">Time</th>' ...
'<th style="border-bottom:solid 1px">Iterations</th>' ...
'<th style="border-bottom:solid 1px">Error</th></tr>'];
for (ii=1:length(algs))
alg = algs{ii};
extra_opt = extra_opts{ii};
name = names{ii};
stemp = s;
stemp{end+1} = '</table>';
stemp{end+1} = sprintf('<p>Solving for PageRank with %s...</p>', char(name));
stemp{end+1} = htmlend;
sOut = [stemp{:}];
web(['text://' sOut],'-noaddressbox');
extra_opt = merge_structs(struct('alg',char(alg)),extra_opt);
[pi flagi histi dti] = pagerank(P, merge_structs(extra_opt,options));
p{ii} = pi;
flag{ii} = flagi;
hist{ii} = histi;
dt{ii} = dti;
err = norm(pi - c*(pi'*P)' - c*(d'*pi)*v - (1-c)*v,1);
if (mod(ii,2) == 0)
s{end+1} = sprintf('<tr style="background-color: #cccccc"><td>%s</td><td>%.2f</td><td>%i</td><td>%2.2e</td></tr>',...
char(name), dti, length(histi), err);
else
s{end+1} = sprintf('<tr><td>%s</td><td>%.2f</td><td>%i</td><td>%2.2e</td></tr>',...
char(name), dti, length(histi), err);
end;
end
s{end+1} = '</table>';
s{end+1} = htmlend;
sOut = [s{:}];
web(['text://' sOut],'-noaddressbox');
s{end+1} = sprintf('<tr><td>%s</td><td></td><td></td><td></td></tr>',char(name));
%
% plot the time histogram
%
figure(1);
close(1);
figure(1);
dts = cell2mat(dt);
flags = cell2mat(flag);
h2 = bar(dts.*(flags==0));
set(h2,'FaceColor',[1 1 1]);
set(h2,'LineWidth',2.0);
set(gca,'XTick', 1:length(algs));
set(gca,'XTickLabel',names);
ylabel('time (sec)');
%
% plot the history results
%
figure(2);
close(2);
figure(2);
lso = get(0,'DefaultAxesLineStyleOrder');
lsc = get(0,'DefaultAxesColorOrder');
lso = {'o-', 'x:', '+-.', 's--', 'd-'};
nlso = length(lso);
curlso = 0;
nlsc = length(lsc);
curlsc = 0;
for ii=1:length(algs)
histi = hist{ii};
%legendname = fn{ii};
%line(1:length(mrval.hist), mrval.hist);
semilogy(1:length(histi),histi,...
lso{mod(curlso,nlso)+1}, ...
'Color',lsc(mod(curlsc,nlsc)+1,:),...
'MarkerSize',3);
hold on;
curlso = curlso+1;
curlsc = curlsc+1;
end;
title('PageRank algorithm convergence (WARNING: DIFFERENT Y-SCALES)');
xlabel('iteration')';
ylabel('convergence measure');
legend(names{:});
function S = merge_structs(A, B)
% MERGE_STRUCTS Merge two structures.
%
% S = merge_structs(A, B) makes the structure S have all the fields from A
% and B. Conflicts are resolved by using the value in A.
%
%
% merge_structs.m
% David Gleich
%
% Revision 1.00
% 19 Octoboer 2005
%
S = A;
fn = fieldnames(B);
for ii = 1:length(fn)
if (~isfield(A, fn{ii}))
S.(fn{ii}) = B.(fn{ii});
end;
end;
function P = normout(A)
% NORMOUT Normalize the outdegrees of the matrix A.
%
% P = normout(A)
%
% P has the same non-zero structure as A, but is normalized such that the
% sum of each row is 1, assuming that A has non-negative entries.
%
%
% normout.m
% David Gleich
%
% Revision 1.00
% 19 Octoboer 2005
%
% compute the row-sums/degrees
d = full(sum(A,2));
% invert the non-zeros in the data
id = invzero(d);
% scale the rows of the matrix
P = diag(sparse(id))*A;
function v = invzero(v)
% INVZERO Compute the inverse elements of a vector with zero entries.
%
% iv = invzero(v)
%
% iv is 1./v except where v = 0, in which case it is 0.
%
%
% invzero.m
% David Gleich
%
% Revision 1.00
% 19 Octoboer 2005
%
% sparse input are easy to handle
if (issparse(v))
[m n] = size(v);
[i j val] = find(v);
val = 1./val;
v = sparse(i,j,val,m,n);
return;
end;
% so are dense input
% compute the 0 mask
zm = abs(v) > eps(1);
% invert all non-zeros
v(zm) = 1./v(zm);
function dmask = dangling(A)
% DANGLING Compute the indicator vector for dangling links for webgraph A
%
% d = dangling(A)
%
d = full(sum(A,2));
dmask = d == 0;
function [k,sizes]=components(A)
% based on components.m from (MESHPART Toolkit)
% which had
% John Gilbert, Xerox PARC, 8 June 1992.
% Copyright (c) 1990-1996 by Xerox Corporation. All rights reserved.
% HELP COPYRIGHT for complete copyright and licensing notice
[p,p,r,r] = dmperm(A|speye(size(A)));
sizes = diff(r);
k = length(sizes);

109
matlab/package/pagerank_gs_mult.c

@ -1,109 +0,0 @@
/*
* =============================================================
* pagerank_gs_mult.c Compute the matrix vector multiplication
* for the gauss seidel iteration in an efficient manner
* (that is, by overwriting the vector x in place.)
*
* David Gleich
* Stanford University
* 28 January 2006
* =============================================================
*/
#include "mex.h"
/*
* The mex function just computes one matrix-vector product.
*/
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
int i, j, k;
int n, mrows, ncols;
/* sparse matrix */
int A_nz;
int *A_row, *A_col;
double *A_val;
double *x, *b;
double *xold;
if (nrhs != 3)
{
mexErrMsgTxt("Three inputs required.");
}
else if (nlhs > 1)
{
mexErrMsgTxt("Too many output arguments");
}
mrows = mxGetM(prhs[0]);
ncols = mxGetN(prhs[0]);
if (mrows != ncols ||
!mxIsSparse(prhs[0]) ||
!mxIsDouble(prhs[0]) ||
mxIsComplex(prhs[0]))
{
mexErrMsgTxt("Input must be a noncomplex square sparse matrix.");
}
/* okay, the first input passes */
n = mrows;
/* The second input must be a vector. */
if (mxGetM(prhs[1])*mxGetN(prhs[1]) != n ||
mxIsSparse(prhs[1]) || !mxIsDouble(prhs[1]))
{
mexErrMsgTxt("Invalid vector.");
}
/* The third input must be a vector. */
if (mxGetM(prhs[2])*mxGetN(prhs[2]) != n ||
mxIsSparse(prhs[2]) || !mxIsDouble(prhs[2]))
{
mexErrMsgTxt("Invalid vector.");
}
/* Get the sparse matrix */
A_nz = mxGetNzmax(prhs[0]);
A_val = mxGetPr(prhs[0]);
A_row = mxGetIr(prhs[0]);
A_col = mxGetJc(prhs[0]);
/* Get the vector x */
x = mxGetPr(prhs[1]);
/* Get the vector b */
b = mxGetPr(prhs[2]);
/* if they request x old, then we need to copy x to xold */
if (nlhs > 0)
{
plhs[0] = mxDuplicateArray(prhs[1]);
}
/* Update x in place, this means we have to iterate over columns
* of the matrix A. */
for (i = 0; i < n; i++)
{
/* we actually compute one iteration for the
* system (I+A')x = b */
double aself = 1.0;
double xnew = b[i];
for (j = A_col[i]; j < A_col[i+1]; ++j)
{
/* add to aself only if the row = i (the column) */
aself += A_val[j]*(A_row[j] == i);
/* add to xnew only if row != i */
xnew -= A_val[j]*x[A_row[j]]*(A_row[j] != i);
}
x[i] = xnew/aself;
}
}

BIN
matlab/package/pagerank_gs_mult.mexa64

Binary file not shown.

BIN
matlab/package/pagerank_gs_mult.mexglx

Binary file not shown.

128
matlab/package/pagerank_mult.c

@ -1,128 +0,0 @@
/*
* =============================================================
* pagerank_mult.c Compute the matrix vector multiplication
* between the PageRank matrix and a vector
*
* David Gleich
* Stanford University
* 14 February 2006
* =============================================================
*/
#include "mex.h"
/*
* The mex function just computes one matrix-vector product.
*
* function y = pagerank_mult(x,Pt,c,d,v)
* y = c*Pt*x + (c*(d'*x))*v + (1-c)*sum(x)*v;
*/
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
int i, j, k;
int n, mrows, ncols;
/* sparse matrix */
int *A_row, *A_col;
double *A_val;
double *x, *d, *v;
double c;
double *y;
double sum_x;
double dtx;
double xval;
if (nrhs != 5)
{
mexErrMsgTxt("5 inputs required.");
}
else if (nlhs > 1)
{
mexErrMsgTxt("Too many output arguments");
}
mrows = mxGetM(prhs[1]);
ncols = mxGetN(prhs[1]);
if (mrows != ncols ||
!mxIsSparse(prhs[1]) ||
!mxIsDouble(prhs[1]) ||
mxIsComplex(prhs[1]))
{
mexErrMsgTxt("Input must be a noncomplex square sparse matrix.");
}
/* okay, the second input passes */
n = mrows;
/* The first input must be a vector. */
if (mxGetM(prhs[0])*mxGetN(prhs[0]) != n ||
mxIsSparse(prhs[0]) || !mxIsDouble(prhs[0]))
{
mexErrMsgTxt("Invalid vector 1.");
}
/* The third input must be a scalar. */
if (mxGetM(prhs[2])*mxGetN(prhs[2]) != 1 || !mxIsDouble(prhs[0]))
{
mxErrMsgTxt("Invalid scalar 3.");
}
/* The fourth input must be a scalar. */
if (mxGetM(prhs[3])*mxGetN(prhs[3]) != n ||
mxIsSparse(prhs[3]) || !mxIsDouble(prhs[3]))
{
mexErrMsgTxt("Invalid vector 4.");
}
/* The fifth input must be a scalar. */
if (mxGetM(prhs[4])*mxGetN(prhs[4]) != n ||
mxIsSparse(prhs[4]) || !mxIsDouble(prhs[4]))
{
mexErrMsgTxt("Invalid vector 5.");
}
/* Get the sparse matrix */
A_val = mxGetPr(prhs[1]);
A_row = mxGetIr(prhs[1]);
A_col = mxGetJc(prhs[1]);
/* Get the vector x */
x = mxGetPr(prhs[0]);
/* Get the vector d */
d = mxGetPr(prhs[3]);
/* Get the vector v */
v = mxGetPr(prhs[4]);
c = mxGetScalar(prhs[2]);
plhs[0] = mxCreateDoubleMatrix(n,1,mxREAL);
y = mxGetPr(plhs[0]);
sum_x = 0.0;
dtx = 0.0;
for (i = 0; i < n; i++)
{
xval = x[i];
sum_x += xval;
dtx += d[i]*xval;
for (j = A_col[i]; j < A_col[i+1]; ++j)
{
y[A_row[j]] += c*A_val[j]*xval;
}
}
xval = c*dtx + (1-c)*sum_x;
for (i=0; i < n;i++)
{
y[i] += xval*v[i];
}
}

BIN
matlab/package/pagerank_mult.mexa64

Binary file not shown.

BIN
matlab/package/pagerank_mult.mexglx

Binary file not shown.

78
matlab/package/spmatvec_mult.c

@ -1,78 +0,0 @@
/*
* ==============================================================
* spmatvec_mult.c Compute a sparse matrix vector multiplication
*
* David Gleich
* 14 February 2006
* =============================================================
*/
#include "mex.h"
/*
* The mex function just computes one matrix-vector product.
*
* function y = A*x;
*/
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
int i, j, k;
int mrows, ncols;
/* sparse matrix */
int *A_row, *A_col;
double *A_val;
double *x;
double *y;
double xval;
if (nrhs != 2)
{
mexErrMsgTxt("2 inputs required.");
}
else if (nlhs > 1)
{
mexErrMsgTxt("Too many output arguments");
}
mrows = mxGetM(prhs[0]);
ncols = mxGetN(prhs[0]);
if (!mxIsSparse(prhs[0]) ||
!mxIsDouble(prhs[0]) ||
mxIsComplex(prhs[0]))
{
mexErrMsgTxt("Input must be a noncomplex sparse matrix.");
}
/* The first input must be a vector. */
if (mxGetM(prhs[1])*mxGetN(prhs[1]) != ncols ||
mxIsSparse(prhs[1]) || !mxIsDouble(prhs[1]))
{
mexErrMsgTxt("Invalid vector.");
}
/* Get the sparse matrix */
A_val = mxGetPr(prhs[0]);
A_row = mxGetIr(prhs[0]);
A_col = mxGetJc(prhs[0]);
/* Get the vector x */
x = mxGetPr(prhs[1]);
plhs[0] = mxCreateDoubleMatrix(mrows,1,mxREAL);
y = mxGetPr(plhs[0]);
for (i = 0; i < ncols; i++)
{
xval = x[i];
for (j = A_col[i]; j < A_col[i+1]; ++j)
{
y[A_row[j]] += A_val[j]*xval;
}
}
}

BIN
matlab/package/spmatvec_mult.mexa64

Binary file not shown.

BIN
matlab/package/spmatvec_mult.mexglx

Binary file not shown.

82
matlab/package/spmatvec_transmult.c

@ -1,82 +0,0 @@
/*
* =============================================================
* spmatvec_mult.c Compute a sparse matrix vector multiplication
* using a transposed matrix.
*
* David Gleich
* Stanford University
* 14 February 2006
* =============================================================
*/
#include "mex.h"
/*
* The mex function just computes one matrix-vector product.
*
* function y = A'*x
*/
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
int i, j, k;
int mrows, ncols;
/* sparse matrix */
int *A_row, *A_col;
double *A_val;
double *x;
double *y;
double yval;
if (nrhs != 2)
{
mexErrMsgTxt("2 inputs required.");
}
else if (nlhs > 1)
{
mexErrMsgTxt("Too many output arguments");
}
mrows = mxGetM(prhs[0]);
ncols = mxGetN(prhs[0]);
if (!mxIsSparse(prhs[0]) ||
!mxIsDouble(prhs[0]) ||
mxIsComplex(prhs[0]))
{
mexErrMsgTxt("Input must be a noncomplex sparse matrix.");
}
/* The second input must be a vector. */
if (mxGetM(prhs[1])*mxGetN(prhs[1]) != mrows ||
mxIsSparse(prhs[1]) || !mxIsDouble(prhs[1]))
{
mexErrMsgTxt("Invalid vector 2.");
}
/* Get the sparse matrix */
A_val = mxGetPr(prhs[0]);
A_row = mxGetIr(prhs[0]);
A_col = mxGetJc(prhs[0]);
/* Get the vector x */
x = mxGetPr(prhs[1]);
plhs[0] = mxCreateDoubleMatrix(ncols,1,mxREAL);
y = mxGetPr(plhs[0]);
for (i = 0; i < ncols; i++)
{
yval = 0.0;
for (j = A_col[i]; j < A_col[i+1]; ++j)
{
yval += A_val[j]*x[A_row[j]];
}
y[i] = yval;
}
}

BIN
matlab/package/spmatvec_transmult.mexa64

Binary file not shown.

BIN
matlab/package/spmatvec_transmult.mexglx

Binary file not shown.

17
openmp/openmp_gs_pagerank_functions.c

@ -384,15 +384,8 @@ void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatri
char buffer[FILE_READ_BUFFER_SIZE]; char buffer[FILE_READ_BUFFER_SIZE];
char *readResult; 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 // First line contains the numbers of nodes and edges
int numberOfNodes = 0, numberOfEdges = 0; int numberOfNodes = 0, numberOfEdges = 0;
readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile); readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile);
@ -430,14 +423,6 @@ void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatri
numberOfNodes, numberOfEdges); 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 maxPageIndex = 0; int maxPageIndex = 0;
CooSparseMatrix tempMatrix = initCooSparseMatrix(); CooSparseMatrix tempMatrix = initCooSparseMatrix();
allocMemoryForCoo(&tempMatrix, numberOfEdges); allocMemoryForCoo(&tempMatrix, numberOfEdges);

37
pthread/Makefile

@ -1,37 +0,0 @@
SHELL := /bin/bash
# ============================================
# COMMANDS
CC = gcc -std=gnu99 -pthread
RM = rm -f
CFLAGS_DEBUG=-O0 -ggdb3 -Wall -I.
CFLAGS=-O3 -Wall -I.
OBJ=serial_gs_pagerank.o serial_gs_pagerank_functions.o coo_sparse_matrix.o csr_sparse_matrix.o
DEPS=serial_gs_pagerank_functions.h coo_sparse_matrix.h csr_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)

132
pthread/coo_sparse_matrix.c

@ -1,132 +0,0 @@
#include "coo_sparse_matrix.h"
CooSparseMatrix initCooSparseMatrix() {
CooSparseMatrix sparseMatrix;
sparseMatrix.size = 0;
sparseMatrix.numberOfNonZeroElements = 0;
sparseMatrix.elements = NULL;
return sparseMatrix;
}
void allocMemoryForCoo(CooSparseMatrix *sparseMatrix, int numberOfElements) {
sparseMatrix->elements = (CooSparseMatrixElement **) malloc(
numberOfElements * sizeof(CooSparseMatrixElement *));
sparseMatrix->size = numberOfElements;
}
void addElement(CooSparseMatrix *sparseMatrix, double value, int row, int column) {
// Checks if there is enough space allocated
if (sparseMatrix->numberOfNonZeroElements == sparseMatrix->size) {
printf("Number of non zero elements exceeded size of matrix!\n");
exit(EXIT_FAILURE);
}
// Creates the new element
CooSparseMatrixElement *newElement = (CooSparseMatrixElement *) malloc(
sizeof(CooSparseMatrixElement));
newElement->value = value;
newElement->rowIndex = row;
newElement->columnIndex = column;
// Adds the new element to the first empty (NULL) address of the matrix
sparseMatrix->elements[sparseMatrix->numberOfNonZeroElements] = newElement;
sparseMatrix->numberOfNonZeroElements = sparseMatrix->numberOfNonZeroElements + 1;
}
void transposeSparseMatrix(CooSparseMatrix *sparseMatrix) {
for (int i=0; i<sparseMatrix->numberOfNonZeroElements; ++i) {
CooSparseMatrixElement *element = sparseMatrix->elements[i];
int tempRow = element->rowIndex;
element->rowIndex = element->columnIndex;
element->columnIndex = tempRow;
}
}
/*
* This function is a port of the one found here:
* https://github.com/scipy/scipy/blob/3b36a57/scipy/sparse/sparsetools/coo.h#L34
*/
void transformToCSR(CooSparseMatrix initialSparseMatrix,
CsrSparseMatrix *transformedSparseMatrix) {
// Checks if the sizes of the two matrices fit
if (initialSparseMatrix.numberOfNonZeroElements > transformedSparseMatrix->size) {
printf("Transformed CSR matrix does not have enough space!\n");
exit(EXIT_FAILURE);
}
// Calculates the elements per row
for (int i=0; i<initialSparseMatrix.numberOfNonZeroElements; ++i){
int rowIndex = initialSparseMatrix.elements[i]->rowIndex;
transformedSparseMatrix->rowCumulativeIndexes[rowIndex] =
transformedSparseMatrix->rowCumulativeIndexes[rowIndex] + 1;
}
// Cumulative sums the non zero elements per row
for (int i=0, sum=0; i<transformedSparseMatrix->size+1; ++i){
int temp = transformedSparseMatrix->rowCumulativeIndexes[i];
transformedSparseMatrix->rowCumulativeIndexes[i] = sum;
sum += temp;
}
// Copies the values and columns of the elements
for (int i=0; i<initialSparseMatrix.numberOfNonZeroElements; ++i){
int row = initialSparseMatrix.elements[i]->rowIndex;
int destinationIndex = transformedSparseMatrix->rowCumulativeIndexes[row];
transformedSparseMatrix->columnIndexes[destinationIndex] = initialSparseMatrix.elements[i]->columnIndex;
transformedSparseMatrix->values[destinationIndex] = initialSparseMatrix.elements[i]->value;
transformedSparseMatrix->rowCumulativeIndexes[row]++;
}
// Fixes the cumulative sum
for (int i=0, last=0; i<=transformedSparseMatrix->size; i++){
int temp = transformedSparseMatrix->rowCumulativeIndexes[i];
transformedSparseMatrix->rowCumulativeIndexes[i] = last;
last = temp;
}
transformedSparseMatrix->numberOfNonZeroElements = initialSparseMatrix.numberOfNonZeroElements;
}
void cooSparseMatrixVectorMultiplication(CooSparseMatrix 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.numberOfNonZeroElements; ++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];
}
}
void destroyCooSparseMatrix(CooSparseMatrix *sparseMatrix) {
for (int i=0; i<sparseMatrix->numberOfNonZeroElements; ++i) {
free(sparseMatrix->elements[i]);
}
free(sparseMatrix->elements);
}
void printCooSparseMatrix(CooSparseMatrix sparseMatrix) {
if (sparseMatrix.numberOfNonZeroElements == 0) {
return;
}
CooSparseMatrixElement *element;
for (int i=0; i<sparseMatrix.numberOfNonZeroElements; ++i) {
element = sparseMatrix.elements[i];
printf("[%d,%d] = %f\n", element->rowIndex, element->columnIndex,
element->value);
}
}

60
pthread/coo_sparse_matrix.h

@ -1,60 +0,0 @@
#ifndef COO_SPARSE_MATRIX_H /* Include guard */
#define COO_SPARSE_MATRIX_H
/* ===== INCLUDES ===== */
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include "csr_sparse_matrix.h"
/* ===== STRUCTURES ===== */
// One element of the coordinate formated sparse matrix.
typedef struct cooSparseMatrixElement {
double value;
int rowIndex, columnIndex;
} CooSparseMatrixElement;
// A sparse matrix in COOrdinate format (aka triplet format).
typedef struct cooSparseMatrix {
int size, numberOfNonZeroElements;
CooSparseMatrixElement **elements;
} CooSparseMatrix;
/* ===== FUNCTION DEFINITIONS ===== */
// initCooSparseMatrix creates and initializes the members of a CooSparseMatrix
// structure instance.
CooSparseMatrix initCooSparseMatrix();
//allocMemoryForCoo allocates memory for the elements of the matrix.
void allocMemoryForCoo(CooSparseMatrix *sparseMatrix, int numberOfElements);
// addElement adds an element representing the triplet passed in the arguments
// to the first empty address of the space allocated for the elements.
void addElement(CooSparseMatrix *sparseMatrix, double value, int row,
int column);
// transposeSparseMatrix transposes the matrix.
void transposeSparseMatrix(CooSparseMatrix *sparseMatrix);
// transformToCSR transforms the sparse matrix representation format from COO
// to CSR.
void transformToCSR(CooSparseMatrix initialSparseMatrix,
CsrSparseMatrix *transformedSparseMatrix);
// cooSparseMatrixVectorMultiplication calculates the product of a
// CooSparseMatrix and a vector.
void cooSparseMatrixVectorMultiplication(CooSparseMatrix sparseMatrix,
double *vector, double **product, int vectorSize);
// destroyCooSparseMatrix frees all space used by the CooSparseMatrix.
void destroyCooSparseMatrix(CooSparseMatrix *sparseMatrix);
// printCooSparseMatrix prints the values of a CooSparseMatrix.
void printCooSparseMatrix(CooSparseMatrix sparseMatrix);
#endif // COO_SPARSE_MATRIX_H

92
pthread/csr_sparse_matrix.c

@ -1,92 +0,0 @@
#include "csr_sparse_matrix.h"
CsrSparseMatrix initCsrSparseMatrix() {
CsrSparseMatrix sparseMatrix;
sparseMatrix.size = 0;
sparseMatrix.numberOfNonZeroElements = 0;
sparseMatrix.values = NULL;
sparseMatrix.columnIndexes = NULL;
sparseMatrix.rowCumulativeIndexes = NULL;
return sparseMatrix;
}
void allocMemoryForCsr(CsrSparseMatrix *sparseMatrix, int numberOfElements) {
sparseMatrix->values = (double *) malloc(numberOfElements * sizeof(double));
sparseMatrix->columnIndexes = (int *) malloc(
numberOfElements * sizeof(int));
sparseMatrix->rowCumulativeIndexes = (int *) malloc(
(numberOfElements + 1) * sizeof(int));
for (int i=0; i<numberOfElements+1; ++i) {
sparseMatrix->rowCumulativeIndexes[i] = 0;
}
sparseMatrix->size = numberOfElements;
}
void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row) {
// Gets start and end indexes of the row's elements
int startIndex = sparseMatrix->rowCumulativeIndexes[row],
endIndex = sparseMatrix->rowCumulativeIndexes[row+1];
for (int i=startIndex; i<endIndex; ++i) {
sparseMatrix->values[i] = 0;
}
}
void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column) {
for (int i=0; i<sparseMatrix->numberOfNonZeroElements; ++i){
if(sparseMatrix->columnIndexes[i] == column){
sparseMatrix->values[i] = 0;
}
}
}
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;
}
for (int i=0; i<sparseMatrix.size; ++i) {
// Gets start and end indexes of this row's elements
int startIndex = sparseMatrix.rowCumulativeIndexes[i],
endIndex = sparseMatrix.rowCumulativeIndexes[i+1];
if (startIndex == endIndex) {
// This row has no elements
continue;
}
double sum = 0;
for(int j=startIndex; j<endIndex; ++j){
int elementColumn = sparseMatrix.columnIndexes[j];
sum += sparseMatrix.values[j] * vector[elementColumn];
}
(*product)[i] = sum;
}
}
void destroyCsrSparseMatrix(CsrSparseMatrix *sparseMatrix) {
free(sparseMatrix->values);
free(sparseMatrix->rowCumulativeIndexes);
free(sparseMatrix->columnIndexes);
}
void printCsrSparseMatrix(CsrSparseMatrix sparseMatrix) {
if (sparseMatrix.size == 0) {
return;
}
for (int i=0; i<sparseMatrix.size; ++i){
int startIndex = sparseMatrix.rowCumulativeIndexes[i],
endIndex = sparseMatrix.rowCumulativeIndexes[i+1];
for(int j=startIndex; j<endIndex; ++j){
printf("Row [%d] has [%d] nz elements: \n at column[%d] is value = %f \n",
i, endIndex-startIndex,
sparseMatrix.columnIndexes[j],
sparseMatrix.values[j]);
}
}
}

47
pthread/csr_sparse_matrix.h

@ -1,47 +0,0 @@
#ifndef CSR_SPARSE_MATRIX_H /* Include guard */
#define CSR_SPARSE_MATRIX_H
/* ===== INCLUDES ===== */
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
/* ===== STRUCTURES ===== */
// A sparse matrix in compressed SparseRow format.
typedef struct csrSparseMatrix {
int size, numberOfNonZeroElements;
int *rowCumulativeIndexes, *columnIndexes;
double *values;
} CsrSparseMatrix;
/* ===== FUNCTION DEFINITIONS ===== */
// initCsrSparseMatrix creates and initializes the members of a CsrSparseMatrix
// structure instance.
CsrSparseMatrix initCsrSparseMatrix();
// allocMemoryForCsr allocates memory for the elements of the matrix.
void allocMemoryForCsr(CsrSparseMatrix *sparseMatrix, int numberOfElements);
// zeroOutRow assigns a zero value to all the elements of a row in the matrix.
void zeroOutRow(CsrSparseMatrix *sparseMatrix, int row);
// zeroOutColumn assigns a zero value to all the elements of a column in the
// matrix.
void zeroOutColumn(CsrSparseMatrix *sparseMatrix, int column);
// csrSparseMatrixVectorMultiplication calculates the product of a
// CsrSparseMatrix and a vector.
void csrSparseMatrixVectorMultiplication(CsrSparseMatrix sparseMatrix,
double *vector, double **product, int vectorSize);
// destroyCsrSparseMatrix frees all space used by the CsrSparseMatrix.
void destroyCsrSparseMatrix(CsrSparseMatrix *sparseMatrix);
// printCsrSparseMatrix prints the values of a CsrSparseMatrix.
void printCsrSparseMatrix(CsrSparseMatrix sparseMatrix);
#endif // CSR_SPARSE_MATRIX_H

BIN
pthread/pagerank.out

Binary file not shown.

42
pthread/serial_gs_pagerank.c

@ -1,42 +0,0 @@
#include <sys/time.h>
#include "serial_gs_pagerank_functions.h"
struct timeval startwtime, endwtime;
int main(int argc, char **argv) {
CsrSparseMatrix transitionMatrix = initCsrSparseMatrix();
double *pagerankVector;
bool convergenceStatus;
Parameters parameters;
parseArguments(argc, argv, &parameters);
initialize(&transitionMatrix, &pagerankVector, &parameters);
// 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);
}

610
pthread/serial_gs_pagerank_functions.c

@ -1,610 +0,0 @@
/* ===== INCLUDES ===== */
#include "serial_gs_pagerank_functions.h"
#include <pthread.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 = 2;
const int SPARSITY_INCREASE_ITERATION_PERIOD = 10;
/* ===== THREAD STUFF ====== */
pthread_mutex_t Q = PTHREAD_MUTEX_INITIALIZER;;
typedef struct threadArgs{
CsrSparseMatrix* transitionMatrix;
double* pagerankVector;
double* previousPagerankVector;
int numberOfPages;
double webUniformProbability;
double *linksFromConvergedPagesPagerankVector;
double *convergedPagerankVector;
int position;
double dF;
}threadArgs;
/* ===== 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;
CooSparseMatrix linksFromConvergedPages = initCooSparseMatrix();
bool *convergenceMatrix;
int threadNum = parameters.numberOfPages;
pthread_t* threads = (pthread_t *)malloc(threadNum*sizeof(pthread_t));
// 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
allocMemoryForCoo(&linksFromConvergedPages, transitionMatrix->numberOfNonZeroElements);
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, threads, threadNum);
if (parameters.history) {
// Outputs pagerank vector to file
savePagerankToFile(parameters.outputFilename, iterations != 0,
*pagerankVector, numberOfPages, iterations);
}
// 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) {
// Filters newly converged pages
if (newlyConvergedPages[i] == true) {
// Checks if this converged page has an out-link to a non converged one
int rowStartIndex = transitionMatrix->rowCumulativeIndexes[i],
rowEndIndex = transitionMatrix->rowCumulativeIndexes[i+1];
if (rowEndIndex > rowStartIndex) {
// This row (page) has non zero elements (out-links)
for (int j=rowStartIndex; j<rowEndIndex; ++j) {
// Checks for links from converged pages to non converged
int pageLinksTo = transitionMatrix->columnIndexes[j];
if (convergenceMatrix[pageLinksTo] == false){
// Link exists, adds element to the vector
addElement(&linksFromConvergedPages,
transitionMatrix->values[j], i, pageLinksTo);
}
}
}
// Increases sparsity of the transition matrix by zeroing
// out elements that correspond to converged pages
zeroOutRow(transitionMatrix, i);
zeroOutColumn(transitionMatrix, i);
// Builds the new linksFromConvergedPagesPagerankVector
cooSparseMatrixVectorMultiplication(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) {
// Always outputs last pagerank vector to file
savePagerankToFile(parameters.outputFilename, false, *pagerankVector,
numberOfPages, iterations);
}
// Frees memory
free(pagerankDifference);
free(previousPagerankVector);
free(convergedPagerankVector);
free(linksFromConvergedPagesPagerankVector);
free(convergenceMatrix);
destroyCooSparseMatrix(&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;
}
}
// ==================== 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, pthread_t *threads, int threadNum) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Calculates the web uniform probability once.
double webUniformProbability = 1. / vectorSize;
int runningThreads = 0;
for (int i=0; i<vectorSize; ++i) {
pthread_mutex_lock(&Q);
threadArgs arg;
arg.position = i;
arg.transitionMatrix = transitionMatrix;
arg.pagerankVector = *pagerankVector;
arg.previousPagerankVector = previousPagerankVector;
arg.linksFromConvergedPagesPagerankVector = linksFromConvergedPagesPagerankVector;
arg.convergedPagerankVector = convergedPagerankVector;
arg.webUniformProbability = webUniformProbability;
arg.dF = dampingFactor;
if(runningThreads < threadNum){
if(pthread_create(&threads[i], &attr, csrSparseMatrixVectorMultiplication_threads, (void *) &arg)){
printf("Error creating thread %d", i);
pthread_mutex_unlock(&Q);
exit(-1);
}
else{
++runningThreads;
pthread_mutex_unlock(&Q);
}
}
else{
pthread_mutex_unlock(&Q);
printf("not enough threads\n");
exit(-1);
}
pthread_join(threads[i], NULL);
if(runningThreads < threadNum){
if(pthread_create(&threads[i], &attr, compPagerankVector_threads, (void *) &arg)){
printf("Error creating thread %d", i);
pthread_mutex_unlock(&Q);
exit(-1);
}
else{
++runningThreads;
pthread_mutex_unlock(&Q);
}
}
else{
printf("You have a problem \n");
exit(-1);
pthread_mutex_unlock(&Q);
}
}
for(int i=0; i<vectorSize; ++i){
pthread_join(threads[i], NULL);
}
free(threads);
}
void compPagerankVector_threads(void* arg){
threadArgs* co = (threadArgs *)arg;
co->pagerankVector[co->position] = co->dF * co->pagerankVector[co->position];
double normDifference = vectorNorm(co->previousPagerankVector, co->numberOfPages) -
vectorNorm(co->pagerankVector, co->numberOfPages);
co->pagerankVector[co->position] += normDifference * co->webUniformProbability +
co->linksFromConvergedPagesPagerankVector[co->position] + co->convergedPagerankVector[co->position];
}
void csrSparseMatrixVectorMultiplication_threads(void* arg){
threadArgs* co = (threadArgs *)arg;
//(CsrSparseMatrix sparseMatrix,
//double *vector, double **product, int vectorSize) {
// Initializes the elements of the product vector to zero
//for (int i=0; i<vectorSize; ++i) {
co->pagerankVector[co->position] = 0;
//}
//for (int i=0; i<sparseMatrix.size; ++i) {
// Gets start and end indexes of this row's elements
int startIndex = co->transitionMatrix[co->position].rowCumulativeIndexes[co->position],
endIndex = co->transitionMatrix[co->position].rowCumulativeIndexes[co->position+1];
if (startIndex == endIndex) {
// This row has no elements
return;
}
double sum = 0;
for(int j=startIndex; j<endIndex; ++j){
int elementColumn = co->transitionMatrix[co->position].columnIndexes[j];
sum += co->transitionMatrix[co->position].values[j] * co->previousPagerankVector[elementColumn];
}
co->pagerankVector[co->position] = sum;
//}
}
/*
* 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 maxPageIndex = 0;
CooSparseMatrix tempMatrix = initCooSparseMatrix();
allocMemoryForCoo(&tempMatrix, numberOfEdges);
for (int i=0; i<numberOfEdges; i++) {
int fileFrom = 0, fileTo = 0;
if (!fscanf(graphFile, "%d %d", &fileFrom, &fileTo)) {
break;
}
if (fileFrom > maxPageIndex) {
maxPageIndex = fileFrom;
}
if (fileTo > maxPageIndex) {
maxPageIndex = fileTo;
}
addElement(&tempMatrix, 1, fileFrom, fileTo);
}
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* pageOutdegree = malloc((*parameters).numberOfPages*sizeof(int));
for (int i=0; i<(*parameters).numberOfPages; ++i){
pageOutdegree[i] = 0;
}
for (int i=0; i<numberOfEdges; ++i) {
int currentRow = tempMatrix.elements[i]->rowIndex;
++pageOutdegree[currentRow];
}
for (int i=0; i<tempMatrix.size; ++i) {
tempMatrix.elements[i]->value = 1./pageOutdegree[tempMatrix.elements[i]->rowIndex];
}
free(pageOutdegree);
// Transposes the temporary transition matrix (P^T).
transposeSparseMatrix(&tempMatrix);
allocMemoryForCsr(transitionMatrix, numberOfEdges);
// Transforms the temporary COO matrix to the desired CSR format
transformToCSR(tempMatrix, transitionMatrix);
destroyCooSparseMatrix(&tempMatrix);
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, int iteration) {
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;
}
// Saves the pagerank vector
//fprintf(outputFile, "Iteration %d:\t", iteration);
double sum = 0;
for (int i=0; i<vectorSize; ++i) {
sum += pagerankVector[i];
}
//fprintf(outputFile, "%f\n", sum);
for (int i=0; i<vectorSize; ++i) {
fprintf(outputFile, "%d = %.10g\n", i, pagerankVector[i]/sum);
}
fclose(outputFile);
}

100
pthread/serial_gs_pagerank_functions.h

@ -1,100 +0,0 @@
#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 "coo_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, int iteration);
// 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, pthread_t *threads, int threadNum);
// 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);
void csrSparseMatrixVectorMultiplication_threads(void* arg);
void compPagerankVector_threads(void* arg);
#endif // SERIAL_GS_PAGERANK_FUNCTIONS_H

4
serial/Makefile

@ -23,7 +23,7 @@ all: $(EXECUTABLES)
# DEPENDENCIES (HEADERS) # DEPENDENCIES (HEADERS)
%.o: %.c $(DEPS) %.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS) $(CC) -c -o $@ $< $(CFLAGS_DEBUG)
.PRECIOUS: $(EXECUTABLES) $(OBJ) .PRECIOUS: $(EXECUTABLES) $(OBJ)
@ -31,7 +31,7 @@ all: $(EXECUTABLES)
# EXECUTABLE (MAIN) # EXECUTABLE (MAIN)
$(EXECUTABLES): $(OBJ) $(EXECUTABLES): $(OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(CC) -o $@ $^ $(CFLAGS_DEBUG)
clean: clean:
$(RM) *.o *~ $(EXECUTABLES) $(RM) *.o *~ $(EXECUTABLES)

17
serial/serial_gs_pagerank_functions.c

@ -358,15 +358,8 @@ void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatri
char buffer[FILE_READ_BUFFER_SIZE]; char buffer[FILE_READ_BUFFER_SIZE];
char *readResult; 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 // First line contains the numbers of nodes and edges
int numberOfNodes = 0, numberOfEdges = 0; int numberOfNodes = 0, numberOfEdges = 0;
readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile); readResult = fgets(buffer, FILE_READ_BUFFER_SIZE, graphFile);
@ -404,14 +397,6 @@ void generateNormalizedTransitionMatrixFromFile(CsrSparseMatrix *transitionMatri
numberOfNodes, numberOfEdges); 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 maxPageIndex = 0; int maxPageIndex = 0;
CooSparseMatrix tempMatrix = initCooSparseMatrix(); CooSparseMatrix tempMatrix = initCooSparseMatrix();
allocMemoryForCoo(&tempMatrix, numberOfEdges); allocMemoryForCoo(&tempMatrix, numberOfEdges);

Loading…
Cancel
Save