Trying to parallelize DFS (recursive) traversal through openMP - c++

It's my first time using openMP.
Below is given the code so far(which I have not yet been able to parallel,even in a very small part, since I am coming face to face with the error given at the end).
// C++ program to print DFS traversal from a given vertex in a given graph
#include <bits/stdc++.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <omp.h>
using namespace std;
// Graph class represents a directed graph using adjacency list representation
class Graph
{
int V; // No. of vertices
// Pointer to an array containing adjacency lists
list<int> *adj;
// A recursive function used by DFS
void DFSUtil(int v, bool visited[]);
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int v, int w);
// DFS traversal of the vertices reachable from v
void DFS(int v);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
}
void Graph::DFSUtil(int v, bool visited[])
{
// Mark the current node as visited and print it
visited[v] = true;
cout << v << " ";
// Recur for all the vertices adjacent to this vertex
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i) {
if (!visited[*i])
DFSUtil(*i, visited);
}
}
// DFS traversal of the vertices reachable from v. It uses recursive DFSUtil().
void Graph::DFS(int v)
{
// Mark all the vertices as not visited
bool *visited = new bool[V];
for (int i = 0; i < v; i++)
visited[i] = false;
// Call the recursive helper function to print DFS traversal
DFSUtil(v, visited);
}
// ------------------Drivercode-------------------------------//
int main()
{
//Create a dynamic array to hold the values
vector<int> numbers;
//Create an input file stream
ifstream in("graph_adjacency_list.txt",ios::in);
/*
As long as we haven't reached the end of the file, keep reading entries.
*/
int number; //Variable to hold each number as it is read
//Read number using the extraction (>>) operator
while (in >> number) {
//Add the number to the end of the array
numbers.push_back(number);
}
//Close the file stream
in.close();
/*
Now, the vector<int> object "numbers" contains both the array of numbers,
and its length (the number count from the file).
*/
//Display the numbers
cout << " \n Numbers of our file (graph_adjacency_list.txt):\n";
for (int i=0; i<numbers.size(); i++) {
cout << numbers[i] << ' ';
}
cout << "\n";
int s = numbers.size();
auto start = chrono::steady_clock::now();
// Create a graph given in the above diagram
Graph g(numbers[0]); //<--Takes the number of Vertices , included in the first position of the array(numbers[])
In this part I have the problem :
#pragma omp parallel shared(g) private(i) firstprivate(s)
{
int i =0;
#pragma omp for
for ( i=0; i<s; i=i+2) {
g.addEdge(numbers[i],numbers[i+1]);
}
}
cout << "\n Following is Depth First Traversal"
" (starting from vertex 0): \n";
g.DFS(0);
cout << "\n";
auto end = chrono::steady_clock::now();
auto diff = end - start;
cout << "\n Time taken:" << chrono::duration <double, milli> (diff).count() << " ms" << endl;
cout << "\n";
return 0;
}
When i compile the file through terminal :
ex.--> g++ parallel_DFS.cpp -o parallel_DFS -fopenmp
I take this error:
parallel_DFS.cpp: In function ‘int main()’:
parallel_DFS.cpp:149:44: error: ‘i’ has not been declared
#pragma omp parallel shared(g) private(i) firstprivate(s)
^
and moreover, when i run it on VScode i take:
malloc(): memory corruption
Aborted (core dumped)
Thanks for any help in advance

Related

Weight implementation in graph

