Beispiel #1
0
    /**
     * Constructor.
     *
     * @param graph Target directed graph.
     * @param thread_num number of threads to compute strong components if thread_num == 1, then it
     *     is a sequential execution of this algorithm, but not a serial version
     */
    public ConnectedComponents(UndirectedGraph graph, ExecutorService threadPool) {
      this.graph = (UndirectedGraph) graph;
      this.ccs = new Vector<Collection<Node<E>>>(INIT_SIZE_FOR_CCS);
      this.pool = threadPool;
      this.numThread = Runtime.getRuntime().availableProcessors(); // should
      // be
      // better
      // determined

      this.numNodes = graph.size();
      this.average = this.numNodes / numThread;
      this.nodesArray.ensureCapacity(numNodes);
      this.pvalues = new int[numNodes];
      this.map = new ConcurrentHashMap<Node<E>, Integer>(numNodes);

      // make it parallel
      this.nodesArray.addAll(graph.getAllNodes());
    }
Beispiel #2
0
    /**
     * Compute non-trivial connected components and return them.
     *
     * @return the result collection.
     * @throws java.lang.Exception
     */
    public Collection<Collection<Node<E>>> getConnectedComponents() throws Exception {
      int i;
      if (graph.size() < 2) return this.ccs;
      // inittask1
      Runnable[] tasks = new Runnable[this.numThread];
      for (i = 0; i < this.numThread; i++) {
        final int index = i;
        tasks[i] =
            new Runnable() {
              public void run() {
                int begin = average * index;
                int end = average * (index + 1);
                if (index == numThread - 1) end = numNodes;
                for (int j = begin; j < end; j++) {
                  map.put(nodesArray.get(j), j);
                  pvalues[j] = j;
                }
              }
            };
      }
      this.runTasks(tasks, 0, numThread);
      // barrier
      // inittask2
      for (i = 0; i < this.numThread; i++) {
        final int index = i;
        tasks[i] =
            new Runnable() {
              public void run() {
                int begin = average * index;
                int end = average * (index + 1);
                if (index == numThread - 1) end = numNodes;
                Iterator<AdjacentNode<E>> itr;
                for (int j = begin; j < end; j++) {
                  itr = graph.getLinkedNodes(nodesArray.get(j)).iterator();
                  while (itr.hasNext()) {
                    pvalues[j] = Math.min(pvalues[j], pvalues[map.get(itr.next().getNode())]);
                  }
                }
              }
            };
      }
      this.runTasks(tasks, 0, this.numThread);
      // barrier

      // main loop
      this.updates = 1; // pretend there is an update
      while (this.updates != 0) {
        this.updates = 0;
        Callable<Integer>[] callables = new Callable[this.numThread];
        for (i = 0; i < this.numThread; i++) {
          final int index = i;
          callables[i] =
              new Callable<Integer>() {
                public Integer call() {
                  int begin = average * index;
                  int end = average * (index + 1);
                  if (index == numThread - 1) end = numNodes;
                  int localUpdates = 0;
                  Iterator<AdjacentNode<E>> itr;
                  // opportunistic pointer jumping
                  for (int j = begin; j < end; j++) {
                    int minVertexValue = Integer.MAX_VALUE;
                    itr = graph.getLinkedNodes(nodesArray.get(j)).iterator();
                    while (itr.hasNext())
                      minVertexValue =
                          Math.min(minVertexValue, pvalues[map.get(itr.next().getNode())]);
                    if (minVertexValue < pvalues[j]) {
                      localUpdates++;
                    }
                    pvalues[j] = Math.min(pvalues[j], minVertexValue);
                  }
                  return localUpdates;
                }
              };
        }
        this.runTasks2(callables, 0, numThread); // also acts as an
        // implicit barrier
        for (i = 0; i < this.numThread; i++) {
          final int index = i;
          callables[i] =
              new Callable<Integer>() {
                public Integer call() {
                  int begin = average * index;
                  int end = average * (index + 1);
                  if (index == numThread - 1) end = numNodes;
                  int localUpdates = 0;
                  // normal pointer jumping
                  for (int j = begin; j < end; j++) {
                    int pvalue = pvalues[j];
                    if (pvalues[pvalue] < pvalue) {
                      localUpdates++;
                    } else if (pvalues[pvalue] > pvalue) throw new RuntimeException("fatal error");
                    pvalues[j] = pvalues[pvalue];
                  }
                  return localUpdates;
                }
              };
        }
        this.runTasks2(callables, 0, numThread); // also acts as an
        // implicit barrier
        // System.out.println("updates:" + this.updates);
      }

      this.pool.shutdown();

      return this.ccs;
    }