Skip to content

Commit 84ada6b

Browse files
committed
Added BFS implementations to stinger_alg.
1 parent 6826367 commit 84ada6b

3 files changed

Lines changed: 188 additions & 0 deletions

File tree

lib/stinger_alg/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(sources
22
src/adamic_adar.c
33
src/betweenness.c
4+
src/bfs.c
45
src/clustering.c
56
src/kcore.c
67
src/pagerank.c
@@ -12,6 +13,7 @@ set(sources
1213
set(headers
1314
inc/adamic_adar.h
1415
inc/betweenness.h
16+
inc/bfs.h
1517
inc/clustering.h
1618
inc/kcore.h
1719
inc/pagerank.h

lib/stinger_alg/inc/bfs.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef STINGER_BFS_H_
2+
#define STINGER_BFS_H_
3+
4+
#include "stinger_core/stinger.h"
5+
#include "stinger_core/xmalloc.h"
6+
#include "stinger_core/stinger_error.h"
7+
8+
int64_t
9+
parallel_breadth_first_search (
10+
struct stinger * S,
11+
int64_t nv,
12+
int64_t source,
13+
int64_t * marks,
14+
int64_t * queue,
15+
int64_t * Qhead,
16+
int64_t * level
17+
);
18+
19+
int64_t
20+
direction_optimizing_parallel_breadth_first_search (
21+
struct stinger * S,
22+
int64_t nv,
23+
int64_t source,
24+
int64_t * marks,
25+
int64_t * queue,
26+
int64_t * Qhead,
27+
int64_t * level
28+
);
29+
30+
#endif

lib/stinger_alg/src/bfs.c

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#include "bfs.h"
2+
3+
#include "stinger_core/x86_full_empty.h"
4+
5+
int64_t
6+
parallel_breadth_first_search (struct stinger * S, int64_t nv,
7+
int64_t source, int64_t * marks,
8+
int64_t * queue, int64_t * Qhead, int64_t * level)
9+
{
10+
for (int64_t i = 0; i < nv; i++) {
11+
level[i] = -1;
12+
marks[i] = 0;
13+
}
14+
15+
int64_t nQ, Qnext, Qstart, Qend;
16+
/* initialize */
17+
queue[0] = source;
18+
level[source] = 0;
19+
marks[source] = 1;
20+
Qnext = 1; /* next open slot in the queue */
21+
nQ = 1; /* level we are currently processing */
22+
Qhead[0] = 0; /* beginning of the current frontier */
23+
Qhead[1] = 1; /* end of the current frontier */
24+
25+
Qstart = Qhead[nQ-1];
26+
Qend = Qhead[nQ];
27+
28+
while (Qstart != Qend) {
29+
OMP ("omp parallel for")
30+
for (int64_t j = Qstart; j < Qend; j++) {
31+
STINGER_FORALL_OUT_EDGES_OF_VTX_BEGIN (S, queue[j]) {
32+
int64_t d = level[STINGER_EDGE_DEST];
33+
if (d < 0) {
34+
if (stinger_int64_fetch_add (&marks[STINGER_EDGE_DEST], 1) == 0) {
35+
level[STINGER_EDGE_DEST] = nQ;
36+
37+
int64_t mine = stinger_int64_fetch_add(&Qnext, 1);
38+
queue[mine] = STINGER_EDGE_DEST;
39+
}
40+
}
41+
} STINGER_FORALL_OUT_EDGES_OF_VTX_END();
42+
}
43+
44+
Qstart = Qhead[nQ-1];
45+
Qend = Qnext;
46+
Qhead[nQ++] = Qend;
47+
}
48+
49+
return nQ;
50+
}
51+
52+
int64_t
53+
direction_optimizing_parallel_breadth_first_search (struct stinger * S, int64_t nv,
54+
int64_t source, int64_t * marks,
55+
int64_t * queue, int64_t * Qhead, int64_t * level)
56+
{
57+
for (int64_t i = 0; i < nv; i++) {
58+
level[i] = -1;
59+
marks[i] = 0;
60+
}
61+
62+
int64_t nQ, Qnext, Qstart, Qend;
63+
int64_t mf = 0; /* number of edges incident on frontier */
64+
int64_t nf = 0; /* number of vertices in frontier */
65+
int64_t mu = 0; /* number of edges incident on unexplored vertices */
66+
int64_t nf_last = 0; /* size of previous frontier */
67+
68+
/* initialize */
69+
queue[0] = source;
70+
level[source] = 0;
71+
marks[source] = 1;
72+
Qnext = 1; /* next open slot in the queue */
73+
nQ = 1; /* level we are currently processing */
74+
Qhead[0] = 0; /* beginning of the current frontier */
75+
Qhead[1] = 1; /* end of the current frontier */
76+
77+
Qstart = Qhead[nQ-1];
78+
Qend = Qhead[nQ];
79+
80+
mf = 0;
81+
nf = 0;
82+
mu = stinger_total_edges(S);
83+
//printf("mf: %ld, nf: %ld, mu: %ld, nf_last: %ld\n", mf, nf, mu, nf_last);
84+
85+
int64_t top_down = 1;
86+
87+
while (Qstart != Qend) {
88+
if (top_down) {
89+
/* forward (top down) traversal */
90+
OMP ("omp parallel for")
91+
for (int64_t j = Qstart; j < Qend; j++) {
92+
STINGER_FORALL_OUT_EDGES_OF_VTX_BEGIN (S, queue[j]) {
93+
int64_t d = level[STINGER_EDGE_DEST];
94+
if (d < 0) {
95+
if (stinger_int64_fetch_add (&marks[STINGER_EDGE_DEST], 1) == 0) {
96+
level[STINGER_EDGE_DEST] = nQ;
97+
98+
int64_t mine = stinger_int64_fetch_add(&Qnext, 1);
99+
queue[mine] = STINGER_EDGE_DEST;
100+
}
101+
}
102+
} STINGER_FORALL_OUT_EDGES_OF_VTX_END();
103+
}
104+
} else {
105+
/* reverse (bottom up) traversal */
106+
OMP ("omp parallel for")
107+
for (int64_t i = 0; i < nv; i++) {
108+
int64_t done = 0;
109+
/* only process unvisited vertices */
110+
if (!marks[i]) {
111+
STINGER_FORALL_OUT_EDGES_OF_VTX_BEGIN (S, i) {
112+
/* neighbor has been visited */
113+
if (!done && level[STINGER_EDGE_DEST] == nQ-1) {
114+
level[i] = nQ;
115+
marks[i] = 1;
116+
117+
/* if we don't queue here, we cannot restart the forward search */
118+
int64_t mine = stinger_int64_fetch_add(&Qnext, 1);
119+
queue[mine] = i;
120+
done = 1;
121+
}
122+
} STINGER_FORALL_OUT_EDGES_OF_VTX_END();
123+
}
124+
}
125+
}
126+
127+
Qstart = Qhead[nQ-1];
128+
Qend = Qnext;
129+
Qhead[nQ++] = Qend;
130+
131+
/* calculate new transition parameters */
132+
nf_last = nf;
133+
nf = Qend - Qstart;
134+
mf = 0;
135+
OMP ("omp parallel for reduction(+:mf) reduction(-:mu)")
136+
for (int64_t j = Qstart; j < Qend; j++) {
137+
int64_t deg_j = stinger_outdegree_get(S, queue[j]);
138+
mf += deg_j;
139+
mu -= deg_j;
140+
}
141+
//printf("mf: %ld, nf: %ld, mu: %ld, nf_last: %ld\n", mf, nf, mu, nf_last);
142+
143+
/* evaluate the transition state machine */
144+
if (top_down) {
145+
if (mf > (mu / 14) && (nf - nf_last > 0)) {
146+
top_down = 0;
147+
}
148+
} else {
149+
if (nf < (nv / 24) && (nf - nf_last < 0)) {
150+
top_down = 1;
151+
}
152+
}
153+
} /* end while */
154+
155+
return nQ;
156+
}

0 commit comments

Comments
 (0)