I am trying to find the path between two vertices and their distance.
My implementation is the following:
#include <iostream>
#include <list>
#include <string>
#include <vector>
using namespace std;
vector <string> v1 = {"Prague", "Helsinki", "Beijing", "Tokyo", "Jakarta","London", "New York"};
vector <int> w = {};
// A directed graph using
// adjacency list representation
class Graph {
int V; // No. of vertices in graph
list<int>* adj; // Pointer to an array containing adjacency lists
// A recursive function used by printAllPaths()
void printAllPathsUtil(int, int, bool[], int[], int&);
public:
Graph(int V); // Constructor
void addVertex(string name);
void addEdge(int u, int v, int weight);
void printAllPaths(int s, int d);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int u, int v, int weight)
{
adj[u].push_back(v); // Add v to u’s list.
w.push_back(weight);
}
// Prints all paths from 's' to 'd'
void Graph::printAllPaths(int s, int d)
{
// Mark all the vertices as not visited
bool* visited = new bool[V];
// Create an array to store paths
int* path = new int[V];
int path_index = 0; // Initialize path[] as empty
// Initialize all vertices as not visited
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to print all paths
printAllPathsUtil(s, d, visited, path, path_index);
}
// A recursive function to print all paths from 'u' to 'd'.
// visited[] keeps track of vertices in current path.
// path[] stores actual vertices and path_index is current
// index in path[]
void Graph::printAllPathsUtil(int u, int d, bool visited[],
int path[], int& path_index)
{
// Mark the current node and store it in path[]
visited[u] = true;
path[path_index] = u;
path_index++;
int sum = 0;
// If current vertex is same as destination, then print
// current path[]
if (u == d) {
for (int i = 0; i < path_index; i++){
sum += w[i];
cout << v1[path[i]] << " ";
}
cout << endl;
cout << "Total distance is: " << sum;
cout << endl;
}
else // If current vertex is not destination
{
// Recur for all the vertices adjacent to current vertex
list<int>::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
if (!visited[*i])
printAllPathsUtil(*i, d, visited, path, path_index);
}
// Remove current vertex from path[] and mark it as unvisited
path_index--;
visited[u] = false;
}
// Driver program
int main()
{
// Create a graph given in the above diagram
Graph g(7);
g.addEdge(0, 1, 1845);
g.addEdge(0, 5, 1264);
g.addEdge(1, 3, 7815);
g.addEdge(2, 5, 8132);
g.addEdge(2, 6, 11550);
g.addEdge(2, 3, 1303);
g.addEdge(3, 4, 5782);
g.addEdge(3, 6, 10838);
g.addEdge(4, 2, 4616);
g.addEdge(5, 3, 9566);
g.addEdge(6, 5, 5567);
int s = 0, d = 2;
cout << "Following are all different paths from " << v1[s] << " to " << v1[d] << endl;
g.printAllPaths(s, d);
return 0;
}
Obviously this part is wrong:
vector <int> w = {};
w.push_back(weight);
int sum = 0;
// If current vertex is same as destination, then print
// current path[]
if (u == d) {
for (int i = 0; i < path_index; i++){
sum += w[i];
cout << v1[path[i]] << " ";
}
cout << endl;
cout << "Total distance is: " << sum;
cout << endl;
Output is:
Prague Helsinki Tokyo Jakarta Beijing
Total distance is: 30606
Prague London Tokyo Jakarta Beijing
Total distance is: 30606
This is wrong (but the path is correct) because of my implementation, it prints out the summation of the overall first 5 weights. But I just did not understand how can I get the weights
How can I get the corresponding weights and add them up?
What I expect:
Prague Helsinki Tokyo Jakarta Beijing
Total distance is: 20058
Prague London Tokyo Jakarta Beijing
Total distance is: (There will be some number I have not calculated yet)
There are two main problems here. When you create the edges you do not coupled their cost to them in any way. Also when you traverse them in your algorithm you do not save the cost of traversing the edge, you only save the cities.
Here is a simple solution if you want to keep almost an identical structure. You can accompany the adjecency lists with a list of the costs for each such edge. Son instead of having the w array you can have one such for each noce (city). Then the path array can also be accompanied by another int array with the costs of each step.
Starting with defining and creating the edges it would be:
class Graph {
int V; // No. of vertices in graph
list<int>* adj; // Pointer to an array containing adjacency lists
list<int>* adj_weights; // Pointer to an array containing adjacency lists
...
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
adj_weights = new list<int>[V];
}
void Graph::addEdge(int u, int v, int weight)
{
adj[u].push_back(v); // Add v to u’s list.
adj_weights[u].push_back(weight); // Add the weight of the path as well.
}
Now we have stored the weights and the edges together in a better way, but we still need to use this in the algorithm. Here is an example change of the main functions:
// Prints all paths from 's' to 'd'
void Graph::printAllPaths(int s, int d)
{
// Mark all the vertices as not visited
bool* visited = new bool[V];
// Create an array to store paths
int* path = new int[V];
int* path_costs = new int[V];
int path_index = 0; // Initialize path[] and path_costs[] as empty
// Initialize all vertices as not visited
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to print all paths
// Note that we let cost = 0 since we don't have to move to the starting city
printAllPathsUtil(s, d, visited, path_costs, path, path_index, 0);
}
// A recursive function to print all paths from 'u' to 'd'.
// visited[] keeps track of vertices in current path.
// path[] stores actual vertices and path_index is current
// index in path[]
void Graph::printAllPathsUtil(int u, int d, bool visited[], int path_costs[],
int path[], int& path_index, int cost)
{
// Mark the current node and store it in path[]
visited[u] = true;
path[path_index] = u;
path_costs[path_index] = cost; // Save cost of this step
path_index++;
int sum = 0;
// If current vertex is same as destination, then print
// current path[]
if (u == d) {
for (int i = 0; i < path_index; i++){
sum += path_costs[i]; // Now add all the costs
cout << v1[path[i]] << " ";
}
cout << endl;
cout << "Total distance is: " << sum;
cout << endl;
}
else // If current vertex is not destination
{
// Recur for all the vertices adjacent to current vertex
// Now we loop over both adj and adj_weights
list<int>::iterator i, j;
for (i = adj[u].begin(), j = adj_weights[u].begin();
i != adj[u].end(); ++i, ++j)
if (!visited[*i])
printAllPathsUtil(*i, d, visited, path_costs, path,
path_index, *j);
}
// Remove current vertex from path[] and mark it as unvisited
path_index--;
visited[u] = false;
}
You can see a full version of the augmented code here https://ideone.com/xGju0y and it gives the following output:
Following are all different paths from Prague to Beijing
Prague Helsinki Tokyo Jakarta Beijing
Total distance is: 20058
Prague London Tokyo Jakarta Beijing
Total distance is: 21228
I hope this helps! I tried to focus on using the same concepts you introduced to not solve things with some new classes or imports. But there are much nicer ways to solve this. One example is to merge the path and path_weights arrays into one array of pairs of ints, and to merge adj and adj_weights into an array of lists of pairs of ints instead of an array of lists of ints.

How to fix the error on erasing element from a vector?

I want to erase a particular element from a vector and I tried the following code. Actually I want to build a adjacency list and I want to delete an element from the adjacency list and to delete all edges connected to deleted element.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<vector<int> > tree(20);
void addEdge(int u, int v)
{
tree[u].push_back(v);
tree[v].push_back(u);
}
void printGraph(vector<vector<int>> tree [], int V)
{
vector<vector<int>>::iterator it;
int j;
for (it = tree.begin(); it != tree.end(); )
{
cout << "\n Adjacency list of vertex ";
for (j = 0; j < (*it).size(); j++)
{
cout << j << "\n head ";
cout << "-> " << (*it)[j];
}
cout << endl;
if (j==2) it = tree.erase(it);
}
}
int main()
{
int n = 5;
addEdge(1, 2);
addEdge(3, 2);
addEdge(4, 2);
addEdge(2, 5);
printGraph(tree, n);
}
How to fix the error on erasing element from a vector?
For your immediate needs, use
for (it = tree.begin(); it != tree.end(); ) // loops on the entire tree
{
for (int j = 0; j < (*it).size(); j++) // loops through adjacent vertices in the current node
cout << ' ' << (*it)[j];
cout << endl;
it = tree.erase(it); // erase current node (same thing as it = tree.erase(it.begin()))
}
to print your tree and linearly delete each row.
Original Answer before question was updated:
as a static array of `std::vector<int</code>'s, we won't be able to use `std::vector<></code> member functions directly on tree (e.g. `tree.begin()</code> generates an error because there is no `.begin()</code> member function for a static array).>
An alternative is to use std::begin(tree) and std::end(tree) defined from the <iterator> header file.
But since, you're wanting to delete (erase) parts of the array, a better way of structuring this data is to use std::vector<std::vector<int>> tree(20) which will create a 2D array. Here, the .erase() member function is valid.
Alternative to Storing Data (Helpful)
Also I believe adjacency matrices usually have static size? For example:
A B C
A 0 1 0
B 1 0 1
C 0 1 0
would show that there are 3 nodes (A, B, C) and there are two edges (AB, BC).
Removing an edge would just be as simple as changing the edge from 1 to 0. Here, you can use std::vector<int> tree[20] or better, bool tree[20][20] (should use bool since we're only dealing with 1's and 0's). Then you would need to reimplement the addEdge function, but that should be in your scope of understanding.
Hope this helps.

Simple DFS stuck in an infinite loop c++

I am trying to implement a simple DFS in C++ with n number of nodes and k number of edges.
For some reason it is getting stuck in an infinite loop:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define MAXV 1000
void addEdge(vector<int> adj[], int u, int v){
adj[u].pb(v);
adj[v].pb(u);
}
void DFSUtil(int u, vector<int> adj[], vector<int>& visited){
visited[u] = 1;
cout << u << " ";
for(int i = 0;i<adj[u].size();i++){
if(visited[adj[u][i]] == 0){
DFSUtil(u,adj,visited);
}
}
}
void DFS(vector<int> adj[], int N){
vector<int> visited(N, 0);
for(int u = 1;u<N;u++){
if(visited[u] == 0){
DFSUtil(u,adj,visited);
cout << "\n";
}
}
}
int main(){
int n,k,m,i,u,v;
scanf("%d %d",&n,&k);
vector<int> adj[n+1];
for(i = 0;i<k;i++){
scanf("%d %d",&u,&v);
addEdge(adj,u,v);
}
// find connected components
DFS(adj,n+1);
return 0;
}
Could someone point me where am I going wrong with this code?
Sample input to test on:
4 3
1 2
2 3
1 4
After navigating through every steps, finally, I am able to find the bug.
The passed value should have been DFSUtil(adj[u][i],adj,visited); instead of DFSUtil(u,adj,visited); which actually calls the same vertex again and again and hence the infinite loop.
void DFSUtil(int u, vector<int> adj[], vector<int>& visited){
visited[u] = 1;
cout << u << " ";
for(int i = 0;i<adj[u].size();i++){
int to = adj[u][i];
if(visited[to] == 0){
DFSUtil(to, adj, visited);
}
}
}

list size is 1 but front() and back() are unequal

The "error" causing code:
struct Edge
{
int src, dest;
};
// Graph class represents a directed graph using adjacency list representation
class Graph
{
int V; // No. of vertices
list<int> *adj; // Pointer to an array containing adjacency lists
void DFSUtil(int v, bool visited[], int &count); // A function used by DFS
public:
Graph(int V); // Constructor
void addEdge(int v, int w); // function to add an edge to graph
void rmEdge(int v, int w);
int DFS(int v); // DFS traversal of the vertices reachable from v
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
}
void Graph::rmEdge(int v, int w)
{
cout << "front == " << adj[v].front() << endl;
cout << "back == " << adj[v].back() << endl;
cout << v << " " << w << endl;
cout << "My size is " << adj[v].size() << endl;
adj[v].remove(w);
}
int main()
{
int n, m;
cin >> n >> m;
struct Edge* edges = new Edge[m];
Graph g(n);
for (int i = 0; i < m; ++i)
{
int temp1, temp2;
cin >> temp1 >> temp2;
g.addEdge(temp1, temp2);
edges[i].src = temp1;
edges[i].dest = temp2;
}
for (int i = 0; i < m; ++i)
{
g.rmEdge(edges[i].src, edges[i].dest);
}
return 0;
}
The input I am giving:
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
The output I am getting:
front == 8
back == 1
2 1
My size is 1
Segmentation fault (core dumped)
Now if the size of the list is 1, then how can the front() and back() be different? And even if they are different, why is remove() giving segmentation fault when the value is present in the list (as the back() element)?
An observation:
This code gave Segmentation fault earlier than this code.
Please pardon my horrible debugging approach, but this observation is implying that a cout << endl; is causing output to change in ways it is not supposed to. What is happening here, I am unable to make any sense out of it?
EDIT: I changed the malloc to new and still the same behaviour is persisting.
You're passing a "10" as a "v" to addEdge, trying to access the 11th element. The adj vector has 10 elements, hence you're writing somewhere in the memory where you should not.
In any case, manual allocation and deallocation is recipe for trouble, consider using stl vectors.

C++11 - Error in calculating mode in a vector of numbers

I'm working on a program that, given a list of values (doubles) from an input file, sorts them in ascending order and calculates the mode, and print the result in an output file. This is what I came up with so far.
What it should do is assign the mode to the xth element of the vector, the one that produces the greater value for current, but when I run this program the mode is always equal to the last element of the vector.
I just can't figure out what mistake I'm doing, because in my mind it seems perfectly logical.
Any help is greatly appreciated.
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <fstream>
using namespace std;
int main()
{
ifstream iFile("inp.txt");
if(!iFile)
{
cout << "Error input!" << endl;
return -1;
}
ofstream oFile("out.txt");
if(!oFile)
{
cout << "Error output!" << endl;
return -1;
}
double data;
vector<double> list;
while(iFile >> data)
{
list.push_back(data); //put the elements in a vector
sort(list.begin(), list.end()); //and sort them in ascending order
}
for(int m = 0; m < list.size(); ++m) //this is just
{ //to verify
oFile << list[m] << endl; //that the elements
} //are listed in order
int current = 0;
int previous = 0;
int mode = 0;
for(int x = 0; x < list.size(); ++x) //select an element of the vector
{
for(int y = 0; y < list.size(); ++y) //match it against all the other elements of the vector
{
if(list[x] == list[y]) //if they're of equal value
{
++current; //add 1 to variable "current"
}
}
if(current > previous) //if "current" > "previous"
{
mode = list[x]; //set the element "x" (from the first for) of the vector "list" to be the new mode
current = previous; //and set current to be the new previous
}
current = 0; //reset current to 0
}
oFile << "\nmode: " << mode << endl; //output "mode"
return 0;
}
Try with
previous = current;
instead of
current = previous;
in the last if, or previous is ever zero and the last x (matching with itself when y is equal to x) generate a current greater than previous (that is zero).
OT: look at this while
while(iFile >> data)
{
list.push_back(data); //put the elements in a vector
sort(list.begin(), list.end()); //and sort them in ascending order
}
There is no need to sort the vector after every single insertion. I suggest you to add in list all the content of the input file and, after, sort the vector. Only one time, only after the last insertion.
Something like
while(iFile >> data)
{
list.push_back(data); //put the elements in a vector
}
sort(list.begin(), list.end()); //and sort them only one time