-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbfs.cpp
More file actions
132 lines (108 loc) · 4.61 KB
/
Copy pathbfs.cpp
File metadata and controls
132 lines (108 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "bfs.h" // Include this first to ensure proper declaration
#include <queue>
#include <limits>
#include <iostream>
#include <omp.h> // Include OpenMP header
#include <vector>
// Sequential BFS implementation
std::vector<int> bfsSequential(const Graph& graph, int source) {
const int num_vertices = graph.getNumVertices();
// Initialize distances to all vertices as infinity
std::vector<int> distances(num_vertices, std::numeric_limits<int>::max());
distances[source] = 0; // Distance to source is 0
// Queue for bfs
std::queue<int> queue;
queue.push(source); // Start BFS from the source vertex
// BFS loop
while(!queue.empty()) {
int current_vertex = queue.front();
queue.pop();
// Process all neighbors
auto [start, end] = graph.getNeighborRange(current_vertex);
for (int edge_idx = start; edge_idx < end; edge_idx++) {
int neighbor = graph.getNeighbor(edge_idx); // Get the neighbor vertex
// If the neighbor has not been visited
if (distances[neighbor] == std::numeric_limits<int>::max()) {
distances[neighbor] = distances[current_vertex] + 1; // Update distance
queue.push(neighbor); // Add neighbor to the queue for further processing
}
}
}
return distances; // Return the distances from the source to all vertices
}
// OpenMP parallel BFS implementation
std::vector<int> bfsOpenMP(const Graph& graph, int source, int num_threads) {
const int num_vertices = graph.getNumVertices();
// Set number of threads if specified
if (num_threads > 0) {
omp_set_num_threads(num_threads);
}
// Initialize distances to "infinity"
std::vector<int> distances(num_vertices, std::numeric_limits<int>::max());
distances[source] = 0;
// BFS uses level-synchronous approach with two frontiers
std::vector<int> current_frontier;
std::vector<int> next_frontier;
// Initial frontier contains just the source
current_frontier.push_back(source);
// Current BFS level
int level = 1;
// Process each level of BFS
while (!current_frontier.empty()) {
next_frontier.clear();
// Process current frontier in parallel
#pragma omp parallel
{
// Thread-local storage for discovered vertices
std::vector<int> local_frontier;
// Divide frontier vertices among threads
#pragma omp for schedule(dynamic, 64)
for (size_t i = 0; i < current_frontier.size(); i++) {
int vertex = current_frontier[i];
// Get neighbors of this vertex
auto [start, end] = graph.getNeighborRange(vertex);
// Process all neighbors
for (int edge_idx = start; edge_idx < end; edge_idx++) {
int neighbor = graph.getNeighbor(edge_idx);
// Check if neighbor hasn't been visited yet
if (distances[neighbor] == std::numeric_limits<int>::max()) {
// Use critical section for correctness
#pragma omp critical
{
// Check again in case another thread updated it
if (distances[neighbor] == std::numeric_limits<int>::max()) {
distances[neighbor] = level;
local_frontier.push_back(neighbor);
}
}
}
}
}
// Combine thread-local frontiers into the next global frontier
#pragma omp critical
{
next_frontier.insert(next_frontier.end(), local_frontier.begin(), local_frontier.end());
}
} // End parallel region
// Move to next level
current_frontier.swap(next_frontier);
level++;
}
return distances;
}
// BFS result verification
bool verifyBFS(const std::vector<int>& result, const std::vector<int>& reference) {
if (result.size() != reference.size()) {
std::cerr << "Result and reference sizes do not match." << std::endl;
return false;
}
for (size_t i = 0; i < result.size(); i++) {
if(result[i] != reference[i]) {
std::cout << "Error at vertex " << i
<< ": got " << result[i]
<< " expected " << reference[i] << std::endl;
return false;
}
}
return true;
}