Пример #1
0
  /**
   * Computer minimal weight for every node. read-only array.
   *
   * @param <E> type of element in node
   * @param graph graph
   * @return minimal weight array for every node.
   */
  private static <E> Map<Node<E>, Double> computeMinWeight(Graph<E> graph) {
    // minWeight record the minimal weight for every node
    Map<Node<E>, Double> minWeight = new ConcurrentHashMap<Node<E>, Double>();

    // linked nodes of target node
    Collection<AdjacentNode<E>> linkedNodes;
    for (Node<E> node : graph.getAllNodes()) {
      // get linked nodes of target node
      linkedNodes = graph.getLinkedNodes(node);
      // recored the min weight of target node if exist, otherwise put
      // infinity
      if (!linkedNodes.isEmpty()) {
        minWeight.put(node, Collections.min(linkedNodes, nodeComparator).getWeight());
      } else {
        minWeight.put(node, Double.POSITIVE_INFINITY);
      }
    }
    return minWeight;
  }
Пример #2
0
  /**
   * This is an implementation of a parallelization of Dijkstra's shortest path algorithm described
   * by Crauser, Mehlhorn, Meyer and Sanders in their paper "A Parallelization of Dijkstra's
   * Shortest Path Algorithm" in 23rd Symposium on Mathematical Foundations of Computer Science,
   * 1998. To gain a complete understanding of this data structure, please first read this paper,
   * available at: http://citeseer.ist.psu.edu/crauser98parallelization.html
   *
   * <p>This paper propose simple criteria which divide Dijkstra's sequential SSSP algorithm into a
   * number of phases,such that the operations within a phase can be done in parallel.
   *
   * <p>In the first variant (OUT-version) we compute a threshold defined via the weights of the
   * outgoing edges:let L=min{tent(u) + c(u,z) : u is queued and (u,z) belongs E} and remove all
   * nodes v from the queue then dist(v) = tent(v). The threshold for the OUT-criterion can either
   * be computed via a second priority queue for o(v) = tent(v) + min(c(u,v) : (u,v) belongs to E}
   * or even on the fly while while removing nodes.
   *
   * <p>The second variant, the IN-version, is defined via the incoming edges: let M = min{tent(u) :
   * u is queued} and i(v) = tent(v) - min{c(u,v) : (u,v) belongs to E} for any queued vertex v.
   * Then v can be safely removed from the queue if i(v) <= M. Removable nodes of the IN-type can be
   * found efficiently by using an additional priority queue for i(.).
   *
   * <p>Finally, the INOUT-applies both criteria in conjunction.
   *
   * <p>Sample performance results here.
   *
   * @param <E> type of element on node
   * @param graph Graph
   * @param exec Thread pool for executing task in parallel.
   * @param source source node
   * @param end end node
   * @return the length of shortest path from source node to end node
   */
  public static <E> double getShortestPath(
      Graph<E> graph, ExecutorService exec, Node<E> source, Node<E> end) {
    // if source is the same as end, return 0
    if (end.equals(source)) {
      return 0;
    }

    // executor for processing node over threshold
    final CompletionService<Boolean> completionService =
        new ExecutorCompletionService<Boolean>(exec);
    // size of nodes in the graph
    final int nodeSize = graph.getAllNodes().size();

    // min weight on the edges in the graph. precompute once and for all
    // upon initialization
    final Map<Node<E>, Double> minWeight = computeMinWeight(graph);

    // tentative length of path from source node to end nodes
    final Map<Node<E>, Double> tentative = computeTentative(graph, source);
    // auxiliary array to record predecessor of shortest path. use to
    // recover the shortest path
    final Map<Node<E>, AdjacentNode<E>> predecessor = computePredecessor(graph, source);
    // nodes queue waiting for being processed
    final PriorityQueue<AdjacentNode<E>> queued =
        new PriorityQueue<AdjacentNode<E>>(nodeSize, nodeComparator);
    // enqueue the source node as initiation
    queued.offer(new AdjacentNode<E>(source, (tentative.get(source))));

    /*
     * thresholds decide which nodes should be choose to be processed
     * parallely
     */
    final PriorityQueue<AdjacentNode<E>> thresholds =
        new PriorityQueue<AdjacentNode<E>>(nodeSize, nodeComparator);
    // enqueue the source node as initiation
    thresholds.offer(new AdjacentNode<E>(source, (tentative.get(source) + minWeight.get(source))));
    // min threshold node from threshold queue
    AdjacentNode<E> thrsNode;
    // value of min threshold
    double threshold;
    // settled list all nodes has be processed
    final List<Node<E>> settled = new ArrayList<Node<E>>();

    while (!queued.isEmpty()) {
      // there is still nodes to be processed

      // find the first node not be settled from thresholds
      do {
        thrsNode = thresholds.poll();
      } while (settled.contains(thrsNode.getNode()));

      // get value of threshold
      threshold = thrsNode.getWeight();

      while (!queued.isEmpty()) {
        // there is still nodes to be processed
        if (queued.peek().getWeight() <= threshold) {
          // weight of the first unprocessed node is less than
          // threshold. it should be dequed for processing.
          final Node<E> v = queued.poll().getNode();
          // mark it as processed
          settled.add(v);

          // get the size of linked nodes
          int size = graph.getLinkedNodes(v).size();

          for (AdjacentNode<E> wAdj : graph.getLinkedNodes(v)) {
            // process linked node
            final Node<E> w = wAdj.getNode();
            final double weight = wAdj.getWeight();

            // submit the linked node to executor to parallelly
            // process
            completionService.submit(
                new Callable<Boolean>() {
                  public Boolean call() {
                    double x = tentative.get(v) + weight;
                    // find a shorter path from source node v to
                    // end node w
                    if (x < tentative.get(w)) {

                      // update tentative array and predecessor
                      // array
                      tentative.put(w, x);
                      predecessor.put(w, new AdjacentNode<E>(v, weight));

                      // update the priority queue queued and
                      // threshold to reflect the new shorter path
                      decreasKey(queued, new AdjacentNode<E>(w, x));
                      decreasKey(thresholds, new AdjacentNode<E>(w, x + minWeight.get(w)));
                    }
                    return true;
                  }
                });
          }

          // synchronization bar.continue after all linked node has
          // been processed
          try {
            for (int i = 0; i < size; i++) {
              completionService.take();
            }
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        } else {
          break;
        }
      }
    }

    // recover path using predecessor array
    double length = 0;
    boolean reachable = false;
    AdjacentNode<E> start;
    while ((start = predecessor.get(end)).getNode() != DUMMY_NODE) {
      reachable = true;
      length += start.getWeight();
      end = start.getNode();
    }

    // return the length if reachable, otherwise return infinity
    if (reachable) {
      return length;
    } else {
      return Double.POSITIVE_INFINITY;
    }
  }