Exemplo n.º 1
0
/**
 *  Parallel BFS to find P, L, and LQ values of the given graph
 */
void bfs(Graph *graph, int v, int *levels, int *P, int *L, int **LQ, int *LQCounts, int *visited) {
    int numThreads = omp_get_max_threads();

    // List of vertices to visit - appended to during the search
    int *toVisit = malloc(sizeof(int) * graph->numVertices);
    int back = 0;
    int *toVisitThreads = malloc(sizeof(int) * (numThreads * graph->numVertices));
    int *threadOffsets = malloc(sizeof(int) * numThreads);

    P[v] = v;
    L[v] = 0;
    LQ[0] = malloc(sizeof(int));
    LQ[0][0] = v;
    LQCounts[0] = 1;

    toVisit[0] = v;
    back = 1;

    // Direction optimising BFS vars
    double alpha = 15.0;
    double beta = 25.0;
    int useBottomUp = 0;
    int nf = 0;
    int localnf;

    #pragma omp parallel
    {
        int tid = omp_get_thread_num();
        int *toVisitThread = &toVisitThreads[tid * graph->numVertices];
        int threadOffset = 0;
        int level = 1;
        int prevLevel;
        int vert, adjEnd, u;
        int * adjVertices;

        while(back) {
            threadOffset = 0;

            if(!useBottomUp) {
                /* Using top down approach */
                #pragma omp for schedule(static) reduction(+:localnf)
                for(int i = 0; i < back; i++) {
                    vert = toVisit[i];
                    adjVertices = adjacentVertices(graph, vert);
                    adjEnd = outDegree(graph, vert);
                    // Go through each vertex adjacent to v
                    for(int j = 0; j < adjEnd; j++) {
                        u = adjVertices[j];
                        if(L[u] < 0) {
                            L[u] = level;
                            P[u] = vert;
                            // Add the adjacent vertex to the threads buffer
                            toVisitThread[threadOffset++] = u;
                            localnf++;
                        }
                    }
                }
            } else {
                /* Using bottom up approach */
                prevLevel = level - 1;

                #pragma omp for schedule(static) reduction(+:localnf)
                for(int i = 0; i < graph->numVertices; i++) {
                    vert = i;
                    if(L[vert] < 0) {
                        adjVertices = adjacentVertices(graph, vert);
                        adjEnd = outDegree(graph, vert);
                        for(int j = 0; j < adjEnd; j++) {
                            u = adjVertices[j];
                            if(L[u] == prevLevel) {
                                L[vert] = level;
                                P[vert] = u;
                                toVisitThread[threadOffset++] = vert;
                                localnf++;
                                break;
                            }
                        }
                    }
                }
            }

            threadOffsets[tid] = threadOffset;

            #pragma omp barrier

            #pragma omp single
            {
                nf += localnf;

                // Determine whether to switch BFS approaches
                if(useBottomUp) {
                    double mf = (double) localnf * graph->avgOutDegree;
                    double mu = (double) (graph->numVertices - nf) * graph->avgOutDegree;

                    // Switch if heuristic is true, and if we haven't switched yet
                    if(mf > (mu / alpha) && mu > 0) {
                        useBottomUp = 1;
                    }
                } else {
                    if(nf < ((double) graph->numVertices / beta)) {
                        useBottomUp = 0;
                    }
                }

                int oldBack = back;
                back = 0;
                // Copy each threads buffer of vertices into main array
                for(int i = 0; i < numThreads; i++) {
                    if(threadOffsets[i]) {
                        int offset = i * graph->numVertices;
                        for(int j = 0; j < threadOffsets[i]; j++) {
                            toVisit[back++] = toVisitThreads[offset + j];
                        }
                    }
                }

                // Store this level in LQ
                LQ[level] = (int *) malloc(sizeof(int) * back);
                for(int i = 0; i < back; i++) {
                    LQ[level][i] = toVisit[i];
                }
                LQCounts[level] = back;
                (*levels)++;
            }
            level++;

            #pragma omp barrier
        }
    }
    
    free(toVisit);
    free(toVisitThreads);
    free(threadOffsets);
}
Exemplo n.º 2
0
void findLowValues(Graph *graph, int root, int *P, int *L, int *Par, int *Low, int **LQ, int *LQCounts, int *Art) {
    int numThreads = omp_get_max_threads();

    // List of vertices to visit - appended to during the search
    int *toVisit = malloc(sizeof(int) * graph->numVertices);
    int back = 0;
    int *toVisitThreads = malloc(sizeof(int) * (numThreads * graph->numVertices));
    int *threadOffsets = malloc(sizeof(int) * numThreads);
    int *stack = (int *) malloc(sizeof(int) * (graph->numVertices * 2));
    int *lows = (int *) malloc(sizeof(int) * numThreads);
    int stackBack = 0;

    int *visited = (int *) malloc(sizeof(int) * graph->numVertices);
    for(int i = 0; i < graph->numVertices; i++) {
        visited[i] = 0;
    }

    int levelSize = LQCounts[1];
    visited[root] = 1;

    // Direction optimising BFS vars
    double alpha = 14.0;
    double beta = 24.0;
    int useBottomUp = 0;
    int nf = 0;
    int localnf;

    for(int l = 0; l < levelSize; l++) {
        int globalLow = graph->numVertices;
        int v = LQ[1][l];
        if(Low[v] == -1) {
            toVisit[0] = v;
            back = 1;
            Par[v] = 0;
            stack[0] = v;
            stackBack = 1;

            #pragma omp parallel
            {
                int tid = omp_get_thread_num();
                int *toVisitThread = &toVisitThreads[tid * graph->numVertices];
                int threadOffset = 0;
                int prevLevel;
                int vert, adjEnd, u;
                int *adjVertices;
                int threadLow = graph->numVertices;

                while(back) {
                    threadOffset = 0;

                    if(!useBottomUp) {
                        #pragma omp for schedule(static) reduction(+:localnf)
                        for(int i = 0; i < back; i++) {
                            vert = toVisit[i];
                            adjEnd = outDegree(graph, vert);
                            adjVertices = adjacentVertices(graph, vert);
                            for(int j = 0; j < adjEnd; j++) {
                                u = adjVertices[j];

                                if(!visited[u] && Low[u] < 0) {
                                    visited[u] = 1;
                                    Par[u] = 0;
                                    toVisitThread[threadOffset++] = u;
                                    if(u < threadLow) {
                                        threadLow = u;
                                    }
                                }
                            }
                        }
                    } else {
                        #pragma omp for schedule(static) reduction(+:localnf)
                        for(int i = 0; i < graph->numVertices; i++) {
                            vert = i;
                            if(!visited[vert] && Low[vert] < 0) {
                                adjEnd = outDegree(graph, vert);
                                adjVertices = adjacentVertices(graph, vert);
                                for(int j = 0; j < adjEnd; j++) {
                                    u = adjVertices[j];
                                    if(visited[j]) {
                                        visited[vert] = 1;
                                        Par[vert] = 0;
                                        toVisitThread[threadOffset++] = vert;
                                        if(vert < threadLow) {
                                            threadLow = vert;
                                        }
                                        localnf++;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    threadOffsets[tid] = threadOffset;
                    lows[tid] = threadLow;

                    #pragma omp barrier

                    #pragma omp single
                    {
                        nf += localnf;

                        if(useBottomUp) {
                            double mf = (double) localnf * graph->avgOutDegree;
                            double mu = (double) (graph->numVertices - nf) * graph->avgOutDegree;

                            // Switch if heuristic is true, and if we haven't switched yet
                            if(mf > (mu / alpha) && mu > 0) {
                                useBottomUp = 1;
                            }
                        } else {
                            if(nf < ((double) graph->numVertices / beta)) {
                                useBottomUp = 0;
                            }
                        }

                        back = 0;
                        for(int i = 0; i < numThreads; i++) {
                            if(lows[i] < globalLow) {
                                globalLow = lows[i];
                            }

                            if(threadOffsets[i]) {
                                int offset = i * graph->numVertices;
                                for(int j = 0; j < threadOffsets[i]; j++) {
                                    toVisit[back++] = toVisitThreads[offset + j];
                                }
                            }
                        }

                        for(int i = 0; i < back; i++) {
                            stack[i + stackBack] = toVisit[i];
                        }
                        stackBack += back;
                    }
                }

                #pragma omp for
                for(int i = 0; i < stackBack; i++) {
                    int v = stack[i];
                    Low[v] = globalLow;
                    visited[v] = 0;
                }
            }
        }
    }

    // Deal with root
    int end = outDegree(graph, root);
    int *adjVertices = adjacentVertices(graph, root);
    for(int i = 0; i < end; i++) {
        int currLow = Low[adjVertices[i]];
        for(int j = i + 1; j < end; j++) {
            if(Low[adjVertices[j]] == currLow) {
                Low[root] = currLow;
                break;
            }
        }
        if(Low[root] >= 0) {
            break;
        }
    }

    if(Low[root] < 0) {
        Art[root] = 1;
        Low[root] = root;
    }

    free(visited);
    free(toVisit);
    free(toVisitThreads);
    free(stack);
    free(threadOffsets);
    free(lows);
}
Exemplo n.º 3
0
void findArticulationPoints(Graph *graph, int *P, int *L, int *Par, int *Low, int **LQ, int *LQCounts, int *Art, int levels) {
    #pragma omp parallel 
    {
        // Each thread maintains it's own visited array
        int *visited = (int *) malloc(sizeof(int) * graph->numVertices);
        for(int i = 0; i < graph->numVertices; i++) {
            visited[i] = 0;
        }

        // Tracks the list of unique vertices encountered
        int *stack = (int *) malloc(sizeof(int) * graph->numVertices);
        int *queue = (int *) malloc(sizeof(int) * graph->numVertices);
        int *nextQueue = (int *) malloc(sizeof(int) * graph->numVertices);
        int maxVert = 0;
        int stackBack;
        int back;
        int nextBack;
        int curLow;
        int isCurrArt;

        for(int l = levels - 1; l > 1; l--) {
            int *currQueue = LQ[l];
            int levelSize = LQCounts[l];

            #pragma omp for schedule(guided)
            for(int v = 0; v < levelSize; v++) {
                int vert = currQueue[v];
                if(Low[vert] > -1) {
                    continue;
                }

                int vertLevel = l;
                int vertParent = P[vert];

                queue[0] = vert;
                back = 1;
                stack[0] = vert;
                stackBack = 1;
                visited[vert] = 1;
                isCurrArt = 0;
                curLow = graph->numVertices;

                while(back) {
                    nextBack = 0;
                    for(int j = 0; j < back; j++) {
                        int newVert = queue[j];
                        int isNewArt = Art[newVert];

                        int *newOuts = adjacentVertices(graph, newVert);
                        int newOutDegree = outDegree(graph, newVert);
                        for(int n = 0; n < newOutDegree; n++) {
                            int newOut = newOuts[n];

                            if(visited[newOut] || newOut == vertParent) {
                                continue;
                            } else if(isNewArt && Low[newOut] > -1) {
                                continue;
                            } else if(L[newOut] < vertLevel) {
                                goto next_out;
                            } else {
                                visited[newOut] = 1;
                                nextQueue[nextBack++] = newOut;
                                stack[stackBack++] = newOut;
                                if(newOut < curLow) 
                                    curLow = newOut;
                            }
                        }
                    }

                    int *tmp = nextQueue;
                    nextQueue = queue;
                    queue = tmp;
                    back = nextBack;
                }

                Art[vertParent] = 1;
                isCurrArt = 1;

                next_out:
                if(isCurrArt) {
                    for(int j = 0; j < stackBack; j++) {
                        int sVert = stack[j];
                        visited[sVert] = 0;
                        Par[sVert] = vert;
                        Low[sVert] = curLow;  
                    }
                } else {
                    for(int j = 0; j < stackBack; j++) {
                        int sVert = stack[j];
                        visited[sVert] = 0;        
                    }
                }
            }
        }

        free(visited);
        free(stack);
        free(queue);
        free(nextQueue);

    }
}
Exemplo n.º 4
0
/**
 *  Finds the articulation points of the given graph by inspecting the queues in LQ in reverse order, and 
 *  determining Par and Low values
 */
void findArticulationPoints2(Graph *graph, int *P, int *L, int *Par, int *Low, int **LQ, int *LQCounts, int *Art, int levels) {
    #pragma omp parallel 
    {
        // Each thread maintains it's own visited array
        int *visited = (int *) malloc(sizeof(int) * graph->numVertices);
        for(int i = 0; i < graph->numVertices; i++) {
            visited[i] = 0;
        }

        // Tracks the list of unique vertices encountered
        int *Vu = (int *) malloc(sizeof(int) * graph->numVertices);
        int *queue = (int *) malloc(sizeof(int) * graph->numVertices);
        int *nextQueue = (int *) malloc(sizeof(int) * graph->numVertices);
        int *queueWhole = (int *) malloc(sizeof(int) * graph->numVertices);

        int maxVert = 0;
        int stackEnd;
        int queueEnd, queueEndWhole;
        int nextQueueEnd;
        int isCurrArt;

        // Lowest vertex identifier encountered
        int vidLow;

        // Inspect LQ in reverse order (LQm..1)
        for(int level = levels - 1; level >= 1; level--) {
            int levelSize = LQCounts[level];

            #pragma omp for schedule(guided)
            for(int uIndex = 0; uIndex < levelSize; uIndex++) {
                int u = LQ[level][uIndex];
                
                if(Low[u] == -1) {
                    // Get the parent of u
                    int v = P[u];

                    queue[0] = u;
                    queueEnd = 1;
                    Vu[0] = u;
                    stackEnd = 1;
                    visited[u] = 1;
                    isCurrArt = 0;
                    vidLow = u;

                    int queueIndex = 0;
                    while(queueIndex < queueEnd) {
                        int x = queue[queueIndex++];

                        int isXArt = Art[x];

                        int *xAdj = adjacentVertices(graph, x);
                        int xAdjEnd = outDegree(graph, x);
                        for(int wIndex = 0; wIndex < xAdjEnd; wIndex++) {
                            int w = xAdj[wIndex];

                            if(visited[w] || w == v) {
                                // This thread has already visited, or it's an edge back to parent, ignore!
                                continue;
                            } else if(isXArt && Low[w] > -1) {
                                // Already know it's an articulation point, ignore!
                                continue;
                            } else if(L[w] < L[u]) {
                                // Ref. lines 11 & 12, Alg. 8 (BFS-LV)
                                // Jump out of this BFS and set everything on the stack to unvisited
                                goto nextOut;
                            } else {
                                // Can keep searching!
                                // Ref. lines 14--18, Alg. 8 (BFS-LV)

                                // Add to the next queue so we process it after everything in the current queue
                                queue[queueEnd++] = w;
                                Vu[stackEnd++] = w;
                                visited[w] = 1;
                                if(w < vidLow) {
                                    vidLow = w;
                                }
                            }
                        }
                    }

                    // Ref. line 14 - 21, Alg. 8 (BFS-LV)
                    Art[v] = 1;
                    numBiconnectedComponents++;
                    isCurrArt = 1;
                    // For each of the unique vertices encountered
                    for(int j = 0; j < stackEnd; j++) {
                        int w = Vu[j];
                        Low[w] = vidLow;
                        Par[w] = v;
                        visited[w] = 0;
                    }

                    nextOut:            // Label to get out of nested loop above
                    if(!isCurrArt) {
                        // We'll get here from the jump above when L[w] < L[u] - set everything on stack to unvisited
                        for(int j = 0; j < stackEnd; j++) {
                            int s = Vu[j];
                            visited[s] = 0;
                        }
                    }
                }
            }
        }

        free(visited);
        free(Vu);
        free(queue);
        free(nextQueue);
    }
}
Exemplo n.º 5
0
int main (int argc, char * argv[]) {
  printf("Blackbox tests...\n");

  printf("Test 1: newGraph...");
  //empty graph
  Graph g1a = mkTestGraph(0);
  destroyGraph(g1a);
  //single graph
  Graph g1b = mkTestGraph(1);
  destroyGraph(g1b);
  printf("Passed!\n");

  printf("Test 1a: mkEdge...");
  //zero cost edge
  Edge e1a = mkEdge(0, 1, 0);
  assert(e1a.v == 0);
  assert(e1a.w == 1);
  assert(e1a.weight == 0);
  Edge e1ar = mkEdge(1, 0, 0);
  assert(e1ar.v == 1);
  assert(e1ar.w == 0);
  assert(e1ar.weight == 0);
  //edge
  Edge e1b = mkEdge(1, 5, 10);
  assert(e1b.v == 1);
  assert(e1b.w == 5);
  assert(e1b.weight == 10);
  Edge e1br = mkEdge(5, 1, 10);
  assert(e1br.v == 5);
  assert(e1br.w == 1);
  assert(e1br.weight == 10);
  printf("Passed!\n");
  
  printf("Test 2: insertE...");
  //double graph
  Graph g2 = mkTestGraph(2);
  Edge e2 = mkEdge(0, 1, 12);
  insertE(g2, e2);
  assert(numE(g2) == 1);
  destroyGraph(g2);
  printf("Passed!\n");

  printf("Test 3: isAdjacent...");
  //double graph
  Graph g3a = mkTestGraph(2);
  Edge e3a = {0, 1, 12};
  insertE(g3a, e3a);
  assert(numV(g3a) == 2);
  assert(numE(g3a) == 1);
  assert(isAdjacent(g3a, 0, 1) == 1);
  assert(isAdjacent(g3a, 1, 0) == 1);
  destroyGraph(g3a);

  //graph
  Graph g3b = mkTestGraph(3);
  assert(isAdjacent(g3b, 0, 1) == 1);
  assert(isAdjacent(g3b, 0, 2) == 1);
  assert(isAdjacent(g3b, 0, 3) == 1);
  assert(isAdjacent(g3b, 0, 4) == 1);
  assert(isAdjacent(g3b, 1, 2) == 1);
  assert(isAdjacent(g3b, 2, 3) == 1);
  assert(isAdjacent(g3b, 3, 4) == 1);
  destroyGraph(g3b);
  printf("Passed!\n");

  printf("Test 4: adjacentVertices...");
  Graph g4a = mkTestGraph(2);
  Edge e4a = {0, 1, 12};
  insertE(g4a, e4a);
  Vertex adj4a[2]; //allocate space for max number of vertices
  assert(adjacentVertices(g4a, 0, adj4a) == 1);
  assert(adj4a[0] >= 0);
  assert(adjacentVertices(g4a, 1, adj4a) == 1);
  assert(adj4a[0] >= 0);
  destroyGraph(g4a);
  printf("Passed!\n");

  printf("Test 5: incidentEdges...");
  Graph g5 = mkTestGraph(2);
  Edge e5 = {0, 1, 12};
  insertE(g5, e5);
  Edge edges5[1]; //allocate space for max num of edges
  assert(incidentEdges(g5, 0, edges5) == 1);
  int v5 = edges5[0].v; int w5 = edges5[0].w;
  assert( (v5 == 0 && w5 == 1) || (v5 == 1 && w5 == 0) );
  assert(edges5[0].weight == 12);
  assert(incidentEdges(g5, 1, edges5) == 1);
  v5 = edges5[0].v; w5 = edges5[0].w;
  assert( (v5 == 0 && w5 == 1) || (v5 == 1 && w5 == 0) );
  assert(edges5[0].weight == 12);
  destroyGraph(g5);
  printf("Passed!\n");

  printf("Test 6: edges...");
  Graph g6 = mkTestGraph(2);
  Edge e6 = {0, 1, 12};
  insertE(g6, e6);
  Edge es6[1]; //allocate space for max num of edges
  assert(edges(es6, 1, g6) == 1);
  int v6 = es6[0].v; int w6 = es6[0].w;
  assert( (v6 == 0 && w6 == 1) || (v6 == 1 && w6 == 0) );
  assert(es6[0].weight == 12);
  destroyGraph(g6);
  printf("Passed!\n");

  printf("All Test Passed! You are a Beast!\n");
  
  return EXIT_SUCCESS;
}